summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CREDITS6
-rw-r--r--Documentation/CodingStyle100
-rw-r--r--Documentation/DocBook/kernel-api.tmpl57
-rw-r--r--Documentation/DocBook/libata.tmpl104
-rw-r--r--Documentation/RCU/checklist.txt44
-rw-r--r--Documentation/RCU/whatisRCU.txt13
-rw-r--r--Documentation/SubmitChecklist57
-rw-r--r--Documentation/devices.txt140
-rw-r--r--Documentation/feature-removal-schedule.txt15
-rw-r--r--Documentation/filesystems/Locking9
-rw-r--r--Documentation/filesystems/automount-support.txt2
-rw-r--r--Documentation/filesystems/fuse.txt118
-rw-r--r--Documentation/filesystems/porting7
-rw-r--r--Documentation/filesystems/ramfs-rootfs-initramfs.txt146
-rw-r--r--Documentation/filesystems/vfs.txt6
-rw-r--r--Documentation/hwmon/abituguru59
-rw-r--r--Documentation/hwmon/abituguru-datasheet312
-rw-r--r--Documentation/hwmon/lm7031
-rw-r--r--Documentation/hwmon/lm8317
-rw-r--r--Documentation/hwmon/smsc47m192102
-rw-r--r--Documentation/hwmon/sysfs-interface274
-rw-r--r--Documentation/hwmon/userspace-tools17
-rw-r--r--Documentation/hwmon/w83791d113
-rw-r--r--Documentation/i2c/busses/i2c-i8013
-rw-r--r--Documentation/i2c/busses/i2c-nforce22
-rw-r--r--Documentation/i2c/busses/i2c-ocores51
-rw-r--r--Documentation/i2c/busses/i2c-piix440
-rw-r--r--Documentation/i2c/busses/scx200_acb19
-rw-r--r--Documentation/ia64/aliasing.txt208
-rw-r--r--Documentation/ioctl-number.txt2
-rw-r--r--Documentation/kdump/kdump.txt420
-rw-r--r--Documentation/kernel-parameters.txt3
-rw-r--r--Documentation/keys.txt39
-rw-r--r--Documentation/memory-barriers.txt34
-rw-r--r--Documentation/networking/tuntap.txt11
-rw-r--r--Documentation/pci.txt14
-rw-r--r--Documentation/power/swsusp.txt45
-rw-r--r--Documentation/power/video.txt4
-rw-r--r--Documentation/rtc.txt7
-rw-r--r--Documentation/sound/alsa/ALSA-Configuration.txt19
-rw-r--r--Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl50
-rw-r--r--Documentation/sparc/sbus_drivers.txt95
-rw-r--r--Documentation/sparse.txt36
-rw-r--r--Documentation/sysctl/vm.txt13
-rw-r--r--Documentation/sysrq.txt5
-rw-r--r--Documentation/video4linux/CARDLIST.bttv4
-rw-r--r--Documentation/video4linux/CARDLIST.cx889
-rw-r--r--Documentation/video4linux/CARDLIST.saa71341
-rw-r--r--Documentation/video4linux/CARDLIST.tuner3
-rw-r--r--Documentation/video4linux/CQcam.txt203
-rw-r--r--Documentation/video4linux/Zoran23
-rw-r--r--Documentation/video4linux/bttv/CONTRIBUTORS8
-rw-r--r--Documentation/video4linux/cx2341x/fw-calling.txt69
-rw-r--r--Documentation/video4linux/cx2341x/fw-decoder-api.txt319
-rw-r--r--Documentation/video4linux/cx2341x/fw-dma.txt94
-rw-r--r--Documentation/video4linux/cx2341x/fw-encoder-api.txt694
-rw-r--r--Documentation/video4linux/cx2341x/fw-memory.txt141
-rw-r--r--Documentation/video4linux/cx2341x/fw-osd-api.txt342
-rw-r--r--Documentation/video4linux/cx2341x/fw-upload.txt49
-rw-r--r--Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt54
-rw-r--r--Documentation/video4linux/et61x251.txt52
-rw-r--r--Documentation/video4linux/ibmcam.txt168
-rw-r--r--Documentation/video4linux/ov511.txt32
-rw-r--r--Documentation/video4linux/sn9c102.txt78
-rw-r--r--Documentation/video4linux/v4lgrab.c192
-rw-r--r--Documentation/video4linux/w9968cf.txt162
-rw-r--r--Documentation/video4linux/zc0301.txt80
-rw-r--r--Documentation/vm/page_migration114
-rw-r--r--Documentation/w1/masters/ds249018
-rw-r--r--Documentation/w1/w1.generic18
-rw-r--r--Documentation/w1/w1.netlink98
-rw-r--r--MAINTAINERS30
-rw-r--r--arch/alpha/kernel/alpha_ksyms.c12
-rw-r--r--arch/alpha/kernel/osf_sys.c2
-rw-r--r--arch/alpha/kernel/signal.c2
-rw-r--r--arch/arm/common/Makefile1
-rw-r--r--arch/arm/common/dmabounce.c67
-rw-r--r--arch/arm/common/uengine.c58
-rw-r--r--arch/arm/configs/lpd270_defconfig963
-rw-r--r--arch/arm/kernel/bios32.c1
-rw-r--r--arch/arm/kernel/entry-armv.S24
-rw-r--r--arch/arm/kernel/irq.c4
-rw-r--r--arch/arm/kernel/iwmmxt.S4
-rw-r--r--arch/arm/kernel/process.c24
-rw-r--r--arch/arm/kernel/signal.c228
-rw-r--r--arch/arm/mach-ep93xx/Makefile2
-rw-r--r--arch/arm/mach-ep93xx/clock.c156
-rw-r--r--arch/arm/mach-ep93xx/core.c33
-rw-r--r--arch/arm/mach-ep93xx/gesbc9312.c24
-rw-r--r--arch/arm/mach-ep93xx/ts72xx.c23
-rw-r--r--arch/arm/mach-imx/dma.c65
-rw-r--r--arch/arm/mach-ixp2000/core.c4
-rw-r--r--arch/arm/mach-ixp23xx/core.c5
-rw-r--r--arch/arm/mach-ixp23xx/espresso.c22
-rw-r--r--arch/arm/mach-ixp23xx/ixdp2351.c22
-rw-r--r--arch/arm/mach-ixp23xx/roadrunner.c22
-rw-r--r--arch/arm/mach-ixp4xx/common.c2
-rw-r--r--arch/arm/mach-ixp4xx/nas100d-power.c3
-rw-r--r--arch/arm/mach-ixp4xx/nas100d-setup.c41
-rw-r--r--arch/arm/mach-ixp4xx/nslu2-power.c3
-rw-r--r--arch/arm/mach-ixp4xx/nslu2-setup.c48
-rw-r--r--arch/arm/mach-omap1/board-ams-delta.c11
-rw-r--r--arch/arm/mach-pnx4008/clock.c129
-rw-r--r--arch/arm/mach-pnx4008/serial.c2
-rw-r--r--arch/arm/mach-s3c2410/Kconfig28
-rw-r--r--arch/arm/mach-s3c2410/Makefile10
-rw-r--r--arch/arm/mach-s3c2410/clock.c249
-rw-r--r--arch/arm/mach-s3c2410/clock.h13
-rw-r--r--arch/arm/mach-s3c2410/cpu.c37
-rw-r--r--arch/arm/mach-s3c2410/cpu.h2
-rw-r--r--arch/arm/mach-s3c2410/irq.c57
-rw-r--r--arch/arm/mach-s3c2410/mach-smdk2413.c126
-rw-r--r--arch/arm/mach-s3c2410/pm-simtec.c3
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-clock.c271
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-gpio.c13
-rw-r--r--arch/arm/mach-s3c2410/s3c2410.c25
-rw-r--r--arch/arm/mach-s3c2410/s3c2410.h2
-rw-r--r--arch/arm/mach-s3c2410/s3c2412-clock.c711
-rw-r--r--arch/arm/mach-s3c2410/s3c2412.c195
-rw-r--r--arch/arm/mach-s3c2410/s3c2412.h29
-rw-r--r--arch/arm/mach-s3c2410/s3c2440-clock.c4
-rw-r--r--arch/arm/mach-s3c2410/s3c2442-clock.c2
-rw-r--r--arch/arm/mach-s3c2410/s3c244x.c2
-rw-r--r--arch/arm/mm/Kconfig10
-rw-r--r--arch/arm/nwfpe/fpmodule.c25
-rw-r--r--arch/arm/plat-omap/timer32k.c3
-rw-r--r--arch/arm/vfp/Makefile5
-rw-r--r--arch/arm/vfp/vfphw.S4
-rw-r--r--arch/arm/vfp/vfpmodule.c71
-rw-r--r--arch/cris/arch-v32/drivers/pci/bios.c2
-rw-r--r--arch/frv/kernel/entry.S2
-rw-r--r--arch/frv/kernel/frv_ksyms.c18
-rw-r--r--arch/frv/kernel/irq-routing.c8
-rw-r--r--arch/frv/kernel/irq.c6
-rw-r--r--arch/frv/kernel/pm.c40
-rw-r--r--arch/frv/kernel/process.c2
-rw-r--r--arch/frv/kernel/setup.c2
-rw-r--r--arch/frv/kernel/signal.c22
-rw-r--r--arch/frv/kernel/sys_frv.c2
-rw-r--r--arch/frv/kernel/sysctl.c4
-rw-r--r--arch/frv/kernel/uaccess.c6
-rw-r--r--arch/frv/mb93090-mb00/pci-irq.c10
-rw-r--r--arch/frv/mm/kmap.c6
-rw-r--r--arch/h8300/kernel/signal.c2
-rw-r--r--arch/i386/Kconfig7
-rw-r--r--arch/i386/kernel/acpi/boot.c10
-rw-r--r--arch/i386/kernel/acpi/processor.c2
-rw-r--r--arch/i386/kernel/acpi/sleep.c19
-rw-r--r--arch/i386/kernel/acpi/wakeup.S11
-rw-r--r--arch/i386/kernel/apic.c4
-rw-r--r--arch/i386/kernel/apm.c39
-rw-r--r--arch/i386/kernel/cpu/common.c2
-rw-r--r--arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c291
-rw-r--r--arch/i386/kernel/cpu/cpufreq/powernow-k8.c30
-rw-r--r--arch/i386/kernel/cpu/cpufreq/powernow-k8.h4
-rw-r--r--arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c266
-rw-r--r--arch/i386/kernel/cpu/cyrix.c9
-rw-r--r--arch/i386/kernel/cpu/proc.c2
-rw-r--r--arch/i386/kernel/crash.c3
-rw-r--r--arch/i386/kernel/doublefault.c3
-rw-r--r--arch/i386/kernel/i387.c2
-rw-r--r--arch/i386/kernel/i8259.c4
-rw-r--r--arch/i386/kernel/io_apic.c31
-rw-r--r--arch/i386/kernel/irq.c12
-rw-r--r--arch/i386/kernel/kprobes.c2
-rw-r--r--arch/i386/kernel/microcode.c73
-rw-r--r--arch/i386/kernel/setup.c125
-rw-r--r--arch/i386/kernel/smpboot.c14
-rw-r--r--arch/i386/kernel/srat.c19
-rw-r--r--arch/i386/kernel/syscall_table.S1
-rw-r--r--arch/i386/kernel/traps.c11
-rw-r--r--arch/i386/kernel/vmlinux.lds.S7
-rw-r--r--arch/i386/lib/usercopy.c256
-rw-r--r--arch/i386/mach-default/setup.c43
-rw-r--r--arch/i386/mach-visws/setup.c49
-rw-r--r--arch/i386/mach-voyager/setup.c74
-rw-r--r--arch/i386/mm/fault.c21
-rw-r--r--arch/i386/mm/init.c3
-rw-r--r--arch/i386/mm/pageattr.c8
-rw-r--r--arch/i386/pci/common.c1
-rw-r--r--arch/i386/pci/i386.c11
-rw-r--r--arch/i386/pci/irq.c15
-rw-r--r--arch/i386/pci/mmconfig.c9
-rw-r--r--arch/i386/pci/pci.h1
-rw-r--r--arch/i386/power/cpu.c2
-rw-r--r--arch/ia64/Kconfig4
-rw-r--r--arch/ia64/Makefile2
-rw-r--r--arch/ia64/hp/common/sba_iommu.c4
-rw-r--r--arch/ia64/kernel/acpi.c32
-rw-r--r--arch/ia64/kernel/asm-offsets.c16
-rw-r--r--arch/ia64/kernel/efi.c156
-rw-r--r--arch/ia64/kernel/efi_stub.S2
-rw-r--r--arch/ia64/kernel/entry.S2
-rw-r--r--arch/ia64/kernel/entry.h1
-rw-r--r--arch/ia64/kernel/irq_ia64.c19
-rw-r--r--arch/ia64/kernel/mca_asm.S28
-rw-r--r--arch/ia64/kernel/perfmon.c10
-rw-r--r--arch/ia64/kernel/sal.c6
-rw-r--r--arch/ia64/kernel/setup.c1
-rw-r--r--arch/ia64/kernel/topology.c2
-rw-r--r--arch/ia64/kernel/uncached.c200
-rw-r--r--arch/ia64/mm/init.c2
-rw-r--r--arch/ia64/mm/ioremap.c27
-rw-r--r--arch/ia64/pci/pci.c22
-rw-r--r--arch/ia64/sn/kernel/io_init.c9
-rw-r--r--arch/ia64/sn/kernel/irq.c142
-rw-r--r--arch/ia64/sn/kernel/setup.c4
-rw-r--r--arch/ia64/sn/kernel/sn2/cache.c15
-rw-r--r--arch/ia64/sn/kernel/sn2/sn_hwperf.c50
-rw-r--r--arch/ia64/sn/pci/pci_dma.c10
-rw-r--r--arch/ia64/sn/pci/pcibr/pcibr_dma.c62
-rw-r--r--arch/ia64/sn/pci/tioca_provider.c8
-rw-r--r--arch/ia64/sn/pci/tioce_provider.c69
-rw-r--r--arch/m68k/amiga/amiga_ksyms.c2
-rw-r--r--arch/m68k/amiga/amiints.c384
-rw-r--r--arch/m68k/amiga/cia.c156
-rw-r--r--arch/m68k/amiga/config.c15
-rw-r--r--arch/m68k/apollo/Makefile2
-rw-r--r--arch/m68k/apollo/config.c24
-rw-r--r--arch/m68k/apollo/dn_ints.c137
-rw-r--r--arch/m68k/atari/ataints.c278
-rw-r--r--arch/m68k/atari/config.c11
-rw-r--r--arch/m68k/bvme6000/Makefile2
-rw-r--r--arch/m68k/bvme6000/bvmeints.c160
-rw-r--r--arch/m68k/bvme6000/config.c21
-rw-r--r--arch/m68k/hp300/Makefile2
-rw-r--r--arch/m68k/hp300/config.c11
-rw-r--r--arch/m68k/hp300/ints.c175
-rw-r--r--arch/m68k/hp300/ints.h9
-rw-r--r--arch/m68k/hp300/time.c3
-rw-r--r--arch/m68k/kernel/Makefile4
-rw-r--r--arch/m68k/kernel/dma.c129
-rw-r--r--arch/m68k/kernel/entry.S104
-rw-r--r--arch/m68k/kernel/ints.c382
-rw-r--r--arch/m68k/kernel/m68k_ksyms.c2
-rw-r--r--arch/m68k/kernel/setup.c3
-rw-r--r--arch/m68k/kernel/signal.c2
-rw-r--r--arch/m68k/kernel/traps.c188
-rw-r--r--arch/m68k/lib/Makefile4
-rw-r--r--arch/m68k/lib/uaccess.c222
-rw-r--r--arch/m68k/mac/baboon.c2
-rw-r--r--arch/m68k/mac/config.c33
-rw-r--r--arch/m68k/mac/iop.c2
-rw-r--r--arch/m68k/mac/macints.c504
-rw-r--r--arch/m68k/mac/oss.c14
-rw-r--r--arch/m68k/mac/psc.c10
-rw-r--r--arch/m68k/mac/via.c33
-rw-r--r--arch/m68k/mm/kmap.c6
-rw-r--r--arch/m68k/mm/motorola.c12
-rw-r--r--arch/m68k/mm/sun3mmu.c5
-rw-r--r--arch/m68k/mvme147/147ints.c145
-rw-r--r--arch/m68k/mvme147/Makefile2
-rw-r--r--arch/m68k/mvme147/config.c22
-rw-r--r--arch/m68k/mvme16x/16xints.c149
-rw-r--r--arch/m68k/mvme16x/Makefile2
-rw-r--r--arch/m68k/mvme16x/config.c23
-rw-r--r--arch/m68k/q40/config.c13
-rw-r--r--arch/m68k/q40/q40ints.c481
-rw-r--r--arch/m68k/sun3/config.c8
-rw-r--r--arch/m68k/sun3/sun3ints.c208
-rw-r--r--arch/m68k/sun3x/config.c7
-rw-r--r--arch/m68knommu/kernel/signal.c2
-rw-r--r--arch/mips/kernel/irixsig.c3
-rw-r--r--arch/mips/kernel/scall32-o32.S2
-rw-r--r--arch/mips/kernel/sysirix.c14
-rw-r--r--arch/parisc/hpux/sys_hpux.c10
-rw-r--r--arch/parisc/kernel/signal.c2
-rw-r--r--arch/powerpc/Kconfig53
-rw-r--r--arch/powerpc/Kconfig.debug13
-rw-r--r--arch/powerpc/Makefile1
-rw-r--r--arch/powerpc/boot/Makefile4
-rw-r--r--arch/powerpc/boot/main.c27
-rw-r--r--arch/powerpc/boot/prom.h7
-rw-r--r--arch/powerpc/configs/cell_defconfig34
-rw-r--r--arch/powerpc/configs/mpc85xx_cds_defconfig846
-rw-r--r--arch/powerpc/configs/mpc8641_hpcn_defconfig921
-rw-r--r--arch/powerpc/configs/pmac32_defconfig204
-rw-r--r--arch/powerpc/configs/pseries_defconfig75
-rw-r--r--arch/powerpc/kernel/align.c189
-rw-r--r--arch/powerpc/kernel/asm-offsets.c5
-rw-r--r--arch/powerpc/kernel/cpu_setup_6xx.S2
-rw-r--r--arch/powerpc/kernel/cpu_setup_power4.S17
-rw-r--r--arch/powerpc/kernel/cputable.c137
-rw-r--r--arch/powerpc/kernel/crash.c13
-rw-r--r--arch/powerpc/kernel/crash_dump.c11
-rw-r--r--arch/powerpc/kernel/entry_64.S2
-rw-r--r--arch/powerpc/kernel/fpu.S6
-rw-r--r--arch/powerpc/kernel/head_32.S14
-rw-r--r--arch/powerpc/kernel/head_64.S29
-rw-r--r--arch/powerpc/kernel/iomap.c2
-rw-r--r--arch/powerpc/kernel/iommu.c23
-rw-r--r--arch/powerpc/kernel/irq.c29
-rw-r--r--arch/powerpc/kernel/lparcfg.c4
-rw-r--r--arch/powerpc/kernel/machine_kexec_64.c99
-rw-r--r--arch/powerpc/kernel/misc_32.S2
-rw-r--r--arch/powerpc/kernel/misc_64.S5
-rw-r--r--arch/powerpc/kernel/nvram_64.c2
-rw-r--r--arch/powerpc/kernel/pci_32.c8
-rw-r--r--arch/powerpc/kernel/pci_64.c63
-rw-r--r--arch/powerpc/kernel/pci_direct_iommu.c18
-rw-r--r--arch/powerpc/kernel/pci_dn.c6
-rw-r--r--arch/powerpc/kernel/pci_iommu.c41
-rw-r--r--arch/powerpc/kernel/proc_ppc64.c4
-rw-r--r--arch/powerpc/kernel/process.c55
-rw-r--r--arch/powerpc/kernel/prom.c145
-rw-r--r--arch/powerpc/kernel/prom_init.c120
-rw-r--r--arch/powerpc/kernel/prom_parse.c25
-rw-r--r--arch/powerpc/kernel/ptrace.c2
-rw-r--r--arch/powerpc/kernel/rtas-rtc.c30
-rw-r--r--arch/powerpc/kernel/rtas.c108
-rw-r--r--arch/powerpc/kernel/rtas_flash.c25
-rw-r--r--arch/powerpc/kernel/rtas_pci.c4
-rw-r--r--arch/powerpc/kernel/setup-common.c20
-rw-r--r--arch/powerpc/kernel/setup.h3
-rw-r--r--arch/powerpc/kernel/setup_32.c18
-rw-r--r--arch/powerpc/kernel/setup_64.c31
-rw-r--r--arch/powerpc/kernel/signal_32.c23
-rw-r--r--arch/powerpc/kernel/signal_64.c16
-rw-r--r--arch/powerpc/kernel/smp.c2
-rw-r--r--arch/powerpc/kernel/systbl.S311
-rw-r--r--arch/powerpc/kernel/time.c67
-rw-r--r--arch/powerpc/kernel/traps.c23
-rw-r--r--arch/powerpc/kernel/udbg.c7
-rw-r--r--arch/powerpc/kernel/vdso.c57
-rw-r--r--arch/powerpc/kernel/vector.S4
-rw-r--r--arch/powerpc/kernel/vio.c344
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S5
-rw-r--r--arch/powerpc/lib/Makefile5
-rw-r--r--arch/powerpc/lib/bitops.c150
-rw-r--r--arch/powerpc/mm/hash_low_32.S34
-rw-r--r--arch/powerpc/mm/hash_low_64.S31
-rw-r--r--arch/powerpc/mm/hash_native_64.c2
-rw-r--r--arch/powerpc/mm/hash_utils_64.c84
-rw-r--r--arch/powerpc/mm/lmb.c43
-rw-r--r--arch/powerpc/mm/mem.c6
-rw-r--r--arch/powerpc/mm/mmu_context_32.c2
-rw-r--r--arch/powerpc/mm/mmu_context_64.c3
-rw-r--r--arch/powerpc/mm/numa.c8
-rw-r--r--arch/powerpc/mm/ppc_mmu_32.c16
-rw-r--r--arch/powerpc/mm/slb.c32
-rw-r--r--arch/powerpc/mm/slb_low.S17
-rw-r--r--arch/powerpc/mm/stab.c4
-rw-r--r--arch/powerpc/mm/tlb_32.c6
-rw-r--r--arch/powerpc/mm/tlb_64.c5
-rw-r--r--arch/powerpc/oprofile/Kconfig1
-rw-r--r--arch/powerpc/oprofile/Makefile4
-rw-r--r--arch/powerpc/oprofile/common.c6
-rw-r--r--arch/powerpc/oprofile/op_model_power4.c37
-rw-r--r--arch/powerpc/platforms/85xx/Kconfig9
-rw-r--r--arch/powerpc/platforms/85xx/Makefile1
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_cds.c359
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_cds.h43
-rw-r--r--arch/powerpc/platforms/86xx/Kconfig36
-rw-r--r--arch/powerpc/platforms/86xx/Makefile10
-rw-r--r--arch/powerpc/platforms/86xx/mpc8641_hpcn.h54
-rw-r--r--arch/powerpc/platforms/86xx/mpc86xx.h28
-rw-r--r--arch/powerpc/platforms/86xx/mpc86xx_hpcn.c326
-rw-r--r--arch/powerpc/platforms/86xx/mpc86xx_pcie.c173
-rw-r--r--arch/powerpc/platforms/86xx/mpc86xx_smp.c117
-rw-r--r--arch/powerpc/platforms/86xx/pci.c325
-rw-r--r--arch/powerpc/platforms/Makefile1
-rw-r--r--arch/powerpc/platforms/cell/Kconfig9
-rw-r--r--arch/powerpc/platforms/cell/Makefile23
-rw-r--r--arch/powerpc/platforms/cell/cbe_regs.c128
-rw-r--r--arch/powerpc/platforms/cell/cbe_regs.h129
-rw-r--r--arch/powerpc/platforms/cell/interrupt.c42
-rw-r--r--arch/powerpc/platforms/cell/iommu.c18
-rw-r--r--arch/powerpc/platforms/cell/pervasive.c104
-rw-r--r--arch/powerpc/platforms/cell/pervasive.h37
-rw-r--r--arch/powerpc/platforms/cell/ras.c112
-rw-r--r--arch/powerpc/platforms/cell/ras.h9
-rw-r--r--arch/powerpc/platforms/cell/setup.c14
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c179
-rw-r--r--arch/powerpc/platforms/cell/spu_callbacks.c314
-rw-r--r--arch/powerpc/platforms/cell/spu_priv1.c133
-rw-r--r--arch/powerpc/platforms/cell/spu_priv1_mmio.c159
-rw-r--r--arch/powerpc/platforms/cell/spufs/Makefile14
-rw-r--r--arch/powerpc/platforms/cell/spufs/context.c12
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c67
-rw-r--r--arch/powerpc/platforms/cell/spufs/hw_ops.c1
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c36
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c3
-rw-r--r--arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped1122
-rw-r--r--arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped922
-rw-r--r--arch/powerpc/platforms/cell/spufs/switch.c48
-rw-r--r--arch/powerpc/platforms/iseries/Makefile6
-rw-r--r--arch/powerpc/platforms/iseries/call_pci.h19
-rw-r--r--arch/powerpc/platforms/iseries/dt.c615
-rw-r--r--arch/powerpc/platforms/iseries/iommu.c46
-rw-r--r--arch/powerpc/platforms/iseries/irq.c7
-rw-r--r--arch/powerpc/platforms/iseries/irq.h2
-rw-r--r--arch/powerpc/platforms/iseries/mf.c9
-rw-r--r--arch/powerpc/platforms/iseries/pci.c347
-rw-r--r--arch/powerpc/platforms/iseries/setup.c271
-rw-r--r--arch/powerpc/platforms/iseries/setup.h2
-rw-r--r--arch/powerpc/platforms/iseries/vio.c131
-rw-r--r--arch/powerpc/platforms/maple/pci.c3
-rw-r--r--arch/powerpc/platforms/maple/setup.c2
-rw-r--r--arch/powerpc/platforms/powermac/backlight.c270
-rw-r--r--arch/powerpc/platforms/powermac/cpufreq_32.c2
-rw-r--r--arch/powerpc/platforms/powermac/feature.c2
-rw-r--r--arch/powerpc/platforms/powermac/pci.c3
-rw-r--r--arch/powerpc/platforms/powermac/pfunc_core.c14
-rw-r--r--arch/powerpc/platforms/powermac/setup.c2
-rw-r--r--arch/powerpc/platforms/pseries/Makefile5
-rw-r--r--arch/powerpc/platforms/pseries/eeh_cache.c2
-rw-r--r--arch/powerpc/platforms/pseries/eeh_driver.c55
-rw-r--r--arch/powerpc/platforms/pseries/eeh_event.c50
-rw-r--r--arch/powerpc/platforms/pseries/iommu.c182
-rw-r--r--arch/powerpc/platforms/pseries/rtasd.c6
-rw-r--r--arch/powerpc/platforms/pseries/scanlog.c6
-rw-r--r--arch/powerpc/platforms/pseries/setup.c6
-rw-r--r--arch/powerpc/platforms/pseries/vio.c274
-rw-r--r--arch/powerpc/platforms/pseries/xics.c25
-rw-r--r--arch/powerpc/sysdev/Makefile4
-rw-r--r--arch/powerpc/sysdev/dart_iommu.c2
-rw-r--r--arch/powerpc/sysdev/mpic.c20
-rw-r--r--arch/powerpc/xmon/xmon.c3
-rw-r--r--arch/ppc/Kconfig4
-rw-r--r--arch/ppc/boot/lib/Makefile2
-rw-r--r--arch/ppc/kernel/pci.c1
-rw-r--r--arch/ppc/mm/init.c2
-rw-r--r--arch/ppc/mm/mmu_context.c2
-rw-r--r--arch/ppc/mm/tlb.c6
-rw-r--r--arch/ppc/platforms/4xx/Kconfig2
-rw-r--r--arch/ppc/platforms/4xx/cpci405.c139
-rw-r--r--arch/ppc/platforms/4xx/cpci405.h30
-rw-r--r--arch/ppc/platforms/85xx/mpc85xx_cds_common.c9
-rw-r--r--arch/s390/Kconfig8
-rw-r--r--arch/s390/Makefile2
-rw-r--r--arch/s390/hypfs/Makefile7
-rw-r--r--arch/s390/hypfs/hypfs.h30
-rw-r--r--arch/s390/hypfs/hypfs_diag.c696
-rw-r--r--arch/s390/hypfs/hypfs_diag.h16
-rw-r--r--arch/s390/hypfs/inode.c491
-rw-r--r--arch/s390/kernel/setup.c15
-rw-r--r--arch/sh64/kernel/signal.c2
-rw-r--r--arch/sparc/kernel/Makefile2
-rw-r--r--arch/sparc/kernel/ebus.c185
-rw-r--r--arch/sparc/kernel/ioport.c131
-rw-r--r--arch/sparc/kernel/of_device.c268
-rw-r--r--arch/sparc/kernel/pcic.c3
-rw-r--r--arch/sparc/kernel/prom.c474
-rw-r--r--arch/sparc/kernel/setup.c2
-rw-r--r--arch/sparc/mm/init.c2
-rw-r--r--arch/sparc64/defconfig12
-rw-r--r--arch/sparc64/kernel/Makefile2
-rw-r--r--arch/sparc64/kernel/auxio.c109
-rw-r--r--arch/sparc64/kernel/central.c127
-rw-r--r--arch/sparc64/kernel/chmc.c69
-rw-r--r--arch/sparc64/kernel/devices.c222
-rw-r--r--arch/sparc64/kernel/ebus.c197
-rw-r--r--arch/sparc64/kernel/irq.c19
-rw-r--r--arch/sparc64/kernel/isa.c183
-rw-r--r--arch/sparc64/kernel/of_device.c279
-rw-r--r--arch/sparc64/kernel/pci.c59
-rw-r--r--arch/sparc64/kernel/pci_common.c227
-rw-r--r--arch/sparc64/kernel/pci_impl.h3
-rw-r--r--arch/sparc64/kernel/pci_psycho.c106
-rw-r--r--arch/sparc64/kernel/pci_sabre.c195
-rw-r--r--arch/sparc64/kernel/pci_schizo.c171
-rw-r--r--arch/sparc64/kernel/pci_sun4v.c160
-rw-r--r--arch/sparc64/kernel/power.c113
-rw-r--r--arch/sparc64/kernel/prom.c650
-rw-r--r--arch/sparc64/kernel/sbus.c67
-rw-r--r--arch/sparc64/kernel/setup.c4
-rw-r--r--arch/sparc64/kernel/smp.c41
-rw-r--r--arch/sparc64/kernel/time.c386
-rw-r--r--arch/sparc64/kernel/traps.c18
-rw-r--r--arch/sparc64/kernel/unaligned.c9
-rw-r--r--arch/sparc64/mm/init.c52
-rw-r--r--arch/sparc64/solaris/fs.c4
-rw-r--r--arch/sparc64/solaris/misc.c34
-rw-r--r--arch/um/Kconfig.debug1
-rw-r--r--arch/um/drivers/mconsole_kern.c2
-rw-r--r--arch/um/include/sysdep-x86_64/syscalls.h2
-rw-r--r--arch/um/kernel/time_kern.c2
-rw-r--r--arch/um/sys-ppc/misc.S6
-rw-r--r--arch/v850/kernel/signal.c2
-rw-r--r--arch/x86_64/Kconfig6
-rw-r--r--arch/x86_64/ia32/ia32entry.S1
-rw-r--r--arch/x86_64/kernel/acpi/Makefile1
-rw-r--r--arch/x86_64/kernel/acpi/processor.c72
-rw-r--r--arch/x86_64/kernel/acpi/sleep.c7
-rw-r--r--arch/x86_64/kernel/apic.c2
-rw-r--r--arch/x86_64/kernel/i387.c2
-rw-r--r--arch/x86_64/kernel/setup.c97
-rw-r--r--arch/x86_64/mm/srat.c33
-rw-r--r--arch/x86_64/pci/mmconfig.c13
-rw-r--r--arch/xtensa/Kconfig4
-rw-r--r--arch/xtensa/boot/lib/Makefile2
-rw-r--r--arch/xtensa/kernel/entry.S2
-rw-r--r--arch/xtensa/kernel/pci.c12
-rw-r--r--arch/xtensa/kernel/signal.c12
-rw-r--r--block/Kconfig.iosched2
-rw-r--r--block/as-iosched.c64
-rw-r--r--block/cfq-iosched.c199
-rw-r--r--block/deadline-iosched.c52
-rw-r--r--block/elevator.c3
-rw-r--r--block/ll_rw_blk.c15
-rw-r--r--drivers/acpi/Kconfig5
-rw-r--r--drivers/acpi/acpi_memhotplug.c12
-rw-r--r--drivers/acpi/asus_acpi.c32
-rw-r--r--drivers/acpi/bus.c22
-rw-r--r--drivers/acpi/dispatcher/dsfield.c13
-rw-r--r--drivers/acpi/dispatcher/dsinit.c6
-rw-r--r--drivers/acpi/dispatcher/dsmethod.c232
-rw-r--r--drivers/acpi/dispatcher/dsmthdat.c43
-rw-r--r--drivers/acpi/dispatcher/dsobject.c25
-rw-r--r--drivers/acpi/dispatcher/dsopcode.c63
-rw-r--r--drivers/acpi/dispatcher/dsutils.c25
-rw-r--r--drivers/acpi/dispatcher/dswexec.c26
-rw-r--r--drivers/acpi/dispatcher/dswload.c67
-rw-r--r--drivers/acpi/dispatcher/dswscope.c10
-rw-r--r--drivers/acpi/dispatcher/dswstate.c72
-rw-r--r--drivers/acpi/ec.c72
-rw-r--r--drivers/acpi/events/evevent.c10
-rw-r--r--drivers/acpi/events/evgpe.c85
-rw-r--r--drivers/acpi/events/evgpeblk.c96
-rw-r--r--drivers/acpi/events/evmisc.c41
-rw-r--r--drivers/acpi/events/evregion.c115
-rw-r--r--drivers/acpi/events/evrgnini.c48
-rw-r--r--drivers/acpi/events/evsci.c8
-rw-r--r--drivers/acpi/events/evxface.c49
-rw-r--r--drivers/acpi/events/evxfevnt.c67
-rw-r--r--drivers/acpi/events/evxfregn.c15
-rw-r--r--drivers/acpi/executer/exconfig.c54
-rw-r--r--drivers/acpi/executer/exconvrt.c12
-rw-r--r--drivers/acpi/executer/excreate.c25
-rw-r--r--drivers/acpi/executer/exdump.c36
-rw-r--r--drivers/acpi/executer/exfield.c18
-rw-r--r--drivers/acpi/executer/exfldio.c67
-rw-r--r--drivers/acpi/executer/exmisc.c25
-rw-r--r--drivers/acpi/executer/exmutex.c15
-rw-r--r--drivers/acpi/executer/exnames.c28
-rw-r--r--drivers/acpi/executer/exoparg1.c101
-rw-r--r--drivers/acpi/executer/exoparg2.c89
-rw-r--r--drivers/acpi/executer/exoparg3.c17
-rw-r--r--drivers/acpi/executer/exoparg6.c3
-rw-r--r--drivers/acpi/executer/exprep.c45
-rw-r--r--drivers/acpi/executer/exregion.c40
-rw-r--r--drivers/acpi/executer/exresnte.c17
-rw-r--r--drivers/acpi/executer/exresolv.c77
-rw-r--r--drivers/acpi/executer/exresop.c12
-rw-r--r--drivers/acpi/executer/exstore.c15
-rw-r--r--drivers/acpi/executer/exstoren.c7
-rw-r--r--drivers/acpi/executer/exstorob.c17
-rw-r--r--drivers/acpi/executer/exsystem.c12
-rw-r--r--drivers/acpi/executer/exutils.c17
-rw-r--r--drivers/acpi/fan.c40
-rw-r--r--drivers/acpi/hardware/hwacpi.c6
-rw-r--r--drivers/acpi/hardware/hwgpe.c8
-rw-r--r--drivers/acpi/hardware/hwregs.c146
-rw-r--r--drivers/acpi/hardware/hwsleep.c31
-rw-r--r--drivers/acpi/hardware/hwtimer.c20
-rw-r--r--drivers/acpi/hotkey.c2
-rw-r--r--drivers/acpi/ibm_acpi.c70
-rw-r--r--drivers/acpi/motherboard.c61
-rw-r--r--drivers/acpi/namespace/nsaccess.c46
-rw-r--r--drivers/acpi/namespace/nsalloc.c118
-rw-r--r--drivers/acpi/namespace/nsdump.c15
-rw-r--r--drivers/acpi/namespace/nsdumpdv.c6
-rw-r--r--drivers/acpi/namespace/nseval.c484
-rw-r--r--drivers/acpi/namespace/nsinit.c298
-rw-r--r--drivers/acpi/namespace/nsload.c27
-rw-r--r--drivers/acpi/namespace/nsnames.c14
-rw-r--r--drivers/acpi/namespace/nsobject.c15
-rw-r--r--drivers/acpi/namespace/nsparse.c6
-rw-r--r--drivers/acpi/namespace/nssearch.c148
-rw-r--r--drivers/acpi/namespace/nsutils.c104
-rw-r--r--drivers/acpi/namespace/nswalk.c6
-rw-r--r--drivers/acpi/namespace/nsxfeval.c203
-rw-r--r--drivers/acpi/namespace/nsxfname.c22
-rw-r--r--drivers/acpi/namespace/nsxfobj.c11
-rw-r--r--drivers/acpi/numa.c48
-rw-r--r--drivers/acpi/osl.c159
-rw-r--r--drivers/acpi/parser/psargs.c25
-rw-r--r--drivers/acpi/parser/psloop.c25
-rw-r--r--drivers/acpi/parser/psopcode.c6
-rw-r--r--drivers/acpi/parser/psparse.c35
-rw-r--r--drivers/acpi/parser/psscope.c17
-rw-r--r--drivers/acpi/parser/pstree.c8
-rw-r--r--drivers/acpi/parser/psutils.c5
-rw-r--r--drivers/acpi/parser/pswalk.c5
-rw-r--r--drivers/acpi/parser/psxface.c46
-rw-r--r--drivers/acpi/pci_link.c25
-rw-r--r--drivers/acpi/processor_core.c16
-rw-r--r--drivers/acpi/processor_idle.c8
-rw-r--r--drivers/acpi/processor_perflib.c247
-rw-r--r--drivers/acpi/resources/rscalc.c108
-rw-r--r--drivers/acpi/resources/rscreate.c33
-rw-r--r--drivers/acpi/resources/rsdump.c42
-rw-r--r--drivers/acpi/resources/rsinfo.c1
-rw-r--r--drivers/acpi/resources/rslist.c102
-rw-r--r--drivers/acpi/resources/rsmisc.c12
-rw-r--r--drivers/acpi/resources/rsutils.c155
-rw-r--r--drivers/acpi/resources/rsxface.c395
-rw-r--r--drivers/acpi/scan.c178
-rw-r--r--drivers/acpi/sleep/main.c8
-rw-r--r--drivers/acpi/sleep/wakeup.c3
-rw-r--r--drivers/acpi/system.c6
-rw-r--r--drivers/acpi/tables.c4
-rw-r--r--drivers/acpi/tables/tbconvrt.c46
-rw-r--r--drivers/acpi/tables/tbget.c65
-rw-r--r--drivers/acpi/tables/tbgetall.c11
-rw-r--r--drivers/acpi/tables/tbinstal.c50
-rw-r--r--drivers/acpi/tables/tbrsdt.c46
-rw-r--r--drivers/acpi/tables/tbutils.c149
-rw-r--r--drivers/acpi/tables/tbxface.c42
-rw-r--r--drivers/acpi/tables/tbxfroot.c82
-rw-r--r--drivers/acpi/thermal.c25
-rw-r--r--drivers/acpi/utilities/utalloc.c634
-rw-r--r--drivers/acpi/utilities/utcache.c18
-rw-r--r--drivers/acpi/utilities/utcopy.c41
-rw-r--r--drivers/acpi/utilities/utdebug.c65
-rw-r--r--drivers/acpi/utilities/utdelete.c62
-rw-r--r--drivers/acpi/utilities/uteval.c141
-rw-r--r--drivers/acpi/utilities/utglobal.c62
-rw-r--r--drivers/acpi/utilities/utinit.c26
-rw-r--r--drivers/acpi/utilities/utmath.c8
-rw-r--r--drivers/acpi/utilities/utmisc.c293
-rw-r--r--drivers/acpi/utilities/utmutex.c42
-rw-r--r--drivers/acpi/utilities/utobject.c23
-rw-r--r--drivers/acpi/utilities/utresrc.c256
-rw-r--r--drivers/acpi/utilities/utstate.c36
-rw-r--r--drivers/acpi/utilities/utxface.c44
-rw-r--r--drivers/acpi/utils.c2
-rw-r--r--drivers/acpi/video.c23
-rw-r--r--drivers/base/core.c19
-rw-r--r--drivers/base/power/Makefile1
-rw-r--r--drivers/base/power/resume.c4
-rw-r--r--drivers/base/power/trace.c228
-rw-r--r--drivers/block/Kconfig1
-rw-r--r--drivers/block/amiflop.c1
-rw-r--r--drivers/block/cciss.c3216
-rw-r--r--drivers/block/cciss.h2
-rw-r--r--drivers/block/cpqarray.c9
-rw-r--r--drivers/block/loop.c26
-rw-r--r--drivers/block/nbd.c34
-rw-r--r--drivers/block/viodasd.c2
-rw-r--r--drivers/cdrom/mcdx.c2
-rw-r--r--drivers/cdrom/viocd.c2
-rw-r--r--drivers/char/Kconfig1
-rw-r--r--drivers/char/agp/Kconfig3
-rw-r--r--drivers/char/agp/hp-agp.c2
-rw-r--r--drivers/char/applicom.c40
-rw-r--r--drivers/char/cyclades.c7
-rw-r--r--drivers/char/drm/i915_dma.c4
-rw-r--r--drivers/char/drm/i915_drm.h13
-rw-r--r--drivers/char/drm/i915_drv.h6
-rw-r--r--drivers/char/drm/i915_irq.c69
-rw-r--r--drivers/char/drm/radeon_cp.c6
-rw-r--r--drivers/char/drm/radeon_drm.h7
-rw-r--r--drivers/char/drm/radeon_drv.h10
-rw-r--r--drivers/char/drm/radeon_state.c39
-rw-r--r--drivers/char/esp.c4
-rw-r--r--drivers/char/hpet.c5
-rw-r--r--drivers/char/hvc_console.c4
-rw-r--r--drivers/char/hvc_rtas.c37
-rw-r--r--drivers/char/hvsi.c2
-rw-r--r--drivers/char/ip2/ip2main.c12
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c25
-rw-r--r--drivers/char/isicom.c4
-rw-r--r--drivers/char/keyboard.c1
-rw-r--r--drivers/char/mmtimer.c1
-rw-r--r--drivers/char/mxser.c836
-rw-r--r--drivers/char/n_r3964.c3
-rw-r--r--drivers/char/pcmcia/synclink_cs.c58
-rw-r--r--drivers/char/rocket.c62
-rw-r--r--drivers/char/rtc.c4
-rw-r--r--drivers/char/sonypi.c10
-rw-r--r--drivers/char/specialix.c4
-rw-r--r--drivers/char/synclink_gt.c119
-rw-r--r--drivers/char/synclinkmp.c4
-rw-r--r--drivers/char/viotape.c2
-rw-r--r--drivers/connector/cn_proc.c1
-rw-r--r--drivers/connector/connector.c7
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c13
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c13
-rw-r--r--drivers/firmware/Kconfig3
-rw-r--r--drivers/firmware/dmi_scan.c13
-rw-r--r--drivers/hwmon/Kconfig65
-rw-r--r--drivers/hwmon/Makefile4
-rw-r--r--drivers/hwmon/abituguru.c1415
-rw-r--r--drivers/hwmon/f71805f.c15
-rw-r--r--drivers/hwmon/hdaps.c8
-rw-r--r--drivers/hwmon/hwmon-vid.c44
-rw-r--r--drivers/hwmon/lm70.c165
-rw-r--r--drivers/hwmon/lm83.c50
-rw-r--r--drivers/hwmon/smsc47m192.c648
-rw-r--r--drivers/hwmon/w83627ehf.c170
-rw-r--r--drivers/hwmon/w83791d.c1255
-rw-r--r--drivers/hwmon/w83792d.c86
-rw-r--r--drivers/i2c/busses/Kconfig26
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-i801.c154
-rw-r--r--drivers/i2c/busses/i2c-nforce2.c38
-rw-r--r--drivers/i2c/busses/i2c-ocores.c341
-rw-r--r--drivers/i2c/busses/i2c-piix4.c33
-rw-r--r--drivers/i2c/busses/scx200_acb.c202
-rw-r--r--drivers/i2c/chips/Kconfig8
-rw-r--r--drivers/i2c/chips/m41t00.c346
-rw-r--r--drivers/i2c/i2c-core.c4
-rw-r--r--drivers/i2c/i2c-dev.c5
-rw-r--r--drivers/ide/ide-cd.c128
-rw-r--r--drivers/ide/ide-dma.c6
-rw-r--r--drivers/ide/ide-floppy.c14
-rw-r--r--drivers/ide/ide-io.c148
-rw-r--r--drivers/ide/ide-iops.c12
-rw-r--r--drivers/ide/ide-lib.c3
-rw-r--r--drivers/ide/ide-tape.c49
-rw-r--r--drivers/ide/ide-taskfile.c3
-rw-r--r--drivers/ide/ide.c8
-rw-r--r--drivers/ide/legacy/q40ide.c1
-rw-r--r--drivers/ide/pci/amd74xx.c7
-rw-r--r--drivers/ide/pci/sgiioc4.c6
-rw-r--r--drivers/ide/pci/trm290.c3
-rw-r--r--drivers/ieee1394/nodemgr.c5
-rw-r--r--drivers/infiniband/core/uverbs_main.c7
-rw-r--r--drivers/infiniband/hw/ipath/ipath_fs.c13
-rw-r--r--drivers/input/evdev.c2
-rw-r--r--drivers/input/keyboard/amikbd.c34
-rw-r--r--drivers/input/misc/Kconfig2
-rw-r--r--drivers/input/misc/sparcspkr.c218
-rw-r--r--drivers/input/serio/i8042-sparcio.h10
-rw-r--r--drivers/input/touchscreen/ads7846.c3
-rw-r--r--drivers/input/touchscreen/h3600_ts_input.c6
-rw-r--r--drivers/isdn/capi/capifs.c6
-rw-r--r--drivers/isdn/i4l/isdn_common.c8
-rw-r--r--drivers/isdn/sc/ioctl.c1
-rw-r--r--drivers/leds/Kconfig15
-rw-r--r--drivers/leds/Makefile2
-rw-r--r--drivers/leds/leds-ams-delta.c162
-rw-r--r--drivers/leds/ledtrig-heartbeat.c118
-rw-r--r--drivers/macintosh/Kconfig20
-rw-r--r--drivers/macintosh/Makefile1
-rw-r--r--drivers/macintosh/adbhid.c28
-rw-r--r--drivers/macintosh/via-pmu-backlight.c150
-rw-r--r--drivers/macintosh/via-pmu.c124
-rw-r--r--drivers/md/raid6algos.c7
-rw-r--r--drivers/media/Kconfig7
-rw-r--r--drivers/media/common/Makefile2
-rw-r--r--drivers/media/common/ir-functions.c1
-rw-r--r--drivers/media/common/ir-keymaps.c82
-rw-r--r--drivers/media/common/saa7146_fops.c4
-rw-r--r--drivers/media/common/saa7146_hlp.c1
-rw-r--r--drivers/media/common/saa7146_video.c2
-rw-r--r--drivers/media/common/saa7146_vv_ksyms.c12
-rw-r--r--drivers/media/dvb/b2c2/flexcop-fe-tuner.c122
-rw-r--r--drivers/media/dvb/b2c2/flexcop-pci.c19
-rw-r--r--drivers/media/dvb/b2c2/flexcop-usb.c10
-rw-r--r--drivers/media/dvb/b2c2/flexcop.c12
-rw-r--r--drivers/media/dvb/bt8xx/bt878.c11
-rw-r--r--drivers/media/dvb/bt8xx/dst.c606
-rw-r--r--drivers/media/dvb/bt8xx/dst_ca.c116
-rw-r--r--drivers/media/dvb/bt8xx/dst_common.h33
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.c118
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.h2
-rw-r--r--drivers/media/dvb/cinergyT2/Kconfig2
-rw-r--r--drivers/media/dvb/cinergyT2/cinergyT2.c8
-rw-r--r--drivers/media/dvb/dvb-core/Makefile6
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c3
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ca_en50221.c25
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.c4
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c151
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h45
-rw-r--r--drivers/media/dvb/dvb-core/dvb_math.c145
-rw-r--r--drivers/media/dvb/dvb-core/dvb_math.h58
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c230
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.c5
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.h4
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig10
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile3
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c48
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-common.c9
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mb.c7
-rw-r--r--drivers/media/dvb/dvb-usb/digitv.c15
-rw-r--r--drivers/media/dvb/dvb-usb/dtt200u-fe.c8
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-dvb.c17
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-i2c.c24
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h4
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb.h6
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk-fe.c272
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk.c256
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk.h79
-rw-r--r--drivers/media/dvb/dvb-usb/umt-010.c2
-rw-r--r--drivers/media/dvb/dvb-usb/vp702x-fe.c7
-rw-r--r--drivers/media/dvb/dvb-usb/vp7045-fe.c9
-rw-r--r--drivers/media/dvb/frontends/Kconfig18
-rw-r--r--drivers/media/dvb/frontends/Makefile2
-rw-r--r--drivers/media/dvb/frontends/bcm3510.c4
-rw-r--r--drivers/media/dvb/frontends/bsbe1.h6
-rw-r--r--drivers/media/dvb/frontends/bsru6.h6
-rw-r--r--drivers/media/dvb/frontends/cx22700.c31
-rw-r--r--drivers/media/dvb/frontends/cx22700.h4
-rw-r--r--drivers/media/dvb/frontends/cx22702.c29
-rw-r--r--drivers/media/dvb/frontends/cx22702.h7
-rw-r--r--drivers/media/dvb/frontends/cx24110.c26
-rw-r--r--drivers/media/dvb/frontends/cx24110.h5
-rw-r--r--drivers/media/dvb/frontends/cx24123.c195
-rw-r--r--drivers/media/dvb/frontends/cx24123.h13
-rw-r--r--drivers/media/dvb/frontends/dib3000-common.h2
-rw-r--r--drivers/media/dvb/frontends/dib3000.h4
-rw-r--r--drivers/media/dvb/frontends/dib3000mb.c11
-rw-r--r--drivers/media/dvb/frontends/dib3000mc.c14
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c181
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.h18
-rw-r--r--drivers/media/dvb/frontends/dvb_dummy_fe.c21
-rw-r--r--drivers/media/dvb/frontends/isl6421.c149
-rw-r--r--drivers/media/dvb/frontends/isl6421.h46
-rw-r--r--drivers/media/dvb/frontends/l64781.c11
-rw-r--r--drivers/media/dvb/frontends/l64781.h4
-rw-r--r--drivers/media/dvb/frontends/lg_h06xf.h64
-rw-r--r--drivers/media/dvb/frontends/lgdt330x.c19
-rw-r--r--drivers/media/dvb/frontends/lgdt330x.h1
-rw-r--r--drivers/media/dvb/frontends/lnbp21.c145
-rw-r--r--drivers/media/dvb/frontends/lnbp21.h102
-rw-r--r--drivers/media/dvb/frontends/mt312.c46
-rw-r--r--drivers/media/dvb/frontends/mt312.h4
-rw-r--r--drivers/media/dvb/frontends/mt352.c23
-rw-r--r--drivers/media/dvb/frontends/mt352.h6
-rw-r--r--drivers/media/dvb/frontends/nxt200x.c20
-rw-r--r--drivers/media/dvb/frontends/nxt200x.h4
-rw-r--r--drivers/media/dvb/frontends/nxt6000.c29
-rw-r--r--drivers/media/dvb/frontends/nxt6000.h4
-rw-r--r--drivers/media/dvb/frontends/or51132.c157
-rw-r--r--drivers/media/dvb/frontends/or51132.h2
-rw-r--r--drivers/media/dvb/frontends/or51211.c4
-rw-r--r--drivers/media/dvb/frontends/s5h1420.c43
-rw-r--r--drivers/media/dvb/frontends/s5h1420.h4
-rw-r--r--drivers/media/dvb/frontends/sp8870.c31
-rw-r--r--drivers/media/dvb/frontends/sp8870.h4
-rw-r--r--drivers/media/dvb/frontends/sp887x.c38
-rw-r--r--drivers/media/dvb/frontends/sp887x.h6
-rw-r--r--drivers/media/dvb/frontends/stv0297.c73
-rw-r--r--drivers/media/dvb/frontends/stv0297.h6
-rw-r--r--drivers/media/dvb/frontends/stv0299.c41
-rw-r--r--drivers/media/dvb/frontends/stv0299.h5
-rw-r--r--drivers/media/dvb/frontends/tda10021.c39
-rw-r--r--drivers/media/dvb/frontends/tda10021.h6
-rw-r--r--drivers/media/dvb/frontends/tda1004x.c55
-rw-r--r--drivers/media/dvb/frontends/tda1004x.h5
-rw-r--r--drivers/media/dvb/frontends/tda8083.c12
-rw-r--r--drivers/media/dvb/frontends/tda8083.h4
-rw-r--r--drivers/media/dvb/frontends/ves1820.c19
-rw-r--r--drivers/media/dvb/frontends/ves1820.h4
-rw-r--r--drivers/media/dvb/frontends/ves1x93.c29
-rw-r--r--drivers/media/dvb/frontends/ves1x93.h4
-rw-r--r--drivers/media/dvb/frontends/zl10353.c30
-rw-r--r--drivers/media/dvb/frontends/zl10353.h6
-rw-r--r--drivers/media/dvb/pluto2/pluto2.c15
-rw-r--r--drivers/media/dvb/ttpci/Kconfig3
-rw-r--r--drivers/media/dvb/ttpci/Makefile6
-rw-r--r--drivers/media/dvb/ttpci/av7110.c135
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c283
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c59
-rw-r--r--drivers/media/dvb/ttpci/budget-core.c4
-rw-r--r--drivers/media/dvb/ttpci/budget-patch.c43
-rw-r--r--drivers/media/dvb/ttpci/budget.c69
-rw-r--r--drivers/media/dvb/ttusb-budget/Kconfig2
-rw-r--r--drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c264
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusb_dec.c6
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusbdecfe.c8
-rw-r--r--drivers/media/radio/Kconfig2
-rw-r--r--drivers/media/radio/Makefile2
-rw-r--r--drivers/media/radio/miropcm20-radio.c17
-rw-r--r--drivers/media/radio/miropcm20-rds-core.c34
-rw-r--r--drivers/media/radio/miropcm20-rds.c2
-rw-r--r--drivers/media/radio/radio-aimslab.c51
-rw-r--r--drivers/media/radio/radio-aztech.c45
-rw-r--r--drivers/media/radio/radio-cadet.c317
-rw-r--r--drivers/media/radio/radio-gemtek-pci.c47
-rw-r--r--drivers/media/radio/radio-gemtek.c33
-rw-r--r--drivers/media/radio/radio-maestro.c10
-rw-r--r--drivers/media/radio/radio-maxiradio.c81
-rw-r--r--drivers/media/radio/radio-rtrack2.c35
-rw-r--r--drivers/media/radio/radio-sf16fmi.c41
-rw-r--r--drivers/media/radio/radio-sf16fmr2.c5
-rw-r--r--drivers/media/radio/radio-terratec.c63
-rw-r--r--drivers/media/radio/radio-trust.c27
-rw-r--r--drivers/media/radio/radio-typhoon.c5
-rw-r--r--drivers/media/radio/radio-zoltrix.c31
-rw-r--r--drivers/media/video/Kconfig79
-rw-r--r--drivers/media/video/Makefile7
-rw-r--r--drivers/media/video/arv.c3
-rw-r--r--drivers/media/video/bt866.c377
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c10
-rw-r--r--drivers/media/video/bt8xx/bttv-gpio.c14
-rw-r--r--drivers/media/video/bt8xx/bttv-input.c2
-rw-r--r--drivers/media/video/bt8xx/bttv.h1
-rw-r--r--drivers/media/video/bt8xx/bttvp.h2
-rw-r--r--drivers/media/video/bw-qcam.c3
-rw-r--r--drivers/media/video/c-qcam.c1
-rw-r--r--drivers/media/video/cpia.c22
-rw-r--r--drivers/media/video/cpia.h3
-rw-r--r--drivers/media/video/cpia2/cpia2.h1
-rw-r--r--drivers/media/video/cpia2/cpia2_v4l.c6
-rw-r--r--drivers/media/video/cpia_pp.c8
-rw-r--r--drivers/media/video/cpia_usb.c6
-rw-r--r--drivers/media/video/cx2341x.c915
-rw-r--r--drivers/media/video/cx25840/cx25840-audio.c54
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c306
-rw-r--r--drivers/media/video/cx25840/cx25840-core.h8
-rw-r--r--drivers/media/video/cx25840/cx25840-vbi.c177
-rw-r--r--drivers/media/video/cx88/Kconfig3
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c5
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c875
-rw-r--r--drivers/media/video/cx88/cx88-cards.c150
-rw-r--r--drivers/media/video/cx88/cx88-core.c8
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c252
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c8
-rw-r--r--drivers/media/video/cx88/cx88-input.c34
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c50
-rw-r--r--drivers/media/video/cx88/cx88-tvaudio.c16
-rw-r--r--drivers/media/video/cx88/cx88-vbi.c4
-rw-r--r--drivers/media/video/cx88/cx88.h25
-rw-r--r--drivers/media/video/dsbr100.c1
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c64
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c12
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c31
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c8
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c22
-rw-r--r--drivers/media/video/em28xx/em28xx.h8
-rw-r--r--drivers/media/video/et61x251/et61x251_core.c3
-rw-r--r--drivers/media/video/ir-kbd-i2c.c60
-rw-r--r--drivers/media/video/ks0127.c846
-rw-r--r--drivers/media/video/ks0127.h53
-rw-r--r--drivers/media/video/meye.c5
-rw-r--r--drivers/media/video/msp3400-driver.c112
-rw-r--r--drivers/media/video/msp3400-kthreads.c40
-rw-r--r--drivers/media/video/ov511.c4
-rw-r--r--drivers/media/video/ov511.h1
-rw-r--r--drivers/media/video/planb.c1
-rw-r--r--drivers/media/video/pms.c3
-rw-r--r--drivers/media/video/pwc/Kconfig13
-rw-r--r--drivers/media/video/pwc/Makefile11
-rw-r--r--drivers/media/video/pwc/pwc-ctrl.c699
-rw-r--r--drivers/media/video/pwc/pwc-dec1.c50
-rw-r--r--drivers/media/video/pwc/pwc-dec1.h43
-rw-r--r--drivers/media/video/pwc/pwc-dec23.c941
-rw-r--r--drivers/media/video/pwc/pwc-dec23.h67
-rw-r--r--drivers/media/video/pwc/pwc-if.c1341
-rw-r--r--drivers/media/video/pwc/pwc-kiara.c575
-rw-r--r--drivers/media/video/pwc/pwc-kiara.h8
-rw-r--r--drivers/media/video/pwc/pwc-misc.c67
-rw-r--r--drivers/media/video/pwc/pwc-timon.c1132
-rw-r--r--drivers/media/video/pwc/pwc-timon.h8
-rw-r--r--drivers/media/video/pwc/pwc-uncompress.c154
-rw-r--r--drivers/media/video/pwc/pwc-uncompress.h4
-rw-r--r--drivers/media/video/pwc/pwc-v4l.c1202
-rw-r--r--drivers/media/video/pwc/pwc.h174
-rw-r--r--drivers/media/video/saa5246a.c1
-rw-r--r--drivers/media/video/saa5249.c1
-rw-r--r--drivers/media/video/saa7110.c1
-rw-r--r--drivers/media/video/saa7115.c137
-rw-r--r--drivers/media/video/saa7127.c2
-rw-r--r--drivers/media/video/saa7134/saa6752hs.c315
-rw-r--r--drivers/media/video/saa7134/saa7134-alsa.c2
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c58
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c259
-rw-r--r--drivers/media/video/saa7134/saa7134-empress.c24
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c13
-rw-r--r--drivers/media/video/saa7134/saa7134.h3
-rw-r--r--drivers/media/video/se401.h1
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c3
-rw-r--r--drivers/media/video/stradis.c1
-rw-r--r--drivers/media/video/stv680.c1
-rw-r--r--drivers/media/video/tda9875.c3
-rw-r--r--drivers/media/video/tda9887.c461
-rw-r--r--drivers/media/video/tea5767.c2
-rw-r--r--drivers/media/video/tlv320aic23b.c217
-rw-r--r--drivers/media/video/tuner-3036.c1
-rw-r--r--drivers/media/video/tuner-core.c34
-rw-r--r--drivers/media/video/tuner-simple.c2
-rw-r--r--drivers/media/video/tuner-types.c38
-rw-r--r--drivers/media/video/tveeprom.c2
-rw-r--r--drivers/media/video/tvmixer.c8
-rw-r--r--drivers/media/video/tvp5150.c45
-rw-r--r--drivers/media/video/usbvideo/Kconfig12
-rw-r--r--drivers/media/video/usbvideo/Makefile1
-rw-r--r--drivers/media/video/usbvideo/quickcam_messenger.c1120
-rw-r--r--drivers/media/video/usbvideo/quickcam_messenger.h126
-rw-r--r--drivers/media/video/usbvideo/usbvideo.h1
-rw-r--r--drivers/media/video/v4l1-compat.c1
-rw-r--r--drivers/media/video/v4l2-common.c533
-rw-r--r--drivers/media/video/video-buf-dvb.c5
-rw-r--r--drivers/media/video/videodev.c1272
-rw-r--r--drivers/media/video/vino.c2
-rw-r--r--drivers/media/video/vivi.c664
-rw-r--r--drivers/media/video/vpx3220.c1
-rw-r--r--drivers/media/video/w9966.c1
-rw-r--r--drivers/media/video/zc0301/Kconfig6
-rw-r--r--drivers/media/video/zc0301/Makefile2
-rw-r--r--drivers/media/video/zc0301/zc0301_core.c22
-rw-r--r--drivers/media/video/zc0301/zc0301_pas202bcb.c4
-rw-r--r--drivers/media/video/zc0301/zc0301_pb0330.c187
-rw-r--r--drivers/media/video/zc0301/zc0301_sensor.h26
-rw-r--r--drivers/media/video/zoran.h8
-rw-r--r--drivers/media/video/zoran_card.c88
-rw-r--r--drivers/media/video/zoran_device.c2
-rw-r--r--drivers/media/video/zoran_driver.c27
-rw-r--r--drivers/media/video/zoran_procfs.c1
-rw-r--r--drivers/misc/ibmasm/ibmasmfs.c7
-rw-r--r--drivers/mmc/at91_mci.c141
-rw-r--r--drivers/mmc/imxmmc.c2
-rw-r--r--drivers/mmc/omap.c6
-rw-r--r--drivers/mmc/sdhci.c8
-rw-r--r--drivers/net/3c527.c3
-rw-r--r--drivers/net/8139cp.c181
-rw-r--r--drivers/net/82596.c3
-rw-r--r--drivers/net/8390.c10
-rw-r--r--drivers/net/Kconfig23
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/a2065.c3
-rw-r--r--drivers/net/ariadne.c3
-rw-r--r--drivers/net/arm/at91_ether.c156
-rw-r--r--drivers/net/arm/at91_ether.h1
-rw-r--r--drivers/net/arm/ether1.c3
-rw-r--r--drivers/net/arm/ether3.c3
-rw-r--r--drivers/net/atarilance.c3
-rw-r--r--drivers/net/b44.c277
-rw-r--r--drivers/net/b44.h7
-rw-r--r--drivers/net/bnx2.c4
-rw-r--r--drivers/net/cassini.c3
-rw-r--r--drivers/net/chelsio/sge.c4
-rw-r--r--drivers/net/declance.c3
-rw-r--r--drivers/net/depca.c7
-rw-r--r--drivers/net/e1000/e1000_main.c10
-rw-r--r--drivers/net/eepro.c3
-rw-r--r--drivers/net/eexpress.c3
-rw-r--r--drivers/net/epic100.c7
-rw-r--r--drivers/net/eth16i.c3
-rw-r--r--drivers/net/forcedeth.c6
-rw-r--r--drivers/net/hp100.c7
-rw-r--r--drivers/net/ibmveth.c2
-rw-r--r--drivers/net/ioc3-eth.c2
-rw-r--r--drivers/net/irda/irda-usb.c2
-rw-r--r--drivers/net/iseries_veth.c27
-rw-r--r--drivers/net/ixgb/ixgb_main.c4
-rw-r--r--drivers/net/lance.c3
-rw-r--r--drivers/net/lasi_82596.c3
-rw-r--r--drivers/net/loopback.c4
-rw-r--r--drivers/net/lp486e.c3
-rw-r--r--drivers/net/myri10ge/myri10ge.c17
-rw-r--r--drivers/net/myri_sbus.c116
-rw-r--r--drivers/net/myri_sbus.h1
-rw-r--r--drivers/net/netx-eth.c516
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c3
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c5
-rw-r--r--drivers/net/phy/Kconfig5
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/vitesse.c112
-rw-r--r--drivers/net/r8169.c5
-rw-r--r--drivers/net/s2io.c64
-rw-r--r--drivers/net/seeq8005.c3
-rw-r--r--drivers/net/sis190.c3
-rw-r--r--drivers/net/sk98lin/skge.c2
-rw-r--r--drivers/net/skge.c3
-rw-r--r--drivers/net/sky2.c4
-rw-r--r--drivers/net/smc9194.c3
-rw-r--r--drivers/net/sonic.c3
-rw-r--r--drivers/net/starfire.c3
-rw-r--r--drivers/net/sun3lance.c2
-rw-r--r--drivers/net/sunbmac.c127
-rw-r--r--drivers/net/sunbmac.h1
-rw-r--r--drivers/net/sundance.c8
-rw-r--r--drivers/net/sungem.c19
-rw-r--r--drivers/net/sunhme.c417
-rw-r--r--drivers/net/sunhme.h1
-rw-r--r--drivers/net/sunlance.c173
-rw-r--r--drivers/net/sunqe.c468
-rw-r--r--drivers/net/tg3.c14
-rw-r--r--drivers/net/tokenring/olympic.c4
-rw-r--r--drivers/net/tulip/tulip_core.c12
-rw-r--r--drivers/net/tun.c3
-rw-r--r--drivers/net/typhoon.c2
-rw-r--r--drivers/net/via-rhine.c7
-rw-r--r--drivers/net/via-velocity.c6
-rw-r--r--drivers/net/wan/c101.c6
-rw-r--r--drivers/net/wan/hdlc_generic.c24
-rw-r--r--drivers/net/wan/n2.c5
-rw-r--r--drivers/net/wan/pci200syn.c1
-rw-r--r--drivers/net/wan/sdla.c4
-rw-r--r--drivers/net/wan/wanxl.c12
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx.h100
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c33
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_leds.c4
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c221
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_phy.c9
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_pio.c44
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_pio.h13
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c38
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_wx.c107
-rw-r--r--drivers/net/wireless/ipw2200.c41
-rw-r--r--drivers/net/wireless/ipw2200.h1
-rw-r--r--drivers/net/wireless/ray_cs.c3
-rw-r--r--drivers/net/wireless/wavelan.c18
-rw-r--r--drivers/net/wireless/wavelan_cs.c7
-rw-r--r--drivers/net/yellowfin.c12
-rw-r--r--drivers/net/znet.c3
-rw-r--r--drivers/oprofile/buffer_sync.c8
-rw-r--r--drivers/oprofile/event_buffer.c12
-rw-r--r--drivers/oprofile/event_buffer.h4
-rw-r--r--drivers/oprofile/oprof.c26
-rw-r--r--drivers/oprofile/oprofilefs.c6
-rw-r--r--drivers/parport/Kconfig17
-rw-r--r--drivers/parport/Makefile3
-rw-r--r--drivers/parport/daisy.c2
-rw-r--r--drivers/parport/parport_arc.c139
-rw-r--r--drivers/parport/parport_ax88796.c443
-rw-r--r--drivers/parport/parport_sunbpp.c134
-rw-r--r--drivers/parport/share.c2
-rw-r--r--drivers/pci/Makefile6
-rw-r--r--drivers/pci/bus.c21
-rw-r--r--drivers/pci/msi-altix.c210
-rw-r--r--drivers/pci/msi-apic.c100
-rw-r--r--drivers/pci/msi.c285
-rw-r--r--drivers/pci/msi.h133
-rw-r--r--drivers/pci/pci-acpi.c16
-rw-r--r--drivers/pci/pci-sysfs.c45
-rw-r--r--drivers/pci/pci.c16
-rw-r--r--drivers/pci/pci.h2
-rw-r--r--drivers/pci/probe.c45
-rw-r--r--drivers/pci/quirks.c47
-rw-r--r--drivers/pci/remove.c12
-rw-r--r--drivers/pci/search.c32
-rw-r--r--drivers/pci/setup-bus.c5
-rw-r--r--drivers/pci/setup-res.c40
-rw-r--r--drivers/pnp/card.c48
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c199
-rw-r--r--drivers/rtc/Kconfig91
-rw-r--r--drivers/rtc/Makefile8
-rw-r--r--drivers/rtc/class.c1
-rw-r--r--drivers/rtc/interface.c22
-rw-r--r--drivers/rtc/rtc-at91.c407
-rw-r--r--drivers/rtc/rtc-dev.c131
-rw-r--r--drivers/rtc/rtc-ds1307.c388
-rw-r--r--drivers/rtc/rtc-ds1553.c414
-rw-r--r--drivers/rtc/rtc-ds1742.c259
-rw-r--r--drivers/rtc/rtc-lib.c19
-rw-r--r--drivers/rtc/rtc-max6902.c286
-rw-r--r--drivers/rtc/rtc-pcf8583.c394
-rw-r--r--drivers/rtc/rtc-pl031.c233
-rw-r--r--drivers/rtc/rtc-sa1100.c4
-rw-r--r--drivers/rtc/rtc-v3020.c264
-rw-r--r--drivers/rtc/rtc-vr41xx.c8
-rw-r--r--drivers/s390/char/sclp_quiesce.c3
-rw-r--r--drivers/s390/net/qeth_eddp.c12
-rw-r--r--drivers/s390/net/qeth_main.c4
-rw-r--r--drivers/s390/net/qeth_tso.h2
-rw-r--r--drivers/sbus/char/bbc_envctrl.c4
-rw-r--r--drivers/sbus/char/bbc_i2c.c4
-rw-r--r--drivers/sbus/char/display7seg.c2
-rw-r--r--drivers/sbus/char/envctrl.c71
-rw-r--r--drivers/sbus/char/flash.c17
-rw-r--r--drivers/sbus/char/openprom.c4
-rw-r--r--drivers/sbus/char/vfc_dev.c2
-rw-r--r--drivers/sbus/sbus.c582
-rw-r--r--drivers/scsi/53c700.h6
-rw-r--r--drivers/scsi/Makefile2
-rw-r--r--drivers/scsi/aacraid/aachba.c15
-rw-r--r--drivers/scsi/aacraid/commsup.c6
-rw-r--r--drivers/scsi/advansys.c6
-rw-r--r--drivers/scsi/ahci.c503
-rw-r--r--drivers/scsi/arm/queue.c6
-rw-r--r--drivers/scsi/ata_piix.c112
-rw-r--r--drivers/scsi/esp.c315
-rw-r--r--drivers/scsi/esp.h4
-rw-r--r--drivers/scsi/ibmmca.c3
-rw-r--r--drivers/scsi/ide-scsi.c6
-rw-r--r--drivers/scsi/libata-bmdma.c160
-rw-r--r--drivers/scsi/libata-core.c3042
-rw-r--r--drivers/scsi/libata-eh.c1907
-rw-r--r--drivers/scsi/libata-scsi.c754
-rw-r--r--drivers/scsi/libata.h31
-rw-r--r--drivers/scsi/mac_esp.c7
-rw-r--r--drivers/scsi/mac_scsi.c7
-rw-r--r--drivers/scsi/megaraid.c2
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.c2
-rw-r--r--drivers/scsi/osst.c2
-rw-r--r--drivers/scsi/pdc_adma.c12
-rw-r--r--drivers/scsi/qla1280.c24
-rw-r--r--drivers/scsi/qlogicpti.c361
-rw-r--r--drivers/scsi/sata_mv.c71
-rw-r--r--drivers/scsi/sata_nv.c535
-rw-r--r--drivers/scsi/sata_promise.c40
-rw-r--r--drivers/scsi/sata_qstor.c15
-rw-r--r--drivers/scsi/sata_sil.c221
-rw-r--r--drivers/scsi/sata_sil24.c646
-rw-r--r--drivers/scsi/sata_sis.c13
-rw-r--r--drivers/scsi/sata_svw.c16
-rw-r--r--drivers/scsi/sata_sx4.c21
-rw-r--r--drivers/scsi/sata_uli.c14
-rw-r--r--drivers/scsi/sata_via.c16
-rw-r--r--drivers/scsi/sata_vsc.c36
-rw-r--r--drivers/scsi/scsi.c18
-rw-r--r--drivers/scsi/scsi_error.c24
-rw-r--r--drivers/scsi/scsi_lib.c2
-rw-r--r--drivers/scsi/scsi_transport_api.h6
-rw-r--r--drivers/scsi/st.c2
-rw-r--r--drivers/scsi/sun3x_esp.c8
-rw-r--r--drivers/scsi/wd33c93.c4
-rw-r--r--drivers/scsi/wd7000.c2
-rw-r--r--drivers/serial/Kconfig28
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/amba-pl010.c2
-rw-r--r--drivers/serial/ioc4_serial.c9
-rw-r--r--drivers/serial/netx-serial.c749
-rw-r--r--drivers/serial/pxa.c1
-rw-r--r--drivers/serial/s3c2410.c143
-rw-r--r--drivers/serial/sunhv.c35
-rw-r--r--drivers/serial/sunsab.c12
-rw-r--r--drivers/serial/sunsu.c4
-rw-r--r--drivers/serial/sunzilog.c2
-rw-r--r--drivers/sn/ioc4.c64
-rw-r--r--drivers/usb/core/devio.c8
-rw-r--r--drivers/usb/core/inode.c8
-rw-r--r--drivers/usb/core/usb.c2
-rw-r--r--drivers/usb/gadget/file_storage.c2
-rw-r--r--drivers/usb/gadget/inode.c6
-rw-r--r--drivers/usb/host/Kconfig3
-rw-r--r--drivers/video/Kconfig56
-rw-r--r--drivers/video/aty/Makefile1
-rw-r--r--drivers/video/aty/aty128fb.c322
-rw-r--r--drivers/video/aty/atyfb.h1
-rw-r--r--drivers/video/aty/atyfb_base.c184
-rw-r--r--drivers/video/aty/radeon_backlight.c247
-rw-r--r--drivers/video/aty/radeon_base.c140
-rw-r--r--drivers/video/aty/radeonfb.h9
-rw-r--r--drivers/video/chipsfb.c30
-rw-r--r--drivers/video/console/mdacon.c2
-rw-r--r--drivers/video/console/vgacon.c19
-rw-r--r--drivers/video/fbsysfs.c88
-rw-r--r--drivers/video/igafb.c3
-rw-r--r--drivers/video/intelfb/intelfb.h2
-rw-r--r--drivers/video/intelfb/intelfbdrv.c18
-rw-r--r--drivers/video/intelfb/intelfbhw.c24
-rw-r--r--drivers/video/matrox/matroxfb_base.c52
-rw-r--r--drivers/video/nvidia/Makefile3
-rw-r--r--drivers/video/nvidia/nv_backlight.c175
-rw-r--r--drivers/video/nvidia/nv_proto.h10
-rw-r--r--drivers/video/nvidia/nvidia.c95
-rw-r--r--drivers/video/riva/fbdev.c222
-rw-r--r--drivers/video/tridentfb.c6
-rw-r--r--drivers/video/vga16fb.c2
-rw-r--r--drivers/w1/Kconfig15
-rw-r--r--drivers/w1/Makefile4
-rw-r--r--drivers/w1/masters/Kconfig27
-rw-r--r--drivers/w1/masters/Makefile7
-rw-r--r--drivers/w1/masters/ds2482.c24
-rw-r--r--drivers/w1/masters/ds2490.c (renamed from drivers/w1/masters/dscore.c)434
-rw-r--r--drivers/w1/masters/ds_w1_bridge.c174
-rw-r--r--drivers/w1/masters/dscore.h166
-rw-r--r--drivers/w1/slaves/Kconfig2
-rw-r--r--drivers/w1/slaves/w1_ds2433.c21
-rw-r--r--drivers/w1/slaves/w1_smem.c1
-rw-r--r--drivers/w1/slaves/w1_therm.c13
-rw-r--r--drivers/w1/w1.c263
-rw-r--r--drivers/w1/w1.h41
-rw-r--r--drivers/w1/w1_family.c18
-rw-r--r--drivers/w1/w1_family.h3
-rw-r--r--drivers/w1/w1_int.c16
-rw-r--r--drivers/w1/w1_io.c31
-rw-r--r--drivers/w1/w1_io.h3
-rw-r--r--drivers/w1/w1_netlink.c219
-rw-r--r--drivers/w1/w1_netlink.h35
-rw-r--r--fs/9p/vfs_inode.c12
-rw-r--r--fs/9p/vfs_super.c28
-rw-r--r--fs/Kconfig15
-rw-r--r--fs/adfs/super.c15
-rw-r--r--fs/affs/super.c24
-rw-r--r--fs/afs/dir.c4
-rw-r--r--fs/afs/mntpt.c13
-rw-r--r--fs/afs/super.c26
-rw-r--r--fs/afs/super.h2
-rw-r--r--fs/aio.c4
-rw-r--r--fs/autofs/init.c6
-rw-r--r--fs/autofs4/expire.c6
-rw-r--r--fs/autofs4/init.c6
-rw-r--r--fs/befs/linuxvfs.c12
-rw-r--r--fs/bfs/inode.c9
-rw-r--r--fs/binfmt_elf.c348
-rw-r--r--fs/binfmt_elf_fdpic.c26
-rw-r--r--fs/binfmt_misc.c10
-rw-r--r--fs/block_dev.c38
-rw-r--r--fs/buffer.c2
-rw-r--r--fs/cifs/cifsfs.c19
-rw-r--r--fs/cifs/cifsfs.h2
-rw-r--r--fs/cifs/file.c26
-rw-r--r--fs/coda/file.c2
-rw-r--r--fs/coda/inode.c12
-rw-r--r--fs/coda/upcall.c4
-rw-r--r--fs/compat.c8
-rw-r--r--fs/compat_ioctl.c33
-rw-r--r--fs/configfs/mount.c8
-rw-r--r--fs/cramfs/inode.c15
-rw-r--r--fs/dcache.c109
-rw-r--r--fs/debugfs/inode.c10
-rw-r--r--fs/devfs/base.c8
-rw-r--r--fs/devpts/inode.c6
-rw-r--r--fs/direct-io.c18
-rw-r--r--fs/efs/super.c12
-rw-r--r--fs/eventpoll.c30
-rw-r--r--fs/exec.c1
-rw-r--r--fs/ext2/Makefile2
-rw-r--r--fs/ext2/balloc.c22
-rw-r--r--fs/ext2/bitmap.c32
-rw-r--r--fs/ext2/dir.c6
-rw-r--r--fs/ext2/fsync.c2
-rw-r--r--fs/ext2/ialloc.c3
-rw-r--r--fs/ext2/super.c39
-rw-r--r--fs/ext3/balloc.c242
-rw-r--r--fs/ext3/ialloc.c10
-rw-r--r--fs/ext3/inode.c57
-rw-r--r--fs/ext3/ioctl.c2
-rw-r--r--fs/ext3/namei.c4
-rw-r--r--fs/ext3/resize.c81
-rw-r--r--fs/ext3/super.c116
-rw-r--r--fs/ext3/xattr.c27
-rw-r--r--fs/fat/inode.c8
-rw-r--r--fs/fat/misc.c1
-rw-r--r--fs/file_table.c2
-rw-r--r--fs/freevxfs/vxfs.h4
-rw-r--r--fs/freevxfs/vxfs_fshead.c12
-rw-r--r--fs/freevxfs/vxfs_subr.c3
-rw-r--r--fs/freevxfs/vxfs_super.c20
-rw-r--r--fs/fs-writeback.c6
-rw-r--r--fs/fuse/Makefile2
-rw-r--r--fs/fuse/control.c218
-rw-r--r--fs/fuse/dev.c418
-rw-r--r--fs/fuse/dir.c56
-rw-r--r--fs/fuse/file.c208
-rw-r--r--fs/fuse/fuse_i.h135
-rw-r--r--fs/fuse/inode.c194
-rw-r--r--fs/hfs/bnode.c2
-rw-r--r--fs/hfs/btree.c2
-rw-r--r--fs/hfs/super.c11
-rw-r--r--fs/hfsplus/bitmap.c15
-rw-r--r--fs/hfsplus/bnode.c2
-rw-r--r--fs/hfsplus/btree.c2
-rw-r--r--fs/hfsplus/super.c12
-rw-r--r--fs/hostfs/hostfs_kern.c12
-rw-r--r--fs/hpfs/super.c10
-rw-r--r--fs/hppfs/hppfs_kern.c10
-rw-r--r--fs/hugetlbfs/inode.c31
-rw-r--r--fs/inotify_user.c6
-rw-r--r--fs/ioprio.c6
-rw-r--r--fs/isofs/inode.c13
-rw-r--r--fs/jbd/checkpoint.c419
-rw-r--r--fs/jbd/commit.c21
-rw-r--r--fs/jbd/recovery.c1
-rw-r--r--fs/jbd/transaction.c12
-rw-r--r--fs/jffs/inode-v23.c11
-rw-r--r--fs/jffs2/fs.c4
-rw-r--r--fs/jffs2/os-linux.h2
-rw-r--r--fs/jffs2/super.c49
-rw-r--r--fs/jfs/jfs_metapage.c5
-rw-r--r--fs/jfs/super.c11
-rw-r--r--fs/libfs.c20
-rw-r--r--fs/lockd/clntlock.c39
-rw-r--r--fs/lockd/clntproc.c14
-rw-r--r--fs/lockd/host.c9
-rw-r--r--fs/locks.c123
-rw-r--r--fs/minix/dir.c3
-rw-r--r--fs/minix/inode.c17
-rw-r--r--fs/mpage.c22
-rw-r--r--fs/msdos/namei.c9
-rw-r--r--fs/namei.c9
-rw-r--r--fs/namespace.c137
-rw-r--r--fs/ncpfs/inode.c11
-rw-r--r--fs/nfs/Makefile8
-rw-r--r--fs/nfs/callback.c2
-rw-r--r--fs/nfs/callback_xdr.c2
-rw-r--r--fs/nfs/dir.c18
-rw-r--r--fs/nfs/direct.c6
-rw-r--r--fs/nfs/file.c34
-rw-r--r--fs/nfs/idmap.c1
-rw-r--r--fs/nfs/inode.c1294
-rw-r--r--fs/nfs/internal.h186
-rw-r--r--fs/nfs/namespace.c229
-rw-r--r--fs/nfs/nfs2xdr.c6
-rw-r--r--fs/nfs/nfs3acl.c11
-rw-r--r--fs/nfs/nfs3proc.c5
-rw-r--r--fs/nfs/nfs3xdr.c6
-rw-r--r--fs/nfs/nfs4_fs.h4
-rw-r--r--fs/nfs/nfs4namespace.c201
-rw-r--r--fs/nfs/nfs4proc.c111
-rw-r--r--fs/nfs/nfs4xdr.c218
-rw-r--r--fs/nfs/pagelist.c51
-rw-r--r--fs/nfs/proc.c5
-rw-r--r--fs/nfs/read.c122
-rw-r--r--fs/nfs/super.c1537
-rw-r--r--fs/nfs/symlink.c13
-rw-r--r--fs/nfs/sysctl.c10
-rw-r--r--fs/nfs/write.c49
-rw-r--r--fs/nfsd/nfs4xdr.c2
-rw-r--r--fs/nfsd/nfsctl.c6
-rw-r--r--fs/nfsd/vfs.c2
-rw-r--r--fs/ntfs/aops.h3
-rw-r--r--fs/ntfs/attrib.c6
-rw-r--r--fs/ntfs/file.c42
-rw-r--r--fs/ntfs/super.c14
-rw-r--r--fs/ocfs2/dlm/dlmfs.c6
-rw-r--r--fs/ocfs2/super.c22
-rw-r--r--fs/ocfs2/symlink.c3
-rw-r--r--fs/open.c30
-rw-r--r--fs/openpromfs/inode.c50
-rw-r--r--fs/partitions/check.c8
-rw-r--r--fs/pipe.c9
-rw-r--r--fs/proc/root.c6
-rw-r--r--fs/qnx4/inode.c13
-rw-r--r--fs/ramfs/inode.c13
-rw-r--r--fs/reiserfs/super.c17
-rw-r--r--fs/reiserfs/xattr.c3
-rw-r--r--fs/romfs/inode.c11
-rw-r--r--fs/select.c90
-rw-r--r--fs/smbfs/inode.c12
-rw-r--r--fs/smbfs/proc.c4
-rw-r--r--fs/smbfs/proto.h2
-rw-r--r--fs/smbfs/smbiod.c26
-rw-r--r--fs/splice.c46
-rw-r--r--fs/super.c113
-rw-r--r--fs/sync.c2
-rw-r--r--fs/sysfs/mount.c6
-rw-r--r--fs/sysv/dir.c3
-rw-r--r--fs/sysv/inode.c3
-rw-r--r--fs/sysv/super.c13
-rw-r--r--fs/udf/super.c12
-rw-r--r--fs/ufs/balloc.c448
-rw-r--r--fs/ufs/cylinder.c49
-rw-r--r--fs/ufs/dir.c1000
-rw-r--r--fs/ufs/file.c21
-rw-r--r--fs/ufs/ialloc.c63
-rw-r--r--fs/ufs/inode.c267
-rw-r--r--fs/ufs/namei.c84
-rw-r--r--fs/ufs/super.c436
-rw-r--r--fs/ufs/truncate.c104
-rw-r--r--fs/ufs/util.c48
-rw-r--r--fs/ufs/util.h107
-rw-r--r--fs/vfat/namei.c9
-rw-r--r--fs/xfs/linux-2.6/xfs_stats.c4
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c13
-rw-r--r--fs/xfs/linux-2.6/xfs_sysctl.c2
-rw-r--r--include/acpi/acconfig.h18
-rw-r--r--include/acpi/acdisasm.h173
-rw-r--r--include/acpi/acdispat.h6
-rw-r--r--include/acpi/acevents.h4
-rw-r--r--include/acpi/acexcep.h6
-rw-r--r--include/acpi/acglobal.h29
-rw-r--r--include/acpi/aclocal.h284
-rw-r--r--include/acpi/acmacros.h81
-rw-r--r--include/acpi/acnamesp.h28
-rw-r--r--include/acpi/acobject.h188
-rw-r--r--include/acpi/acopcode.h2
-rw-r--r--include/acpi/acoutput.h10
-rw-r--r--include/acpi/acparser.h4
-rw-r--r--include/acpi/acpi_bus.h10
-rw-r--r--include/acpi/acpi_numa.h23
-rw-r--r--include/acpi/acpiosxf.h35
-rw-r--r--include/acpi/acpixf.h4
-rw-r--r--include/acpi/acresrc.h20
-rw-r--r--include/acpi/acstruct.h121
-rw-r--r--include/acpi/actables.h6
-rw-r--r--include/acpi/actbl.h400
-rw-r--r--include/acpi/actbl1.h639
-rw-r--r--include/acpi/actbl2.h230
-rw-r--r--include/acpi/actypes.h88
-rw-r--r--include/acpi/acutils.h95
-rw-r--r--include/acpi/amlcode.h6
-rw-r--r--include/acpi/amlresrc.h85
-rw-r--r--include/acpi/pdc_intel.h5
-rw-r--r--include/acpi/platform/acenv.h47
-rw-r--r--include/acpi/platform/aclinux.h23
-rw-r--r--include/acpi/processor.h27
-rw-r--r--include/asm-alpha/floppy.h5
-rw-r--r--include/asm-alpha/irq.h4
-rw-r--r--include/asm-alpha/vga.h2
-rw-r--r--include/asm-arm/arch-aaec2000/io.h1
-rw-r--r--include/asm-arm/arch-clps711x/io.h1
-rw-r--r--include/asm-arm/arch-ebsa285/io.h8
-rw-r--r--include/asm-arm/arch-ep93xx/ep93xx-regs.h2
-rw-r--r--include/asm-arm/arch-ep93xx/platform.h1
-rw-r--r--include/asm-arm/arch-imx/imx-dma.h8
-rw-r--r--include/asm-arm/arch-integrator/io.h1
-rw-r--r--include/asm-arm/arch-iop3xx/io.h1
-rw-r--r--include/asm-arm/arch-ixp23xx/ixp23xx.h3
-rw-r--r--include/asm-arm/arch-ixp23xx/platform.h15
-rw-r--r--include/asm-arm/arch-l7200/io.h1
-rw-r--r--include/asm-arm/arch-lh7a40x/io.h1
-rw-r--r--include/asm-arm/arch-netx/eth.h27
-rw-r--r--include/asm-arm/arch-netx/io.h1
-rw-r--r--include/asm-arm/arch-omap/io.h1
-rw-r--r--include/asm-arm/arch-pnx4008/debug-macro.S4
-rw-r--r--include/asm-arm/arch-pnx4008/gpio.h102
-rw-r--r--include/asm-arm/arch-pnx4008/pm.h29
-rw-r--r--include/asm-arm/arch-pxa/io.h1
-rw-r--r--include/asm-arm/arch-realview/io.h1
-rw-r--r--include/asm-arm/arch-s3c2410/debug-macro.S10
-rw-r--r--include/asm-arm/arch-s3c2410/entry-macro.S30
-rw-r--r--include/asm-arm/arch-s3c2410/map.h16
-rw-r--r--include/asm-arm/arch-s3c2410/regs-clock.h63
-rw-r--r--include/asm-arm/arch-s3c2410/regs-dsc.h5
-rw-r--r--include/asm-arm/arch-s3c2410/regs-gpio.h63
-rw-r--r--include/asm-arm/arch-s3c2410/regs-gpioj.h5
-rw-r--r--include/asm-arm/arch-s3c2410/regs-irq.h6
-rw-r--r--include/asm-arm/arch-s3c2410/regs-serial.h15
-rw-r--r--include/asm-arm/arch-sa1100/io.h1
-rw-r--r--include/asm-arm/arch-versatile/io.h1
-rw-r--r--include/asm-arm/floppy.h2
-rw-r--r--include/asm-arm/irq.h4
-rw-r--r--include/asm-arm/thread_notify.h48
-rw-r--r--include/asm-arm/ucontext.h79
-rw-r--r--include/asm-arm/vga.h2
-rw-r--r--include/asm-arm26/floppy.h2
-rw-r--r--include/asm-arm26/irq.h4
-rw-r--r--include/asm-frv/atomic.h4
-rw-r--r--include/asm-frv/checksum.h2
-rw-r--r--include/asm-frv/highmem.h2
-rw-r--r--include/asm-frv/io.h40
-rw-r--r--include/asm-frv/mb-regs.h27
-rw-r--r--include/asm-frv/signal.h6
-rw-r--r--include/asm-frv/uaccess.h64
-rw-r--r--include/asm-frv/unistd.h19
-rw-r--r--include/asm-generic/bug.h13
-rw-r--r--include/asm-generic/memory_model.h27
-rw-r--r--include/asm-generic/percpu.h2
-rw-r--r--include/asm-generic/rtc.h7
-rw-r--r--include/asm-h8300/irq.h4
-rw-r--r--include/asm-i386/alternative.h2
-rw-r--r--include/asm-i386/apic.h2
-rw-r--r--include/asm-i386/apicdef.h1
-rw-r--r--include/asm-i386/cpufeature.h12
-rw-r--r--include/asm-i386/floppy.h5
-rw-r--r--include/asm-i386/mach-default/setup_arch.h (renamed from include/asm-i386/mach-default/setup_arch_pre.h)0
-rw-r--r--include/asm-i386/mach-default/setup_arch_post.h40
-rw-r--r--include/asm-i386/mach-visws/setup_arch.h (renamed from include/asm-i386/mach-visws/setup_arch_pre.h)0
-rw-r--r--include/asm-i386/mach-visws/setup_arch_post.h49
-rw-r--r--include/asm-i386/mach-voyager/setup_arch.h (renamed from include/asm-i386/mach-voyager/setup_arch_pre.h)2
-rw-r--r--include/asm-i386/mach-voyager/setup_arch_post.h73
-rw-r--r--include/asm-i386/mce.h5
-rw-r--r--include/asm-i386/msi.h10
-rw-r--r--include/asm-i386/mtrr.h4
-rw-r--r--include/asm-i386/processor.h14
-rw-r--r--include/asm-i386/setup.h15
-rw-r--r--include/asm-i386/uaccess.h69
-rw-r--r--include/asm-i386/unistd.h3
-rw-r--r--include/asm-i386/vga.h2
-rw-r--r--include/asm-ia64/hw_irq.h15
-rw-r--r--include/asm-ia64/io.h1
-rw-r--r--include/asm-ia64/machvec.h7
-rw-r--r--include/asm-ia64/machvec_sn2.h7
-rw-r--r--include/asm-ia64/mca.h9
-rw-r--r--include/asm-ia64/msi.h12
-rw-r--r--include/asm-ia64/percpu.h2
-rw-r--r--include/asm-ia64/pgtable.h22
-rw-r--r--include/asm-ia64/sn/intr.h8
-rw-r--r--include/asm-ia64/sn/pcibr_provider.h5
-rw-r--r--include/asm-ia64/sn/pcibus_provider_defs.h17
-rw-r--r--include/asm-ia64/sn/sn_sal.h2
-rw-r--r--include/asm-ia64/sn/tiocp.h3
-rw-r--r--include/asm-ia64/unistd.h2
-rw-r--r--include/asm-ia64/vga.h2
-rw-r--r--include/asm-m32r/vga.h2
-rw-r--r--include/asm-m68k/amigaints.h96
-rw-r--r--include/asm-m68k/apollohw.h4
-rw-r--r--include/asm-m68k/atari_stdma.h2
-rw-r--r--include/asm-m68k/atariints.h11
-rw-r--r--include/asm-m68k/bvme6000hw.h30
-rw-r--r--include/asm-m68k/cacheflush.h40
-rw-r--r--include/asm-m68k/dma-mapping.h90
-rw-r--r--include/asm-m68k/irq.h108
-rw-r--r--include/asm-m68k/mac_oss.h10
-rw-r--r--include/asm-m68k/machdep.h6
-rw-r--r--include/asm-m68k/macintosh.h10
-rw-r--r--include/asm-m68k/macints.h14
-rw-r--r--include/asm-m68k/mvme147hw.h44
-rw-r--r--include/asm-m68k/mvme16xhw.h40
-rw-r--r--include/asm-m68k/processor.h8
-rw-r--r--include/asm-m68k/scatterlist.h9
-rw-r--r--include/asm-m68k/signal.h19
-rw-r--r--include/asm-m68k/sun3ints.h22
-rw-r--r--include/asm-m68k/traps.h7
-rw-r--r--include/asm-m68k/uaccess.h1100
-rw-r--r--include/asm-m68k/unistd.h39
-rw-r--r--include/asm-m68knommu/irq.h4
-rw-r--r--include/asm-m68knommu/ptrace.h2
-rw-r--r--include/asm-mips/compat.h3
-rw-r--r--include/asm-mips/mach-au1x00/au1xxx_psc.h9
-rw-r--r--include/asm-mips/mach-db1x00/db1x00.h12
-rw-r--r--include/asm-mips/mach-generic/floppy.h2
-rw-r--r--include/asm-mips/mach-jazz/floppy.h2
-rw-r--r--include/asm-mips/mmzone.h1
-rw-r--r--include/asm-mips/vga.h2
-rw-r--r--include/asm-parisc/floppy.h6
-rw-r--r--include/asm-parisc/mmzone.h5
-rw-r--r--include/asm-powerpc/backlight.h30
-rw-r--r--include/asm-powerpc/bitops.h6
-rw-r--r--include/asm-powerpc/cputable.h82
-rw-r--r--include/asm-powerpc/delay.h13
-rw-r--r--include/asm-powerpc/eeh.h15
-rw-r--r--include/asm-powerpc/eeh_event.h10
-rw-r--r--include/asm-powerpc/elf.h2
-rw-r--r--include/asm-powerpc/floppy.h3
-rw-r--r--include/asm-powerpc/hvcall.h10
-rw-r--r--include/asm-powerpc/immap_86xx.h199
-rw-r--r--include/asm-powerpc/io.h6
-rw-r--r--include/asm-powerpc/iommu.h6
-rw-r--r--include/asm-powerpc/irq.h86
-rw-r--r--include/asm-powerpc/iseries/iommu.h (renamed from arch/powerpc/platforms/iseries/iommu.h)6
-rw-r--r--include/asm-powerpc/kdump.h29
-rw-r--r--include/asm-powerpc/kexec.h16
-rw-r--r--include/asm-powerpc/machdep.h5
-rw-r--r--include/asm-powerpc/mmu.h16
-rw-r--r--include/asm-powerpc/mmu_context.h12
-rw-r--r--include/asm-powerpc/mpc86xx.h47
-rw-r--r--include/asm-powerpc/mpic.h10
-rw-r--r--include/asm-powerpc/paca.h4
-rw-r--r--include/asm-powerpc/page.h11
-rw-r--r--include/asm-powerpc/pci-bridge.h14
-rw-r--r--include/asm-powerpc/percpu.h2
-rw-r--r--include/asm-powerpc/pgtable-4k.h2
-rw-r--r--include/asm-powerpc/pgtable-64k.h2
-rw-r--r--include/asm-powerpc/pgtable.h10
-rw-r--r--include/asm-powerpc/processor.h16
-rw-r--r--include/asm-powerpc/prom.h9
-rw-r--r--include/asm-powerpc/ptrace.h2
-rw-r--r--include/asm-powerpc/reg.h69
-rw-r--r--include/asm-powerpc/rtas.h9
-rw-r--r--include/asm-powerpc/spu.h29
-rw-r--r--include/asm-powerpc/spu_csa.h13
-rw-r--r--include/asm-powerpc/spu_priv1.h182
-rw-r--r--include/asm-powerpc/systbl.h306
-rw-r--r--include/asm-powerpc/tce.h35
-rw-r--r--include/asm-powerpc/topology.h9
-rw-r--r--include/asm-powerpc/udbg.h3
-rw-r--r--include/asm-powerpc/vga.h4
-rw-r--r--include/asm-powerpc/vio.h16
-rw-r--r--include/asm-ppc/floppy.h6
-rw-r--r--include/asm-ppc/mmu.h23
-rw-r--r--include/asm-ppc/mmu_context.h27
-rw-r--r--include/asm-ppc/mpc85xx.h3
-rw-r--r--include/asm-ppc/pgtable.h2
-rw-r--r--include/asm-s390/irq.h4
-rw-r--r--include/asm-s390/percpu.h2
-rw-r--r--include/asm-sh/floppy.h7
-rw-r--r--include/asm-sparc/ebus.h17
-rw-r--r--include/asm-sparc/irq.h4
-rw-r--r--include/asm-sparc/of_device.h63
-rw-r--r--include/asm-sparc/pbm.h3
-rw-r--r--include/asm-sparc/prom.h98
-rw-r--r--include/asm-sparc/sbus.h28
-rw-r--r--include/asm-sparc64/ebus.h20
-rw-r--r--include/asm-sparc64/fhc.h7
-rw-r--r--include/asm-sparc64/floppy.h27
-rw-r--r--include/asm-sparc64/isa.h21
-rw-r--r--include/asm-sparc64/of_device.h64
-rw-r--r--include/asm-sparc64/oplib.h5
-rw-r--r--include/asm-sparc64/parport.h25
-rw-r--r--include/asm-sparc64/pbm.h15
-rw-r--r--include/asm-sparc64/percpu.h2
-rw-r--r--include/asm-sparc64/pgtable.h2
-rw-r--r--include/asm-sparc64/prom.h98
-rw-r--r--include/asm-sparc64/sbus.h29
-rw-r--r--include/asm-sparc64/vdev.h5
-rw-r--r--include/asm-sparc64/vga.h2
-rw-r--r--include/asm-v850/irq.h2
-rw-r--r--include/asm-x86_64/acpi.h2
-rw-r--r--include/asm-x86_64/apicdef.h2
-rw-r--r--include/asm-x86_64/floppy.h6
-rw-r--r--include/asm-x86_64/mmzone.h1
-rw-r--r--include/asm-x86_64/msi.h10
-rw-r--r--include/asm-x86_64/numa.h1
-rw-r--r--include/asm-x86_64/percpu.h2
-rw-r--r--include/asm-x86_64/unistd.h4
-rw-r--r--include/asm-x86_64/vga.h2
-rw-r--r--include/asm-xtensa/checksum.h3
-rw-r--r--include/asm-xtensa/rwsem.h7
-rw-r--r--include/asm-xtensa/uaccess.h34
-rw-r--r--include/asm-xtensa/vga.h2
-rw-r--r--include/linux/acct.h8
-rw-r--r--include/linux/acpi.h9
-rw-r--r--include/linux/ata.h37
-rw-r--r--include/linux/bio.h2
-rw-r--r--include/linux/blkdev.h18
-rw-r--r--include/linux/blktrace_api.h6
-rw-r--r--include/linux/bootmem.h4
-rw-r--r--include/linux/cn_proc.h21
-rw-r--r--include/linux/coda_linux.h2
-rw-r--r--include/linux/coda_psdev.h2
-rw-r--r--include/linux/connector.h5
-rw-r--r--include/linux/console.h1
-rw-r--r--include/linux/cpufreq.h4
-rw-r--r--include/linux/cpumask.h4
-rw-r--r--include/linux/dcache.h1
-rw-r--r--include/linux/delay.h5
-rw-r--r--include/linux/dvb/dmx.h26
-rw-r--r--include/linux/efi.h1
-rw-r--r--include/linux/ethtool.h2
-rw-r--r--include/linux/eventpoll.h2
-rw-r--r--include/linux/ext3_fs.h31
-rw-r--r--include/linux/ext3_fs_i.h16
-rw-r--r--include/linux/fb.h23
-rw-r--r--include/linux/fcntl.h1
-rw-r--r--include/linux/fs.h46
-rw-r--r--include/linux/fuse.h36
-rw-r--r--include/linux/genalloc.h35
-rw-r--r--include/linux/hdlc.h2
-rw-r--r--include/linux/hrtimer.h3
-rw-r--r--include/linux/hugetlb.h8
-rw-r--r--include/linux/i2c-id.h3
-rw-r--r--include/linux/i2c-ocores.h19
-rw-r--r--include/linux/i2c.h4
-rw-r--r--include/linux/ide.h3
-rw-r--r--include/linux/interrupt.h21
-rw-r--r--include/linux/ioc4.h5
-rw-r--r--include/linux/irq.h11
-rw-r--r--include/linux/irqreturn.h25
-rw-r--r--include/linux/jbd.h8
-rw-r--r--include/linux/kernel.h7
-rw-r--r--include/linux/kexec.h1
-rw-r--r--include/linux/key.h23
-rw-r--r--include/linux/kthread.h65
-rw-r--r--include/linux/ktime.h8
-rw-r--r--include/linux/libata.h473
-rw-r--r--include/linux/list.h157
-rw-r--r--include/linux/lockd/lockd.h4
-rw-r--r--include/linux/loop.h2
-rw-r--r--include/linux/m41t00.h50
-rw-r--r--include/linux/migrate.h31
-rw-r--r--include/linux/mm.h14
-rw-r--r--include/linux/mmzone.h12
-rw-r--r--include/linux/module.h2
-rw-r--r--include/linux/mount.h13
-rw-r--r--include/linux/nbd.h12
-rw-r--r--include/linux/netdevice.h23
-rw-r--r--include/linux/netlink.h2
-rw-r--r--include/linux/nfs4.h1
-rw-r--r--include/linux/nfs_fs.h62
-rw-r--r--include/linux/nfs_fs_sb.h1
-rw-r--r--include/linux/nfs_page.h5
-rw-r--r--include/linux/nfs_xdr.h61
-rw-r--r--include/linux/page-flags.h14
-rw-r--r--include/linux/pagemap.h7
-rw-r--r--include/linux/parport.h5
-rw-r--r--include/linux/pci.h4
-rw-r--r--include/linux/pci_ids.h25
-rw-r--r--include/linux/pci_regs.h1
-rw-r--r--include/linux/percpu_counter.h38
-rw-r--r--include/linux/pmu.h4
-rw-r--r--include/linux/prctl.h7
-rw-r--r--include/linux/ptrace.h4
-rw-r--r--include/linux/radix-tree.h5
-rw-r--r--include/linux/ramfs.h4
-rw-r--r--include/linux/rbtree.h4
-rw-r--r--include/linux/rcupdate.h3
-rw-r--r--include/linux/reboot.h4
-rw-r--r--include/linux/resource.h4
-rw-r--r--include/linux/resume-trace.h30
-rw-r--r--include/linux/rmap.h1
-rw-r--r--include/linux/rtc-v3020.h35
-rw-r--r--include/linux/rtc.h12
-rw-r--r--include/linux/sched.h24
-rw-r--r--include/linux/security.h55
-rw-r--r--include/linux/serial_core.h3
-rw-r--r--include/linux/skbuff.h26
-rw-r--r--include/linux/slab.h50
-rw-r--r--include/linux/string.h1
-rw-r--r--include/linux/sunrpc/xdr.h1
-rw-r--r--include/linux/suspend.h1
-rw-r--r--include/linux/swap.h101
-rw-r--r--include/linux/swapops.h53
-rw-r--r--include/linux/synclink.h5
-rw-r--r--include/linux/syscalls.h10
-rw-r--r--include/linux/sysctl.h5
-rw-r--r--include/linux/tcp.h2
-rw-r--r--include/linux/uaccess.h22
-rw-r--r--include/linux/ufs_fs.h104
-rw-r--r--include/linux/ufs_fs_i.h1
-rw-r--r--include/linux/videodev.h51
-rw-r--r--include/linux/videodev2.h392
-rw-r--r--include/linux/vmalloc.h8
-rw-r--r--include/linux/writeback.h5
-rw-r--r--include/linux/zconf.h12
-rw-r--r--include/linux/zlib.h209
-rw-r--r--include/linux/zorro.h42
-rw-r--r--include/linux/zutil.h12
-rw-r--r--include/media/cx2341x.h189
-rw-r--r--include/media/ir-common.h5
-rw-r--r--include/media/ir-kbd-i2c.h3
-rw-r--r--include/media/ovcamchip.h1
-rw-r--r--include/media/pwc-ioctl.h325
-rw-r--r--include/media/saa7115.h11
-rw-r--r--include/media/saa7146_vv.h2
-rw-r--r--include/media/tuner.h13
-rw-r--r--include/media/tvp5150.h34
-rw-r--r--include/media/v4l2-common.h32
-rw-r--r--include/media/v4l2-dev.h375
-rw-r--r--include/media/video-buf-dvb.h3
-rw-r--r--include/media/video-buf.h1
-rw-r--r--include/net/ieee80211.h5
-rw-r--r--include/net/protocol.h1
-rw-r--r--include/net/sock.h5
-rw-r--r--include/net/tcp.h6
-rw-r--r--include/scsi/scsi_cmnd.h1
-rw-r--r--include/scsi/scsi_host.h1
-rw-r--r--include/sound/ac97_codec.h1
-rw-r--r--include/sound/asequencer.h4
-rw-r--r--include/sound/asound.h2
-rw-r--r--include/sound/core.h3
-rw-r--r--include/sound/emu10k1.h2
-rw-r--r--include/sound/info.h11
-rw-r--r--include/sound/mpu401.h14
-rw-r--r--include/sound/pcm.h19
-rw-r--r--include/sound/pcm_params.h125
-rw-r--r--include/sound/rawmidi.h3
-rw-r--r--include/sound/tea575x-tuner.h3
-rw-r--r--include/sound/version.h4
-rw-r--r--init/Kconfig3
-rw-r--r--ipc/mqueue.c10
-rw-r--r--ipc/shm.c3
-rw-r--r--kernel/acct.c117
-rw-r--r--kernel/auditsc.c1
-rw-r--r--kernel/compat.c30
-rw-r--r--kernel/cpuset.c16
-rw-r--r--kernel/exit.c14
-rw-r--r--kernel/fork.c6
-rw-r--r--kernel/futex.c8
-rw-r--r--kernel/hrtimer.c15
-rw-r--r--kernel/irq/handle.c5
-rw-r--r--kernel/irq/migration.c4
-rw-r--r--kernel/irq/proc.c3
-rw-r--r--kernel/irq/spurious.c12
-rw-r--r--kernel/kexec.c6
-rw-r--r--kernel/ksysfs.c19
-rw-r--r--kernel/kthread.c61
-rw-r--r--kernel/module.c2
-rw-r--r--kernel/power/Kconfig9
-rw-r--r--kernel/power/disk.c2
-rw-r--r--kernel/power/main.c6
-rw-r--r--kernel/power/power.h6
-rw-r--r--kernel/power/snapshot.c260
-rw-r--r--kernel/power/swsusp.c32
-rw-r--r--kernel/printk.c52
-rw-r--r--kernel/rcupdate.c13
-rw-r--r--kernel/sched.c18
-rw-r--r--kernel/softirq.c2
-rw-r--r--kernel/softlockup.c4
-rw-r--r--kernel/stop_machine.c17
-rw-r--r--kernel/sys.c80
-rw-r--r--kernel/sys_ni.c2
-rw-r--r--kernel/sysctl.c22
-rw-r--r--kernel/timer.c32
-rw-r--r--kernel/user.c2
-rw-r--r--kernel/workqueue.c34
-rw-r--r--lib/Makefile1
-rw-r--r--lib/bitmap.c31
-rw-r--r--lib/crc-ccitt.c6
-rw-r--r--lib/crc16.c10
-rw-r--r--lib/crc32.c54
-rw-r--r--lib/genalloc.c263
-rw-r--r--lib/idr.c16
-rw-r--r--lib/libcrc32c.c2
-rw-r--r--lib/percpu_counter.c46
-rw-r--r--lib/radix-tree.c197
-rw-r--r--lib/reed_solomon/reed_solomon.c11
-rw-r--r--lib/string.c30
-rw-r--r--lib/vsprintf.c88
-rw-r--r--lib/zlib_deflate/deflate.c25
-rw-r--r--lib/zlib_deflate/deflate_syms.c3
-rw-r--r--lib/zlib_inflate/Makefile4
-rw-r--r--lib/zlib_inflate/infblock.c365
-rw-r--r--lib/zlib_inflate/infblock.h48
-rw-r--r--lib/zlib_inflate/infcodes.c202
-rw-r--r--lib/zlib_inflate/infcodes.h33
-rw-r--r--lib/zlib_inflate/inffast.c462
-rw-r--r--lib/zlib_inflate/inffast.h12
-rw-r--r--lib/zlib_inflate/inffixed.h94
-rw-r--r--lib/zlib_inflate/inflate.c1086
-rw-r--r--lib/zlib_inflate/inflate.h107
-rw-r--r--lib/zlib_inflate/inflate_syms.c3
-rw-r--r--lib/zlib_inflate/inflate_sync.c152
-rw-r--r--lib/zlib_inflate/inftrees.c683
-rw-r--r--lib/zlib_inflate/inftrees.h99
-rw-r--r--lib/zlib_inflate/infutil.c88
-rw-r--r--lib/zlib_inflate/infutil.h176
-rw-r--r--mm/Kconfig4
-rw-r--r--mm/filemap.c217
-rw-r--r--mm/filemap.h32
-rw-r--r--mm/fremap.c9
-rw-r--r--mm/hugetlb.c282
-rw-r--r--mm/memory.c125
-rw-r--r--mm/memory_hotplug.c27
-rw-r--r--mm/mempolicy.c42
-rw-r--r--mm/migrate.c1076
-rw-r--r--mm/mmap.c12
-rw-r--r--mm/mprotect.c37
-rw-r--r--mm/msync.c3
-rw-r--r--mm/oom_kill.c9
-rw-r--r--mm/page-writeback.c3
-rw-r--r--mm/page_alloc.c187
-rw-r--r--mm/pdflush.c18
-rw-r--r--mm/readahead.c16
-rw-r--r--mm/rmap.c114
-rw-r--r--mm/shmem.c20
-rw-r--r--mm/slab.c249
-rw-r--r--mm/sparse.c22
-rw-r--r--mm/swap.c42
-rw-r--r--mm/swapfile.c43
-rw-r--r--mm/truncate.c22
-rw-r--r--mm/vmalloc.c122
-rw-r--r--mm/vmscan.c240
-rw-r--r--net/bridge/br_forward.c4
-rw-r--r--net/bridge/br_if.c17
-rw-r--r--net/bridge/br_netfilter.c2
-rw-r--r--net/core/dev.c143
-rw-r--r--net/core/ethtool.c29
-rw-r--r--net/core/link_watch.c5
-rw-r--r--net/core/skbuff.c178
-rw-r--r--net/dccp/Kconfig2
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_wx.c2
-rw-r--r--net/ipv4/af_inet.c51
-rw-r--r--net/ipv4/ip_output.c16
-rw-r--r--net/ipv4/netfilter/ip_tables.c2
-rw-r--r--net/ipv4/route.c2
-rw-r--r--net/ipv4/tcp.c66
-rw-r--r--net/ipv4/tcp_input.c2
-rw-r--r--net/ipv4/tcp_output.c47
-rw-r--r--net/ipv4/xfrm4_output.c54
-rw-r--r--net/ipv6/addrconf.c9
-rw-r--r--net/ipv6/ip6_output.c7
-rw-r--r--net/ipv6/xfrm6_output.c39
-rw-r--r--net/sched/sch_generic.c29
-rw-r--r--net/socket.c7
-rw-r--r--net/sunrpc/auth_null.c2
-rw-r--r--net/sunrpc/auth_unix.c1
-rw-r--r--net/sunrpc/rpc_pipe.c8
-rw-r--r--net/sunrpc/xdr.c28
-rw-r--r--net/sunrpc/xprt.c4
-rw-r--r--net/sunrpc/xprtsock.c11
-rwxr-xr-xscripts/bloat-o-meter3
-rwxr-xr-xscripts/checkstack.pl14
-rwxr-xr-xscripts/kernel-doc19
-rw-r--r--security/dummy.c16
-rw-r--r--security/inode.c10
-rw-r--r--security/keys/key.c12
-rw-r--r--security/keys/keyring.c5
-rw-r--r--security/keys/process_keys.c57
-rw-r--r--security/keys/request_key.c6
-rw-r--r--security/keys/request_key_auth.c47
-rw-r--r--security/selinux/hooks.c82
-rw-r--r--security/selinux/include/av_perm_to_string.h6
-rw-r--r--security/selinux/include/av_permissions.h8
-rw-r--r--security/selinux/include/class_to_string.h1
-rw-r--r--security/selinux/include/flask.h1
-rw-r--r--security/selinux/include/objsec.h5
-rw-r--r--security/selinux/selinuxfs.c7
-rw-r--r--sound/Kconfig2
-rw-r--r--sound/Makefile2
-rw-r--r--sound/aoa/Kconfig17
-rw-r--r--sound/aoa/Makefile4
-rw-r--r--sound/aoa/aoa-gpio.h81
-rw-r--r--sound/aoa/aoa.h131
-rw-r--r--sound/aoa/codecs/Kconfig32
-rw-r--r--sound/aoa/codecs/Makefile3
-rw-r--r--sound/aoa/codecs/snd-aoa-codec-onyx.c1113
-rw-r--r--sound/aoa/codecs/snd-aoa-codec-onyx.h76
-rw-r--r--sound/aoa/codecs/snd-aoa-codec-tas-gain-table.h209
-rw-r--r--sound/aoa/codecs/snd-aoa-codec-tas.c654
-rw-r--r--sound/aoa/codecs/snd-aoa-codec-tas.h47
-rw-r--r--sound/aoa/codecs/snd-aoa-codec-toonie.c141
-rw-r--r--sound/aoa/core/Makefile5
-rw-r--r--sound/aoa/core/snd-aoa-alsa.c98
-rw-r--r--sound/aoa/core/snd-aoa-alsa.h16
-rw-r--r--sound/aoa/core/snd-aoa-core.c162
-rw-r--r--sound/aoa/core/snd-aoa-gpio-feature.c399
-rw-r--r--sound/aoa/core/snd-aoa-gpio-pmf.c246
-rw-r--r--sound/aoa/fabrics/Kconfig12
-rw-r--r--sound/aoa/fabrics/Makefile1
-rw-r--r--sound/aoa/fabrics/snd-aoa-fabric-layout.c1109
-rw-r--r--sound/aoa/soundbus/Kconfig14
-rw-r--r--sound/aoa/soundbus/Makefile3
-rw-r--r--sound/aoa/soundbus/core.c250
-rw-r--r--sound/aoa/soundbus/i2sbus/Makefile2
-rw-r--r--sound/aoa/soundbus/i2sbus/i2sbus-control.c192
-rw-r--r--sound/aoa/soundbus/i2sbus/i2sbus-control.h37
-rw-r--r--sound/aoa/soundbus/i2sbus/i2sbus-core.c387
-rw-r--r--sound/aoa/soundbus/i2sbus/i2sbus-interface.h187
-rw-r--r--sound/aoa/soundbus/i2sbus/i2sbus-pcm.c1021
-rw-r--r--sound/aoa/soundbus/i2sbus/i2sbus.h112
-rw-r--r--sound/aoa/soundbus/soundbus.h202
-rw-r--r--sound/aoa/soundbus/sysfs.c43
-rw-r--r--sound/arm/sa11xx-uda1341.c16
-rw-r--r--sound/core/control.c31
-rw-r--r--sound/core/device.c6
-rw-r--r--sound/core/hwdep.c1
-rw-r--r--sound/core/info.c178
-rw-r--r--sound/core/info_oss.c3
-rw-r--r--sound/core/init.c78
-rw-r--r--sound/core/isadma.c6
-rw-r--r--sound/core/memory.c5
-rw-r--r--sound/core/misc.c6
-rw-r--r--sound/core/oss/mixer_oss.c2
-rw-r--r--sound/core/oss/pcm_oss.c529
-rw-r--r--sound/core/pcm.c90
-rw-r--r--sound/core/pcm_compat.c4
-rw-r--r--sound/core/pcm_lib.c725
-rw-r--r--sound/core/pcm_memory.c14
-rw-r--r--sound/core/pcm_misc.c24
-rw-r--r--sound/core/pcm_native.c113
-rw-r--r--sound/core/rawmidi.c3
-rw-r--r--sound/core/seq/oss/seq_oss.c1
-rw-r--r--sound/core/seq/seq.c22
-rw-r--r--sound/core/seq/seq_clientmgr.c12
-rw-r--r--sound/core/seq/seq_device.c3
-rw-r--r--sound/core/seq/seq_dummy.c6
-rw-r--r--sound/core/seq/seq_info.c11
-rw-r--r--sound/core/seq/seq_lock.c2
-rw-r--r--sound/core/seq/seq_memory.c3
-rw-r--r--sound/core/seq/seq_midi.c11
-rw-r--r--sound/core/seq/seq_ports.c5
-rw-r--r--sound/core/seq/seq_virmidi.c4
-rw-r--r--sound/core/sound.c109
-rw-r--r--sound/core/sound_oss.c9
-rw-r--r--sound/core/timer.c6
-rw-r--r--sound/drivers/dummy.c4
-rw-r--r--sound/drivers/mpu401/mpu401.c4
-rw-r--r--sound/drivers/mpu401/mpu401_uart.c186
-rw-r--r--sound/drivers/mtpav.c14
-rw-r--r--sound/drivers/opl3/opl3_lib.c19
-rw-r--r--sound/drivers/opl3/opl3_oss.c3
-rw-r--r--sound/drivers/opl3/opl3_seq.c4
-rw-r--r--sound/drivers/opl3/opl3_synth.c4
-rw-r--r--sound/drivers/opl4/opl4_lib.c12
-rw-r--r--sound/drivers/opl4/opl4_seq.c4
-rw-r--r--sound/drivers/serial-u16550.c4
-rw-r--r--sound/drivers/virmidi.c4
-rw-r--r--sound/drivers/vx/vx_core.c32
-rw-r--r--sound/drivers/vx/vx_hwdep.c3
-rw-r--r--sound/i2c/i2c.c17
-rw-r--r--sound/i2c/l3/uda1341.c4
-rw-r--r--sound/isa/gus/gus_irq.c2
-rw-r--r--sound/isa/gus/gus_mem.c6
-rw-r--r--sound/isa/gus/gus_synth.c4
-rw-r--r--sound/isa/gus/interwave.c4
-rw-r--r--sound/isa/opl3sa2.c12
-rw-r--r--sound/isa/opti9xx/miro.c2
-rw-r--r--sound/isa/sb/emu8000.c22
-rw-r--r--sound/isa/sb/emu8000_patch.c2
-rw-r--r--sound/isa/sb/sb16.c2
-rw-r--r--sound/isa/sb/sb16_csp.c2
-rw-r--r--sound/isa/sb/sb8_midi.c20
-rw-r--r--sound/isa/sscape.c3
-rw-r--r--sound/isa/wavefront/wavefront.c2
-rw-r--r--sound/oss/Kconfig5
-rw-r--r--sound/oss/au1550_ac97.c11
-rw-r--r--sound/oss/cs46xx.c1272
-rw-r--r--sound/oss/emu10k1/midi.c2
-rw-r--r--sound/oss/msnd.c2
-rw-r--r--sound/pci/Kconfig9
-rw-r--r--sound/pci/ac97/ac97_codec.c61
-rw-r--r--sound/pci/ac97/ac97_patch.c19
-rw-r--r--sound/pci/ac97/ac97_pcm.c10
-rw-r--r--sound/pci/ac97/ac97_proc.c5
-rw-r--r--sound/pci/ac97/ak4531_codec.c2
-rw-r--r--sound/pci/ad1889.c2
-rw-r--r--sound/pci/ali5451/ali5451.c4
-rw-r--r--sound/pci/als4000.c4
-rw-r--r--sound/pci/atiixp.c2
-rw-r--r--sound/pci/atiixp_modem.c2
-rw-r--r--sound/pci/au88x0/au88x0.c12
-rw-r--r--sound/pci/au88x0/au88x0_mpu401.c11
-rw-r--r--sound/pci/au88x0/au88x0_xtalk.c29
-rw-r--r--sound/pci/azt3328.c234
-rw-r--r--sound/pci/azt3328.h36
-rw-r--r--sound/pci/bt87x.c8
-rw-r--r--sound/pci/ca0106/ca0106.h4
-rw-r--r--sound/pci/ca0106/ca0106_main.c57
-rw-r--r--sound/pci/ca0106/ca0106_mixer.c181
-rw-r--r--sound/pci/ca0106/ca0106_proc.c17
-rw-r--r--sound/pci/cmipci.c10
-rw-r--r--sound/pci/cs4281.c16
-rw-r--r--sound/pci/cs46xx/cs46xx.c4
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.c5
-rw-r--r--sound/pci/cs46xx/dsp_spos.c7
-rw-r--r--sound/pci/cs46xx/dsp_spos_scb_lib.c1
-rw-r--r--sound/pci/cs5535audio/Makefile4
-rw-r--r--sound/pci/cs5535audio/cs5535audio.c41
-rw-r--r--sound/pci/cs5535audio/cs5535audio.h8
-rw-r--r--sound/pci/cs5535audio/cs5535audio_pcm.c24
-rw-r--r--sound/pci/cs5535audio/cs5535audio_pm.c123
-rw-r--r--sound/pci/emu10k1/emu10k1.c8
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c69
-rw-r--r--sound/pci/emu10k1/emu10k1x.c3
-rw-r--r--sound/pci/emu10k1/emumixer.c54
-rw-r--r--sound/pci/emu10k1/emuproc.c27
-rw-r--r--sound/pci/emu10k1/io.c4
-rw-r--r--sound/pci/emu10k1/memory.c8
-rw-r--r--sound/pci/emu10k1/p17v.h111
-rw-r--r--sound/pci/emu10k1/tina2.h8
-rw-r--r--sound/pci/emu10k1/voice.c4
-rw-r--r--sound/pci/ens1370.c2
-rw-r--r--sound/pci/es1938.c3
-rw-r--r--sound/pci/es1968.c5
-rw-r--r--sound/pci/fm801.c5
-rw-r--r--sound/pci/hda/Makefile2
-rw-r--r--sound/pci/hda/hda_codec.c41
-rw-r--r--sound/pci/hda/hda_intel.c20
-rw-r--r--sound/pci/hda/hda_patch.h3
-rw-r--r--sound/pci/hda/hda_proc.c6
-rw-r--r--sound/pci/hda/patch_analog.c61
-rw-r--r--sound/pci/hda/patch_atihdmi.c165
-rw-r--r--sound/pci/hda/patch_realtek.c30
-rw-r--r--sound/pci/hda/patch_sigmatel.c82
-rw-r--r--sound/pci/ice1712/aureon.c26
-rw-r--r--sound/pci/ice1712/aureon.h1
-rw-r--r--sound/pci/ice1712/ews.c3
-rw-r--r--sound/pci/ice1712/ice1712.c43
-rw-r--r--sound/pci/ice1712/ice1712.h5
-rw-r--r--sound/pci/ice1712/ice1724.c5
-rw-r--r--sound/pci/ice1712/pontis.c8
-rw-r--r--sound/pci/intel8x0.c10
-rw-r--r--sound/pci/intel8x0m.c4
-rw-r--r--sound/pci/korg1212/korg1212.c2
-rw-r--r--sound/pci/maestro3.c3
-rw-r--r--sound/pci/mixart/mixart.c1
-rw-r--r--sound/pci/pcxhr/pcxhr.c4
-rw-r--r--sound/pci/riptide/riptide.c6
-rw-r--r--sound/pci/rme32.c14
-rw-r--r--sound/pci/rme96.c44
-rw-r--r--sound/pci/rme9652/hdsp.c7
-rw-r--r--sound/pci/rme9652/hdspm.c2
-rw-r--r--sound/pci/rme9652/rme9652.c4
-rw-r--r--sound/pci/sonicvibes.c8
-rw-r--r--sound/pci/trident/trident.c3
-rw-r--r--sound/pci/trident/trident_main.c22
-rw-r--r--sound/pci/trident/trident_memory.c3
-rw-r--r--sound/pci/trident/trident_synth.c4
-rw-r--r--sound/pci/via82xx.c12
-rw-r--r--sound/pci/via82xx_modem.c2
-rw-r--r--sound/pci/ymfpci/ymfpci.c3
-rw-r--r--sound/pci/ymfpci/ymfpci_main.c2
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf_core.c2
-rw-r--r--sound/pcmcia/vx/vxp_ops.c2
-rw-r--r--sound/pcmcia/vx/vxpocket.c2
-rw-r--r--sound/ppc/Makefile2
-rw-r--r--sound/ppc/pmac.c44
-rw-r--r--sound/ppc/pmac.h3
-rw-r--r--sound/ppc/powermac.c21
-rw-r--r--sound/ppc/toonie.c378
-rw-r--r--sound/sparc/amd7930.c138
-rw-r--r--sound/sparc/cs4231.c13
-rw-r--r--sound/sparc/dbri.c8
-rw-r--r--sound/synth/emux/emux.c12
-rw-r--r--sound/synth/emux/emux_proc.c1
-rw-r--r--sound/synth/emux/emux_seq.c3
-rw-r--r--sound/synth/emux/emux_synth.c5
-rw-r--r--sound/synth/emux/soundfont.c6
-rw-r--r--sound/usb/usbaudio.c15
-rw-r--r--sound/usb/usbaudio.h7
-rw-r--r--sound/usb/usbmidi.c202
-rw-r--r--sound/usb/usbmixer.c70
-rw-r--r--sound/usb/usx2y/usx2yhwdeppcm.c2
2162 files changed, 102029 insertions, 44965 deletions
diff --git a/CREDITS b/CREDITS
index 9bf714a..1d35f10 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1573,12 +1573,8 @@ S: 160 00 Praha 6
S: Czech Republic
N: Niels Kristian Bech Jensen
-E: nkbj@image.dk
-W: http://www.image.dk/~nkbj
+E: nkbj1970@hotmail.com
D: Miscellaneous kernel updates and fixes.
-S: Dr. Holsts Vej 34, lejl. 164
-S: DK-8230 Åbyhøj
-S: Denmark
N: Michael K. Johnson
E: johnsonm@redhat.com
diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle
index ce5d2c0..6d2412e 100644
--- a/Documentation/CodingStyle
+++ b/Documentation/CodingStyle
@@ -155,7 +155,83 @@ problem, which is called the function-growth-hormone-imbalance syndrome.
See next chapter.
- Chapter 5: Functions
+ Chapter 5: Typedefs
+
+Please don't use things like "vps_t".
+
+It's a _mistake_ to use typedef for structures and pointers. When you see a
+
+ vps_t a;
+
+in the source, what does it mean?
+
+In contrast, if it says
+
+ struct virtual_container *a;
+
+you can actually tell what "a" is.
+
+Lots of people think that typedefs "help readability". Not so. They are
+useful only for:
+
+ (a) totally opaque objects (where the typedef is actively used to _hide_
+ what the object is).
+
+ Example: "pte_t" etc. opaque objects that you can only access using
+ the proper accessor functions.
+
+ NOTE! Opaqueness and "accessor functions" are not good in themselves.
+ The reason we have them for things like pte_t etc. is that there
+ really is absolutely _zero_ portably accessible information there.
+
+ (b) Clear integer types, where the abstraction _helps_ avoid confusion
+ whether it is "int" or "long".
+
+ u8/u16/u32 are perfectly fine typedefs, although they fit into
+ category (d) better than here.
+
+ NOTE! Again - there needs to be a _reason_ for this. If something is
+ "unsigned long", then there's no reason to do
+
+ typedef unsigned long myflags_t;
+
+ but if there is a clear reason for why it under certain circumstances
+ might be an "unsigned int" and under other configurations might be
+ "unsigned long", then by all means go ahead and use a typedef.
+
+ (c) when you use sparse to literally create a _new_ type for
+ type-checking.
+
+ (d) New types which are identical to standard C99 types, in certain
+ exceptional circumstances.
+
+ Although it would only take a short amount of time for the eyes and
+ brain to become accustomed to the standard types like 'uint32_t',
+ some people object to their use anyway.
+
+ Therefore, the Linux-specific 'u8/u16/u32/u64' types and their
+ signed equivalents which are identical to standard types are
+ permitted -- although they are not mandatory in new code of your
+ own.
+
+ When editing existing code which already uses one or the other set
+ of types, you should conform to the existing choices in that code.
+
+ (e) Types safe for use in userspace.
+
+ In certain structures which are visible to userspace, we cannot
+ require C99 types and cannot use the 'u32' form above. Thus, we
+ use __u32 and similar types in all structures which are shared
+ with userspace.
+
+Maybe there are other cases too, but the rule should basically be to NEVER
+EVER use a typedef unless you can clearly match one of those rules.
+
+In general, a pointer, or a struct that has elements that can reasonably
+be directly accessed should _never_ be a typedef.
+
+
+ Chapter 6: Functions
Functions should be short and sweet, and do just one thing. They should
fit on one or two screenfuls of text (the ISO/ANSI screen size is 80x24,
@@ -183,7 +259,7 @@ and it gets confused. You know you're brilliant, but maybe you'd like
to understand what you did 2 weeks from now.
- Chapter 6: Centralized exiting of functions
+ Chapter 7: Centralized exiting of functions
Albeit deprecated by some people, the equivalent of the goto statement is
used frequently by compilers in form of the unconditional jump instruction.
@@ -220,7 +296,7 @@ out:
return result;
}
- Chapter 7: Commenting
+ Chapter 8: Commenting
Comments are good, but there is also a danger of over-commenting. NEVER
try to explain HOW your code works in a comment: it's much better to
@@ -240,7 +316,7 @@ When commenting the kernel API functions, please use the kerneldoc format.
See the files Documentation/kernel-doc-nano-HOWTO.txt and scripts/kernel-doc
for details.
- Chapter 8: You've made a mess of it
+ Chapter 9: You've made a mess of it
That's OK, we all do. You've probably been told by your long-time Unix
user helper that "GNU emacs" automatically formats the C sources for
@@ -288,7 +364,7 @@ re-formatting you may want to take a look at the man page. But
remember: "indent" is not a fix for bad programming.
- Chapter 9: Configuration-files
+ Chapter 10: Configuration-files
For configuration options (arch/xxx/Kconfig, and all the Kconfig files),
somewhat different indentation is used.
@@ -313,7 +389,7 @@ support for file-systems, for instance) should be denoted (DANGEROUS), other
experimental options should be denoted (EXPERIMENTAL).
- Chapter 10: Data structures
+ Chapter 11: Data structures
Data structures that have visibility outside the single-threaded
environment they are created and destroyed in should always have
@@ -344,7 +420,7 @@ Remember: if another thread can find your data structure, and you don't
have a reference count on it, you almost certainly have a bug.
- Chapter 11: Macros, Enums and RTL
+ Chapter 12: Macros, Enums and RTL
Names of macros defining constants and labels in enums are capitalized.
@@ -399,7 +475,7 @@ The cpp manual deals with macros exhaustively. The gcc internals manual also
covers RTL which is used frequently with assembly language in the kernel.
- Chapter 12: Printing kernel messages
+ Chapter 13: Printing kernel messages
Kernel developers like to be seen as literate. Do mind the spelling
of kernel messages to make a good impression. Do not use crippled
@@ -410,7 +486,7 @@ Kernel messages do not have to be terminated with a period.
Printing numbers in parentheses (%d) adds no value and should be avoided.
- Chapter 13: Allocating memory
+ Chapter 14: Allocating memory
The kernel provides the following general purpose memory allocators:
kmalloc(), kzalloc(), kcalloc(), and vmalloc(). Please refer to the API
@@ -429,7 +505,7 @@ from void pointer to any other pointer type is guaranteed by the C programming
language.
- Chapter 14: The inline disease
+ Chapter 15: The inline disease
There appears to be a common misperception that gcc has a magic "make me
faster" speedup option called "inline". While the use of inlines can be
@@ -457,7 +533,7 @@ something it would have done anyway.
- Chapter 15: References
+ Appendix I: References
The C Programming Language, Second Edition
by Brian W. Kernighan and Dennis M. Ritchie.
@@ -481,4 +557,4 @@ Kernel CodingStyle, by greg@kroah.com at OLS 2002:
http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
--
-Last updated on 30 December 2005 by a community effort on LKML.
+Last updated on 30 April 2006.
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index ca02e04..3630a0d 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -62,6 +62,8 @@
<sect1><title>Internal Functions</title>
!Ikernel/exit.c
!Ikernel/signal.c
+!Iinclude/linux/kthread.h
+!Ekernel/kthread.c
</sect1>
<sect1><title>Kernel objects manipulation</title>
@@ -114,9 +116,33 @@ X!Ilib/string.c
</sect1>
</chapter>
+ <chapter id="kernel-lib">
+ <title>Basic Kernel Library Functions</title>
+
+ <para>
+ The Linux kernel provides more basic utility functions.
+ </para>
+
+ <sect1><title>Bitmap Operations</title>
+!Elib/bitmap.c
+!Ilib/bitmap.c
+ </sect1>
+
+ <sect1><title>Command-line Parsing</title>
+!Elib/cmdline.c
+ </sect1>
+
+ <sect1><title>CRC Functions</title>
+!Elib/crc16.c
+!Elib/crc32.c
+!Elib/crc-ccitt.c
+ </sect1>
+ </chapter>
+
<chapter id="mm">
<title>Memory Management in Linux</title>
<sect1><title>The Slab Cache</title>
+!Iinclude/linux/slab.h
!Emm/slab.c
</sect1>
<sect1><title>User Space Memory Access</title>
@@ -280,12 +306,13 @@ X!Ekernel/module.c
<sect1><title>MTRR Handling</title>
!Earch/i386/kernel/cpu/mtrr/main.c
</sect1>
+
<sect1><title>PCI Support Library</title>
!Edrivers/pci/pci.c
!Edrivers/pci/pci-driver.c
!Edrivers/pci/remove.c
!Edrivers/pci/pci-acpi.c
-<!-- kerneldoc does not understand to __devinit
+<!-- kerneldoc does not understand __devinit
X!Edrivers/pci/search.c
-->
!Edrivers/pci/msi.c
@@ -314,6 +341,13 @@ X!Earch/i386/kernel/mca.c
</sect1>
</chapter>
+ <chapter id="firmware">
+ <title>Firmware Interfaces</title>
+ <sect1><title>DMI Interfaces</title>
+!Edrivers/firmware/dmi_scan.c
+ </sect1>
+ </chapter>
+
<chapter id="devfs">
<title>The Device File System</title>
!Efs/devfs/base.c
@@ -331,6 +365,18 @@ X!Earch/i386/kernel/mca.c
!Esecurity/security.c
</chapter>
+ <chapter id="audit">
+ <title>Audit Interfaces</title>
+!Ekernel/audit.c
+!Ikernel/auditsc.c
+!Ikernel/auditfilter.c
+ </chapter>
+
+ <chapter id="accounting">
+ <title>Accounting Framework</title>
+!Ikernel/acct.c
+ </chapter>
+
<chapter id="pmfuncs">
<title>Power Management</title>
!Ekernel/power/pm.c
@@ -390,7 +436,6 @@ X!Edrivers/pnp/system.c
</sect1>
</chapter>
-
<chapter id="blkdev">
<title>Block Devices</title>
!Eblock/ll_rw_blk.c
@@ -401,6 +446,14 @@ X!Edrivers/pnp/system.c
!Edrivers/char/misc.c
</chapter>
+ <chapter id="parportdev">
+ <title>Parallel Port Devices</title>
+!Iinclude/linux/parport.h
+!Edrivers/parport/ieee1284.c
+!Edrivers/parport/share.c
+!Idrivers/parport/daisy.c
+ </chapter>
+
<chapter id="viddev">
<title>Video4Linux</title>
!Edrivers/media/video/videodev.c
diff --git a/Documentation/DocBook/libata.tmpl b/Documentation/DocBook/libata.tmpl
index f869b03..e97c323 100644
--- a/Documentation/DocBook/libata.tmpl
+++ b/Documentation/DocBook/libata.tmpl
@@ -169,6 +169,22 @@ void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf);
</sect2>
+ <sect2><title>PIO data read/write</title>
+ <programlisting>
+void (*data_xfer) (struct ata_device *, unsigned char *, unsigned int, int);
+ </programlisting>
+
+ <para>
+All bmdma-style drivers must implement this hook. This is the low-level
+operation that actually copies the data bytes during a PIO data
+transfer.
+Typically the driver
+will choose one of ata_pio_data_xfer_noirq(), ata_pio_data_xfer(), or
+ata_mmio_data_xfer().
+ </para>
+
+ </sect2>
+
<sect2><title>ATA command execute</title>
<programlisting>
void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
@@ -204,11 +220,10 @@ command.
<programlisting>
u8 (*check_status)(struct ata_port *ap);
u8 (*check_altstatus)(struct ata_port *ap);
-u8 (*check_err)(struct ata_port *ap);
</programlisting>
<para>
- Reads the Status/AltStatus/Error ATA shadow register from
+ Reads the Status/AltStatus ATA shadow register from
hardware. On some hardware, reading the Status register has
the side effect of clearing the interrupt condition.
Most drivers for taskfile-based hardware use
@@ -269,23 +284,6 @@ void (*set_mode) (struct ata_port *ap);
</sect2>
- <sect2><title>Reset ATA bus</title>
- <programlisting>
-void (*phy_reset) (struct ata_port *ap);
- </programlisting>
-
- <para>
- The very first step in the probe phase. Actions vary depending
- on the bus type, typically. After waking up the device and probing
- for device presence (PATA and SATA), typically a soft reset
- (SRST) will be performed. Drivers typically use the helper
- functions ata_bus_reset() or sata_phy_reset() for this hook.
- Many SATA drivers use sata_phy_reset() or call it from within
- their own phy_reset() functions.
- </para>
-
- </sect2>
-
<sect2><title>Control PCI IDE BMDMA engine</title>
<programlisting>
void (*bmdma_setup) (struct ata_queued_cmd *qc);
@@ -354,16 +352,74 @@ int (*qc_issue) (struct ata_queued_cmd *qc);
</sect2>
- <sect2><title>Timeout (error) handling</title>
+ <sect2><title>Exception and probe handling (EH)</title>
<programlisting>
void (*eng_timeout) (struct ata_port *ap);
+void (*phy_reset) (struct ata_port *ap);
+ </programlisting>
+
+ <para>
+Deprecated. Use ->error_handler() instead.
+ </para>
+
+ <programlisting>
+void (*freeze) (struct ata_port *ap);
+void (*thaw) (struct ata_port *ap);
+ </programlisting>
+
+ <para>
+ata_port_freeze() is called when HSM violations or some other
+condition disrupts normal operation of the port. A frozen port
+is not allowed to perform any operation until the port is
+thawed, which usually follows a successful reset.
+ </para>
+
+ <para>
+The optional ->freeze() callback can be used for freezing the port
+hardware-wise (e.g. mask interrupt and stop DMA engine). If a
+port cannot be frozen hardware-wise, the interrupt handler
+must ack and clear interrupts unconditionally while the port
+is frozen.
+ </para>
+ <para>
+The optional ->thaw() callback is called to perform the opposite of ->freeze():
+prepare the port for normal operation once again. Unmask interrupts,
+start DMA engine, etc.
+ </para>
+
+ <programlisting>
+void (*error_handler) (struct ata_port *ap);
+ </programlisting>
+
+ <para>
+->error_handler() is a driver's hook into probe, hotplug, and recovery
+and other exceptional conditions. The primary responsibility of an
+implementation is to call ata_do_eh() or ata_bmdma_drive_eh() with a set
+of EH hooks as arguments:
+ </para>
+
+ <para>
+'prereset' hook (may be NULL) is called during an EH reset, before any other actions
+are taken.
+ </para>
+
+ <para>
+'postreset' hook (may be NULL) is called after the EH reset is performed. Based on
+existing conditions, severity of the problem, and hardware capabilities,
+ </para>
+
+ <para>
+Either 'softreset' (may be NULL) or 'hardreset' (may be NULL) will be
+called to perform the low-level EH reset.
+ </para>
+
+ <programlisting>
+void (*post_internal_cmd) (struct ata_queued_cmd *qc);
</programlisting>
<para>
-This is a high level error handling function, called from the
-error handling thread, when a command times out. Most newer
-hardware will implement its own error handling code here. IDE BMDMA
-drivers may use the helper function ata_eng_timeout().
+Perform any hardware-specific actions necessary to finish processing
+after executing a probe-time or EH-time command via ata_exec_internal().
</para>
</sect2>
diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt
index 49e27cc..1d50cf0 100644
--- a/Documentation/RCU/checklist.txt
+++ b/Documentation/RCU/checklist.txt
@@ -144,9 +144,47 @@ over a rather long period of time, but improvements are always welcome!
whether the increased speed is worth it.
8. Although synchronize_rcu() is a bit slower than is call_rcu(),
- it usually results in simpler code. So, unless update performance
- is important or the updaters cannot block, synchronize_rcu()
- should be used in preference to call_rcu().
+ it usually results in simpler code. So, unless update
+ performance is critically important or the updaters cannot block,
+ synchronize_rcu() should be used in preference to call_rcu().
+
+ An especially important property of the synchronize_rcu()
+ primitive is that it automatically self-limits: if grace periods
+ are delayed for whatever reason, then the synchronize_rcu()
+ primitive will correspondingly delay updates. In contrast,
+ code using call_rcu() should explicitly limit update rate in
+ cases where grace periods are delayed, as failing to do so can
+ result in excessive realtime latencies or even OOM conditions.
+
+ Ways of gaining this self-limiting property when using call_rcu()
+ include:
+
+ a. Keeping a count of the number of data-structure elements
+ used by the RCU-protected data structure, including those
+ waiting for a grace period to elapse. Enforce a limit
+ on this number, stalling updates as needed to allow
+ previously deferred frees to complete.
+
+ Alternatively, limit only the number awaiting deferred
+ free rather than the total number of elements.
+
+ b. Limiting update rate. For example, if updates occur only
+ once per hour, then no explicit rate limiting is required,
+ unless your system is already badly broken. The dcache
+ subsystem takes this approach -- updates are guarded
+ by a global lock, limiting their rate.
+
+ c. Trusted update -- if updates can only be done manually by
+ superuser or some other trusted user, then it might not
+ be necessary to automatically limit them. The theory
+ here is that superuser already has lots of ways to crash
+ the machine.
+
+ d. Use call_rcu_bh() rather than call_rcu(), in order to take
+ advantage of call_rcu_bh()'s faster grace periods.
+
+ e. Periodically invoke synchronize_rcu(), permitting a limited
+ number of updates per grace period.
9. All RCU list-traversal primitives, which include
list_for_each_rcu(), list_for_each_entry_rcu(),
diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt
index 07cb93b..4f41a60 100644
--- a/Documentation/RCU/whatisRCU.txt
+++ b/Documentation/RCU/whatisRCU.txt
@@ -184,7 +184,17 @@ synchronize_rcu()
blocking, it registers a function and argument which are invoked
after all ongoing RCU read-side critical sections have completed.
This callback variant is particularly useful in situations where
- it is illegal to block.
+ it is illegal to block or where update-side performance is
+ critically important.
+
+ However, the call_rcu() API should not be used lightly, as use
+ of the synchronize_rcu() API generally results in simpler code.
+ In addition, the synchronize_rcu() API has the nice property
+ of automatically limiting update rate should grace periods
+ be delayed. This property results in system resilience in face
+ of denial-of-service attacks. Code using call_rcu() should limit
+ update rate in order to gain this same sort of resilience. See
+ checklist.txt for some approaches to limiting the update rate.
rcu_assign_pointer()
@@ -790,7 +800,6 @@ RCU pointer update:
RCU grace period:
- synchronize_kernel (deprecated)
synchronize_net
synchronize_sched
synchronize_rcu
diff --git a/Documentation/SubmitChecklist b/Documentation/SubmitChecklist
new file mode 100644
index 0000000..8230098
--- /dev/null
+++ b/Documentation/SubmitChecklist
@@ -0,0 +1,57 @@
+Linux Kernel patch sumbittal checklist
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Here are some basic things that developers should do if they
+want to see their kernel patch submittals accepted quicker.
+
+These are all above and beyond the documentation that is provided
+in Documentation/SubmittingPatches and elsewhere about submitting
+Linux kernel patches.
+
+
+
+- Builds cleanly with applicable or modified CONFIG options =y, =m, and =n.
+ No gcc warnings/errors, no linker warnings/errors.
+
+- Passes allnoconfig, allmodconfig
+
+- Builds on multiple CPU arch-es by using local cross-compile tools
+ or something like PLM at OSDL.
+
+- ppc64 is a good architecture for cross-compilation checking because it
+ tends to use `unsigned long' for 64-bit quantities.
+
+- Matches kernel coding style(!)
+
+- Any new or modified CONFIG options don't muck up the config menu.
+
+- All new Kconfig options have help text.
+
+- Has been carefully reviewed with respect to relevant Kconfig
+ combinations. This is very hard to get right with testing --
+ brainpower pays off here.
+
+- Check cleanly with sparse.
+
+- Use 'make checkstack' and 'make namespacecheck' and fix any
+ problems that they find. Note: checkstack does not point out
+ problems explicitly, but any one function that uses more than
+ 512 bytes on the stack is a candidate for change.
+
+- Include kernel-doc to document global kernel APIs. (Not required
+ for static functions, but OK there also.) Use 'make htmldocs'
+ or 'make mandocs' to check the kernel-doc and fix any issues.
+
+- Has been tested with CONFIG_PREEMPT, CONFIG_DEBUG_PREEMPT,
+ CONFIG_DEBUG_SLAB, CONFIG_DEBUG_PAGEALLOC, CONFIG_DEBUG_MUTEXES,
+ CONFIG_DEBUG_SPINLOCK, CONFIG_DEBUG_SPINLOCK_SLEEP all simultaneously
+ enabled.
+
+- Has been build- and runtime tested with and without CONFIG_SMP and
+ CONFIG_PREEMPT.
+
+- If the patch affects IO/Disk, etc: has been tested with and without
+ CONFIG_LBD.
+
+
+2006-APR-27
diff --git a/Documentation/devices.txt b/Documentation/devices.txt
index b369a8c..4aaf68f 100644
--- a/Documentation/devices.txt
+++ b/Documentation/devices.txt
@@ -3,7 +3,7 @@
Maintained by Torben Mathiasen <device@lanana.org>
- Last revised: 25 January 2005
+ Last revised: 15 May 2006
This list is the Linux Device List, the official registry of allocated
device numbers and /dev directory nodes for the Linux operating
@@ -94,7 +94,6 @@ Your cooperation is appreciated.
9 = /dev/urandom Faster, less secure random number gen.
10 = /dev/aio Asyncronous I/O notification interface
11 = /dev/kmsg Writes to this come out as printk's
- 12 = /dev/oldmem Access to crash dump from kexec kernel
1 block RAM disk
0 = /dev/ram0 First RAM disk
1 = /dev/ram1 Second RAM disk
@@ -262,13 +261,13 @@ Your cooperation is appreciated.
NOTE: These devices permit both read and write access.
7 block Loopback devices
- 0 = /dev/loop0 First loopback device
- 1 = /dev/loop1 Second loopback device
+ 0 = /dev/loop0 First loop device
+ 1 = /dev/loop1 Second loop device
...
- The loopback devices are used to mount filesystems not
+ The loop devices are used to mount filesystems not
associated with block devices. The binding to the
- loopback devices is handled by mount(8) or losetup(8).
+ loop devices is handled by mount(8) or losetup(8).
8 block SCSI disk devices (0-15)
0 = /dev/sda First SCSI disk whole disk
@@ -943,7 +942,7 @@ Your cooperation is appreciated.
240 = /dev/ftlp FTL on 16th Memory Technology Device
Partitions are handled in the same way as for IDE
- disks (see major number 3) expect that the partition
+ disks (see major number 3) except that the partition
limit is 15 rather than 63 per disk (same as SCSI.)
45 char isdn4linux ISDN BRI driver
@@ -1168,7 +1167,7 @@ Your cooperation is appreciated.
The filename of the encrypted container and the passwords
are sent via ioctls (using the sdmount tool) to the master
node which then activates them via one of the
- /dev/scramdisk/x nodes for loopback mounting (all handled
+ /dev/scramdisk/x nodes for loop mounting (all handled
through the sdmount tool).
Requested by: andy@scramdisklinux.org
@@ -2538,18 +2537,32 @@ Your cooperation is appreciated.
0 = /dev/usb/lp0 First USB printer
...
15 = /dev/usb/lp15 16th USB printer
- 16 = /dev/usb/mouse0 First USB mouse
- ...
- 31 = /dev/usb/mouse15 16th USB mouse
- 32 = /dev/usb/ez0 First USB firmware loader
- ...
- 47 = /dev/usb/ez15 16th USB firmware loader
48 = /dev/usb/scanner0 First USB scanner
...
63 = /dev/usb/scanner15 16th USB scanner
64 = /dev/usb/rio500 Diamond Rio 500
65 = /dev/usb/usblcd USBLCD Interface (info@usblcd.de)
66 = /dev/usb/cpad0 Synaptics cPad (mouse/LCD)
+ 96 = /dev/usb/hiddev0 1st USB HID device
+ ...
+ 111 = /dev/usb/hiddev15 16th USB HID device
+ 112 = /dev/usb/auer0 1st auerswald ISDN device
+ ...
+ 127 = /dev/usb/auer15 16th auerswald ISDN device
+ 128 = /dev/usb/brlvgr0 First Braille Voyager device
+ ...
+ 131 = /dev/usb/brlvgr3 Fourth Braille Voyager device
+ 132 = /dev/usb/idmouse ID Mouse (fingerprint scanner) device
+ 133 = /dev/usb/sisusbvga1 First SiSUSB VGA device
+ ...
+ 140 = /dev/usb/sisusbvga8 Eigth SISUSB VGA device
+ 144 = /dev/usb/lcd USB LCD device
+ 160 = /dev/usb/legousbtower0 1st USB Legotower device
+ ...
+ 175 = /dev/usb/legousbtower15 16th USB Legotower device
+ 240 = /dev/usb/dabusb0 First daubusb device
+ ...
+ 243 = /dev/usb/dabusb3 Fourth dabusb device
180 block USB block devices
0 = /dev/uba First USB block device
@@ -2710,6 +2723,17 @@ Your cooperation is appreciated.
1 = /dev/cpu/1/msr MSRs on CPU 1
...
+202 block Xen Virtual Block Device
+ 0 = /dev/xvda First Xen VBD whole disk
+ 16 = /dev/xvdb Second Xen VBD whole disk
+ 32 = /dev/xvdc Third Xen VBD whole disk
+ ...
+ 240 = /dev/xvdp Sixteenth Xen VBD whole disk
+
+ Partitions are handled in the same way as for IDE
+ disks (see major number 3) except that the limit on
+ partitions is 15.
+
203 char CPU CPUID information
0 = /dev/cpu/0/cpuid CPUID on CPU 0
1 = /dev/cpu/1/cpuid CPUID on CPU 1
@@ -2747,11 +2771,27 @@ Your cooperation is appreciated.
46 = /dev/ttyCPM0 PPC CPM (SCC or SMC) - port 0
...
47 = /dev/ttyCPM5 PPC CPM (SCC or SMC) - port 5
- 50 = /dev/ttyIOC40 Altix serial card
+ 50 = /dev/ttyIOC0 Altix serial card
+ ...
+ 81 = /dev/ttyIOC31 Altix serial card
+ 82 = /dev/ttyVR0 NEC VR4100 series SIU
+ 83 = /dev/ttyVR1 NEC VR4100 series DSIU
+ 84 = /dev/ttyIOC84 Altix ioc4 serial card
+ ...
+ 115 = /dev/ttyIOC115 Altix ioc4 serial card
+ 116 = /dev/ttySIOC0 Altix ioc3 serial card
+ ...
+ 147 = /dev/ttySIOC31 Altix ioc3 serial card
+ 148 = /dev/ttyPSC0 PPC PSC - port 0
+ ...
+ 153 = /dev/ttyPSC5 PPC PSC - port 5
+ 154 = /dev/ttyAT0 ATMEL serial port 0
+ ...
+ 169 = /dev/ttyAT15 ATMEL serial port 15
+ 170 = /dev/ttyNX0 Hilscher netX serial port 0
...
- 81 = /dev/ttyIOC431 Altix serial card
- 82 = /dev/ttyVR0 NEC VR4100 series SIU
- 83 = /dev/ttyVR1 NEC VR4100 series DSIU
+ 185 = /dev/ttyNX15 Hilscher netX serial port 15
+ 186 = /dev/ttyJ0 JTAG1 DCC protocol based serial port emulation
205 char Low-density serial ports (alternate device)
0 = /dev/culu0 Callout device for ttyLU0
@@ -2786,8 +2826,8 @@ Your cooperation is appreciated.
50 = /dev/cuioc40 Callout device for ttyIOC40
...
81 = /dev/cuioc431 Callout device for ttyIOC431
- 82 = /dev/cuvr0 Callout device for ttyVR0
- 83 = /dev/cuvr1 Callout device for ttyVR1
+ 82 = /dev/cuvr0 Callout device for ttyVR0
+ 83 = /dev/cuvr1 Callout device for ttyVR1
206 char OnStream SC-x0 tape devices
@@ -2897,7 +2937,6 @@ Your cooperation is appreciated.
...
196 = /dev/dvb/adapter3/video0 first video decoder of fourth card
-
216 char Bluetooth RFCOMM TTY devices
0 = /dev/rfcomm0 First Bluetooth RFCOMM TTY device
1 = /dev/rfcomm1 Second Bluetooth RFCOMM TTY device
@@ -3002,12 +3041,43 @@ Your cooperation is appreciated.
ioctl()'s can be used to rewind the tape regardless of
the device used to access it.
-231 char InfiniBand MAD
+231 char InfiniBand
0 = /dev/infiniband/umad0
1 = /dev/infiniband/umad1
- ...
+ ...
+ 63 = /dev/infiniband/umad63 63rd InfiniBandMad device
+ 64 = /dev/infiniband/issm0 First InfiniBand IsSM device
+ 65 = /dev/infiniband/issm1 Second InfiniBand IsSM device
+ ...
+ 127 = /dev/infiniband/issm63 63rd InfiniBand IsSM device
+ 128 = /dev/infiniband/uverbs0 First InfiniBand verbs device
+ 129 = /dev/infiniband/uverbs1 Second InfiniBand verbs device
+ ...
+ 159 = /dev/infiniband/uverbs31 31st InfiniBand verbs device
+
+232 char Biometric Devices
+ 0 = /dev/biometric/sensor0/fingerprint first fingerprint sensor on first device
+ 1 = /dev/biometric/sensor0/iris first iris sensor on first device
+ 2 = /dev/biometric/sensor0/retina first retina sensor on first device
+ 3 = /dev/biometric/sensor0/voiceprint first voiceprint sensor on first device
+ 4 = /dev/biometric/sensor0/facial first facial sensor on first device
+ 5 = /dev/biometric/sensor0/hand first hand sensor on first device
+ ...
+ 10 = /dev/biometric/sensor1/fingerprint first fingerprint sensor on second device
+ ...
+ 20 = /dev/biometric/sensor2/fingerprint first fingerprint sensor on third device
+ ...
+
+233 char PathScale InfiniPath interconnect
+ 0 = /dev/ipath Primary device for programs (any unit)
+ 1 = /dev/ipath0 Access specifically to unit 0
+ 2 = /dev/ipath1 Access specifically to unit 1
+ ...
+ 4 = /dev/ipath3 Access specifically to unit 3
+ 129 = /dev/ipath_sma Device used by Subnet Management Agent
+ 130 = /dev/ipath_diag Device used by diagnostics programs
-232-239 UNASSIGNED
+234-239 UNASSIGNED
240-254 char LOCAL/EXPERIMENTAL USE
240-254 block LOCAL/EXPERIMENTAL USE
@@ -3021,6 +3091,28 @@ Your cooperation is appreciated.
This major is reserved to assist the expansion to a
larger number space. No device nodes with this major
should ever be created on the filesystem.
+ (This is probaly not true anymore, but I'll leave it
+ for now /Torben)
+
+---LARGE MAJORS!!!!!---
+
+256 char Equinox SST multi-port serial boards
+ 0 = /dev/ttyEQ0 First serial port on first Equinox SST board
+ 127 = /dev/ttyEQ127 Last serial port on first Equinox SST board
+ 128 = /dev/ttyEQ128 First serial port on second Equinox SST board
+ ...
+ 1027 = /dev/ttyEQ1027 Last serial port on eighth Equinox SST board
+
+256 block Resident Flash Disk Flash Translation Layer
+ 0 = /dev/rfda First RFD FTL layer
+ 16 = /dev/rfdb Second RFD FTL layer
+ ...
+ 240 = /dev/rfdp 16th RFD FTL layer
+
+257 char Phoenix Technologies Cryptographic Services Driver
+ 0 = /dev/ptlsec Crypto Services Driver
+
+
**** ADDITIONAL /dev DIRECTORY ENTRIES
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index f729329..027285d 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -33,21 +33,6 @@ Who: Adrian Bunk <bunk@stusta.de>
---------------------------
-What: RCU API moves to EXPORT_SYMBOL_GPL
-When: April 2006
-Files: include/linux/rcupdate.h, kernel/rcupdate.c
-Why: Outside of Linux, the only implementations of anything even
- vaguely resembling RCU that I am aware of are in DYNIX/ptx,
- VM/XA, Tornado, and K42. I do not expect anyone to port binary
- drivers or kernel modules from any of these, since the first two
- are owned by IBM and the last two are open-source research OSes.
- So these will move to GPL after a grace period to allow
- people, who might be using implementations that I am not aware
- of, to adjust to this upcoming change.
-Who: Paul E. McKenney <paulmck@us.ibm.com>
-
----------------------------
-
What: raw1394: requests of type RAW1394_REQ_ISO_SEND, RAW1394_REQ_ISO_LISTEN
When: November 2006
Why: Deprecated in favour of the new ioctl-based rawiso interface, which is
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 1045da5..d31efbb 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -99,7 +99,7 @@ prototypes:
int (*sync_fs)(struct super_block *sb, int wait);
void (*write_super_lockfs) (struct super_block *);
void (*unlockfs) (struct super_block *);
- int (*statfs) (struct super_block *, struct kstatfs *);
+ int (*statfs) (struct dentry *, struct kstatfs *);
int (*remount_fs) (struct super_block *, int *, char *);
void (*clear_inode) (struct inode *);
void (*umount_begin) (struct super_block *);
@@ -142,15 +142,16 @@ see also dquot_operations section.
--------------------------- file_system_type ---------------------------
prototypes:
- struct super_block *(*get_sb) (struct file_system_type *, int,
- const char *, void *);
+ struct int (*get_sb) (struct file_system_type *, int,
+ const char *, void *, struct vfsmount *);
void (*kill_sb) (struct super_block *);
locking rules:
may block BKL
get_sb yes yes
kill_sb yes yes
-->get_sb() returns error or a locked superblock (exclusive on ->s_umount).
+->get_sb() returns error or 0 with locked superblock attached to the vfsmount
+(exclusive on ->s_umount).
->kill_sb() takes a write-locked superblock, does all shutdown work on it,
unlocks and drops the reference.
diff --git a/Documentation/filesystems/automount-support.txt b/Documentation/filesystems/automount-support.txt
index 58c65a1..7cac200 100644
--- a/Documentation/filesystems/automount-support.txt
+++ b/Documentation/filesystems/automount-support.txt
@@ -19,7 +19,7 @@ following procedure:
(2) Have the follow_link() op do the following steps:
- (a) Call do_kern_mount() to call the appropriate filesystem to set up a
+ (a) Call vfs_kern_mount() to call the appropriate filesystem to set up a
superblock and gain a vfsmount structure representing it.
(b) Copy the nameidata provided as an argument and substitute the dentry
diff --git a/Documentation/filesystems/fuse.txt b/Documentation/filesystems/fuse.txt
index 33f7431..a584f05 100644
--- a/Documentation/filesystems/fuse.txt
+++ b/Documentation/filesystems/fuse.txt
@@ -18,6 +18,14 @@ Non-privileged mount (or user mount):
user. NOTE: this is not the same as mounts allowed with the "user"
option in /etc/fstab, which is not discussed here.
+Filesystem connection:
+
+ A connection between the filesystem daemon and the kernel. The
+ connection exists until either the daemon dies, or the filesystem is
+ umounted. Note that detaching (or lazy umounting) the filesystem
+ does _not_ break the connection, in this case it will exist until
+ the last reference to the filesystem is released.
+
Mount owner:
The user who does the mounting.
@@ -86,16 +94,20 @@ Mount options
The default is infinite. Note that the size of read requests is
limited anyway to 32 pages (which is 128kbyte on i386).
-Sysfs
-~~~~~
+Control filesystem
+~~~~~~~~~~~~~~~~~~
+
+There's a control filesystem for FUSE, which can be mounted by:
-FUSE sets up the following hierarchy in sysfs:
+ mount -t fusectl none /sys/fs/fuse/connections
- /sys/fs/fuse/connections/N/
+Mounting it under the '/sys/fs/fuse/connections' directory makes it
+backwards compatible with earlier versions.
-where N is an increasing number allocated to each new connection.
+Under the fuse control filesystem each connection has a directory
+named by a unique number.
-For each connection the following attributes are defined:
+For each connection the following files exist within this directory:
'waiting'
@@ -110,7 +122,47 @@ For each connection the following attributes are defined:
connection. This means that all waiting requests will be aborted an
error returned for all aborted and new requests.
-Only a privileged user may read or write these attributes.
+Only the owner of the mount may read or write these files.
+
+Interrupting filesystem operations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If a process issuing a FUSE filesystem request is interrupted, the
+following will happen:
+
+ 1) If the request is not yet sent to userspace AND the signal is
+ fatal (SIGKILL or unhandled fatal signal), then the request is
+ dequeued and returns immediately.
+
+ 2) If the request is not yet sent to userspace AND the signal is not
+ fatal, then an 'interrupted' flag is set for the request. When
+ the request has been successfully transfered to userspace and
+ this flag is set, an INTERRUPT request is queued.
+
+ 3) If the request is already sent to userspace, then an INTERRUPT
+ request is queued.
+
+INTERRUPT requests take precedence over other requests, so the
+userspace filesystem will receive queued INTERRUPTs before any others.
+
+The userspace filesystem may ignore the INTERRUPT requests entirely,
+or may honor them by sending a reply to the _original_ request, with
+the error set to EINTR.
+
+It is also possible that there's a race between processing the
+original request and it's INTERRUPT request. There are two possibilities:
+
+ 1) The INTERRUPT request is processed before the original request is
+ processed
+
+ 2) The INTERRUPT request is processed after the original request has
+ been answered
+
+If the filesystem cannot find the original request, it should wait for
+some timeout and/or a number of new requests to arrive, after which it
+should reply to the INTERRUPT request with an EAGAIN error. In case
+1) the INTERRUPT request will be requeued. In case 2) the INTERRUPT
+reply will be ignored.
Aborting a filesystem connection
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -139,8 +191,8 @@ the filesystem. There are several ways to do this:
- Use forced umount (umount -f). Works in all cases but only if
filesystem is still attached (it hasn't been lazy unmounted)
- - Abort filesystem through the sysfs interface. Most powerful
- method, always works.
+ - Abort filesystem through the FUSE control filesystem. Most
+ powerful method, always works.
How do non-privileged mounts work?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -304,25 +356,7 @@ Scenario 1 - Simple deadlock
| | for "file"]
| | *DEADLOCK*
-The solution for this is to allow requests to be interrupted while
-they are in userspace:
-
- | [interrupted by signal] |
- | <fuse_unlink() |
- | [release semaphore] | [semaphore acquired]
- | <sys_unlink() |
- | | >fuse_unlink()
- | | [queue req on fc->pending]
- | | [wake up fc->waitq]
- | | [sleep on req->waitq]
-
-If the filesystem daemon was single threaded, this will stop here,
-since there's no other thread to dequeue and execute the request.
-In this case the solution is to kill the FUSE daemon as well. If
-there are multiple serving threads, you just have to kill them as
-long as any remain.
-
-Moral: a filesystem which deadlocks, can soon find itself dead.
+The solution for this is to allow the filesystem to be aborted.
Scenario 2 - Tricky deadlock
----------------------------
@@ -355,24 +389,14 @@ but is caused by a pagefault.
| | [lock page]
| | * DEADLOCK *
-Solution is again to let the the request be interrupted (not
-elaborated further).
-
-An additional problem is that while the write buffer is being
-copied to the request, the request must not be interrupted. This
-is because the destination address of the copy may not be valid
-after the request is interrupted.
-
-This is solved with doing the copy atomically, and allowing
-interruption while the page(s) belonging to the write buffer are
-faulted with get_user_pages(). The 'req->locked' flag indicates
-when the copy is taking place, and interruption is delayed until
-this flag is unset.
+Solution is basically the same as above.
-Scenario 3 - Tricky deadlock with asynchronous read
----------------------------------------------------
+An additional problem is that while the write buffer is being copied
+to the request, the request must not be interrupted/aborted. This is
+because the destination address of the copy may not be valid after the
+request has returned.
-The same situation as above, except thread-1 will wait on page lock
-and hence it will be uninterruptible as well. The solution is to
-abort the connection with forced umount (if mount is attached) or
-through the abort attribute in sysfs.
+This is solved with doing the copy atomically, and allowing abort
+while the page(s) belonging to the write buffer are faulted with
+get_user_pages(). The 'req->locked' flag indicates when the copy is
+taking place, and abort is delayed until this flag is unset.
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index 2f38846..5531694 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -50,10 +50,11 @@ Turn your foo_read_super() into a function that would return 0 in case of
success and negative number in case of error (-EINVAL unless you have more
informative error value to report). Call it foo_fill_super(). Now declare
-struct super_block foo_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+int foo_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, ext2_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, foo_fill_super,
+ mnt);
}
(or similar with s/bdev/nodev/ or s/bdev/single/, depending on the kind of
diff --git a/Documentation/filesystems/ramfs-rootfs-initramfs.txt b/Documentation/filesystems/ramfs-rootfs-initramfs.txt
index 60ab61e..25981e2 100644
--- a/Documentation/filesystems/ramfs-rootfs-initramfs.txt
+++ b/Documentation/filesystems/ramfs-rootfs-initramfs.txt
@@ -70,11 +70,13 @@ tmpfs mounts. See Documentation/filesystems/tmpfs.txt for more information.
What is rootfs?
---------------
-Rootfs is a special instance of ramfs, which is always present in 2.6 systems.
-(It's used internally as the starting and stopping point for searches of the
-kernel's doubly-linked list of mount points.)
+Rootfs is a special instance of ramfs (or tmpfs, if that's enabled), which is
+always present in 2.6 systems. You can't unmount rootfs for approximately the
+same reason you can't kill the init process; rather than having special code
+to check for and handle an empty list, it's smaller and simpler for the kernel
+to just make sure certain lists can't become empty.
-Most systems just mount another filesystem over it and ignore it. The
+Most systems just mount another filesystem over rootfs and ignore it. The
amount of space an empty instance of ramfs takes up is tiny.
What is initramfs?
@@ -92,14 +94,16 @@ out of that.
All this differs from the old initrd in several ways:
- - The old initrd was a separate file, while the initramfs archive is linked
- into the linux kernel image. (The directory linux-*/usr is devoted to
- generating this archive during the build.)
+ - The old initrd was always a separate file, while the initramfs archive is
+ linked into the linux kernel image. (The directory linux-*/usr is devoted
+ to generating this archive during the build.)
- The old initrd file was a gzipped filesystem image (in some file format,
- such as ext2, that had to be built into the kernel), while the new
+ such as ext2, that needed a driver built into the kernel), while the new
initramfs archive is a gzipped cpio archive (like tar only simpler,
- see cpio(1) and Documentation/early-userspace/buffer-format.txt).
+ see cpio(1) and Documentation/early-userspace/buffer-format.txt). The
+ kernel's cpio extraction code is not only extremely small, it's also
+ __init data that can be discarded during the boot process.
- The program run by the old initrd (which was called /initrd, not /init) did
some setup and then returned to the kernel, while the init program from
@@ -124,13 +128,14 @@ Populating initramfs:
The 2.6 kernel build process always creates a gzipped cpio format initramfs
archive and links it into the resulting kernel binary. By default, this
-archive is empty (consuming 134 bytes on x86). The config option
-CONFIG_INITRAMFS_SOURCE (for some reason buried under devices->block devices
-in menuconfig, and living in usr/Kconfig) can be used to specify a source for
-the initramfs archive, which will automatically be incorporated into the
-resulting binary. This option can point to an existing gzipped cpio archive, a
-directory containing files to be archived, or a text file specification such
-as the following example:
+archive is empty (consuming 134 bytes on x86).
+
+The config option CONFIG_INITRAMFS_SOURCE (for some reason buried under
+devices->block devices in menuconfig, and living in usr/Kconfig) can be used
+to specify a source for the initramfs archive, which will automatically be
+incorporated into the resulting binary. This option can point to an existing
+gzipped cpio archive, a directory containing files to be archived, or a text
+file specification such as the following example:
dir /dev 755 0 0
nod /dev/console 644 0 0 c 5 1
@@ -146,23 +151,84 @@ as the following example:
Run "usr/gen_init_cpio" (after the kernel build) to get a usage message
documenting the above file format.
-One advantage of the text file is that root access is not required to
+One advantage of the configuration file is that root access is not required to
set permissions or create device nodes in the new archive. (Note that those
two example "file" entries expect to find files named "init.sh" and "busybox" in
a directory called "initramfs", under the linux-2.6.* directory. See
Documentation/early-userspace/README for more details.)
-The kernel does not depend on external cpio tools, gen_init_cpio is created
-from usr/gen_init_cpio.c which is entirely self-contained, and the kernel's
-boot-time extractor is also (obviously) self-contained. However, if you _do_
-happen to have cpio installed, the following command line can extract the
-generated cpio image back into its component files:
+The kernel does not depend on external cpio tools. If you specify a
+directory instead of a configuration file, the kernel's build infrastructure
+creates a configuration file from that directory (usr/Makefile calls
+scripts/gen_initramfs_list.sh), and proceeds to package up that directory
+using the config file (by feeding it to usr/gen_init_cpio, which is created
+from usr/gen_init_cpio.c). The kernel's build-time cpio creation code is
+entirely self-contained, and the kernel's boot-time extractor is also
+(obviously) self-contained.
+
+The one thing you might need external cpio utilities installed for is creating
+or extracting your own preprepared cpio files to feed to the kernel build
+(instead of a config file or directory).
+
+The following command line can extract a cpio image (either by the above script
+or by the kernel build) back into its component files:
cpio -i -d -H newc -F initramfs_data.cpio --no-absolute-filenames
+The following shell script can create a prebuilt cpio archive you can
+use in place of the above config file:
+
+ #!/bin/sh
+
+ # Copyright 2006 Rob Landley <rob@landley.net> and TimeSys Corporation.
+ # Licensed under GPL version 2
+
+ if [ $# -ne 2 ]
+ then
+ echo "usage: mkinitramfs directory imagename.cpio.gz"
+ exit 1
+ fi
+
+ if [ -d "$1" ]
+ then
+ echo "creating $2 from $1"
+ (cd "$1"; find . | cpio -o -H newc | gzip) > "$2"
+ else
+ echo "First argument must be a directory"
+ exit 1
+ fi
+
+Note: The cpio man page contains some bad advice that will break your initramfs
+archive if you follow it. It says "A typical way to generate the list
+of filenames is with the find command; you should give find the -depth option
+to minimize problems with permissions on directories that are unwritable or not
+searchable." Don't do this when creating initramfs.cpio.gz images, it won't
+work. The Linux kernel cpio extractor won't create files in a directory that
+doesn't exist, so the directory entries must go before the files that go in
+those directories. The above script gets them in the right order.
+
+External initramfs images:
+--------------------------
+
+If the kernel has initrd support enabled, an external cpio.gz archive can also
+be passed into a 2.6 kernel in place of an initrd. In this case, the kernel
+will autodetect the type (initramfs, not initrd) and extract the external cpio
+archive into rootfs before trying to run /init.
+
+This has the memory efficiency advantages of initramfs (no ramdisk block
+device) but the separate packaging of initrd (which is nice if you have
+non-GPL code you'd like to run from initramfs, without conflating it with
+the GPL licensed Linux kernel binary).
+
+It can also be used to supplement the kernel's built-in initamfs image. The
+files in the external archive will overwrite any conflicting files in
+the built-in initramfs archive. Some distributors also prefer to customize
+a single kernel image with task-specific initramfs images, without recompiling.
+
Contents of initramfs:
----------------------
+An initramfs archive is a complete self-contained root filesystem for Linux.
If you don't already understand what shared libraries, devices, and paths
you need to get a minimal root filesystem up and running, here are some
references:
@@ -176,13 +242,36 @@ code against, along with some related utilities. It is BSD licensed.
I use uClibc (http://www.uclibc.org) and busybox (http://www.busybox.net)
myself. These are LGPL and GPL, respectively. (A self-contained initramfs
-package is planned for the busybox 1.2 release.)
+package is planned for the busybox 1.3 release.)
In theory you could use glibc, but that's not well suited for small embedded
uses like this. (A "hello world" program statically linked against glibc is
over 400k. With uClibc it's 7k. Also note that glibc dlopens libnss to do
name lookups, even when otherwise statically linked.)
+A good first step is to get initramfs to run a statically linked "hello world"
+program as init, and test it under an emulator like qemu (www.qemu.org) or
+User Mode Linux, like so:
+
+ cat > hello.c << EOF
+ #include <stdio.h>
+ #include <unistd.h>
+
+ int main(int argc, char *argv[])
+ {
+ printf("Hello world!\n");
+ sleep(999999999);
+ }
+ EOF
+ gcc -static hello2.c -o init
+ echo init | cpio -o -H newc | gzip > test.cpio.gz
+ # Testing external initramfs using the initrd loading mechanism.
+ qemu -kernel /boot/vmlinuz -initrd test.cpio.gz /dev/zero
+
+When debugging a normal root filesystem, it's nice to be able to boot with
+"init=/bin/sh". The initramfs equivalent is "rdinit=/bin/sh", and it's
+just as useful.
+
Why cpio rather than tar?
-------------------------
@@ -241,7 +330,7 @@ the above threads) is:
Future directions:
------------------
-Today (2.6.14), initramfs is always compiled in, but not always used. The
+Today (2.6.16), initramfs is always compiled in, but not always used. The
kernel falls back to legacy boot code that is reached only if initramfs does
not contain an /init program. The fallback is legacy code, there to ensure a
smooth transition and allowing early boot functionality to gradually move to
@@ -258,8 +347,9 @@ and so on.
This kind of complexity (which inevitably includes policy) is rightly handled
in userspace. Both klibc and busybox/uClibc are working on simple initramfs
-packages to drop into a kernel build, and when standard solutions are ready
-and widely deployed, the kernel's legacy early boot code will become obsolete
-and a candidate for the feature removal schedule.
+packages to drop into a kernel build.
-But that's a while off yet.
+The klibc package has now been accepted into Andrew Morton's 2.6.17-mm tree.
+The kernel's current early boot code (partition detection, etc) will probably
+be migrated into a default initramfs, automatically created and used by the
+kernel build.
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 3a2e552..9d3aed6 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -113,8 +113,8 @@ members are defined:
struct file_system_type {
const char *name;
int fs_flags;
- struct super_block *(*get_sb) (struct file_system_type *, int,
- const char *, void *);
+ struct int (*get_sb) (struct file_system_type *, int,
+ const char *, void *, struct vfsmount *);
void (*kill_sb) (struct super_block *);
struct module *owner;
struct file_system_type * next;
@@ -211,7 +211,7 @@ struct super_operations {
int (*sync_fs)(struct super_block *sb, int wait);
void (*write_super_lockfs) (struct super_block *);
void (*unlockfs) (struct super_block *);
- int (*statfs) (struct super_block *, struct kstatfs *);
+ int (*statfs) (struct dentry *, struct kstatfs *);
int (*remount_fs) (struct super_block *, int *, char *);
void (*clear_inode) (struct inode *);
void (*umount_begin) (struct super_block *);
diff --git a/Documentation/hwmon/abituguru b/Documentation/hwmon/abituguru
new file mode 100644
index 0000000..69cdb52
--- /dev/null
+++ b/Documentation/hwmon/abituguru
@@ -0,0 +1,59 @@
+Kernel driver abituguru
+=======================
+
+Supported chips:
+ * Abit uGuru (Hardware Monitor part only)
+ Prefix: 'abituguru'
+ Addresses scanned: ISA 0x0E0
+ Datasheet: Not available, this driver is based on reverse engineering.
+ A "Datasheet" has been written based on the reverse engineering it
+ should be available in the same dir as this file under the name
+ abituguru-datasheet.
+
+Authors:
+ Hans de Goede <j.w.r.degoede@hhs.nl>,
+ (Initial reverse engineering done by Olle Sandberg
+ <ollebull@gmail.com>)
+
+
+Module Parameters
+-----------------
+
+* force: bool Force detection. Note this parameter only causes the
+ detection to be skipped, if the uGuru can't be read
+ the module initialization (insmod) will still fail.
+* fan_sensors: int Tell the driver how many fan speed sensors there are
+ on your motherboard. Default: 0 (autodetect).
+* pwms: int Tell the driver how many fan speed controls (fan
+ pwms) your motherboard has. Default: 0 (autodetect).
+* verbose: int How verbose should the driver be? (0-3):
+ 0 normal output
+ 1 + verbose error reporting
+ 2 + sensors type probing info\n"
+ 3 + retryable error reporting
+ Default: 2 (the driver is still in the testing phase)
+
+Notice if you need any of the first three options above please insmod the
+driver with verbose set to 3 and mail me <j.w.r.degoede@hhs.nl> the output of:
+dmesg | grep abituguru
+
+
+Description
+-----------
+
+This driver supports the hardware monitoring features of the Abit uGuru chip
+found on Abit uGuru featuring motherboards (most modern Abit motherboards).
+
+The uGuru chip in reality is a Winbond W83L950D in disguise (despite Abit
+claiming it is "a new microprocessor designed by the ABIT Engineers").
+Unfortunatly this doesn't help since the W83L950D is a generic
+microcontroller with a custom Abit application running on it.
+
+Despite Abit not releasing any information regarding the uGuru, Olle
+Sandberg <ollebull@gmail.com> has managed to reverse engineer the sensor part
+of the uGuru. Without his work this driver would not have been possible.
+
+Known Issues
+------------
+
+The voltage and frequency control parts of the Abit uGuru are not supported.
diff --git a/Documentation/hwmon/abituguru-datasheet b/Documentation/hwmon/abituguru-datasheet
new file mode 100644
index 0000000..aef5a9b
--- /dev/null
+++ b/Documentation/hwmon/abituguru-datasheet
@@ -0,0 +1,312 @@
+uGuru datasheet
+===============
+
+First of all, what I know about uGuru is no fact based on any help, hints or
+datasheet from Abit. The data I have got on uGuru have I assembled through
+my weak knowledge in "backwards engineering".
+And just for the record, you may have noticed uGuru isn't a chip developed by
+Abit, as they claim it to be. It's realy just an microprocessor (uC) created by
+Winbond (W83L950D). And no, reading the manual for this specific uC or
+mailing Windbond for help won't give any usefull data about uGuru, as it is
+the program inside the uC that is responding to calls.
+
+Olle Sandberg <ollebull@gmail.com>, 2005-05-25
+
+
+Original version by Olle Sandberg who did the heavy lifting of the initial
+reverse engineering. This version has been almost fully rewritten for clarity
+and extended with write support and info on more databanks, the write support
+is once again reverse engineered by Olle the additional databanks have been
+reverse engineered by me. I would like to express my thanks to Olle, this
+document and the Linux driver could not have been written without his efforts.
+
+Note: because of the lack of specs only the sensors part of the uGuru is
+described here and not the CPU / RAM / etc voltage & frequency control.
+
+Hans de Goede <j.w.r.degoede@hhs.nl>, 28-01-2006
+
+
+Detection
+=========
+
+As far as known the uGuru is always placed at and using the (ISA) I/O-ports
+0xE0 and 0xE4, so we don't have to scan any port-range, just check what the two
+ports are holding for detection. We will refer to 0xE0 as CMD (command-port)
+and 0xE4 as DATA because Abit refers to them with these names.
+
+If DATA holds 0x00 or 0x08 and CMD holds 0x00 or 0xAC an uGuru could be
+present. We have to check for two different values at data-port, because
+after a reboot uGuru will hold 0x00 here, but if the driver is removed and
+later on attached again data-port will hold 0x08, more about this later.
+
+After wider testing of the Linux kernel driver some variants of the uGuru have
+turned up which will hold 0x00 instead of 0xAC at the CMD port, thus we also
+have to test CMD for two different values. On these uGuru's DATA will initally
+hold 0x09 and will only hold 0x08 after reading CMD first, so CMD must be read
+first!
+
+To be really sure an uGuru is present a test read of one or more register
+sets should be done.
+
+
+Reading / Writing
+=================
+
+Addressing
+----------
+
+The uGuru has a number of different addressing levels. The first addressing
+level we will call banks. A bank holds data for one or more sensors. The data
+in a bank for a sensor is one or more bytes large.
+
+The number of bytes is fixed for a given bank, you should always read or write
+that many bytes, reading / writing more will fail, the results when writing
+less then the number of bytes for a given bank are undetermined.
+
+See below for all known bank addresses, numbers of sensors in that bank,
+number of bytes data per sensor and contents/meaning of those bytes.
+
+Although both this document and the kernel driver have kept the sensor
+terminoligy for the addressing within a bank this is not 100% correct, in
+bank 0x24 for example the addressing within the bank selects a PWM output not
+a sensor.
+
+Notice that some banks have both a read and a write address this is how the
+uGuru determines if a read from or a write to the bank is taking place, thus
+when reading you should always use the read address and when writing the
+write address. The write address is always one (1) more then the read address.
+
+
+uGuru ready
+-----------
+
+Before you can read from or write to the uGuru you must first put the uGuru
+in "ready" mode.
+
+To put the uGuru in ready mode first write 0x00 to DATA and then wait for DATA
+to hold 0x09, DATA should read 0x09 within 250 read cycles.
+
+Next CMD _must_ be read and should hold 0xAC, usually CMD will hold 0xAC the
+first read but sometimes it takes a while before CMD holds 0xAC and thus it
+has to be read a number of times (max 50).
+
+After reading CMD, DATA should hold 0x08 which means that the uGuru is ready
+for input. As above DATA will usually hold 0x08 the first read but not always.
+This step can be skipped, but it is undetermined what happens if the uGuru has
+not yet reported 0x08 at DATA and you proceed with writing a bank address.
+
+
+Sending bank and sensor addresses to the uGuru
+----------------------------------------------
+
+First the uGuru must be in "ready" mode as described above, DATA should hold
+0x08 indicating that the uGuru wants input, in this case the bank address.
+
+Next write the bank address to DATA. After the bank address has been written
+wait for to DATA to hold 0x08 again indicating that it wants / is ready for
+more input (max 250 reads).
+
+Once DATA holds 0x08 again write the sensor address to CMD.
+
+
+Reading
+-------
+
+First send the bank and sensor addresses as described above.
+Then for each byte of data you want to read wait for DATA to hold 0x01
+which indicates that the uGuru is ready to be read (max 250 reads) and once
+DATA holds 0x01 read the byte from CMD.
+
+Once all bytes have been read data will hold 0x09, but there is no reason to
+test for this. Notice that the number of bytes is bank address dependent see
+above and below.
+
+After completing a successfull read it is advised to put the uGuru back in
+ready mode, so that it is ready for the next read / write cycle. This way
+if your program / driver is unloaded and later loaded again the detection
+algorithm described above will still work.
+
+
+
+Writing
+-------
+
+First send the bank and sensor addresses as described above.
+Then for each byte of data you want to write wait for DATA to hold 0x00
+which indicates that the uGuru is ready to be written (max 250 reads) and
+once DATA holds 0x00 write the byte to CMD.
+
+Once all bytes have been written wait for DATA to hold 0x01 (max 250 reads)
+don't ask why this is the way it is.
+
+Once DATA holds 0x01 read CMD it should hold 0xAC now.
+
+After completing a successfull write it is advised to put the uGuru back in
+ready mode, so that it is ready for the next read / write cycle. This way
+if your program / driver is unloaded and later loaded again the detection
+algorithm described above will still work.
+
+
+Gotchas
+-------
+
+After wider testing of the Linux kernel driver some variants of the uGuru have
+turned up which do not hold 0x08 at DATA within 250 reads after writing the
+bank address. With these versions this happens quite frequent, using larger
+timeouts doesn't help, they just go offline for a second or 2, doing some
+internal callibration or whatever. Your code should be prepared to handle
+this and in case of no response in this specific case just goto sleep for a
+while and then retry.
+
+
+Address Map
+===========
+
+Bank 0x20 Alarms (R)
+--------------------
+This bank contains 0 sensors, iow the sensor address is ignored (but must be
+written) just use 0. Bank 0x20 contains 3 bytes:
+
+Byte 0:
+This byte holds the alarm flags for sensor 0-7 of Sensor Bank1, with bit 0
+corresponding to sensor 0, 1 to 1, etc.
+
+Byte 1:
+This byte holds the alarm flags for sensor 8-15 of Sensor Bank1, with bit 0
+corresponding to sensor 8, 1 to 9, etc.
+
+Byte 2:
+This byte holds the alarm flags for sensor 0-5 of Sensor Bank2, with bit 0
+corresponding to sensor 0, 1 to 1, etc.
+
+
+Bank 0x21 Sensor Bank1 Values / Readings (R)
+--------------------------------------------
+This bank contains 16 sensors, for each sensor it contains 1 byte.
+So far the following sensors are known to be available on all motherboards:
+Sensor 0 CPU temp
+Sensor 1 SYS temp
+Sensor 3 CPU core volt
+Sensor 4 DDR volt
+Sensor 10 DDR Vtt volt
+Sensor 15 PWM temp
+
+Byte 0:
+This byte holds the reading from the sensor. Sensors in Bank1 can be both
+volt and temp sensors, this is motherboard specific. The uGuru however does
+seem to know (be programmed with) what kindoff sensor is attached see Sensor
+Bank1 Settings description.
+
+Volt sensors use a linear scale, a reading 0 corresponds with 0 volt and a
+reading of 255 with 3494 mV. The sensors for higher voltages however are
+connected through a division circuit. The currently known division circuits
+in use result in ranges of: 0-4361mV, 0-6248mV or 0-14510mV. 3.3 volt sources
+use the 0-4361mV range, 5 volt the 0-6248mV and 12 volt the 0-14510mV .
+
+Temp sensors also use a linear scale, a reading of 0 corresponds with 0 degree
+Celsius and a reading of 255 with a reading of 255 degrees Celsius.
+
+
+Bank 0x22 Sensor Bank1 Settings (R)
+Bank 0x23 Sensor Bank1 Settings (W)
+-----------------------------------
+
+This bank contains 16 sensors, for each sensor it contains 3 bytes. Each
+set of 3 bytes contains the settings for the sensor with the same sensor
+address in Bank 0x21 .
+
+Byte 0:
+Alarm behaviour for the selected sensor. A 1 enables the described behaviour.
+Bit 0: Give an alarm if measured temp is over the warning threshold (RW) *
+Bit 1: Give an alarm if measured volt is over the max threshold (RW) **
+Bit 2: Give an alarm if measured volt is under the min threshold (RW) **
+Bit 3: Beep if alarm (RW)
+Bit 4: 1 if alarm cause measured temp is over the warning threshold (R)
+Bit 5: 1 if alarm cause measured volt is over the max threshold (R)
+Bit 6: 1 if alarm cause measured volt is under the min threshold (R)
+Bit 7: Volt sensor: Shutdown if alarm persist for more then 4 seconds (RW)
+ Temp sensor: Shutdown if temp is over the shutdown threshold (RW)
+
+* This bit is only honored/used by the uGuru if a temp sensor is connected
+** This bit is only honored/used by the uGuru if a volt sensor is connected
+Note with some trickery this can be used to find out what kinda sensor is
+detected see the Linux kernel driver for an example with many comments on
+how todo this.
+
+Byte 1:
+Temp sensor: warning threshold (scale as bank 0x21)
+Volt sensor: min threshold (scale as bank 0x21)
+
+Byte 2:
+Temp sensor: shutdown threshold (scale as bank 0x21)
+Volt sensor: max threshold (scale as bank 0x21)
+
+
+Bank 0x24 PWM outputs for FAN's (R)
+Bank 0x25 PWM outputs for FAN's (W)
+-----------------------------------
+
+This bank contains 3 "sensors", for each sensor it contains 5 bytes.
+Sensor 0 usually controls the CPU fan
+Sensor 1 usually controls the NB (or chipset for single chip) fan
+Sensor 2 usually controls the System fan
+
+Byte 0:
+Flag 0x80 to enable control, Fan runs at 100% when disabled.
+low nibble (temp)sensor address at bank 0x21 used for control.
+
+Byte 1:
+0-255 = 0-12v (linear), specify voltage at which fan will rotate when under
+low threshold temp (specified in byte 3)
+
+Byte 2:
+0-255 = 0-12v (linear), specify voltage at which fan will rotate when above
+high threshold temp (specified in byte 4)
+
+Byte 3:
+Low threshold temp (scale as bank 0x21)
+
+byte 4:
+High threshold temp (scale as bank 0x21)
+
+
+Bank 0x26 Sensors Bank2 Values / Readings (R)
+---------------------------------------------
+
+This bank contains 6 sensors (AFAIK), for each sensor it contains 1 byte.
+So far the following sensors are known to be available on all motherboards:
+Sensor 0: CPU fan speed
+Sensor 1: NB (or chipset for single chip) fan speed
+Sensor 2: SYS fan speed
+
+Byte 0:
+This byte holds the reading from the sensor. 0-255 = 0-15300 (linear)
+
+
+Bank 0x27 Sensors Bank2 Settings (R)
+Bank 0x28 Sensors Bank2 Settings (W)
+------------------------------------
+
+This bank contains 6 sensors (AFAIK), for each sensor it contains 2 bytes.
+
+Byte 0:
+Alarm behaviour for the selected sensor. A 1 enables the described behaviour.
+Bit 0: Give an alarm if measured rpm is under the min threshold (RW)
+Bit 3: Beep if alarm (RW)
+Bit 7: Shutdown if alarm persist for more then 4 seconds (RW)
+
+Byte 1:
+min threshold (scale as bank 0x26)
+
+
+Warning for the adventerous
+===========================
+
+A word of caution to those who want to experiment and see if they can figure
+the voltage / clock programming out, I tried reading and only reading banks
+0-0x30 with the reading code used for the sensor banks (0x20-0x28) and this
+resulted in a _permanent_ reprogramming of the voltages, luckily I had the
+sensors part configured so that it would shutdown my system on any out of spec
+voltages which proprably safed my computer (after a reboot I managed to
+immediatly enter the bios and reload the defaults). This probably means that
+the read/write cycle for the non sensor part is different from the sensor part.
diff --git a/Documentation/hwmon/lm70 b/Documentation/hwmon/lm70
new file mode 100644
index 0000000..2bdd3fe
--- /dev/null
+++ b/Documentation/hwmon/lm70
@@ -0,0 +1,31 @@
+Kernel driver lm70
+==================
+
+Supported chip:
+ * National Semiconductor LM70
+ Datasheet: http://www.national.com/pf/LM/LM70.html
+
+Author:
+ Kaiwan N Billimoria <kaiwan@designergraphix.com>
+
+Description
+-----------
+
+This driver implements support for the National Semiconductor LM70
+temperature sensor.
+
+The LM70 temperature sensor chip supports a single temperature sensor.
+It communicates with a host processor (or microcontroller) via an
+SPI/Microwire Bus interface.
+
+Communication with the LM70 is simple: when the temperature is to be sensed,
+the driver accesses the LM70 using SPI communication: 16 SCLK cycles
+comprise the MOSI/MISO loop. At the end of the transfer, the 11-bit 2's
+complement digital temperature (sent via the SIO line), is available in the
+driver for interpretation. This driver makes use of the kernel's in-core
+SPI support.
+
+Thanks to
+---------
+Jean Delvare <khali@linux-fr.org> for mentoring the hwmon-side driver
+development.
diff --git a/Documentation/hwmon/lm83 b/Documentation/hwmon/lm83
index 061d9ed..f7aad14 100644
--- a/Documentation/hwmon/lm83
+++ b/Documentation/hwmon/lm83
@@ -7,6 +7,10 @@ Supported chips:
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
Datasheet: Publicly available at the National Semiconductor website
http://www.national.com/pf/LM/LM83.html
+ * National Semiconductor LM82
+ Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+ Datasheet: Publicly available at the National Semiconductor website
+ http://www.national.com/pf/LM/LM82.html
Author: Jean Delvare <khali@linux-fr.org>
@@ -15,10 +19,11 @@ Description
-----------
The LM83 is a digital temperature sensor. It senses its own temperature as
-well as the temperature of up to three external diodes. It is compatible
-with many other devices such as the LM84 and all other ADM1021 clones.
-The main difference between the LM83 and the LM84 in that the later can
-only sense the temperature of one external diode.
+well as the temperature of up to three external diodes. The LM82 is
+a stripped down version of the LM83 that only supports one external diode.
+Both are compatible with many other devices such as the LM84 and all
+other ADM1021 clones. The main difference between the LM83 and the LM84
+in that the later can only sense the temperature of one external diode.
Using the adm1021 driver for a LM83 should work, but only two temperatures
will be reported instead of four.
@@ -30,12 +35,16 @@ contact us. Note that the LM90 can easily be misdetected as a LM83.
Confirmed motherboards:
SBS P014
+ SBS PSL09
Unconfirmed motherboards:
Gigabyte GA-8IK1100
Iwill MPX2
Soltek SL-75DRV5
+The LM82 is confirmed to have been found on most AMD Geode reference
+designs and test platforms.
+
The driver has been successfully tested by Magnus Forsström, who I'd
like to thank here. More testers will be of course welcome.
diff --git a/Documentation/hwmon/smsc47m192 b/Documentation/hwmon/smsc47m192
new file mode 100644
index 0000000..45d6453
--- /dev/null
+++ b/Documentation/hwmon/smsc47m192
@@ -0,0 +1,102 @@
+Kernel driver smsc47m192
+========================
+
+Supported chips:
+ * SMSC LPC47M192 and LPC47M997
+ Prefix: 'smsc47m192'
+ Addresses scanned: I2C 0x2c - 0x2d
+ Datasheet: The datasheet for LPC47M192 is publicly available from
+ http://www.smsc.com/
+ The LPC47M997 is compatible for hardware monitoring.
+
+Author: Hartmut Rick <linux@rick.claranet.de>
+ Special thanks to Jean Delvare for careful checking
+ of the code and many helpful comments and suggestions.
+
+
+Description
+-----------
+
+This driver implements support for the hardware sensor capabilities
+of the SMSC LPC47M192 and LPC47M997 Super-I/O chips.
+
+These chips support 3 temperature channels and 8 voltage inputs
+as well as CPU voltage VID input.
+
+They do also have fan monitoring and control capabilities, but the
+these features are accessed via ISA bus and are not supported by this
+driver. Use the 'smsc47m1' driver for fan monitoring and control.
+
+Voltages and temperatures are measured by an 8-bit ADC, the resolution
+of the temperatures is 1 bit per degree C.
+Voltages are scaled such that the nominal voltage corresponds to
+192 counts, i.e. 3/4 of the full range. Thus the available range for
+each voltage channel is 0V ... 255/192*(nominal voltage), the resolution
+is 1 bit per (nominal voltage)/192.
+Both voltage and temperature values are scaled by 1000, the sys files
+show voltages in mV and temperatures in units of 0.001 degC.
+
+The +12V analog voltage input channel (in4_input) is multiplexed with
+bit 4 of the encoded CPU voltage. This means that you either get
+a +12V voltage measurement or a 5 bit CPU VID, but not both.
+The default setting is to use the pin as 12V input, and use only 4 bit VID.
+This driver assumes that the information in the configuration register
+is correct, i.e. that the BIOS has updated the configuration if
+the motherboard has this input wired to VID4.
+
+The temperature and voltage readings are updated once every 1.5 seconds.
+Reading them more often repeats the same values.
+
+
+sysfs interface
+---------------
+
+in0_input - +2.5V voltage input
+in1_input - CPU voltage input (nominal 2.25V)
+in2_input - +3.3V voltage input
+in3_input - +5V voltage input
+in4_input - +12V voltage input (may be missing if used as VID4)
+in5_input - Vcc voltage input (nominal 3.3V)
+ This is the supply voltage of the sensor chip itself.
+in6_input - +1.5V voltage input
+in7_input - +1.8V voltage input
+
+in[0-7]_min,
+in[0-7]_max - lower and upper alarm thresholds for in[0-7]_input reading
+
+ All voltages are read and written in mV.
+
+in[0-7]_alarm - alarm flags for voltage inputs
+ These files read '1' in case of alarm, '0' otherwise.
+
+temp1_input - chip temperature measured by on-chip diode
+temp[2-3]_input - temperature measured by external diodes (one of these would
+ typically be wired to the diode inside the CPU)
+
+temp[1-3]_min,
+temp[1-3]_max - lower and upper alarm thresholds for temperatures
+
+temp[1-3]_offset - temperature offset registers
+ The chip adds the offsets stored in these registers to
+ the corresponding temperature readings.
+ Note that temp1 and temp2 offsets share the same register,
+ they cannot both be different from zero at the same time.
+ Writing a non-zero number to one of them will reset the other
+ offset to zero.
+
+ All temperatures and offsets are read and written in
+ units of 0.001 degC.
+
+temp[1-3]_alarm - alarm flags for temperature inputs, '1' in case of alarm,
+ '0' otherwise.
+temp[2-3]_input_fault - diode fault flags for temperature inputs 2 and 3.
+ A fault is detected if the two pins for the corresponding
+ sensor are open or shorted, or any of the two is shorted
+ to ground or Vcc. '1' indicates a diode fault.
+
+cpu0_vid - CPU voltage as received from the CPU
+
+vrm - CPU VID standard used for decoding CPU voltage
+
+ The *_min, *_max, *_offset and vrm files can be read and
+ written, all others are read-only.
diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface
index a0d0ab2..d1d390a 100644
--- a/Documentation/hwmon/sysfs-interface
+++ b/Documentation/hwmon/sysfs-interface
@@ -3,15 +3,15 @@ Naming and data format standards for sysfs files
The libsensors library offers an interface to the raw sensors data
through the sysfs interface. See libsensors documentation and source for
-more further information. As of writing this document, libsensors
-(from lm_sensors 2.8.3) is heavily chip-dependant. Adding or updating
+further information. As of writing this document, libsensors
+(from lm_sensors 2.8.3) is heavily chip-dependent. Adding or updating
support for any given chip requires modifying the library's code.
This is because libsensors was written for the procfs interface
older kernel modules were using, which wasn't standardized enough.
Recent versions of libsensors (from lm_sensors 2.8.2 and later) have
support for the sysfs interface, though.
-The new sysfs interface was designed to be as chip-independant as
+The new sysfs interface was designed to be as chip-independent as
possible.
Note that motherboards vary widely in the connections to sensor chips.
@@ -24,7 +24,7 @@ range using external resistors. Since the values of these resistors
can change from motherboard to motherboard, the conversions cannot be
hard coded into the driver and have to be done in user space.
-For this reason, even if we aim at a chip-independant libsensors, it will
+For this reason, even if we aim at a chip-independent libsensors, it will
still require a configuration file (e.g. /etc/sensors.conf) for proper
values conversion, labeling of inputs and hiding of unused inputs.
@@ -39,15 +39,16 @@ If you are developing a userspace application please send us feedback on
this standard.
Note that this standard isn't completely established yet, so it is subject
-to changes, even important ones. One more reason to use the library instead
-of accessing sysfs files directly.
+to changes. If you are writing a new hardware monitoring driver those
+features can't seem to fit in this interface, please contact us with your
+extension proposal. Keep in mind that backward compatibility must be
+preserved.
Each chip gets its own directory in the sysfs /sys/devices tree. To
-find all sensor chips, it is easier to follow the symlinks from
-/sys/i2c/devices/
+find all sensor chips, it is easier to follow the device symlinks from
+/sys/class/hwmon/hwmon*.
-All sysfs values are fixed point numbers. To get the true value of some
-of the values, you should divide by the specified value.
+All sysfs values are fixed point numbers.
There is only one value per file, unlike the older /proc specification.
The common scheme for files naming is: <type><number>_<item>. Usual
@@ -69,28 +70,40 @@ to cause an alarm) is chip-dependent.
-------------------------------------------------------------------------
+[0-*] denotes any positive number starting from 0
+[1-*] denotes any positive number starting from 1
+RO read only value
+RW read/write value
+
+Read/write values may be read-only for some chips, depending on the
+hardware implementation.
+
+All entries are optional, and should only be created in a given driver
+if the chip has the feature.
+
************
* Voltages *
************
-in[0-8]_min Voltage min value.
+in[0-*]_min Voltage min value.
Unit: millivolt
- Read/Write
+ RW
-in[0-8]_max Voltage max value.
+in[0-*]_max Voltage max value.
Unit: millivolt
- Read/Write
+ RW
-in[0-8]_input Voltage input value.
+in[0-*]_input Voltage input value.
Unit: millivolt
- Read only
+ RO
+ Voltage measured on the chip pin.
Actual voltage depends on the scaling resistors on the
motherboard, as recommended in the chip datasheet.
This varies by chip and by motherboard.
Because of this variation, values are generally NOT scaled
by the chip driver, and must be done by the application.
However, some drivers (notably lm87 and via686a)
- do scale, with various degrees of success.
+ do scale, because of internal resistors built into a chip.
These drivers will output the actual voltage.
Typical usage:
@@ -104,58 +117,72 @@ in[0-8]_input Voltage input value.
in7_* varies
in8_* varies
-cpu[0-1]_vid CPU core reference voltage.
+cpu[0-*]_vid CPU core reference voltage.
Unit: millivolt
- Read only.
+ RO
Not always correct.
vrm Voltage Regulator Module version number.
- Read only.
- Two digit number, first is major version, second is
- minor version.
+ RW (but changing it should no more be necessary)
+ Originally the VRM standard version multiplied by 10, but now
+ an arbitrary number, as not all standards have a version
+ number.
Affects the way the driver calculates the CPU core reference
voltage from the vid pins.
+Also see the Alarms section for status flags associated with voltages.
+
********
* Fans *
********
-fan[1-3]_min Fan minimum value
+fan[1-*]_min Fan minimum value
Unit: revolution/min (RPM)
- Read/Write.
+ RW
-fan[1-3]_input Fan input value.
+fan[1-*]_input Fan input value.
Unit: revolution/min (RPM)
- Read only.
+ RO
-fan[1-3]_div Fan divisor.
+fan[1-*]_div Fan divisor.
Integer value in powers of two (1, 2, 4, 8, 16, 32, 64, 128).
+ RW
Some chips only support values 1, 2, 4 and 8.
Note that this is actually an internal clock divisor, which
affects the measurable speed range, not the read value.
+Also see the Alarms section for status flags associated with fans.
+
+
*******
* PWM *
*******
-pwm[1-3] Pulse width modulation fan control.
+pwm[1-*] Pulse width modulation fan control.
Integer value in the range 0 to 255
- Read/Write
+ RW
255 is max or 100%.
-pwm[1-3]_enable
+pwm[1-*]_enable
Switch PWM on and off.
Not always present even if fan*_pwm is.
- 0 to turn off
- 1 to turn on in manual mode
- 2 to turn on in automatic mode
- Read/Write
+ 0: turn off
+ 1: turn on in manual mode
+ 2+: turn on in automatic mode
+ Check individual chip documentation files for automatic mode details.
+ RW
+
+pwm[1-*]_mode
+ 0: DC mode
+ 1: PWM mode
+ RW
pwm[1-*]_auto_channels_temp
Select which temperature channels affect this PWM output in
auto mode. Bitfield, 1 is temp1, 2 is temp2, 4 is temp3 etc...
Which values are possible depend on the chip used.
+ RW
pwm[1-*]_auto_point[1-*]_pwm
pwm[1-*]_auto_point[1-*]_temp
@@ -163,6 +190,7 @@ pwm[1-*]_auto_point[1-*]_temp_hyst
Define the PWM vs temperature curve. Number of trip points is
chip-dependent. Use this for chips which associate trip points
to PWM output channels.
+ RW
OR
@@ -172,50 +200,57 @@ temp[1-*]_auto_point[1-*]_temp_hyst
Define the PWM vs temperature curve. Number of trip points is
chip-dependent. Use this for chips which associate trip points
to temperature channels.
+ RW
****************
* Temperatures *
****************
-temp[1-3]_type Sensor type selection.
+temp[1-*]_type Sensor type selection.
Integers 1 to 4 or thermistor Beta value (typically 3435)
- Read/Write.
+ RW
1: PII/Celeron Diode
2: 3904 transistor
3: thermal diode
4: thermistor (default/unknown Beta)
Not all types are supported by all chips
-temp[1-4]_max Temperature max value.
- Unit: millidegree Celcius
- Read/Write value.
+temp[1-*]_max Temperature max value.
+ Unit: millidegree Celsius (or millivolt, see below)
+ RW
-temp[1-3]_min Temperature min value.
- Unit: millidegree Celcius
- Read/Write value.
+temp[1-*]_min Temperature min value.
+ Unit: millidegree Celsius
+ RW
-temp[1-3]_max_hyst
+temp[1-*]_max_hyst
Temperature hysteresis value for max limit.
- Unit: millidegree Celcius
+ Unit: millidegree Celsius
Must be reported as an absolute temperature, NOT a delta
from the max value.
- Read/Write value.
+ RW
-temp[1-4]_input Temperature input value.
- Unit: millidegree Celcius
- Read only value.
+temp[1-*]_input Temperature input value.
+ Unit: millidegree Celsius
+ RO
-temp[1-4]_crit Temperature critical value, typically greater than
+temp[1-*]_crit Temperature critical value, typically greater than
corresponding temp_max values.
- Unit: millidegree Celcius
- Read/Write value.
+ Unit: millidegree Celsius
+ RW
-temp[1-2]_crit_hyst
+temp[1-*]_crit_hyst
Temperature hysteresis value for critical limit.
- Unit: millidegree Celcius
+ Unit: millidegree Celsius
Must be reported as an absolute temperature, NOT a delta
from the critical value.
+ RW
+
+temp[1-4]_offset
+ Temperature offset which is added to the temperature reading
+ by the chip.
+ Unit: millidegree Celsius
Read/Write value.
If there are multiple temperature sensors, temp1_* is
@@ -225,6 +260,17 @@ temp[1-2]_crit_hyst
itself, for example the thermal diode inside the CPU or
a thermistor nearby.
+Some chips measure temperature using external thermistors and an ADC, and
+report the temperature measurement as a voltage. Converting this voltage
+back to a temperature (or the other way around for limits) requires
+mathematical functions not available in the kernel, so the conversion
+must occur in user space. For these chips, all temp* files described
+above should contain values expressed in millivolt instead of millidegree
+Celsius. In other words, such temperature channels are handled as voltage
+channels by the driver.
+
+Also see the Alarms section for status flags associated with temperatures.
+
************
* Currents *
@@ -233,25 +279,88 @@ temp[1-2]_crit_hyst
Note that no known chip provides current measurements as of writing,
so this part is theoretical, so to say.
-curr[1-n]_max Current max value
+curr[1-*]_max Current max value
Unit: milliampere
- Read/Write.
+ RW
-curr[1-n]_min Current min value.
+curr[1-*]_min Current min value.
Unit: milliampere
- Read/Write.
+ RW
-curr[1-n]_input Current input value
+curr[1-*]_input Current input value
Unit: milliampere
- Read only.
+ RO
-*********
-* Other *
-*********
+**********
+* Alarms *
+**********
+
+Each channel or limit may have an associated alarm file, containing a
+boolean value. 1 means than an alarm condition exists, 0 means no alarm.
+
+Usually a given chip will either use channel-related alarms, or
+limit-related alarms, not both. The driver should just reflect the hardware
+implementation.
+
+in[0-*]_alarm
+fan[1-*]_alarm
+temp[1-*]_alarm
+ Channel alarm
+ 0: no alarm
+ 1: alarm
+ RO
+
+OR
+
+in[0-*]_min_alarm
+in[0-*]_max_alarm
+fan[1-*]_min_alarm
+temp[1-*]_min_alarm
+temp[1-*]_max_alarm
+temp[1-*]_crit_alarm
+ Limit alarm
+ 0: no alarm
+ 1: alarm
+ RO
+
+Each input channel may have an associated fault file. This can be used
+to notify open diodes, unconnected fans etc. where the hardware
+supports it. When this boolean has value 1, the measurement for that
+channel should not be trusted.
+
+in[0-*]_input_fault
+fan[1-*]_input_fault
+temp[1-*]_input_fault
+ Input fault condition
+ 0: no fault occured
+ 1: fault condition
+ RO
+
+Some chips also offer the possibility to get beeped when an alarm occurs:
+
+beep_enable Master beep enable
+ 0: no beeps
+ 1: beeps
+ RW
+
+in[0-*]_beep
+fan[1-*]_beep
+temp[1-*]_beep
+ Channel beep
+ 0: disable
+ 1: enable
+ RW
+
+In theory, a chip could provide per-limit beep masking, but no such chip
+was seen so far.
+
+Old drivers provided a different, non-standard interface to alarms and
+beeps. These interface files are deprecated, but will be kept around
+for compatibility reasons:
alarms Alarm bitmask.
- Read only.
+ RO
Integer representation of one to four bytes.
A '1' bit means an alarm.
Chips should be programmed for 'comparator' mode so that
@@ -259,35 +368,26 @@ alarms Alarm bitmask.
if it is still valid.
Generally a direct representation of a chip's internal
alarm registers; there is no standard for the position
- of individual bits.
+ of individual bits. For this reason, the use of this
+ interface file for new drivers is discouraged. Use
+ individual *_alarm and *_fault files instead.
Bits are defined in kernel/include/sensors.h.
-alarms_in Alarm bitmask relative to in (voltage) channels
- Read only
- A '1' bit means an alarm, LSB corresponds to in0 and so on
- Prefered to 'alarms' for newer chips
-
-alarms_fan Alarm bitmask relative to fan channels
- Read only
- A '1' bit means an alarm, LSB corresponds to fan1 and so on
- Prefered to 'alarms' for newer chips
-
-alarms_temp Alarm bitmask relative to temp (temperature) channels
- Read only
- A '1' bit means an alarm, LSB corresponds to temp1 and so on
- Prefered to 'alarms' for newer chips
+beep_mask Bitmask for beep.
+ Same format as 'alarms' with the same bit locations,
+ use discouraged for the same reason. Use individual
+ *_beep files instead.
+ RW
-beep_enable Beep/interrupt enable
- 0 to disable.
- 1 to enable.
- Read/Write
-beep_mask Bitmask for beep.
- Same format as 'alarms' with the same bit locations.
- Read/Write
+*********
+* Other *
+*********
eeprom Raw EEPROM data in binary form.
- Read only.
+ RO
pec Enable or disable PEC (SMBus only)
- Read/Write
+ 0: disable
+ 1: enable
+ RW
diff --git a/Documentation/hwmon/userspace-tools b/Documentation/hwmon/userspace-tools
index 2622aac..19900a8 100644
--- a/Documentation/hwmon/userspace-tools
+++ b/Documentation/hwmon/userspace-tools
@@ -6,31 +6,32 @@ voltages, fans speed). They are often connected through an I2C bus, but some
are also connected directly through the ISA bus.
The kernel drivers make the data from the sensor chips available in the /sys
-virtual filesystem. Userspace tools are then used to display or set or the
-data in a more friendly manner.
+virtual filesystem. Userspace tools are then used to display the measured
+values or configure the chips in a more friendly manner.
Lm-sensors
----------
-Core set of utilites that will allow you to obtain health information,
+Core set of utilities that will allow you to obtain health information,
setup monitoring limits etc. You can get them on their homepage
http://www.lm-sensors.nu/ or as a package from your Linux distribution.
If from website:
-Get lmsensors from project web site. Please note, you need only userspace
-part, so compile with "make user_install" target.
+Get lm-sensors from project web site. Please note, you need only userspace
+part, so compile with "make user" and install with "make user_install".
General hints to get things working:
0) get lm-sensors userspace utils
-1) compile all drivers in I2C section as modules in your kernel
+1) compile all drivers in I2C and Hardware Monitoring sections as modules
+ in your kernel
2) run sensors-detect script, it will tell you what modules you need to load.
3) load them and run "sensors" command, you should see some results.
4) fix sensors.conf, labels, limits, fan divisors
5) if any more problems consult FAQ, or documentation
-Other utilites
---------------
+Other utilities
+---------------
If you want some graphical indicators of system health look for applications
like: gkrellm, ksensors, xsensors, wmtemp, wmsensors, wmgtemp, ksysguardd,
diff --git a/Documentation/hwmon/w83791d b/Documentation/hwmon/w83791d
new file mode 100644
index 0000000..83a3836
--- /dev/null
+++ b/Documentation/hwmon/w83791d
@@ -0,0 +1,113 @@
+Kernel driver w83791d
+=====================
+
+Supported chips:
+ * Winbond W83791D
+ Prefix: 'w83791d'
+ Addresses scanned: I2C 0x2c - 0x2f
+ Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83791Da.pdf
+
+Author: Charles Spirakis <bezaur@gmail.com>
+
+This driver was derived from the w83781d.c and w83792d.c source files.
+
+Credits:
+ w83781d.c:
+ Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>,
+ and Mark Studebaker <mdsxyz123@yahoo.com>
+ w83792d.c:
+ Chunhao Huang <DZShen@Winbond.com.tw>,
+ Rudolf Marek <r.marek@sh.cvut.cz>
+
+Module Parameters
+-----------------
+
+* init boolean
+ (default 0)
+ Use 'init=1' to have the driver do extra software initializations.
+ The default behavior is to do the minimum initialization possible
+ and depend on the BIOS to properly setup the chip. If you know you
+ have a w83791d and you're having problems, try init=1 before trying
+ reset=1.
+
+* reset boolean
+ (default 0)
+ Use 'reset=1' to reset the chip (via index 0x40, bit 7). The default
+ behavior is no chip reset to preserve BIOS settings.
+
+* force_subclients=bus,caddr,saddr,saddr
+ This is used to force the i2c addresses for subclients of
+ a certain chip. Example usage is `force_subclients=0,0x2f,0x4a,0x4b'
+ to force the subclients of chip 0x2f on bus 0 to i2c addresses
+ 0x4a and 0x4b.
+
+
+Description
+-----------
+
+This driver implements support for the Winbond W83791D chip.
+
+Detection of the chip can sometimes be foiled because it can be in an
+internal state that allows no clean access (Bank with ID register is not
+currently selected). If you know the address of the chip, use a 'force'
+parameter; this will put it into a more well-behaved state first.
+
+The driver implements three temperature sensors, five fan rotation speed
+sensors, and ten voltage sensors.
+
+Temperatures are measured in degrees Celsius and measurement resolution is 1
+degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when
+the temperature gets higher than the Overtemperature Shutdown value; it stays
+on until the temperature falls below the Hysteresis value.
+
+Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
+triggered if the rotation speed has dropped below a programmable limit. Fan
+readings can be divided by a programmable divider (1, 2, 4, 8 for fan 1/2/3
+and 1, 2, 4, 8, 16, 32, 64 or 128 for fan 4/5) to give the readings more
+range or accuracy.
+
+Voltage sensors (also known as IN sensors) report their values in millivolts.
+An alarm is triggered if the voltage has crossed a programmable minimum
+or maximum limit.
+
+Alarms are provided as output from a "realtime status register". The
+following bits are defined:
+
+bit - alarm on:
+0 - Vcore
+1 - VINR0
+2 - +3.3VIN
+3 - 5VDD
+4 - temp1
+5 - temp2
+6 - fan1
+7 - fan2
+8 - +12VIN
+9 - -12VIN
+10 - -5VIN
+11 - fan3
+12 - chassis
+13 - temp3
+14 - VINR1
+15 - reserved
+16 - tart1
+17 - tart2
+18 - tart3
+19 - VSB
+20 - VBAT
+21 - fan4
+22 - fan5
+23 - reserved
+
+When an alarm goes off, you can be warned by a beeping signal through your
+computer speaker. It is possible to enable all beeping globally, or only
+the beeping for some alarms.
+
+The driver only reads the chip values each 3 seconds; reading them more
+often will do no harm, but will return 'old' values.
+
+W83791D TODO:
+---------------
+Provide a patch for per-file alarms as discussed on the mailing list
+Provide a patch for smart-fan control (still need appropriate motherboard/fans)
diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801
index fd4b271..e46c234 100644
--- a/Documentation/i2c/busses/i2c-i801
+++ b/Documentation/i2c/busses/i2c-i801
@@ -21,8 +21,7 @@ Authors:
Module Parameters
-----------------
-* force_addr: int
- Forcibly enable the ICH at the given address. EXTREMELY DANGEROUS!
+None.
Description
diff --git a/Documentation/i2c/busses/i2c-nforce2 b/Documentation/i2c/busses/i2c-nforce2
index d751282..cd49c42 100644
--- a/Documentation/i2c/busses/i2c-nforce2
+++ b/Documentation/i2c/busses/i2c-nforce2
@@ -7,6 +7,8 @@ Supported adapters:
* nForce3 250Gb MCP 10de:00E4
* nForce4 MCP 10de:0052
* nForce4 MCP-04 10de:0034
+ * nForce4 MCP51 10de:0264
+ * nForce4 MCP55 10de:0368
Datasheet: not publically available, but seems to be similar to the
AMD-8111 SMBus 2.0 adapter.
diff --git a/Documentation/i2c/busses/i2c-ocores b/Documentation/i2c/busses/i2c-ocores
new file mode 100644
index 0000000..cfcebb1
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-ocores
@@ -0,0 +1,51 @@
+Kernel driver i2c-ocores
+
+Supported adapters:
+ * OpenCores.org I2C controller by Richard Herveille (see datasheet link)
+ Datasheet: http://www.opencores.org/projects.cgi/web/i2c/overview
+
+Author: Peter Korsgaard <jacmet@sunsite.dk>
+
+Description
+-----------
+
+i2c-ocores is an i2c bus driver for the OpenCores.org I2C controller
+IP core by Richard Herveille.
+
+Usage
+-----
+
+i2c-ocores uses the platform bus, so you need to provide a struct
+platform_device with the base address and interrupt number. The
+dev.platform_data of the device should also point to a struct
+ocores_i2c_platform_data (see linux/i2c-ocores.h) describing the
+distance between registers and the input clock speed.
+
+E.G. something like:
+
+static struct resource ocores_resources[] = {
+ [0] = {
+ .start = MYI2C_BASEADDR,
+ .end = MYI2C_BASEADDR + 8,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = MYI2C_IRQ,
+ .end = MYI2C_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct ocores_i2c_platform_data myi2c_data = {
+ .regstep = 2, /* two bytes between registers */
+ .clock_khz = 50000, /* input clock of 50MHz */
+};
+
+static struct platform_device myi2c = {
+ .name = "ocores-i2c",
+ .dev = {
+ .platform_data = &myi2c_data,
+ },
+ .num_resources = ARRAY_SIZE(ocores_resources),
+ .resource = ocores_resources,
+};
diff --git a/Documentation/i2c/busses/i2c-piix4 b/Documentation/i2c/busses/i2c-piix4
index a1c8f58..9214763 100644
--- a/Documentation/i2c/busses/i2c-piix4
+++ b/Documentation/i2c/busses/i2c-piix4
@@ -6,6 +6,8 @@ Supported adapters:
Datasheet: Publicly available at the Intel website
* ServerWorks OSB4, CSB5, CSB6 and HT-1000 southbridges
Datasheet: Only available via NDA from ServerWorks
+ * ATI IXP southbridges IXP200, IXP300, IXP400
+ Datasheet: Not publicly available
* Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge
Datasheet: Publicly available at the SMSC website http://www.smsc.com
@@ -21,8 +23,6 @@ Module Parameters
Forcibly enable the PIIX4. DANGEROUS!
* force_addr: int
Forcibly enable the PIIX4 at the given address. EXTREMELY DANGEROUS!
-* fix_hstcfg: int
- Fix config register. Needed on some boards (Force CPCI735).
Description
@@ -63,10 +63,36 @@ The PIIX4E is just an new version of the PIIX4; it is supported as well.
The PIIX/PIIX3 does not implement an SMBus or I2C bus, so you can't use
this driver on those mainboards.
-The ServerWorks Southbridges, the Intel 440MX, and the Victory766 are
+The ServerWorks Southbridges, the Intel 440MX, and the Victory66 are
identical to the PIIX4 in I2C/SMBus support.
-A few OSB4 southbridges are known to be misconfigured by the BIOS. In this
-case, you have you use the fix_hstcfg module parameter. Do not use it
-unless you know you have to, because in some cases it also breaks
-configuration on southbridges that don't need it.
+If you own Force CPCI735 motherboard or other OSB4 based systems you may need
+to change the SMBus Interrupt Select register so the SMBus controller uses
+the SMI mode.
+
+1) Use lspci command and locate the PCI device with the SMBus controller:
+ 00:0f.0 ISA bridge: ServerWorks OSB4 South Bridge (rev 4f)
+ The line may vary for different chipsets. Please consult the driver source
+ for all possible PCI ids (and lspci -n to match them). Lets assume the
+ device is located at 00:0f.0.
+2) Now you just need to change the value in 0xD2 register. Get it first with
+ command: lspci -xxx -s 00:0f.0
+ If the value is 0x3 then you need to change it to 0x1
+ setpci -s 00:0f.0 d2.b=1
+
+Please note that you don't need to do that in all cases, just when the SMBus is
+not working properly.
+
+
+Hardware-specific issues
+------------------------
+
+This driver will refuse to load on IBM systems with an Intel PIIX4 SMBus.
+Some of these machines have an RFID EEPROM (24RF08) connected to the SMBus,
+which can easily get corrupted due to a state machine bug. These are mostly
+Thinkpad laptops, but desktop systems may also be affected. We have no list
+of all affected systems, so the only safe solution was to prevent access to
+the SMBus on all IBM systems (detected using DMI data.)
+
+For additional information, read:
+http://www2.lm-sensors.nu/~lm78/cvs/lm_sensors2/README.thinkpad
diff --git a/Documentation/i2c/busses/scx200_acb b/Documentation/i2c/busses/scx200_acb
index f50e699..7c07883d 100644
--- a/Documentation/i2c/busses/scx200_acb
+++ b/Documentation/i2c/busses/scx200_acb
@@ -2,14 +2,31 @@ Kernel driver scx200_acb
Author: Christer Weinigel <wingel@nano-system.com>
+The driver supersedes the older, never merged driver named i2c-nscacb.
+
Module Parameters
-----------------
-* base: int
+* base: up to 4 ints
Base addresses for the ACCESS.bus controllers on SCx200 and SC1100 devices
+ By default the driver uses two base addresses 0x820 and 0x840.
+ If you want only one base address, specify the second as 0 so as to
+ override this default.
+
Description
-----------
Enable the use of the ACCESS.bus controller on the Geode SCx200 and
SC1100 processors and the CS5535 and CS5536 Geode companion devices.
+
+Device-specific notes
+---------------------
+
+The SC1100 WRAP boards are known to use base addresses 0x810 and 0x820.
+If the scx200_acb driver is built into the kernel, add the following
+parameter to your boot command line:
+ scx200_acb.base=0x810,0x820
+If the scx200_acb driver is built as a module, add the following line to
+the file /etc/modprobe.conf instead:
+ options scx200_acb base=0x810,0x820
diff --git a/Documentation/ia64/aliasing.txt b/Documentation/ia64/aliasing.txt
new file mode 100644
index 0000000..38f9a52
--- /dev/null
+++ b/Documentation/ia64/aliasing.txt
@@ -0,0 +1,208 @@
+ MEMORY ATTRIBUTE ALIASING ON IA-64
+
+ Bjorn Helgaas
+ <bjorn.helgaas@hp.com>
+ May 4, 2006
+
+
+MEMORY ATTRIBUTES
+
+ Itanium supports several attributes for virtual memory references.
+ The attribute is part of the virtual translation, i.e., it is
+ contained in the TLB entry. The ones of most interest to the Linux
+ kernel are:
+
+ WB Write-back (cacheable)
+ UC Uncacheable
+ WC Write-coalescing
+
+ System memory typically uses the WB attribute. The UC attribute is
+ used for memory-mapped I/O devices. The WC attribute is uncacheable
+ like UC is, but writes may be delayed and combined to increase
+ performance for things like frame buffers.
+
+ The Itanium architecture requires that we avoid accessing the same
+ page with both a cacheable mapping and an uncacheable mapping[1].
+
+ The design of the chipset determines which attributes are supported
+ on which regions of the address space. For example, some chipsets
+ support either WB or UC access to main memory, while others support
+ only WB access.
+
+MEMORY MAP
+
+ Platform firmware describes the physical memory map and the
+ supported attributes for each region. At boot-time, the kernel uses
+ the EFI GetMemoryMap() interface. ACPI can also describe memory
+ devices and the attributes they support, but Linux/ia64 currently
+ doesn't use this information.
+
+ The kernel uses the efi_memmap table returned from GetMemoryMap() to
+ learn the attributes supported by each region of physical address
+ space. Unfortunately, this table does not completely describe the
+ address space because some machines omit some or all of the MMIO
+ regions from the map.
+
+ The kernel maintains another table, kern_memmap, which describes the
+ memory Linux is actually using and the attribute for each region.
+ This contains only system memory; it does not contain MMIO space.
+
+ The kern_memmap table typically contains only a subset of the system
+ memory described by the efi_memmap. Linux/ia64 can't use all memory
+ in the system because of constraints imposed by the identity mapping
+ scheme.
+
+ The efi_memmap table is preserved unmodified because the original
+ boot-time information is required for kexec.
+
+KERNEL IDENTITY MAPPINGS
+
+ Linux/ia64 identity mappings are done with large pages, currently
+ either 16MB or 64MB, referred to as "granules." Cacheable mappings
+ are speculative[2], so the processor can read any location in the
+ page at any time, independent of the programmer's intentions. This
+ means that to avoid attribute aliasing, Linux can create a cacheable
+ identity mapping only when the entire granule supports cacheable
+ access.
+
+ Therefore, kern_memmap contains only full granule-sized regions that
+ can referenced safely by an identity mapping.
+
+ Uncacheable mappings are not speculative, so the processor will
+ generate UC accesses only to locations explicitly referenced by
+ software. This allows UC identity mappings to cover granules that
+ are only partially populated, or populated with a combination of UC
+ and WB regions.
+
+USER MAPPINGS
+
+ User mappings are typically done with 16K or 64K pages. The smaller
+ page size allows more flexibility because only 16K or 64K has to be
+ homogeneous with respect to memory attributes.
+
+POTENTIAL ATTRIBUTE ALIASING CASES
+
+ There are several ways the kernel creates new mappings:
+
+ mmap of /dev/mem
+
+ This uses remap_pfn_range(), which creates user mappings. These
+ mappings may be either WB or UC. If the region being mapped
+ happens to be in kern_memmap, meaning that it may also be mapped
+ by a kernel identity mapping, the user mapping must use the same
+ attribute as the kernel mapping.
+
+ If the region is not in kern_memmap, the user mapping should use
+ an attribute reported as being supported in the EFI memory map.
+
+ Since the EFI memory map does not describe MMIO on some
+ machines, this should use an uncacheable mapping as a fallback.
+
+ mmap of /sys/class/pci_bus/.../legacy_mem
+
+ This is very similar to mmap of /dev/mem, except that legacy_mem
+ only allows mmap of the one megabyte "legacy MMIO" area for a
+ specific PCI bus. Typically this is the first megabyte of
+ physical address space, but it may be different on machines with
+ several VGA devices.
+
+ "X" uses this to access VGA frame buffers. Using legacy_mem
+ rather than /dev/mem allows multiple instances of X to talk to
+ different VGA cards.
+
+ The /dev/mem mmap constraints apply.
+
+ However, since this is for mapping legacy MMIO space, WB access
+ does not make sense. This matters on machines without legacy
+ VGA support: these machines may have WB memory for the entire
+ first megabyte (or even the entire first granule).
+
+ On these machines, we could mmap legacy_mem as WB, which would
+ be safe in terms of attribute aliasing, but X has no way of
+ knowing that it is accessing regular memory, not a frame buffer,
+ so the kernel should fail the mmap rather than doing it with WB.
+
+ read/write of /dev/mem
+
+ This uses copy_from_user(), which implicitly uses a kernel
+ identity mapping. This is obviously safe for things in
+ kern_memmap.
+
+ There may be corner cases of things that are not in kern_memmap,
+ but could be accessed this way. For example, registers in MMIO
+ space are not in kern_memmap, but could be accessed with a UC
+ mapping. This would not cause attribute aliasing. But
+ registers typically can be accessed only with four-byte or
+ eight-byte accesses, and the copy_from_user() path doesn't allow
+ any control over the access size, so this would be dangerous.
+
+ ioremap()
+
+ This returns a kernel identity mapping for use inside the
+ kernel.
+
+ If the region is in kern_memmap, we should use the attribute
+ specified there. Otherwise, if the EFI memory map reports that
+ the entire granule supports WB, we should use that (granules
+ that are partially reserved or occupied by firmware do not appear
+ in kern_memmap). Otherwise, we should use a UC mapping.
+
+PAST PROBLEM CASES
+
+ mmap of various MMIO regions from /dev/mem by "X" on Intel platforms
+
+ The EFI memory map may not report these MMIO regions.
+
+ These must be allowed so that X will work. This means that
+ when the EFI memory map is incomplete, every /dev/mem mmap must
+ succeed. It may create either WB or UC user mappings, depending
+ on whether the region is in kern_memmap or the EFI memory map.
+
+ mmap of 0x0-0xA0000 /dev/mem by "hwinfo" on HP sx1000 with VGA enabled
+
+ See https://bugzilla.novell.com/show_bug.cgi?id=140858.
+
+ The EFI memory map reports the following attributes:
+ 0x00000-0x9FFFF WB only
+ 0xA0000-0xBFFFF UC only (VGA frame buffer)
+ 0xC0000-0xFFFFF WB only
+
+ This mmap is done with user pages, not kernel identity mappings,
+ so it is safe to use WB mappings.
+
+ The kernel VGA driver may ioremap the VGA frame buffer at 0xA0000,
+ which will use a granule-sized UC mapping covering 0-0xFFFFF. This
+ granule covers some WB-only memory, but since UC is non-speculative,
+ the processor will never generate an uncacheable reference to the
+ WB-only areas unless the driver explicitly touches them.
+
+ mmap of 0x0-0xFFFFF legacy_mem by "X"
+
+ If the EFI memory map reports this entire range as WB, there
+ is no VGA MMIO hole, and the mmap should fail or be done with
+ a WB mapping.
+
+ There's no easy way for X to determine whether the 0xA0000-0xBFFFF
+ region is a frame buffer or just memory, so I think it's best to
+ just fail this mmap request rather than using a WB mapping. As
+ far as I know, there's no need to map legacy_mem with WB
+ mappings.
+
+ Otherwise, a UC mapping of the entire region is probably safe.
+ The VGA hole means the region will not be in kern_memmap. The
+ HP sx1000 chipset doesn't support UC access to the memory surrounding
+ the VGA hole, but X doesn't need that area anyway and should not
+ reference it.
+
+ mmap of 0xA0000-0xBFFFF legacy_mem by "X" on HP sx1000 with VGA disabled
+
+ The EFI memory map reports the following attributes:
+ 0x00000-0xFFFFF WB only (no VGA MMIO hole)
+
+ This is a special case of the previous case, and the mmap should
+ fail for the same reason as above.
+
+NOTES
+
+ [1] SDM rev 2.2, vol 2, sec 4.4.1.
+ [2] SDM rev 2.2, vol 2, sec 4.4.6.
diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt
index 171a44e..1543802 100644
--- a/Documentation/ioctl-number.txt
+++ b/Documentation/ioctl-number.txt
@@ -85,7 +85,9 @@ Code Seq# Include File Comments
<mailto:maassen@uni-freiburg.de>
'C' all linux/soundcard.h
'D' all asm-s390/dasd.h
+'E' all linux/input.h
'F' all linux/fb.h
+'H' all linux/hiddev.h
'I' all linux/isdn.h
'J' 00-1F drivers/scsi/gdth_ioctl.h
'K' all linux/kd.h
diff --git a/Documentation/kdump/kdump.txt b/Documentation/kdump/kdump.txt
index 212cf3c..08bafa8 100644
--- a/Documentation/kdump/kdump.txt
+++ b/Documentation/kdump/kdump.txt
@@ -1,155 +1,325 @@
-Documentation for kdump - the kexec-based crash dumping solution
+================================================================
+Documentation for Kdump - The kexec-based Crash Dumping Solution
================================================================
-DESIGN
-======
+This document includes overview, setup and installation, and analysis
+information.
-Kdump uses kexec to reboot to a second kernel whenever a dump needs to be
-taken. This second kernel is booted with very little memory. The first kernel
-reserves the section of memory that the second kernel uses. This ensures that
-on-going DMA from the first kernel does not corrupt the second kernel.
+Overview
+========
-All the necessary information about Core image is encoded in ELF format and
-stored in reserved area of memory before crash. Physical address of start of
-ELF header is passed to new kernel through command line parameter elfcorehdr=.
+Kdump uses kexec to quickly boot to a dump-capture kernel whenever a
+dump of the system kernel's memory needs to be taken (for example, when
+the system panics). The system kernel's memory image is preserved across
+the reboot and is accessible to the dump-capture kernel.
-On i386, the first 640 KB of physical memory is needed to boot, irrespective
-of where the kernel loads. Hence, this region is backed up by kexec just before
-rebooting into the new kernel.
+You can use common Linux commands, such as cp and scp, to copy the
+memory image to a dump file on the local disk, or across the network to
+a remote system.
-In the second kernel, "old memory" can be accessed in two ways.
+Kdump and kexec are currently supported on the x86, x86_64, and ppc64
+architectures.
-- The first one is through a /dev/oldmem device interface. A capture utility
- can read the device file and write out the memory in raw format. This is raw
- dump of memory and analysis/capture tool should be intelligent enough to
- determine where to look for the right information. ELF headers (elfcorehdr=)
- can become handy here.
+When the system kernel boots, it reserves a small section of memory for
+the dump-capture kernel. This ensures that ongoing Direct Memory Access
+(DMA) from the system kernel does not corrupt the dump-capture kernel.
+The kexec -p command loads the dump-capture kernel into this reserved
+memory.
-- The second interface is through /proc/vmcore. This exports the dump as an ELF
- format file which can be written out using any file copy command
- (cp, scp, etc). Further, gdb can be used to perform limited debugging on
- the dump file. This method ensures methods ensure that there is correct
- ordering of the dump pages (corresponding to the first 640 KB that has been
- relocated).
+On x86 machines, the first 640 KB of physical memory is needed to boot,
+regardless of where the kernel loads. Therefore, kexec backs up this
+region just before rebooting into the dump-capture kernel.
-SETUP
-=====
+All of the necessary information about the system kernel's core image is
+encoded in the ELF format, and stored in a reserved area of memory
+before a crash. The physical address of the start of the ELF header is
+passed to the dump-capture kernel through the elfcorehdr= boot
+parameter.
+
+With the dump-capture kernel, you can access the memory image, or "old
+memory," in two ways:
+
+- Through a /dev/oldmem device interface. A capture utility can read the
+ device file and write out the memory in raw format. This is a raw dump
+ of memory. Analysis and capture tools must be intelligent enough to
+ determine where to look for the right information.
+
+- Through /proc/vmcore. This exports the dump as an ELF-format file that
+ you can write out using file copy commands such as cp or scp. Further,
+ you can use analysis tools such as the GNU Debugger (GDB) and the Crash
+ tool to debug the dump file. This method ensures that the dump pages are
+ correctly ordered.
+
+
+Setup and Installation
+======================
+
+Install kexec-tools and the Kdump patch
+---------------------------------------
+
+1) Login as the root user.
+
+2) Download the kexec-tools user-space package from the following URL:
+
+ http://www.xmission.com/~ebiederm/files/kexec/kexec-tools-1.101.tar.gz
+
+3) Unpack the tarball with the tar command, as follows:
+
+ tar xvpzf kexec-tools-1.101.tar.gz
+
+4) Download the latest consolidated Kdump patch from the following URL:
+
+ http://lse.sourceforge.net/kdump/
+
+ (This location is being used until all the user-space Kdump patches
+ are integrated with the kexec-tools package.)
+
+5) Change to the kexec-tools-1.101 directory, as follows:
+
+ cd kexec-tools-1.101
+
+6) Apply the consolidated patch to the kexec-tools-1.101 source tree
+ with the patch command, as follows. (Modify the path to the downloaded
+ patch as necessary.)
+
+ patch -p1 < /path-to-kdump-patch/kexec-tools-1.101-kdump.patch
+
+7) Configure the package, as follows:
+
+ ./configure
+
+8) Compile the package, as follows:
+
+ make
+
+9) Install the package, as follows:
+
+ make install
+
+
+Download and build the system and dump-capture kernels
+------------------------------------------------------
+
+Download the mainline (vanilla) kernel source code (2.6.13-rc1 or newer)
+from http://www.kernel.org. Two kernels must be built: a system kernel
+and a dump-capture kernel. Use the following steps to configure these
+kernels with the necessary kexec and Kdump features:
+
+System kernel
+-------------
+
+1) Enable "kexec system call" in "Processor type and features."
+
+ CONFIG_KEXEC=y
+
+2) Enable "sysfs file system support" in "Filesystem" -> "Pseudo
+ filesystems." This is usually enabled by default.
+
+ CONFIG_SYSFS=y
+
+ Note that "sysfs file system support" might not appear in the "Pseudo
+ filesystems" menu if "Configure standard kernel features (for small
+ systems)" is not enabled in "General Setup." In this case, check the
+ .config file itself to ensure that sysfs is turned on, as follows:
+
+ grep 'CONFIG_SYSFS' .config
+
+3) Enable "Compile the kernel with debug info" in "Kernel hacking."
+
+ CONFIG_DEBUG_INFO=Y
+
+ This causes the kernel to be built with debug symbols. The dump
+ analysis tools require a vmlinux with debug symbols in order to read
+ and analyze a dump file.
+
+4) Make and install the kernel and its modules. Update the boot loader
+ (such as grub, yaboot, or lilo) configuration files as necessary.
+
+5) Boot the system kernel with the boot parameter "crashkernel=Y@X",
+ where Y specifies how much memory to reserve for the dump-capture kernel
+ and X specifies the beginning of this reserved memory. For example,
+ "crashkernel=64M@16M" tells the system kernel to reserve 64 MB of memory
+ starting at physical address 0x01000000 for the dump-capture kernel.
+
+ On x86 and x86_64, use "crashkernel=64M@16M".
+
+ On ppc64, use "crashkernel=128M@32M".
+
+
+The dump-capture kernel
+-----------------------
-1) Download the upstream kexec-tools userspace package from
- http://www.xmission.com/~ebiederm/files/kexec/kexec-tools-1.101.tar.gz.
-
- Apply the latest consolidated kdump patch on top of kexec-tools-1.101
- from http://lse.sourceforge.net/kdump/. This arrangment has been made
- till all the userspace patches supporting kdump are integrated with
- upstream kexec-tools userspace.
-
-2) Download and build the appropriate (2.6.13-rc1 onwards) vanilla kernels.
- Two kernels need to be built in order to get this feature working.
- Following are the steps to properly configure the two kernels specific
- to kexec and kdump features:
-
- A) First kernel or regular kernel:
- ----------------------------------
- a) Enable "kexec system call" feature (in Processor type and features).
- CONFIG_KEXEC=y
- b) Enable "sysfs file system support" (in Pseudo filesystems).
- CONFIG_SYSFS=y
- c) make
- d) Boot into first kernel with the command line parameter "crashkernel=Y@X".
- Use appropriate values for X and Y. Y denotes how much memory to reserve
- for the second kernel, and X denotes at what physical address the
- reserved memory section starts. For example: "crashkernel=64M@16M".
-
-
- B) Second kernel or dump capture kernel:
- ---------------------------------------
- a) For i386 architecture enable Highmem support
- CONFIG_HIGHMEM=y
- b) Enable "kernel crash dumps" feature (under "Processor type and features")
- CONFIG_CRASH_DUMP=y
- c) Make sure a suitable value for "Physical address where the kernel is
- loaded" (under "Processor type and features"). By default this value
- is 0x1000000 (16MB) and it should be same as X (See option d above),
- e.g., 16 MB or 0x1000000.
- CONFIG_PHYSICAL_START=0x1000000
- d) Enable "/proc/vmcore support" (Optional, under "Pseudo filesystems").
- CONFIG_PROC_VMCORE=y
-
-3) After booting to regular kernel or first kernel, load the second kernel
- using the following command:
-
- kexec -p <second-kernel> --args-linux --elf32-core-headers
- --append="root=<root-dev> init 1 irqpoll maxcpus=1"
-
- Notes:
- ======
- i) <second-kernel> has to be a vmlinux image ie uncompressed elf image.
- bzImage will not work, as of now.
- ii) --args-linux has to be speicfied as if kexec it loading an elf image,
- it needs to know that the arguments supplied are of linux type.
- iii) By default ELF headers are stored in ELF64 format to support systems
- with more than 4GB memory. Option --elf32-core-headers forces generation
- of ELF32 headers. The reason for this option being, as of now gdb can
- not open vmcore file with ELF64 headers on a 32 bit systems. So ELF32
- headers can be used if one has non-PAE systems and hence memory less
- than 4GB.
- iv) Specify "irqpoll" as command line parameter. This reduces driver
- initialization failures in second kernel due to shared interrupts.
- v) <root-dev> needs to be specified in a format corresponding to the root
- device name in the output of mount command.
- vi) If you have built the drivers required to mount root file system as
- modules in <second-kernel>, then, specify
- --initrd=<initrd-for-second-kernel>.
- vii) Specify maxcpus=1 as, if during first kernel run, if panic happens on
- non-boot cpus, second kernel doesn't seem to be boot up all the cpus.
- The other option is to always built the second kernel without SMP
- support ie CONFIG_SMP=n
-
-4) After successfully loading the second kernel as above, if a panic occurs
- system reboots into the second kernel. A module can be written to force
- the panic or "ALT-SysRq-c" can be used initiate a crash dump for testing
- purposes.
-
-5) Once the second kernel has booted, write out the dump file using
+1) Under "General setup," append "-kdump" to the current string in
+ "Local version."
+
+2) On x86, enable high memory support under "Processor type and
+ features":
+
+ CONFIG_HIGHMEM64G=y
+ or
+ CONFIG_HIGHMEM4G
+
+3) On x86 and x86_64, disable symmetric multi-processing support
+ under "Processor type and features":
+
+ CONFIG_SMP=n
+ (If CONFIG_SMP=y, then specify maxcpus=1 on the kernel command line
+ when loading the dump-capture kernel, see section "Load the Dump-capture
+ Kernel".)
+
+4) On ppc64, disable NUMA support and enable EMBEDDED support:
+
+ CONFIG_NUMA=n
+ CONFIG_EMBEDDED=y
+ CONFIG_EEH=N for the dump-capture kernel
+
+5) Enable "kernel crash dumps" support under "Processor type and
+ features":
+
+ CONFIG_CRASH_DUMP=y
+
+6) Use a suitable value for "Physical address where the kernel is
+ loaded" (under "Processor type and features"). This only appears when
+ "kernel crash dumps" is enabled. By default this value is 0x1000000
+ (16MB). It should be the same as X in the "crashkernel=Y@X" boot
+ parameter discussed above.
+
+ On x86 and x86_64, use "CONFIG_PHYSICAL_START=0x1000000".
+
+ On ppc64 the value is automatically set at 32MB when
+ CONFIG_CRASH_DUMP is set.
+
+6) Optionally enable "/proc/vmcore support" under "Filesystems" ->
+ "Pseudo filesystems".
+
+ CONFIG_PROC_VMCORE=y
+ (CONFIG_PROC_VMCORE is set by default when CONFIG_CRASH_DUMP is selected.)
+
+7) Make and install the kernel and its modules. DO NOT add this kernel
+ to the boot loader configuration files.
+
+
+Load the Dump-capture Kernel
+============================
+
+After booting to the system kernel, load the dump-capture kernel using
+the following command:
+
+ kexec -p <dump-capture-kernel> \
+ --initrd=<initrd-for-dump-capture-kernel> --args-linux \
+ --append="root=<root-dev> init 1 irqpoll"
+
+
+Notes on loading the dump-capture kernel:
+
+* <dump-capture-kernel> must be a vmlinux image (that is, an
+ uncompressed ELF image). bzImage does not work at this time.
+
+* By default, the ELF headers are stored in ELF64 format to support
+ systems with more than 4GB memory. The --elf32-core-headers option can
+ be used to force the generation of ELF32 headers. This is necessary
+ because GDB currently cannot open vmcore files with ELF64 headers on
+ 32-bit systems. ELF32 headers can be used on non-PAE systems (that is,
+ less than 4GB of memory).
+
+* The "irqpoll" boot parameter reduces driver initialization failures
+ due to shared interrupts in the dump-capture kernel.
+
+* You must specify <root-dev> in the format corresponding to the root
+ device name in the output of mount command.
+
+* "init 1" boots the dump-capture kernel into single-user mode without
+ networking. If you want networking, use "init 3."
+
+
+Kernel Panic
+============
+
+After successfully loading the dump-capture kernel as previously
+described, the system will reboot into the dump-capture kernel if a
+system crash is triggered. Trigger points are located in panic(),
+die(), die_nmi() and in the sysrq handler (ALT-SysRq-c).
+
+The following conditions will execute a crash trigger point:
+
+If a hard lockup is detected and "NMI watchdog" is configured, the system
+will boot into the dump-capture kernel ( die_nmi() ).
+
+If die() is called, and it happens to be a thread with pid 0 or 1, or die()
+is called inside interrupt context or die() is called and panic_on_oops is set,
+the system will boot into the dump-capture kernel.
+
+On powererpc systems when a soft-reset is generated, die() is called by all cpus and the system system will boot into the dump-capture kernel.
+
+For testing purposes, you can trigger a crash by using "ALT-SysRq-c",
+"echo c > /proc/sysrq-trigger or write a module to force the panic.
+
+Write Out the Dump File
+=======================
+
+After the dump-capture kernel is booted, write out the dump file with
+the following command:
cp /proc/vmcore <dump-file>
- Dump memory can also be accessed as a /dev/oldmem device for a linear/raw
- view. To create the device, type:
+You can also access dumped memory as a /dev/oldmem device for a linear
+and raw view. To create the device, use the following command:
- mknod /dev/oldmem c 1 12
+ mknod /dev/oldmem c 1 12
- Use "dd" with suitable options for count, bs and skip to access specific
- portions of the dump.
+Use the dd command with suitable options for count, bs, and skip to
+access specific portions of the dump.
- Entire memory: dd if=/dev/oldmem of=oldmem.001
+To see the entire memory, use the following command:
+ dd if=/dev/oldmem of=oldmem.001
-ANALYSIS
+
+Analysis
========
-Limited analysis can be done using gdb on the dump file copied out of
-/proc/vmcore. Use vmlinux built with -g and run
- gdb vmlinux <dump-file>
+Before analyzing the dump image, you should reboot into a stable kernel.
+
+You can do limited analysis using GDB on the dump file copied out of
+/proc/vmcore. Use the debug vmlinux built with -g and run the following
+command:
+
+ gdb vmlinux <dump-file>
-Stack trace for the task on processor 0, register display, memory display
-work fine.
+Stack trace for the task on processor 0, register display, and memory
+display work fine.
-Note: gdb cannot analyse core files generated in ELF64 format for i386.
+Note: GDB cannot analyze core files generated in ELF64 format for x86.
+On systems with a maximum of 4GB of memory, you can generate
+ELF32-format headers using the --elf32-core-headers kernel option on the
+dump kernel.
-Latest "crash" (crash-4.0-2.18) as available on Dave Anderson's site
-http://people.redhat.com/~anderson/ works well with kdump format.
+You can also use the Crash utility to analyze dump files in Kdump
+format. Crash is available on Dave Anderson's site at the following URL:
+ http://people.redhat.com/~anderson/
+
+
+To Do
+=====
-TODO
-====
-1) Provide a kernel pages filtering mechanism so that core file size is not
- insane on systems having huge memory banks.
-2) Relocatable kernel can help in maintaining multiple kernels for crashdump
- and same kernel as the first kernel can be used to capture the dump.
+1) Provide a kernel pages filtering mechanism, so core file size is not
+ extreme on systems with huge memory banks.
+2) Relocatable kernel can help in maintaining multiple kernels for
+ crash_dump, and the same kernel as the system kernel can be used to
+ capture the dump.
-CONTACT
+
+Contact
=======
+
Vivek Goyal (vgoyal@in.ibm.com)
Maneesh Soni (maneesh@in.ibm.com)
+
+
+Trademark
+=========
+
+Linux is a trademark of Linus Torvalds in the United States, other
+countries, or both.
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index a9d3a17..bca6f38 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -147,6 +147,9 @@ running once the system is up.
acpi_irq_isa= [HW,ACPI] If irq_balance, mark listed IRQs used by ISA
Format: <irq>,<irq>...
+ acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS
+ Format: To spoof as Windows 98: ="Microsoft Windows"
+
acpi_osi= [HW,ACPI] empty param disables _OSI
acpi_serialize [HW,ACPI] force serialization of AML methods
diff --git a/Documentation/keys.txt b/Documentation/keys.txt
index aaa01b0..3bbe157 100644
--- a/Documentation/keys.txt
+++ b/Documentation/keys.txt
@@ -19,6 +19,7 @@ This document has the following sections:
- Key overview
- Key service overview
- Key access permissions
+ - SELinux support
- New procfs files
- Userspace system call interface
- Kernel services
@@ -232,6 +233,34 @@ For changing the ownership, group ID or permissions mask, being the owner of
the key or having the sysadmin capability is sufficient.
+===============
+SELINUX SUPPORT
+===============
+
+The security class "key" has been added to SELinux so that mandatory access
+controls can be applied to keys created within various contexts. This support
+is preliminary, and is likely to change quite significantly in the near future.
+Currently, all of the basic permissions explained above are provided in SELinux
+as well; SE Linux is simply invoked after all basic permission checks have been
+performed.
+
+Each key is labeled with the same context as the task to which it belongs.
+Typically, this is the same task that was running when the key was created.
+The default keyrings are handled differently, but in a way that is very
+intuitive:
+
+ (*) The user and user session keyrings that are created when the user logs in
+ are currently labeled with the context of the login manager.
+
+ (*) The keyrings associated with new threads are each labeled with the context
+ of their associated thread, and both session and process keyrings are
+ handled similarly.
+
+Note, however, that the default keyrings associated with the root user are
+labeled with the default kernel context, since they are created early in the
+boot process, before root has a chance to log in.
+
+
================
NEW PROCFS FILES
================
@@ -935,6 +964,16 @@ The structure has a number of fields, some of which are mandatory:
It is not safe to sleep in this method; the caller may hold spinlocks.
+ (*) void (*revoke)(struct key *key);
+
+ This method is optional. It is called to discard part of the payload
+ data upon a key being revoked. The caller will have the key semaphore
+ write-locked.
+
+ It is safe to sleep in this method, though care should be taken to avoid
+ a deadlock against the key semaphore.
+
+
(*) void (*destroy)(struct key *key);
This method is optional. It is called to discard the payload data on a key
diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt
index 4710845..cf0d541 100644
--- a/Documentation/memory-barriers.txt
+++ b/Documentation/memory-barriers.txt
@@ -262,9 +262,14 @@ What is required is some way of intervening to instruct the compiler and the
CPU to restrict the order.
Memory barriers are such interventions. They impose a perceived partial
-ordering between the memory operations specified on either side of the barrier.
-They request that the sequence of memory events generated appears to other
-parts of the system as if the barrier is effective on that CPU.
+ordering over the memory operations on either side of the barrier.
+
+Such enforcement is important because the CPUs and other devices in a system
+can use a variety of tricks to improve performance - including reordering,
+deferral and combination of memory operations; speculative loads; speculative
+branch prediction and various types of caching. Memory barriers are used to
+override or suppress these tricks, allowing the code to sanely control the
+interaction of multiple CPUs and/or devices.
VARIETIES OF MEMORY BARRIER
@@ -282,7 +287,7 @@ Memory barriers come in four basic varieties:
A write barrier is a partial ordering on stores only; it is not required
to have any effect on loads.
- A CPU can be viewed as as commiting a sequence of store operations to the
+ A CPU can be viewed as committing a sequence of store operations to the
memory system as time progresses. All stores before a write barrier will
occur in the sequence _before_ all the stores after the write barrier.
@@ -413,7 +418,7 @@ There are certain things that the Linux kernel memory barriers do not guarantee:
indirect effect will be the order in which the second CPU sees the effects
of the first CPU's accesses occur, but see the next point:
- (*) There is no guarantee that the a CPU will see the correct order of effects
+ (*) There is no guarantee that a CPU will see the correct order of effects
from a second CPU's accesses, even _if_ the second CPU uses a memory
barrier, unless the first CPU _also_ uses a matching memory barrier (see
the subsection on "SMP Barrier Pairing").
@@ -461,8 +466,8 @@ Whilst this may seem like a failure of coherency or causality maintenance, it
isn't, and this behaviour can be observed on certain real CPUs (such as the DEC
Alpha).
-To deal with this, a data dependency barrier must be inserted between the
-address load and the data load:
+To deal with this, a data dependency barrier or better must be inserted
+between the address load and the data load:
CPU 1 CPU 2
=============== ===============
@@ -484,7 +489,7 @@ lines. The pointer P might be stored in an odd-numbered cache line, and the
variable B might be stored in an even-numbered cache line. Then, if the
even-numbered bank of the reading CPU's cache is extremely busy while the
odd-numbered bank is idle, one can see the new value of the pointer P (&B),
-but the old value of the variable B (1).
+but the old value of the variable B (2).
Another example of where data dependency barriers might by required is where a
@@ -744,7 +749,7 @@ some effectively random order, despite the write barrier issued by CPU 1:
: :
-If, however, a read barrier were to be placed between the load of E and the
+If, however, a read barrier were to be placed between the load of B and the
load of A on CPU 2:
CPU 1 CPU 2
@@ -1461,9 +1466,8 @@ instruction itself is complete.
On a UP system - where this wouldn't be a problem - the smp_mb() is just a
compiler barrier, thus making sure the compiler emits the instructions in the
-right order without actually intervening in the CPU. Since there there's only
-one CPU, that CPU's dependency ordering logic will take care of everything
-else.
+right order without actually intervening in the CPU. Since there's only one
+CPU, that CPU's dependency ordering logic will take care of everything else.
ATOMIC OPERATIONS
@@ -1640,9 +1644,9 @@ functions:
The PCI bus, amongst others, defines an I/O space concept - which on such
CPUs as i386 and x86_64 cpus readily maps to the CPU's concept of I/O
- space. However, it may also mapped as a virtual I/O space in the CPU's
- memory map, particularly on those CPUs that don't support alternate
- I/O spaces.
+ space. However, it may also be mapped as a virtual I/O space in the CPU's
+ memory map, particularly on those CPUs that don't support alternate I/O
+ spaces.
Accesses to this space may be fully synchronous (as on i386), but
intermediary bridges (such as the PCI host bridge) may not fully honour
diff --git a/Documentation/networking/tuntap.txt b/Documentation/networking/tuntap.txt
index 76750fb..839cbb7 100644
--- a/Documentation/networking/tuntap.txt
+++ b/Documentation/networking/tuntap.txt
@@ -39,10 +39,13 @@ Copyright (C) 1999-2000 Maxim Krasnyansky <max_mk@yahoo.com>
mknod /dev/net/tun c 10 200
Set permissions:
- e.g. chmod 0700 /dev/net/tun
- if you want the device only accessible by root. Giving regular users the
- right to assign network devices is NOT a good idea. Users could assign
- bogus network interfaces to trick firewalls or administrators.
+ e.g. chmod 0666 /dev/net/tun
+ There's no harm in allowing the device to be accessible by non-root users,
+ since CAP_NET_ADMIN is required for creating network devices or for
+ connecting to network devices which aren't owned by the user in question.
+ If you want to create persistent devices and give ownership of them to
+ unprivileged users, then you need the /dev/net/tun device to be usable by
+ those users.
Driver module autoloading
diff --git a/Documentation/pci.txt b/Documentation/pci.txt
index 66bbbf1..3242e5c 100644
--- a/Documentation/pci.txt
+++ b/Documentation/pci.txt
@@ -213,9 +213,17 @@ have been remapped by the kernel.
See Documentation/IO-mapping.txt for how to access device memory.
- You still need to call request_region() for I/O regions and
-request_mem_region() for memory regions to make sure nobody else is using the
-same device.
+ The device driver needs to call pci_request_region() to make sure
+no other device is already using the same resource. The driver is expected
+to determine MMIO and IO Port resource availability _before_ calling
+pci_enable_device(). Conversely, drivers should call pci_release_region()
+_after_ calling pci_disable_device(). The idea is to prevent two devices
+colliding on the same address range.
+
+Generic flavors of pci_request_region() are request_mem_region()
+(for MMIO ranges) and request_region() (for IO Port ranges).
+Use these for address resources that are not described by "normal" PCI
+interfaces (e.g. BAR).
All interrupt handlers should be registered with SA_SHIRQ and use the devid
to map IRQs to devices (remember that all PCI interrupts are shared).
diff --git a/Documentation/power/swsusp.txt b/Documentation/power/swsusp.txt
index 516c501..823b2cf 100644
--- a/Documentation/power/swsusp.txt
+++ b/Documentation/power/swsusp.txt
@@ -350,9 +350,34 @@ Q: How do I make suspend more verbose?
A: If you want to see any non-error kernel messages on the virtual
terminal the kernel switches to during suspend, you have to set the
-kernel console loglevel to at least 5, for example by doing
-
- echo 5 > /proc/sys/kernel/printk
+kernel console loglevel to at least 4 (KERN_WARNING), for example by
+doing
+
+ # save the old loglevel
+ read LOGLEVEL DUMMY < /proc/sys/kernel/printk
+ # set the loglevel so we see the progress bar.
+ # if the level is higher than needed, we leave it alone.
+ if [ $LOGLEVEL -lt 5 ]; then
+ echo 5 > /proc/sys/kernel/printk
+ fi
+
+ IMG_SZ=0
+ read IMG_SZ < /sys/power/image_size
+ echo -n disk > /sys/power/state
+ RET=$?
+ #
+ # the logic here is:
+ # if image_size > 0 (without kernel support, IMG_SZ will be zero),
+ # then try again with image_size set to zero.
+ if [ $RET -ne 0 -a $IMG_SZ -ne 0 ]; then # try again with minimal image size
+ echo 0 > /sys/power/image_size
+ echo -n disk > /sys/power/state
+ RET=$?
+ fi
+
+ # restore previous loglevel
+ echo $LOGLEVEL > /proc/sys/kernel/printk
+ exit $RET
Q: Is this true that if I have a mounted filesystem on a USB device and
I suspend to disk, I can lose data unless the filesystem has been mounted
@@ -380,3 +405,17 @@ safest thing is to unmount all filesystems on removable media (such USB,
Firewire, CompactFlash, MMC, external SATA, or even IDE hotplug bays)
before suspending; then remount them after resuming.
+Q: I upgraded the kernel from 2.6.15 to 2.6.16. Both kernels were
+compiled with the similar configuration files. Anyway I found that
+suspend to disk (and resume) is much slower on 2.6.16 compared to
+2.6.15. Any idea for why that might happen or how can I speed it up?
+
+A: This is because the size of the suspend image is now greater than
+for 2.6.15 (by saving more data we can get more responsive system
+after resume).
+
+There's the /sys/power/image_size knob that controls the size of the
+image. If you set it to 0 (eg. by echo 0 > /sys/power/image_size as
+root), the 2.6.15 behavior should be restored. If it is still too
+slow, take a look at suspend.sf.net -- userland suspend is faster and
+supports LZF compression to speed it up further.
diff --git a/Documentation/power/video.txt b/Documentation/power/video.txt
index 43a889f..d859faa 100644
--- a/Documentation/power/video.txt
+++ b/Documentation/power/video.txt
@@ -90,6 +90,7 @@ Table of known working notebooks:
Model hack (or "how to do it")
------------------------------------------------------------------------------
Acer Aspire 1406LC ole's late BIOS init (7), turn off DRI
+Acer TM 230 s3_bios (2)
Acer TM 242FX vbetool (6)
Acer TM C110 video_post (8)
Acer TM C300 vga=normal (only suspend on console, not in X), vbetool (6) or video_post (8)
@@ -115,6 +116,7 @@ Dell D610 vga=normal and X (possibly vbestate (6) too, but not tested)
Dell Inspiron 4000 ??? (*)
Dell Inspiron 500m ??? (*)
Dell Inspiron 510m ???
+Dell Inspiron 5150 vbetool needed (6)
Dell Inspiron 600m ??? (*)
Dell Inspiron 8200 ??? (*)
Dell Inspiron 8500 ??? (*)
@@ -125,6 +127,7 @@ HP NX7000 ??? (*)
HP Pavilion ZD7000 vbetool post needed, need open-source nv driver for X
HP Omnibook XE3 athlon version none (1)
HP Omnibook XE3GC none (1), video is S3 Savage/IX-MV
+HP Omnibook XE3L-GF vbetool (6)
HP Omnibook 5150 none (1), (S1 also works OK)
IBM TP T20, model 2647-44G none (1), video is S3 Inc. 86C270-294 Savage/IX-MV, vesafb gets "interesting" but X work.
IBM TP A31 / Type 2652-M5G s3_mode (3) [works ok with BIOS 1.04 2002-08-23, but not at all with BIOS 1.11 2004-11-05 :-(]
@@ -157,6 +160,7 @@ Sony Vaio vgn-s260 X or boot-radeon can init it (5)
Sony Vaio vgn-S580BH vga=normal, but suspend from X. Console will be blank unless you return to X.
Sony Vaio vgn-FS115B s3_bios (2),s3_mode (4)
Toshiba Libretto L5 none (1)
+Toshiba Libretto 100CT/110CT vbetool (6)
Toshiba Portege 3020CT s3_mode (3)
Toshiba Satellite 4030CDT s3_mode (3) (S1 also works OK)
Toshiba Satellite 4080XCDT s3_mode (3) (S1 also works OK)
diff --git a/Documentation/rtc.txt b/Documentation/rtc.txt
index 95d17b3..2a58f98 100644
--- a/Documentation/rtc.txt
+++ b/Documentation/rtc.txt
@@ -44,8 +44,10 @@ normal timer interrupt, which is 100Hz.
Programming and/or enabling interrupt frequencies greater than 64Hz is
only allowed by root. This is perhaps a bit conservative, but we don't want
an evil user generating lots of IRQs on a slow 386sx-16, where it might have
-a negative impact on performance. Note that the interrupt handler is only
-a few lines of code to minimize any possibility of this effect.
+a negative impact on performance. This 64Hz limit can be changed by writing
+a different value to /proc/sys/dev/rtc/max-user-freq. Note that the
+interrupt handler is only a few lines of code to minimize any possibility
+of this effect.
Also, if the kernel time is synchronized with an external source, the
kernel will write the time back to the CMOS clock every 11 minutes. In
@@ -81,6 +83,7 @@ that will be using this driver.
*/
#include <stdio.h>
+#include <stdlib.h>
#include <linux/rtc.h>
#include <sys/ioctl.h>
#include <sys/time.h>
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 0ee2c7d..87d76a5 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -366,7 +366,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
Module for C-Media CMI8338 and 8738 PCI sound cards.
- mpu_port - 0x300,0x310,0x320,0x330, 0 = disable (default)
+ mpu_port - 0x300,0x310,0x320,0x330 = legacy port,
+ 1 = integrated PCI port,
+ 0 = disable (default)
fm_port - 0x388 (default), 0 = disable (default)
soft_ac3 - Software-conversion of raw SPDIF packets (model 033 only)
(default = 1)
@@ -468,7 +470,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
Module for multifunction CS5535 companion PCI device
- This module supports multiple cards.
+ The power-management is supported.
Module snd-dt019x
-----------------
@@ -707,8 +709,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
Module snd-hda-intel
--------------------
- Module for Intel HD Audio (ICH6, ICH6M, ICH7), ATI SB450,
- VIA VT8251/VT8237A
+ Module for Intel HD Audio (ICH6, ICH6M, ESB2, ICH7, ICH8),
+ ATI SB450, SB600, RS600,
+ VIA VT8251/VT8237A,
+ SIS966, ULI M5461
model - force the model name
position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)
@@ -778,6 +782,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
AD1981
basic 3-jack (default)
hp HP nx6320
+ thinkpad Lenovo Thinkpad T60/X60/Z60
AD1986A
6stack 6-jack, separate surrounds (default)
@@ -1633,9 +1638,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
About capture IBL, see the description of snd-vx222 module.
- Note: the driver is build only when CONFIG_ISA is set.
-
- Note2: snd-vxp440 driver is merged to snd-vxpocket driver since
+ Note: snd-vxp440 driver is merged to snd-vxpocket driver since
ALSA 1.0.10.
The power-management is supported.
@@ -1662,8 +1665,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
Module for Sound Core PDAudioCF sound card.
- Note: the driver is build only when CONFIG_ISA is set.
-
The power-management is supported.
diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
index 1faf763..635cbb9 100644
--- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
+++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
@@ -4215,7 +4215,7 @@ struct _snd_pcm_runtime {
<programlisting>
<![CDATA[
struct snd_rawmidi *rmidi;
- snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, port, integrated,
+ snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, port, info_flags,
irq, irq_flags, &rmidi);
]]>
</programlisting>
@@ -4242,15 +4242,36 @@ struct _snd_pcm_runtime {
</para>
<para>
+ The 5th argument is bitflags for additional information.
When the i/o port address above is a part of the PCI i/o
region, the MPU401 i/o port might have been already allocated
- (reserved) by the driver itself. In such a case, pass non-zero
- to the 5th argument
- (<parameter>integrated</parameter>). Otherwise, pass 0 to it,
+ (reserved) by the driver itself. In such a case, pass a bit flag
+ <constant>MPU401_INFO_INTEGRATED</constant>,
and
the mpu401-uart layer will allocate the i/o ports by itself.
</para>
+ <para>
+ When the controller supports only the input or output MIDI stream,
+ pass <constant>MPU401_INFO_INPUT</constant> or
+ <constant>MPU401_INFO_OUTPUT</constant> bitflag, respectively.
+ Then the rawmidi instance is created as a single stream.
+ </para>
+
+ <para>
+ <constant>MPU401_INFO_MMIO</constant> bitflag is used to change
+ the access method to MMIO (via readb and writeb) instead of
+ iob and outb. In this case, you have to pass the iomapped address
+ to <function>snd_mpu401_uart_new()</function>.
+ </para>
+
+ <para>
+ When <constant>MPU401_INFO_TX_IRQ</constant> is set, the output
+ stream isn't checked in the default interrupt handler. The driver
+ needs to call <function>snd_mpu401_uart_interrupt_tx()</function>
+ by itself to start processing the output stream in irq handler.
+ </para>
+
<para>
Usually, the port address corresponds to the command port and
port + 1 corresponds to the data port. If not, you may change
@@ -5333,7 +5354,7 @@ struct _snd_pcm_runtime {
<informalexample>
<programlisting>
<![CDATA[
- snd_info_set_text_ops(entry, chip, read_size, my_proc_read);
+ snd_info_set_text_ops(entry, chip, my_proc_read);
]]>
</programlisting>
</informalexample>
@@ -5394,7 +5415,6 @@ struct _snd_pcm_runtime {
<informalexample>
<programlisting>
<![CDATA[
- entry->c.text.write_size = 256;
entry->c.text.write = my_proc_write;
]]>
</programlisting>
@@ -5402,22 +5422,6 @@ struct _snd_pcm_runtime {
</para>
<para>
- The buffer size for read is set to 1024 implicitly by
- <function>snd_info_set_text_ops()</function>. It should suffice
- in most cases (the size will be aligned to
- <constant>PAGE_SIZE</constant> anyway), but if you need to handle
- very large text files, you can set it explicitly, too.
-
- <informalexample>
- <programlisting>
-<![CDATA[
- entry->c.text.read_size = 65536;
-]]>
- </programlisting>
- </informalexample>
- </para>
-
- <para>
For the write callback, you can use
<function>snd_info_get_line()</function> to get a text line, and
<function>snd_info_get_str()</function> to retrieve a string from
@@ -5562,7 +5566,7 @@ struct _snd_pcm_runtime {
power status.</para></listitem>
<listitem><para>Call <function>snd_pcm_suspend_all()</function> to suspend the running PCM streams.</para></listitem>
<listitem><para>If AC97 codecs are used, call
- <function>snd_ac97_resume()</function> for each codec.</para></listitem>
+ <function>snd_ac97_suspend()</function> for each codec.</para></listitem>
<listitem><para>Save the register values if necessary.</para></listitem>
<listitem><para>Stop the hardware if necessary.</para></listitem>
<listitem><para>Disable the PCI device by calling
diff --git a/Documentation/sparc/sbus_drivers.txt b/Documentation/sparc/sbus_drivers.txt
index 876195d..4b93516 100644
--- a/Documentation/sparc/sbus_drivers.txt
+++ b/Documentation/sparc/sbus_drivers.txt
@@ -25,42 +25,84 @@ the bits necessary to run your device. The most commonly
used members of this structure, and their typical usage,
will be detailed below.
- Here is how probing is performed by an SBUS driver
-under Linux:
+ Here is a piece of skeleton code for perofming a device
+probe in an SBUS driverunder Linux:
- static void init_one_mydevice(struct sbus_dev *sdev)
+ static int __devinit mydevice_probe_one(struct sbus_dev *sdev)
{
+ struct mysdevice *mp = kzalloc(sizeof(*mp), GFP_KERNEL);
+
+ if (!mp)
+ return -ENODEV;
+
+ ...
+ dev_set_drvdata(&sdev->ofdev.dev, mp);
+ return 0;
...
}
- static int mydevice_match(struct sbus_dev *sdev)
+ static int __devinit mydevice_probe(struct of_device *dev,
+ const struct of_device_id *match)
{
- if (some_criteria(sdev))
- return 1;
- return 0;
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+
+ return mydevice_probe_one(sdev);
}
- static void mydevice_probe(void)
+ static int __devexit mydevice_remove(struct of_device *dev)
{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev;
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+ struct mydevice *mp = dev_get_drvdata(&dev->dev);
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- if (mydevice_match(sdev))
- init_one_mydevice(sdev);
- }
- }
+ return mydevice_remove_one(sdev, mp);
}
- All this does is walk through all SBUS devices in the
-system, checks each to see if it is of the type which
-your driver is written for, and if so it calls the init
-routine to attach the device and prepare to drive it.
+ static struct of_device_id mydevice_match[] = {
+ {
+ .name = "mydevice",
+ },
+ {},
+ };
+
+ MODULE_DEVICE_TABLE(of, mydevice_match);
- "init_one_mydevice" might do things like allocate software
-state structures, map in I/O registers, place the hardware
-into an initialized state, etc.
+ static struct of_platform_driver mydevice_driver = {
+ .name = "mydevice",
+ .match_table = mydevice_match,
+ .probe = mydevice_probe,
+ .remove = __devexit_p(mydevice_remove),
+ };
+
+ static int __init mydevice_init(void)
+ {
+ return of_register_driver(&mydevice_driver, &sbus_bus_type);
+ }
+
+ static void __exit mydevice_exit(void)
+ {
+ of_unregister_driver(&mydevice_driver);
+ }
+
+ module_init(mydevice_init);
+ module_exit(mydevice_exit);
+
+ The mydevice_match table is a series of entries which
+describes what SBUS devices your driver is meant for. In the
+simplest case you specify a string for the 'name' field. Every
+SBUS device with a 'name' property matching your string will
+be passed one-by-one to your .probe method.
+
+ You should store away your device private state structure
+pointer in the drvdata area so that you can retrieve it later on
+in your .remove method.
+
+ Any memory allocated, registers mapped, IRQs registered,
+etc. must be undone by your .remove method so that all resources
+of your device are relased by the time it returns.
+
+ You should _NOT_ use the for_each_sbus(), for_each_sbusdev(),
+and for_all_sbusdev() interfaces. They are deprecated, will be
+removed, and no new driver should reference them ever.
Mapping and Accessing I/O Registers
@@ -263,10 +305,3 @@ discussed above and plus it handles both PCI and SBUS boards.
Lance driver abuses consistent mappings for data transfer.
It is a nifty trick which we do not particularly recommend...
Just check it out and know that it's legal.
-
- Bad examples, do NOT use
-
- drivers/video/cgsix.c
- This one uses result of sbus_ioremap as if it is an address.
-This does NOT work on sparc64 and therefore is broken. We will
-convert it at a later date.
diff --git a/Documentation/sparse.txt b/Documentation/sparse.txt
index 3f1c546..5a311c3 100644
--- a/Documentation/sparse.txt
+++ b/Documentation/sparse.txt
@@ -1,5 +1,6 @@
Copyright 2004 Linus Torvalds
Copyright 2004 Pavel Machek <pavel@suse.cz>
+Copyright 2006 Bob Copeland <me@bobcopeland.com>
Using sparse for typechecking
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -41,15 +42,8 @@ sure that bitwise types don't get mixed up (little-endian vs big-endian
vs cpu-endian vs whatever), and there the constant "0" really _is_
special.
-Use
-
- make C=[12] CF=-Wbitwise
-
-or you don't get any checking at all.
-
-
-Where to get sparse
-~~~~~~~~~~~~~~~~~~~
+Getting sparse
+~~~~~~~~~~~~~~
With git, you can just get it from
@@ -57,7 +51,7 @@ With git, you can just get it from
and DaveJ has tar-balls at
- http://www.codemonkey.org.uk/projects/git-snapshots/sparse/
+ http://www.codemonkey.org.uk/projects/git-snapshots/sparse/
Once you have it, just do
@@ -65,8 +59,20 @@ Once you have it, just do
make
make install
-as your regular user, and it will install sparse in your ~/bin directory.
-After that, doing a kernel make with "make C=1" will run sparse on all the
-C files that get recompiled, or with "make C=2" will run sparse on the
-files whether they need to be recompiled or not (ie the latter is fast way
-to check the whole tree if you have already built it).
+as a regular user, and it will install sparse in your ~/bin directory.
+
+Using sparse
+~~~~~~~~~~~~
+
+Do a kernel make with "make C=1" to run sparse on all the C files that get
+recompiled, or use "make C=2" to run sparse on the files whether they need to
+be recompiled or not. The latter is a fast way to check the whole tree if you
+have already built it.
+
+The optional make variable CF can be used to pass arguments to sparse. The
+build system passes -Wbitwise to sparse automatically. To perform endianness
+checks, you may define __CHECK_ENDIAN__:
+
+ make C=2 CF="-D__CHECK_ENDIAN__"
+
+These checks are disabled by default as they generate a host of warnings.
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index a46c10f..2dc246a 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -29,6 +29,7 @@ Currently, these files are in /proc/sys/vm:
- drop-caches
- zone_reclaim_mode
- zone_reclaim_interval
+- panic_on_oom
==============================================================
@@ -178,3 +179,15 @@ Time is set in seconds and set by default to 30 seconds.
Reduce the interval if undesired off node allocations occur. However, too
frequent scans will have a negative impact onoff node allocation performance.
+=============================================================
+
+panic_on_oom
+
+This enables or disables panic on out-of-memory feature. If this is set to 1,
+the kernel panics when out-of-memory happens. If this is set to 0, the kernel
+will kill some rogue process, called oom_killer. Usually, oom_killer can kill
+rogue processes and system will survive. If you want to panic the system
+rather than killing rogue processes, set this to 1.
+
+The default value is 0.
+
diff --git a/Documentation/sysrq.txt b/Documentation/sysrq.txt
index ad0bedf..e0188a2 100644
--- a/Documentation/sysrq.txt
+++ b/Documentation/sysrq.txt
@@ -115,8 +115,9 @@ trojan program is running at console and which could grab your password
when you would try to login. It will kill all programs on given console
and thus letting you make sure that the login prompt you see is actually
the one from init, not some trojan program.
-IMPORTANT:In its true form it is not a true SAK like the one in :IMPORTANT
-IMPORTANT:c2 compliant systems, and it should be mistook as such. :IMPORTANT
+IMPORTANT: In its true form it is not a true SAK like the one in a :IMPORTANT
+IMPORTANT: c2 compliant system, and it should not be mistaken as :IMPORTANT
+IMPORTANT: such. :IMPORTANT
It seems other find it useful as (System Attention Key) which is
useful when you want to exit a program that will not let you switch consoles.
(For example, X or a svgalib program.)
diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv
index b72706c..4efa464 100644
--- a/Documentation/video4linux/CARDLIST.bttv
+++ b/Documentation/video4linux/CARDLIST.bttv
@@ -87,7 +87,7 @@
86 -> Osprey 101/151 w/ svid
87 -> Osprey 200/201/250/251
88 -> Osprey 200/250 [0070:ff01]
- 89 -> Osprey 210/220
+ 89 -> Osprey 210/220/230
90 -> Osprey 500 [0070:ff02]
91 -> Osprey 540 [0070:ff04]
92 -> Osprey 2000 [0070:ff03]
@@ -111,7 +111,7 @@
110 -> IVC-100 [ff00:a132]
111 -> IVC-120G [ff00:a182,ff01:a182,ff02:a182,ff03:a182,ff04:a182,ff05:a182,ff06:a182,ff07:a182,ff08:a182,ff09:a182,ff0a:a182,ff0b:a182,ff0c:a182,ff0d:a182,ff0e:a182,ff0f:a182]
112 -> pcHDTV HD-2000 TV [7063:2000]
-113 -> Twinhan DST + clones [11bd:0026,1822:0001,270f:fc00]
+113 -> Twinhan DST + clones [11bd:0026,1822:0001,270f:fc00,1822:0026]
114 -> Winfast VC100 [107d:6607]
115 -> Teppro TEV-560/InterVision IV-560
116 -> SIMUS GVC1100 [aa6a:82b2]
diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
index 3b39a91..6cb63dd 100644
--- a/Documentation/video4linux/CARDLIST.cx88
+++ b/Documentation/video4linux/CARDLIST.cx88
@@ -15,7 +15,7 @@
14 -> KWorld/VStream XPert DVB-T [17de:08a6]
15 -> DViCO FusionHDTV DVB-T1 [18ac:db00]
16 -> KWorld LTV883RF
- 17 -> DViCO FusionHDTV 3 Gold-Q [18ac:d810]
+ 17 -> DViCO FusionHDTV 3 Gold-Q [18ac:d810,18ac:d800]
18 -> Hauppauge Nova-T DVB-T [0070:9002,0070:9001]
19 -> Conexant DVB-T reference design [14f1:0187]
20 -> Provideo PV259 [1540:2580]
@@ -40,8 +40,13 @@
39 -> KWorld DVB-S 100 [17de:08b2]
40 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid [0070:9400,0070:9402]
41 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile) [0070:9800,0070:9802]
- 42 -> digitalnow DNTV Live! DVB-T Pro [1822:0025]
+ 42 -> digitalnow DNTV Live! DVB-T Pro [1822:0025,1822:0019]
43 -> KWorld/VStream XPert DVB-T with cx22702 [17de:08a1]
44 -> DViCO FusionHDTV DVB-T Dual Digital [18ac:db50,18ac:db54]
45 -> KWorld HardwareMpegTV XPert [17de:0840]
46 -> DViCO FusionHDTV DVB-T Hybrid [18ac:db40,18ac:db44]
+ 47 -> pcHDTV HD5500 HDTV [7063:5500]
+ 48 -> Kworld MCE 200 Deluxe [17de:0841]
+ 49 -> PixelView PlayTV P7000 [1554:4813]
+ 50 -> NPG Tech Real TV FM Top 10 [14f1:0842]
+ 51 -> WinFast DTV2000 H [107d:665e]
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index bca5090..9068b66 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -93,3 +93,4 @@
92 -> AVerMedia A169 B1 [1461:6360]
93 -> Medion 7134 Bridge #2 [16be:0005]
94 -> LifeView FlyDVB-T Hybrid Cardbus [5168:3306,5168:3502]
+ 95 -> LifeView FlyVIDEO3000 (NTSC) [5169:0138]
diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner
index 1bcdac6..44134f0 100644
--- a/Documentation/video4linux/CARDLIST.tuner
+++ b/Documentation/video4linux/CARDLIST.tuner
@@ -62,7 +62,7 @@ tuner=60 - Thomson DTT 761X (ATSC/NTSC)
tuner=61 - Tena TNF9533-D/IF/TNF9533-B/DF
tuner=62 - Philips TEA5767HN FM Radio
tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner
-tuner=64 - LG TDVS-H062F/TUA6034
+tuner=64 - LG TDVS-H06xF
tuner=65 - Ymec TVF66T5-B/DFF
tuner=66 - LG TALN series
tuner=67 - Philips TD1316 Hybrid Tuner
@@ -71,3 +71,4 @@ tuner=69 - Tena TNF 5335 and similar models
tuner=70 - Samsung TCPN 2121P30A
tuner=71 - Xceive xc3028
tuner=72 - Thomson FE6600
+tuner=73 - Samsung TCPG 6121P30A
diff --git a/Documentation/video4linux/CQcam.txt b/Documentation/video4linux/CQcam.txt
index 464e4ce..ade8651 100644
--- a/Documentation/video4linux/CQcam.txt
+++ b/Documentation/video4linux/CQcam.txt
@@ -185,207 +185,10 @@ this work is documented at the video4linux2 site listed below.
9.0 --- A sample program using v4lgrabber,
-This program is a simple image grabber that will copy a frame from the
+v4lgrab is a simple image grabber that will copy a frame from the
first video device, /dev/video0 to standard output in portable pixmap
-format (.ppm) Using this like: 'v4lgrab | convert - c-qcam.jpg'
-produced this picture of me at
- http://mug.sys.virginia.edu/~drf5n/extras/c-qcam.jpg
-
--------------------- 8< ---------------- 8< -----------------------------
-
-/* Simple Video4Linux image grabber. */
-/*
- * Video4Linux Driver Test/Example Framegrabbing Program
- *
- * Compile with:
- * gcc -s -Wall -Wstrict-prototypes v4lgrab.c -o v4lgrab
- * Use as:
- * v4lgrab >image.ppm
- *
- * Copyright (C) 1998-05-03, Phil Blundell <philb@gnu.org>
- * Copied from http://www.tazenda.demon.co.uk/phil/vgrabber.c
- * with minor modifications (Dave Forrest, drf5n@virginia.edu).
- *
- */
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <sys/ioctl.h>
-#include <stdlib.h>
-
-#include <linux/types.h>
-#include <linux/videodev.h>
-
-#define FILE "/dev/video0"
-
-/* Stole this from tvset.c */
-
-#define READ_VIDEO_PIXEL(buf, format, depth, r, g, b) \
-{ \
- switch (format) \
- { \
- case VIDEO_PALETTE_GREY: \
- switch (depth) \
- { \
- case 4: \
- case 6: \
- case 8: \
- (r) = (g) = (b) = (*buf++ << 8);\
- break; \
- \
- case 16: \
- (r) = (g) = (b) = \
- *((unsigned short *) buf); \
- buf += 2; \
- break; \
- } \
- break; \
- \
- \
- case VIDEO_PALETTE_RGB565: \
- { \
- unsigned short tmp = *(unsigned short *)buf; \
- (r) = tmp&0xF800; \
- (g) = (tmp<<5)&0xFC00; \
- (b) = (tmp<<11)&0xF800; \
- buf += 2; \
- } \
- break; \
- \
- case VIDEO_PALETTE_RGB555: \
- (r) = (buf[0]&0xF8)<<8; \
- (g) = ((buf[0] << 5 | buf[1] >> 3)&0xF8)<<8; \
- (b) = ((buf[1] << 2 ) & 0xF8)<<8; \
- buf += 2; \
- break; \
- \
- case VIDEO_PALETTE_RGB24: \
- (r) = buf[0] << 8; (g) = buf[1] << 8; \
- (b) = buf[2] << 8; \
- buf += 3; \
- break; \
- \
- default: \
- fprintf(stderr, \
- "Format %d not yet supported\n", \
- format); \
- } \
-}
-
-int get_brightness_adj(unsigned char *image, long size, int *brightness) {
- long i, tot = 0;
- for (i=0;i<size*3;i++)
- tot += image[i];
- *brightness = (128 - tot/(size*3))/3;
- return !((tot/(size*3)) >= 126 && (tot/(size*3)) <= 130);
-}
-
-int main(int argc, char ** argv)
-{
- int fd = open(FILE, O_RDONLY), f;
- struct video_capability cap;
- struct video_window win;
- struct video_picture vpic;
-
- unsigned char *buffer, *src;
- int bpp = 24, r, g, b;
- unsigned int i, src_depth;
-
- if (fd < 0) {
- perror(FILE);
- exit(1);
- }
-
- if (ioctl(fd, VIDIOCGCAP, &cap) < 0) {
- perror("VIDIOGCAP");
- fprintf(stderr, "(" FILE " not a video4linux device?)\n");
- close(fd);
- exit(1);
- }
-
- if (ioctl(fd, VIDIOCGWIN, &win) < 0) {
- perror("VIDIOCGWIN");
- close(fd);
- exit(1);
- }
-
- if (ioctl(fd, VIDIOCGPICT, &vpic) < 0) {
- perror("VIDIOCGPICT");
- close(fd);
- exit(1);
- }
-
- if (cap.type & VID_TYPE_MONOCHROME) {
- vpic.depth=8;
- vpic.palette=VIDEO_PALETTE_GREY; /* 8bit grey */
- if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
- vpic.depth=6;
- if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
- vpic.depth=4;
- if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
- fprintf(stderr, "Unable to find a supported capture format.\n");
- close(fd);
- exit(1);
- }
- }
- }
- } else {
- vpic.depth=24;
- vpic.palette=VIDEO_PALETTE_RGB24;
-
- if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
- vpic.palette=VIDEO_PALETTE_RGB565;
- vpic.depth=16;
-
- if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
- vpic.palette=VIDEO_PALETTE_RGB555;
- vpic.depth=15;
-
- if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
- fprintf(stderr, "Unable to find a supported capture format.\n");
- return -1;
- }
- }
- }
- }
-
- buffer = malloc(win.width * win.height * bpp);
- if (!buffer) {
- fprintf(stderr, "Out of memory.\n");
- exit(1);
- }
-
- do {
- int newbright;
- read(fd, buffer, win.width * win.height * bpp);
- f = get_brightness_adj(buffer, win.width * win.height, &newbright);
- if (f) {
- vpic.brightness += (newbright << 8);
- if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
- perror("VIDIOSPICT");
- break;
- }
- }
- } while (f);
-
- fprintf(stdout, "P6\n%d %d 255\n", win.width, win.height);
-
- src = buffer;
-
- for (i = 0; i < win.width * win.height; i++) {
- READ_VIDEO_PIXEL(src, vpic.palette, src_depth, r, g, b);
- fputc(r>>8, stdout);
- fputc(g>>8, stdout);
- fputc(b>>8, stdout);
- }
-
- close(fd);
- return 0;
-}
--------------------- 8< ---------------- 8< -----------------------------
+format (.ppm) To produce .jpg output, you can use it like this:
+'v4lgrab | convert - c-qcam.jpg'
10.0 --- Other Information
diff --git a/Documentation/video4linux/Zoran b/Documentation/video4linux/Zoran
index be9f21b..040a2c8 100644
--- a/Documentation/video4linux/Zoran
+++ b/Documentation/video4linux/Zoran
@@ -33,6 +33,21 @@ Inputs/outputs: Composite and S-video
Norms: PAL, SECAM (720x576 @ 25 fps), NTSC (720x480 @ 29.97 fps)
Card number: 7
+AverMedia 6 Eyes AVS6EYES:
+* Zoran zr36067 PCI controller
+* Zoran zr36060 MJPEG codec
+* Samsung ks0127 TV decoder
+* Conexant bt866 TV encoder
+Drivers to use: videodev, i2c-core, i2c-algo-bit,
+ videocodec, ks0127, bt866, zr36060, zr36067
+Inputs/outputs: Six physical inputs. 1-6 are composite,
+ 1-2, 3-4, 5-6 doubles as S-video,
+ 1-3 triples as component.
+ One composite output.
+Norms: PAL, SECAM (720x576 @ 25 fps), NTSC (720x480 @ 29.97 fps)
+Card number: 8
+Not autodetected, card=8 is necessary.
+
Linux Media Labs LML33:
* Zoran zr36067 PCI controller
* Zoran zr36060 MJPEG codec
@@ -192,6 +207,10 @@ Micronas vpx3220a TV decoder
was introduced in 1996, is used in the DC30 and DC30+ and
can handle: PAL B/G/H/I, PAL N, PAL M, NTSC M, NTSC 44, PAL 60, SECAM,NTSC Comb
+Samsung ks0127 TV decoder
+is used in the AVS6EYES card and
+can handle: NTSC-M/N/44, PAL-M/N/B/G/H/I/D/K/L and SECAM
+
===========================
1.2 What the TV encoder can do an what not
@@ -221,6 +240,10 @@ ITT mse3000 TV encoder
was introduced in 1991, is used in the DC10 old
can generate: PAL , NTSC , SECAM
+Conexant bt866 TV encoder
+is used in AVS6EYES, and
+can generate: NTSC/PAL, PAL­M, PAL­N
+
The adv717x, should be able to produce PAL N. But you find nothing PAL N
specific in the registers. Seem that you have to reuse a other standard
to generate PAL N, maybe it would work if you use the PAL M settings.
diff --git a/Documentation/video4linux/bttv/CONTRIBUTORS b/Documentation/video4linux/bttv/CONTRIBUTORS
index aef49db..8aad6dd 100644
--- a/Documentation/video4linux/bttv/CONTRIBUTORS
+++ b/Documentation/video4linux/bttv/CONTRIBUTORS
@@ -1,4 +1,4 @@
-Contributors to bttv:
+Contributors to bttv:
Michael Chu <mmchu@pobox.com>
AverMedia fix and more flexible card recognition
@@ -8,8 +8,8 @@ Alan Cox <alan@redhat.com>
Chris Kleitsch
Hardware I2C
-
-Gerd Knorr <kraxel@cs.tu-berlin.de>
+
+Gerd Knorr <kraxel@cs.tu-berlin.de>
Radio card (ITT sound processor)
bigfoot <bigfoot@net-way.net>
@@ -18,7 +18,7 @@ Ragnar Hojland Espinosa <ragnar@macula.net>
+ many more (please mail me if you are missing in this list and would
- like to be mentioned)
+ like to be mentioned)
diff --git a/Documentation/video4linux/cx2341x/fw-calling.txt b/Documentation/video4linux/cx2341x/fw-calling.txt
new file mode 100644
index 0000000..8d21181
--- /dev/null
+++ b/Documentation/video4linux/cx2341x/fw-calling.txt
@@ -0,0 +1,69 @@
+This page describes how to make calls to the firmware api.
+
+How to call
+===========
+
+The preferred calling convention is known as the firmware mailbox. The
+mailboxes are basically a fixed length array that serves as the call-stack.
+
+Firmware mailboxes can be located by searching the encoder and decoder memory
+for a 16 byte signature. That signature will be located on a 256-byte boundary.
+
+Signature:
+0x78, 0x56, 0x34, 0x12, 0x12, 0x78, 0x56, 0x34,
+0x34, 0x12, 0x78, 0x56, 0x56, 0x34, 0x12, 0x78
+
+The firmware implements 20 mailboxes of 20 32-bit words. The first 10 are
+reserved for API calls. The second 10 are used by the firmware for event
+notification.
+
+ Index Name
+ ----- ----
+ 0 Flags
+ 1 Command
+ 2 Return value
+ 3 Timeout
+ 4-19 Parameter/Result
+
+
+The flags are defined in the following table. The direction is from the
+perspective of the firmware.
+
+ Bit Direction Purpose
+ --- --------- -------
+ 2 O Firmware has processed the command.
+ 1 I Driver has finished setting the parameters.
+ 0 I Driver is using this mailbox.
+
+
+The command is a 32-bit enumerator. The API specifics may be found in the
+fw-*-api.txt documents.
+
+The return value is a 32-bit enumerator. Only two values are currently defined:
+0=success and -1=command undefined.
+
+There are 16 parameters/results 32-bit fields. The driver populates these fields
+with values for all the parameters required by the call. The driver overwrites
+these fields with result values returned by the call. The API specifics may be
+found in the fw-*-api.txt documents.
+
+The timeout value protects the card from a hung driver thread. If the driver
+doesn't handle the completed call within the timeout specified, the firmware
+will reset that mailbox.
+
+To make an API call, the driver iterates over each mailbox looking for the
+first one available (bit 0 has been cleared). The driver sets that bit, fills
+in the command enumerator, the timeout value and any required parameters. The
+driver then sets the parameter ready bit (bit 1). The firmware scans the
+mailboxes for pending commands, processes them, sets the result code, populates
+the result value array with that call's return values and sets the call
+complete bit (bit 2). Once bit 2 is set, the driver should retrieve the results
+and clear all the flags. If the driver does not perform this task within the
+time set in the timeout register, the firmware will reset that mailbox.
+
+Event notifications are sent from the firmware to the host. The host tells the
+firmware which events it is interested in via an API call. That call tells the
+firmware which notification mailbox to use. The firmware signals the host via
+an interrupt. Only the 16 Results fields are used, the Flags, Command, Return
+value and Timeout words are not used.
+
diff --git a/Documentation/video4linux/cx2341x/fw-decoder-api.txt b/Documentation/video4linux/cx2341x/fw-decoder-api.txt
new file mode 100644
index 0000000..9df4fb3
--- /dev/null
+++ b/Documentation/video4linux/cx2341x/fw-decoder-api.txt
@@ -0,0 +1,319 @@
+Decoder firmware API description
+================================
+
+Note: this API is part of the decoder firmware, so it's cx23415 only.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_PING_FW
+Enum 0/0x00
+Description
+ This API call does nothing. It may be used to check if the firmware
+ is responding.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_START_PLAYBACK
+Enum 1/0x01
+Description
+ Begin or resume playback.
+Param[0]
+ 0 based frame number in GOP to begin playback from.
+Param[1]
+ Specifies the number of muted audio frames to play before normal
+ audio resumes.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_STOP_PLAYBACK
+Enum 2/0x02
+Description
+ Ends playback and clears all decoder buffers. If PTS is not zero,
+ playback stops at specified PTS.
+Param[0]
+ Display 0=last frame, 1=black
+Param[1]
+ PTS low
+Param[2]
+ PTS high
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_SET_PLAYBACK_SPEED
+Enum 3/0x03
+Description
+ Playback stream at speed other than normal. There are two modes of
+ operation:
+ Smooth: host transfers entire stream and firmware drops unused
+ frames.
+ Coarse: host drops frames based on indexing as required to achieve
+ desired speed.
+Param[0]
+ Bitmap:
+ 0:7 0 normal
+ 1 fast only "1.5 times"
+ n nX fast, 1/nX slow
+ 30 Framedrop:
+ '0' during 1.5 times play, every other B frame is dropped
+ '1' during 1.5 times play, stream is unchanged (bitrate
+ must not exceed 8mbps)
+ 31 Speed:
+ '0' slow
+ '1' fast
+Param[1]
+ Direction: 0=forward, 1=reverse
+Param[2]
+ Picture mask:
+ 1=I frames
+ 3=I, P frames
+ 7=I, P, B frames
+Param[3]
+ B frames per GOP (for reverse play only)
+Param[4]
+ Mute audio: 0=disable, 1=enable
+Param[5]
+ Display 0=frame, 1=field
+Param[6]
+ Specifies the number of muted audio frames to play before normal audio
+ resumes.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_STEP_VIDEO
+Enum 5/0x05
+Description
+ Each call to this API steps the playback to the next unit defined below
+ in the current playback direction.
+Param[0]
+ 0=frame, 1=top field, 2=bottom field
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_SET_DMA_BLOCK_SIZE
+Enum 8/0x08
+Description
+ Set DMA transfer block size. Counterpart to API 0xC9
+Param[0]
+ DMA transfer block size in bytes. A different size may be specified
+ when issuing the DMA transfer command.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_GET_XFER_INFO
+Enum 9/0x09
+Description
+ This API call may be used to detect an end of stream condtion.
+Result[0]
+ Stream type
+Result[1]
+ Address offset
+Result[2]
+ Maximum bytes to transfer
+Result[3]
+ Buffer fullness
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_GET_DMA_STATUS
+Enum 10/0x0A
+Description
+ Status of the last DMA transfer
+Result[0]
+ Bit 1 set means transfer complete
+ Bit 2 set means DMA error
+ Bit 3 set means linked list error
+Result[1]
+ DMA type: 0=MPEG, 1=OSD, 2=YUV
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_SCHED_DMA_FROM_HOST
+Enum 11/0x0B
+Description
+ Setup DMA from host operation. Counterpart to API 0xCC
+Param[0]
+ Memory address of link list
+Param[1]
+ Total # of bytes to transfer
+Param[2]
+ DMA type (0=MPEG, 1=OSD, 2=YUV)
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_PAUSE_PLAYBACK
+Enum 13/0x0D
+Description
+ Freeze playback immediately. In this mode, when internal buffers are
+ full, no more data will be accepted and data request IRQs will be
+ masked.
+Param[0]
+ Display: 0=last frame, 1=black
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_HALT_FW
+Enum 14/0x0E
+Description
+ The firmware is halted and no further API calls are serviced until
+ the firmware is uploaded again.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_SET_STANDARD
+Enum 16/0x10
+Description
+ Selects display standard
+Param[0]
+ 0=NTSC, 1=PAL
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_GET_VERSION
+Enum 17/0x11
+Description
+ Returns decoder firmware version information
+Result[0]
+ Version bitmask:
+ Bits 0:15 build
+ Bits 16:23 minor
+ Bits 24:31 major
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_SET_STREAM_INPUT
+Enum 20/0x14
+Description
+ Select decoder stream input port
+Param[0]
+ 0=memory (default), 1=streaming
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_GET_TIMING_INFO
+Enum 21/0x15
+Description
+ Returns timing information from start of playback
+Result[0]
+ Frame count by decode order
+Result[1]
+ Video PTS bits 0:31 by display order
+Result[2]
+ Video PTS bit 32 by display order
+Result[3]
+ SCR bits 0:31 by display order
+Result[4]
+ SCR bit 32 by display order
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_SET_AUDIO_MODE
+Enum 22/0x16
+Description
+ Select audio mode
+Param[0]
+ Dual mono mode action
+Param[1]
+ Stereo mode action:
+ 0=Stereo, 1=Left, 2=Right, 3=Mono, 4=Swap, -1=Unchanged
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_SET_EVENT_NOTIFICATION
+Enum 23/0x17
+Description
+ Setup firmware to notify the host about a particular event.
+ Counterpart to API 0xD5
+Param[0]
+ Event: 0=Audio mode change between stereo and dual channel
+Param[1]
+ Notification 0=disabled, 1=enabled
+Param[2]
+ Interrupt bit
+Param[3]
+ Mailbox slot, -1 if no mailbox required.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_SET_DISPLAY_BUFFERS
+Enum 24/0x18
+Description
+ Number of display buffers. To decode all frames in reverse playback you
+ must use nine buffers.
+Param[0]
+ 0=six buffers, 1=nine buffers
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_EXTRACT_VBI
+Enum 25/0x19
+Description
+ Extracts VBI data
+Param[0]
+ 0=extract from extension & user data, 1=extract from private packets
+Result[0]
+ VBI table location
+Result[1]
+ VBI table size
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_SET_DECODER_SOURCE
+Enum 26/0x1A
+Description
+ Selects decoder source. Ensure that the parameters passed to this
+ API match the encoder settings.
+Param[0]
+ Mode: 0=MPEG from host, 1=YUV from encoder, 2=YUV from host
+Param[1]
+ YUV picture width
+Param[2]
+ YUV picture height
+Param[3]
+ Bitmap: see Param[0] of API 0xBD
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_SET_AUDIO_OUTPUT
+Enum 27/0x1B
+Description
+ Select audio output format
+Param[0]
+ Bitmask:
+ 0:1 Data size:
+ '00' 16 bit
+ '01' 20 bit
+ '10' 24 bit
+ 2:7 Unused
+ 8:9 Mode:
+ '00' 2 channels
+ '01' 4 channels
+ '10' 6 channels
+ '11' 6 channels with one line data mode
+ (for left justified MSB first mode, 20 bit only)
+ 10:11 Unused
+ 12:13 Channel format:
+ '00' right justified MSB first mode
+ '01' left justified MSB first mode
+ '10' I2S mode
+ 14:15 Unused
+ 16:21 Right justify bit count
+ 22:31 Unused
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_SET_AV_DELAY
+Enum 28/0x1C
+Description
+ Set audio/video delay in 90Khz ticks
+Param[0]
+ 0=A/V in sync, negative=audio lags, positive=video lags
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_SET_PREBUFFERING
+Enum 30/0x1E
+Description
+ Decoder prebuffering, when enabled up to 128KB are buffered for
+ streams <8mpbs or 640KB for streams >8mbps
+Param[0]
+ 0=off, 1=on
diff --git a/Documentation/video4linux/cx2341x/fw-dma.txt b/Documentation/video4linux/cx2341x/fw-dma.txt
new file mode 100644
index 0000000..8123e26
--- /dev/null
+++ b/Documentation/video4linux/cx2341x/fw-dma.txt
@@ -0,0 +1,94 @@
+This page describes the structures and procedures used by the cx2341x DMA
+engine.
+
+Introduction
+============
+
+The cx2341x PCI interface is busmaster capable. This means it has a DMA
+engine to efficiently transfer large volumes of data between the card and main
+memory without requiring help from a CPU. Like most hardware, it must operate
+on contiguous physical memory. This is difficult to come by in large quantities
+on virtual memory machines.
+
+Therefore, it also supports a technique called "scatter-gather". The card can
+transfer multiple buffers in one operation. Instead of allocating one large
+contiguous buffer, the driver can allocate several smaller buffers.
+
+In practice, I've seen the average transfer to be roughly 80K, but transfers
+above 128K were not uncommon, particularly at startup. The 128K figure is
+important, because that is the largest block that the kernel can normally
+allocate. Even still, 128K blocks are hard to come by, so the driver writer is
+urged to choose a smaller block size and learn the scatter-gather technique.
+
+Mailbox #10 is reserved for DMA transfer information.
+
+Flow
+====
+
+This section describes, in general, the order of events when handling DMA
+transfers. Detailed information follows this section.
+
+- The card raises the Encoder interrupt.
+- The driver reads the transfer type, offset and size from Mailbox #10.
+- The driver constructs the scatter-gather array from enough free dma buffers
+ to cover the size.
+- The driver schedules the DMA transfer via the ScheduleDMAtoHost API call.
+- The card raises the DMA Complete interrupt.
+- The driver checks the DMA status register for any errors.
+- The driver post-processes the newly transferred buffers.
+
+NOTE! It is possible that the Encoder and DMA Complete interrupts get raised
+simultaneously. (End of the last, start of the next, etc.)
+
+Mailbox #10
+===========
+
+The Flags, Command, Return Value and Timeout fields are ignored.
+
+Name: Mailbox #10
+Results[0]: Type: 0: MPEG.
+Results[1]: Offset: The position relative to the card's memory space.
+Results[2]: Size: The exact number of bytes to transfer.
+
+My speculation is that since the StartCapture API has a capture type of "RAW"
+available, that the type field will have other values that correspond to YUV
+and PCM data.
+
+Scatter-Gather Array
+====================
+
+The scatter-gather array is a contiguously allocated block of memory that
+tells the card the source and destination of each data-block to transfer.
+Card "addresses" are derived from the offset supplied by Mailbox #10. Host
+addresses are the physical memory location of the target DMA buffer.
+
+Each S-G array element is a struct of three 32-bit words. The first word is
+the source address, the second is the destination address. Both take up the
+entire 32 bits. The lowest 16 bits of the third word is the transfer byte
+count. The high-bit of the third word is the "last" flag. The last-flag tells
+the card to raise the DMA_DONE interrupt. From hard personal experience, if
+you forget to set this bit, the card will still "work" but the stream will
+most likely get corrupted.
+
+The transfer count must be a multiple of 256. Therefore, the driver will need
+to track how much data in the target buffer is valid and deal with it
+accordingly.
+
+Array Element:
+
+- 32-bit Source Address
+- 32-bit Destination Address
+- 16-bit reserved (high bit is the last flag)
+- 16-bit byte count
+
+DMA Transfer Status
+===================
+
+Register 0x0004 holds the DMA Transfer Status:
+
+Bit
+4 Scatter-Gather array error
+3 DMA write error
+2 DMA read error
+1 write completed
+0 read completed
diff --git a/Documentation/video4linux/cx2341x/fw-encoder-api.txt b/Documentation/video4linux/cx2341x/fw-encoder-api.txt
new file mode 100644
index 0000000..001c686
--- /dev/null
+++ b/Documentation/video4linux/cx2341x/fw-encoder-api.txt
@@ -0,0 +1,694 @@
+Encoder firmware API description
+================================
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_PING_FW
+Enum 128/0x80
+Description
+ Does nothing. Can be used to check if the firmware is responding.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_START_CAPTURE
+Enum 129/0x81
+Description
+ Commences the capture of video, audio and/or VBI data. All encoding
+ parameters must be initialized prior to this API call. Captures frames
+ continuously or until a predefined number of frames have been captured.
+Param[0]
+ Capture stream type:
+ 0=MPEG
+ 1=Raw
+ 2=Raw passthrough
+ 3=VBI
+
+Param[1]
+ Bitmask:
+ Bit 0 when set, captures YUV
+ Bit 1 when set, captures PCM audio
+ Bit 2 when set, captures VBI (same as param[0]=3)
+ Bit 3 when set, the capture destination is the decoder
+ (same as param[0]=2)
+ Bit 4 when set, the capture destination is the host
+ Note: this parameter is only meaningful for RAW capture type.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_STOP_CAPTURE
+Enum 130/0x82
+Description
+ Ends a capture in progress
+Param[0]
+ 0=stop at end of GOP (generates IRQ)
+ 1=stop immediate (no IRQ)
+Param[1]
+ Stream type to stop, see param[0] of API 0x81
+Param[2]
+ Subtype, see param[1] of API 0x81
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_AUDIO_ID
+Enum 137/0x89
+Description
+ Assigns the transport stream ID of the encoded audio stream
+Param[0]
+ Audio Stream ID
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_VIDEO_ID
+Enum 139/0x8B
+Description
+ Set video transport stream ID
+Param[0]
+ Video stream ID
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_PCR_ID
+Enum 141/0x8D
+Description
+ Assigns the transport stream ID for PCR packets
+Param[0]
+ PCR Stream ID
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_FRAME_RATE
+Enum 143/0x8F
+Description
+ Set video frames per second. Change occurs at start of new GOP.
+Param[0]
+ 0=30fps
+ 1=25fps
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_FRAME_SIZE
+Enum 145/0x91
+Description
+ Select video stream encoding resolution.
+Param[0]
+ Height in lines. Default 480
+Param[1]
+ Width in pixels. Default 720
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_BIT_RATE
+Enum 149/0x95
+Description
+ Assign average video stream bitrate. Note on the last three params:
+ Param[3] and [4] seem to be always 0, param [5] doesn't seem to be used.
+Param[0]
+ 0=variable bitrate, 1=constant bitrate
+Param[1]
+ bitrate in bits per second
+Param[2]
+ peak bitrate in bits per second, divided by 400
+Param[3]
+ Mux bitrate in bits per second, divided by 400. May be 0 (default).
+Param[4]
+ Rate Control VBR Padding
+Param[5]
+ VBV Buffer used by encoder
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_GOP_PROPERTIES
+Enum 151/0x97
+Description
+ Setup the GOP structure
+Param[0]
+ GOP size (maximum is 34)
+Param[1]
+ Number of B frames between the I and P frame, plus 1.
+ For example: IBBPBBPBBPBB --> GOP size: 12, number of B frames: 2+1 = 3
+ Note that GOP size must be a multiple of (B-frames + 1).
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_ASPECT_RATIO
+Enum 153/0x99
+Description
+ Sets the encoding aspect ratio. Changes in the aspect ratio take effect
+ at the start of the next GOP.
+Param[0]
+ '0000' forbidden
+ '0001' 1:1 square
+ '0010' 4:3
+ '0011' 16:9
+ '0100' 2.21:1
+ '0101' reserved
+ ....
+ '1111' reserved
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_DNR_FILTER_MODE
+Enum 155/0x9B
+Description
+ Assign Dynamic Noise Reduction operating mode
+Param[0]
+ Bit0: Spatial filter, set=auto, clear=manual
+ Bit1: Temporal filter, set=auto, clear=manual
+Param[1]
+ Median filter:
+ 0=Disabled
+ 1=Horizontal
+ 2=Vertical
+ 3=Horiz/Vert
+ 4=Diagonal
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_DNR_FILTER_PROPS
+Enum 157/0x9D
+Description
+ These Dynamic Noise Reduction filter values are only meaningful when
+ the respective filter is set to "manual" (See API 0x9B)
+Param[0]
+ Spatial filter: default 0, range 0:15
+Param[1]
+ Temporal filter: default 0, range 0:31
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_CORING_LEVELS
+Enum 159/0x9F
+Description
+ Assign Dynamic Noise Reduction median filter properties.
+Param[0]
+ Threshold above which the luminance median filter is enabled.
+ Default: 0, range 0:255
+Param[1]
+ Threshold below which the luminance median filter is enabled.
+ Default: 255, range 0:255
+Param[2]
+ Threshold above which the chrominance median filter is enabled.
+ Default: 0, range 0:255
+Param[3]
+ Threshold below which the chrominance median filter is enabled.
+ Default: 255, range 0:255
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_SPATIAL_FILTER_TYPE
+Enum 161/0xA1
+Description
+ Assign spatial prefilter parameters
+Param[0]
+ Luminance filter
+ 0=Off
+ 1=1D Horizontal
+ 2=1D Vertical
+ 3=2D H/V Separable (default)
+ 4=2D Symmetric non-separable
+Param[1]
+ Chrominance filter
+ 0=Off
+ 1=1D Horizontal (default)
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_3_2_PULLDOWN
+Enum 177/0xB1
+Description
+ 3:2 pulldown properties
+Param[0]
+ 0=enabled
+ 1=disabled
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_VBI_LINE
+Enum 183/0xB7
+Description
+ Selects VBI line number.
+Param[0]
+ Bits 0:4 line number
+ Bit 31 0=top_field, 1=bottom_field
+ Bits 0:31 all set specifies "all lines"
+Param[1]
+ VBI line information features: 0=disabled, 1=enabled
+Param[2]
+ Slicing: 0=None, 1=Closed Caption
+ Almost certainly not implemented. Set to 0.
+Param[3]
+ Luminance samples in this line.
+ Almost certainly not implemented. Set to 0.
+Param[4]
+ Chrominance samples in this line
+ Almost certainly not implemented. Set to 0.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_STREAM_TYPE
+Enum 185/0xB9
+Description
+ Assign stream type
+ Note: Transport stream is not working in recent firmwares.
+ And in older firmwares the timestamps in the TS seem to be
+ unreliable.
+Param[0]
+ 0=Program stream
+ 1=Transport stream
+ 2=MPEG1 stream
+ 3=PES A/V stream
+ 5=PES Video stream
+ 7=PES Audio stream
+ 10=DVD stream
+ 11=VCD stream
+ 12=SVCD stream
+ 13=DVD_S1 stream
+ 14=DVD_S2 stream
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_OUTPUT_PORT
+Enum 187/0xBB
+Description
+ Assign stream output port. Normally 0 when the data is copied through
+ the PCI bus (DMA), and 1 when the data is streamed to another chip
+ (pvrusb and cx88-blackbird).
+Param[0]
+ 0=Memory (default)
+ 1=Streaming
+ 2=Serial
+Param[1]
+ Unknown, but leaving this to 0 seems to work best. Indications are that
+ this might have to do with USB support, although passing anything but 0
+ onl breaks things.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_AUDIO_PROPERTIES
+Enum 189/0xBD
+Description
+ Set audio stream properties, may be called while encoding is in progress.
+ Note: all bitfields are consistent with ISO11172 documentation except
+ bits 2:3 which ISO docs define as:
+ '11' Layer I
+ '10' Layer II
+ '01' Layer III
+ '00' Undefined
+ This discrepancy may indicate a possible error in the documentation.
+ Testing indicated that only Layer II is actually working, and that
+ the minimum bitrate should be 192 kbps.
+Param[0]
+ Bitmask:
+ 0:1 '00' 44.1Khz
+ '01' 48Khz
+ '10' 32Khz
+ '11' reserved
+
+ 2:3 '01'=Layer I
+ '10'=Layer II
+
+ 4:7 Bitrate:
+ Index | Layer I | Layer II
+ ------+-------------+------------
+ '0000' | free format | free format
+ '0001' | 32 kbit/s | 32 kbit/s
+ '0010' | 64 kbit/s | 48 kbit/s
+ '0011' | 96 kbit/s | 56 kbit/s
+ '0100' | 128 kbit/s | 64 kbit/s
+ '0101' | 160 kbit/s | 80 kbit/s
+ '0110' | 192 kbit/s | 96 kbit/s
+ '0111' | 224 kbit/s | 112 kbit/s
+ '1000' | 256 kbit/s | 128 kbit/s
+ '1001' | 288 kbit/s | 160 kbit/s
+ '1010' | 320 kbit/s | 192 kbit/s
+ '1011' | 352 kbit/s | 224 kbit/s
+ '1100' | 384 kbit/s | 256 kbit/s
+ '1101' | 416 kbit/s | 320 kbit/s
+ '1110' | 448 kbit/s | 384 kbit/s
+ Note: For Layer II, not all combinations of total bitrate
+ and mode are allowed. See ISO11172-3 3-Annex B, Table 3-B.2
+
+ 8:9 '00'=Stereo
+ '01'=JointStereo
+ '10'=Dual
+ '11'=Mono
+ Note: testing seems to indicate that Mono and possibly
+ JointStereo are not working (default to stereo).
+ Dual does work, though.
+
+ 10:11 Mode Extension used in joint_stereo mode.
+ In Layer I and II they indicate which subbands are in
+ intensity_stereo. All other subbands are coded in stereo.
+ '00' subbands 4-31 in intensity_stereo, bound==4
+ '01' subbands 8-31 in intensity_stereo, bound==8
+ '10' subbands 12-31 in intensity_stereo, bound==12
+ '11' subbands 16-31 in intensity_stereo, bound==16
+
+ 12:13 Emphasis:
+ '00' None
+ '01' 50/15uS
+ '10' reserved
+ '11' CCITT J.17
+
+ 14 CRC:
+ '0' off
+ '1' on
+
+ 15 Copyright:
+ '0' off
+ '1' on
+
+ 16 Generation:
+ '0' copy
+ '1' original
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_HALT_FW
+Enum 195/0xC3
+Description
+ The firmware is halted and no further API calls are serviced until the
+ firmware is uploaded again.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_GET_VERSION
+Enum 196/0xC4
+Description
+ Returns the version of the encoder firmware.
+Result[0]
+ Version bitmask:
+ Bits 0:15 build
+ Bits 16:23 minor
+ Bits 24:31 major
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_GOP_CLOSURE
+Enum 197/0xC5
+Description
+ Assigns the GOP open/close property.
+Param[0]
+ 0=Open
+ 1=Closed
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_GET_SEQ_END
+Enum 198/0xC6
+Description
+ Obtains the sequence end code of the encoder's buffer. When a capture
+ is started a number of interrupts are still generated, the last of
+ which will have Result[0] set to 1 and Result[1] will contain the size
+ of the buffer.
+Result[0]
+ State of the transfer (1 if last buffer)
+Result[1]
+ If Result[0] is 1, this contains the size of the last buffer, undefined
+ otherwise.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_PGM_INDEX_INFO
+Enum 199/0xC7
+Description
+ Sets the Program Index Information.
+Param[0]
+ Picture Mask:
+ 0=No index capture
+ 1=I frames
+ 3=I,P frames
+ 7=I,P,B frames
+Param[1]
+ Elements requested (up to 400)
+Result[0]
+ Offset in SDF memory of the table.
+Result[1]
+ Number of allocated elements up to a maximum of Param[1]
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_VBI_CONFIG
+Enum 200/0xC8
+Description
+ Configure VBI settings
+Param[0]
+ Bitmap:
+ 0 Mode '0' Sliced, '1' Raw
+ 1:3 Insertion:
+ '000' insert in extension & user data
+ '001' insert in private packets
+ '010' separate stream and user data
+ '111' separate stream and private data
+ 8:15 Stream ID (normally 0xBD)
+Param[1]
+ Frames per interrupt (max 8). Only valid in raw mode.
+Param[2]
+ Total raw VBI frames. Only valid in raw mode.
+Param[3]
+ Start codes
+Param[4]
+ Stop codes
+Param[5]
+ Lines per frame
+Param[6]
+ Byte per line
+Result[0]
+ Observed frames per interrupt in raw mode only. Rage 1 to Param[1]
+Result[1]
+ Observed number of frames in raw mode. Range 1 to Param[2]
+Result[2]
+ Memory offset to start or raw VBI data
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_DMA_BLOCK_SIZE
+Enum 201/0xC9
+Description
+ Set DMA transfer block size
+Param[0]
+ DMA transfer block size in bytes or frames. When unit is bytes,
+ supported block sizes are 2^7, 2^8 and 2^9 bytes.
+Param[1]
+ Unit: 0=bytes, 1=frames
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_GET_PREV_DMA_INFO_MB_10
+Enum 202/0xCA
+Description
+ Returns information on the previous DMA transfer in conjunction with
+ bit 27 of the interrupt mask. Uses mailbox 10.
+Result[0]
+ Type of stream
+Result[1]
+ Address Offset
+Result[2]
+ Maximum size of transfer
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_GET_PREV_DMA_INFO_MB_9
+Enum 203/0xCB
+Description
+ Returns information on the previous DMA transfer in conjunction with
+ bit 27 of the interrupt mask. Uses mailbox 9.
+Result[0]
+ Status bits:
+ Bit 0 set indicates transfer complete
+ Bit 2 set indicates transfer error
+ Bit 4 set indicates linked list error
+Result[1]
+ DMA type
+Result[2]
+ Presentation Time Stamp bits 0..31
+Result[3]
+ Presentation Time Stamp bit 32
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SCHED_DMA_TO_HOST
+Enum 204/0xCC
+Description
+ Setup DMA to host operation
+Param[0]
+ Memory address of link list
+Param[1]
+ Length of link list (wtf: what units ???)
+Param[2]
+ DMA type (0=MPEG)
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_INITIALIZE_INPUT
+Enum 205/0xCD
+Description
+ Initializes the video input
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_FRAME_DROP_RATE
+Enum 208/0xD0
+Description
+ For each frame captured, skip specified number of frames.
+Param[0]
+ Number of frames to skip
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_PAUSE_ENCODER
+Enum 210/0xD2
+Description
+ During a pause condition, all frames are dropped instead of being encoded.
+Param[0]
+ 0=Pause encoding
+ 1=Continue encoding
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_REFRESH_INPUT
+Enum 211/0xD3
+Description
+ Refreshes the video input
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_COPYRIGHT
+Enum 212/0xD4
+Description
+ Sets stream copyright property
+Param[0]
+ 0=Stream is not copyrighted
+ 1=Stream is copyrighted
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_EVENT_NOTIFICATION
+Enum 213/0xD5
+Description
+ Setup firmware to notify the host about a particular event. Host must
+ unmask the interrupt bit.
+Param[0]
+ Event (0=refresh encoder input)
+Param[1]
+ Notification 0=disabled 1=enabled
+Param[2]
+ Interrupt bit
+Param[3]
+ Mailbox slot, -1 if no mailbox required.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_NUM_VSYNC_LINES
+Enum 214/0xD6
+Description
+ Depending on the analog video decoder used, this assigns the number
+ of lines for field 1 and 2.
+Param[0]
+ Field 1 number of lines:
+ 0x00EF for SAA7114
+ 0x00F0 for SAA7115
+ 0x0105 for Micronas
+Param[1]
+ Field 2 number of lines:
+ 0x00EF for SAA7114
+ 0x00F0 for SAA7115
+ 0x0106 for Micronas
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_PLACEHOLDER
+Enum 215/0xD7
+Description
+ Provides a mechanism of inserting custom user data in the MPEG stream.
+Param[0]
+ 0=extension & user data
+ 1=private packet with stream ID 0xBD
+Param[1]
+ Rate at which to insert data, in units of frames (for private packet)
+ or GOPs (for ext. & user data)
+Param[2]
+ Number of data DWORDs (below) to insert
+Param[3]
+ Custom data 0
+Param[4]
+ Custom data 1
+Param[5]
+ Custom data 2
+Param[6]
+ Custom data 3
+Param[7]
+ Custom data 4
+Param[8]
+ Custom data 5
+Param[9]
+ Custom data 6
+Param[10]
+ Custom data 7
+Param[11]
+ Custom data 8
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_MUTE_VIDEO
+Enum 217/0xD9
+Description
+ Video muting
+Param[0]
+ Bit usage:
+ 0 '0'=video not muted
+ '1'=video muted, creates frames with the YUV color defined below
+ 1:7 Unused
+ 8:15 V chrominance information
+ 16:23 U chrominance information
+ 24:31 Y luminance information
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_MUTE_AUDIO
+Enum 218/0xDA
+Description
+ Audio muting
+Param[0]
+ 0=audio not muted
+ 1=audio muted (produces silent mpeg audio stream)
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_UNKNOWN
+Enum 219/0xDB
+Description
+ Unknown API, it's used by Hauppauge though.
+Param[0]
+ 0 This is the value Hauppauge uses, Unknown what it means.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_MISC
+Enum 220/0xDC
+Description
+ Miscellaneous actions. Not known for 100% what it does. It's really a
+ sort of ioctl call. The first parameter is a command number, the second
+ the value.
+Param[0]
+ Command number:
+ 1=set initial SCR value when starting encoding.
+ 2=set quality mode (apparently some test setting).
+ 3=setup advanced VIM protection handling (supposedly only for the cx23416
+ for raw YUV).
+ Actually it looks like this should be 0 for saa7114/5 based card and 1
+ for cx25840 based cards.
+ 4=generate artificial PTS timestamps
+ 5=USB flush mode
+ 6=something to do with the quantization matrix
+ 7=set navigation pack insertion for DVD
+ 8=enable scene change detection (seems to be a failure)
+ 9=set history parameters of the video input module
+ 10=set input field order of VIM
+ 11=set quantization matrix
+ 12=reset audio interface
+ 13=set audio volume delay
+ 14=set audio delay
+
+Param[1]
+ Command value.
diff --git a/Documentation/video4linux/cx2341x/fw-memory.txt b/Documentation/video4linux/cx2341x/fw-memory.txt
new file mode 100644
index 0000000..ef0aad3
--- /dev/null
+++ b/Documentation/video4linux/cx2341x/fw-memory.txt
@@ -0,0 +1,141 @@
+This document describes the cx2341x memory map and documents some of the register
+space.
+
+Warning! This information was figured out from searching through the memory and
+registers, this information may not be correct and is certainly not complete, and
+was not derived from anything more than searching through the memory space with
+commands like:
+
+ ivtvctl -O min=0x02000000,max=0x020000ff
+
+So take this as is, I'm always searching for more stuff, it's a large
+register space :-).
+
+Memory Map
+==========
+
+The cx2341x exposes its entire 64M memory space to the PCI host via the PCI BAR0
+(Base Address Register 0). The addresses here are offsets relative to the
+address held in BAR0.
+
+0x00000000-0x00ffffff Encoder memory space
+0x00000000-0x0003ffff Encode.rom
+ ???-??? MPEG buffer(s)
+ ???-??? Raw video capture buffer(s)
+ ???-??? Raw audio capture buffer(s)
+ ???-??? Display buffers (6 or 9)
+
+0x01000000-0x01ffffff Decoder memory space
+0x01000000-0x0103ffff Decode.rom
+ ???-??? MPEG buffers(s)
+0x0114b000-0x0115afff Audio.rom (deprecated?)
+
+0x02000000-0x0200ffff Register Space
+
+Registers
+=========
+
+The registers occupy the 64k space starting at the 0x02000000 offset from BAR0.
+All of these registers are 32 bits wide.
+
+DMA Registers 0x000-0xff:
+
+ 0x00 - Control:
+ 0=reset/cancel, 1=read, 2=write, 4=stop
+ 0x04 - DMA status:
+ 1=read busy, 2=write busy, 4=read error, 8=write error, 16=link list error
+ 0x08 - pci DMA pointer for read link list
+ 0x0c - pci DMA pointer for write link list
+ 0x10 - read/write DMA enable:
+ 1=read enable, 2=write enable
+ 0x14 - always 0xffffffff, if set any lower instability occurs, 0x00 crashes
+ 0x18 - ??
+ 0x1c - always 0x20 or 32, smaller values slow down DMA transactions
+ 0x20 - always value of 0x780a010a
+ 0x24-0x3c - usually just random values???
+ 0x40 - Interrupt status
+ 0x44 - Write a bit here and shows up in Interrupt status 0x40
+ 0x48 - Interrupt Mask
+ 0x4C - always value of 0xfffdffff,
+ if changed to 0xffffffff DMA write interrupts break.
+ 0x50 - always 0xffffffff
+ 0x54 - always 0xffffffff (0x4c, 0x50, 0x54 seem like interrupt masks, are
+ 3 processors on chip, Java ones, VPU, SPU, APU, maybe these are the
+ interrupt masks???).
+ 0x60-0x7C - random values
+ 0x80 - first write linked list reg, for Encoder Memory addr
+ 0x84 - first write linked list reg, for pci memory addr
+ 0x88 - first write linked list reg, for length of buffer in memory addr
+ (|0x80000000 or this for last link)
+ 0x8c-0xcc - rest of write linked list reg, 8 sets of 3 total, DMA goes here
+ from linked list addr in reg 0x0c, firmware must push through or
+ something.
+ 0xe0 - first (and only) read linked list reg, for pci memory addr
+ 0xe4 - first (and only) read linked list reg, for Decoder memory addr
+ 0xe8 - first (and only) read linked list reg, for length of buffer
+ 0xec-0xff - Nothing seems to be in these registers, 0xec-f4 are 0x00000000.
+
+Memory locations for Encoder Buffers 0x700-0x7ff:
+
+These registers show offsets of memory locations pertaining to each
+buffer area used for encoding, have to shift them by <<1 first.
+
+0x07F8: Encoder SDRAM refresh
+0x07FC: Encoder SDRAM pre-charge
+
+Memory locations for Decoder Buffers 0x800-0x8ff:
+
+These registers show offsets of memory locations pertaining to each
+buffer area used for decoding, have to shift them by <<1 first.
+
+0x08F8: Decoder SDRAM refresh
+0x08FC: Decoder SDRAM pre-charge
+
+Other memory locations:
+
+0x2800: Video Display Module control
+0x2D00: AO (audio output?) control
+0x2D24: Bytes Flushed
+0x7000: LSB I2C write clock bit (inverted)
+0x7004: LSB I2C write data bit (inverted)
+0x7008: LSB I2C read clock bit
+0x700c: LSB I2C read data bit
+0x9008: GPIO get input state
+0x900c: GPIO set output state
+0x9020: GPIO direction (Bit7 (GPIO 0..7) - 0:input, 1:output)
+0x9050: SPU control
+0x9054: Reset HW blocks
+0x9058: VPU control
+0xA018: Bit6: interrupt pending?
+0xA064: APU command
+
+
+Interrupt Status Register
+=========================
+
+The definition of the bits in the interrupt status register 0x0040, and the
+interrupt mask 0x0048. If a bit is cleared in the mask, then we want our ISR to
+execute.
+
+Bit
+31 Encoder Start Capture
+30 Encoder EOS
+29 Encoder VBI capture
+28 Encoder Video Input Module reset event
+27 Encoder DMA complete
+26
+25 Decoder copy protect detection event
+24 Decoder audio mode change detection event
+23
+22 Decoder data request
+21 Decoder I-Frame? done
+20 Decoder DMA complete
+19 Decoder VBI re-insertion
+18 Decoder DMA err (linked-list bad)
+
+Missing
+Encoder API call completed
+Decoder API call completed
+Encoder API post(?)
+Decoder API post(?)
+Decoder VTRACE event
diff --git a/Documentation/video4linux/cx2341x/fw-osd-api.txt b/Documentation/video4linux/cx2341x/fw-osd-api.txt
new file mode 100644
index 0000000..da98ae3
--- /dev/null
+++ b/Documentation/video4linux/cx2341x/fw-osd-api.txt
@@ -0,0 +1,342 @@
+OSD firmware API description
+============================
+
+Note: this API is part of the decoder firmware, so it's cx23415 only.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_GET_FRAMEBUFFER
+Enum 65/0x41
+Description
+ Return base and length of contiguous OSD memory.
+Result[0]
+ OSD base address
+Result[1]
+ OSD length
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_GET_PIXEL_FORMAT
+Enum 66/0x42
+Description
+ Query OSD format
+Result[0]
+ 0=8bit index, 4=AlphaRGB 8:8:8:8
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_SET_PIXEL_FORMAT
+Enum 67/0x43
+Description
+ Assign pixel format
+Param[0]
+ 0=8bit index, 4=AlphaRGB 8:8:8:8
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_GET_STATE
+Enum 68/0x44
+Description
+ Query OSD state
+Result[0]
+ Bit 0 0=off, 1=on
+ Bits 1:2 alpha control
+ Bits 3:5 pixel format
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_SET_STATE
+Enum 69/0x45
+Description
+ OSD switch
+Param[0]
+ 0=off, 1=on
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_GET_OSD_COORDS
+Enum 70/0x46
+Description
+ Retrieve coordinates of OSD area blended with video
+Result[0]
+ OSD buffer address
+Result[1]
+ Stride in pixels
+Result[2]
+ Lines in OSD buffer
+Result[3]
+ Horizontal offset in buffer
+Result[4]
+ Vertical offset in buffer
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_SET_OSD_COORDS
+Enum 71/0x47
+Description
+ Assign the coordinates of the OSD area to blend with video
+Param[0]
+ buffer address
+Param[1]
+ buffer stride in pixels
+Param[2]
+ lines in buffer
+Param[3]
+ horizontal offset
+Param[4]
+ vertical offset
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_GET_SCREEN_COORDS
+Enum 72/0x48
+Description
+ Retrieve OSD screen area coordinates
+Result[0]
+ top left horizontal offset
+Result[1]
+ top left vertical offset
+Result[2]
+ bottom right hotizontal offset
+Result[3]
+ bottom right vertical offset
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_SET_SCREEN_COORDS
+Enum 73/0x49
+Description
+ Assign the coordinates of the screen area to blend with video
+Param[0]
+ top left horizontal offset
+Param[1]
+ top left vertical offset
+Param[2]
+ bottom left horizontal offset
+Param[3]
+ bottom left vertical offset
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_GET_GLOBAL_ALPHA
+Enum 74/0x4A
+Description
+ Retrieve OSD global alpha
+Result[0]
+ global alpha: 0=off, 1=on
+Result[1]
+ bits 0:7 global alpha
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_SET_GLOBAL_ALPHA
+Enum 75/0x4B
+Description
+ Update global alpha
+Param[0]
+ global alpha: 0=off, 1=on
+Param[1]
+ global alpha (8 bits)
+Param[2]
+ local alpha: 0=on, 1=off
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_SET_BLEND_COORDS
+Enum 78/0x4C
+Description
+ Move start of blending area within display buffer
+Param[0]
+ horizontal offset in buffer
+Param[1]
+ vertical offset in buffer
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_GET_FLICKER_STATE
+Enum 79/0x4F
+Description
+ Retrieve flicker reduction module state
+Result[0]
+ flicker state: 0=off, 1=on
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_SET_FLICKER_STATE
+Enum 80/0x50
+Description
+ Set flicker reduction module state
+Param[0]
+ State: 0=off, 1=on
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_BLT_COPY
+Enum 82/0x52
+Description
+ BLT copy
+Param[0]
+'0000' zero
+'0001' ~destination AND ~source
+'0010' ~destination AND source
+'0011' ~destination
+'0100' destination AND ~source
+'0101' ~source
+'0110' destination XOR source
+'0111' ~destination OR ~source
+'1000' ~destination AND ~source
+'1001' destination XNOR source
+'1010' source
+'1011' ~destination OR source
+'1100' destination
+'1101' destination OR ~source
+'1110' destination OR source
+'1111' one
+
+Param[1]
+ Resulting alpha blending
+ '01' source_alpha
+ '10' destination_alpha
+ '11' source_alpha*destination_alpha+1
+ (zero if both source and destination alpha are zero)
+Param[2]
+ '00' output_pixel = source_pixel
+
+ '01' if source_alpha=0:
+ output_pixel = destination_pixel
+ if 256 > source_alpha > 1:
+ output_pixel = ((source_alpha + 1)*source_pixel +
+ (255 - source_alpha)*destination_pixel)/256
+
+ '10' if destination_alpha=0:
+ output_pixel = source_pixel
+ if 255 > destination_alpha > 0:
+ output_pixel = ((255 - destination_alpha)*source_pixel +
+ (destination_alpha + 1)*destination_pixel)/256
+
+ '11' if source_alpha=0:
+ source_temp = 0
+ if source_alpha=255:
+ source_temp = source_pixel*256
+ if 255 > source_alpha > 0:
+ source_temp = source_pixel*(source_alpha + 1)
+ if destination_alpha=0:
+ destination_temp = 0
+ if destination_alpha=255:
+ destination_temp = destination_pixel*256
+ if 255 > destination_alpha > 0:
+ destination_temp = destination_pixel*(destination_alpha + 1)
+ output_pixel = (source_temp + destination_temp)/256
+Param[3]
+ width
+Param[4]
+ height
+Param[5]
+ destination pixel mask
+Param[6]
+ destination rectangle start address
+Param[7]
+ destination stride in dwords
+Param[8]
+ source stride in dwords
+Param[9]
+ source rectangle start address
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_BLT_FILL
+Enum 83/0x53
+Description
+ BLT fill color
+Param[0]
+ Same as Param[0] on API 0x52
+Param[1]
+ Same as Param[1] on API 0x52
+Param[2]
+ Same as Param[2] on API 0x52
+Param[3]
+ width
+Param[4]
+ height
+Param[5]
+ destination pixel mask
+Param[6]
+ destination rectangle start address
+Param[7]
+ destination stride in dwords
+Param[8]
+ color fill value
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_BLT_TEXT
+Enum 84/0x54
+Description
+ BLT for 8 bit alpha text source
+Param[0]
+ Same as Param[0] on API 0x52
+Param[1]
+ Same as Param[1] on API 0x52
+Param[2]
+ Same as Param[2] on API 0x52
+Param[3]
+ width
+Param[4]
+ height
+Param[5]
+ destination pixel mask
+Param[6]
+ destination rectangle start address
+Param[7]
+ destination stride in dwords
+Param[8]
+ source stride in dwords
+Param[9]
+ source rectangle start address
+Param[10]
+ color fill value
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_SET_FRAMEBUFFER_WINDOW
+Enum 86/0x56
+Description
+ Positions the main output window on the screen. The coordinates must be
+ such that the entire window fits on the screen.
+Param[0]
+ window width
+Param[1]
+ window height
+Param[2]
+ top left window corner horizontal offset
+Param[3]
+ top left window corner vertical offset
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_SET_CHROMA_KEY
+Enum 96/0x60
+Description
+ Chroma key switch and color
+Param[0]
+ state: 0=off, 1=on
+Param[1]
+ color
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_GET_ALPHA_CONTENT_INDEX
+Enum 97/0x61
+Description
+ Retrieve alpha content index
+Result[0]
+ alpha content index, Range 0:15
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_SET_ALPHA_CONTENT_INDEX
+Enum 98/0x62
+Description
+ Assign alpha content index
+Param[0]
+ alpha content index, range 0:15
diff --git a/Documentation/video4linux/cx2341x/fw-upload.txt b/Documentation/video4linux/cx2341x/fw-upload.txt
new file mode 100644
index 0000000..60c502c
--- /dev/null
+++ b/Documentation/video4linux/cx2341x/fw-upload.txt
@@ -0,0 +1,49 @@
+This document describes how to upload the cx2341x firmware to the card.
+
+How to find
+===========
+
+See the web pages of the various projects that uses this chip for information
+on how to obtain the firmware.
+
+The firmware stored in a Windows driver can be detected as follows:
+
+- Each firmware image is 256k bytes.
+- The 1st 32-bit word of the Encoder image is 0x0000da7
+- The 1st 32-bit word of the Decoder image is 0x00003a7
+- The 2nd 32-bit word of both images is 0xaa55bb66
+
+How to load
+===========
+
+- Issue the FWapi command to stop the encoder if it is running. Wait for the
+ command to complete.
+- Issue the FWapi command to stop the decoder if it is running. Wait for the
+ command to complete.
+- Issue the I2C command to the digitizer to stop emitting VSYNC events.
+- Issue the FWapi command to halt the encoder's firmware.
+- Sleep for 10ms.
+- Issue the FWapi command to halt the decoder's firmware.
+- Sleep for 10ms.
+- Write 0x00000000 to register 0x2800 to stop the Video Display Module.
+- Write 0x00000005 to register 0x2D00 to stop the AO (audio output?).
+- Write 0x00000000 to register 0xA064 to ping? the APU.
+- Write 0xFFFFFFFE to register 0x9058 to stop the VPU.
+- Write 0xFFFFFFFF to register 0x9054 to reset the HW blocks.
+- Write 0x00000001 to register 0x9050 to stop the SPU.
+- Sleep for 10ms.
+- Write 0x0000001A to register 0x07FC to init the Encoder SDRAM's pre-charge.
+- Write 0x80000640 to register 0x07F8 to init the Encoder SDRAM's refresh to 1us.
+- Write 0x0000001A to register 0x08FC to init the Decoder SDRAM's pre-charge.
+- Write 0x80000640 to register 0x08F8 to init the Decoder SDRAM's refresh to 1us.
+- Sleep for 512ms. (600ms is recommended)
+- Transfer the encoder's firmware image to offset 0 in Encoder memory space.
+- Transfer the decoder's firmware image to offset 0 in Decoder memory space.
+- Use a read-modify-write operation to Clear bit 0 of register 0x9050 to
+ re-enable the SPU.
+- Sleep for 1 second.
+- Use a read-modify-write operation to Clear bits 3 and 0 of register 0x9058
+ to re-enable the VPU.
+- Sleep for 1 second.
+- Issue status API commands to both firmware images to verify.
+
diff --git a/Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt b/Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt
new file mode 100644
index 0000000..93fec32
--- /dev/null
+++ b/Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt
@@ -0,0 +1,54 @@
+The controls for the mux are GPIO [0,1] for source, and GPIO 2 for muting.
+
+GPIO0 GPIO1
+ 0 0 TV Audio
+ 1 0 FM radio
+ 0 1 Line-In
+ 1 1 Mono tuner bypass or CD passthru (tuner specific)
+
+GPIO 16(i believe) is tied to the IR port (if present).
+
+------------------------------------------------------------------------------------
+
+>From the data sheet:
+ Register 24'h20004 PCI Interrupt Status
+ bit [18] IR_SMP_INT Set when 32 input samples have been collected over
+ gpio[16] pin into GP_SAMPLE register.
+
+What's missing from the data sheet:
+
+Setup 4KHz sampling rate (roughly 2x oversampled; good enough for our RC5
+compat remote)
+set register 0x35C050 to 0xa80a80
+
+enable sampling
+set register 0x35C054 to 0x5
+
+Of course, enable the IRQ bit 18 in the interrupt mask register .(and
+provide for a handler)
+
+GP_SAMPLE register is at 0x35C058
+
+Bits are then right shifted into the GP_SAMPLE register at the specified
+rate; you get an interrupt when a full DWORD is recieved.
+You need to recover the actual RC5 bits out of the (oversampled) IR sensor
+bits. (Hint: look for the 0/1and 1/0 crossings of the RC5 bi-phase data) An
+actual raw RC5 code will span 2-3 DWORDS, depending on the actual alignment.
+
+I'm pretty sure when no IR signal is present the receiver is always in a
+marking state(1); but stray light, etc can cause intermittent noise values
+as well. Remember, this is a free running sample of the IR receiver state
+over time, so don't assume any sample starts at any particular place.
+
+http://www.atmel.com/dyn/resources/prod_documents/doc2817.pdf
+This data sheet (google search) seems to have a lovely description of the
+RC5 basics
+
+http://users.pandora.be/nenya/electronics/rc5/ and more data
+
+http://www.ee.washington.edu/circuit_archive/text/ir_decode.txt
+and even a reference to how to decode a bi-phase data stream.
+
+http://www.xs4all.nl/~sbp/knowledge/ir/rc5.htm
+still more info
+
diff --git a/Documentation/video4linux/et61x251.txt b/Documentation/video4linux/et61x251.txt
index 2934028..cd584f2 100644
--- a/Documentation/video4linux/et61x251.txt
+++ b/Documentation/video4linux/et61x251.txt
@@ -1,9 +1,9 @@
- ET61X[12]51 PC Camera Controllers
- Driver for Linux
- =================================
+ ET61X[12]51 PC Camera Controllers
+ Driver for Linux
+ =================================
- - Documentation -
+ - Documentation -
Index
@@ -156,46 +156,46 @@ Name: video_nr
Type: short array (min = 0, max = 64)
Syntax: <-1|n[,...]>
Description: Specify V4L2 minor mode number:
- -1 = use next available
- n = use minor number n
- You can specify up to 64 cameras this way.
- For example:
- video_nr=-1,2,-1 would assign minor number 2 to the second
- registered camera and use auto for the first one and for every
- other camera.
+ -1 = use next available
+ n = use minor number n
+ You can specify up to 64 cameras this way.
+ For example:
+ video_nr=-1,2,-1 would assign minor number 2 to the second
+ registered camera and use auto for the first one and for every
+ other camera.
Default: -1
-------------------------------------------------------------------------------
Name: force_munmap
Type: bool array (min = 0, max = 64)
Syntax: <0|1[,...]>
Description: Force the application to unmap previously mapped buffer memory
- before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
- all the applications support this feature. This parameter is
- specific for each detected camera.
- 0 = do not force memory unmapping
- 1 = force memory unmapping (save memory)
+ before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
+ all the applications support this feature. This parameter is
+ specific for each detected camera.
+ 0 = do not force memory unmapping
+ 1 = force memory unmapping (save memory)
Default: 0
-------------------------------------------------------------------------------
Name: frame_timeout
Type: uint array (min = 0, max = 64)
Syntax: <n[,...]>
Description: Timeout for a video frame in seconds. This parameter is
- specific for each detected camera. This parameter can be
- changed at runtime thanks to the /sys filesystem interface.
+ specific for each detected camera. This parameter can be
+ changed at runtime thanks to the /sys filesystem interface.
Default: 2
-------------------------------------------------------------------------------
Name: debug
Type: ushort
Syntax: <n>
Description: Debugging information level, from 0 to 3:
- 0 = none (use carefully)
- 1 = critical errors
- 2 = significant informations
- 3 = more verbose messages
- Level 3 is useful for testing only, when only one device
- is used at the same time. It also shows some more informations
- about the hardware being detected. This module parameter can be
- changed at runtime thanks to the /sys filesystem interface.
+ 0 = none (use carefully)
+ 1 = critical errors
+ 2 = significant informations
+ 3 = more verbose messages
+ Level 3 is useful for testing only, when only one device
+ is used at the same time. It also shows some more informations
+ about the hardware being detected. This module parameter can be
+ changed at runtime thanks to the /sys filesystem interface.
Default: 2
-------------------------------------------------------------------------------
diff --git a/Documentation/video4linux/ibmcam.txt b/Documentation/video4linux/ibmcam.txt
index 4a40a2e..397a94e 100644
--- a/Documentation/video4linux/ibmcam.txt
+++ b/Documentation/video4linux/ibmcam.txt
@@ -21,7 +21,7 @@ Internal interface: Video For Linux (V4L)
Supported controls:
- by V4L: Contrast, Brightness, Color, Hue
- by driver options: frame rate, lighting conditions, video format,
- default picture settings, sharpness.
+ default picture settings, sharpness.
SUPPORTED CAMERAS:
@@ -191,66 +191,66 @@ init_model2_sat Integer 0..255 [0x34] init_model2_sat=65
init_model2_yb Integer 0..255 [0xa0] init_model2_yb=200
debug You don't need this option unless you are a developer.
- If you are a developer then you will see in the code
- what values do what. 0=off.
+ If you are a developer then you will see in the code
+ what values do what. 0=off.
flags This is a bit mask, and you can combine any number of
- bits to produce what you want. Usually you don't want
- any of extra features this option provides:
-
- FLAGS_RETRY_VIDIOCSYNC 1 This bit allows to retry failed
- VIDIOCSYNC ioctls without failing.
- Will work with xawtv, will not
- with xrealproducer. Default is
- not set.
- FLAGS_MONOCHROME 2 Activates monochrome (b/w) mode.
- FLAGS_DISPLAY_HINTS 4 Shows colored pixels which have
- magic meaning to developers.
- FLAGS_OVERLAY_STATS 8 Shows tiny numbers on screen,
- useful only for debugging.
- FLAGS_FORCE_TESTPATTERN 16 Shows blue screen with numbers.
- FLAGS_SEPARATE_FRAMES 32 Shows each frame separately, as
- it was received from the camera.
- Default (not set) is to mix the
- preceding frame in to compensate
- for occasional loss of Isoc data
- on high frame rates.
- FLAGS_CLEAN_FRAMES 64 Forces "cleanup" of each frame
- prior to use; relevant only if
- FLAGS_SEPARATE_FRAMES is set.
- Default is not to clean frames,
- this is a little faster but may
- produce flicker if frame rate is
- too high and Isoc data gets lost.
- FLAGS_NO_DECODING 128 This flag turns the video stream
- decoder off, and dumps the raw
- Isoc data from the camera into
- the reading process. Useful to
- developers, but not to users.
+ bits to produce what you want. Usually you don't want
+ any of extra features this option provides:
+
+ FLAGS_RETRY_VIDIOCSYNC 1 This bit allows to retry failed
+ VIDIOCSYNC ioctls without failing.
+ Will work with xawtv, will not
+ with xrealproducer. Default is
+ not set.
+ FLAGS_MONOCHROME 2 Activates monochrome (b/w) mode.
+ FLAGS_DISPLAY_HINTS 4 Shows colored pixels which have
+ magic meaning to developers.
+ FLAGS_OVERLAY_STATS 8 Shows tiny numbers on screen,
+ useful only for debugging.
+ FLAGS_FORCE_TESTPATTERN 16 Shows blue screen with numbers.
+ FLAGS_SEPARATE_FRAMES 32 Shows each frame separately, as
+ it was received from the camera.
+ Default (not set) is to mix the
+ preceding frame in to compensate
+ for occasional loss of Isoc data
+ on high frame rates.
+ FLAGS_CLEAN_FRAMES 64 Forces "cleanup" of each frame
+ prior to use; relevant only if
+ FLAGS_SEPARATE_FRAMES is set.
+ Default is not to clean frames,
+ this is a little faster but may
+ produce flicker if frame rate is
+ too high and Isoc data gets lost.
+ FLAGS_NO_DECODING 128 This flag turns the video stream
+ decoder off, and dumps the raw
+ Isoc data from the camera into
+ the reading process. Useful to
+ developers, but not to users.
framerate This setting controls frame rate of the camera. This is
- an approximate setting (in terms of "worst" ... "best")
- because camera changes frame rate depending on amount
- of light available. Setting 0 is slowest, 6 is fastest.
- Beware - fast settings are very demanding and may not
- work well with all video sizes. Be conservative.
+ an approximate setting (in terms of "worst" ... "best")
+ because camera changes frame rate depending on amount
+ of light available. Setting 0 is slowest, 6 is fastest.
+ Beware - fast settings are very demanding and may not
+ work well with all video sizes. Be conservative.
hue_correction This highly optional setting allows to adjust the
- hue of the image in a way slightly different from
- what usual "hue" control does. Both controls affect
- YUV colorspace: regular "hue" control adjusts only
- U component, and this "hue_correction" option similarly
- adjusts only V component. However usually it is enough
- to tweak only U or V to compensate for colored light or
- color temperature; this option simply allows more
- complicated correction when and if it is necessary.
+ hue of the image in a way slightly different from
+ what usual "hue" control does. Both controls affect
+ YUV colorspace: regular "hue" control adjusts only
+ U component, and this "hue_correction" option similarly
+ adjusts only V component. However usually it is enough
+ to tweak only U or V to compensate for colored light or
+ color temperature; this option simply allows more
+ complicated correction when and if it is necessary.
init_brightness These settings specify _initial_ values which will be
init_contrast used to set up the camera. If your V4L application has
init_color its own controls to adjust the picture then these
init_hue controls will be used too. These options allow you to
- preconfigure the camera when it gets connected, before
- any V4L application connects to it. Good for webcams.
+ preconfigure the camera when it gets connected, before
+ any V4L application connects to it. Good for webcams.
init_model2_rg These initial settings alter color balance of the
init_model2_rg2 camera on hardware level. All four settings may be used
@@ -258,47 +258,47 @@ init_model2_sat to tune the camera to specific lighting conditions. These
init_model2_yb settings only apply to Model 2 cameras.
lighting This option selects one of three hardware-defined
- photosensitivity settings of the camera. 0=bright light,
- 1=Medium (default), 2=Low light. This setting affects
- frame rate: the dimmer the lighting the lower the frame
- rate (because longer exposition time is needed). The
- Model 2 cameras allow values more than 2 for this option,
- thus enabling extremely high sensitivity at cost of frame
- rate, color saturation and imaging sensor noise.
+ photosensitivity settings of the camera. 0=bright light,
+ 1=Medium (default), 2=Low light. This setting affects
+ frame rate: the dimmer the lighting the lower the frame
+ rate (because longer exposition time is needed). The
+ Model 2 cameras allow values more than 2 for this option,
+ thus enabling extremely high sensitivity at cost of frame
+ rate, color saturation and imaging sensor noise.
sharpness This option controls smoothing (noise reduction)
- made by camera. Setting 0 is most smooth, setting 6
- is most sharp. Be aware that CMOS sensor used in the
- camera is pretty noisy, so if you choose 6 you will
- be greeted with "snowy" image. Default is 4. Model 2
- cameras do not support this feature.
+ made by camera. Setting 0 is most smooth, setting 6
+ is most sharp. Be aware that CMOS sensor used in the
+ camera is pretty noisy, so if you choose 6 you will
+ be greeted with "snowy" image. Default is 4. Model 2
+ cameras do not support this feature.
size This setting chooses one of several image sizes that are
- supported by this driver. Cameras may support more, but
- it's difficult to reverse-engineer all formats.
- Following video sizes are supported:
-
- size=0 128x96 (Model 1 only)
- size=1 160x120
- size=2 176x144
- size=3 320x240 (Model 2 only)
- size=4 352x240 (Model 2 only)
- size=5 352x288
- size=6 640x480 (Model 3 only)
-
- The 352x288 is the native size of the Model 1 sensor
- array, so it's the best resolution the camera can
- yield. The best resolution of Model 2 is 176x144, and
- larger images are produced by stretching the bitmap.
- Model 3 has sensor with 640x480 grid, and it works too,
- but the frame rate will be exceptionally low (1-2 FPS);
- it may be still OK for some applications, like security.
- Choose the image size you need. The smaller image can
- support faster frame rate. Default is 352x288.
+ supported by this driver. Cameras may support more, but
+ it's difficult to reverse-engineer all formats.
+ Following video sizes are supported:
+
+ size=0 128x96 (Model 1 only)
+ size=1 160x120
+ size=2 176x144
+ size=3 320x240 (Model 2 only)
+ size=4 352x240 (Model 2 only)
+ size=5 352x288
+ size=6 640x480 (Model 3 only)
+
+ The 352x288 is the native size of the Model 1 sensor
+ array, so it's the best resolution the camera can
+ yield. The best resolution of Model 2 is 176x144, and
+ larger images are produced by stretching the bitmap.
+ Model 3 has sensor with 640x480 grid, and it works too,
+ but the frame rate will be exceptionally low (1-2 FPS);
+ it may be still OK for some applications, like security.
+ Choose the image size you need. The smaller image can
+ support faster frame rate. Default is 352x288.
For more information and the Troubleshooting FAQ visit this URL:
- http://www.linux-usb.org/ibmcam/
+ http://www.linux-usb.org/ibmcam/
WHAT NEEDS TO BE DONE:
diff --git a/Documentation/video4linux/ov511.txt b/Documentation/video4linux/ov511.txt
index 142741e..79af610 100644
--- a/Documentation/video4linux/ov511.txt
+++ b/Documentation/video4linux/ov511.txt
@@ -81,7 +81,7 @@ MODULE PARAMETERS:
TYPE: integer (Boolean)
DEFAULT: 1
DESC: Brightness is normally under automatic control and can't be set
- manually by the video app. Set to 0 for manual control.
+ manually by the video app. Set to 0 for manual control.
NAME: autogain
TYPE: integer (Boolean)
@@ -97,13 +97,13 @@ MODULE PARAMETERS:
TYPE: integer (0-6)
DEFAULT: 3
DESC: Sets the threshold for printing debug messages. The higher the value,
- the more is printed. The levels are cumulative, and are as follows:
- 0=no debug messages
- 1=init/detection/unload and other significant messages
- 2=some warning messages
- 3=config/control function calls
- 4=most function calls and data parsing messages
- 5=highly repetitive mesgs
+ the more is printed. The levels are cumulative, and are as follows:
+ 0=no debug messages
+ 1=init/detection/unload and other significant messages
+ 2=some warning messages
+ 3=config/control function calls
+ 4=most function calls and data parsing messages
+ 5=highly repetitive mesgs
NAME: snapshot
TYPE: integer (Boolean)
@@ -116,24 +116,24 @@ MODULE PARAMETERS:
TYPE: integer (1-4 for OV511, 1-31 for OV511+)
DEFAULT: 1
DESC: Number of cameras allowed to stream simultaneously on a single bus.
- Values higher than 1 reduce the data rate of each camera, allowing two
- or more to be used at once. If you have a complicated setup involving
- both OV511 and OV511+ cameras, trial-and-error may be necessary for
- finding the optimum setting.
+ Values higher than 1 reduce the data rate of each camera, allowing two
+ or more to be used at once. If you have a complicated setup involving
+ both OV511 and OV511+ cameras, trial-and-error may be necessary for
+ finding the optimum setting.
NAME: compress
TYPE: integer (Boolean)
DEFAULT: 0
DESC: Set this to 1 to turn on the camera's compression engine. This can
- potentially increase the frame rate at the expense of quality, if you
- have a fast CPU. You must load the proper compression module for your
- camera before starting your application (ov511_decomp or ov518_decomp).
+ potentially increase the frame rate at the expense of quality, if you
+ have a fast CPU. You must load the proper compression module for your
+ camera before starting your application (ov511_decomp or ov518_decomp).
NAME: testpat
TYPE: integer (Boolean)
DEFAULT: 0
DESC: This configures the camera's sensor to transmit a colored test-pattern
- instead of an image. This does not work correctly yet.
+ instead of an image. This does not work correctly yet.
NAME: dumppix
TYPE: integer (0-2)
diff --git a/Documentation/video4linux/sn9c102.txt b/Documentation/video4linux/sn9c102.txt
index 142920b..1d20895 100644
--- a/Documentation/video4linux/sn9c102.txt
+++ b/Documentation/video4linux/sn9c102.txt
@@ -1,9 +1,9 @@
- SN9C10x PC Camera Controllers
- Driver for Linux
- =============================
+ SN9C10x PC Camera Controllers
+ Driver for Linux
+ =============================
- - Documentation -
+ - Documentation -
Index
@@ -176,46 +176,46 @@ Name: video_nr
Type: short array (min = 0, max = 64)
Syntax: <-1|n[,...]>
Description: Specify V4L2 minor mode number:
- -1 = use next available
- n = use minor number n
- You can specify up to 64 cameras this way.
- For example:
- video_nr=-1,2,-1 would assign minor number 2 to the second
- recognized camera and use auto for the first one and for every
- other camera.
+ -1 = use next available
+ n = use minor number n
+ You can specify up to 64 cameras this way.
+ For example:
+ video_nr=-1,2,-1 would assign minor number 2 to the second
+ recognized camera and use auto for the first one and for every
+ other camera.
Default: -1
-------------------------------------------------------------------------------
Name: force_munmap
Type: bool array (min = 0, max = 64)
Syntax: <0|1[,...]>
Description: Force the application to unmap previously mapped buffer memory
- before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
- all the applications support this feature. This parameter is
- specific for each detected camera.
- 0 = do not force memory unmapping
- 1 = force memory unmapping (save memory)
+ before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
+ all the applications support this feature. This parameter is
+ specific for each detected camera.
+ 0 = do not force memory unmapping
+ 1 = force memory unmapping (save memory)
Default: 0
-------------------------------------------------------------------------------
Name: frame_timeout
Type: uint array (min = 0, max = 64)
Syntax: <n[,...]>
Description: Timeout for a video frame in seconds. This parameter is
- specific for each detected camera. This parameter can be
- changed at runtime thanks to the /sys filesystem interface.
+ specific for each detected camera. This parameter can be
+ changed at runtime thanks to the /sys filesystem interface.
Default: 2
-------------------------------------------------------------------------------
Name: debug
Type: ushort
Syntax: <n>
Description: Debugging information level, from 0 to 3:
- 0 = none (use carefully)
- 1 = critical errors
- 2 = significant informations
- 3 = more verbose messages
- Level 3 is useful for testing only, when only one device
- is used. It also shows some more informations about the
- hardware being detected. This parameter can be changed at
- runtime thanks to the /sys filesystem interface.
+ 0 = none (use carefully)
+ 1 = critical errors
+ 2 = significant informations
+ 3 = more verbose messages
+ Level 3 is useful for testing only, when only one device
+ is used. It also shows some more informations about the
+ hardware being detected. This parameter can be changed at
+ runtime thanks to the /sys filesystem interface.
Default: 2
-------------------------------------------------------------------------------
@@ -280,24 +280,24 @@ Byte # Value Description
0x04 0xC4 Frame synchronisation pattern.
0x05 0x96 Frame synchronisation pattern.
0x06 0xXX Unknown meaning. The exact value depends on the chip;
- possible values are 0x00, 0x01 and 0x20.
+ possible values are 0x00, 0x01 and 0x20.
0x07 0xXX Variable value, whose bits are ff00uzzc, where ff is a
- frame counter, u is unknown, zz is a size indicator
- (00 = VGA, 01 = SIF, 10 = QSIF) and c stands for
- "compression enabled" (1 = yes, 0 = no).
+ frame counter, u is unknown, zz is a size indicator
+ (00 = VGA, 01 = SIF, 10 = QSIF) and c stands for
+ "compression enabled" (1 = yes, 0 = no).
0x08 0xXX Brightness sum inside Auto-Exposure area (low-byte).
0x09 0xXX Brightness sum inside Auto-Exposure area (high-byte).
- For a pure white image, this number will be equal to 500
- times the area of the specified AE area. For images
- that are not pure white, the value scales down according
- to relative whiteness.
+ For a pure white image, this number will be equal to 500
+ times the area of the specified AE area. For images
+ that are not pure white, the value scales down according
+ to relative whiteness.
0x0A 0xXX Brightness sum outside Auto-Exposure area (low-byte).
0x0B 0xXX Brightness sum outside Auto-Exposure area (high-byte).
- For a pure white image, this number will be equal to 125
- times the area outside of the specified AE area. For
- images that are not pure white, the value scales down
- according to relative whiteness.
- according to relative whiteness.
+ For a pure white image, this number will be equal to 125
+ times the area outside of the specified AE area. For
+ images that are not pure white, the value scales down
+ according to relative whiteness.
+ according to relative whiteness.
The following bytes are used by the SN9C103 bridge only:
diff --git a/Documentation/video4linux/v4lgrab.c b/Documentation/video4linux/v4lgrab.c
new file mode 100644
index 0000000..079b628
--- /dev/null
+++ b/Documentation/video4linux/v4lgrab.c
@@ -0,0 +1,192 @@
+/* Simple Video4Linux image grabber. */
+/*
+ * Video4Linux Driver Test/Example Framegrabbing Program
+ *
+ * Compile with:
+ * gcc -s -Wall -Wstrict-prototypes v4lgrab.c -o v4lgrab
+ * Use as:
+ * v4lgrab >image.ppm
+ *
+ * Copyright (C) 1998-05-03, Phil Blundell <philb@gnu.org>
+ * Copied from http://www.tazenda.demon.co.uk/phil/vgrabber.c
+ * with minor modifications (Dave Forrest, drf5n@virginia.edu).
+ *
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+
+#include <linux/types.h>
+#include <linux/videodev.h>
+
+#define FILE "/dev/video0"
+
+/* Stole this from tvset.c */
+
+#define READ_VIDEO_PIXEL(buf, format, depth, r, g, b) \
+{ \
+ switch (format) \
+ { \
+ case VIDEO_PALETTE_GREY: \
+ switch (depth) \
+ { \
+ case 4: \
+ case 6: \
+ case 8: \
+ (r) = (g) = (b) = (*buf++ << 8);\
+ break; \
+ \
+ case 16: \
+ (r) = (g) = (b) = \
+ *((unsigned short *) buf); \
+ buf += 2; \
+ break; \
+ } \
+ break; \
+ \
+ \
+ case VIDEO_PALETTE_RGB565: \
+ { \
+ unsigned short tmp = *(unsigned short *)buf; \
+ (r) = tmp&0xF800; \
+ (g) = (tmp<<5)&0xFC00; \
+ (b) = (tmp<<11)&0xF800; \
+ buf += 2; \
+ } \
+ break; \
+ \
+ case VIDEO_PALETTE_RGB555: \
+ (r) = (buf[0]&0xF8)<<8; \
+ (g) = ((buf[0] << 5 | buf[1] >> 3)&0xF8)<<8; \
+ (b) = ((buf[1] << 2 ) & 0xF8)<<8; \
+ buf += 2; \
+ break; \
+ \
+ case VIDEO_PALETTE_RGB24: \
+ (r) = buf[0] << 8; (g) = buf[1] << 8; \
+ (b) = buf[2] << 8; \
+ buf += 3; \
+ break; \
+ \
+ default: \
+ fprintf(stderr, \
+ "Format %d not yet supported\n", \
+ format); \
+ } \
+}
+
+int get_brightness_adj(unsigned char *image, long size, int *brightness) {
+ long i, tot = 0;
+ for (i=0;i<size*3;i++)
+ tot += image[i];
+ *brightness = (128 - tot/(size*3))/3;
+ return !((tot/(size*3)) >= 126 && (tot/(size*3)) <= 130);
+}
+
+int main(int argc, char ** argv)
+{
+ int fd = open(FILE, O_RDONLY), f;
+ struct video_capability cap;
+ struct video_window win;
+ struct video_picture vpic;
+
+ unsigned char *buffer, *src;
+ int bpp = 24, r, g, b;
+ unsigned int i, src_depth;
+
+ if (fd < 0) {
+ perror(FILE);
+ exit(1);
+ }
+
+ if (ioctl(fd, VIDIOCGCAP, &cap) < 0) {
+ perror("VIDIOGCAP");
+ fprintf(stderr, "(" FILE " not a video4linux device?)\n");
+ close(fd);
+ exit(1);
+ }
+
+ if (ioctl(fd, VIDIOCGWIN, &win) < 0) {
+ perror("VIDIOCGWIN");
+ close(fd);
+ exit(1);
+ }
+
+ if (ioctl(fd, VIDIOCGPICT, &vpic) < 0) {
+ perror("VIDIOCGPICT");
+ close(fd);
+ exit(1);
+ }
+
+ if (cap.type & VID_TYPE_MONOCHROME) {
+ vpic.depth=8;
+ vpic.palette=VIDEO_PALETTE_GREY; /* 8bit grey */
+ if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
+ vpic.depth=6;
+ if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
+ vpic.depth=4;
+ if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
+ fprintf(stderr, "Unable to find a supported capture format.\n");
+ close(fd);
+ exit(1);
+ }
+ }
+ }
+ } else {
+ vpic.depth=24;
+ vpic.palette=VIDEO_PALETTE_RGB24;
+
+ if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
+ vpic.palette=VIDEO_PALETTE_RGB565;
+ vpic.depth=16;
+
+ if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
+ vpic.palette=VIDEO_PALETTE_RGB555;
+ vpic.depth=15;
+
+ if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
+ fprintf(stderr, "Unable to find a supported capture format.\n");
+ return -1;
+ }
+ }
+ }
+ }
+
+ buffer = malloc(win.width * win.height * bpp);
+ if (!buffer) {
+ fprintf(stderr, "Out of memory.\n");
+ exit(1);
+ }
+
+ do {
+ int newbright;
+ read(fd, buffer, win.width * win.height * bpp);
+ f = get_brightness_adj(buffer, win.width * win.height, &newbright);
+ if (f) {
+ vpic.brightness += (newbright << 8);
+ if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
+ perror("VIDIOSPICT");
+ break;
+ }
+ }
+ } while (f);
+
+ fprintf(stdout, "P6\n%d %d 255\n", win.width, win.height);
+
+ src = buffer;
+
+ for (i = 0; i < win.width * win.height; i++) {
+ READ_VIDEO_PIXEL(src, vpic.palette, src_depth, r, g, b);
+ fputc(r>>8, stdout);
+ fputc(g>>8, stdout);
+ fputc(b>>8, stdout);
+ }
+
+ close(fd);
+ return 0;
+}
diff --git a/Documentation/video4linux/w9968cf.txt b/Documentation/video4linux/w9968cf.txt
index 3b704f2..0d53ce7 100644
--- a/Documentation/video4linux/w9968cf.txt
+++ b/Documentation/video4linux/w9968cf.txt
@@ -1,9 +1,9 @@
- W996[87]CF JPEG USB Dual Mode Camera Chip
- Driver for Linux 2.6 (basic version)
- =========================================
+ W996[87]CF JPEG USB Dual Mode Camera Chip
+ Driver for Linux 2.6 (basic version)
+ =========================================
- - Documentation -
+ - Documentation -
Index
@@ -188,57 +188,57 @@ Name: ovmod_load
Type: bool
Syntax: <0|1>
Description: Automatic 'ovcamchip' module loading: 0 disabled, 1 enabled.
- If enabled, 'insmod' searches for the required 'ovcamchip'
- module in the system, according to its configuration, and
- loads that module automatically. This action is performed as
- once soon as the 'w9968cf' module is loaded into memory.
+ If enabled, 'insmod' searches for the required 'ovcamchip'
+ module in the system, according to its configuration, and
+ loads that module automatically. This action is performed as
+ once soon as the 'w9968cf' module is loaded into memory.
Default: 1
Note: The kernel must be compiled with the CONFIG_KMOD option
- enabled for the 'ovcamchip' module to be loaded and for
- this parameter to be present.
+ enabled for the 'ovcamchip' module to be loaded and for
+ this parameter to be present.
-------------------------------------------------------------------------------
Name: simcams
Type: int
Syntax: <n>
Description: Number of cameras allowed to stream simultaneously.
- n may vary from 0 to 32.
+ n may vary from 0 to 32.
Default: 32
-------------------------------------------------------------------------------
Name: video_nr
Type: int array (min = 0, max = 32)
Syntax: <-1|n[,...]>
Description: Specify V4L minor mode number.
- -1 = use next available
- n = use minor number n
- You can specify up to 32 cameras this way.
- For example:
- video_nr=-1,2,-1 would assign minor number 2 to the second
- recognized camera and use auto for the first one and for every
- other camera.
+ -1 = use next available
+ n = use minor number n
+ You can specify up to 32 cameras this way.
+ For example:
+ video_nr=-1,2,-1 would assign minor number 2 to the second
+ recognized camera and use auto for the first one and for every
+ other camera.
Default: -1
-------------------------------------------------------------------------------
Name: packet_size
Type: int array (min = 0, max = 32)
Syntax: <n[,...]>
Description: Specify the maximum data payload size in bytes for alternate
- settings, for each device. n is scaled between 63 and 1023.
+ settings, for each device. n is scaled between 63 and 1023.
Default: 1023
-------------------------------------------------------------------------------
Name: max_buffers
Type: int array (min = 0, max = 32)
Syntax: <n[,...]>
Description: For advanced users.
- Specify the maximum number of video frame buffers to allocate
- for each device, from 2 to 32.
+ Specify the maximum number of video frame buffers to allocate
+ for each device, from 2 to 32.
Default: 2
-------------------------------------------------------------------------------
Name: double_buffer
Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Hardware double buffering: 0 disabled, 1 enabled.
- It should be enabled if you want smooth video output: if you
- obtain out of sync. video, disable it, or try to
- decrease the 'clockdiv' module parameter value.
+ It should be enabled if you want smooth video output: if you
+ obtain out of sync. video, disable it, or try to
+ decrease the 'clockdiv' module parameter value.
Default: 1 for every device.
-------------------------------------------------------------------------------
Name: clamping
@@ -251,9 +251,9 @@ Name: filter_type
Type: int array (min = 0, max = 32)
Syntax: <0|1|2[,...]>
Description: Video filter type.
- 0 none, 1 (1-2-1) 3-tap filter, 2 (2-3-6-3-2) 5-tap filter.
- The filter is used to reduce noise and aliasing artifacts
- produced by the CCD or CMOS image sensor.
+ 0 none, 1 (1-2-1) 3-tap filter, 2 (2-3-6-3-2) 5-tap filter.
+ The filter is used to reduce noise and aliasing artifacts
+ produced by the CCD or CMOS image sensor.
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: largeview
@@ -266,9 +266,9 @@ Name: upscaling
Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Software scaling (for non-compressed video only):
- 0 disabled, 1 enabled.
- Disable it if you have a slow CPU or you don't have enough
- memory.
+ 0 disabled, 1 enabled.
+ Disable it if you have a slow CPU or you don't have enough
+ memory.
Default: 0 for every device.
Note: If 'w9968cf-vpp' is not present, this parameter is set to 0.
-------------------------------------------------------------------------------
@@ -276,36 +276,36 @@ Name: decompression
Type: int array (min = 0, max = 32)
Syntax: <0|1|2[,...]>
Description: Software video decompression:
- 0 = disables decompression
- (doesn't allow formats needing decompression).
- 1 = forces decompression
- (allows formats needing decompression only).
- 2 = allows any permitted formats.
- Formats supporting (de)compressed video are YUV422P and
- YUV420P/YUV420 in any resolutions where width and height are
- multiples of 16.
+ 0 = disables decompression
+ (doesn't allow formats needing decompression).
+ 1 = forces decompression
+ (allows formats needing decompression only).
+ 2 = allows any permitted formats.
+ Formats supporting (de)compressed video are YUV422P and
+ YUV420P/YUV420 in any resolutions where width and height are
+ multiples of 16.
Default: 2 for every device.
Note: If 'w9968cf-vpp' is not present, forcing decompression is not
- allowed; in this case this parameter is set to 2.
+ allowed; in this case this parameter is set to 2.
-------------------------------------------------------------------------------
Name: force_palette
Type: int array (min = 0, max = 32)
Syntax: <0|9|10|13|15|8|7|1|6|3|4|5[,...]>
Description: Force picture palette.
- In order:
- 0 = Off - allows any of the following formats:
- 9 = UYVY 16 bpp - Original video, compression disabled
- 10 = YUV420 12 bpp - Original video, compression enabled
- 13 = YUV422P 16 bpp - Original video, compression enabled
- 15 = YUV420P 12 bpp - Original video, compression enabled
- 8 = YUVY 16 bpp - Software conversion from UYVY
- 7 = YUV422 16 bpp - Software conversion from UYVY
- 1 = GREY 8 bpp - Software conversion from UYVY
- 6 = RGB555 16 bpp - Software conversion from UYVY
- 3 = RGB565 16 bpp - Software conversion from UYVY
- 4 = RGB24 24 bpp - Software conversion from UYVY
- 5 = RGB32 32 bpp - Software conversion from UYVY
- When not 0, this parameter will override 'decompression'.
+ In order:
+ 0 = Off - allows any of the following formats:
+ 9 = UYVY 16 bpp - Original video, compression disabled
+ 10 = YUV420 12 bpp - Original video, compression enabled
+ 13 = YUV422P 16 bpp - Original video, compression enabled
+ 15 = YUV420P 12 bpp - Original video, compression enabled
+ 8 = YUVY 16 bpp - Software conversion from UYVY
+ 7 = YUV422 16 bpp - Software conversion from UYVY
+ 1 = GREY 8 bpp - Software conversion from UYVY
+ 6 = RGB555 16 bpp - Software conversion from UYVY
+ 3 = RGB565 16 bpp - Software conversion from UYVY
+ 4 = RGB24 24 bpp - Software conversion from UYVY
+ 5 = RGB32 32 bpp - Software conversion from UYVY
+ When not 0, this parameter will override 'decompression'.
Default: 0 for every device. Initial palette is 9 (UYVY).
Note: If 'w9968cf-vpp' is not present, this parameter is set to 9.
-------------------------------------------------------------------------------
@@ -313,77 +313,77 @@ Name: force_rgb
Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Read RGB video data instead of BGR:
- 1 = use RGB component ordering.
- 0 = use BGR component ordering.
- This parameter has effect when using RGBX palettes only.
+ 1 = use RGB component ordering.
+ 0 = use BGR component ordering.
+ This parameter has effect when using RGBX palettes only.
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: autobright
Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Image sensor automatically changes brightness:
- 0 = no, 1 = yes
+ 0 = no, 1 = yes
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: autoexp
Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Image sensor automatically changes exposure:
- 0 = no, 1 = yes
+ 0 = no, 1 = yes
Default: 1 for every device.
-------------------------------------------------------------------------------
Name: lightfreq
Type: int array (min = 0, max = 32)
Syntax: <50|60[,...]>
Description: Light frequency in Hz:
- 50 for European and Asian lighting, 60 for American lighting.
+ 50 for European and Asian lighting, 60 for American lighting.
Default: 50 for every device.
-------------------------------------------------------------------------------
Name: bandingfilter
Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Banding filter to reduce effects of fluorescent
- lighting:
- 0 disabled, 1 enabled.
- This filter tries to reduce the pattern of horizontal
- light/dark bands caused by some (usually fluorescent) lighting.
+ lighting:
+ 0 disabled, 1 enabled.
+ This filter tries to reduce the pattern of horizontal
+ light/dark bands caused by some (usually fluorescent) lighting.
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: clockdiv
Type: int array (min = 0, max = 32)
Syntax: <-1|n[,...]>
Description: Force pixel clock divisor to a specific value (for experts):
- n may vary from 0 to 127.
- -1 for automatic value.
- See also the 'double_buffer' module parameter.
+ n may vary from 0 to 127.
+ -1 for automatic value.
+ See also the 'double_buffer' module parameter.
Default: -1 for every device.
-------------------------------------------------------------------------------
Name: backlight
Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Objects are lit from behind:
- 0 = no, 1 = yes
+ 0 = no, 1 = yes
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: mirror
Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Reverse image horizontally:
- 0 = no, 1 = yes
+ 0 = no, 1 = yes
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: monochrome
Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: The image sensor is monochrome:
- 0 = no, 1 = yes
+ 0 = no, 1 = yes
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: brightness
Type: long array (min = 0, max = 32)
Syntax: <n[,...]>
Description: Set picture brightness (0-65535).
- This parameter has no effect if 'autobright' is enabled.
+ This parameter has no effect if 'autobright' is enabled.
Default: 31000 for every device.
-------------------------------------------------------------------------------
Name: hue
@@ -414,23 +414,23 @@ Name: debug
Type: int
Syntax: <n>
Description: Debugging information level, from 0 to 6:
- 0 = none (use carefully)
- 1 = critical errors
- 2 = significant informations
- 3 = configuration or general messages
- 4 = warnings
- 5 = called functions
- 6 = function internals
- Level 5 and 6 are useful for testing only, when only one
- device is used.
+ 0 = none (use carefully)
+ 1 = critical errors
+ 2 = significant informations
+ 3 = configuration or general messages
+ 4 = warnings
+ 5 = called functions
+ 6 = function internals
+ Level 5 and 6 are useful for testing only, when only one
+ device is used.
Default: 2
-------------------------------------------------------------------------------
Name: specific_debug
Type: bool
Syntax: <0|1>
Description: Enable or disable specific debugging messages:
- 0 = print messages concerning every level <= 'debug' level.
- 1 = print messages concerning the level indicated by 'debug'.
+ 0 = print messages concerning every level <= 'debug' level.
+ 1 = print messages concerning the level indicated by 'debug'.
Default: 0
-------------------------------------------------------------------------------
diff --git a/Documentation/video4linux/zc0301.txt b/Documentation/video4linux/zc0301.txt
index f55262c..f406f5e 100644
--- a/Documentation/video4linux/zc0301.txt
+++ b/Documentation/video4linux/zc0301.txt
@@ -1,9 +1,9 @@
- ZC0301 Image Processor and Control Chip
- Driver for Linux
- =======================================
+ ZC0301 and ZC0301P Image Processor and Control Chip
+ Driver for Linux
+ ===================================================
- - Documentation -
+ - Documentation -
Index
@@ -51,13 +51,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
4. Overview and features
========================
-This driver supports the video interface of the devices mounting the ZC0301
-Image Processor and Control Chip.
+This driver supports the video interface of the devices mounting the ZC0301 or
+ZC0301P Image Processors and Control Chips.
The driver relies on the Video4Linux2 and USB core modules. It has been
designed to run properly on SMP systems as well.
-The latest version of the ZC0301 driver can be found at the following URL:
+The latest version of the ZC0301[P] driver can be found at the following URL:
http://www.linux-projects.org/
Some of the features of the driver are:
@@ -117,7 +117,7 @@ supported by the USB Audio driver thanks to the ALSA API:
And finally:
- # USB Multimedia devices
+ # V4L USB devices
#
CONFIG_USB_ZC0301=m
@@ -146,46 +146,46 @@ Name: video_nr
Type: short array (min = 0, max = 64)
Syntax: <-1|n[,...]>
Description: Specify V4L2 minor mode number:
- -1 = use next available
- n = use minor number n
- You can specify up to 64 cameras this way.
- For example:
- video_nr=-1,2,-1 would assign minor number 2 to the second
- registered camera and use auto for the first one and for every
- other camera.
+ -1 = use next available
+ n = use minor number n
+ You can specify up to 64 cameras this way.
+ For example:
+ video_nr=-1,2,-1 would assign minor number 2 to the second
+ registered camera and use auto for the first one and for every
+ other camera.
Default: -1
-------------------------------------------------------------------------------
Name: force_munmap
Type: bool array (min = 0, max = 64)
Syntax: <0|1[,...]>
Description: Force the application to unmap previously mapped buffer memory
- before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
- all the applications support this feature. This parameter is
- specific for each detected camera.
- 0 = do not force memory unmapping
- 1 = force memory unmapping (save memory)
+ before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
+ all the applications support this feature. This parameter is
+ specific for each detected camera.
+ 0 = do not force memory unmapping
+ 1 = force memory unmapping (save memory)
Default: 0
-------------------------------------------------------------------------------
Name: frame_timeout
Type: uint array (min = 0, max = 64)
Syntax: <n[,...]>
Description: Timeout for a video frame in seconds. This parameter is
- specific for each detected camera. This parameter can be
- changed at runtime thanks to the /sys filesystem interface.
+ specific for each detected camera. This parameter can be
+ changed at runtime thanks to the /sys filesystem interface.
Default: 2
-------------------------------------------------------------------------------
Name: debug
Type: ushort
Syntax: <n>
Description: Debugging information level, from 0 to 3:
- 0 = none (use carefully)
- 1 = critical errors
- 2 = significant informations
- 3 = more verbose messages
- Level 3 is useful for testing only, when only one device
- is used at the same time. It also shows some more informations
- about the hardware being detected. This module parameter can be
- changed at runtime thanks to the /sys filesystem interface.
+ 0 = none (use carefully)
+ 1 = critical errors
+ 2 = significant informations
+ 3 = more verbose messages
+ Level 3 is useful for testing only, when only one device
+ is used at the same time. It also shows some more informations
+ about the hardware being detected. This module parameter can be
+ changed at runtime thanks to the /sys filesystem interface.
Default: 2
-------------------------------------------------------------------------------
@@ -204,11 +204,25 @@ Vendor ID Product ID
0x041e 0x4017
0x041e 0x401c
0x041e 0x401e
+0x041e 0x401f
+0x041e 0x4022
0x041e 0x4034
0x041e 0x4035
+0x041e 0x4036
+0x041e 0x403a
+0x0458 0x7007
+0x0458 0x700C
+0x0458 0x700f
+0x046d 0x08ae
+0x055f 0xd003
+0x055f 0xd004
0x046d 0x08ae
0x0ac8 0x0301
+0x0ac8 0x301b
+0x0ac8 0x303b
+0x10fd 0x0128
0x10fd 0x8050
+0x10fd 0x804e
The list above does not imply that all those devices work with this driver: up
until now only the ones that mount the following image sensors are supported;
@@ -217,6 +231,7 @@ kernel messages will always tell you whether this is the case:
Model Manufacturer
----- ------------
PAS202BCB PixArt Imaging, Inc.
+PB-0330 Photobit Corporation
9. Notes for V4L2 application developers
@@ -250,5 +265,6 @@ the fingerprint is: '88E8 F32F 7244 68BA 3958 5D40 99DA 5D2A FCE6 35A4'.
been taken from the documentation of the ZC030x Video4Linux1 driver written
by Andrew Birkett <andy@nobugs.org>;
- The initialization values of the ZC0301 controller connected to the PAS202BCB
- image sensor have been taken from the SPCA5XX driver maintained by
- Michel Xhaard <mxhaard@magic.fr>.
+ and PB-0330 image sensors have been taken from the SPCA5XX driver maintained
+ by Michel Xhaard <mxhaard@magic.fr>;
+- Stanislav Lechev donated one camera.
diff --git a/Documentation/vm/page_migration b/Documentation/vm/page_migration
index 0dd4ef3..99f89aa 100644
--- a/Documentation/vm/page_migration
+++ b/Documentation/vm/page_migration
@@ -26,8 +26,13 @@ a process are located. See also the numa_maps manpage in the numactl package.
Manual migration is useful if for example the scheduler has relocated
a process to a processor on a distant node. A batch scheduler or an
administrator may detect the situation and move the pages of the process
-nearer to the new processor. At some point in the future we may have
-some mechanism in the scheduler that will automatically move the pages.
+nearer to the new processor. The kernel itself does only provide
+manual page migration support. Automatic page migration may be implemented
+through user space processes that move pages. A special function call
+"move_pages" allows the moving of individual pages within a process.
+A NUMA profiler may f.e. obtain a log showing frequent off node
+accesses and may use the result to move pages to more advantageous
+locations.
Larger installations usually partition the system using cpusets into
sections of nodes. Paul Jackson has equipped cpusets with the ability to
@@ -62,22 +67,14 @@ A. In kernel use of migrate_pages()
It also prevents the swapper or other scans to encounter
the page.
-2. Generate a list of newly allocates page. These pages will contain the
- contents of the pages from the first list after page migration is
- complete.
+2. We need to have a function of type new_page_t that can be
+ passed to migrate_pages(). This function should figure out
+ how to allocate the correct new page given the old page.
3. The migrate_pages() function is called which attempts
- to do the migration. It returns the moved pages in the
- list specified as the third parameter and the failed
- migrations in the fourth parameter. The first parameter
- will contain the pages that could still be retried.
-
-4. The leftover pages of various types are returned
- to the LRU using putback_to_lru_pages() or otherwise
- disposed of. The pages will still have the refcount as
- increased by isolate_lru_pages() if putback_to_lru_pages() is not
- used! The kernel may want to handle the various cases of failures in
- different ways.
+ to do the migration. It will call the function to allocate
+ the new page for each page that is considered for
+ moving.
B. How migrate_pages() works
----------------------------
@@ -93,83 +90,58 @@ Steps:
2. Insure that writeback is complete.
-3. Make sure that the page has assigned swap cache entry if
- it is an anonyous page. The swap cache reference is necessary
- to preserve the information contain in the page table maps while
- page migration occurs.
-
-4. Prep the new page that we want to move to. It is locked
+3. Prep the new page that we want to move to. It is locked
and set to not being uptodate so that all accesses to the new
page immediately lock while the move is in progress.
-5. All the page table references to the page are either dropped (file
- backed pages) or converted to swap references (anonymous pages).
- This should decrease the reference count.
+4. The new page is prepped with some settings from the old page so that
+ accesses to the new page will discover a page with the correct settings.
+
+5. All the page table references to the page are converted
+ to migration entries or dropped (nonlinear vmas).
+ This decrease the mapcount of a page. If the resulting
+ mapcount is not zero then we do not migrate the page.
+ All user space processes that attempt to access the page
+ will now wait on the page lock.
6. The radix tree lock is taken. This will cause all processes trying
- to reestablish a pte to block on the radix tree spinlock.
+ to access the page via the mapping to block on the radix tree spinlock.
7. The refcount of the page is examined and we back out if references remain
otherwise we know that we are the only one referencing this page.
8. The radix tree is checked and if it does not contain the pointer to this
- page then we back out because someone else modified the mapping first.
-
-9. The mapping is checked. If the mapping is gone then a truncate action may
- be in progress and we back out.
-
-10. The new page is prepped with some settings from the old page so that
- accesses to the new page will be discovered to have the correct settings.
+ page then we back out because someone else modified the radix tree.
-11. The radix tree is changed to point to the new page.
+9. The radix tree is changed to point to the new page.
-12. The reference count of the old page is dropped because the radix tree
- reference is gone.
+10. The reference count of the old page is dropped because the radix tree
+ reference is gone. A reference to the new page is established because
+ the new page is referenced to by the radix tree.
-13. The radix tree lock is dropped. With that lookups become possible again
- and other processes will move from spinning on the tree lock to sleeping on
- the locked new page.
+11. The radix tree lock is dropped. With that lookups in the mapping
+ become possible again. Processes will move from spinning on the tree_lock
+ to sleeping on the locked new page.
-14. The page contents are copied to the new page.
+12. The page contents are copied to the new page.
-15. The remaining page flags are copied to the new page.
+13. The remaining page flags are copied to the new page.
-16. The old page flags are cleared to indicate that the page does
- not use any information anymore.
+14. The old page flags are cleared to indicate that the page does
+ not provide any information anymore.
-17. Queued up writeback on the new page is triggered.
+15. Queued up writeback on the new page is triggered.
-18. If swap pte's were generated for the page then replace them with real
- ptes. This will reenable access for processes not blocked by the page lock.
+16. If migration entries were page then replace them with real ptes. Doing
+ so will enable access for user space processes not already waiting for
+ the page lock.
19. The page locks are dropped from the old and new page.
- Processes waiting on the page lock can continue.
+ Processes waiting on the page lock will redo their page faults
+ and will reach the new page.
20. The new page is moved to the LRU and can be scanned by the swapper
etc again.
-TODO list
----------
-
-- Page migration requires the use of swap handles to preserve the
- information of the anonymous page table entries. This means that swap
- space is reserved but never used. The maximum number of swap handles used
- is determined by CHUNK_SIZE (see mm/mempolicy.c) per ongoing migration.
- Reservation of pages could be avoided by having a special type of swap
- handle that does not require swap space and that would only track the page
- references. Something like that was proposed by Marcelo Tosatti in the
- past (search for migration cache on lkml or linux-mm@kvack.org).
-
-- Page migration unmaps ptes for file backed pages and requires page
- faults to reestablish these ptes. This could be optimized by somehow
- recording the references before migration and then reestablish them later.
- However, there are several locking challenges that have to be overcome
- before this is possible.
-
-- Page migration generates read ptes for anonymous pages. Dirty page
- faults are required to make the pages writable again. It may be possible
- to generate a pte marked dirty if it is known that the page is dirty and
- that this process has the only reference to that page.
-
-Christoph Lameter, March 8, 2006.
+Christoph Lameter, May 8, 2006.
diff --git a/Documentation/w1/masters/ds2490 b/Documentation/w1/masters/ds2490
new file mode 100644
index 0000000..44a4918
--- /dev/null
+++ b/Documentation/w1/masters/ds2490
@@ -0,0 +1,18 @@
+Kernel driver ds2490
+====================
+
+Supported chips:
+ * Maxim DS2490 based
+
+Author: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+
+
+Description
+-----------
+
+The Maixm/Dallas Semiconductor DS2490 is a chip
+which allows to build USB <-> W1 bridges.
+
+DS9490(R) is a USB <-> W1 bus master device
+which has 0x81 family ID integrated chip and DS2490
+low-level operational chip.
diff --git a/Documentation/w1/w1.generic b/Documentation/w1/w1.generic
index f937fbe..4c6509d 100644
--- a/Documentation/w1/w1.generic
+++ b/Documentation/w1/w1.generic
@@ -27,8 +27,19 @@ When a w1 master driver registers with the w1 subsystem, the following occurs:
When a device is found on the bus, w1 core checks if driver for it's family is
loaded. If so, the family driver is attached to the slave.
-If there is no driver for the family, a simple sysfs entry is created
-for the slave device.
+If there is no driver for the family, default one is assigned, which allows to perform
+almost any kind of operations. Each logical operation is a transaction
+in nature, which can contain several (two or one) low-level operations.
+Let's see how one can read EEPROM context:
+1. one must write control buffer, i.e. buffer containing command byte
+and two byte address. At this step bus is reset and appropriate device
+is selected using either W1_SKIP_ROM or W1_MATCH_ROM command.
+Then provided control buffer is being written to the wire.
+2. reading. This will issue reading eeprom response.
+
+It is possible that between 1. and 2. w1 master thread will reset bus for searching
+and slave device will be even removed, but in this case 0xff will
+be read, since no device was selected.
W1 device families
@@ -89,4 +100,5 @@ driver - (standard) symlink to the w1 driver
name - the device name, usually the same as the directory name
w1_slave - (optional) a binary file whose meaning depends on the
family driver
-
+rw - (optional) created for slave devices which do not have
+ appropriate family driver. Allows to read/write binary data.
diff --git a/Documentation/w1/w1.netlink b/Documentation/w1/w1.netlink
new file mode 100644
index 0000000..3640c7c8
--- /dev/null
+++ b/Documentation/w1/w1.netlink
@@ -0,0 +1,98 @@
+Userspace communication protocol over connector [1].
+
+
+Message types.
+=============
+
+There are three types of messages between w1 core and userspace:
+1. Events. They are generated each time new master or slave device found
+ either due to automatic or requested search.
+2. Userspace commands. Includes read/write and search/alarm search comamnds.
+3. Replies to userspace commands.
+
+
+Protocol.
+========
+
+[struct cn_msg] - connector header. It's length field is equal to size of the attached data.
+[struct w1_netlink_msg] - w1 netlink header.
+ __u8 type - message type.
+ W1_SLAVE_ADD/W1_SLAVE_REMOVE - slave add/remove events.
+ W1_MASTER_ADD/W1_MASTER_REMOVE - master add/remove events.
+ W1_MASTER_CMD - userspace command for bus master device (search/alarm search).
+ W1_SLAVE_CMD - userspace command for slave device (read/write/ search/alarm search
+ for bus master device where given slave device found).
+ __u8 res - reserved
+ __u16 len - size of attached to this header data.
+ union {
+ __u8 id; - slave unique device id
+ struct w1_mst {
+ __u32 id; - master's id.
+ __u32 res; - reserved
+ } mst;
+ } id;
+
+[strucrt w1_netlink_cmd] - command for gived master or slave device.
+ __u8 cmd - command opcode.
+ W1_CMD_READ - read command.
+ W1_CMD_WRITE - write command.
+ W1_CMD_SEARCH - search command.
+ W1_CMD_ALARM_SEARCH - alarm search command.
+ __u8 res - reserved
+ __u16 len - length of data for this command.
+ For read command data must be allocated like for write command.
+ __u8 data[0] - data for this command.
+
+
+Each connector message can include one or more w1_netlink_msg with zero of more attached w1_netlink_cmd messages.
+
+For event messages there are no w1_netlink_cmd embedded structures, only connector header
+and w1_netlink_msg strucutre with "len" field being zero and filled type (one of event types)
+and id - either 8 bytes of slave unique id in host order, or master's id, which is assigned
+to bus master device when it is added to w1 core.
+
+Currently replies to userspace commands are only generated for read command request.
+One reply is generated exactly for one w1_netlink_cmd read request.
+Replies are not combined when sent - i.e. typical reply messages looks like the following:
+[cn_msg][w1_netlink_msg][w1_netlink_cmd]
+cn_msg.len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd) + cmd->len;
+w1_netlink_msg.len = sizeof(struct w1_netlink_cmd) + cmd->len;
+w1_netlink_cmd.len = cmd->len;
+
+
+Operation steps in w1 core when new command is received.
+=======================================================
+
+When new message (w1_netlink_msg) is received w1 core detects if it is master of slave request,
+according to w1_netlink_msg.type field.
+Then master or slave device is searched for.
+When found, master device (requested or those one on where slave device is found) is locked.
+If slave command is requested, then reset/select procedure is started to select given device.
+
+Then all requested in w1_netlink_msg operations are performed one by one.
+If command requires reply (like read command) it is sent on command completion.
+
+When all commands (w1_netlink_cmd) are processed muster device is unlocked
+and next w1_netlink_msg header processing started.
+
+
+Connector [1] specific documentation.
+====================================
+
+Each connector message includes two u32 fields as "address".
+w1 uses CN_W1_IDX and CN_W1_VAL defined in include/linux/connector.h header.
+Each message also includes sequence and acknowledge numbers.
+Sequence number for event messages is appropriate bus master sequence number increased with
+each event message sent "through" this master.
+Sequence number for userspace requests is set by userspace application.
+Sequence number for reply is the same as was in request, and
+acknowledge number is set to seq+1.
+
+
+Additional documantion, source code examples.
+============================================
+
+1. Documentation/connector
+2. http://tservice.net.ru/~s0mbre/archive/w1
+This archive includes userspace application w1d.c which
+uses read/write/search commands for all master/slave devices found on the bus.
diff --git a/MAINTAINERS b/MAINTAINERS
index d10e629..4dcd2f1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -181,6 +181,12 @@ M: bcrl@kvack.org
L: linux-aio@kvack.org
S: Supported
+ABIT UGURU HARDWARE MONITOR DRIVER
+P: Hans de Goede
+M: j.w.r.degoede@hhs.nl
+L: lm-sensors@lm-sensors.org
+S: Maintained
+
ACENIC DRIVER
P: Jes Sorensen
M: jes@trained-monkey.org
@@ -568,6 +574,12 @@ L: linuxppc-dev@ozlabs.org
W: http://www.penguinppc.org/ppc64/
S: Supported
+BROADCOM B44 10/100 ETHERNET DRIVER
+P: Gary Zambrano
+M: zambrano@broadcom.com
+L: netdev@vger.kernel.org
+S: Supported
+
BROADCOM BNX2 GIGABIT ETHERNET DRIVER
P: Michael Chan
M: mchan@broadcom.com
@@ -2057,6 +2069,12 @@ M: adaplas@pol.net
L: linux-fbdev-devel@lists.sourceforge.net
S: Maintained
+OPENCORES I2C BUS DRIVER
+P: Peter Korsgaard
+M: jacmet@sunsite.dk
+L: lm-sensors@lm-sensors.org
+S: Maintained
+
ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
P: Mark Fasheh
M: mark.fasheh@oracle.com
@@ -2528,12 +2546,6 @@ M: thomas@winischhofer.net
W: http://www.winischhofer.at/linuxsisusbvga.shtml
S: Maintained
-SMSC47M1 HARDWARE MONITOR DRIVER
-P: Jean Delvare
-M: khali@linux-fr.org
-L: lm-sensors@lm-sensors.org
-S: Odd Fixes
-
SMB FILESYSTEM
P: Urban Widmark
M: urban@teststation.com
@@ -3146,12 +3158,6 @@ L: wbsd-devel@list.drzeus.cx
W: http://projects.drzeus.cx/wbsd
S: Maintained
-W83L785TS HARDWARE MONITOR DRIVER
-P: Jean Delvare
-M: khali@linux-fr.org
-L: lm-sensors@lm-sensors.org
-S: Odd Fixes
-
WATCHDOG DEVICE DRIVERS
P: Wim Van Sebroeck
M: wim@iguana.be
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
index 2b245ad..d3848c5 100644
--- a/arch/alpha/kernel/alpha_ksyms.c
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -53,10 +53,6 @@ extern void __divqu (void);
extern void __remqu (void);
EXPORT_SYMBOL(alpha_mv);
-EXPORT_SYMBOL(enable_irq);
-EXPORT_SYMBOL(disable_irq);
-EXPORT_SYMBOL(disable_irq_nosync);
-EXPORT_SYMBOL(probe_irq_mask);
EXPORT_SYMBOL(screen_info);
EXPORT_SYMBOL(perf_irq);
EXPORT_SYMBOL(callback_getenv);
@@ -68,19 +64,13 @@ EXPORT_SYMBOL(alpha_using_srm);
/* platform dependent support */
EXPORT_SYMBOL(strcat);
-EXPORT_SYMBOL(strcmp);
EXPORT_SYMBOL(strcpy);
EXPORT_SYMBOL(strlen);
-EXPORT_SYMBOL(strncmp);
EXPORT_SYMBOL(strncpy);
-EXPORT_SYMBOL(strnlen);
EXPORT_SYMBOL(strncat);
-EXPORT_SYMBOL(strstr);
EXPORT_SYMBOL(strchr);
EXPORT_SYMBOL(strrchr);
-EXPORT_SYMBOL(memcmp);
EXPORT_SYMBOL(memmove);
-EXPORT_SYMBOL(memscan);
EXPORT_SYMBOL(__memcpy);
EXPORT_SYMBOL(__memset);
EXPORT_SYMBOL(__memsetw);
@@ -122,11 +112,9 @@ EXPORT_SYMBOL(alpha_write_fp_reg_s);
/* In-kernel system calls. */
EXPORT_SYMBOL(kernel_thread);
-EXPORT_SYMBOL(sys_open);
EXPORT_SYMBOL(sys_dup);
EXPORT_SYMBOL(sys_exit);
EXPORT_SYMBOL(sys_write);
-EXPORT_SYMBOL(sys_read);
EXPORT_SYMBOL(sys_lseek);
EXPORT_SYMBOL(execve);
EXPORT_SYMBOL(sys_setsid);
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 31afe3d..e15dcf4 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -244,7 +244,7 @@ do_osf_statfs(struct dentry * dentry, struct osf_statfs __user *buffer,
unsigned long bufsiz)
{
struct kstatfs linux_stat;
- int error = vfs_statfs(dentry->d_inode->i_sb, &linux_stat);
+ int error = vfs_statfs(dentry, &linux_stat);
if (!error)
error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);
return error;
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index 2e45e86..741da09 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -375,7 +375,7 @@ give_sigsegv:
static inline void __user *
get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
{
- if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp))
+ if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp))
sp = current->sas_ss_sp + current->sas_ss_size;
return (void __user *)((sp - frame_size) & -32ul);
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
index 847e3e6..e1289a2 100644
--- a/arch/arm/common/Makefile
+++ b/arch/arm/common/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o
obj-$(CONFIG_SHARPSL_PM) += sharpsl_pm.o
obj-$(CONFIG_SHARP_SCOOP) += scoop.o
obj-$(CONFIG_ARCH_IXP2000) += uengine.o
+obj-$(CONFIG_ARCH_IXP23XX) += uengine.o
diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c
index 7971d0d..5b7c263 100644
--- a/arch/arm/common/dmabounce.c
+++ b/arch/arm/common/dmabounce.c
@@ -77,6 +77,8 @@ struct dmabounce_device_info {
#endif
struct dmabounce_pool small;
struct dmabounce_pool large;
+
+ rwlock_t lock;
};
static LIST_HEAD(dmabounce_devs);
@@ -116,6 +118,7 @@ alloc_safe_buffer(struct dmabounce_device_info *device_info, void *ptr,
struct safe_buffer *buf;
struct dmabounce_pool *pool;
struct device *dev = device_info->dev;
+ unsigned long flags;
dev_dbg(dev, "%s(ptr=%p, size=%d, dir=%d)\n",
__func__, ptr, size, dir);
@@ -163,8 +166,12 @@ alloc_safe_buffer(struct dmabounce_device_info *device_info, void *ptr,
print_alloc_stats(device_info);
#endif
+ write_lock_irqsave(&device_info->lock, flags);
+
list_add(&buf->node, &device_info->safe_buffers);
+ write_unlock_irqrestore(&device_info->lock, flags);
+
return buf;
}
@@ -172,22 +179,32 @@ alloc_safe_buffer(struct dmabounce_device_info *device_info, void *ptr,
static inline struct safe_buffer *
find_safe_buffer(struct dmabounce_device_info *device_info, dma_addr_t safe_dma_addr)
{
- struct safe_buffer *b;
+ struct safe_buffer *b = NULL;
+ unsigned long flags;
+
+ read_lock_irqsave(&device_info->lock, flags);
list_for_each_entry(b, &device_info->safe_buffers, node)
if (b->safe_dma_addr == safe_dma_addr)
- return b;
+ break;
- return NULL;
+ read_unlock_irqrestore(&device_info->lock, flags);
+ return b;
}
static inline void
free_safe_buffer(struct dmabounce_device_info *device_info, struct safe_buffer *buf)
{
+ unsigned long flags;
+
dev_dbg(device_info->dev, "%s(buf=%p)\n", __func__, buf);
+ write_lock_irqsave(&device_info->lock, flags);
+
list_del(&buf->node);
+ write_unlock_irqrestore(&device_info->lock, flags);
+
if (buf->pool)
dma_pool_free(buf->pool->pool, buf->safe, buf->safe_dma_addr);
else
@@ -396,7 +413,6 @@ dma_addr_t
dma_map_single(struct device *dev, void *ptr, size_t size,
enum dma_data_direction dir)
{
- unsigned long flags;
dma_addr_t dma_addr;
dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
@@ -404,12 +420,8 @@ dma_map_single(struct device *dev, void *ptr, size_t size,
BUG_ON(dir == DMA_NONE);
- local_irq_save(flags);
-
dma_addr = map_single(dev, ptr, size, dir);
- local_irq_restore(flags);
-
return dma_addr;
}
@@ -424,25 +436,18 @@ void
dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
enum dma_data_direction dir)
{
- unsigned long flags;
-
dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
__func__, (void *) dma_addr, size, dir);
BUG_ON(dir == DMA_NONE);
- local_irq_save(flags);
-
unmap_single(dev, dma_addr, size, dir);
-
- local_irq_restore(flags);
}
int
dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
enum dma_data_direction dir)
{
- unsigned long flags;
int i;
dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n",
@@ -450,8 +455,6 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
BUG_ON(dir == DMA_NONE);
- local_irq_save(flags);
-
for (i = 0; i < nents; i++, sg++) {
struct page *page = sg->page;
unsigned int offset = sg->offset;
@@ -462,8 +465,6 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
map_single(dev, ptr, length, dir);
}
- local_irq_restore(flags);
-
return nents;
}
@@ -471,7 +472,6 @@ void
dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
enum dma_data_direction dir)
{
- unsigned long flags;
int i;
dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n",
@@ -479,55 +479,38 @@ dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
BUG_ON(dir == DMA_NONE);
- local_irq_save(flags);
-
for (i = 0; i < nents; i++, sg++) {
dma_addr_t dma_addr = sg->dma_address;
unsigned int length = sg->length;
unmap_single(dev, dma_addr, length, dir);
}
-
- local_irq_restore(flags);
}
void
dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_addr, size_t size,
enum dma_data_direction dir)
{
- unsigned long flags;
-
dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
__func__, (void *) dma_addr, size, dir);
- local_irq_save(flags);
-
sync_single(dev, dma_addr, size, dir);
-
- local_irq_restore(flags);
}
void
dma_sync_single_for_device(struct device *dev, dma_addr_t dma_addr, size_t size,
enum dma_data_direction dir)
{
- unsigned long flags;
-
dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
__func__, (void *) dma_addr, size, dir);
- local_irq_save(flags);
-
sync_single(dev, dma_addr, size, dir);
-
- local_irq_restore(flags);
}
void
dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents,
enum dma_data_direction dir)
{
- unsigned long flags;
int i;
dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n",
@@ -535,23 +518,18 @@ dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents,
BUG_ON(dir == DMA_NONE);
- local_irq_save(flags);
-
for (i = 0; i < nents; i++, sg++) {
dma_addr_t dma_addr = sg->dma_address;
unsigned int length = sg->length;
sync_single(dev, dma_addr, length, dir);
}
-
- local_irq_restore(flags);
}
void
dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents,
enum dma_data_direction dir)
{
- unsigned long flags;
int i;
dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n",
@@ -559,16 +537,12 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents,
BUG_ON(dir == DMA_NONE);
- local_irq_save(flags);
-
for (i = 0; i < nents; i++, sg++) {
dma_addr_t dma_addr = sg->dma_address;
unsigned int length = sg->length;
sync_single(dev, dma_addr, length, dir);
}
-
- local_irq_restore(flags);
}
static int
@@ -622,6 +596,7 @@ dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size,
device_info->dev = dev;
INIT_LIST_HEAD(&device_info->safe_buffers);
+ rwlock_init(&device_info->lock);
#ifdef STATS
device_info->total_allocs = 0;
diff --git a/arch/arm/common/uengine.c b/arch/arm/common/uengine.c
index a1310b7..dfca596 100644
--- a/arch/arm/common/uengine.c
+++ b/arch/arm/common/uengine.c
@@ -18,10 +18,26 @@
#include <linux/module.h>
#include <linux/string.h>
#include <asm/hardware.h>
-#include <asm/arch/ixp2000-regs.h>
+#include <asm/arch/hardware.h>
#include <asm/hardware/uengine.h>
#include <asm/io.h>
+#if defined(CONFIG_ARCH_IXP2000)
+#define IXP_UENGINE_CSR_VIRT_BASE IXP2000_UENGINE_CSR_VIRT_BASE
+#define IXP_PRODUCT_ID IXP2000_PRODUCT_ID
+#define IXP_MISC_CONTROL IXP2000_MISC_CONTROL
+#define IXP_RESET1 IXP2000_RESET1
+#else
+#if defined(CONFIG_ARCH_IXP23XX)
+#define IXP_UENGINE_CSR_VIRT_BASE IXP23XX_UENGINE_CSR_VIRT_BASE
+#define IXP_PRODUCT_ID IXP23XX_PRODUCT_ID
+#define IXP_MISC_CONTROL IXP23XX_MISC_CONTROL
+#define IXP_RESET1 IXP23XX_RESET1
+#else
+#error unknown platform
+#endif
+#endif
+
#define USTORE_ADDRESS 0x000
#define USTORE_DATA_LOWER 0x004
#define USTORE_DATA_UPPER 0x008
@@ -43,7 +59,7 @@ u32 ixp2000_uengine_mask;
static void *ixp2000_uengine_csr_area(int uengine)
{
- return ((void *)IXP2000_UENGINE_CSR_VIRT_BASE) + (uengine << 10);
+ return ((void *)IXP_UENGINE_CSR_VIRT_BASE) + (uengine << 10);
}
/*
@@ -91,8 +107,13 @@ EXPORT_SYMBOL(ixp2000_uengine_csr_write);
void ixp2000_uengine_reset(u32 uengine_mask)
{
- ixp2000_reg_wrb(IXP2000_RESET1, uengine_mask & ixp2000_uengine_mask);
- ixp2000_reg_wrb(IXP2000_RESET1, 0);
+ u32 value;
+
+ value = ixp2000_reg_read(IXP_RESET1) & ~ixp2000_uengine_mask;
+
+ uengine_mask &= ixp2000_uengine_mask;
+ ixp2000_reg_wrb(IXP_RESET1, value | uengine_mask);
+ ixp2000_reg_wrb(IXP_RESET1, value);
}
EXPORT_SYMBOL(ixp2000_uengine_reset);
@@ -235,11 +256,12 @@ static int check_ixp_type(struct ixp2000_uengine_code *c)
u32 product_id;
u32 rev;
- product_id = ixp2000_reg_read(IXP2000_PRODUCT_ID);
+ product_id = ixp2000_reg_read(IXP_PRODUCT_ID);
if (((product_id >> 16) & 0x1f) != 0)
return 0;
switch ((product_id >> 8) & 0xff) {
+#ifdef CONFIG_ARCH_IXP2000
case 0: /* IXP2800 */
if (!(c->cpu_model_bitmask & 4))
return 0;
@@ -254,6 +276,14 @@ static int check_ixp_type(struct ixp2000_uengine_code *c)
if (!(c->cpu_model_bitmask & 2))
return 0;
break;
+#endif
+
+#ifdef CONFIG_ARCH_IXP23XX
+ case 4: /* IXP23xx */
+ if (!(c->cpu_model_bitmask & 0x3f0))
+ return 0;
+ break;
+#endif
default:
return 0;
@@ -432,7 +462,8 @@ static int __init ixp2000_uengine_init(void)
/*
* Determine number of microengines present.
*/
- switch ((ixp2000_reg_read(IXP2000_PRODUCT_ID) >> 8) & 0x1fff) {
+ switch ((ixp2000_reg_read(IXP_PRODUCT_ID) >> 8) & 0x1fff) {
+#ifdef CONFIG_ARCH_IXP2000
case 0: /* IXP2800 */
case 1: /* IXP2850 */
ixp2000_uengine_mask = 0x00ff00ff;
@@ -441,10 +472,17 @@ static int __init ixp2000_uengine_init(void)
case 2: /* IXP2400 */
ixp2000_uengine_mask = 0x000f000f;
break;
+#endif
+
+#ifdef CONFIG_ARCH_IXP23XX
+ case 4: /* IXP23xx */
+ ixp2000_uengine_mask = (*IXP23XX_EXP_CFG_FUSE >> 8) & 0xf;
+ break;
+#endif
default:
printk(KERN_INFO "Detected unknown IXP2000 model (%.8x)\n",
- (unsigned int)ixp2000_reg_read(IXP2000_PRODUCT_ID));
+ (unsigned int)ixp2000_reg_read(IXP_PRODUCT_ID));
ixp2000_uengine_mask = 0x00000000;
break;
}
@@ -457,15 +495,15 @@ static int __init ixp2000_uengine_init(void)
/*
* Synchronise timestamp counters across all microengines.
*/
- value = ixp2000_reg_read(IXP2000_MISC_CONTROL);
- ixp2000_reg_wrb(IXP2000_MISC_CONTROL, value & ~0x80);
+ value = ixp2000_reg_read(IXP_MISC_CONTROL);
+ ixp2000_reg_wrb(IXP_MISC_CONTROL, value & ~0x80);
for (uengine = 0; uengine < 32; uengine++) {
if (ixp2000_uengine_mask & (1 << uengine)) {
ixp2000_uengine_csr_write(uengine, TIMESTAMP_LOW, 0);
ixp2000_uengine_csr_write(uengine, TIMESTAMP_HIGH, 0);
}
}
- ixp2000_reg_wrb(IXP2000_MISC_CONTROL, value | 0x80);
+ ixp2000_reg_wrb(IXP_MISC_CONTROL, value | 0x80);
return 0;
}
diff --git a/arch/arm/configs/lpd270_defconfig b/arch/arm/configs/lpd270_defconfig
new file mode 100644
index 0000000..d08bbe5
--- /dev/null
+++ b/arch/arm/configs/lpd270_defconfig
@@ -0,0 +1,963 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.17-git2
+# Wed Jun 21 22:20:18 2006
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_MTD_XIP=y
+CONFIG_VECTORS_BASE=0xffff0000
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_UID16=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91RM9200 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PNX4008 is not set
+CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+
+#
+# Intel PXA2xx Implementations
+#
+# CONFIG_ARCH_LUBBOCK is not set
+CONFIG_MACH_LOGICPD_PXA270=y
+# CONFIG_MACH_MAINSTONE is not set
+# CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_PXA_SHARPSL is not set
+CONFIG_PXA27x=y
+CONFIG_IWMMXT=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+CONFIG_XSCALE_PMU=y
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/nfs ip=bootp console=ttyS0,115200 mem=64M"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+# CONFIG_PACKET is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+# CONFIG_MTD_CFI_I1 is not set
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_XIP is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_SHARP_SL is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_IDE_GENERIC is not set
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+# CONFIG_SMC911X is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_PXA=y
+CONFIG_SERIAL_PXA_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_FIRMWARE_EDID=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_PXA=y
+# CONFIG_FB_PXA_PARAMETERS is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_AC97_CODEC=y
+CONFIG_SND_AC97_BUS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA ARM devices
+#
+CONFIG_SND_PXA2XX_PCM=y
+CONFIG_SND_PXA2XX_AC97=y
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_VFAT_FS is not set
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_UNWIND_INFO is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index de606df..302fc14 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -702,7 +702,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
/*
* Mark this as IO
*/
- vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
if (remap_pfn_range(vma, vma->vm_start, phys,
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index ab8e600..86c9252 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -20,6 +20,7 @@
#include <asm/glue.h>
#include <asm/vfpmacros.h>
#include <asm/arch/entry-macro.S>
+#include <asm/thread_notify.h>
#include "entry-header.S"
@@ -560,10 +561,8 @@ ENTRY(__switch_to)
add ip, r1, #TI_CPU_SAVE
ldr r3, [r2, #TI_TP_VALUE]
stmia ip!, {r4 - sl, fp, sp, lr} @ Store most regs on stack
-#ifndef CONFIG_MMU
- add r2, r2, #TI_CPU_DOMAIN
-#else
- ldr r6, [r2, #TI_CPU_DOMAIN]!
+#ifdef CONFIG_MMU
+ ldr r6, [r2, #TI_CPU_DOMAIN]
#endif
#if __LINUX_ARM_ARCH__ >= 6
#ifdef CONFIG_CPU_32v6K
@@ -585,21 +584,20 @@ ENTRY(__switch_to)
#ifdef CONFIG_MMU
mcr p15, 0, r6, c3, c0, 0 @ Set domain register
#endif
-#ifdef CONFIG_VFP
- @ Always disable VFP so we can lazily save/restore the old
- @ state. This occurs in the context of the previous thread.
- VFPFMRX r4, FPEXC
- bic r4, r4, #FPEXC_ENABLE
- VFPFMXR FPEXC, r4
-#endif
#if defined(CONFIG_IWMMXT)
bl iwmmxt_task_switch
#elif defined(CONFIG_CPU_XSCALE)
- add r4, r2, #40 @ cpu_context_save->extra
+ add r4, r2, #TI_CPU_DOMAIN + 40 @ cpu_context_save->extra
ldmib r4, {r4, r5}
mar acc0, r4, r5
#endif
- ldmib r2, {r4 - sl, fp, sp, pc} @ Load all regs saved previously
+ mov r5, r0
+ add r4, r2, #TI_CPU_SAVE
+ ldr r0, =thread_notify_head
+ mov r1, #THREAD_NOTIFY_SWITCH
+ bl atomic_notifier_call_chain
+ mov r0, r5
+ ldmia r4, {r4 - sl, fp, sp, pc} @ Load all regs saved previously
__INIT
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index bcc19fb..ec20f89 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -52,7 +52,7 @@
*/
#define MAX_IRQ_CNT 100000
-static int noirqdebug;
+static int noirqdebug __read_mostly;
static volatile unsigned long irq_err_count;
static DEFINE_SPINLOCK(irq_controller_lock);
static LIST_HEAD(irq_pending);
@@ -81,7 +81,7 @@ irqreturn_t no_action(int irq, void *dev_id, struct pt_regs *regs)
void do_bad_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
{
- irq_err_count += 1;
+ irq_err_count++;
printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq);
}
diff --git a/arch/arm/kernel/iwmmxt.S b/arch/arm/kernel/iwmmxt.S
index 24c7b04..a3bae95 100644
--- a/arch/arm/kernel/iwmmxt.S
+++ b/arch/arm/kernel/iwmmxt.S
@@ -273,7 +273,7 @@ ENTRY(iwmmxt_task_restore)
*
* r0 = previous task_struct pointer (must be preserved)
* r1 = previous thread_info pointer
- * r2 = next thread_info.cpu_domain pointer (must be preserved)
+ * r2 = next thread_info pointer (must be preserved)
*
* Called only from __switch_to with task preemption disabled.
* No need to care about preserving r4 and above.
@@ -285,7 +285,7 @@ ENTRY(iwmmxt_task_switch)
bne 1f @ yes: block them for next task
ldr r5, =concan_owner
- add r6, r2, #(TI_IWMMXT_STATE - TI_CPU_DOMAIN) @ get next task Concan save area
+ add r6, r2, #TI_IWMMXT_STATE @ get next task Concan save area
ldr r5, [r5] @ get current Concan owner
teq r5, r6 @ next task owns it?
movne pc, lr @ no: leave Concan disabled
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 17c38db..e1c77ee 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -33,6 +33,7 @@
#include <asm/leds.h>
#include <asm/processor.h>
#include <asm/system.h>
+#include <asm/thread_notify.h>
#include <asm/uaccess.h>
#include <asm/mach/time.h>
@@ -338,13 +339,9 @@ void exit_thread(void)
{
}
-static void default_fp_init(union fp_state *fp)
-{
- memset(fp, 0, sizeof(union fp_state));
-}
+ATOMIC_NOTIFIER_HEAD(thread_notify_head);
-void (*fp_init)(union fp_state *) = default_fp_init;
-EXPORT_SYMBOL(fp_init);
+EXPORT_SYMBOL_GPL(thread_notify_head);
void flush_thread(void)
{
@@ -353,22 +350,21 @@ void flush_thread(void)
memset(thread->used_cp, 0, sizeof(thread->used_cp));
memset(&tsk->thread.debug, 0, sizeof(struct debug_info));
+ memset(&thread->fpstate, 0, sizeof(union fp_state));
+
+ thread_notify(THREAD_NOTIFY_FLUSH, thread);
#if defined(CONFIG_IWMMXT)
iwmmxt_task_release(thread);
#endif
- fp_init(&thread->fpstate);
-#if defined(CONFIG_VFP)
- vfp_flush_thread(&thread->vfpstate);
-#endif
}
void release_thread(struct task_struct *dead_task)
{
-#if defined(CONFIG_VFP)
- vfp_release_thread(&task_thread_info(dead_task)->vfpstate);
-#endif
+ struct thread_info *thread = task_thread_info(dead_task);
+
+ thread_notify(THREAD_NOTIFY_RELEASE, thread);
#if defined(CONFIG_IWMMXT)
- iwmmxt_task_release(task_thread_info(dead_task));
+ iwmmxt_task_release(thread);
#endif
}
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index a0cd0a9..1ce05ec 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -134,17 +134,6 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
#ifdef CONFIG_IWMMXT
-/* iwmmxt_area is 0x98 bytes long, preceeded by 8 bytes of signature */
-#define IWMMXT_STORAGE_SIZE (0x98 + 8)
-#define IWMMXT_MAGIC0 0x12ef842a
-#define IWMMXT_MAGIC1 0x1c07ca71
-
-struct iwmmxt_sigframe {
- unsigned long magic0;
- unsigned long magic1;
- unsigned long storage[0x98/4];
-};
-
static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame)
{
char kbuf[sizeof(*frame) + 8];
@@ -152,8 +141,8 @@ static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame)
/* the iWMMXt context must be 64 bit aligned */
kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7);
- kframe->magic0 = IWMMXT_MAGIC0;
- kframe->magic1 = IWMMXT_MAGIC1;
+ kframe->magic = IWMMXT_MAGIC;
+ kframe->size = IWMMXT_STORAGE_SIZE;
iwmmxt_task_copy(current_thread_info(), &kframe->storage);
return __copy_to_user(frame, kframe, sizeof(*frame));
}
@@ -167,8 +156,8 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame)
kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7);
if (__copy_from_user(kframe, frame, sizeof(*frame)))
return -1;
- if (kframe->magic0 != IWMMXT_MAGIC0 ||
- kframe->magic1 != IWMMXT_MAGIC1)
+ if (kframe->magic != IWMMXT_MAGIC ||
+ kframe->size != IWMMXT_STORAGE_SIZE)
return -1;
iwmmxt_task_restore(current_thread_info(), &kframe->storage);
return 0;
@@ -177,70 +166,61 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame)
#endif
/*
- * Auxiliary signal frame. This saves stuff like FP state.
- * The layout of this structure is not part of the user ABI.
- */
-struct aux_sigframe {
-#ifdef CONFIG_IWMMXT
- struct iwmmxt_sigframe iwmmxt;
-#endif
-#ifdef CONFIG_VFP
- union vfp_state vfp;
-#endif
-};
-
-/*
* Do a signal return; undo the signal stack. These are aligned to 64-bit.
*/
struct sigframe {
- struct sigcontext sc;
- unsigned long extramask[_NSIG_WORDS-1];
+ struct ucontext uc;
unsigned long retcode[2];
- struct aux_sigframe aux __attribute__((aligned(8)));
};
struct rt_sigframe {
- struct siginfo __user *pinfo;
- void __user *puc;
struct siginfo info;
- struct ucontext uc;
- unsigned long retcode[2];
- struct aux_sigframe aux __attribute__((aligned(8)));
+ struct sigframe sig;
};
-static int
-restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
- struct aux_sigframe __user *aux)
+static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf)
{
- int err = 0;
+ struct aux_sigframe __user *aux;
+ sigset_t set;
+ int err;
- __get_user_error(regs->ARM_r0, &sc->arm_r0, err);
- __get_user_error(regs->ARM_r1, &sc->arm_r1, err);
- __get_user_error(regs->ARM_r2, &sc->arm_r2, err);
- __get_user_error(regs->ARM_r3, &sc->arm_r3, err);
- __get_user_error(regs->ARM_r4, &sc->arm_r4, err);
- __get_user_error(regs->ARM_r5, &sc->arm_r5, err);
- __get_user_error(regs->ARM_r6, &sc->arm_r6, err);
- __get_user_error(regs->ARM_r7, &sc->arm_r7, err);
- __get_user_error(regs->ARM_r8, &sc->arm_r8, err);
- __get_user_error(regs->ARM_r9, &sc->arm_r9, err);
- __get_user_error(regs->ARM_r10, &sc->arm_r10, err);
- __get_user_error(regs->ARM_fp, &sc->arm_fp, err);
- __get_user_error(regs->ARM_ip, &sc->arm_ip, err);
- __get_user_error(regs->ARM_sp, &sc->arm_sp, err);
- __get_user_error(regs->ARM_lr, &sc->arm_lr, err);
- __get_user_error(regs->ARM_pc, &sc->arm_pc, err);
- __get_user_error(regs->ARM_cpsr, &sc->arm_cpsr, err);
+ err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));
+ if (err == 0) {
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sighand->siglock);
+ current->blocked = set;
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+ }
+
+ __get_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err);
+ __get_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err);
+ __get_user_error(regs->ARM_r2, &sf->uc.uc_mcontext.arm_r2, err);
+ __get_user_error(regs->ARM_r3, &sf->uc.uc_mcontext.arm_r3, err);
+ __get_user_error(regs->ARM_r4, &sf->uc.uc_mcontext.arm_r4, err);
+ __get_user_error(regs->ARM_r5, &sf->uc.uc_mcontext.arm_r5, err);
+ __get_user_error(regs->ARM_r6, &sf->uc.uc_mcontext.arm_r6, err);
+ __get_user_error(regs->ARM_r7, &sf->uc.uc_mcontext.arm_r7, err);
+ __get_user_error(regs->ARM_r8, &sf->uc.uc_mcontext.arm_r8, err);
+ __get_user_error(regs->ARM_r9, &sf->uc.uc_mcontext.arm_r9, err);
+ __get_user_error(regs->ARM_r10, &sf->uc.uc_mcontext.arm_r10, err);
+ __get_user_error(regs->ARM_fp, &sf->uc.uc_mcontext.arm_fp, err);
+ __get_user_error(regs->ARM_ip, &sf->uc.uc_mcontext.arm_ip, err);
+ __get_user_error(regs->ARM_sp, &sf->uc.uc_mcontext.arm_sp, err);
+ __get_user_error(regs->ARM_lr, &sf->uc.uc_mcontext.arm_lr, err);
+ __get_user_error(regs->ARM_pc, &sf->uc.uc_mcontext.arm_pc, err);
+ __get_user_error(regs->ARM_cpsr, &sf->uc.uc_mcontext.arm_cpsr, err);
err |= !valid_user_regs(regs);
+ aux = (struct aux_sigframe __user *) sf->uc.uc_regspace;
#ifdef CONFIG_IWMMXT
if (err == 0 && test_thread_flag(TIF_USING_IWMMXT))
err |= restore_iwmmxt_context(&aux->iwmmxt);
#endif
#ifdef CONFIG_VFP
// if (err == 0)
-// err |= vfp_restore_state(&aux->vfp);
+// err |= vfp_restore_state(&sf->aux.vfp);
#endif
return err;
@@ -249,7 +229,6 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
asmlinkage int sys_sigreturn(struct pt_regs *regs)
{
struct sigframe __user *frame;
- sigset_t set;
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
@@ -266,19 +245,8 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs)
if (!access_ok(VERIFY_READ, frame, sizeof (*frame)))
goto badframe;
- if (__get_user(set.sig[0], &frame->sc.oldmask)
- || (_NSIG_WORDS > 1
- && __copy_from_user(&set.sig[1], &frame->extramask,
- sizeof(frame->extramask))))
- goto badframe;
- sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
- if (restore_sigcontext(regs, &frame->sc, &frame->aux))
+ if (restore_sigframe(regs, frame))
goto badframe;
/* Send SIGTRAP if we're single-stepping */
@@ -297,7 +265,6 @@ badframe:
asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
- sigset_t set;
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
@@ -314,19 +281,11 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
if (!access_ok(VERIFY_READ, frame, sizeof (*frame)))
goto badframe;
- if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
- goto badframe;
- sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
- if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &frame->aux))
+ if (restore_sigframe(regs, &frame->sig))
goto badframe;
- if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT)
+ if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT)
goto badframe;
/* Send SIGTRAP if we're single-stepping */
@@ -343,42 +302,46 @@ badframe:
}
static int
-setup_sigcontext(struct sigcontext __user *sc, struct aux_sigframe __user *aux,
- struct pt_regs *regs, unsigned long mask)
+setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set)
{
+ struct aux_sigframe __user *aux;
int err = 0;
- __put_user_error(regs->ARM_r0, &sc->arm_r0, err);
- __put_user_error(regs->ARM_r1, &sc->arm_r1, err);
- __put_user_error(regs->ARM_r2, &sc->arm_r2, err);
- __put_user_error(regs->ARM_r3, &sc->arm_r3, err);
- __put_user_error(regs->ARM_r4, &sc->arm_r4, err);
- __put_user_error(regs->ARM_r5, &sc->arm_r5, err);
- __put_user_error(regs->ARM_r6, &sc->arm_r6, err);
- __put_user_error(regs->ARM_r7, &sc->arm_r7, err);
- __put_user_error(regs->ARM_r8, &sc->arm_r8, err);
- __put_user_error(regs->ARM_r9, &sc->arm_r9, err);
- __put_user_error(regs->ARM_r10, &sc->arm_r10, err);
- __put_user_error(regs->ARM_fp, &sc->arm_fp, err);
- __put_user_error(regs->ARM_ip, &sc->arm_ip, err);
- __put_user_error(regs->ARM_sp, &sc->arm_sp, err);
- __put_user_error(regs->ARM_lr, &sc->arm_lr, err);
- __put_user_error(regs->ARM_pc, &sc->arm_pc, err);
- __put_user_error(regs->ARM_cpsr, &sc->arm_cpsr, err);
-
- __put_user_error(current->thread.trap_no, &sc->trap_no, err);
- __put_user_error(current->thread.error_code, &sc->error_code, err);
- __put_user_error(current->thread.address, &sc->fault_address, err);
- __put_user_error(mask, &sc->oldmask, err);
-
+ __put_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err);
+ __put_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err);
+ __put_user_error(regs->ARM_r2, &sf->uc.uc_mcontext.arm_r2, err);
+ __put_user_error(regs->ARM_r3, &sf->uc.uc_mcontext.arm_r3, err);
+ __put_user_error(regs->ARM_r4, &sf->uc.uc_mcontext.arm_r4, err);
+ __put_user_error(regs->ARM_r5, &sf->uc.uc_mcontext.arm_r5, err);
+ __put_user_error(regs->ARM_r6, &sf->uc.uc_mcontext.arm_r6, err);
+ __put_user_error(regs->ARM_r7, &sf->uc.uc_mcontext.arm_r7, err);
+ __put_user_error(regs->ARM_r8, &sf->uc.uc_mcontext.arm_r8, err);
+ __put_user_error(regs->ARM_r9, &sf->uc.uc_mcontext.arm_r9, err);
+ __put_user_error(regs->ARM_r10, &sf->uc.uc_mcontext.arm_r10, err);
+ __put_user_error(regs->ARM_fp, &sf->uc.uc_mcontext.arm_fp, err);
+ __put_user_error(regs->ARM_ip, &sf->uc.uc_mcontext.arm_ip, err);
+ __put_user_error(regs->ARM_sp, &sf->uc.uc_mcontext.arm_sp, err);
+ __put_user_error(regs->ARM_lr, &sf->uc.uc_mcontext.arm_lr, err);
+ __put_user_error(regs->ARM_pc, &sf->uc.uc_mcontext.arm_pc, err);
+ __put_user_error(regs->ARM_cpsr, &sf->uc.uc_mcontext.arm_cpsr, err);
+
+ __put_user_error(current->thread.trap_no, &sf->uc.uc_mcontext.trap_no, err);
+ __put_user_error(current->thread.error_code, &sf->uc.uc_mcontext.error_code, err);
+ __put_user_error(current->thread.address, &sf->uc.uc_mcontext.fault_address, err);
+ __put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err);
+
+ err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
+
+ aux = (struct aux_sigframe __user *) sf->uc.uc_regspace;
#ifdef CONFIG_IWMMXT
if (err == 0 && test_thread_flag(TIF_USING_IWMMXT))
err |= preserve_iwmmxt_context(&aux->iwmmxt);
#endif
#ifdef CONFIG_VFP
// if (err == 0)
-// err |= vfp_save_state(&aux->vfp);
+// err |= vfp_save_state(&sf->aux.vfp);
#endif
+ __put_user_error(0, &aux->end_magic, err);
return err;
}
@@ -487,13 +450,12 @@ setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *reg
if (!frame)
return 1;
- err |= setup_sigcontext(&frame->sc, &frame->aux, regs, set->sig[0]);
-
- if (_NSIG_WORDS > 1) {
- err |= __copy_to_user(frame->extramask, &set->sig[1],
- sizeof(frame->extramask));
- }
+ /*
+ * Set uc.uc_flags to a value which sc.trap_no would never have.
+ */
+ __put_user_error(0x5ac3c35a, &frame->uc.uc_flags, err);
+ err |= setup_sigframe(frame, regs, set);
if (err == 0)
err = setup_return(regs, ka, frame->retcode, frame, usig);
@@ -511,25 +473,20 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
if (!frame)
return 1;
- __put_user_error(&frame->info, &frame->pinfo, err);
- __put_user_error(&frame->uc, &frame->puc, err);
err |= copy_siginfo_to_user(&frame->info, info);
- __put_user_error(0, &frame->uc.uc_flags, err);
- __put_user_error(NULL, &frame->uc.uc_link, err);
+ __put_user_error(0, &frame->sig.uc.uc_flags, err);
+ __put_user_error(NULL, &frame->sig.uc.uc_link, err);
memset(&stack, 0, sizeof(stack));
stack.ss_sp = (void __user *)current->sas_ss_sp;
stack.ss_flags = sas_ss_flags(regs->ARM_sp);
stack.ss_size = current->sas_ss_size;
- err |= __copy_to_user(&frame->uc.uc_stack, &stack, sizeof(stack));
-
- err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->aux,
- regs, set->sig[0]);
- err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+ err |= __copy_to_user(&frame->sig.uc.uc_stack, &stack, sizeof(stack));
+ err |= setup_sigframe(&frame->sig, regs, set);
if (err == 0)
- err = setup_return(regs, ka, frame->retcode, frame, usig);
+ err = setup_return(regs, ka, frame->sig.retcode, frame, usig);
if (err == 0) {
/*
@@ -538,7 +495,7 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
* -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06
*/
regs->ARM_r1 = (unsigned long)&frame->info;
- regs->ARM_r2 = (unsigned long)&frame->uc;
+ regs->ARM_r2 = (unsigned long)&frame->sig.uc;
}
return err;
@@ -665,17 +622,33 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
if (syscall) {
if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) {
if (thumb_mode(regs)) {
- regs->ARM_r7 = __NR_restart_syscall;
+ regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE;
regs->ARM_pc -= 2;
} else {
+#if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT)
+ regs->ARM_r7 = __NR_restart_syscall;
+ regs->ARM_pc -= 4;
+#else
u32 __user *usp;
+ u32 swival = __NR_restart_syscall;
regs->ARM_sp -= 12;
usp = (u32 __user *)regs->ARM_sp;
+ /*
+ * Either we supports OABI only, or we have
+ * EABI with the OABI compat layer enabled.
+ * In the later case we don't know if user
+ * space is EABI or not, and if not we must
+ * not clobber r7. Always using the OABI
+ * syscall solves that issue and works for
+ * all those cases.
+ */
+ swival = swival - __NR_SYSCALL_BASE + __NR_OABI_SYSCALL_BASE;
+
put_user(regs->ARM_pc, &usp[0]);
/* swi __NR_restart_syscall */
- put_user(0xef000000 | __NR_restart_syscall, &usp[1]);
+ put_user(0xef000000 | swival, &usp[1]);
/* ldr pc, [sp], #12 */
put_user(0xe49df00c, &usp[2]);
@@ -683,6 +656,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
(unsigned long)(usp + 3));
regs->ARM_pc = regs->ARM_sp + 4;
+#endif
}
}
if (regs->ARM_r0 == -ERESTARTNOHAND ||
diff --git a/arch/arm/mach-ep93xx/Makefile b/arch/arm/mach-ep93xx/Makefile
index 5393af9..05a48a2 100644
--- a/arch/arm/mach-ep93xx/Makefile
+++ b/arch/arm/mach-ep93xx/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for the linux kernel.
#
-obj-y := core.o
+obj-y := core.o clock.o
obj-m :=
obj-n :=
obj- :=
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
new file mode 100644
index 0000000..08ad782
--- /dev/null
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -0,0 +1,156 @@
+/*
+ * arch/arm/mach-ep93xx/clock.c
+ * Clock control for Cirrus EP93xx chips.
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <asm/div64.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+
+struct clk {
+ char *name;
+ unsigned long rate;
+ int users;
+ u32 enable_reg;
+ u32 enable_mask;
+};
+
+static struct clk clk_pll1 = {
+ .name = "pll1",
+};
+static struct clk clk_f = {
+ .name = "fclk",
+};
+static struct clk clk_h = {
+ .name = "hclk",
+};
+static struct clk clk_p = {
+ .name = "pclk",
+};
+static struct clk clk_pll2 = {
+ .name = "pll2",
+};
+static struct clk clk_usb_host = {
+ .name = "usb_host",
+ .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL,
+ .enable_mask = EP93XX_SYSCON_CLOCK_USH_EN,
+};
+
+
+static struct clk *clocks[] = {
+ &clk_pll1,
+ &clk_f,
+ &clk_h,
+ &clk_p,
+ &clk_pll2,
+ &clk_usb_host,
+};
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(clocks); i++) {
+ if (!strcmp(clocks[i]->name, id))
+ return clocks[i];
+ }
+
+ return ERR_PTR(-ENOENT);
+}
+
+int clk_enable(struct clk *clk)
+{
+ if (!clk->users++ && clk->enable_reg) {
+ u32 value;
+
+ value = __raw_readl(clk->enable_reg);
+ __raw_writel(value | clk->enable_mask, clk->enable_reg);
+ }
+
+ return 0;
+}
+
+void clk_disable(struct clk *clk)
+{
+ if (!--clk->users && clk->enable_reg) {
+ u32 value;
+
+ value = __raw_readl(clk->enable_reg);
+ __raw_writel(value & ~clk->enable_mask, clk->enable_reg);
+ }
+}
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ return clk->rate;
+}
+
+void clk_put(struct clk *clk)
+{
+}
+
+
+
+static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 };
+static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 };
+static char pclk_divisors[] = { 1, 2, 4, 8 };
+
+/*
+ * PLL rate = 14.7456 MHz * (X1FBD + 1) * (X2FBD + 1) / (X2IPD + 1) / 2^PS
+ */
+static unsigned long calc_pll_rate(u32 config_word)
+{
+ unsigned long long rate;
+ int i;
+
+ rate = 14745600;
+ rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */
+ rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */
+ do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */
+ for (i = 0; i < ((config_word >> 16) & 3); i++) /* PS */
+ rate >>= 1;
+
+ return (unsigned long)rate;
+}
+
+void ep93xx_clock_init(void)
+{
+ u32 value;
+
+ value = __raw_readl(EP93XX_SYSCON_CLOCK_SET1);
+ if (!(value & 0x00800000)) { /* PLL1 bypassed? */
+ clk_pll1.rate = 14745600;
+ } else {
+ clk_pll1.rate = calc_pll_rate(value);
+ }
+ clk_f.rate = clk_pll1.rate / fclk_divisors[(value >> 25) & 0x7];
+ clk_h.rate = clk_pll1.rate / hclk_divisors[(value >> 20) & 0x7];
+ clk_p.rate = clk_h.rate / pclk_divisors[(value >> 18) & 0x3];
+
+ value = __raw_readl(EP93XX_SYSCON_CLOCK_SET2);
+ if (!(value & 0x00080000)) { /* PLL2 bypassed? */
+ clk_pll2.rate = 14745600;
+ } else if (value & 0x00040000) { /* PLL2 enabled? */
+ clk_pll2.rate = calc_pll_rate(value);
+ } else {
+ clk_pll2.rate = 0;
+ }
+ clk_usb_host.rate = clk_pll2.rate / (((value >> 28) & 0xf) + 1);
+
+ printk(KERN_INFO "ep93xx: PLL1 running at %ld MHz, PLL2 at %ld MHz\n",
+ clk_pll1.rate / 1000000, clk_pll2.rate / 1000000);
+ printk(KERN_INFO "ep93xx: FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n",
+ clk_f.rate / 1000000, clk_h.rate / 1000000,
+ clk_p.rate / 1000000);
+}
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index dcd4176..1fe73c0 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -103,7 +103,8 @@ static int ep93xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
write_seqlock(&xtime_lock);
__raw_writel(1, EP93XX_TIMER1_CLEAR);
- while (__raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time
+ while ((signed long)
+ (__raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time)
>= TIMER4_TICKS_PER_JIFFY) {
last_jiffy_time += TIMER4_TICKS_PER_JIFFY;
timer_tick(regs);
@@ -124,7 +125,7 @@ static void __init ep93xx_timer_init(void)
{
/* Enable periodic HZ timer. */
__raw_writel(0x48, EP93XX_TIMER1_CONTROL);
- __raw_writel((508000 / HZ) - 1, EP93XX_TIMER1_LOAD);
+ __raw_writel((508469 / HZ) - 1, EP93XX_TIMER1_LOAD);
__raw_writel(0xc8, EP93XX_TIMER1_CONTROL);
/* Enable lost jiffy timer. */
@@ -432,10 +433,37 @@ static struct platform_device ep93xx_rtc_device = {
};
+static struct resource ep93xx_ohci_resources[] = {
+ [0] = {
+ .start = EP93XX_USB_PHYS_BASE,
+ .end = EP93XX_USB_PHYS_BASE + 0x0fff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_EP93XX_USB,
+ .end = IRQ_EP93XX_USB,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device ep93xx_ohci_device = {
+ .name = "ep93xx-ohci",
+ .id = -1,
+ .dev = {
+ .dma_mask = (void *)0xffffffff,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(ep93xx_ohci_resources),
+ .resource = ep93xx_ohci_resources,
+};
+
+
void __init ep93xx_init_devices(void)
{
unsigned int v;
+ ep93xx_clock_init();
+
/*
* Disallow access to MaverickCrunch initially.
*/
@@ -449,4 +477,5 @@ void __init ep93xx_init_devices(void)
amba_device_register(&uart3_device, &iomem_resource);
platform_device_register(&ep93xx_rtc_device);
+ platform_device_register(&ep93xx_ohci_device);
}
diff --git a/arch/arm/mach-ep93xx/gesbc9312.c b/arch/arm/mach-ep93xx/gesbc9312.c
index d18fcb1..47cc6c8 100644
--- a/arch/arm/mach-ep93xx/gesbc9312.c
+++ b/arch/arm/mach-ep93xx/gesbc9312.c
@@ -16,16 +16,38 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
+#include <linux/ioport.h>
#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+static struct physmap_flash_data gesbc9312_flash_data = {
+ .width = 4,
+};
+
+static struct resource gesbc9312_flash_resource = {
+ .start = 0x60000000,
+ .end = 0x60800000,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device gesbc9312_flash = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &gesbc9312_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &gesbc9312_flash_resource,
+};
+
static void __init gesbc9312_init_machine(void)
{
ep93xx_init_devices();
- physmap_configure(0x60000000, 0x00800000, 4, NULL);
+ platform_device_register(&gesbc9312_flash);
}
MACHINE_START(GESBC9312, "Glomation GESBC-9312-sx")
diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c
index e24566b..6e5a56c 100644
--- a/arch/arm/mach-ep93xx/ts72xx.c
+++ b/arch/arm/mach-ep93xx/ts72xx.c
@@ -16,6 +16,7 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
+#include <linux/ioport.h>
#include <linux/mtd/physmap.h>
#include <linux/platform_device.h>
#include <linux/m48t86.h>
@@ -111,6 +112,26 @@ static void __init ts72xx_map_io(void)
}
}
+static struct physmap_flash_data ts72xx_flash_data = {
+ .width = 1,
+};
+
+static struct resource ts72xx_flash_resource = {
+ .start = TS72XX_NOR_PHYS_BASE,
+ .end = TS72XX_NOR_PHYS_BASE + 0x01000000,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device ts72xx_flash = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &ts72xx_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &ts72xx_flash_resource,
+};
+
static unsigned char ts72xx_rtc_readbyte(unsigned long addr)
{
__raw_writeb(addr, TS72XX_RTC_INDEX_VIRT_BASE);
@@ -141,7 +162,7 @@ static void __init ts72xx_init_machine(void)
{
ep93xx_init_devices();
if (board_is_ts7200())
- physmap_configure(TS72XX_NOR_PHYS_BASE, 0x01000000, 1, NULL);
+ platform_device_register(&ts72xx_flash);
platform_device_register(&ts72xx_rtc_device);
}
diff --git a/arch/arm/mach-imx/dma.c b/arch/arm/mach-imx/dma.c
index 4ca51dc..3657887 100644
--- a/arch/arm/mach-imx/dma.c
+++ b/arch/arm/mach-imx/dma.c
@@ -15,6 +15,9 @@
* Changed to support scatter gather DMA
* by taking Russell's code from RiscPC
*
+ * 2006-05-31 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ * Corrected error handling code.
+ *
*/
#undef DEBUG
@@ -277,7 +280,7 @@ imx_dma_setup_sg(imx_dmach_t dma_ch,
int
imx_dma_setup_handlers(imx_dmach_t dma_ch,
void (*irq_handler) (int, void *, struct pt_regs *),
- void (*err_handler) (int, void *, struct pt_regs *),
+ void (*err_handler) (int, void *, struct pt_regs *, int),
void *data)
{
struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
@@ -463,43 +466,53 @@ static irqreturn_t dma_err_handler(int irq, void *dev_id, struct pt_regs *regs)
int i, disr = DISR;
struct imx_dma_channel *channel;
unsigned int err_mask = DBTOSR | DRTOSR | DSESR | DBOSR;
+ int errcode;
- DISR = disr;
+ DISR = disr & err_mask;
for (i = 0; i < IMX_DMA_CHANNELS; i++) {
- channel = &imx_dma_channels[i];
-
- if ((err_mask & 1 << i) && channel->name
- && channel->err_handler) {
- channel->err_handler(i, channel->data, regs);
+ if(!(err_mask & (1 << i)))
continue;
- }
-
- imx_dma_channels[i].sg = NULL;
+ channel = &imx_dma_channels[i];
+ errcode = 0;
if (DBTOSR & (1 << i)) {
- printk(KERN_WARNING
- "Burst timeout on channel %d (%s)\n",
- i, channel->name);
- DBTOSR |= (1 << i);
+ DBTOSR = (1 << i);
+ errcode |= IMX_DMA_ERR_BURST;
}
if (DRTOSR & (1 << i)) {
- printk(KERN_WARNING
- "Request timeout on channel %d (%s)\n",
- i, channel->name);
- DRTOSR |= (1 << i);
+ DRTOSR = (1 << i);
+ errcode |= IMX_DMA_ERR_REQUEST;
}
if (DSESR & (1 << i)) {
- printk(KERN_WARNING
- "Transfer timeout on channel %d (%s)\n",
- i, channel->name);
- DSESR |= (1 << i);
+ DSESR = (1 << i);
+ errcode |= IMX_DMA_ERR_TRANSFER;
}
if (DBOSR & (1 << i)) {
- printk(KERN_WARNING
- "Buffer overflow timeout on channel %d (%s)\n",
- i, channel->name);
- DBOSR |= (1 << i);
+ DBOSR = (1 << i);
+ errcode |= IMX_DMA_ERR_BUFFER;
}
+
+ /*
+ * The cleaning of @sg field would be questionable
+ * there, because its value can help to compute
+ * remaining/transfered bytes count in the handler
+ */
+ /*imx_dma_channels[i].sg = NULL;*/
+
+ if (channel->name && channel->err_handler) {
+ channel->err_handler(i, channel->data, regs, errcode);
+ continue;
+ }
+
+ imx_dma_channels[i].sg = NULL;
+
+ printk(KERN_WARNING
+ "DMA timeout on channel %d (%s) -%s%s%s%s\n",
+ i, channel->name,
+ errcode&IMX_DMA_ERR_BURST? " burst":"",
+ errcode&IMX_DMA_ERR_REQUEST? " request":"",
+ errcode&IMX_DMA_ERR_TRANSFER? " transfer":"",
+ errcode&IMX_DMA_ERR_BUFFER? " buffer":"");
}
return IRQ_HANDLED;
}
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
index 6e8d504..ebe4391 100644
--- a/arch/arm/mach-ixp2000/core.c
+++ b/arch/arm/mach-ixp2000/core.c
@@ -211,7 +211,8 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* clear timer 1 */
ixp2000_reg_wrb(IXP2000_T1_CLR, 1);
- while ((next_jiffy_time - *missing_jiffy_timer_csr) > ticks_per_jiffy) {
+ while ((signed long)(next_jiffy_time - *missing_jiffy_timer_csr)
+ >= ticks_per_jiffy) {
timer_tick(regs);
next_jiffy_time -= ticks_per_jiffy;
}
@@ -301,6 +302,7 @@ void gpio_line_config(int line, int direction)
}
local_irq_restore(flags);
}
+EXPORT_SYMBOL(gpio_line_config);
/*************************************************************************
diff --git a/arch/arm/mach-ixp23xx/core.c b/arch/arm/mach-ixp23xx/core.c
index affd1d5..051e3d7 100644
--- a/arch/arm/mach-ixp23xx/core.c
+++ b/arch/arm/mach-ixp23xx/core.c
@@ -334,7 +334,7 @@ void __init ixp23xx_init_irq(void)
/*************************************************************************
* Timer-tick functions for IXP23xx
*************************************************************************/
-#define CLOCK_TICKS_PER_USEC CLOCK_TICK_RATE / (USEC_PER_SEC)
+#define CLOCK_TICKS_PER_USEC (CLOCK_TICK_RATE / USEC_PER_SEC)
static unsigned long next_jiffy_time;
@@ -353,7 +353,7 @@ ixp23xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
/* Clear Pending Interrupt by writing '1' to it */
*IXP23XX_TIMER_STATUS = IXP23XX_TIMER1_INT_PEND;
- while ((*IXP23XX_TIMER_CONT - next_jiffy_time) > LATCH) {
+ while ((signed long)(*IXP23XX_TIMER_CONT - next_jiffy_time) >= LATCH) {
timer_tick(regs);
next_jiffy_time += LATCH;
}
@@ -439,5 +439,6 @@ static struct platform_device *ixp23xx_devices[] __initdata = {
void __init ixp23xx_sys_init(void)
{
+ *IXP23XX_EXP_UNIT_FUSE |= 0xf;
platform_add_devices(ixp23xx_devices, ARRAY_SIZE(ixp23xx_devices));
}
diff --git a/arch/arm/mach-ixp23xx/espresso.c b/arch/arm/mach-ixp23xx/espresso.c
index bf688c1..dc5e489 100644
--- a/arch/arm/mach-ixp23xx/espresso.c
+++ b/arch/arm/mach-ixp23xx/espresso.c
@@ -53,9 +53,29 @@ static int __init espresso_pci_init(void)
};
subsys_initcall(espresso_pci_init);
+static struct physmap_flash_data espresso_flash_data = {
+ .width = 2,
+};
+
+static struct resource espresso_flash_resource = {
+ .start = 0x90000000,
+ .end = 0x92000000,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device espresso_flash = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &espresso_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &espresso_flash_resource,
+};
+
static void __init espresso_init(void)
{
- physmap_configure(0x90000000, 0x02000000, 2, NULL);
+ platform_device_register(&espresso_flash);
/*
* Mark flash as writeable.
diff --git a/arch/arm/mach-ixp23xx/ixdp2351.c b/arch/arm/mach-ixp23xx/ixdp2351.c
index 00146c3..535b334 100644
--- a/arch/arm/mach-ixp23xx/ixdp2351.c
+++ b/arch/arm/mach-ixp23xx/ixdp2351.c
@@ -298,9 +298,29 @@ static void __init ixdp2351_map_io(void)
iotable_init(ixdp2351_io_desc, ARRAY_SIZE(ixdp2351_io_desc));
}
+static struct physmap_flash_data ixdp2351_flash_data = {
+ .width = 1,
+};
+
+static struct resource ixdp2351_flash_resource = {
+ .start = 0x90000000,
+ .end = 0x94000000,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device ixdp2351_flash = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &ixdp2351_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &ixdp2351_flash_resource,
+};
+
static void __init ixdp2351_init(void)
{
- physmap_configure(0x90000000, 0x04000000, 1, NULL);
+ platform_device_register(&ixdp2351_flash);
/*
* Mark flash as writeable
diff --git a/arch/arm/mach-ixp23xx/roadrunner.c b/arch/arm/mach-ixp23xx/roadrunner.c
index 43c14e7..b9f5d13 100644
--- a/arch/arm/mach-ixp23xx/roadrunner.c
+++ b/arch/arm/mach-ixp23xx/roadrunner.c
@@ -137,9 +137,29 @@ static int __init roadrunner_pci_init(void)
subsys_initcall(roadrunner_pci_init);
+static struct physmap_flash_data roadrunner_flash_data = {
+ .width = 2,
+};
+
+static struct resource roadrunner_flash_resource = {
+ .start = 0x90000000,
+ .end = 0x94000000,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device roadrunner_flash = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &roadrunner_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &roadrunner_flash_resource,
+};
+
static void __init roadrunner_init(void)
{
- physmap_configure(0x90000000, 0x04000000, 2, NULL);
+ platform_device_register(&roadrunner_flash);
/*
* Mark flash as writeable
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index 00b761f..bf25a76 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -276,7 +276,7 @@ static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id, struct pt_regs
/*
* Catch up with the real idea of time
*/
- while ((*IXP4XX_OSTS - last_jiffy_time) > LATCH) {
+ while ((signed long)(*IXP4XX_OSTS - last_jiffy_time) >= LATCH) {
timer_tick(regs);
last_jiffy_time += LATCH;
}
diff --git a/arch/arm/mach-ixp4xx/nas100d-power.c b/arch/arm/mach-ixp4xx/nas100d-power.c
index 99d333d..a3745ed 100644
--- a/arch/arm/mach-ixp4xx/nas100d-power.c
+++ b/arch/arm/mach-ixp4xx/nas100d-power.c
@@ -20,11 +20,10 @@
#include <linux/module.h>
#include <linux/reboot.h>
#include <linux/interrupt.h>
+#include <linux/reboot.h>
#include <asm/mach-types.h>
-extern void ctrl_alt_del(void);
-
static irqreturn_t nas100d_reset_handler(int irq, void *dev_id, struct pt_regs *regs)
{
/* Signal init to do the ctrlaltdel action, this will bypass init if
diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c
index a3b4c6a..9a31444 100644
--- a/arch/arm/mach-ixp4xx/nas100d-setup.c
+++ b/arch/arm/mach-ixp4xx/nas100d-setup.c
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/serial.h>
#include <linux/serial_8250.h>
+#include <linux/leds.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -37,6 +38,36 @@ static struct platform_device nas100d_flash = {
.resource = &nas100d_flash_resource,
};
+#ifdef CONFIG_LEDS_IXP4XX
+static struct resource nas100d_led_resources[] = {
+ {
+ .name = "wlan", /* green led */
+ .start = 0,
+ .end = 0,
+ .flags = IXP4XX_GPIO_LOW,
+ },
+ {
+ .name = "ready", /* blue power led (off is flashing!) */
+ .start = 15,
+ .end = 15,
+ .flags = IXP4XX_GPIO_LOW,
+ },
+ {
+ .name = "disk", /* yellow led */
+ .start = 3,
+ .end = 3,
+ .flags = IXP4XX_GPIO_LOW,
+ },
+};
+
+static struct platform_device nas100d_leds = {
+ .name = "IXP4XX-GPIO-LED",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(nas100d_led_resources),
+ .resource = nas100d_led_resources,
+};
+#endif
+
static struct ixp4xx_i2c_pins nas100d_i2c_gpio_pins = {
.sda_pin = NAS100D_SDA_PIN,
.scl_pin = NAS100D_SCL_PIN,
@@ -95,7 +126,9 @@ static struct platform_device nas100d_uart = {
static struct platform_device *nas100d_devices[] __initdata = {
&nas100d_i2c_controller,
&nas100d_flash,
- &nas100d_uart,
+#ifdef CONFIG_LEDS_IXP4XX
+ &nas100d_leds,
+#endif
};
static void nas100d_power_off(void)
@@ -122,6 +155,12 @@ static void __init nas100d_init(void)
pm_power_off = nas100d_power_off;
+ /* This is only useful on a modified machine, but it is valuable
+ * to have it first in order to see debug messages, and so that
+ * it does *not* get removed if platform_add_devices fails!
+ */
+ (void)platform_device_register(&nas100d_uart);
+
platform_add_devices(nas100d_devices, ARRAY_SIZE(nas100d_devices));
}
diff --git a/arch/arm/mach-ixp4xx/nslu2-power.c b/arch/arm/mach-ixp4xx/nslu2-power.c
index d80c362..6d38e97 100644
--- a/arch/arm/mach-ixp4xx/nslu2-power.c
+++ b/arch/arm/mach-ixp4xx/nslu2-power.c
@@ -20,11 +20,10 @@
#include <linux/module.h>
#include <linux/reboot.h>
#include <linux/interrupt.h>
+#include <linux/reboot.h>
#include <asm/mach-types.h>
-extern void ctrl_alt_del(void);
-
static irqreturn_t nslu2_power_handler(int irq, void *dev_id, struct pt_regs *regs)
{
/* Signal init to do the ctrlaltdel action, this will bypass init if
diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c
index 55411f2..749a337 100644
--- a/arch/arm/mach-ixp4xx/nslu2-setup.c
+++ b/arch/arm/mach-ixp4xx/nslu2-setup.c
@@ -7,6 +7,7 @@
* Copyright (C) 2003-2004 MontaVista Software, Inc.
*
* Author: Mark Rakes <mrakes at mac.com>
+ * Author: Rod Whitby <rod@whitby.id.au>
* Maintainers: http://www.nslu2-linux.org/
*
* Fixed missing init_time in MACHINE_START kas11 10/22/04
@@ -16,6 +17,7 @@
#include <linux/kernel.h>
#include <linux/serial.h>
#include <linux/serial_8250.h>
+#include <linux/leds.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -43,6 +45,42 @@ static struct ixp4xx_i2c_pins nslu2_i2c_gpio_pins = {
.scl_pin = NSLU2_SCL_PIN,
};
+#ifdef CONFIG_LEDS_IXP4XX
+static struct resource nslu2_led_resources[] = {
+ {
+ .name = "ready", /* green led */
+ .start = NSLU2_LED_GRN,
+ .end = NSLU2_LED_GRN,
+ .flags = IXP4XX_GPIO_HIGH,
+ },
+ {
+ .name = "status", /* red led */
+ .start = NSLU2_LED_RED,
+ .end = NSLU2_LED_RED,
+ .flags = IXP4XX_GPIO_HIGH,
+ },
+ {
+ .name = "disk-1",
+ .start = NSLU2_LED_DISK1,
+ .end = NSLU2_LED_DISK1,
+ .flags = IXP4XX_GPIO_LOW,
+ },
+ {
+ .name = "disk-2",
+ .start = NSLU2_LED_DISK2,
+ .end = NSLU2_LED_DISK2,
+ .flags = IXP4XX_GPIO_LOW,
+ },
+};
+
+static struct platform_device nslu2_leds = {
+ .name = "IXP4XX-GPIO-LED",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(nslu2_led_resources),
+ .resource = nslu2_led_resources,
+};
+#endif
+
static struct platform_device nslu2_i2c_controller = {
.name = "IXP4XX-I2C",
.id = 0,
@@ -102,8 +140,10 @@ static struct platform_device nslu2_uart = {
static struct platform_device *nslu2_devices[] __initdata = {
&nslu2_i2c_controller,
&nslu2_flash,
- &nslu2_uart,
&nslu2_beeper,
+#ifdef CONFIG_LEDS_IXP4XX
+ &nslu2_leds,
+#endif
};
static void nslu2_power_off(void)
@@ -127,6 +167,12 @@ static void __init nslu2_init(void)
pm_power_off = nslu2_power_off;
+ /* This is only useful on a modified machine, but it is valuable
+ * to have it first in order to see debug messages, and so that
+ * it does *not* get removed if platform_add_devices fails!
+ */
+ (void)platform_device_register(&nslu2_uart);
+
platform_add_devices(nslu2_devices, ARRAY_SIZE(nslu2_devices));
}
diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c
index 6178f04..73df32a 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -84,6 +84,15 @@ static struct omap_board_config_kernel ams_delta_config[] = {
{ OMAP_TAG_UART, &ams_delta_uart_config },
};
+static struct platform_device ams_delta_led_device = {
+ .name = "ams-delta-led",
+ .id = -1
+};
+
+static struct platform_device *ams_delta_devices[] __initdata = {
+ &ams_delta_led_device,
+};
+
static void __init ams_delta_init(void)
{
iotable_init(ams_delta_io_desc, ARRAY_SIZE(ams_delta_io_desc));
@@ -94,6 +103,8 @@ static void __init ams_delta_init(void)
/* Clear latch2 (NAND, LCD, modem enable) */
ams_delta_latch2_write(~0, 0);
+
+ platform_add_devices(ams_delta_devices, ARRAY_SIZE(ams_delta_devices));
}
static void __init ams_delta_map_io(void)
diff --git a/arch/arm/mach-pnx4008/clock.c b/arch/arm/mach-pnx4008/clock.c
index 285b22f..f582ed2 100644
--- a/arch/arm/mach-pnx4008/clock.c
+++ b/arch/arm/mach-pnx4008/clock.c
@@ -767,6 +767,54 @@ static struct clk *onchip_clks[] = {
&uart6_ck,
};
+static int local_clk_enable(struct clk *clk)
+{
+ int ret = 0;
+
+ if (!(clk->flags & FIXED_RATE) && !clk->rate && clk->set_rate
+ && clk->user_rate)
+ ret = clk->set_rate(clk, clk->user_rate);
+ return ret;
+}
+
+static void local_clk_disable(struct clk *clk)
+{
+ if (!(clk->flags & FIXED_RATE) && clk->rate && clk->set_rate)
+ clk->set_rate(clk, 0);
+}
+
+static void local_clk_unuse(struct clk *clk)
+{
+ if (clk->usecount > 0 && !(--clk->usecount)) {
+ local_clk_disable(clk);
+ if (clk->parent)
+ local_clk_unuse(clk->parent);
+ }
+}
+
+static int local_clk_use(struct clk *clk)
+{
+ int ret = 0;
+ if (clk->usecount++ == 0) {
+ if (clk->parent)
+ ret = local_clk_use(clk->parent);
+
+ if (ret != 0) {
+ clk->usecount--;
+ goto out;
+ }
+
+ ret = local_clk_enable(clk);
+
+ if (ret != 0 && clk->parent) {
+ local_clk_unuse(clk->parent);
+ clk->usecount--;
+ }
+ }
+out:
+ return ret;
+}
+
static int local_set_rate(struct clk *clk, u32 rate)
{
int ret = -EINVAL;
@@ -847,28 +895,12 @@ unsigned long clk_get_rate(struct clk *clk)
}
EXPORT_SYMBOL(clk_get_rate);
-static int local_clk_enable(struct clk *clk)
-{
- int ret = 0;
-
- if (!(clk->flags & FIXED_RATE) && !clk->rate && clk->set_rate
- && clk->user_rate)
- ret = clk->set_rate(clk, clk->user_rate);
- return ret;
-}
-
-static void local_clk_disable(struct clk *clk)
-{
- if (!(clk->flags & FIXED_RATE) && clk->rate && clk->set_rate)
- clk->set_rate(clk, 0);
-}
-
int clk_enable(struct clk *clk)
{
int ret = 0;
clock_lock();
- ret = local_clk_enable(clk);
+ ret = local_clk_use(clk);
clock_unlock();
return ret;
}
@@ -878,70 +910,11 @@ EXPORT_SYMBOL(clk_enable);
void clk_disable(struct clk *clk)
{
clock_lock();
- local_clk_disable(clk);
- clock_unlock();
-}
-
-EXPORT_SYMBOL(clk_disable);
-
-static void local_clk_unuse(struct clk *clk)
-{
- if (clk->usecount > 0 && !(--clk->usecount)) {
- local_clk_disable(clk);
- if (clk->parent)
- local_clk_unuse(clk->parent);
- }
-}
-
-static int local_clk_use(struct clk *clk)
-{
- int ret = 0;
- if (clk->usecount++ == 0) {
- if (clk->parent)
- ret = local_clk_use(clk->parent);
-
- if (ret != 0) {
- clk->usecount--;
- goto out;
- }
-
- ret = local_clk_enable(clk);
-
- if (ret != 0 && clk->parent) {
- local_clk_unuse(clk->parent);
- clk->usecount--;
- }
- }
-out:
- return ret;
-}
-
-/* The main purpose of clk_use ans clk_unuse functions
- * is to control switching 13MHz oscillator and PLL1 (13'MHz),
- * so that they are disabled whenever none of PLL2-5 is using them.
- * Although in theory these functions should work with any clock,
- * please use them only on PLL2 - PLL5 to avoid confusion.
- */
-int clk_use(struct clk *clk)
-{
- int ret = 0;
-
- clock_lock();
- ret = local_clk_use(clk);
- clock_unlock();
- return ret;
-}
-EXPORT_SYMBOL(clk_use);
-
-void clk_unuse(struct clk *clk)
-{
-
- clock_lock();
local_clk_unuse(clk);
clock_unlock();
}
-EXPORT_SYMBOL(clk_unuse);
+EXPORT_SYMBOL(clk_disable);
long clk_round_rate(struct clk *clk, unsigned long rate)
{
@@ -995,7 +968,7 @@ static int __init clk_init(void)
__FUNCTION__, (*clkp)->name, (*clkp)->rate);
}
- clk_use(&ck_pll4);
+ local_clk_use(&ck_pll4);
/* if ck_13MHz is not used, disable it. */
if (ck_13MHz.usecount == 0)
diff --git a/arch/arm/mach-pnx4008/serial.c b/arch/arm/mach-pnx4008/serial.c
index 1032238..95a1b3f 100644
--- a/arch/arm/mach-pnx4008/serial.c
+++ b/arch/arm/mach-pnx4008/serial.c
@@ -20,7 +20,7 @@
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
-#include <asm/arch/pm.h>
+#include <asm/arch/gpio.h>
#include <asm/arch/clock.h>
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index 0c33413..f5d9cd4 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -81,6 +81,12 @@ config SMDK2440_CPU2442
depends on ARCH_S3C2440
select CPU_S3C2442
+config MACH_SMDK2413
+ bool "SMDK2413"
+ select CPU_S3C2412
+ select MACH_SMDK
+ help
+ Say Y here if you are using an SMDK2413
config MACH_VR1000
bool "Thorcom VR1000"
@@ -114,13 +120,33 @@ config MACH_NEXCODER_2440
endmenu
+config S3C2410_CLOCK
+ bool
+ help
+ Clock code for the S3C2410, and similar processors
+
config CPU_S3C2410
bool
depends on ARCH_S3C2410
+ select S3C2410_CLOCK
help
Support for S3C2410 and S3C2410A family from the S3C24XX line
of Samsung Mobile CPUs.
+# internal node to signify if we are only dealing with an S3C2412
+
+config CPU_S3C2412_ONLY
+ bool
+ depends on ARCH_S3C2410 && !CPU_S3C2400 && !CPU_S3C2410 && \
+ !CPU_S3C2440 && !CPU_S3C2442 && CPU_S3C2412
+ default y if CPU_S3C2412
+
+config CPU_S3C2412
+ bool
+ depends on ARCH_S3C2410
+ help
+ Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line
+
config CPU_S3C244X
bool
depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442)
@@ -130,6 +156,7 @@ config CPU_S3C244X
config CPU_S3C2440
bool
depends on ARCH_S3C2410
+ select S3C2410_CLOCK
select CPU_S3C244X
help
Support for S3C2440 Samsung Mobile CPU based systems.
@@ -137,6 +164,7 @@ config CPU_S3C2440
config CPU_S3C2442
bool
depends on ARCH_S3C2420
+ select S3C2410_CLOCK
select CPU_S3C244X
help
Support for S3C2442 Samsung Mobile CPU based systems.
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
index 5e09355..0c79386 100644
--- a/arch/arm/mach-s3c2410/Makefile
+++ b/arch/arm/mach-s3c2410/Makefile
@@ -24,11 +24,20 @@ obj-$(CONFIG_S3C2410_DMA) += dma.o
obj-$(CONFIG_PM) += pm.o sleep.o
obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o
+# S3C2412 support
+obj-$(CONFIG_CPU_S3C2412) += s3c2412.o
+obj-$(CONFIG_CPU_S3C2412) += s3c2412-clock.o
+
+#
# S3C244X support
obj-$(CONFIG_CPU_S3C244X) += s3c244x.o
obj-$(CONFIG_CPU_S3C244X) += s3c244x-irq.o
+# Clock control
+
+obj-$(CONFIG_S3C2410_CLOCK) += s3c2410-clock.o
+
# S3C2440 support
obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s3c2440-dsc.o
@@ -53,6 +62,7 @@ obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o
obj-$(CONFIG_ARCH_H1940) += mach-h1940.o
obj-$(CONFIG_MACH_N30) += mach-n30.o
obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o
+obj-$(CONFIG_MACH_SMDK2413) += mach-smdk2413.o
obj-$(CONFIG_ARCH_S3C2440) += mach-smdk2440.o
obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o
obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c
index 99d1746..e13fb67 100644
--- a/arch/arm/mach-s3c2410/clock.c
+++ b/arch/arm/mach-s3c2410/clock.c
@@ -3,7 +3,7 @@
* Copyright (c) 2004-2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
- * S3C2410 Clock control support
+ * S3C24XX Core clock control support
*
* Based on, and code from linux/arch/arm/mach-versatile/clock.c
**
@@ -56,25 +56,6 @@ static LIST_HEAD(clocks);
DEFINE_MUTEX(clocks_mutex);
-/* old functions */
-
-void inline s3c24xx_clk_enable(unsigned int clocks, unsigned int enable)
-{
- unsigned long clkcon;
-
- clkcon = __raw_readl(S3C2410_CLKCON);
-
- if (enable)
- clkcon |= clocks;
- else
- clkcon &= ~clocks;
-
- /* ensure none of the special function bits set */
- clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER | 3);
-
- __raw_writel(clkcon, S3C2410_CLKCON);
-}
-
/* enable and disable calls for use with the clk struct */
static int clk_null_enable(struct clk *clk, int enable)
@@ -82,12 +63,6 @@ static int clk_null_enable(struct clk *clk, int enable)
return 0;
}
-int s3c24xx_clkcon_enable(struct clk *clk, int enable)
-{
- s3c24xx_clk_enable(clk->ctrlbit, enable);
- return 0;
-}
-
/* Clock API calls */
struct clk *clk_get(struct device *dev, const char *id)
@@ -173,8 +148,11 @@ unsigned long clk_get_rate(struct clk *clk)
if (clk->rate != 0)
return clk->rate;
- while (clk->parent != NULL && clk->rate == 0)
- clk = clk->parent;
+ if (clk->get_rate != NULL)
+ return (clk->get_rate)(clk);
+
+ if (clk->parent != NULL)
+ return clk_get_rate(clk->parent);
return clk->rate;
}
@@ -233,31 +211,9 @@ EXPORT_SYMBOL(clk_set_rate);
EXPORT_SYMBOL(clk_get_parent);
EXPORT_SYMBOL(clk_set_parent);
-/* base clock enable */
-
-static int s3c24xx_upll_enable(struct clk *clk, int enable)
-{
- unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
- unsigned long orig = clkslow;
-
- if (enable)
- clkslow &= ~S3C2410_CLKSLOW_UCLK_OFF;
- else
- clkslow |= S3C2410_CLKSLOW_UCLK_OFF;
-
- __raw_writel(clkslow, S3C2410_CLKSLOW);
-
- /* if we started the UPLL, then allow to settle */
-
- if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF))
- udelay(200);
-
- return 0;
-}
-
/* base clocks */
-static struct clk clk_xtal = {
+struct clk clk_xtal = {
.name = "xtal",
.id = -1,
.rate = 0,
@@ -265,23 +221,27 @@ static struct clk clk_xtal = {
.ctrlbit = 0,
};
-static struct clk clk_upll = {
+struct clk clk_mpll = {
+ .name = "mpll",
+ .id = -1,
+};
+
+struct clk clk_upll = {
.name = "upll",
.id = -1,
.parent = NULL,
- .enable = s3c24xx_upll_enable,
.ctrlbit = 0,
};
-static struct clk clk_f = {
+struct clk clk_f = {
.name = "fclk",
.id = -1,
.rate = 0,
- .parent = NULL,
+ .parent = &clk_mpll,
.ctrlbit = 0,
};
-static struct clk clk_h = {
+struct clk clk_h = {
.name = "hclk",
.id = -1,
.rate = 0,
@@ -289,7 +249,7 @@ static struct clk clk_h = {
.ctrlbit = 0,
};
-static struct clk clk_p = {
+struct clk clk_p = {
.name = "pclk",
.id = -1,
.rate = 0,
@@ -308,14 +268,14 @@ struct clk clk_usb_bus = {
static int s3c24xx_dclk_enable(struct clk *clk, int enable)
{
- unsigned long dclkcon = __raw_readl(S3C2410_DCLKCON);
+ unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
if (enable)
dclkcon |= clk->ctrlbit;
else
dclkcon &= ~clk->ctrlbit;
- __raw_writel(dclkcon, S3C2410_DCLKCON);
+ __raw_writel(dclkcon, S3C24XX_DCLKCON);
return 0;
}
@@ -334,7 +294,7 @@ static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
clk->parent = parent;
- dclkcon = __raw_readl(S3C2410_DCLKCON);
+ dclkcon = __raw_readl(S3C24XX_DCLKCON);
if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
if (uclk)
@@ -348,7 +308,7 @@ static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
}
- __raw_writel(dclkcon, S3C2410_DCLKCON);
+ __raw_writel(dclkcon, S3C24XX_DCLKCON);
return 0;
}
@@ -426,108 +386,6 @@ struct clk s3c24xx_uclk = {
.id = -1,
};
-
-/* standard clock definitions */
-
-static struct clk init_clocks[] = {
- {
- .name = "nand",
- .id = -1,
- .parent = &clk_h,
- .enable = s3c24xx_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_NAND,
- }, {
- .name = "lcd",
- .id = -1,
- .parent = &clk_h,
- .enable = s3c24xx_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_LCDC,
- }, {
- .name = "usb-host",
- .id = -1,
- .parent = &clk_h,
- .enable = s3c24xx_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_USBH,
- }, {
- .name = "usb-device",
- .id = -1,
- .parent = &clk_h,
- .enable = s3c24xx_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_USBD,
- }, {
- .name = "timers",
- .id = -1,
- .parent = &clk_p,
- .enable = s3c24xx_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_PWMT,
- }, {
- .name = "sdi",
- .id = -1,
- .parent = &clk_p,
- .enable = s3c24xx_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_SDI,
- }, {
- .name = "uart",
- .id = 0,
- .parent = &clk_p,
- .enable = s3c24xx_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_UART0,
- }, {
- .name = "uart",
- .id = 1,
- .parent = &clk_p,
- .enable = s3c24xx_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_UART1,
- }, {
- .name = "uart",
- .id = 2,
- .parent = &clk_p,
- .enable = s3c24xx_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_UART2,
- }, {
- .name = "gpio",
- .id = -1,
- .parent = &clk_p,
- .enable = s3c24xx_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_GPIO,
- }, {
- .name = "rtc",
- .id = -1,
- .parent = &clk_p,
- .enable = s3c24xx_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_RTC,
- }, {
- .name = "adc",
- .id = -1,
- .parent = &clk_p,
- .enable = s3c24xx_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_ADC,
- }, {
- .name = "i2c",
- .id = -1,
- .parent = &clk_p,
- .enable = s3c24xx_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_IIC,
- }, {
- .name = "iis",
- .id = -1,
- .parent = &clk_p,
- .enable = s3c24xx_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_IIS,
- }, {
- .name = "spi",
- .id = -1,
- .parent = &clk_p,
- .enable = s3c24xx_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_SPI,
- }, {
- .name = "watchdog",
- .id = -1,
- .parent = &clk_p,
- .ctrlbit = 0,
- }
-};
-
/* initialise the clock system */
int s3c24xx_register_clock(struct clk *clk)
@@ -537,14 +395,6 @@ int s3c24xx_register_clock(struct clk *clk)
if (clk->enable == NULL)
clk->enable = clk_null_enable;
- /* if this is a standard clock, set the usage state */
-
- if (clk->ctrlbit && clk->enable == s3c24xx_clkcon_enable) {
- unsigned long clkcon = __raw_readl(S3C2410_CLKCON);
-
- clk->usage = (clkcon & clk->ctrlbit) ? 1 : 0;
- }
-
/* add to the list of available clocks */
mutex_lock(&clocks_mutex);
@@ -561,44 +411,18 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
unsigned long hclk,
unsigned long pclk)
{
- unsigned long upllcon = __raw_readl(S3C2410_UPLLCON);
- unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
- struct clk *clkp = init_clocks;
- int ptr;
- int ret;
-
- printk(KERN_INFO "S3C2410 Clocks, (c) 2004 Simtec Electronics\n");
+ printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n");
/* initialise the main system clocks */
clk_xtal.rate = xtal;
- clk_upll.rate = s3c2410_get_pll(upllcon, xtal);
+ clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal);
+ clk_mpll.rate = fclk;
clk_h.rate = hclk;
clk_p.rate = pclk;
clk_f.rate = fclk;
- /* We must be careful disabling the clocks we are not intending to
- * be using at boot time, as subsytems such as the LCD which do
- * their own DMA requests to the bus can cause the system to lockup
- * if they where in the middle of requesting bus access.
- *
- * Disabling the LCD clock if the LCD is active is very dangerous,
- * and therefore the bootloader should be careful to not enable
- * the LCD clock if it is not needed.
- */
-
- mutex_lock(&clocks_mutex);
-
- s3c24xx_clk_enable(S3C2410_CLKCON_NAND, 0);
- s3c24xx_clk_enable(S3C2410_CLKCON_USBH, 0);
- s3c24xx_clk_enable(S3C2410_CLKCON_USBD, 0);
- s3c24xx_clk_enable(S3C2410_CLKCON_ADC, 0);
- s3c24xx_clk_enable(S3C2410_CLKCON_IIC, 0);
- s3c24xx_clk_enable(S3C2410_CLKCON_SPI, 0);
-
- mutex_unlock(&clocks_mutex);
-
/* assume uart clocks are correctly setup */
/* register our clocks */
@@ -606,6 +430,9 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
if (s3c24xx_register_clock(&clk_xtal) < 0)
printk(KERN_ERR "failed to register master xtal\n");
+ if (s3c24xx_register_clock(&clk_mpll) < 0)
+ printk(KERN_ERR "failed to register mpll clock\n");
+
if (s3c24xx_register_clock(&clk_upll) < 0)
printk(KERN_ERR "failed to register upll clock\n");
@@ -618,27 +445,5 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
if (s3c24xx_register_clock(&clk_p) < 0)
printk(KERN_ERR "failed to register cpu pclk\n");
-
- if (s3c24xx_register_clock(&clk_usb_bus) < 0)
- printk(KERN_ERR "failed to register usb bus clock\n");
-
- /* register clocks from clock array */
-
- for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
- ret = s3c24xx_register_clock(clkp);
- if (ret < 0) {
- printk(KERN_ERR "Failed to register clock %s (%d)\n",
- clkp->name, ret);
- }
- }
-
- /* show the clock-slow value */
-
- printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n",
- print_mhz(xtal / ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))),
- (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast",
- (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on",
- (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on");
-
return 0;
}
diff --git a/arch/arm/mach-s3c2410/clock.h b/arch/arm/mach-s3c2410/clock.h
index 01bb458..7f0ea03 100644
--- a/arch/arm/mach-s3c2410/clock.h
+++ b/arch/arm/mach-s3c2410/clock.h
@@ -22,6 +22,7 @@ struct clk {
int (*enable)(struct clk *, int enable);
int (*set_rate)(struct clk *c, unsigned long rate);
+ unsigned long (*get_rate)(struct clk *c);
unsigned long (*round_rate)(struct clk *c, unsigned long rate);
int (*set_parent)(struct clk *c, struct clk *parent);
};
@@ -36,6 +37,15 @@ extern struct clk s3c24xx_uclk;
extern struct clk clk_usb_bus;
+/* core clock support */
+
+extern struct clk clk_f;
+extern struct clk clk_h;
+extern struct clk clk_p;
+extern struct clk clk_mpll;
+extern struct clk clk_upll;
+extern struct clk clk_xtal;
+
/* exports for arch/arm/mach-s3c2410
*
* Please DO NOT use these outside of arch/arm/mach-s3c2410
@@ -43,7 +53,8 @@ extern struct clk clk_usb_bus;
extern struct mutex clocks_mutex;
-extern int s3c24xx_clkcon_enable(struct clk *clk, int enable);
+extern int s3c2410_clkcon_enable(struct clk *clk, int enable);
+
extern int s3c24xx_register_clock(struct clk *clk);
extern int s3c24xx_setup_clocks(unsigned long xtal,
diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/mach-s3c2410/cpu.c
index 52842e6..1c3c6ad 100644
--- a/arch/arm/mach-s3c2410/cpu.c
+++ b/arch/arm/mach-s3c2410/cpu.c
@@ -44,6 +44,7 @@
#include "clock.h"
#include "s3c2400.h"
#include "s3c2410.h"
+#include "s3c2412.h"
#include "s3c244x.h"
#include "s3c2440.h"
#include "s3c2442.h"
@@ -62,6 +63,7 @@ struct cpu_table {
static const char name_s3c2400[] = "S3C2400";
static const char name_s3c2410[] = "S3C2410";
+static const char name_s3c2412[] = "S3C2412";
static const char name_s3c2440[] = "S3C2440";
static const char name_s3c2442[] = "S3C2442";
static const char name_s3c2410a[] = "S3C2410A";
@@ -114,6 +116,15 @@ static struct cpu_table cpu_ids[] __initdata = {
.name = name_s3c2442
},
{
+ .idcode = 0x32412001,
+ .idmask = 0xffffffff,
+ .map_io = s3c2412_map_io,
+ .init_clocks = s3c2412_init_clocks,
+ .init_uarts = s3c2412_init_uarts,
+ .init = s3c2412_init,
+ .name = name_s3c2412,
+ },
+ {
.idcode = 0x0, /* S3C2400 doesn't have an idcode */
.idmask = 0xffffffff,
.map_io = s3c2400_map_io,
@@ -171,6 +182,24 @@ void s3c24xx_set_board(struct s3c24xx_board *b)
static struct cpu_table *cpu;
+static unsigned long s3c24xx_read_idcode_v5(void)
+{
+#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
+ return __raw_readl(S3C2412_GSTATUS1);
+#else
+ return 1UL; /* don't look like an 2400 */
+#endif
+}
+
+static unsigned long s3c24xx_read_idcode_v4(void)
+{
+#ifndef CONFIG_CPU_S3C2400
+ return __raw_readl(S3C2410_GSTATUS1);
+#else
+ return 0UL;
+#endif
+}
+
void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
{
unsigned long idcode = 0x0;
@@ -178,9 +207,11 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
/* initialise the io descriptors we need for initialisation */
iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc));
-#ifndef CONFIG_CPU_S3C2400
- idcode = __raw_readl(S3C2410_GSTATUS1);
-#endif
+ if (cpu_architecture() >= CPU_ARCH_ARMv5) {
+ idcode = s3c24xx_read_idcode_v5();
+ } else {
+ idcode = s3c24xx_read_idcode_v4();
+ }
cpu = s3c_lookup_cpu(idcode);
diff --git a/arch/arm/mach-s3c2410/cpu.h b/arch/arm/mach-s3c2410/cpu.h
index 4086289..b0ed9d2 100644
--- a/arch/arm/mach-s3c2410/cpu.h
+++ b/arch/arm/mach-s3c2410/cpu.h
@@ -73,5 +73,7 @@ extern struct sys_timer s3c24xx_timer;
/* system device classes */
+extern struct sysdev_class s3c2410_sysclass;
+extern struct sysdev_class s3c2412_sysclass;
extern struct sysdev_class s3c2440_sysclass;
extern struct sysdev_class s3c2442_sysclass;
diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c
index 66d8c06..6822dc7 100644
--- a/arch/arm/mach-s3c2410/irq.c
+++ b/arch/arm/mach-s3c2410/irq.c
@@ -191,13 +191,9 @@ static struct irqchip s3c_irq_chip = {
.ack = s3c_irq_ack,
.mask = s3c_irq_mask,
.unmask = s3c_irq_unmask,
- .set_wake = s3c_irq_wake
+ .set_wake = s3c_irq_wake
};
-/* S3C2410_EINTMASK
- * S3C2410_EINTPEND
- */
-
static void
s3c_irqext_mask(unsigned int irqno)
{
@@ -205,9 +201,9 @@ s3c_irqext_mask(unsigned int irqno)
irqno -= EXTINT_OFF;
- mask = __raw_readl(S3C2410_EINTMASK);
+ mask = __raw_readl(S3C24XX_EINTMASK);
mask |= ( 1UL << irqno);
- __raw_writel(mask, S3C2410_EINTMASK);
+ __raw_writel(mask, S3C24XX_EINTMASK);
if (irqno <= (IRQ_EINT7 - EXTINT_OFF)) {
/* check to see if all need masking */
@@ -232,11 +228,11 @@ s3c_irqext_ack(unsigned int irqno)
bit = 1UL << (irqno - EXTINT_OFF);
- mask = __raw_readl(S3C2410_EINTMASK);
+ mask = __raw_readl(S3C24XX_EINTMASK);
- __raw_writel(bit, S3C2410_EINTPEND);
+ __raw_writel(bit, S3C24XX_EINTPEND);
- req = __raw_readl(S3C2410_EINTPEND);
+ req = __raw_readl(S3C24XX_EINTPEND);
req &= ~mask;
/* not sure if we should be acking the parent irq... */
@@ -257,9 +253,9 @@ s3c_irqext_unmask(unsigned int irqno)
irqno -= EXTINT_OFF;
- mask = __raw_readl(S3C2410_EINTMASK);
+ mask = __raw_readl(S3C24XX_EINTMASK);
mask &= ~( 1UL << irqno);
- __raw_writel(mask, S3C2410_EINTMASK);
+ __raw_writel(mask, S3C24XX_EINTMASK);
s3c_irq_unmask((irqno <= (IRQ_EINT7 - EXTINT_OFF)) ? IRQ_EINT4t7 : IRQ_EINT8t23);
}
@@ -275,28 +271,28 @@ s3c_irqext_type(unsigned int irq, unsigned int type)
if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3))
{
gpcon_reg = S3C2410_GPFCON;
- extint_reg = S3C2410_EXTINT0;
+ extint_reg = S3C24XX_EXTINT0;
gpcon_offset = (irq - IRQ_EINT0) * 2;
extint_offset = (irq - IRQ_EINT0) * 4;
}
else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7))
{
gpcon_reg = S3C2410_GPFCON;
- extint_reg = S3C2410_EXTINT0;
+ extint_reg = S3C24XX_EXTINT0;
gpcon_offset = (irq - (EXTINT_OFF)) * 2;
extint_offset = (irq - (EXTINT_OFF)) * 4;
}
else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15))
{
gpcon_reg = S3C2410_GPGCON;
- extint_reg = S3C2410_EXTINT1;
+ extint_reg = S3C24XX_EXTINT1;
gpcon_offset = (irq - IRQ_EINT8) * 2;
extint_offset = (irq - IRQ_EINT8) * 4;
}
else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23))
{
gpcon_reg = S3C2410_GPGCON;
- extint_reg = S3C2410_EXTINT2;
+ extint_reg = S3C24XX_EXTINT2;
gpcon_offset = (irq - IRQ_EINT8) * 2;
extint_offset = (irq - IRQ_EINT16) * 4;
} else
@@ -572,6 +568,23 @@ s3c_irq_demux_uart2(unsigned int irq,
s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs);
}
+static void
+s3c_irq_demux_extint(unsigned int irq,
+ struct irqdesc *desc,
+ struct pt_regs *regs)
+{
+ unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
+ unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
+
+ eintpnd &= ~eintmsk;
+
+ if (eintpnd) {
+ irq = fls(eintpnd);
+ irq += (IRQ_EINT4 - (4 + 1));
+
+ desc_handle_irq(irq, irq_desc + irq, regs);
+ }
+}
/* s3c24xx_init_irq
*
@@ -591,12 +604,12 @@ void __init s3c24xx_init_irq(void)
last = 0;
for (i = 0; i < 4; i++) {
- pend = __raw_readl(S3C2410_EINTPEND);
+ pend = __raw_readl(S3C24XX_EINTPEND);
if (pend == 0 || pend == last)
break;
- __raw_writel(pend, S3C2410_EINTPEND);
+ __raw_writel(pend, S3C24XX_EINTPEND);
printk("irq: clearing pending ext status %08x\n", (int)pend);
last = pend;
}
@@ -630,12 +643,14 @@ void __init s3c24xx_init_irq(void)
irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n");
- for (irqno = IRQ_BATT_FLT; irqno <= IRQ_ADCPARENT; irqno++) {
+ for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) {
/* set all the s3c2410 internal irqs */
switch (irqno) {
/* deal with the special IRQs (cascaded) */
+ case IRQ_EINT4t7:
+ case IRQ_EINT8t23:
case IRQ_UART0:
case IRQ_UART1:
case IRQ_UART2:
@@ -659,12 +674,14 @@ void __init s3c24xx_init_irq(void)
/* setup the cascade irq handlers */
+ set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint);
+ set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint);
+
set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);
-
/* external interrupts */
for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
diff --git a/arch/arm/mach-s3c2410/mach-smdk2413.c b/arch/arm/mach-s3c2410/mach-smdk2413.c
new file mode 100644
index 0000000..b7ef7d3
--- /dev/null
+++ b/arch/arm/mach-s3c2410/mach-smdk2413.c
@@ -0,0 +1,126 @@
+/* linux/arch/arm/mach-s3c2410/mach-smdk2413.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Thanks to Dimity Andric (TomTom) and Steven Ryu (Samsung) for the
+ * loans of SMDK2413 to work with.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/hardware/iomd.h>
+#include <asm/setup.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+//#include <asm/debug-ll.h>
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-lcd.h>
+
+#include <asm/arch/idle.h>
+#include <asm/arch/fb.h>
+
+#include "s3c2410.h"
+#include "s3c2412.h"
+#include "clock.h"
+#include "devs.h"
+#include "cpu.h"
+
+#include "common-smdk.h"
+
+static struct map_desc smdk2413_iodesc[] __initdata = {
+};
+
+static struct s3c2410_uartcfg smdk2413_uartcfgs[] __initdata = {
+ [0] = {
+ .hwport = 0,
+ .flags = 0,
+ .ucon = 0x3c5,
+ .ulcon = 0x03,
+ .ufcon = 0x51,
+ },
+ [1] = {
+ .hwport = 1,
+ .flags = 0,
+ .ucon = 0x3c5,
+ .ulcon = 0x03,
+ .ufcon = 0x51,
+ },
+ /* IR port */
+ [2] = {
+ .hwport = 2,
+ .flags = 0,
+ .ucon = 0x3c5,
+ .ulcon = 0x43,
+ .ufcon = 0x51,
+ }
+};
+
+static struct platform_device *smdk2413_devices[] __initdata = {
+ &s3c_device_usb,
+ //&s3c_device_lcd,
+ &s3c_device_wdt,
+ &s3c_device_i2c,
+ &s3c_device_iis,
+};
+
+static struct s3c24xx_board smdk2413_board __initdata = {
+ .devices = smdk2413_devices,
+ .devices_count = ARRAY_SIZE(smdk2413_devices)
+};
+
+static void __init smdk2413_fixup(struct machine_desc *desc,
+ struct tag *tags, char **cmdline,
+ struct meminfo *mi)
+{
+ if (tags != phys_to_virt(S3C2410_SDRAM_PA + 0x100)) {
+ mi->nr_banks=1;
+ mi->bank[0].start = 0x30000000;
+ mi->bank[0].size = SZ_64M;
+ mi->bank[0].node = 0;
+ }
+}
+
+static void __init smdk2413_map_io(void)
+{
+ s3c24xx_init_io(smdk2413_iodesc, ARRAY_SIZE(smdk2413_iodesc));
+ s3c24xx_init_clocks(12000000);
+ s3c24xx_init_uarts(smdk2413_uartcfgs, ARRAY_SIZE(smdk2413_uartcfgs));
+ s3c24xx_set_board(&smdk2413_board);
+}
+
+static void __init smdk2413_machine_init(void)
+{
+ smdk_machine_init();
+}
+
+MACHINE_START(S3C2413, "SMDK2413")
+ /* Maintainer: Ben Dooks <ben@fluff.org> */
+ .phys_io = S3C2410_PA_UART,
+ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
+ .boot_params = S3C2410_SDRAM_PA + 0x100,
+
+ .fixup = smdk2413_fixup,
+ .init_irq = s3c24xx_init_irq,
+ .map_io = smdk2413_map_io,
+ .init_machine = smdk2413_machine_init,
+ .timer = &s3c24xx_timer,
+MACHINE_END
diff --git a/arch/arm/mach-s3c2410/pm-simtec.c b/arch/arm/mach-s3c2410/pm-simtec.c
index 4c7ccef..7b24456 100644
--- a/arch/arm/mach-s3c2410/pm-simtec.c
+++ b/arch/arm/mach-s3c2410/pm-simtec.c
@@ -48,7 +48,8 @@ static __init int pm_simtec_init(void)
/* check which machine we are running on */
- if (!machine_is_bast() && !machine_is_vr1000() && !machine_is_anubis())
+ if (!machine_is_bast() && !machine_is_vr1000() &&
+ !machine_is_anubis() && !machine_is_osiris())
return 0;
printk(KERN_INFO "Simtec Board Power Manangement" COPYRIGHT "\n");
diff --git a/arch/arm/mach-s3c2410/s3c2410-clock.c b/arch/arm/mach-s3c2410/s3c2410-clock.c
new file mode 100644
index 0000000..9971866
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2410-clock.c
@@ -0,0 +1,271 @@
+/* linux/arch/arm/mach-s3c2410/clock.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410,S3C2440,S3C2442 Clock control support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/sysdev.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-gpio.h>
+
+#include "clock.h"
+#include "cpu.h"
+
+int s3c2410_clkcon_enable(struct clk *clk, int enable)
+{
+ unsigned int clocks = clk->ctrlbit;
+ unsigned long clkcon;
+
+ clkcon = __raw_readl(S3C2410_CLKCON);
+
+ if (enable)
+ clkcon |= clocks;
+ else
+ clkcon &= ~clocks;
+
+ /* ensure none of the special function bits set */
+ clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER);
+
+ __raw_writel(clkcon, S3C2410_CLKCON);
+
+ return 0;
+}
+
+static int s3c2410_upll_enable(struct clk *clk, int enable)
+{
+ unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
+ unsigned long orig = clkslow;
+
+ if (enable)
+ clkslow &= ~S3C2410_CLKSLOW_UCLK_OFF;
+ else
+ clkslow |= S3C2410_CLKSLOW_UCLK_OFF;
+
+ __raw_writel(clkslow, S3C2410_CLKSLOW);
+
+ /* if we started the UPLL, then allow to settle */
+
+ if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF))
+ udelay(200);
+
+ return 0;
+}
+
+/* standard clock definitions */
+
+static struct clk init_clocks_disable[] = {
+ {
+ .name = "nand",
+ .id = -1,
+ .parent = &clk_h,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_NAND,
+ }, {
+ .name = "sdi",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_SDI,
+ }, {
+ .name = "adc",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_ADC,
+ }, {
+ .name = "i2c",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_IIC,
+ }, {
+ .name = "iis",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_IIS,
+ }, {
+ .name = "spi",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_SPI,
+ }
+};
+
+static struct clk init_clocks[] = {
+ {
+ .name = "lcd",
+ .id = -1,
+ .parent = &clk_h,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_LCDC,
+ }, {
+ .name = "gpio",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_GPIO,
+ }, {
+ .name = "usb-host",
+ .id = -1,
+ .parent = &clk_h,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_USBH,
+ }, {
+ .name = "usb-device",
+ .id = -1,
+ .parent = &clk_h,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_USBD,
+ }, {
+ .name = "timers",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_PWMT,
+ }, {
+ .name = "uart",
+ .id = 0,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_UART0,
+ }, {
+ .name = "uart",
+ .id = 1,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_UART1,
+ }, {
+ .name = "uart",
+ .id = 2,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_UART2,
+ }, {
+ .name = "rtc",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_RTC,
+ }, {
+ .name = "watchdog",
+ .id = -1,
+ .parent = &clk_p,
+ .ctrlbit = 0,
+ }, {
+ .name = "usb-bus-host",
+ .id = -1,
+ .parent = &clk_usb_bus,
+ }, {
+ .name = "usb-bus-gadget",
+ .id = -1,
+ .parent = &clk_usb_bus,
+ },
+};
+
+/* s3c2410_baseclk_add()
+ *
+ * Add all the clocks used by the s3c2410 or compatible CPUs
+ * such as the S3C2440 and S3C2442.
+ *
+ * We cannot use a system device as we are needed before any
+ * of the init-calls that initialise the devices are actually
+ * done.
+*/
+
+int __init s3c2410_baseclk_add(void)
+{
+ unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
+ unsigned long clkcon = __raw_readl(S3C2410_CLKCON);
+ struct clk *clkp;
+ struct clk *xtal;
+ int ret;
+ int ptr;
+
+ clk_upll.enable = s3c2410_upll_enable;
+
+ if (s3c24xx_register_clock(&clk_usb_bus) < 0)
+ printk(KERN_ERR "failed to register usb bus clock\n");
+
+ /* register clocks from clock array */
+
+ clkp = init_clocks;
+ for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
+ /* ensure that we note the clock state */
+
+ clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0;
+
+ ret = s3c24xx_register_clock(clkp);
+ if (ret < 0) {
+ printk(KERN_ERR "Failed to register clock %s (%d)\n",
+ clkp->name, ret);
+ }
+ }
+
+ /* We must be careful disabling the clocks we are not intending to
+ * be using at boot time, as subsytems such as the LCD which do
+ * their own DMA requests to the bus can cause the system to lockup
+ * if they where in the middle of requesting bus access.
+ *
+ * Disabling the LCD clock if the LCD is active is very dangerous,
+ * and therefore the bootloader should be careful to not enable
+ * the LCD clock if it is not needed.
+ */
+
+ /* install (and disable) the clocks we do not need immediately */
+
+ clkp = init_clocks_disable;
+ for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
+
+ ret = s3c24xx_register_clock(clkp);
+ if (ret < 0) {
+ printk(KERN_ERR "Failed to register clock %s (%d)\n",
+ clkp->name, ret);
+ }
+
+ s3c2410_clkcon_enable(clkp, 0);
+ }
+
+ /* show the clock-slow value */
+
+ xtal = clk_get(NULL, "xtal");
+
+ printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n",
+ print_mhz(clk_get_rate(xtal) /
+ ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))),
+ (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast",
+ (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on",
+ (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on");
+
+ return 0;
+}
diff --git a/arch/arm/mach-s3c2410/s3c2410-gpio.c b/arch/arm/mach-s3c2410/s3c2410-gpio.c
index d5e1cae..471a714 100644
--- a/arch/arm/mach-s3c2410/s3c2410-gpio.c
+++ b/arch/arm/mach-s3c2410/s3c2410-gpio.c
@@ -18,9 +18,6 @@
* 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
- *
- * Changelog
- * 15-Jan-2006 LCVR Splitted from gpio.c
*/
#include <linux/kernel.h>
@@ -38,7 +35,7 @@
int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
unsigned int config)
{
- void __iomem *reg = S3C2410_EINFLT0;
+ void __iomem *reg = S3C24XX_EINFLT0;
unsigned long flags;
unsigned long val;
@@ -47,7 +44,7 @@ int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
config &= 0xff;
- pin -= S3C2410_GPG8_EINT16;
+ pin -= S3C2410_GPG8;
reg += pin & ~3;
local_irq_save(flags);
@@ -61,10 +58,10 @@ int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
/* update filter enable */
- val = __raw_readl(S3C2410_EXTINT2);
+ val = __raw_readl(S3C24XX_EXTINT2);
val &= ~(1 << ((pin * 4) + 3));
val |= on << ((pin * 4) + 3);
- __raw_writel(val, S3C2410_EXTINT2);
+ __raw_writel(val, S3C24XX_EXTINT2);
local_irq_restore(flags);
@@ -75,7 +72,7 @@ EXPORT_SYMBOL(s3c2410_gpio_irqfilter);
int s3c2410_gpio_getirq(unsigned int pin)
{
- if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15_EINT23)
+ if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15)
return -1; /* not valid interrupts */
if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7)
diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c
index 0852e87..a110cff 100644
--- a/arch/arm/mach-s3c2410/s3c2410.c
+++ b/arch/arm/mach-s3c2410/s3c2410.c
@@ -27,6 +27,7 @@
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
+#include <linux/sysdev.h>
#include <linux/platform_device.h>
#include <asm/mach/arch.h>
@@ -108,11 +109,33 @@ void __init s3c2410_init_clocks(int xtal)
*/
s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
+ s3c2410_baseclk_add();
}
+struct sysdev_class s3c2410_sysclass = {
+ set_kset_name("s3c2410-core"),
+};
+
+static struct sys_device s3c2410_sysdev = {
+ .cls = &s3c2410_sysclass,
+};
+
+/* need to register class before we actually register the device, and
+ * we also need to ensure that it has been initialised before any of the
+ * drivers even try to use it (even if not on an s3c2440 based system)
+ * as a driver which may support both 2410 and 2440 may try and use it.
+*/
+
+static int __init s3c2410_core_init(void)
+{
+ return sysdev_class_register(&s3c2410_sysclass);
+}
+
+core_initcall(s3c2410_core_init);
+
int __init s3c2410_init(void)
{
printk("S3C2410: Initialising architecture\n");
- return 0;
+ return sysdev_register(&s3c2410_sysdev);
}
diff --git a/arch/arm/mach-s3c2410/s3c2410.h b/arch/arm/mach-s3c2410/s3c2410.h
index 4d5312a..73f1a24 100644
--- a/arch/arm/mach-s3c2410/s3c2410.h
+++ b/arch/arm/mach-s3c2410/s3c2410.h
@@ -29,6 +29,8 @@ extern void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no);
extern void s3c2410_init_clocks(int xtal);
+extern int s3c2410_baseclk_add(void);
+
#else
#define s3c2410_init_clocks NULL
#define s3c2410_init_uarts NULL
diff --git a/arch/arm/mach-s3c2410/s3c2412-clock.c b/arch/arm/mach-s3c2410/s3c2412-clock.c
new file mode 100644
index 0000000..c95ed3e
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2412-clock.c
@@ -0,0 +1,711 @@
+/* linux/arch/arm/mach-s3c2410/s3c2412-clock.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2412,S3C2413 Clock control support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/sysdev.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-gpio.h>
+
+#include "clock.h"
+#include "cpu.h"
+
+/* We currently have to assume that the system is running
+ * from the XTPll input, and that all ***REFCLKs are being
+ * fed from it, as we cannot read the state of OM[4] from
+ * software.
+ *
+ * It would be possible for each board initialisation to
+ * set the correct muxing at initialisation
+*/
+
+int s3c2412_clkcon_enable(struct clk *clk, int enable)
+{
+ unsigned int clocks = clk->ctrlbit;
+ unsigned long clkcon;
+
+ clkcon = __raw_readl(S3C2410_CLKCON);
+
+ if (enable)
+ clkcon |= clocks;
+ else
+ clkcon &= ~clocks;
+
+ __raw_writel(clkcon, S3C2410_CLKCON);
+
+ return 0;
+}
+
+static int s3c2412_upll_enable(struct clk *clk, int enable)
+{
+ unsigned long upllcon = __raw_readl(S3C2410_UPLLCON);
+ unsigned long orig = upllcon;
+
+ if (!enable)
+ upllcon |= S3C2412_PLLCON_OFF;
+ else
+ upllcon &= ~S3C2412_PLLCON_OFF;
+
+ __raw_writel(upllcon, S3C2410_UPLLCON);
+
+ /* allow ~150uS for the PLL to settle and lock */
+
+ if (enable && (orig & S3C2412_PLLCON_OFF))
+ udelay(150);
+
+ return 0;
+}
+
+/* clock selections */
+
+/* CPU EXTCLK input */
+static struct clk clk_ext = {
+ .name = "extclk",
+ .id = -1,
+};
+
+static struct clk clk_erefclk = {
+ .name = "erefclk",
+ .id = -1,
+};
+
+static struct clk clk_urefclk = {
+ .name = "urefclk",
+ .id = -1,
+};
+
+static int s3c2412_setparent_usysclk(struct clk *clk, struct clk *parent)
+{
+ unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
+
+ if (parent == &clk_urefclk)
+ clksrc &= ~S3C2412_CLKSRC_USYSCLK_UPLL;
+ else if (parent == &clk_upll)
+ clksrc |= S3C2412_CLKSRC_USYSCLK_UPLL;
+ else
+ return -EINVAL;
+
+ clk->parent = parent;
+
+ __raw_writel(clksrc, S3C2412_CLKSRC);
+ return 0;
+}
+
+static struct clk clk_usysclk = {
+ .name = "usysclk",
+ .id = -1,
+ .parent = &clk_xtal,
+ .set_parent = s3c2412_setparent_usysclk,
+};
+
+static struct clk clk_mrefclk = {
+ .name = "mrefclk",
+ .parent = &clk_xtal,
+ .id = -1,
+};
+
+static struct clk clk_mdivclk = {
+ .name = "mdivclk",
+ .parent = &clk_xtal,
+ .id = -1,
+};
+
+static int s3c2412_setparent_usbsrc(struct clk *clk, struct clk *parent)
+{
+ unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
+
+ if (parent == &clk_usysclk)
+ clksrc &= ~S3C2412_CLKSRC_USBCLK_HCLK;
+ else if (parent == &clk_h)
+ clksrc |= S3C2412_CLKSRC_USBCLK_HCLK;
+ else
+ return -EINVAL;
+
+ clk->parent = parent;
+
+ __raw_writel(clksrc, S3C2412_CLKSRC);
+ return 0;
+}
+
+static unsigned long s3c2412_roundrate_usbsrc(struct clk *clk,
+ unsigned long rate)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ int div;
+
+ if (rate > parent_rate)
+ return parent_rate;
+
+ div = parent_rate / rate;
+ if (div > 2)
+ div = 2;
+
+ return parent_rate / div;
+}
+
+static unsigned long s3c2412_getrate_usbsrc(struct clk *clk)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long div = __raw_readl(S3C2410_CLKDIVN);
+
+ return parent_rate / ((div & S3C2412_CLKDIVN_USB48DIV) ? 2 : 1);
+}
+
+static int s3c2412_setrate_usbsrc(struct clk *clk, unsigned long rate)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
+
+ rate = s3c2412_roundrate_usbsrc(clk, rate);
+
+ if ((parent_rate / rate) == 2)
+ clkdivn |= S3C2412_CLKDIVN_USB48DIV;
+ else
+ clkdivn &= ~S3C2412_CLKDIVN_USB48DIV;
+
+ __raw_writel(clkdivn, S3C2410_CLKDIVN);
+ return 0;
+}
+
+static struct clk clk_usbsrc = {
+ .name = "usbsrc",
+ .id = -1,
+ .get_rate = s3c2412_getrate_usbsrc,
+ .set_rate = s3c2412_setrate_usbsrc,
+ .round_rate = s3c2412_roundrate_usbsrc,
+ .set_parent = s3c2412_setparent_usbsrc,
+};
+
+static int s3c2412_setparent_msysclk(struct clk *clk, struct clk *parent)
+{
+ unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
+
+ if (parent == &clk_mdivclk)
+ clksrc &= ~S3C2412_CLKSRC_MSYSCLK_MPLL;
+ else if (parent == &clk_upll)
+ clksrc |= S3C2412_CLKSRC_MSYSCLK_MPLL;
+ else
+ return -EINVAL;
+
+ clk->parent = parent;
+
+ __raw_writel(clksrc, S3C2412_CLKSRC);
+ return 0;
+}
+
+static struct clk clk_msysclk = {
+ .name = "msysclk",
+ .id = -1,
+ .set_parent = s3c2412_setparent_msysclk,
+};
+
+/* these next clocks have an divider immediately after them,
+ * so we can register them with their divider and leave out the
+ * intermediate clock stage
+*/
+static unsigned long s3c2412_roundrate_clksrc(struct clk *clk,
+ unsigned long rate)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ int div;
+
+ if (rate > parent_rate)
+ return parent_rate;
+
+ /* note, we remove the +/- 1 calculations as they cancel out */
+
+ div = (rate / parent_rate);
+
+ if (div < 1)
+ div = 1;
+ else if (div > 16)
+ div = 16;
+
+ return parent_rate / div;
+}
+
+static int s3c2412_setparent_uart(struct clk *clk, struct clk *parent)
+{
+ unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
+
+ if (parent == &clk_erefclk)
+ clksrc &= ~S3C2412_CLKSRC_UARTCLK_MPLL;
+ else if (parent == &clk_mpll)
+ clksrc |= S3C2412_CLKSRC_UARTCLK_MPLL;
+ else
+ return -EINVAL;
+
+ clk->parent = parent;
+
+ __raw_writel(clksrc, S3C2412_CLKSRC);
+ return 0;
+}
+
+static unsigned long s3c2412_getrate_uart(struct clk *clk)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long div = __raw_readl(S3C2410_CLKDIVN);
+
+ div &= S3C2412_CLKDIVN_UARTDIV_MASK;
+ div >>= S3C2412_CLKDIVN_UARTDIV_SHIFT;
+
+ return parent_rate / (div + 1);
+}
+
+static int s3c2412_setrate_uart(struct clk *clk, unsigned long rate)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
+
+ rate = s3c2412_roundrate_clksrc(clk, rate);
+
+ clkdivn &= ~S3C2412_CLKDIVN_UARTDIV_MASK;
+ clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_UARTDIV_SHIFT;
+
+ __raw_writel(clkdivn, S3C2410_CLKDIVN);
+ return 0;
+}
+
+static struct clk clk_uart = {
+ .name = "uartclk",
+ .id = -1,
+ .get_rate = s3c2412_getrate_uart,
+ .set_rate = s3c2412_setrate_uart,
+ .set_parent = s3c2412_setparent_uart,
+ .round_rate = s3c2412_roundrate_clksrc,
+};
+
+static int s3c2412_setparent_i2s(struct clk *clk, struct clk *parent)
+{
+ unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
+
+ if (parent == &clk_erefclk)
+ clksrc &= ~S3C2412_CLKSRC_I2SCLK_MPLL;
+ else if (parent == &clk_mpll)
+ clksrc |= S3C2412_CLKSRC_I2SCLK_MPLL;
+ else
+ return -EINVAL;
+
+ clk->parent = parent;
+
+ __raw_writel(clksrc, S3C2412_CLKSRC);
+ return 0;
+}
+
+static unsigned long s3c2412_getrate_i2s(struct clk *clk)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long div = __raw_readl(S3C2410_CLKDIVN);
+
+ div &= S3C2412_CLKDIVN_I2SDIV_MASK;
+ div >>= S3C2412_CLKDIVN_I2SDIV_SHIFT;
+
+ return parent_rate / (div + 1);
+}
+
+static int s3c2412_setrate_i2s(struct clk *clk, unsigned long rate)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
+
+ rate = s3c2412_roundrate_clksrc(clk, rate);
+
+ clkdivn &= ~S3C2412_CLKDIVN_I2SDIV_MASK;
+ clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_I2SDIV_SHIFT;
+
+ __raw_writel(clkdivn, S3C2410_CLKDIVN);
+ return 0;
+}
+
+static struct clk clk_i2s = {
+ .name = "i2sclk",
+ .id = -1,
+ .get_rate = s3c2412_getrate_i2s,
+ .set_rate = s3c2412_setrate_i2s,
+ .set_parent = s3c2412_setparent_i2s,
+ .round_rate = s3c2412_roundrate_clksrc,
+};
+
+static int s3c2412_setparent_cam(struct clk *clk, struct clk *parent)
+{
+ unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
+
+ if (parent == &clk_usysclk)
+ clksrc &= ~S3C2412_CLKSRC_CAMCLK_HCLK;
+ else if (parent == &clk_h)
+ clksrc |= S3C2412_CLKSRC_CAMCLK_HCLK;
+ else
+ return -EINVAL;
+
+ clk->parent = parent;
+
+ __raw_writel(clksrc, S3C2412_CLKSRC);
+ return 0;
+}
+static unsigned long s3c2412_getrate_cam(struct clk *clk)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long div = __raw_readl(S3C2410_CLKDIVN);
+
+ div &= S3C2412_CLKDIVN_CAMDIV_MASK;
+ div >>= S3C2412_CLKDIVN_CAMDIV_SHIFT;
+
+ return parent_rate / (div + 1);
+}
+
+static int s3c2412_setrate_cam(struct clk *clk, unsigned long rate)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
+
+ rate = s3c2412_roundrate_clksrc(clk, rate);
+
+ clkdivn &= ~S3C2412_CLKDIVN_CAMDIV_MASK;
+ clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_CAMDIV_SHIFT;
+
+ __raw_writel(clkdivn, S3C2410_CLKDIVN);
+ return 0;
+}
+
+static struct clk clk_cam = {
+ .name = "camif-upll", /* same as 2440 name */
+ .id = -1,
+ .get_rate = s3c2412_getrate_cam,
+ .set_rate = s3c2412_setrate_cam,
+ .set_parent = s3c2412_setparent_cam,
+ .round_rate = s3c2412_roundrate_clksrc,
+};
+
+/* standard clock definitions */
+
+static struct clk init_clocks_disable[] = {
+ {
+ .name = "nand",
+ .id = -1,
+ .parent = &clk_h,
+ .enable = s3c2412_clkcon_enable,
+ .ctrlbit = S3C2412_CLKCON_NAND,
+ }, {
+ .name = "sdi",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2412_clkcon_enable,
+ .ctrlbit = S3C2412_CLKCON_SDI,
+ }, {
+ .name = "adc",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2412_clkcon_enable,
+ .ctrlbit = S3C2412_CLKCON_ADC,
+ }, {
+ .name = "i2c",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2412_clkcon_enable,
+ .ctrlbit = S3C2412_CLKCON_IIC,
+ }, {
+ .name = "iis",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2412_clkcon_enable,
+ .ctrlbit = S3C2412_CLKCON_IIS,
+ }, {
+ .name = "spi",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2412_clkcon_enable,
+ .ctrlbit = S3C2412_CLKCON_SPI,
+ }
+};
+
+static struct clk init_clocks[] = {
+ {
+ .name = "dma",
+ .id = 0,
+ .parent = &clk_h,
+ .enable = s3c2412_clkcon_enable,
+ .ctrlbit = S3C2412_CLKCON_DMA0,
+ }, {
+ .name = "dma",
+ .id = 1,
+ .parent = &clk_h,
+ .enable = s3c2412_clkcon_enable,
+ .ctrlbit = S3C2412_CLKCON_DMA1,
+ }, {
+ .name = "dma",
+ .id = 2,
+ .parent = &clk_h,
+ .enable = s3c2412_clkcon_enable,
+ .ctrlbit = S3C2412_CLKCON_DMA2,
+ }, {
+ .name = "dma",
+ .id = 3,
+ .parent = &clk_h,
+ .enable = s3c2412_clkcon_enable,
+ .ctrlbit = S3C2412_CLKCON_DMA3,
+ }, {
+ .name = "lcd",
+ .id = -1,
+ .parent = &clk_h,
+ .enable = s3c2412_clkcon_enable,
+ .ctrlbit = S3C2412_CLKCON_LCDC,
+ }, {
+ .name = "gpio",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2412_clkcon_enable,
+ .ctrlbit = S3C2412_CLKCON_GPIO,
+ }, {
+ .name = "usb-host",
+ .id = -1,
+ .parent = &clk_h,
+ .enable = s3c2412_clkcon_enable,
+ .ctrlbit = S3C2412_CLKCON_USBH,
+ }, {
+ .name = "usb-device",
+ .id = -1,
+ .parent = &clk_h,
+ .enable = s3c2412_clkcon_enable,
+ .ctrlbit = S3C2412_CLKCON_USBD,
+ }, {
+ .name = "timers",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2412_clkcon_enable,
+ .ctrlbit = S3C2412_CLKCON_PWMT,
+ }, {
+ .name = "uart",
+ .id = 0,
+ .parent = &clk_p,
+ .enable = s3c2412_clkcon_enable,
+ .ctrlbit = S3C2412_CLKCON_UART0,
+ }, {
+ .name = "uart",
+ .id = 1,
+ .parent = &clk_p,
+ .enable = s3c2412_clkcon_enable,
+ .ctrlbit = S3C2412_CLKCON_UART1,
+ }, {
+ .name = "uart",
+ .id = 2,
+ .parent = &clk_p,
+ .enable = s3c2412_clkcon_enable,
+ .ctrlbit = S3C2412_CLKCON_UART2,
+ }, {
+ .name = "rtc",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2412_clkcon_enable,
+ .ctrlbit = S3C2412_CLKCON_RTC,
+ }, {
+ .name = "watchdog",
+ .id = -1,
+ .parent = &clk_p,
+ .ctrlbit = 0,
+ }, {
+ .name = "usb-bus-gadget",
+ .id = -1,
+ .parent = &clk_usb_bus,
+ .enable = s3c2412_clkcon_enable,
+ .ctrlbit = S3C2412_CLKCON_USB_DEV48,
+ }, {
+ .name = "usb-bus-host",
+ .id = -1,
+ .parent = &clk_usb_bus,
+ .enable = s3c2412_clkcon_enable,
+ .ctrlbit = S3C2412_CLKCON_USB_HOST48,
+ }
+};
+
+/* clocks to add where we need to check their parentage */
+
+struct clk_init {
+ struct clk *clk;
+ unsigned int bit;
+ struct clk *src_0;
+ struct clk *src_1;
+};
+
+struct clk_init clks_src[] __initdata = {
+ {
+ .clk = &clk_usysclk,
+ .bit = S3C2412_CLKSRC_USBCLK_HCLK,
+ .src_0 = &clk_urefclk,
+ .src_1 = &clk_upll,
+ }, {
+ .clk = &clk_i2s,
+ .bit = S3C2412_CLKSRC_I2SCLK_MPLL,
+ .src_0 = &clk_erefclk,
+ .src_1 = &clk_mpll,
+ }, {
+ .clk = &clk_cam,
+ .bit = S3C2412_CLKSRC_CAMCLK_HCLK,
+ .src_0 = &clk_usysclk,
+ .src_1 = &clk_h,
+ }, {
+ .clk = &clk_msysclk,
+ .bit = S3C2412_CLKSRC_MSYSCLK_MPLL,
+ .src_0 = &clk_mdivclk,
+ .src_1 = &clk_mpll,
+ }, {
+ .clk = &clk_uart,
+ .bit = S3C2412_CLKSRC_UARTCLK_MPLL,
+ .src_0 = &clk_erefclk,
+ .src_1 = &clk_mpll,
+ }, {
+ .clk = &clk_usbsrc,
+ .bit = S3C2412_CLKSRC_USBCLK_HCLK,
+ .src_0 = &clk_usysclk,
+ .src_1 = &clk_h,
+ },
+};
+
+/* s3c2412_clk_initparents
+ *
+ * Initialise the parents for the clocks that we get at start-time
+*/
+
+static void __init s3c2412_clk_initparents(void)
+{
+ unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
+ struct clk_init *cip = clks_src;
+ struct clk *src;
+ int ptr;
+ int ret;
+
+ for (ptr = 0; ptr < ARRAY_SIZE(clks_src); ptr++, cip++) {
+ ret = s3c24xx_register_clock(cip->clk);
+ if (ret < 0) {
+ printk(KERN_ERR "Failed to register clock %s (%d)\n",
+ cip->clk->name, ret);
+ }
+
+ src = (clksrc & cip->bit) ? cip->src_1 : cip->src_0;
+
+ printk(KERN_INFO "%s: parent %s\n", cip->clk->name, src->name);
+ clk_set_parent(cip->clk, src);
+ }
+}
+
+/* clocks to add straight away */
+
+struct clk *clks[] __initdata = {
+ &clk_ext,
+ &clk_usb_bus,
+ &clk_erefclk,
+ &clk_urefclk,
+ &clk_mrefclk,
+};
+
+int __init s3c2412_baseclk_add(void)
+{
+ unsigned long clkcon = __raw_readl(S3C2410_CLKCON);
+ struct clk *clkp;
+ int ret;
+ int ptr;
+
+ clk_upll.enable = s3c2412_upll_enable;
+ clk_usb_bus.parent = &clk_usbsrc;
+ clk_usb_bus.rate = 0x0;
+
+ s3c2412_clk_initparents();
+
+ for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
+ clkp = clks[ptr];
+
+ ret = s3c24xx_register_clock(clkp);
+ if (ret < 0) {
+ printk(KERN_ERR "Failed to register clock %s (%d)\n",
+ clkp->name, ret);
+ }
+ }
+
+ /* ensure usb bus clock is within correct rate of 48MHz */
+
+ if (clk_get_rate(&clk_usb_bus) != (48 * 1000 * 1000)) {
+ printk(KERN_INFO "Warning: USB bus clock not at 48MHz\n");
+
+ /* for the moment, let's use the UPLL, and see if we can
+ * get 48MHz */
+
+ clk_set_parent(&clk_usysclk, &clk_upll);
+ clk_set_parent(&clk_usbsrc, &clk_usysclk);
+ clk_set_rate(&clk_usbsrc, 48*1000*1000);
+ }
+
+ printk("S3C2412: upll %s, %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
+ (__raw_readl(S3C2410_UPLLCON) & S3C2412_PLLCON_OFF) ? "off":"on",
+ print_mhz(clk_get_rate(&clk_upll)),
+ print_mhz(clk_get_rate(&clk_usb_bus)));
+
+ /* register clocks from clock array */
+
+ clkp = init_clocks;
+ for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
+ /* ensure that we note the clock state */
+
+ clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0;
+
+ ret = s3c24xx_register_clock(clkp);
+ if (ret < 0) {
+ printk(KERN_ERR "Failed to register clock %s (%d)\n",
+ clkp->name, ret);
+ }
+ }
+
+ /* We must be careful disabling the clocks we are not intending to
+ * be using at boot time, as subsytems such as the LCD which do
+ * their own DMA requests to the bus can cause the system to lockup
+ * if they where in the middle of requesting bus access.
+ *
+ * Disabling the LCD clock if the LCD is active is very dangerous,
+ * and therefore the bootloader should be careful to not enable
+ * the LCD clock if it is not needed.
+ */
+
+ /* install (and disable) the clocks we do not need immediately */
+
+ clkp = init_clocks_disable;
+ for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
+
+ ret = s3c24xx_register_clock(clkp);
+ if (ret < 0) {
+ printk(KERN_ERR "Failed to register clock %s (%d)\n",
+ clkp->name, ret);
+ }
+
+ s3c2412_clkcon_enable(clkp, 0);
+ }
+
+ return 0;
+}
diff --git a/arch/arm/mach-s3c2410/s3c2412.c b/arch/arm/mach-s3c2410/s3c2412.c
new file mode 100644
index 0000000..e24ffd5
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2412.c
@@ -0,0 +1,195 @@
+/* linux/arch/arm/mach-s3c2410/s3c2412.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://armlinux.simtec.co.uk/.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Modifications:
+ * 16-May-2003 BJD Created initial version
+ * 16-Aug-2003 BJD Fixed header files and copyright, added URL
+ * 05-Sep-2003 BJD Moved to kernel v2.6
+ * 18-Jan-2004 BJD Added serial port configuration
+ * 21-Aug-2004 BJD Added new struct s3c2410_board handler
+ * 28-Sep-2004 BJD Updates for new serial port bits
+ * 04-Nov-2004 BJD Updated UART configuration process
+ * 10-Jan-2005 BJD Removed s3c2410_clock_tick_rate
+ * 13-Aug-2005 DA Removed UART from initial I/O mappings
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/sysdev.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-gpioj.h>
+#include <asm/arch/regs-dsc.h>
+
+#include "s3c2412.h"
+#include "cpu.h"
+#include "devs.h"
+#include "clock.h"
+#include "pm.h"
+
+#ifndef CONFIG_CPU_S3C2412_ONLY
+void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO;
+#endif
+
+/* Initial IO mappings */
+
+static struct map_desc s3c2412_iodesc[] __initdata = {
+ IODESC_ENT(CLKPWR),
+ IODESC_ENT(LCD),
+ IODESC_ENT(TIMER),
+ IODESC_ENT(ADC),
+ IODESC_ENT(WATCHDOG),
+};
+
+/* uart registration process */
+
+void __init s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+ s3c24xx_init_uartdevs("s3c2412-uart", s3c2410_uart_resources, cfg, no);
+
+ /* rename devices that are s3c2412/s3c2413 specific */
+ s3c_device_sdi.name = "s3c2412-sdi";
+ s3c_device_nand.name = "s3c2412-nand";
+}
+
+/* s3c2412_map_io
+ *
+ * register the standard cpu IO areas, and any passed in from the
+ * machine specific initialisation.
+*/
+
+void __init s3c2412_map_io(struct map_desc *mach_desc, int mach_size)
+{
+ /* move base of IO */
+
+ s3c24xx_va_gpio2 = S3C24XX_VA_GPIO + 0x10;
+
+ /* register our io-tables */
+
+ iotable_init(s3c2412_iodesc, ARRAY_SIZE(s3c2412_iodesc));
+ iotable_init(mach_desc, mach_size);
+}
+
+void __init s3c2412_init_clocks(int xtal)
+{
+ unsigned long tmp;
+ unsigned long fclk;
+ unsigned long hclk;
+ unsigned long pclk;
+
+ /* now we've got our machine bits initialised, work out what
+ * clocks we've got */
+
+ fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal*2);
+
+ tmp = __raw_readl(S3C2410_CLKDIVN);
+
+ /* work out clock scalings */
+
+ hclk = fclk / ((tmp & S3C2412_CLKDIVN_HDIVN_MASK) + 1);
+ hclk /= ((tmp & S3C2421_CLKDIVN_ARMDIVN) ? 2 : 1);
+ pclk = hclk / ((tmp & S3C2412_CLKDIVN_PDIVN) ? 2 : 1);
+
+ /* print brieft summary of clocks, etc */
+
+ printk("S3C2412: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
+ print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
+
+ /* initialise the clocks here, to allow other things like the
+ * console to use them
+ */
+
+ s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
+ s3c2412_baseclk_add();
+}
+
+/* need to register class before we actually register the device, and
+ * we also need to ensure that it has been initialised before any of the
+ * drivers even try to use it (even if not on an s3c2412 based system)
+ * as a driver which may support both 2410 and 2440 may try and use it.
+*/
+
+#ifdef CONFIG_PM
+static struct sleep_save s3c2412_sleep[] = {
+ SAVE_ITEM(S3C2412_DSC0),
+ SAVE_ITEM(S3C2412_DSC1),
+ SAVE_ITEM(S3C2413_GPJDAT),
+ SAVE_ITEM(S3C2413_GPJCON),
+ SAVE_ITEM(S3C2413_GPJUP),
+
+ /* save the sleep configuration anyway, just in case these
+ * get damaged during wakeup */
+
+ SAVE_ITEM(S3C2412_GPBSLPCON),
+ SAVE_ITEM(S3C2412_GPCSLPCON),
+ SAVE_ITEM(S3C2412_GPDSLPCON),
+ SAVE_ITEM(S3C2412_GPESLPCON),
+ SAVE_ITEM(S3C2412_GPFSLPCON),
+ SAVE_ITEM(S3C2412_GPGSLPCON),
+ SAVE_ITEM(S3C2412_GPHSLPCON),
+ SAVE_ITEM(S3C2413_GPJSLPCON),
+};
+
+static int s3c2412_suspend(struct sys_device *dev, pm_message_t state)
+{
+ s3c2410_pm_do_save(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
+ return 0;
+}
+
+static int s3c2412_resume(struct sys_device *dev)
+{
+ s3c2410_pm_do_restore(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
+ return 0;
+}
+
+#else
+#define s3c2412_suspend NULL
+#define s3c2412_resume NULL
+#endif
+
+struct sysdev_class s3c2412_sysclass = {
+ set_kset_name("s3c2412-core"),
+ .suspend = s3c2412_suspend,
+ .resume = s3c2412_resume
+};
+
+static int __init s3c2412_core_init(void)
+{
+ return sysdev_class_register(&s3c2412_sysclass);
+}
+
+core_initcall(s3c2412_core_init);
+
+static struct sys_device s3c2412_sysdev = {
+ .cls = &s3c2412_sysclass,
+};
+
+int __init s3c2412_init(void)
+{
+ printk("S3C2412: Initialising architecture\n");
+
+ return sysdev_register(&s3c2412_sysdev);
+}
diff --git a/arch/arm/mach-s3c2410/s3c2412.h b/arch/arm/mach-s3c2410/s3c2412.h
new file mode 100644
index 0000000..c6e5603
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2412.h
@@ -0,0 +1,29 @@
+/* arch/arm/mach-s3c2410/s3c2412.h
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Header file for s3c2412 cpu support
+ *
+ * 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.
+*/
+
+#ifdef CONFIG_CPU_S3C2412
+
+extern int s3c2412_init(void);
+
+extern void s3c2412_map_io(struct map_desc *mach_desc, int size);
+
+extern void s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no);
+
+extern void s3c2412_init_clocks(int xtal);
+
+extern int s3c2412_baseclk_add(void);
+#else
+#define s3c2412_init_clocks NULL
+#define s3c2412_init_uarts NULL
+#define s3c2412_map_io NULL
+#define s3c2412_init NULL
+#endif
diff --git a/arch/arm/mach-s3c2410/s3c2440-clock.c b/arch/arm/mach-s3c2410/s3c2440-clock.c
index d7a30ed..1579686 100644
--- a/arch/arm/mach-s3c2410/s3c2440-clock.c
+++ b/arch/arm/mach-s3c2410/s3c2440-clock.c
@@ -91,7 +91,7 @@ static int s3c2440_camif_upll_setrate(struct clk *clk, unsigned long rate)
static struct clk s3c2440_clk_cam = {
.name = "camif",
.id = -1,
- .enable = s3c24xx_clkcon_enable,
+ .enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2440_CLKCON_CAMERA,
};
@@ -105,7 +105,7 @@ static struct clk s3c2440_clk_cam_upll = {
static struct clk s3c2440_clk_ac97 = {
.name = "ac97",
.id = -1,
- .enable = s3c24xx_clkcon_enable,
+ .enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2440_CLKCON_CAMERA,
};
diff --git a/arch/arm/mach-s3c2410/s3c2442-clock.c b/arch/arm/mach-s3c2410/s3c2442-clock.c
index 5b7b301..d9f54b5 100644
--- a/arch/arm/mach-s3c2410/s3c2442-clock.c
+++ b/arch/arm/mach-s3c2410/s3c2442-clock.c
@@ -102,7 +102,7 @@ static int s3c2442_camif_upll_setrate(struct clk *clk, unsigned long rate)
static struct clk s3c2442_clk_cam = {
.name = "camif",
.id = -1,
- .enable = s3c24xx_clkcon_enable,
+ .enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2440_CLKCON_CAMERA,
};
diff --git a/arch/arm/mach-s3c2410/s3c244x.c b/arch/arm/mach-s3c2410/s3c244x.c
index 96852a7..838bc52 100644
--- a/arch/arm/mach-s3c2410/s3c244x.c
+++ b/arch/arm/mach-s3c2410/s3c244x.c
@@ -34,6 +34,7 @@
#include <asm/arch/regs-gpioj.h>
#include <asm/arch/regs-dsc.h>
+#include "s3c2410.h"
#include "s3c2440.h"
#include "s3c244x.h"
#include "clock.h"
@@ -118,6 +119,7 @@ void __init s3c244x_init_clocks(int xtal)
*/
s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
+ s3c2410_baseclk_add();
}
#ifdef CONFIG_PM
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 4221d05..ecf5e23 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -61,9 +61,9 @@ config CPU_ARM720T
# ARM920T
config CPU_ARM920T
- bool "Support ARM920T processor" if !ARCH_S3C2410
- depends on ARCH_EP93XX || ARCH_INTEGRATOR || ARCH_S3C2410 || ARCH_IMX || ARCH_AAEC2000 || ARCH_AT91RM9200
- default y if ARCH_S3C2410 || ARCH_AT91RM9200
+ bool "Support ARM920T processor"
+ depends on ARCH_EP93XX || ARCH_INTEGRATOR || CPU_S3C2410 || CPU_S3C2440 || CPU_S3C2442 || ARCH_IMX || ARCH_AAEC2000 || ARCH_AT91RM9200
+ default y if CPU_S3C2410 || CPU_S3C2440 || CPU_S3C2442 || ARCH_AT91RM9200
select CPU_32v4
select CPU_ABRT_EV4T
select CPU_CACHE_V4WT
@@ -121,8 +121,8 @@ config CPU_ARM925T
# ARM926T
config CPU_ARM926T
bool "Support ARM926T processor"
- depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX
- default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX
+ depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412
+ default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412
select CPU_32v5
select CPU_ABRT_EV5TJ
select CPU_CACHE_VIVT
diff --git a/arch/arm/nwfpe/fpmodule.c b/arch/arm/nwfpe/fpmodule.c
index 2dfe1ac..7d977d2 100644
--- a/arch/arm/nwfpe/fpmodule.c
+++ b/arch/arm/nwfpe/fpmodule.c
@@ -33,7 +33,8 @@
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/init.h>
-/* XXX */
+
+#include <asm/thread_notify.h>
#include "softfloat.h"
#include "fpopcode.h"
@@ -56,16 +57,28 @@ void fp_send_sig(unsigned long sig, struct task_struct *p, int priv);
extern char fpe_type[];
#endif
+static int nwfpe_notify(struct notifier_block *self, unsigned long cmd, void *v)
+{
+ struct thread_info *thread = v;
+
+ if (cmd == THREAD_NOTIFY_FLUSH)
+ nwfpe_init_fpa(&thread->fpstate);
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block nwfpe_notifier_block = {
+ .notifier_call = nwfpe_notify,
+};
+
/* kernel function prototypes required */
void fp_setup(void);
/* external declarations for saved kernel symbols */
extern void (*kern_fp_enter)(void);
-extern void (*fp_init)(union fp_state *);
/* Original value of fp_enter from kernel before patched by fpe_init. */
static void (*orig_fp_enter)(void);
-static void (*orig_fp_init)(union fp_state *);
/* forward declarations */
extern void nwfpe_enter(void);
@@ -88,20 +101,20 @@ static int __init fpe_init(void)
printk(KERN_WARNING "NetWinder Floating Point Emulator V0.97 ("
NWFPE_BITS " precision)\n");
+ thread_register_notifier(&nwfpe_notifier_block);
+
/* Save pointer to the old FP handler and then patch ourselves in */
orig_fp_enter = kern_fp_enter;
- orig_fp_init = fp_init;
kern_fp_enter = nwfpe_enter;
- fp_init = nwfpe_init_fpa;
return 0;
}
static void __exit fpe_exit(void)
{
+ thread_unregister_notifier(&nwfpe_notifier_block);
/* Restore the values we saved earlier. */
kern_fp_enter = orig_fp_enter;
- fp_init = orig_fp_init;
}
/*
diff --git a/arch/arm/plat-omap/timer32k.c b/arch/arm/plat-omap/timer32k.c
index b2a943b..3461a6c 100644
--- a/arch/arm/plat-omap/timer32k.c
+++ b/arch/arm/plat-omap/timer32k.c
@@ -210,7 +210,8 @@ static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id,
now = omap_32k_sync_timer_read();
- while (now - omap_32k_last_tick >= OMAP_32K_TICKS_PER_HZ) {
+ while ((signed long)(now - omap_32k_last_tick)
+ >= OMAP_32K_TICKS_PER_HZ) {
omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ;
timer_tick(regs);
}
diff --git a/arch/arm/vfp/Makefile b/arch/arm/vfp/Makefile
index afabac3..7e136e7 100644
--- a/arch/arm/vfp/Makefile
+++ b/arch/arm/vfp/Makefile
@@ -7,6 +7,9 @@
# EXTRA_CFLAGS := -DDEBUG
# EXTRA_AFLAGS := -DDEBUG
+AFLAGS :=$(AFLAGS:-msoft-float=-Wa,-mfpu=softvfp+vfp)
+LDFLAGS +=--no-warn-mismatch
+
obj-y += vfp.o
-vfp-$(CONFIG_VFP) += entry.o vfpmodule.o vfphw.o vfpsingle.o vfpdouble.o
+vfp-$(CONFIG_VFP) += vfpmodule.o entry.o vfphw.o vfpsingle.o vfpdouble.o
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
index a3f65b4..eb683cd 100644
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -192,7 +192,7 @@ vfp_get_double:
add pc, pc, r0, lsl #3
mov r0, r0
.irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
- mrrc p11, 1, r0, r1, c\dr @ fmrrd r0, r1, d\dr
+ fmrrd r0, r1, d\dr
mov pc, lr
.endr
@@ -206,6 +206,6 @@ vfp_put_double:
add pc, pc, r0, lsl #3
mov r0, r0
.irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
- mcrr p11, 1, r1, r2, c\dr @ fmdrr r1, r2, d\dr
+ fmdrr d\dr, r1, r2
mov pc, lr
.endr
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 03486be..2476f4c 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -15,6 +15,8 @@
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/init.h>
+
+#include <asm/thread_notify.h>
#include <asm/vfp.h>
#include "vfpinstr.h"
@@ -36,38 +38,55 @@ union vfp_state *last_VFP_context;
*/
unsigned int VFP_arch;
-/*
- * Per-thread VFP initialisation.
- */
-void vfp_flush_thread(union vfp_state *vfp)
+static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
{
- memset(vfp, 0, sizeof(union vfp_state));
+ struct thread_info *thread = v;
+ union vfp_state *vfp = &thread->vfpstate;
- vfp->hard.fpexc = FPEXC_ENABLE;
- vfp->hard.fpscr = FPSCR_ROUND_NEAREST;
+ switch (cmd) {
+ case THREAD_NOTIFY_FLUSH:
+ /*
+ * Per-thread VFP initialisation.
+ */
+ memset(vfp, 0, sizeof(union vfp_state));
- /*
- * Disable VFP to ensure we initialise it first.
- */
- fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE);
+ vfp->hard.fpexc = FPEXC_ENABLE;
+ vfp->hard.fpscr = FPSCR_ROUND_NEAREST;
- /*
- * Ensure we don't try to overwrite our newly initialised
- * state information on the first fault.
- */
- if (last_VFP_context == vfp)
- last_VFP_context = NULL;
-}
+ /*
+ * Disable VFP to ensure we initialise it first.
+ */
+ fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE);
-/*
- * Per-thread VFP cleanup.
- */
-void vfp_release_thread(union vfp_state *vfp)
-{
- if (last_VFP_context == vfp)
- last_VFP_context = NULL;
+ /*
+ * FALLTHROUGH: Ensure we don't try to overwrite our newly
+ * initialised state information on the first fault.
+ */
+
+ case THREAD_NOTIFY_RELEASE:
+ /*
+ * Per-thread VFP cleanup.
+ */
+ if (last_VFP_context == vfp)
+ last_VFP_context = NULL;
+ break;
+
+ case THREAD_NOTIFY_SWITCH:
+ /*
+ * Always disable VFP so we can lazily save/restore the
+ * old state.
+ */
+ fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE);
+ break;
+ }
+
+ return NOTIFY_DONE;
}
+static struct notifier_block vfp_notifier_block = {
+ .notifier_call = vfp_notifier,
+};
+
/*
* Raise a SIGFPE for the current process.
* sicode describes the signal being raised.
@@ -281,6 +300,8 @@ static int __init vfp_init(void)
(vfpsid & FPSID_VARIANT_MASK) >> FPSID_VARIANT_BIT,
(vfpsid & FPSID_REV_MASK) >> FPSID_REV_BIT);
vfp_vector = vfp_support_entry;
+
+ thread_register_notifier(&vfp_notifier_block);
}
return 0;
}
diff --git a/arch/cris/arch-v32/drivers/pci/bios.c b/arch/cris/arch-v32/drivers/pci/bios.c
index 24bc149..1e9d062 100644
--- a/arch/cris/arch-v32/drivers/pci/bios.c
+++ b/arch/cris/arch-v32/drivers/pci/bios.c
@@ -27,8 +27,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
/* Leave vm_pgoff as-is, the PCI space address is the physical
* address on this platform.
*/
- vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO);
-
prot = pgprot_val(vma->vm_page_prot);
vma->vm_page_prot = __pgprot(prot);
diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S
index a9b5952..81d94e4 100644
--- a/arch/frv/kernel/entry.S
+++ b/arch/frv/kernel/entry.S
@@ -1474,7 +1474,7 @@ sys_call_table:
.long sys_mknodat
.long sys_fchownat
.long sys_futimesat
- .long sys_newfstatat /* 300 */
+ .long sys_fstatat64 /* 300 */
.long sys_unlinkat
.long sys_renameat
.long sys_linkat
diff --git a/arch/frv/kernel/frv_ksyms.c b/arch/frv/kernel/frv_ksyms.c
index 0f273a7..dee637f 100644
--- a/arch/frv/kernel/frv_ksyms.c
+++ b/arch/frv/kernel/frv_ksyms.c
@@ -26,16 +26,6 @@ extern long __memset_user(void *dst, const void *src, size_t count);
EXPORT_SYMBOL(__ioremap);
EXPORT_SYMBOL(iounmap);
-EXPORT_SYMBOL(strnlen);
-EXPORT_SYMBOL(strrchr);
-EXPORT_SYMBOL(strstr);
-EXPORT_SYMBOL(strchr);
-EXPORT_SYMBOL(strcat);
-EXPORT_SYMBOL(strlen);
-EXPORT_SYMBOL(strcmp);
-EXPORT_SYMBOL(strncmp);
-EXPORT_SYMBOL(strncpy);
-
EXPORT_SYMBOL(ip_fast_csum);
#if 0
@@ -44,8 +34,6 @@ EXPORT_SYMBOL(local_bh_count);
#endif
EXPORT_SYMBOL(kernel_thread);
-EXPORT_SYMBOL(enable_irq);
-EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL(__res_bus_clock_speed_HZ);
EXPORT_SYMBOL(__page_offset);
EXPORT_SYMBOL(__memcpy_user);
@@ -62,18 +50,12 @@ EXPORT_SYMBOL(memory_end);
EXPORT_SYMBOL(__debug_bug_trap);
-/* Networking helper routines. */
-EXPORT_SYMBOL(csum_partial_copy);
-
/* The following are special because they're not called
explicitly (the C compiler generates them). Fortunately,
their interface isn't gonna change any time soon now, so
it's OK to leave it out of version control. */
EXPORT_SYMBOL(memcpy);
EXPORT_SYMBOL(memset);
-EXPORT_SYMBOL(memcmp);
-EXPORT_SYMBOL(memscan);
-EXPORT_SYMBOL(memmove);
EXPORT_SYMBOL(__outsl_ns);
EXPORT_SYMBOL(__insl_ns);
diff --git a/arch/frv/kernel/irq-routing.c b/arch/frv/kernel/irq-routing.c
index d4776d1..b90b70a 100644
--- a/arch/frv/kernel/irq-routing.c
+++ b/arch/frv/kernel/irq-routing.c
@@ -112,7 +112,7 @@ struct irq_source frv_cpuuart[2] = {
#define __CPUUART(X, A) \
[X] = { \
.muxname = "uart", \
- .muxdata = (volatile void __iomem *) A, \
+ .muxdata = (volatile void __iomem *)(unsigned long)A,\
.irqmask = 1 << IRQ_CPU_UART##X, \
.doirq = frv_cpuuart_doirq, \
}
@@ -136,7 +136,7 @@ struct irq_source frv_cpudma[8] = {
#define __CPUDMA(X, A) \
[X] = { \
.muxname = "dma", \
- .muxdata = (volatile void __iomem *) A, \
+ .muxdata = (volatile void __iomem *)(unsigned long)A,\
.irqmask = 1 << IRQ_CPU_DMA##X, \
.doirq = frv_cpudma_doirq, \
}
@@ -164,7 +164,7 @@ struct irq_source frv_cputimer[3] = {
#define __CPUTIMER(X) \
[X] = { \
.muxname = "timer", \
- .muxdata = 0, \
+ .muxdata = NULL, \
.irqmask = 1 << IRQ_CPU_TIMER##X, \
.doirq = frv_cputimer_doirq, \
}
@@ -187,7 +187,7 @@ struct irq_source frv_cpuexternal[8] = {
#define __CPUEXTERNAL(X) \
[X] = { \
.muxname = "ext", \
- .muxdata = 0, \
+ .muxdata = NULL, \
.irqmask = 1 << IRQ_CPU_EXTERNAL##X, \
.doirq = frv_cpuexternal_doirq, \
}
diff --git a/arch/frv/kernel/irq.c b/arch/frv/kernel/irq.c
index 11fa326..8b112b3 100644
--- a/arch/frv/kernel/irq.c
+++ b/arch/frv/kernel/irq.c
@@ -625,7 +625,7 @@ static struct proc_dir_entry * irq_dir [NR_IRQS];
#define HEX_DIGITS 8
-static unsigned int parse_hex_value (const char *buffer,
+static unsigned int parse_hex_value (const char __user *buffer,
unsigned long count, unsigned long *ret)
{
unsigned char hexnum [HEX_DIGITS];
@@ -672,7 +672,7 @@ static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
return sprintf (page, "%08lx\n", *mask);
}
-static int prof_cpu_mask_write_proc (struct file *file, const char *buffer,
+static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
unsigned long *mask = (unsigned long *) data, full_count = count, err;
@@ -711,7 +711,7 @@ void init_irq_proc (void)
int i;
/* create /proc/irq */
- root_irq_dir = proc_mkdir("irq", 0);
+ root_irq_dir = proc_mkdir("irq", NULL);
/* create /proc/irq/prof_cpu_mask */
entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
diff --git a/arch/frv/kernel/pm.c b/arch/frv/kernel/pm.c
index f0b8fff..43ce28a13 100644
--- a/arch/frv/kernel/pm.c
+++ b/arch/frv/kernel/pm.c
@@ -137,7 +137,7 @@ unsigned long sleep_phys_sp(void *sp)
#define CTL_PM_P0 4
#define CTL_PM_CM 5
-static int user_atoi(char *ubuf, size_t len)
+static int user_atoi(char __user *ubuf, size_t len)
{
char buf[16];
unsigned long ret;
@@ -159,7 +159,7 @@ static int user_atoi(char *ubuf, size_t len)
* Send us to sleep.
*/
static int sysctl_pm_do_suspend(ctl_table *ctl, int write, struct file *filp,
- void *buffer, size_t *lenp, loff_t *fpos)
+ void __user *buffer, size_t *lenp, loff_t *fpos)
{
int retval, mode;
@@ -215,7 +215,7 @@ static int try_set_cmode(int new_cmode)
static int cmode_procctl(ctl_table *ctl, int write, struct file *filp,
- void *buffer, size_t *lenp, loff_t *fpos)
+ void __user *buffer, size_t *lenp, loff_t *fpos)
{
int new_cmode;
@@ -227,9 +227,9 @@ static int cmode_procctl(ctl_table *ctl, int write, struct file *filp,
return try_set_cmode(new_cmode)?:*lenp;
}
-static int cmode_sysctl(ctl_table *table, int *name, int nlen,
- void *oldval, size_t *oldlenp,
- void *newval, size_t newlen, void **context)
+static int cmode_sysctl(ctl_table *table, int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen, void **context)
{
if (oldval && oldlenp) {
size_t oldlen;
@@ -240,7 +240,7 @@ static int cmode_sysctl(ctl_table *table, int *name, int nlen,
if (oldlen != sizeof(int))
return -EINVAL;
- if (put_user(clock_cmode_current, (unsigned int *)oldval) ||
+ if (put_user(clock_cmode_current, (unsigned __user *)oldval) ||
put_user(sizeof(int), oldlenp))
return -EFAULT;
}
@@ -250,7 +250,7 @@ static int cmode_sysctl(ctl_table *table, int *name, int nlen,
if (newlen != sizeof(int))
return -EINVAL;
- if (get_user(new_cmode, (int *)newval))
+ if (get_user(new_cmode, (int __user *)newval))
return -EFAULT;
return try_set_cmode(new_cmode)?:1;
@@ -318,7 +318,7 @@ static int try_set_cm(int new_cm)
}
static int p0_procctl(ctl_table *ctl, int write, struct file *filp,
- void *buffer, size_t *lenp, loff_t *fpos)
+ void __user *buffer, size_t *lenp, loff_t *fpos)
{
int new_p0;
@@ -330,9 +330,9 @@ static int p0_procctl(ctl_table *ctl, int write, struct file *filp,
return try_set_p0(new_p0)?:*lenp;
}
-static int p0_sysctl(ctl_table *table, int *name, int nlen,
- void *oldval, size_t *oldlenp,
- void *newval, size_t newlen, void **context)
+static int p0_sysctl(ctl_table *table, int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen, void **context)
{
if (oldval && oldlenp) {
size_t oldlen;
@@ -343,7 +343,7 @@ static int p0_sysctl(ctl_table *table, int *name, int nlen,
if (oldlen != sizeof(int))
return -EINVAL;
- if (put_user(clock_p0_current, (unsigned int *)oldval) ||
+ if (put_user(clock_p0_current, (unsigned __user *)oldval) ||
put_user(sizeof(int), oldlenp))
return -EFAULT;
}
@@ -353,7 +353,7 @@ static int p0_sysctl(ctl_table *table, int *name, int nlen,
if (newlen != sizeof(int))
return -EINVAL;
- if (get_user(new_p0, (int *)newval))
+ if (get_user(new_p0, (int __user *)newval))
return -EFAULT;
return try_set_p0(new_p0)?:1;
@@ -362,7 +362,7 @@ static int p0_sysctl(ctl_table *table, int *name, int nlen,
}
static int cm_procctl(ctl_table *ctl, int write, struct file *filp,
- void *buffer, size_t *lenp, loff_t *fpos)
+ void __user *buffer, size_t *lenp, loff_t *fpos)
{
int new_cm;
@@ -374,9 +374,9 @@ static int cm_procctl(ctl_table *ctl, int write, struct file *filp,
return try_set_cm(new_cm)?:*lenp;
}
-static int cm_sysctl(ctl_table *table, int *name, int nlen,
- void *oldval, size_t *oldlenp,
- void *newval, size_t newlen, void **context)
+static int cm_sysctl(ctl_table *table, int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen, void **context)
{
if (oldval && oldlenp) {
size_t oldlen;
@@ -387,7 +387,7 @@ static int cm_sysctl(ctl_table *table, int *name, int nlen,
if (oldlen != sizeof(int))
return -EINVAL;
- if (put_user(clock_cm_current, (unsigned int *)oldval) ||
+ if (put_user(clock_cm_current, (unsigned __user *)oldval) ||
put_user(sizeof(int), oldlenp))
return -EFAULT;
}
@@ -397,7 +397,7 @@ static int cm_sysctl(ctl_table *table, int *name, int nlen,
if (newlen != sizeof(int))
return -EINVAL;
- if (get_user(new_cm, (int *)newval))
+ if (get_user(new_cm, (int __user *)newval))
return -EFAULT;
return try_set_cm(new_cm)?:1;
diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c
index 0fff8a6..489e6c4 100644
--- a/arch/frv/kernel/process.c
+++ b/arch/frv/kernel/process.c
@@ -246,7 +246,7 @@ int copy_thread(int nr, unsigned long clone_flags,
/*
* sys_execve() executes a new program.
*/
-asmlinkage int sys_execve(char *name, char **argv, char **envp)
+asmlinkage int sys_execve(char __user *name, char __user * __user *argv, char __user * __user *envp)
{
int error;
char * filename;
diff --git a/arch/frv/kernel/setup.c b/arch/frv/kernel/setup.c
index 5908dea..1f7d65f 100644
--- a/arch/frv/kernel/setup.c
+++ b/arch/frv/kernel/setup.c
@@ -814,7 +814,7 @@ void __init setup_arch(char **cmdline_p)
* - by now the stack is part of the init task */
printk("Memory %08lx-%08lx\n", memory_start, memory_end);
- if (memory_start == memory_end) BUG();
+ BUG_ON(memory_start == memory_end);
init_mm.start_code = (unsigned long) &_stext;
init_mm.end_code = (unsigned long) &_etext;
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c
index 679c1d5..b8a5882 100644
--- a/arch/frv/kernel/signal.c
+++ b/arch/frv/kernel/signal.c
@@ -98,7 +98,7 @@ int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
struct sigframe
{
- void (*pretcode)(void);
+ __sigrestore_t pretcode;
int sig;
struct sigcontext sc;
unsigned long extramask[_NSIG_WORDS-1];
@@ -107,10 +107,10 @@ struct sigframe
struct rt_sigframe
{
- void (*pretcode)(void);
+ __sigrestore_t pretcode;
int sig;
- struct siginfo *pinfo;
- void *puc;
+ struct siginfo __user *pinfo;
+ void __user *puc;
struct siginfo info;
struct ucontext uc;
uint32_t retcode[2];
@@ -233,7 +233,7 @@ static inline void __user *get_sigframe(struct k_sigaction *ka,
/* This is the X/Open sanctioned signal stack switching. */
if (ka->sa.sa_flags & SA_ONSTACK) {
- if (! on_sig_stack(sp))
+ if (! sas_ss_flags(sp))
sp = current->sas_ss_sp + current->sas_ss_size;
}
@@ -284,7 +284,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set)
* setlos #__NR_sigreturn,gr7
* tira gr0,0
*/
- if (__put_user((void (*)(void))frame->retcode, &frame->pretcode) ||
+ if (__put_user((__sigrestore_t)frame->retcode, &frame->pretcode) ||
__put_user(0x8efc0000|__NR_sigreturn, &frame->retcode[0]) ||
__put_user(0xc0700000, &frame->retcode[1]))
goto give_sigsegv;
@@ -300,7 +300,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set)
if (get_personality & FDPIC_FUNCPTRS) {
struct fdpic_func_descriptor __user *funcptr =
- (struct fdpic_func_descriptor *) ka->sa.sa_handler;
+ (struct fdpic_func_descriptor __user *) ka->sa.sa_handler;
__get_user(__frame->pc, &funcptr->text);
__get_user(__frame->gr15, &funcptr->GOT);
} else {
@@ -359,8 +359,8 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Create the ucontext. */
if (__put_user(0, &frame->uc.uc_flags) ||
- __put_user(0, &frame->uc.uc_link) ||
- __put_user((void*)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp) ||
+ __put_user(NULL, &frame->uc.uc_link) ||
+ __put_user((void __user *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp) ||
__put_user(sas_ss_flags(__frame->sp), &frame->uc.uc_stack.ss_flags) ||
__put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size))
goto give_sigsegv;
@@ -382,7 +382,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
* setlos #__NR_sigreturn,gr7
* tira gr0,0
*/
- if (__put_user((void (*)(void))frame->retcode, &frame->pretcode) ||
+ if (__put_user((__sigrestore_t)frame->retcode, &frame->pretcode) ||
__put_user(0x8efc0000|__NR_rt_sigreturn, &frame->retcode[0]) ||
__put_user(0xc0700000, &frame->retcode[1]))
goto give_sigsegv;
@@ -398,7 +398,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
__frame->gr9 = (unsigned long) &frame->info;
if (get_personality & FDPIC_FUNCPTRS) {
- struct fdpic_func_descriptor *funcptr =
+ struct fdpic_func_descriptor __user *funcptr =
(struct fdpic_func_descriptor __user *) ka->sa.sa_handler;
__get_user(__frame->pc, &funcptr->text);
__get_user(__frame->gr15, &funcptr->GOT);
diff --git a/arch/frv/kernel/sys_frv.c b/arch/frv/kernel/sys_frv.c
index 931aa6d..c4d4348 100644
--- a/arch/frv/kernel/sys_frv.c
+++ b/arch/frv/kernel/sys_frv.c
@@ -32,7 +32,7 @@
* sys_pipe() is the normal C calling standard for creating
* a pipe. It's not the way unix traditionally does this, though.
*/
-asmlinkage long sys_pipe(unsigned long * fildes)
+asmlinkage long sys_pipe(unsigned long __user * fildes)
{
int fd[2];
int error;
diff --git a/arch/frv/kernel/sysctl.c b/arch/frv/kernel/sysctl.c
index 408b0f3..b908863 100644
--- a/arch/frv/kernel/sysctl.c
+++ b/arch/frv/kernel/sysctl.c
@@ -49,7 +49,7 @@ static void frv_change_dcache_mode(unsigned long newmode)
* handle requests to dynamically switch the write caching mode delivered by /proc
*/
static int procctl_frv_cachemode(ctl_table *table, int write, struct file *filp,
- void *buffer, size_t *lenp, loff_t *ppos)
+ void __user *buffer, size_t *lenp, loff_t *ppos)
{
unsigned long hsr0;
char buff[8];
@@ -123,7 +123,7 @@ static int procctl_frv_cachemode(ctl_table *table, int write, struct file *filp,
*/
#ifdef CONFIG_MMU
static int procctl_frv_pin_cxnr(ctl_table *table, int write, struct file *filp,
- void *buffer, size_t *lenp, loff_t *ppos)
+ void __user *buffer, size_t *lenp, loff_t *ppos)
{
pid_t pid;
char buff[16], *p;
diff --git a/arch/frv/kernel/uaccess.c b/arch/frv/kernel/uaccess.c
index 9b751c0..9fb771a 100644
--- a/arch/frv/kernel/uaccess.c
+++ b/arch/frv/kernel/uaccess.c
@@ -17,7 +17,7 @@
/*
* copy a null terminated string from userspace
*/
-long strncpy_from_user(char *dst, const char *src, long count)
+long strncpy_from_user(char *dst, const char __user *src, long count)
{
unsigned long max;
char *p, ch;
@@ -70,9 +70,9 @@ EXPORT_SYMBOL(strncpy_from_user);
*
* Return 0 on exception, a value greater than N if too long
*/
-long strnlen_user(const char *src, long count)
+long strnlen_user(const char __user *src, long count)
{
- const char *p;
+ const char __user *p;
long err = 0;
char ch;
diff --git a/arch/frv/mb93090-mb00/pci-irq.c b/arch/frv/mb93090-mb00/pci-irq.c
index c4a1144..45ae39d 100644
--- a/arch/frv/mb93090-mb00/pci-irq.c
+++ b/arch/frv/mb93090-mb00/pci-irq.c
@@ -32,11 +32,11 @@
*/
static const uint8_t __initdata pci_bus0_irq_routing[32][4] = {
- [0 ] { IRQ_FPGA_MB86943_PCI_INTA },
- [16] { IRQ_FPGA_RTL8029_INTA },
- [17] { IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD, IRQ_FPGA_PCI_INTA, IRQ_FPGA_PCI_INTB },
- [18] { IRQ_FPGA_PCI_INTB, IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD, IRQ_FPGA_PCI_INTA },
- [19] { IRQ_FPGA_PCI_INTA, IRQ_FPGA_PCI_INTB, IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD },
+ [0 ] = { IRQ_FPGA_MB86943_PCI_INTA },
+ [16] = { IRQ_FPGA_RTL8029_INTA },
+ [17] = { IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD, IRQ_FPGA_PCI_INTA, IRQ_FPGA_PCI_INTB },
+ [18] = { IRQ_FPGA_PCI_INTB, IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD, IRQ_FPGA_PCI_INTA },
+ [19] = { IRQ_FPGA_PCI_INTA, IRQ_FPGA_PCI_INTB, IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD },
};
void __init pcibios_irq_init(void)
diff --git a/arch/frv/mm/kmap.c b/arch/frv/mm/kmap.c
index c54f18e..40b62c5 100644
--- a/arch/frv/mm/kmap.c
+++ b/arch/frv/mm/kmap.c
@@ -31,15 +31,15 @@
* Map some physical address range into the kernel address space.
*/
-void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
+void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
{
- return (void *)physaddr;
+ return (void __iomem *)physaddr;
}
/*
* Unmap a ioremap()ed region again
*/
-void iounmap(void *addr)
+void iounmap(void volatile __iomem *addr)
{
}
diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c
index f13d5e8..7787f70 100644
--- a/arch/h8300/kernel/signal.c
+++ b/arch/h8300/kernel/signal.c
@@ -307,7 +307,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
/* This is the X/Open sanctioned signal stack switching. */
if (ka->sa.sa_flags & SA_ONSTACK) {
- if (!on_sig_stack(usp))
+ if (!sas_ss_flags(usp))
usp = current->sas_ss_sp + current->sas_ss_size;
}
return (void *)((usp - frame_size) & -8UL);
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index 8dfa305..1596101 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -173,6 +173,12 @@ config ACPI_SRAT
bool
default y
depends on NUMA && (X86_SUMMIT || X86_GENERICARCH)
+ select ACPI_NUMA
+
+config HAVE_ARCH_PARSE_SRAT
+ bool
+ default y
+ depends on ACPI_SRAT
config X86_SUMMIT_NUMA
bool
@@ -224,7 +230,6 @@ config NR_CPUS
config SCHED_SMT
bool "SMT (Hyperthreading) scheduler support"
depends on SMP
- default off
help
SMT scheduler support improves the CPU scheduler's decision making
when dealing with Intel Pentium 4 chips with HyperThreading at a
diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
index 40e5aba..97ca171 100644
--- a/arch/i386/kernel/acpi/boot.c
+++ b/arch/i386/kernel/acpi/boot.c
@@ -202,6 +202,8 @@ int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
if (mcfg->config[i].base_reserved) {
printk(KERN_ERR PREFIX
"MMCONFIG not in low 4GB of memory\n");
+ kfree(pci_mmcfg_config);
+ pci_mmcfg_config_num = 0;
return -ENODEV;
}
}
@@ -215,7 +217,7 @@ static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size)
{
struct acpi_table_madt *madt = NULL;
- if (!phys_addr || !size)
+ if (!phys_addr || !size || !cpu_has_apic)
return -EINVAL;
madt = (struct acpi_table_madt *)__acpi_map_table(phys_addr, size);
@@ -621,9 +623,9 @@ extern u32 pmtmr_ioport;
static int __init acpi_parse_fadt(unsigned long phys, unsigned long size)
{
- struct fadt_descriptor_rev2 *fadt = NULL;
+ struct fadt_descriptor *fadt = NULL;
- fadt = (struct fadt_descriptor_rev2 *)__acpi_map_table(phys, size);
+ fadt = (struct fadt_descriptor *)__acpi_map_table(phys, size);
if (!fadt) {
printk(KERN_WARNING PREFIX "Unable to map FADT\n");
return 0;
@@ -754,7 +756,7 @@ static int __init acpi_parse_madt_ioapic_entries(void)
return -ENODEV;
}
- if (!cpu_has_apic)
+ if (!cpu_has_apic)
return -ENODEV;
/*
diff --git a/arch/i386/kernel/acpi/processor.c b/arch/i386/kernel/acpi/processor.c
index 9f4cc02..b54fded 100644
--- a/arch/i386/kernel/acpi/processor.c
+++ b/arch/i386/kernel/acpi/processor.c
@@ -47,7 +47,7 @@ static void init_intel_pdc(struct acpi_processor *pr, struct cpuinfo_x86 *c)
buf[2] = ACPI_PDC_C_CAPABILITY_SMP;
if (cpu_has(c, X86_FEATURE_EST))
- buf[2] |= ACPI_PDC_EST_CAPABILITY_SMP;
+ buf[2] |= ACPI_PDC_EST_CAPABILITY_SWSMP;
obj->type = ACPI_TYPE_BUFFER;
obj->buffer.length = 12;
diff --git a/arch/i386/kernel/acpi/sleep.c b/arch/i386/kernel/acpi/sleep.c
index 1cb2b18..4ee8357 100644
--- a/arch/i386/kernel/acpi/sleep.c
+++ b/arch/i386/kernel/acpi/sleep.c
@@ -8,30 +8,17 @@
#include <linux/acpi.h>
#include <linux/bootmem.h>
#include <linux/dmi.h>
+#include <linux/cpumask.h>
+
#include <asm/smp.h>
-#include <asm/tlbflush.h>
/* address in low memory of the wakeup routine. */
unsigned long acpi_wakeup_address = 0;
unsigned long acpi_video_flags;
extern char wakeup_start, wakeup_end;
-extern void zap_low_mappings(void);
-
extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long));
-static void init_low_mapping(pgd_t * pgd, int pgd_limit)
-{
- int pgd_ofs = 0;
-
- while ((pgd_ofs < pgd_limit)
- && (pgd_ofs + USER_PTRS_PER_PGD < PTRS_PER_PGD)) {
- set_pgd(pgd, *(pgd + USER_PTRS_PER_PGD));
- pgd_ofs++, pgd++;
- }
- flush_tlb_all();
-}
-
/**
* acpi_save_state_mem - save kernel state
*
@@ -42,7 +29,6 @@ int acpi_save_state_mem(void)
{
if (!acpi_wakeup_address)
return 1;
- init_low_mapping(swapper_pg_dir, USER_PTRS_PER_PGD);
memcpy((void *)acpi_wakeup_address, &wakeup_start,
&wakeup_end - &wakeup_start);
acpi_copy_wakeup_routine(acpi_wakeup_address);
@@ -55,7 +41,6 @@ int acpi_save_state_mem(void)
*/
void acpi_restore_state_mem(void)
{
- zap_low_mappings();
}
/**
diff --git a/arch/i386/kernel/acpi/wakeup.S b/arch/i386/kernel/acpi/wakeup.S
index 7c74fe0..9f408ee 100644
--- a/arch/i386/kernel/acpi/wakeup.S
+++ b/arch/i386/kernel/acpi/wakeup.S
@@ -56,7 +56,7 @@ wakeup_code:
1:
# set up page table
- movl $swapper_pg_dir-__PAGE_OFFSET, %eax
+ movl $swsusp_pg_dir-__PAGE_OFFSET, %eax
movl %eax, %cr3
testl $1, real_efer_save_restore - wakeup_code
@@ -265,11 +265,6 @@ ENTRY(acpi_copy_wakeup_routine)
movl $0x12345678, saved_magic
ret
-.data
-ALIGN
-ENTRY(saved_magic) .long 0
-ENTRY(saved_eip) .long 0
-
save_registers:
leal 4(%esp), %eax
movl %eax, saved_context_esp
@@ -304,7 +299,11 @@ ret_point:
call restore_processor_state
ret
+.data
ALIGN
+ENTRY(saved_magic) .long 0
+ENTRY(saved_eip) .long 0
+
# saved registers
saved_gdt: .long 0,0
saved_idt: .long 0,0
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 3d4b2f3..5ab59c1 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -62,7 +62,7 @@ int apic_verbosity;
static void apic_pm_activate(void);
-int modern_apic(void)
+static int modern_apic(void)
{
unsigned int lvr, version;
/* AMD systems use old APIC versions, so check the CPU */
@@ -113,7 +113,7 @@ void __init apic_intr_init(void)
}
/* Using APIC to generate smp_local_timer_interrupt? */
-int using_apic_timer = 0;
+int using_apic_timer __read_mostly = 0;
static int enabled_via_apicbase;
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index df0e174..9e819eb 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -374,14 +374,14 @@ static struct {
unsigned short segment;
} apm_bios_entry;
static int clock_slowed;
-static int idle_threshold = DEFAULT_IDLE_THRESHOLD;
-static int idle_period = DEFAULT_IDLE_PERIOD;
+static int idle_threshold __read_mostly = DEFAULT_IDLE_THRESHOLD;
+static int idle_period __read_mostly = DEFAULT_IDLE_PERIOD;
static int set_pm_idle;
static int suspends_pending;
static int standbys_pending;
static int ignore_sys_suspend;
static int ignore_normal_resume;
-static int bounce_interval = DEFAULT_BOUNCE_INTERVAL;
+static int bounce_interval __read_mostly = DEFAULT_BOUNCE_INTERVAL;
#ifdef CONFIG_APM_RTC_IS_GMT
# define clock_cmos_diff 0
@@ -390,8 +390,8 @@ static int bounce_interval = DEFAULT_BOUNCE_INTERVAL;
static long clock_cmos_diff;
static int got_clock_diff;
#endif
-static int debug;
-static int smp;
+static int debug __read_mostly;
+static int smp __read_mostly;
static int apm_disabled = -1;
#ifdef CONFIG_SMP
static int power_off;
@@ -403,8 +403,8 @@ static int realmode_power_off = 1;
#else
static int realmode_power_off;
#endif
-static int exit_kapmd;
-static int kapmd_running;
+static int exit_kapmd __read_mostly;
+static int kapmd_running __read_mostly;
#ifdef CONFIG_APM_ALLOW_INTS
static int allow_ints = 1;
#else
@@ -416,15 +416,15 @@ static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
static struct apm_user * user_list;
static DEFINE_SPINLOCK(user_list_lock);
-static struct desc_struct bad_bios_desc = { 0, 0x00409200 };
+static const struct desc_struct bad_bios_desc = { 0, 0x00409200 };
-static char driver_version[] = "1.16ac"; /* no spaces */
+static const char driver_version[] = "1.16ac"; /* no spaces */
/*
* APM event names taken from the APM 1.2 specification. These are
* the message codes that the BIOS uses to tell us about events
*/
-static char * apm_event_name[] = {
+static const char * const apm_event_name[] = {
"system standby",
"system suspend",
"normal resume",
@@ -616,7 +616,7 @@ static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in,
* @ecx_in: ECX register value for BIOS call
* @eax: EAX register on return from the BIOS call
*
- * Make a BIOS call that does only returns one value, or just status.
+ * Make a BIOS call that returns one value only, or just status.
* If there is an error, then the error code is returned in AH
* (bits 8-15 of eax) and this function returns non-zero. This is
* used for simpler BIOS operations. This call may hold interrupts
@@ -822,7 +822,7 @@ static void apm_do_busy(void)
#define IDLE_CALC_LIMIT (HZ * 100)
#define IDLE_LEAKY_MAX 16
-static void (*original_pm_idle)(void);
+static void (*original_pm_idle)(void) __read_mostly;
/**
* apm_cpu_idle - cpu idling for APM capable Linux
@@ -1063,7 +1063,8 @@ static int apm_engage_power_management(u_short device, int enable)
static int apm_console_blank(int blank)
{
- int error, i;
+ int error = APM_NOT_ENGAGED; /* silence gcc */
+ int i;
u_short state;
static const u_short dev[3] = { 0x100, 0x1FF, 0x101 };
@@ -1104,7 +1105,8 @@ static int queue_empty(struct apm_user *as)
static apm_event_t get_queued_event(struct apm_user *as)
{
- as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
+ if (++as->event_tail >= APM_MAX_EVENTS)
+ as->event_tail = 0;
return as->events[as->event_tail];
}
@@ -1118,13 +1120,16 @@ static void queue_event(apm_event_t event, struct apm_user *sender)
for (as = user_list; as != NULL; as = as->next) {
if ((as == sender) || (!as->reader))
continue;
- as->event_head = (as->event_head + 1) % APM_MAX_EVENTS;
+ if (++as->event_head >= APM_MAX_EVENTS)
+ as->event_head = 0;
+
if (as->event_head == as->event_tail) {
static int notified;
if (notified++ == 0)
printk(KERN_ERR "apm: an event queue overflowed\n");
- as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
+ if (++as->event_tail >= APM_MAX_EVENTS)
+ as->event_tail = 0;
}
as->events[as->event_head] = event;
if ((!as->suser) || (!as->writer))
@@ -1282,7 +1287,7 @@ static void standby(void)
static apm_event_t get_event(void)
{
int error;
- apm_event_t event;
+ apm_event_t event = APM_NO_EVENTS; /* silence gcc */
apm_eventinfo_t info;
static int notified;
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
index a06a490..44f2c5f 100644
--- a/arch/i386/kernel/cpu/common.c
+++ b/arch/i386/kernel/cpu/common.c
@@ -11,6 +11,8 @@
#include <asm/msr.h>
#include <asm/io.h>
#include <asm/mmu_context.h>
+#include <asm/mtrr.h>
+#include <asm/mce.h>
#ifdef CONFIG_X86_LOCAL_APIC
#include <asm/mpspec.h>
#include <asm/apic.h>
diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
index 1a7bdce..5fd6532 100644
--- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -48,12 +48,13 @@ MODULE_LICENSE("GPL");
struct cpufreq_acpi_io {
- struct acpi_processor_performance acpi_data;
+ struct acpi_processor_performance *acpi_data;
struct cpufreq_frequency_table *freq_table;
unsigned int resume;
};
static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS];
+static struct acpi_processor_performance *acpi_perf_data[NR_CPUS];
static struct cpufreq_driver acpi_cpufreq_driver;
@@ -104,64 +105,43 @@ acpi_processor_set_performance (
{
u16 port = 0;
u8 bit_width = 0;
- int ret;
- u32 value = 0;
int i = 0;
- struct cpufreq_freqs cpufreq_freqs;
- cpumask_t saved_mask;
+ int ret = 0;
+ u32 value = 0;
int retval;
+ struct acpi_processor_performance *perf;
dprintk("acpi_processor_set_performance\n");
- /*
- * TBD: Use something other than set_cpus_allowed.
- * As set_cpus_allowed is a bit racy,
- * with any other set_cpus_allowed for this process.
- */
- saved_mask = current->cpus_allowed;
- set_cpus_allowed(current, cpumask_of_cpu(cpu));
- if (smp_processor_id() != cpu) {
- return (-EAGAIN);
- }
-
- if (state == data->acpi_data.state) {
+ retval = 0;
+ perf = data->acpi_data;
+ if (state == perf->state) {
if (unlikely(data->resume)) {
dprintk("Called after resume, resetting to P%d\n", state);
data->resume = 0;
} else {
dprintk("Already at target state (P%d)\n", state);
- retval = 0;
- goto migrate_end;
+ return (retval);
}
}
- dprintk("Transitioning from P%d to P%d\n",
- data->acpi_data.state, state);
-
- /* cpufreq frequency struct */
- cpufreq_freqs.cpu = cpu;
- cpufreq_freqs.old = data->freq_table[data->acpi_data.state].frequency;
- cpufreq_freqs.new = data->freq_table[state].frequency;
-
- /* notify cpufreq */
- cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
+ dprintk("Transitioning from P%d to P%d\n", perf->state, state);
/*
* First we write the target state's 'control' value to the
* control_register.
*/
- port = data->acpi_data.control_register.address;
- bit_width = data->acpi_data.control_register.bit_width;
- value = (u32) data->acpi_data.states[state].control;
+ port = perf->control_register.address;
+ bit_width = perf->control_register.bit_width;
+ value = (u32) perf->states[state].control;
dprintk("Writing 0x%08x to port 0x%04x\n", value, port);
ret = acpi_processor_write_port(port, bit_width, value);
if (ret) {
dprintk("Invalid port width 0x%04x\n", bit_width);
- retval = ret;
- goto migrate_end;
+ return (ret);
}
/*
@@ -177,48 +157,35 @@ acpi_processor_set_performance (
* before giving up.
*/
- port = data->acpi_data.status_register.address;
- bit_width = data->acpi_data.status_register.bit_width;
+ port = perf->status_register.address;
+ bit_width = perf->status_register.bit_width;
dprintk("Looking for 0x%08x from port 0x%04x\n",
- (u32) data->acpi_data.states[state].status, port);
+ (u32) perf->states[state].status, port);
- for (i=0; i<100; i++) {
+ for (i = 0; i < 100; i++) {
ret = acpi_processor_read_port(port, bit_width, &value);
if (ret) {
dprintk("Invalid port width 0x%04x\n", bit_width);
- retval = ret;
- goto migrate_end;
+ return (ret);
}
- if (value == (u32) data->acpi_data.states[state].status)
+ if (value == (u32) perf->states[state].status)
break;
udelay(10);
}
} else {
- value = (u32) data->acpi_data.states[state].status;
+ value = (u32) perf->states[state].status;
}
- /* notify cpufreq */
- cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
-
- if (unlikely(value != (u32) data->acpi_data.states[state].status)) {
- unsigned int tmp = cpufreq_freqs.new;
- cpufreq_freqs.new = cpufreq_freqs.old;
- cpufreq_freqs.old = tmp;
- cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
- cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
+ if (unlikely(value != (u32) perf->states[state].status)) {
printk(KERN_WARNING "acpi-cpufreq: Transition failed\n");
retval = -ENODEV;
- goto migrate_end;
+ return (retval);
}
dprintk("Transition successful after %d microseconds\n", i * 10);
- data->acpi_data.state = state;
-
- retval = 0;
-migrate_end:
- set_cpus_allowed(current, saved_mask);
+ perf->state = state;
return (retval);
}
@@ -230,8 +197,17 @@ acpi_cpufreq_target (
unsigned int relation)
{
struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
+ struct acpi_processor_performance *perf;
+ struct cpufreq_freqs freqs;
+ cpumask_t online_policy_cpus;
+ cpumask_t saved_mask;
+ cpumask_t set_mask;
+ cpumask_t covered_cpus;
+ unsigned int cur_state = 0;
unsigned int next_state = 0;
unsigned int result = 0;
+ unsigned int j;
+ unsigned int tmp;
dprintk("acpi_cpufreq_setpolicy\n");
@@ -240,11 +216,95 @@ acpi_cpufreq_target (
target_freq,
relation,
&next_state);
- if (result)
+ if (unlikely(result))
return (result);
- result = acpi_processor_set_performance (data, policy->cpu, next_state);
+ perf = data->acpi_data;
+ cur_state = perf->state;
+ freqs.old = data->freq_table[cur_state].frequency;
+ freqs.new = data->freq_table[next_state].frequency;
+
+#ifdef CONFIG_HOTPLUG_CPU
+ /* cpufreq holds the hotplug lock, so we are safe from here on */
+ cpus_and(online_policy_cpus, cpu_online_map, policy->cpus);
+#else
+ online_policy_cpus = policy->cpus;
+#endif
+
+ for_each_cpu_mask(j, online_policy_cpus) {
+ freqs.cpu = j;
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ }
+
+ /*
+ * We need to call driver->target() on all or any CPU in
+ * policy->cpus, depending on policy->shared_type.
+ */
+ saved_mask = current->cpus_allowed;
+ cpus_clear(covered_cpus);
+ for_each_cpu_mask(j, online_policy_cpus) {
+ /*
+ * Support for SMP systems.
+ * Make sure we are running on CPU that wants to change freq
+ */
+ cpus_clear(set_mask);
+ if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
+ cpus_or(set_mask, set_mask, online_policy_cpus);
+ else
+ cpu_set(j, set_mask);
+
+ set_cpus_allowed(current, set_mask);
+ if (unlikely(!cpu_isset(smp_processor_id(), set_mask))) {
+ dprintk("couldn't limit to CPUs in this domain\n");
+ result = -EAGAIN;
+ break;
+ }
+
+ result = acpi_processor_set_performance (data, j, next_state);
+ if (result) {
+ result = -EAGAIN;
+ break;
+ }
+
+ if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
+ break;
+
+ cpu_set(j, covered_cpus);
+ }
+
+ for_each_cpu_mask(j, online_policy_cpus) {
+ freqs.cpu = j;
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ }
+ if (unlikely(result)) {
+ /*
+ * We have failed halfway through the frequency change.
+ * We have sent callbacks to online_policy_cpus and
+ * acpi_processor_set_performance() has been called on
+ * coverd_cpus. Best effort undo..
+ */
+
+ if (!cpus_empty(covered_cpus)) {
+ for_each_cpu_mask(j, covered_cpus) {
+ policy->cpu = j;
+ acpi_processor_set_performance (data,
+ j,
+ cur_state);
+ }
+ }
+
+ tmp = freqs.new;
+ freqs.new = freqs.old;
+ freqs.old = tmp;
+ for_each_cpu_mask(j, online_policy_cpus) {
+ freqs.cpu = j;
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ }
+ }
+
+ set_cpus_allowed(current, saved_mask);
return (result);
}
@@ -270,30 +330,65 @@ acpi_cpufreq_guess_freq (
struct cpufreq_acpi_io *data,
unsigned int cpu)
{
+ struct acpi_processor_performance *perf = data->acpi_data;
+
if (cpu_khz) {
/* search the closest match to cpu_khz */
unsigned int i;
unsigned long freq;
- unsigned long freqn = data->acpi_data.states[0].core_frequency * 1000;
+ unsigned long freqn = perf->states[0].core_frequency * 1000;
- for (i=0; i < (data->acpi_data.state_count - 1); i++) {
+ for (i = 0; i < (perf->state_count - 1); i++) {
freq = freqn;
- freqn = data->acpi_data.states[i+1].core_frequency * 1000;
+ freqn = perf->states[i+1].core_frequency * 1000;
if ((2 * cpu_khz) > (freqn + freq)) {
- data->acpi_data.state = i;
+ perf->state = i;
return (freq);
}
}
- data->acpi_data.state = data->acpi_data.state_count - 1;
+ perf->state = perf->state_count - 1;
return (freqn);
- } else
+ } else {
/* assume CPU is at P0... */
- data->acpi_data.state = 0;
- return data->acpi_data.states[0].core_frequency * 1000;
-
+ perf->state = 0;
+ return perf->states[0].core_frequency * 1000;
+ }
}
+/*
+ * acpi_cpufreq_early_init - initialize ACPI P-States library
+ *
+ * Initialize the ACPI P-States library (drivers/acpi/processor_perflib.c)
+ * in order to determine correct frequency and voltage pairings. We can
+ * do _PDC and _PSD and find out the processor dependency for the
+ * actual init that will happen later...
+ */
+static int acpi_cpufreq_early_init_acpi(void)
+{
+ struct acpi_processor_performance *data;
+ unsigned int i, j;
+
+ dprintk("acpi_cpufreq_early_init\n");
+
+ for_each_possible_cpu(i) {
+ data = kzalloc(sizeof(struct acpi_processor_performance),
+ GFP_KERNEL);
+ if (!data) {
+ for_each_possible_cpu(j) {
+ kfree(acpi_perf_data[j]);
+ acpi_perf_data[j] = NULL;
+ }
+ return (-ENOMEM);
+ }
+ acpi_perf_data[i] = data;
+ }
+
+ /* Do initialization in ACPI core */
+ acpi_processor_preregister_performance(acpi_perf_data);
+ return 0;
+}
+
static int
acpi_cpufreq_cpu_init (
struct cpufreq_policy *policy)
@@ -303,41 +398,51 @@ acpi_cpufreq_cpu_init (
struct cpufreq_acpi_io *data;
unsigned int result = 0;
struct cpuinfo_x86 *c = &cpu_data[policy->cpu];
+ struct acpi_processor_performance *perf;
dprintk("acpi_cpufreq_cpu_init\n");
+ if (!acpi_perf_data[cpu])
+ return (-ENODEV);
+
data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
if (!data)
return (-ENOMEM);
+ data->acpi_data = acpi_perf_data[cpu];
acpi_io_data[cpu] = data;
- result = acpi_processor_register_performance(&data->acpi_data, cpu);
+ result = acpi_processor_register_performance(data->acpi_data, cpu);
if (result)
goto err_free;
+ perf = data->acpi_data;
+ policy->cpus = perf->shared_cpu_map;
+ policy->shared_type = perf->shared_type;
+
if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) {
acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS;
}
/* capability check */
- if (data->acpi_data.state_count <= 1) {
+ if (perf->state_count <= 1) {
dprintk("No P-States\n");
result = -ENODEV;
goto err_unreg;
}
- if ((data->acpi_data.control_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO) ||
- (data->acpi_data.status_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
+
+ if ((perf->control_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO) ||
+ (perf->status_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
dprintk("Unsupported address space [%d, %d]\n",
- (u32) (data->acpi_data.control_register.space_id),
- (u32) (data->acpi_data.status_register.space_id));
+ (u32) (perf->control_register.space_id),
+ (u32) (perf->status_register.space_id));
result = -ENODEV;
goto err_unreg;
}
/* alloc freq_table */
- data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * (data->acpi_data.state_count + 1), GFP_KERNEL);
+ data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * (perf->state_count + 1), GFP_KERNEL);
if (!data->freq_table) {
result = -ENOMEM;
goto err_unreg;
@@ -345,9 +450,9 @@ acpi_cpufreq_cpu_init (
/* detect transition latency */
policy->cpuinfo.transition_latency = 0;
- for (i=0; i<data->acpi_data.state_count; i++) {
- if ((data->acpi_data.states[i].transition_latency * 1000) > policy->cpuinfo.transition_latency)
- policy->cpuinfo.transition_latency = data->acpi_data.states[i].transition_latency * 1000;
+ for (i=0; i<perf->state_count; i++) {
+ if ((perf->states[i].transition_latency * 1000) > policy->cpuinfo.transition_latency)
+ policy->cpuinfo.transition_latency = perf->states[i].transition_latency * 1000;
}
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
@@ -355,11 +460,11 @@ acpi_cpufreq_cpu_init (
policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu);
/* table init */
- for (i=0; i<=data->acpi_data.state_count; i++)
+ for (i=0; i<=perf->state_count; i++)
{
data->freq_table[i].index = i;
- if (i<data->acpi_data.state_count)
- data->freq_table[i].frequency = data->acpi_data.states[i].core_frequency * 1000;
+ if (i<perf->state_count)
+ data->freq_table[i].frequency = perf->states[i].core_frequency * 1000;
else
data->freq_table[i].frequency = CPUFREQ_TABLE_END;
}
@@ -374,12 +479,12 @@ acpi_cpufreq_cpu_init (
printk(KERN_INFO "acpi-cpufreq: CPU%u - ACPI performance management activated.\n",
cpu);
- for (i = 0; i < data->acpi_data.state_count; i++)
+ for (i = 0; i < perf->state_count; i++)
dprintk(" %cP%d: %d MHz, %d mW, %d uS\n",
- (i == data->acpi_data.state?'*':' '), i,
- (u32) data->acpi_data.states[i].core_frequency,
- (u32) data->acpi_data.states[i].power,
- (u32) data->acpi_data.states[i].transition_latency);
+ (i == perf->state?'*':' '), i,
+ (u32) perf->states[i].core_frequency,
+ (u32) perf->states[i].power,
+ (u32) perf->states[i].transition_latency);
cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu);
@@ -394,7 +499,7 @@ acpi_cpufreq_cpu_init (
err_freqfree:
kfree(data->freq_table);
err_unreg:
- acpi_processor_unregister_performance(&data->acpi_data, cpu);
+ acpi_processor_unregister_performance(perf, cpu);
err_free:
kfree(data);
acpi_io_data[cpu] = NULL;
@@ -415,7 +520,7 @@ acpi_cpufreq_cpu_exit (
if (data) {
cpufreq_frequency_table_put_attr(policy->cpu);
acpi_io_data[policy->cpu] = NULL;
- acpi_processor_unregister_performance(&data->acpi_data, policy->cpu);
+ acpi_processor_unregister_performance(data->acpi_data, policy->cpu);
kfree(data);
}
@@ -462,7 +567,10 @@ acpi_cpufreq_init (void)
dprintk("acpi_cpufreq_init\n");
- result = cpufreq_register_driver(&acpi_cpufreq_driver);
+ result = acpi_cpufreq_early_init_acpi();
+
+ if (!result)
+ result = cpufreq_register_driver(&acpi_cpufreq_driver);
return (result);
}
@@ -471,10 +579,15 @@ acpi_cpufreq_init (void)
static void __exit
acpi_cpufreq_exit (void)
{
+ unsigned int i;
dprintk("acpi_cpufreq_exit\n");
cpufreq_unregister_driver(&acpi_cpufreq_driver);
+ for_each_possible_cpu(i) {
+ kfree(acpi_perf_data[i]);
+ acpi_perf_data[i] = NULL;
+ }
return;
}
diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
index b4277f5..2d64916 100644
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
@@ -120,7 +120,7 @@ static int pending_bit_stuck(void)
{
u32 lo, hi;
- if (cpu_family)
+ if (cpu_family == CPU_HW_PSTATE)
return 0;
rdmsr(MSR_FIDVID_STATUS, lo, hi);
@@ -136,7 +136,7 @@ static int query_current_values_with_pending_wait(struct powernow_k8_data *data)
u32 lo, hi;
u32 i = 0;
- if (cpu_family) {
+ if (cpu_family == CPU_HW_PSTATE) {
rdmsr(MSR_PSTATE_STATUS, lo, hi);
i = lo & HW_PSTATE_MASK;
rdmsr(MSR_PSTATE_DEF_BASE + i, lo, hi);
@@ -598,7 +598,7 @@ static void print_basics(struct powernow_k8_data *data)
int j;
for (j = 0; j < data->numps; j++) {
if (data->powernow_table[j].frequency != CPUFREQ_ENTRY_INVALID) {
- if (cpu_family) {
+ if (cpu_family == CPU_HW_PSTATE) {
printk(KERN_INFO PFX " %d : fid 0x%x gid 0x%x (%d MHz)\n", j, (data->powernow_table[j].index & 0xff00) >> 8,
(data->powernow_table[j].index & 0xff0000) >> 16,
data->powernow_table[j].frequency/1000);
@@ -758,7 +758,7 @@ static int find_psb_table(struct powernow_k8_data *data)
#ifdef CONFIG_X86_POWERNOW_K8_ACPI
static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index)
{
- if (!data->acpi_data.state_count || cpu_family)
+ if (!data->acpi_data.state_count || (cpu_family == CPU_HW_PSTATE))
return;
data->irt = (data->acpi_data.states[index].control >> IRT_SHIFT) & IRT_MASK;
@@ -801,7 +801,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
goto err_out;
}
- if (cpu_family)
+ if (cpu_family == CPU_HW_PSTATE)
ret_val = fill_powernow_table_pstate(data, powernow_table);
else
ret_val = fill_powernow_table_fidvid(data, powernow_table);
@@ -885,8 +885,8 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data, struct cpuf
u32 vid;
if (data->exttype) {
- fid = data->acpi_data.states[i].status & FID_MASK;
- vid = (data->acpi_data.states[i].status >> VID_SHIFT) & VID_MASK;
+ fid = data->acpi_data.states[i].status & EXT_FID_MASK;
+ vid = (data->acpi_data.states[i].status >> VID_SHIFT) & EXT_VID_MASK;
} else {
fid = data->acpi_data.states[i].control & FID_MASK;
vid = (data->acpi_data.states[i].control >> VID_SHIFT) & VID_MASK;
@@ -1082,7 +1082,7 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi
if (query_current_values_with_pending_wait(data))
goto err_out;
- if (cpu_family)
+ if (cpu_family == CPU_HW_PSTATE)
dprintk("targ: curr fid 0x%x, did 0x%x\n",
data->currfid, data->currvid);
else {
@@ -1103,7 +1103,7 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi
powernow_k8_acpi_pst_values(data, newstate);
- if (cpu_family)
+ if (cpu_family == CPU_HW_PSTATE)
ret = transition_frequency_pstate(data, newstate);
else
ret = transition_frequency_fidvid(data, newstate);
@@ -1115,7 +1115,7 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi
}
mutex_unlock(&fidvid_mutex);
- if (cpu_family)
+ if (cpu_family == CPU_HW_PSTATE)
pol->cur = find_khz_freq_from_fiddid(data->currfid, data->currdid);
else
pol->cur = find_khz_freq_from_fid(data->currfid);
@@ -1163,7 +1163,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
* Use the PSB BIOS structure. This is only availabe on
* an UP version, and is deprecated by AMD.
*/
- if ((num_online_cpus() != 1) || (num_possible_cpus() != 1)) {
+ if (num_online_cpus() != 1) {
printk(KERN_ERR PFX "MP systems not supported by PSB BIOS structure\n");
kfree(data);
return -ENODEV;
@@ -1197,14 +1197,14 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
if (query_current_values_with_pending_wait(data))
goto err_out;
- if (!cpu_family)
+ if (cpu_family == CPU_OPTERON)
fidvid_msr_init();
/* run on any CPU again */
set_cpus_allowed(current, oldmask);
pol->governor = CPUFREQ_DEFAULT_GOVERNOR;
- if (cpu_family)
+ if (cpu_family == CPU_HW_PSTATE)
pol->cpus = cpumask_of_cpu(pol->cpu);
else
pol->cpus = cpu_core_map[pol->cpu];
@@ -1215,7 +1215,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
pol->cpuinfo.transition_latency = (((data->rvo + 8) * data->vstable * VST_UNITS_20US)
+ (3 * (1 << data->irt) * 10)) * 1000;
- if (cpu_family)
+ if (cpu_family == CPU_HW_PSTATE)
pol->cur = find_khz_freq_from_fiddid(data->currfid, data->currdid);
else
pol->cur = find_khz_freq_from_fid(data->currfid);
@@ -1232,7 +1232,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
cpufreq_frequency_table_get_attr(data->powernow_table, pol->cpu);
- if (cpu_family)
+ if (cpu_family == CPU_HW_PSTATE)
dprintk("cpu_init done, current fid 0x%x, did 0x%x\n",
data->currfid, data->currdid);
else
diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
index bf8ad9e..0fb2a30 100644
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
@@ -169,7 +169,9 @@ struct powernow_k8_data {
#define MVS_MASK 3
#define VST_MASK 0x7f
#define VID_MASK 0x1f
-#define FID_MASK 0x3f
+#define FID_MASK 0x1f
+#define EXT_VID_MASK 0x3f
+#define EXT_FID_MASK 0x3f
/*
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
index ce54ff1..f7e4356 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
@@ -2,19 +2,15 @@
* cpufreq driver for Enhanced SpeedStep, as found in Intel's Pentium
* M (part of the Centrino chipset).
*
+ * Since the original Pentium M, most new Intel CPUs support Enhanced
+ * SpeedStep.
+ *
* Despite the "SpeedStep" in the name, this is almost entirely unlike
* traditional SpeedStep.
*
* Modelled on speedstep.c
*
* Copyright (C) 2003 Jeremy Fitzhardinge <jeremy@goop.org>
- *
- * WARNING WARNING WARNING
- *
- * This driver manipulates the PERF_CTL MSR, which is only somewhat
- * documented. While it seems to work on my laptop, it has not been
- * tested anywhere else, and it may not work for you, do strange
- * things or simply crash.
*/
#include <linux/kernel.h>
@@ -36,7 +32,7 @@
#include <asm/cpufeature.h>
#define PFX "speedstep-centrino: "
-#define MAINTAINER "Jeremy Fitzhardinge <jeremy@goop.org>"
+#define MAINTAINER "cpufreq@lists.linux.org.uk"
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-centrino", msg)
@@ -351,7 +347,36 @@ static unsigned int get_cur_freq(unsigned int cpu)
#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
-static struct acpi_processor_performance p;
+static struct acpi_processor_performance *acpi_perf_data[NR_CPUS];
+
+/*
+ * centrino_cpu_early_init_acpi - Do the preregistering with ACPI P-States
+ * library
+ *
+ * Before doing the actual init, we need to do _PSD related setup whenever
+ * supported by the BIOS. These are handled by this early_init routine.
+ */
+static int centrino_cpu_early_init_acpi(void)
+{
+ unsigned int i, j;
+ struct acpi_processor_performance *data;
+
+ for_each_possible_cpu(i) {
+ data = kzalloc(sizeof(struct acpi_processor_performance),
+ GFP_KERNEL);
+ if (!data) {
+ for_each_possible_cpu(j) {
+ kfree(acpi_perf_data[j]);
+ acpi_perf_data[j] = NULL;
+ }
+ return (-ENOMEM);
+ }
+ acpi_perf_data[i] = data;
+ }
+
+ acpi_processor_preregister_performance(acpi_perf_data);
+ return 0;
+}
/*
* centrino_cpu_init_acpi - register with ACPI P-States library
@@ -365,46 +390,51 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
unsigned long cur_freq;
int result = 0, i;
unsigned int cpu = policy->cpu;
+ struct acpi_processor_performance *p;
+
+ p = acpi_perf_data[cpu];
/* register with ACPI core */
- if (acpi_processor_register_performance(&p, cpu)) {
- dprintk("obtaining ACPI data failed\n");
+ if (acpi_processor_register_performance(p, cpu)) {
+ dprintk(PFX "obtaining ACPI data failed\n");
return -EIO;
}
+ policy->cpus = p->shared_cpu_map;
+ policy->shared_type = p->shared_type;
/* verify the acpi_data */
- if (p.state_count <= 1) {
+ if (p->state_count <= 1) {
dprintk("No P-States\n");
result = -ENODEV;
goto err_unreg;
}
- if ((p.control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) ||
- (p.status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) {
+ if ((p->control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) ||
+ (p->status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) {
dprintk("Invalid control/status registers (%x - %x)\n",
- p.control_register.space_id, p.status_register.space_id);
+ p->control_register.space_id, p->status_register.space_id);
result = -EIO;
goto err_unreg;
}
- for (i=0; i<p.state_count; i++) {
- if (p.states[i].control != p.states[i].status) {
+ for (i=0; i<p->state_count; i++) {
+ if (p->states[i].control != p->states[i].status) {
dprintk("Different control (%llu) and status values (%llu)\n",
- p.states[i].control, p.states[i].status);
+ p->states[i].control, p->states[i].status);
result = -EINVAL;
goto err_unreg;
}
- if (!p.states[i].core_frequency) {
+ if (!p->states[i].core_frequency) {
dprintk("Zero core frequency for state %u\n", i);
result = -EINVAL;
goto err_unreg;
}
- if (p.states[i].core_frequency > p.states[0].core_frequency) {
+ if (p->states[i].core_frequency > p->states[0].core_frequency) {
dprintk("P%u has larger frequency (%llu) than P0 (%llu), skipping\n", i,
- p.states[i].core_frequency, p.states[0].core_frequency);
- p.states[i].core_frequency = 0;
+ p->states[i].core_frequency, p->states[0].core_frequency);
+ p->states[i].core_frequency = 0;
continue;
}
}
@@ -416,26 +446,26 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
}
centrino_model[cpu]->model_name=NULL;
- centrino_model[cpu]->max_freq = p.states[0].core_frequency * 1000;
+ centrino_model[cpu]->max_freq = p->states[0].core_frequency * 1000;
centrino_model[cpu]->op_points = kmalloc(sizeof(struct cpufreq_frequency_table) *
- (p.state_count + 1), GFP_KERNEL);
+ (p->state_count + 1), GFP_KERNEL);
if (!centrino_model[cpu]->op_points) {
result = -ENOMEM;
goto err_kfree;
}
- for (i=0; i<p.state_count; i++) {
- centrino_model[cpu]->op_points[i].index = p.states[i].control;
- centrino_model[cpu]->op_points[i].frequency = p.states[i].core_frequency * 1000;
+ for (i=0; i<p->state_count; i++) {
+ centrino_model[cpu]->op_points[i].index = p->states[i].control;
+ centrino_model[cpu]->op_points[i].frequency = p->states[i].core_frequency * 1000;
dprintk("adding state %i with frequency %u and control value %04x\n",
i, centrino_model[cpu]->op_points[i].frequency, centrino_model[cpu]->op_points[i].index);
}
- centrino_model[cpu]->op_points[p.state_count].frequency = CPUFREQ_TABLE_END;
+ centrino_model[cpu]->op_points[p->state_count].frequency = CPUFREQ_TABLE_END;
cur_freq = get_cur_freq(cpu);
- for (i=0; i<p.state_count; i++) {
- if (!p.states[i].core_frequency) {
+ for (i=0; i<p->state_count; i++) {
+ if (!p->states[i].core_frequency) {
dprintk("skipping state %u\n", i);
centrino_model[cpu]->op_points[i].frequency = CPUFREQ_ENTRY_INVALID;
continue;
@@ -451,7 +481,7 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
}
if (cur_freq == centrino_model[cpu]->op_points[i].frequency)
- p.state = i;
+ p->state = i;
}
/* notify BIOS that we exist */
@@ -464,12 +494,13 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
err_kfree:
kfree(centrino_model[cpu]);
err_unreg:
- acpi_processor_unregister_performance(&p, cpu);
- dprintk("invalid ACPI data\n");
+ acpi_processor_unregister_performance(p, cpu);
+ dprintk(PFX "invalid ACPI data\n");
return (result);
}
#else
static inline int centrino_cpu_init_acpi(struct cpufreq_policy *policy) { return -ENODEV; }
+static inline int centrino_cpu_early_init_acpi(void) { return 0; }
#endif
static int centrino_cpu_init(struct cpufreq_policy *policy)
@@ -555,10 +586,15 @@ static int centrino_cpu_exit(struct cpufreq_policy *policy)
#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
if (!centrino_model[cpu]->model_name) {
- dprintk("unregistering and freeing ACPI data\n");
- acpi_processor_unregister_performance(&p, cpu);
- kfree(centrino_model[cpu]->op_points);
- kfree(centrino_model[cpu]);
+ static struct acpi_processor_performance *p;
+
+ if (acpi_perf_data[cpu]) {
+ p = acpi_perf_data[cpu];
+ dprintk("unregistering and freeing ACPI data\n");
+ acpi_processor_unregister_performance(p, cpu);
+ kfree(centrino_model[cpu]->op_points);
+ kfree(centrino_model[cpu]);
+ }
}
#endif
@@ -592,63 +628,128 @@ static int centrino_target (struct cpufreq_policy *policy,
unsigned int relation)
{
unsigned int newstate = 0;
- unsigned int msr, oldmsr, h, cpu = policy->cpu;
+ unsigned int msr, oldmsr = 0, h = 0, cpu = policy->cpu;
struct cpufreq_freqs freqs;
+ cpumask_t online_policy_cpus;
cpumask_t saved_mask;
- int retval;
+ cpumask_t set_mask;
+ cpumask_t covered_cpus;
+ int retval = 0;
+ unsigned int j, k, first_cpu, tmp;
- if (centrino_model[cpu] == NULL)
+ if (unlikely(centrino_model[cpu] == NULL))
return -ENODEV;
- /*
- * Support for SMP systems.
- * Make sure we are running on the CPU that wants to change frequency
- */
- saved_mask = current->cpus_allowed;
- set_cpus_allowed(current, policy->cpus);
- if (!cpu_isset(smp_processor_id(), policy->cpus)) {
- dprintk("couldn't limit to CPUs in this domain\n");
- return(-EAGAIN);
+ if (unlikely(cpufreq_frequency_table_target(policy,
+ centrino_model[cpu]->op_points,
+ target_freq,
+ relation,
+ &newstate))) {
+ return -EINVAL;
}
- if (cpufreq_frequency_table_target(policy, centrino_model[cpu]->op_points, target_freq,
- relation, &newstate)) {
- retval = -EINVAL;
- goto migrate_end;
- }
+#ifdef CONFIG_HOTPLUG_CPU
+ /* cpufreq holds the hotplug lock, so we are safe from here on */
+ cpus_and(online_policy_cpus, cpu_online_map, policy->cpus);
+#else
+ online_policy_cpus = policy->cpus;
+#endif
- msr = centrino_model[cpu]->op_points[newstate].index;
- rdmsr(MSR_IA32_PERF_CTL, oldmsr, h);
+ saved_mask = current->cpus_allowed;
+ first_cpu = 1;
+ cpus_clear(covered_cpus);
+ for_each_cpu_mask(j, online_policy_cpus) {
+ /*
+ * Support for SMP systems.
+ * Make sure we are running on CPU that wants to change freq
+ */
+ cpus_clear(set_mask);
+ if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
+ cpus_or(set_mask, set_mask, online_policy_cpus);
+ else
+ cpu_set(j, set_mask);
+
+ set_cpus_allowed(current, set_mask);
+ if (unlikely(!cpu_isset(smp_processor_id(), set_mask))) {
+ dprintk("couldn't limit to CPUs in this domain\n");
+ retval = -EAGAIN;
+ if (first_cpu) {
+ /* We haven't started the transition yet. */
+ goto migrate_end;
+ }
+ break;
+ }
- if (msr == (oldmsr & 0xffff)) {
- retval = 0;
- dprintk("no change needed - msr was and needs to be %x\n", oldmsr);
- goto migrate_end;
- }
+ msr = centrino_model[cpu]->op_points[newstate].index;
+
+ if (first_cpu) {
+ rdmsr(MSR_IA32_PERF_CTL, oldmsr, h);
+ if (msr == (oldmsr & 0xffff)) {
+ dprintk("no change needed - msr was and needs "
+ "to be %x\n", oldmsr);
+ retval = 0;
+ goto migrate_end;
+ }
+
+ freqs.old = extract_clock(oldmsr, cpu, 0);
+ freqs.new = extract_clock(msr, cpu, 0);
+
+ dprintk("target=%dkHz old=%d new=%d msr=%04x\n",
+ target_freq, freqs.old, freqs.new, msr);
+
+ for_each_cpu_mask(k, online_policy_cpus) {
+ freqs.cpu = k;
+ cpufreq_notify_transition(&freqs,
+ CPUFREQ_PRECHANGE);
+ }
+
+ first_cpu = 0;
+ /* all but 16 LSB are reserved, treat them with care */
+ oldmsr &= ~0xffff;
+ msr &= 0xffff;
+ oldmsr |= msr;
+ }
- freqs.cpu = cpu;
- freqs.old = extract_clock(oldmsr, cpu, 0);
- freqs.new = extract_clock(msr, cpu, 0);
+ wrmsr(MSR_IA32_PERF_CTL, oldmsr, h);
+ if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
+ break;
- dprintk("target=%dkHz old=%d new=%d msr=%04x\n",
- target_freq, freqs.old, freqs.new, msr);
+ cpu_set(j, covered_cpus);
+ }
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ for_each_cpu_mask(k, online_policy_cpus) {
+ freqs.cpu = k;
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ }
- /* all but 16 LSB are "reserved", so treat them with
- care */
- oldmsr &= ~0xffff;
- msr &= 0xffff;
- oldmsr |= msr;
+ if (unlikely(retval)) {
+ /*
+ * We have failed halfway through the frequency change.
+ * We have sent callbacks to policy->cpus and
+ * MSRs have already been written on coverd_cpus.
+ * Best effort undo..
+ */
- wrmsr(MSR_IA32_PERF_CTL, oldmsr, h);
+ if (!cpus_empty(covered_cpus)) {
+ for_each_cpu_mask(j, covered_cpus) {
+ set_cpus_allowed(current, cpumask_of_cpu(j));
+ wrmsr(MSR_IA32_PERF_CTL, oldmsr, h);
+ }
+ }
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ tmp = freqs.new;
+ freqs.new = freqs.old;
+ freqs.old = tmp;
+ for_each_cpu_mask(j, online_policy_cpus) {
+ freqs.cpu = j;
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ }
+ }
- retval = 0;
migrate_end:
set_cpus_allowed(current, saved_mask);
- return (retval);
+ return 0;
}
static struct freq_attr* centrino_attr[] = {
@@ -690,12 +791,25 @@ static int __init centrino_init(void)
if (!cpu_has(cpu, X86_FEATURE_EST))
return -ENODEV;
+ centrino_cpu_early_init_acpi();
+
return cpufreq_register_driver(&centrino_driver);
}
static void __exit centrino_exit(void)
{
+#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
+ unsigned int j;
+#endif
+
cpufreq_unregister_driver(&centrino_driver);
+
+#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
+ for_each_possible_cpu(j) {
+ kfree(acpi_perf_data[j]);
+ acpi_perf_data[j] = NULL;
+ }
+#endif
}
MODULE_AUTHOR ("Jeremy Fitzhardinge <jeremy@goop.org>");
diff --git a/arch/i386/kernel/cpu/cyrix.c b/arch/i386/kernel/cpu/cyrix.c
index 00f2e05..fc32c80 100644
--- a/arch/i386/kernel/cpu/cyrix.c
+++ b/arch/i386/kernel/cpu/cyrix.c
@@ -184,7 +184,7 @@ static void __init geode_configure(void)
#ifdef CONFIG_PCI
-static struct pci_device_id cyrix_55x0[] = {
+static struct pci_device_id __initdata cyrix_55x0[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510) },
{ PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520) },
{ },
@@ -272,14 +272,15 @@ static void __init init_cyrix(struct cpuinfo_x86 *c)
printk(KERN_INFO "Working around Cyrix MediaGX virtual DMA bugs.\n");
isa_dma_bridge_buggy = 2;
-#endif
- c->x86_cache_size=16; /* Yep 16K integrated cache thats it */
-
+
+
/*
* The 5510/5520 companion chips have a funky PIT.
*/
if (pci_dev_present(cyrix_55x0))
pit_latch_buggy = 1;
+#endif
+ c->x86_cache_size=16; /* Yep 16K integrated cache thats it */
/* GXm supports extended cpuid levels 'ala' AMD */
if (c->cpuid_level == 2) {
diff --git a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c
index f94cdb7..a19fcb2 100644
--- a/arch/i386/kernel/cpu/proc.c
+++ b/arch/i386/kernel/cpu/proc.c
@@ -52,7 +52,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
/* VIA/Cyrix/Centaur-defined */
NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c
index 2b0cfce..21dc1bb 100644
--- a/arch/i386/kernel/crash.c
+++ b/arch/i386/kernel/crash.c
@@ -114,7 +114,8 @@ static int crash_nmi_callback(struct pt_regs *regs, int cpu)
atomic_dec(&waiting_for_crash_ipi);
/* Assume hlt works */
halt();
- for(;;);
+ for (;;)
+ cpu_relax();
return 1;
}
diff --git a/arch/i386/kernel/doublefault.c b/arch/i386/kernel/doublefault.c
index 5edb1d3..b4d14c2 100644
--- a/arch/i386/kernel/doublefault.c
+++ b/arch/i386/kernel/doublefault.c
@@ -44,7 +44,8 @@ static void doublefault_fn(void)
}
}
- for (;;) /* nothing */;
+ for (;;)
+ cpu_relax();
}
struct tss_struct doublefault_tss __cacheline_aligned = {
diff --git a/arch/i386/kernel/i387.c b/arch/i386/kernel/i387.c
index d755247..c435197 100644
--- a/arch/i386/kernel/i387.c
+++ b/arch/i386/kernel/i387.c
@@ -25,7 +25,7 @@
#define HAVE_HWFP 1
#endif
-static unsigned long mxcsr_feature_mask = 0xffffffff;
+static unsigned long mxcsr_feature_mask __read_mostly = 0xffffffff;
void mxcsr_feature_mask_init(void)
{
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
index 323ef8a..b7636b9 100644
--- a/arch/i386/kernel/i8259.c
+++ b/arch/i386/kernel/i8259.c
@@ -271,8 +271,8 @@ static int i8259A_shutdown(struct sys_device *dev)
* the kernel initialization code can get it
* out of.
*/
- outb(0xff, 0x21); /* mask all of 8259A-1 */
- outb(0xff, 0xA1); /* mask all of 8259A-1 */
+ outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */
+ outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-1 */
return 0;
}
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index d70f2ad..a62df3e 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -267,7 +267,7 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask)
# include <linux/slab.h> /* kmalloc() */
# include <linux/timer.h> /* time_after() */
-# ifdef CONFIG_BALANCED_IRQ_DEBUG
+#ifdef CONFIG_BALANCED_IRQ_DEBUG
# define TDprintk(x...) do { printk("<%ld:%s:%d>: ", jiffies, __FILE__, __LINE__); printk(x); } while (0)
# define Dprintk(x...) do { TDprintk(x); } while (0)
# else
@@ -275,10 +275,15 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask)
# define Dprintk(x...)
# endif
-
#define IRQBALANCE_CHECK_ARCH -999
-static int irqbalance_disabled = IRQBALANCE_CHECK_ARCH;
-static int physical_balance = 0;
+#define MAX_BALANCED_IRQ_INTERVAL (5*HZ)
+#define MIN_BALANCED_IRQ_INTERVAL (HZ/2)
+#define BALANCED_IRQ_MORE_DELTA (HZ/10)
+#define BALANCED_IRQ_LESS_DELTA (HZ)
+
+static int irqbalance_disabled __read_mostly = IRQBALANCE_CHECK_ARCH;
+static int physical_balance __read_mostly;
+static long balanced_irq_interval __read_mostly = MAX_BALANCED_IRQ_INTERVAL;
static struct irq_cpu_info {
unsigned long * last_irq;
@@ -297,12 +302,14 @@ static struct irq_cpu_info {
#define CPU_TO_PACKAGEINDEX(i) (first_cpu(cpu_sibling_map[i]))
-#define MAX_BALANCED_IRQ_INTERVAL (5*HZ)
-#define MIN_BALANCED_IRQ_INTERVAL (HZ/2)
-#define BALANCED_IRQ_MORE_DELTA (HZ/10)
-#define BALANCED_IRQ_LESS_DELTA (HZ)
+static cpumask_t balance_irq_affinity[NR_IRQS] = {
+ [0 ... NR_IRQS-1] = CPU_MASK_ALL
+};
-static long balanced_irq_interval = MAX_BALANCED_IRQ_INTERVAL;
+void set_balance_irq_affinity(unsigned int irq, cpumask_t mask)
+{
+ balance_irq_affinity[irq] = mask;
+}
static unsigned long move(int curr_cpu, cpumask_t allowed_mask,
unsigned long now, int direction)
@@ -340,7 +347,7 @@ static inline void balance_irq(int cpu, int irq)
if (irqbalance_disabled)
return;
- cpus_and(allowed_mask, cpu_online_map, irq_affinity[irq]);
+ cpus_and(allowed_mask, cpu_online_map, balance_irq_affinity[irq]);
new_cpu = move(cpu, allowed_mask, now, 1);
if (cpu != new_cpu) {
set_pending_irq(irq, cpumask_of_cpu(new_cpu));
@@ -529,7 +536,9 @@ tryanotherirq:
}
}
- cpus_and(allowed_mask, cpu_online_map, irq_affinity[selected_irq]);
+ cpus_and(allowed_mask,
+ cpu_online_map,
+ balance_irq_affinity[selected_irq]);
target_cpu_mask = cpumask_of_cpu(min_loaded);
cpus_and(tmp, target_cpu_mask, allowed_mask);
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index f3a9c78..49ce4c3 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -42,8 +42,8 @@ union irq_ctx {
u32 stack[THREAD_SIZE/sizeof(u32)];
};
-static union irq_ctx *hardirq_ctx[NR_CPUS];
-static union irq_ctx *softirq_ctx[NR_CPUS];
+static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly;
+static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly;
#endif
/*
@@ -95,6 +95,14 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
irqctx->tinfo.task = curctx->tinfo.task;
irqctx->tinfo.previous_esp = current_stack_pointer;
+ /*
+ * Copy the softirq bits in preempt_count so that the
+ * softirq checks work in the hardirq context.
+ */
+ irqctx->tinfo.preempt_count =
+ irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK |
+ curctx->tinfo.preempt_count & SOFTIRQ_MASK;
+
asm volatile(
" xchgl %%ebx,%%esp \n"
" call __do_IRQ \n"
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
index 38806f4..395a9a6 100644
--- a/arch/i386/kernel/kprobes.c
+++ b/arch/i386/kernel/kprobes.c
@@ -607,7 +607,7 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
struct die_args *args = (struct die_args *)data;
int ret = NOTIFY_DONE;
- if (args->regs && user_mode(args->regs))
+ if (args->regs && user_mode_vm(args->regs))
return ret;
switch (val) {
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
index e7c138f..0a86588 100644
--- a/arch/i386/kernel/microcode.c
+++ b/arch/i386/kernel/microcode.c
@@ -91,7 +91,10 @@ MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver");
MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
MODULE_LICENSE("GPL");
-#define MICROCODE_VERSION "1.14"
+static int verbose;
+module_param(verbose, int, 0644);
+
+#define MICROCODE_VERSION "1.14a"
#define DEFAULT_UCODE_DATASIZE (2000) /* 2000 bytes */
#define MC_HEADER_SIZE (sizeof (microcode_header_t)) /* 48 bytes */
@@ -122,14 +125,15 @@ static unsigned int user_buffer_size; /* it's size */
typedef enum mc_error_code {
MC_SUCCESS = 0,
- MC_NOTFOUND = 1,
- MC_MARKED = 2,
- MC_ALLOCATED = 3,
+ MC_IGNORED = 1,
+ MC_NOTFOUND = 2,
+ MC_MARKED = 3,
+ MC_ALLOCATED = 4,
} mc_error_code_t;
static struct ucode_cpu_info {
unsigned int sig;
- unsigned int pf;
+ unsigned int pf, orig_pf;
unsigned int rev;
unsigned int cksum;
mc_error_code_t err;
@@ -164,6 +168,7 @@ static void collect_cpu_info (void *unused)
rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
uci->pf = 1 << ((val[1] >> 18) & 7);
}
+ uci->orig_pf = uci->pf;
}
wrmsr(MSR_IA32_UCODE_REV, 0, 0);
@@ -197,21 +202,34 @@ static inline void mark_microcode_update (int cpu_num, microcode_header_t *mc_he
pr_debug(" Checksum 0x%x\n", cksum);
if (mc_header->rev < uci->rev) {
- printk(KERN_ERR "microcode: CPU%d not 'upgrading' to earlier revision"
- " 0x%x (current=0x%x)\n", cpu_num, mc_header->rev, uci->rev);
- goto out;
+ if (uci->err == MC_NOTFOUND) {
+ uci->err = MC_IGNORED;
+ uci->cksum = mc_header->rev;
+ } else if (uci->err == MC_IGNORED && uci->cksum < mc_header->rev)
+ uci->cksum = mc_header->rev;
} else if (mc_header->rev == uci->rev) {
- /* notify the caller of success on this cpu */
- uci->err = MC_SUCCESS;
- goto out;
+ if (uci->err < MC_MARKED) {
+ /* notify the caller of success on this cpu */
+ uci->err = MC_SUCCESS;
+ }
+ } else if (uci->err != MC_ALLOCATED || mc_header->rev > uci->mc->hdr.rev) {
+ pr_debug("microcode: CPU%d found a matching microcode update with "
+ " revision 0x%x (current=0x%x)\n", cpu_num, mc_header->rev, uci->rev);
+ uci->cksum = cksum;
+ uci->pf = pf; /* keep the original mc pf for cksum calculation */
+ uci->err = MC_MARKED; /* found the match */
+ for_each_online_cpu(cpu_num) {
+ if (ucode_cpu_info + cpu_num != uci
+ && ucode_cpu_info[cpu_num].mc == uci->mc) {
+ uci->mc = NULL;
+ break;
+ }
+ }
+ if (uci->mc != NULL) {
+ vfree(uci->mc);
+ uci->mc = NULL;
+ }
}
-
- pr_debug("microcode: CPU%d found a matching microcode update with "
- " revision 0x%x (current=0x%x)\n", cpu_num, mc_header->rev, uci->rev);
- uci->cksum = cksum;
- uci->pf = pf; /* keep the original mc pf for cksum calculation */
- uci->err = MC_MARKED; /* found the match */
-out:
return;
}
@@ -253,10 +271,8 @@ static int find_matching_ucodes (void)
for_each_online_cpu(cpu_num) {
struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
- if (uci->err != MC_NOTFOUND) /* already found a match or not an online cpu*/
- continue;
- if (sigmatch(mc_header.sig, uci->sig, mc_header.pf, uci->pf))
+ if (sigmatch(mc_header.sig, uci->sig, mc_header.pf, uci->orig_pf))
mark_microcode_update(cpu_num, &mc_header, mc_header.sig, mc_header.pf, mc_header.cksum);
}
@@ -295,9 +311,8 @@ static int find_matching_ucodes (void)
}
for_each_online_cpu(cpu_num) {
struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
- if (uci->err != MC_NOTFOUND) /* already found a match or not an online cpu*/
- continue;
- if (sigmatch(ext_sig.sig, uci->sig, ext_sig.pf, uci->pf)) {
+
+ if (sigmatch(ext_sig.sig, uci->sig, ext_sig.pf, uci->orig_pf)) {
mark_microcode_update(cpu_num, &mc_header, ext_sig.sig, ext_sig.pf, ext_sig.cksum);
}
}
@@ -368,6 +383,13 @@ static void do_update_one (void * unused)
struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
if (uci->mc == NULL) {
+ if (verbose) {
+ if (uci->err == MC_SUCCESS)
+ printk(KERN_INFO "microcode: CPU%d already at revision 0x%x\n",
+ cpu_num, uci->rev);
+ else
+ printk(KERN_INFO "microcode: No new microcode data for CPU%d\n", cpu_num);
+ }
return;
}
@@ -426,6 +448,9 @@ out_free:
ucode_cpu_info[j].mc = NULL;
}
}
+ if (ucode_cpu_info[i].err == MC_IGNORED && verbose)
+ printk(KERN_WARNING "microcode: CPU%d not 'upgrading' to earlier revision"
+ " 0x%x (current=0x%x)\n", i, ucode_cpu_info[i].cksum, ucode_cpu_info[i].rev);
}
out:
return error;
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index dd6b0e3..6c16398 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -48,6 +48,7 @@
#include <linux/crash_dump.h>
#include <linux/dmi.h>
#include <linux/pfn.h>
+#include <linux/suspend.h>
#include <video/edid.h>
@@ -60,7 +61,7 @@
#include <asm/io_apic.h>
#include <asm/ist.h>
#include <asm/io.h>
-#include "setup_arch_pre.h"
+#include <setup_arch.h>
#include <bios_ebda.h>
/* Forward Declaration. */
@@ -410,8 +411,8 @@ static void __init limit_regions(unsigned long long size)
}
}
-static void __init add_memory_region(unsigned long long start,
- unsigned long long size, int type)
+void __init add_memory_region(unsigned long long start,
+ unsigned long long size, int type)
{
int x;
@@ -474,7 +475,7 @@ static struct change_member *change_point[2*E820MAX] __initdata;
static struct e820entry *overlap_list[E820MAX] __initdata;
static struct e820entry new_bios[E820MAX] __initdata;
-static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
+int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
{
struct change_member *change_tmp;
unsigned long current_type, last_type;
@@ -643,7 +644,7 @@ static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
* thinkpad 560x, for example, does not cooperate with the memory
* detection code.)
*/
-static int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
+int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
{
/* Only one memory region (or negative)? Ignore it */
if (nr_map < 2)
@@ -701,12 +702,6 @@ static inline void copy_edd(void)
}
#endif
-/*
- * Do NOT EVER look at the BIOS memory size location.
- * It does not work on many machines.
- */
-#define LOWMEMSIZE() (0x9f000)
-
static void __init parse_cmdline_early (char ** cmdline_p)
{
char c = ' ', *to = command_line, *from = saved_command_line;
@@ -1423,8 +1418,6 @@ static void __init register_memory(void)
pci_mem_start, gapstart, gapsize);
}
-static char * __init machine_specific_memory_setup(void);
-
#ifdef CONFIG_MCA
static void set_mca_bus(int x)
{
@@ -1434,6 +1427,111 @@ static void set_mca_bus(int x)
static void set_mca_bus(int x) { }
#endif
+#ifdef CONFIG_SOFTWARE_SUSPEND
+static void __init mark_nosave_page_range(unsigned long start, unsigned long end)
+{
+ struct page *page;
+ while (start <= end) {
+ page = pfn_to_page(start);
+ SetPageNosave(page);
+ start++;
+ }
+}
+
+static void __init e820_nosave_reserved_pages(void)
+{
+ int i;
+ unsigned long r_start = 0, r_end = 0;
+
+ /* Assume e820 map is sorted */
+ for (i = 0; i < e820.nr_map; i++) {
+ struct e820entry *ei = &e820.map[i];
+ unsigned long start, end;
+
+ start = PFN_DOWN(ei->addr);
+ end = PFN_UP(ei->addr + ei->size);
+ if (start >= end)
+ continue;
+ if (ei->type == E820_RESERVED)
+ continue;
+ r_end = start;
+ /*
+ * Highmem 'Reserved' pages are marked as reserved, swsusp
+ * will not save/restore them, so we ignore these pages here.
+ */
+ if (r_end > max_low_pfn)
+ r_end = max_low_pfn;
+ if (r_end > r_start)
+ mark_nosave_page_range(r_start, r_end-1);
+ if (r_end >= max_low_pfn)
+ break;
+ r_start = end;
+ }
+}
+
+static void __init e820_save_acpi_pages(void)
+{
+ int i;
+
+ /* Assume e820 map is sorted */
+ for (i = 0; i < e820.nr_map; i++) {
+ struct e820entry *ei = &e820.map[i];
+ unsigned long start, end;
+
+ start = ei->addr;
+ end = ei->addr + ei->size;
+ if (start >= end)
+ continue;
+ if (ei->type != E820_ACPI && ei->type != E820_NVS)
+ continue;
+ /*
+ * If the region is below max_low_pfn, it will be
+ * saved/restored by swsusp follow 'RAM' type.
+ */
+ if (start < (max_low_pfn << PAGE_SHIFT))
+ start = max_low_pfn << PAGE_SHIFT;
+ /*
+ * Highmem pages (ACPI NVS/Data) are reserved, but swsusp
+ * highmem save/restore will not save/restore them. We marked
+ * them as arch saveable pages here
+ */
+ if (end > start)
+ swsusp_add_arch_pages(start, end);
+ }
+}
+
+extern char __start_rodata, __end_rodata;
+/*
+ * BIOS reserved region/hole - no save/restore
+ * ACPI NVS - save/restore
+ * ACPI Data - this is a little tricky, the mem could be used by OS after OS
+ * reads tables from the region, but anyway save/restore the memory hasn't any
+ * side effect and Linux runtime module load/unload might use it.
+ * kernel rodata - no save/restore (kernel rodata isn't changed)
+ */
+static int __init mark_nosave_pages(void)
+{
+ unsigned long pfn_start, pfn_end;
+
+ /* FIXME: provide a version for efi BIOS */
+ if (efi_enabled)
+ return 0;
+ /* BIOS reserved regions & holes */
+ e820_nosave_reserved_pages();
+
+ /* kernel rodata */
+ pfn_start = PFN_UP(virt_to_phys(&__start_rodata));
+ pfn_end = PFN_DOWN(virt_to_phys(&__end_rodata));
+ mark_nosave_page_range(pfn_start, pfn_end-1);
+
+ /* record ACPI Data/NVS as saveable */
+ e820_save_acpi_pages();
+
+ return 0;
+}
+core_initcall(mark_nosave_pages);
+#endif
+
/*
* Determine if we were loaded by an EFI loader. If so, then we have also been
* passed the efi memmap, systab, etc., so we should use these data structures
@@ -1602,7 +1700,6 @@ static __init int add_pcspkr(void)
}
device_initcall(add_pcspkr);
-#include "setup_arch_post.h"
/*
* Local Variables:
* mode:c
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index 825b2b4..bd0ca5c 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -257,7 +257,7 @@ static void __init synchronize_tsc_bp (void)
* all APs synchronize but they loop on '== num_cpus'
*/
while (atomic_read(&tsc_count_start) != num_booting_cpus()-1)
- mb();
+ cpu_relax();
atomic_set(&tsc_count_stop, 0);
wmb();
/*
@@ -276,7 +276,7 @@ static void __init synchronize_tsc_bp (void)
* Wait for all APs to leave the synchronization point:
*/
while (atomic_read(&tsc_count_stop) != num_booting_cpus()-1)
- mb();
+ cpu_relax();
atomic_set(&tsc_count_start, 0);
wmb();
atomic_inc(&tsc_count_stop);
@@ -333,19 +333,21 @@ static void __init synchronize_tsc_ap (void)
* this gets called, so we first wait for the BP to
* finish SMP initialization:
*/
- while (!atomic_read(&tsc_start_flag)) mb();
+ while (!atomic_read(&tsc_start_flag))
+ cpu_relax();
for (i = 0; i < NR_LOOPS; i++) {
atomic_inc(&tsc_count_start);
while (atomic_read(&tsc_count_start) != num_booting_cpus())
- mb();
+ cpu_relax();
rdtscll(tsc_values[smp_processor_id()]);
if (i == NR_LOOPS-1)
write_tsc(0, 0);
atomic_inc(&tsc_count_stop);
- while (atomic_read(&tsc_count_stop) != num_booting_cpus()) mb();
+ while (atomic_read(&tsc_count_stop) != num_booting_cpus())
+ cpu_relax();
}
}
#undef NR_LOOPS
@@ -1433,7 +1435,7 @@ int __devinit __cpu_up(unsigned int cpu)
/* Unleash the CPU! */
cpu_set(cpu, smp_commenced_mask);
while (!cpu_isset(cpu, cpu_online_map))
- mb();
+ cpu_relax();
return 0;
}
diff --git a/arch/i386/kernel/srat.c b/arch/i386/kernel/srat.c
index 52b3ed5..989c852 100644
--- a/arch/i386/kernel/srat.c
+++ b/arch/i386/kernel/srat.c
@@ -39,7 +39,6 @@
#define NODE_ARRAY_OFFSET(x) ((x) % 8) /* 8 bits/char */
#define BMAP_SET(bmap, bit) ((bmap)[NODE_ARRAY_INDEX(bit)] |= 1 << NODE_ARRAY_OFFSET(bit))
#define BMAP_TEST(bmap, bit) ((bmap)[NODE_ARRAY_INDEX(bit)] & (1 << NODE_ARRAY_OFFSET(bit)))
-#define MAX_PXM_DOMAINS 256 /* 1 byte and no promises about values */
/* bitmap length; _PXM is at most 255 */
#define PXM_BITMAP_LEN (MAX_PXM_DOMAINS / 8)
static u8 pxm_bitmap[PXM_BITMAP_LEN]; /* bitmap of proximity domains */
@@ -213,19 +212,11 @@ static __init void node_read_chunk(int nid, struct node_memory_chunk_s *memory_c
node_end_pfn[nid] = memory_chunk->end_pfn;
}
-static u8 pxm_to_nid_map[MAX_PXM_DOMAINS];/* _PXM to logical node ID map */
-
-int pxm_to_node(int pxm)
-{
- return pxm_to_nid_map[pxm];
-}
-
/* Parse the ACPI Static Resource Affinity Table */
static int __init acpi20_parse_srat(struct acpi_table_srat *sratp)
{
u8 *start, *end, *p;
int i, j, nid;
- u8 nid_to_pxm_map[MAX_NUMNODES];/* logical node ID to _PXM map */
start = (u8 *)(&(sratp->reserved) + 1); /* skip header */
p = start;
@@ -235,10 +226,6 @@ static int __init acpi20_parse_srat(struct acpi_table_srat *sratp)
memset(node_memory_chunk, 0, sizeof(node_memory_chunk));
memset(zholes_size, 0, sizeof(zholes_size));
- /* -1 in these maps means not available */
- memset(pxm_to_nid_map, -1, sizeof(pxm_to_nid_map));
- memset(nid_to_pxm_map, -1, sizeof(nid_to_pxm_map));
-
num_memory_chunks = 0;
while (p < end) {
switch (*p) {
@@ -278,9 +265,7 @@ static int __init acpi20_parse_srat(struct acpi_table_srat *sratp)
nodes_clear(node_online_map);
for (i = 0; i < MAX_PXM_DOMAINS; i++) {
if (BMAP_TEST(pxm_bitmap, i)) {
- nid = num_online_nodes();
- pxm_to_nid_map[i] = nid;
- nid_to_pxm_map[nid] = i;
+ int nid = acpi_map_pxm_to_node(i);
node_set_online(nid);
}
}
@@ -288,7 +273,7 @@ static int __init acpi20_parse_srat(struct acpi_table_srat *sratp)
/* set cnode id in memory chunk structure */
for (i = 0; i < num_memory_chunks; i++)
- node_memory_chunk[i].nid = pxm_to_nid_map[node_memory_chunk[i].pxm];
+ node_memory_chunk[i].nid = pxm_to_node(node_memory_chunk[i].pxm);
printk("pxm bitmap: ");
for (i = 0; i < sizeof(pxm_bitmap); i++) {
diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S
index af56987..dd63d47 100644
--- a/arch/i386/kernel/syscall_table.S
+++ b/arch/i386/kernel/syscall_table.S
@@ -316,3 +316,4 @@ ENTRY(sys_call_table)
.long sys_sync_file_range
.long sys_tee /* 315 */
.long sys_vmsplice
+ .long sys_move_pages
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 0e49836..dcc1447 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -149,6 +149,12 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo,
while (valid_stack_ptr(tinfo, (void *)ebp)) {
addr = *(unsigned long *)(ebp + 4);
printed = print_addr_and_symbol(addr, log_lvl, printed);
+ /*
+ * break out of recursive entries (such as
+ * end_of_stack_stop_unwind_function):
+ */
+ if (ebp == *(unsigned long *)ebp)
+ break;
ebp = *(unsigned long *)ebp;
}
#else
@@ -268,8 +274,9 @@ void show_registers(struct pt_regs *regs)
regs->esi, regs->edi, regs->ebp, esp);
printk(KERN_EMERG "ds: %04x es: %04x ss: %04x\n",
regs->xds & 0xffff, regs->xes & 0xffff, ss);
- printk(KERN_EMERG "Process %s (pid: %d, threadinfo=%p task=%p)",
- current->comm, current->pid, current_thread_info(), current);
+ printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)",
+ TASK_COMM_LEN, current->comm, current->pid,
+ current_thread_info(), current, current->thread_info);
/*
* When in-kernel, we also print out the stack and code at the
* time of the fault..
diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S
index 8831303..7512f39 100644
--- a/arch/i386/kernel/vmlinux.lds.S
+++ b/arch/i386/kernel/vmlinux.lds.S
@@ -37,6 +37,13 @@ SECTIONS
RODATA
+ . = ALIGN(4);
+ __tracedata_start = .;
+ .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) {
+ *(.tracedata)
+ }
+ __tracedata_end = .;
+
/* writeable */
.data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */
*(.data)
diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c
index 4cf981d..c5aa65f 100644
--- a/arch/i386/lib/usercopy.c
+++ b/arch/i386/lib/usercopy.c
@@ -425,15 +425,212 @@ __copy_user_zeroing_intel(void *to, const void __user *from, unsigned long size)
: "eax", "edx", "memory");
return size;
}
+
+/*
+ * Non Temporal Hint version of __copy_user_zeroing_intel. It is cache aware.
+ * hyoshiok@miraclelinux.com
+ */
+
+static unsigned long __copy_user_zeroing_intel_nocache(void *to,
+ const void __user *from, unsigned long size)
+{
+ int d0, d1;
+
+ __asm__ __volatile__(
+ " .align 2,0x90\n"
+ "0: movl 32(%4), %%eax\n"
+ " cmpl $67, %0\n"
+ " jbe 2f\n"
+ "1: movl 64(%4), %%eax\n"
+ " .align 2,0x90\n"
+ "2: movl 0(%4), %%eax\n"
+ "21: movl 4(%4), %%edx\n"
+ " movnti %%eax, 0(%3)\n"
+ " movnti %%edx, 4(%3)\n"
+ "3: movl 8(%4), %%eax\n"
+ "31: movl 12(%4),%%edx\n"
+ " movnti %%eax, 8(%3)\n"
+ " movnti %%edx, 12(%3)\n"
+ "4: movl 16(%4), %%eax\n"
+ "41: movl 20(%4), %%edx\n"
+ " movnti %%eax, 16(%3)\n"
+ " movnti %%edx, 20(%3)\n"
+ "10: movl 24(%4), %%eax\n"
+ "51: movl 28(%4), %%edx\n"
+ " movnti %%eax, 24(%3)\n"
+ " movnti %%edx, 28(%3)\n"
+ "11: movl 32(%4), %%eax\n"
+ "61: movl 36(%4), %%edx\n"
+ " movnti %%eax, 32(%3)\n"
+ " movnti %%edx, 36(%3)\n"
+ "12: movl 40(%4), %%eax\n"
+ "71: movl 44(%4), %%edx\n"
+ " movnti %%eax, 40(%3)\n"
+ " movnti %%edx, 44(%3)\n"
+ "13: movl 48(%4), %%eax\n"
+ "81: movl 52(%4), %%edx\n"
+ " movnti %%eax, 48(%3)\n"
+ " movnti %%edx, 52(%3)\n"
+ "14: movl 56(%4), %%eax\n"
+ "91: movl 60(%4), %%edx\n"
+ " movnti %%eax, 56(%3)\n"
+ " movnti %%edx, 60(%3)\n"
+ " addl $-64, %0\n"
+ " addl $64, %4\n"
+ " addl $64, %3\n"
+ " cmpl $63, %0\n"
+ " ja 0b\n"
+ " sfence \n"
+ "5: movl %0, %%eax\n"
+ " shrl $2, %0\n"
+ " andl $3, %%eax\n"
+ " cld\n"
+ "6: rep; movsl\n"
+ " movl %%eax,%0\n"
+ "7: rep; movsb\n"
+ "8:\n"
+ ".section .fixup,\"ax\"\n"
+ "9: lea 0(%%eax,%0,4),%0\n"
+ "16: pushl %0\n"
+ " pushl %%eax\n"
+ " xorl %%eax,%%eax\n"
+ " rep; stosb\n"
+ " popl %%eax\n"
+ " popl %0\n"
+ " jmp 8b\n"
+ ".previous\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .long 0b,16b\n"
+ " .long 1b,16b\n"
+ " .long 2b,16b\n"
+ " .long 21b,16b\n"
+ " .long 3b,16b\n"
+ " .long 31b,16b\n"
+ " .long 4b,16b\n"
+ " .long 41b,16b\n"
+ " .long 10b,16b\n"
+ " .long 51b,16b\n"
+ " .long 11b,16b\n"
+ " .long 61b,16b\n"
+ " .long 12b,16b\n"
+ " .long 71b,16b\n"
+ " .long 13b,16b\n"
+ " .long 81b,16b\n"
+ " .long 14b,16b\n"
+ " .long 91b,16b\n"
+ " .long 6b,9b\n"
+ " .long 7b,16b\n"
+ ".previous"
+ : "=&c"(size), "=&D" (d0), "=&S" (d1)
+ : "1"(to), "2"(from), "0"(size)
+ : "eax", "edx", "memory");
+ return size;
+}
+
+static unsigned long __copy_user_intel_nocache(void *to,
+ const void __user *from, unsigned long size)
+{
+ int d0, d1;
+
+ __asm__ __volatile__(
+ " .align 2,0x90\n"
+ "0: movl 32(%4), %%eax\n"
+ " cmpl $67, %0\n"
+ " jbe 2f\n"
+ "1: movl 64(%4), %%eax\n"
+ " .align 2,0x90\n"
+ "2: movl 0(%4), %%eax\n"
+ "21: movl 4(%4), %%edx\n"
+ " movnti %%eax, 0(%3)\n"
+ " movnti %%edx, 4(%3)\n"
+ "3: movl 8(%4), %%eax\n"
+ "31: movl 12(%4),%%edx\n"
+ " movnti %%eax, 8(%3)\n"
+ " movnti %%edx, 12(%3)\n"
+ "4: movl 16(%4), %%eax\n"
+ "41: movl 20(%4), %%edx\n"
+ " movnti %%eax, 16(%3)\n"
+ " movnti %%edx, 20(%3)\n"
+ "10: movl 24(%4), %%eax\n"
+ "51: movl 28(%4), %%edx\n"
+ " movnti %%eax, 24(%3)\n"
+ " movnti %%edx, 28(%3)\n"
+ "11: movl 32(%4), %%eax\n"
+ "61: movl 36(%4), %%edx\n"
+ " movnti %%eax, 32(%3)\n"
+ " movnti %%edx, 36(%3)\n"
+ "12: movl 40(%4), %%eax\n"
+ "71: movl 44(%4), %%edx\n"
+ " movnti %%eax, 40(%3)\n"
+ " movnti %%edx, 44(%3)\n"
+ "13: movl 48(%4), %%eax\n"
+ "81: movl 52(%4), %%edx\n"
+ " movnti %%eax, 48(%3)\n"
+ " movnti %%edx, 52(%3)\n"
+ "14: movl 56(%4), %%eax\n"
+ "91: movl 60(%4), %%edx\n"
+ " movnti %%eax, 56(%3)\n"
+ " movnti %%edx, 60(%3)\n"
+ " addl $-64, %0\n"
+ " addl $64, %4\n"
+ " addl $64, %3\n"
+ " cmpl $63, %0\n"
+ " ja 0b\n"
+ " sfence \n"
+ "5: movl %0, %%eax\n"
+ " shrl $2, %0\n"
+ " andl $3, %%eax\n"
+ " cld\n"
+ "6: rep; movsl\n"
+ " movl %%eax,%0\n"
+ "7: rep; movsb\n"
+ "8:\n"
+ ".section .fixup,\"ax\"\n"
+ "9: lea 0(%%eax,%0,4),%0\n"
+ "16: jmp 8b\n"
+ ".previous\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .long 0b,16b\n"
+ " .long 1b,16b\n"
+ " .long 2b,16b\n"
+ " .long 21b,16b\n"
+ " .long 3b,16b\n"
+ " .long 31b,16b\n"
+ " .long 4b,16b\n"
+ " .long 41b,16b\n"
+ " .long 10b,16b\n"
+ " .long 51b,16b\n"
+ " .long 11b,16b\n"
+ " .long 61b,16b\n"
+ " .long 12b,16b\n"
+ " .long 71b,16b\n"
+ " .long 13b,16b\n"
+ " .long 81b,16b\n"
+ " .long 14b,16b\n"
+ " .long 91b,16b\n"
+ " .long 6b,9b\n"
+ " .long 7b,16b\n"
+ ".previous"
+ : "=&c"(size), "=&D" (d0), "=&S" (d1)
+ : "1"(to), "2"(from), "0"(size)
+ : "eax", "edx", "memory");
+ return size;
+}
+
#else
+
/*
* Leave these declared but undefined. They should not be any references to
* them
*/
-unsigned long
-__copy_user_zeroing_intel(void *to, const void __user *from, unsigned long size);
-unsigned long
-__copy_user_intel(void __user *to, const void *from, unsigned long size);
+unsigned long __copy_user_zeroing_intel(void *to, const void __user *from,
+ unsigned long size);
+unsigned long __copy_user_intel(void __user *to, const void *from,
+ unsigned long size);
+unsigned long __copy_user_zeroing_intel_nocache(void *to,
+ const void __user *from, unsigned long size);
#endif /* CONFIG_X86_INTEL_USERCOPY */
/* Generic arbitrary sized copy. */
@@ -515,8 +712,8 @@ do { \
: "memory"); \
} while (0)
-
-unsigned long __copy_to_user_ll(void __user *to, const void *from, unsigned long n)
+unsigned long __copy_to_user_ll(void __user *to, const void *from,
+ unsigned long n)
{
BUG_ON((long) n < 0);
#ifndef CONFIG_X86_WP_WORKS_OK
@@ -576,8 +773,8 @@ survive:
}
EXPORT_SYMBOL(__copy_to_user_ll);
-unsigned long
-__copy_from_user_ll(void *to, const void __user *from, unsigned long n)
+unsigned long __copy_from_user_ll(void *to, const void __user *from,
+ unsigned long n)
{
BUG_ON((long)n < 0);
if (movsl_is_ok(to, from, n))
@@ -588,6 +785,49 @@ __copy_from_user_ll(void *to, const void __user *from, unsigned long n)
}
EXPORT_SYMBOL(__copy_from_user_ll);
+unsigned long __copy_from_user_ll_nozero(void *to, const void __user *from,
+ unsigned long n)
+{
+ BUG_ON((long)n < 0);
+ if (movsl_is_ok(to, from, n))
+ __copy_user(to, from, n);
+ else
+ n = __copy_user_intel((void __user *)to,
+ (const void *)from, n);
+ return n;
+}
+EXPORT_SYMBOL(__copy_from_user_ll_nozero);
+
+unsigned long __copy_from_user_ll_nocache(void *to, const void __user *from,
+ unsigned long n)
+{
+ BUG_ON((long)n < 0);
+#ifdef CONFIG_X86_INTEL_USERCOPY
+ if ( n > 64 && cpu_has_xmm2)
+ n = __copy_user_zeroing_intel_nocache(to, from, n);
+ else
+ __copy_user_zeroing(to, from, n);
+#else
+ __copy_user_zeroing(to, from, n);
+#endif
+ return n;
+}
+
+unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from,
+ unsigned long n)
+{
+ BUG_ON((long)n < 0);
+#ifdef CONFIG_X86_INTEL_USERCOPY
+ if ( n > 64 && cpu_has_xmm2)
+ n = __copy_user_intel_nocache(to, from, n);
+ else
+ __copy_user(to, from, n);
+#else
+ __copy_user(to, from, n);
+#endif
+ return n;
+}
+
/**
* copy_to_user: - Copy a block of data into user space.
* @to: Destination address, in user space.
diff --git a/arch/i386/mach-default/setup.c b/arch/i386/mach-default/setup.c
index b4a7455..004837c 100644
--- a/arch/i386/mach-default/setup.c
+++ b/arch/i386/mach-default/setup.c
@@ -8,6 +8,8 @@
#include <linux/interrupt.h>
#include <asm/acpi.h>
#include <asm/arch_hooks.h>
+#include <asm/e820.h>
+#include <asm/setup.h>
#ifdef CONFIG_HOTPLUG_CPU
#define DEFAULT_SEND_IPI (1)
@@ -130,3 +132,44 @@ static int __init print_ipi_mode(void)
}
late_initcall(print_ipi_mode);
+
+/**
+ * machine_specific_memory_setup - Hook for machine specific memory setup.
+ *
+ * Description:
+ * This is included late in kernel/setup.c so that it can make
+ * use of all of the static functions.
+ **/
+
+char * __init machine_specific_memory_setup(void)
+{
+ char *who;
+
+
+ who = "BIOS-e820";
+
+ /*
+ * Try to copy the BIOS-supplied E820-map.
+ *
+ * Otherwise fake a memory map; one section from 0k->640k,
+ * the next section from 1mb->appropriate_mem_k
+ */
+ sanitize_e820_map(E820_MAP, &E820_MAP_NR);
+ if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
+ unsigned long mem_size;
+
+ /* compare results from other methods and take the greater */
+ if (ALT_MEM_K < EXT_MEM_K) {
+ mem_size = EXT_MEM_K;
+ who = "BIOS-88";
+ } else {
+ mem_size = ALT_MEM_K;
+ who = "BIOS-e801";
+ }
+
+ e820.nr_map = 0;
+ add_memory_region(0, LOWMEMSIZE(), E820_RAM);
+ add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
+ }
+ return who;
+}
diff --git a/arch/i386/mach-visws/setup.c b/arch/i386/mach-visws/setup.c
index 07fac7e..8a9e1a6 100644
--- a/arch/i386/mach-visws/setup.c
+++ b/arch/i386/mach-visws/setup.c
@@ -10,6 +10,8 @@
#include <asm/fixmap.h>
#include <asm/arch_hooks.h>
#include <asm/io.h>
+#include <asm/e820.h>
+#include <asm/setup.h>
#include "cobalt.h"
#include "piix4.h"
@@ -133,3 +135,50 @@ void __init time_init_hook(void)
/* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */
setup_irq(0, &irq0);
}
+
+/* Hook for machine specific memory setup. */
+
+#define MB (1024 * 1024)
+
+static unsigned long sgivwfb_mem_phys;
+static unsigned long sgivwfb_mem_size;
+
+long long mem_size __initdata = 0;
+
+char * __init machine_specific_memory_setup(void)
+{
+ long long gfx_mem_size = 8 * MB;
+
+ mem_size = ALT_MEM_K;
+
+ if (!mem_size) {
+ printk(KERN_WARNING "Bootloader didn't set memory size, upgrade it !\n");
+ mem_size = 128 * MB;
+ }
+
+ /*
+ * this hardcodes the graphics memory to 8 MB
+ * it really should be sized dynamically (or at least
+ * set as a boot param)
+ */
+ if (!sgivwfb_mem_size) {
+ printk(KERN_WARNING "Defaulting to 8 MB framebuffer size\n");
+ sgivwfb_mem_size = 8 * MB;
+ }
+
+ /*
+ * Trim to nearest MB
+ */
+ sgivwfb_mem_size &= ~((1 << 20) - 1);
+ sgivwfb_mem_phys = mem_size - gfx_mem_size;
+
+ add_memory_region(0, LOWMEMSIZE(), E820_RAM);
+ add_memory_region(HIGH_MEMORY, mem_size - sgivwfb_mem_size - HIGH_MEMORY, E820_RAM);
+ add_memory_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED);
+
+ return "PROM";
+
+ /* Remove gcc warnings */
+ (void) sanitize_e820_map(NULL, NULL);
+ (void) copy_e820_map(NULL, 0);
+}
diff --git a/arch/i386/mach-voyager/setup.c b/arch/i386/mach-voyager/setup.c
index 7d8a3ac..0e22505 100644
--- a/arch/i386/mach-voyager/setup.c
+++ b/arch/i386/mach-voyager/setup.c
@@ -7,6 +7,9 @@
#include <linux/interrupt.h>
#include <asm/acpi.h>
#include <asm/arch_hooks.h>
+#include <asm/voyager.h>
+#include <asm/e820.h>
+#include <asm/setup.h>
void __init pre_intr_init_hook(void)
{
@@ -45,3 +48,74 @@ void __init time_init_hook(void)
{
setup_irq(0, &irq0);
}
+
+/* Hook for machine specific memory setup. */
+
+char * __init machine_specific_memory_setup(void)
+{
+ char *who;
+
+ who = "NOT VOYAGER";
+
+ if(voyager_level == 5) {
+ __u32 addr, length;
+ int i;
+
+ who = "Voyager-SUS";
+
+ e820.nr_map = 0;
+ for(i=0; voyager_memory_detect(i, &addr, &length); i++) {
+ add_memory_region(addr, length, E820_RAM);
+ }
+ return who;
+ } else if(voyager_level == 4) {
+ __u32 tom;
+ __u16 catbase = inb(VOYAGER_SSPB_RELOCATION_PORT)<<8;
+ /* select the DINO config space */
+ outb(VOYAGER_DINO, VOYAGER_CAT_CONFIG_PORT);
+ /* Read DINO top of memory register */
+ tom = ((inb(catbase + 0x4) & 0xf0) << 16)
+ + ((inb(catbase + 0x5) & 0x7f) << 24);
+
+ if(inb(catbase) != VOYAGER_DINO) {
+ printk(KERN_ERR "Voyager: Failed to get DINO for L4, setting tom to EXT_MEM_K\n");
+ tom = (EXT_MEM_K)<<10;
+ }
+ who = "Voyager-TOM";
+ add_memory_region(0, 0x9f000, E820_RAM);
+ /* map from 1M to top of memory */
+ add_memory_region(1*1024*1024, tom - 1*1024*1024, E820_RAM);
+ /* FIXME: Should check the ASICs to see if I need to
+ * take out the 8M window. Just do it at the moment
+ * */
+ add_memory_region(8*1024*1024, 8*1024*1024, E820_RESERVED);
+ return who;
+ }
+
+ who = "BIOS-e820";
+
+ /*
+ * Try to copy the BIOS-supplied E820-map.
+ *
+ * Otherwise fake a memory map; one section from 0k->640k,
+ * the next section from 1mb->appropriate_mem_k
+ */
+ sanitize_e820_map(E820_MAP, &E820_MAP_NR);
+ if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
+ unsigned long mem_size;
+
+ /* compare results from other methods and take the greater */
+ if (ALT_MEM_K < EXT_MEM_K) {
+ mem_size = EXT_MEM_K;
+ who = "BIOS-88";
+ } else {
+ mem_size = ALT_MEM_K;
+ who = "BIOS-e801";
+ }
+
+ e820.nr_map = 0;
+ add_memory_region(0, LOWMEMSIZE(), E820_RAM);
+ add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
+ }
+ return who;
+}
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index 7f0fcf2..bd6fe96 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -77,12 +77,15 @@ static inline unsigned long get_segment_eip(struct pt_regs *regs,
unsigned seg = regs->xcs & 0xffff;
u32 seg_ar, seg_limit, base, *desc;
+ /* Unlikely, but must come before segment checks. */
+ if (unlikely(regs->eflags & VM_MASK)) {
+ base = seg << 4;
+ *eip_limit = base + 0xffff;
+ return base + (eip & 0xffff);
+ }
+
/* The standard kernel/user address space limit. */
*eip_limit = (seg & 3) ? USER_DS.seg : KERNEL_DS.seg;
-
- /* Unlikely, but must come before segment checks. */
- if (unlikely((regs->eflags & VM_MASK) != 0))
- return eip + (seg << 4);
/* By far the most common cases. */
if (likely(seg == __USER_CS || seg == __KERNEL_CS))
@@ -380,12 +383,12 @@ fastcall void __kprobes do_page_fault(struct pt_regs *regs,
goto bad_area;
if (error_code & 4) {
/*
- * accessing the stack below %esp is always a bug.
- * The "+ 32" is there due to some instructions (like
- * pusha) doing post-decrement on the stack and that
- * doesn't show up until later..
+ * Accessing the stack below %esp is always a bug.
+ * The large cushion allows instructions like enter
+ * and pusha to work. ("enter $65535,$31" pushes
+ * 32 pointers and then decrements %esp by 65535.)
*/
- if (address + 32 < regs->esp)
+ if (address + 65536 + 32 * sizeof(unsigned long) < regs->esp)
goto bad_area;
}
if (expand_stack(vma, address))
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index 3df1371..bf19513 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -29,6 +29,7 @@
#include <linux/efi.h>
#include <linux/memory_hotplug.h>
#include <linux/initrd.h>
+#include <linux/cpumask.h>
#include <asm/processor.h>
#include <asm/system.h>
@@ -384,7 +385,7 @@ static void __init pagetable_init (void)
#endif
}
-#ifdef CONFIG_SOFTWARE_SUSPEND
+#if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_ACPI_SLEEP)
/*
* Swap suspend & friends need this for resume because things like the intel-agp
* driver might have split up a kernel 4MB mapping.
diff --git a/arch/i386/mm/pageattr.c b/arch/i386/mm/pageattr.c
index 92c3d9f..0887b34 100644
--- a/arch/i386/mm/pageattr.c
+++ b/arch/i386/mm/pageattr.c
@@ -209,19 +209,19 @@ int change_page_attr(struct page *page, int numpages, pgprot_t prot)
}
void global_flush_tlb(void)
-{
- LIST_HEAD(l);
+{
+ struct list_head l;
struct page *pg, *next;
BUG_ON(irqs_disabled());
spin_lock_irq(&cpa_lock);
- list_splice_init(&df_list, &l);
+ list_replace_init(&df_list, &l);
spin_unlock_irq(&cpa_lock);
flush_map();
list_for_each_entry_safe(pg, next, &l, lru)
__free_page(pg);
-}
+}
#ifdef CONFIG_DEBUG_PAGEALLOC
void kernel_map_pages(struct page *page, int numpages, int enable)
diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c
index dbece77..c624b61 100644
--- a/arch/i386/pci/common.c
+++ b/arch/i386/pci/common.c
@@ -288,6 +288,7 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
void pcibios_disable_device (struct pci_dev *dev)
{
+ pcibios_disable_resources(dev);
if (pcibios_disable_irq)
pcibios_disable_irq(dev);
}
diff --git a/arch/i386/pci/i386.c b/arch/i386/pci/i386.c
index ed2c8c8..a151f7a 100644
--- a/arch/i386/pci/i386.c
+++ b/arch/i386/pci/i386.c
@@ -242,6 +242,15 @@ int pcibios_enable_resources(struct pci_dev *dev, int mask)
return 0;
}
+void pcibios_disable_resources(struct pci_dev *dev)
+{
+ u16 cmd;
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+}
+
/*
* If we set up a device for bus mastering, we need to check the latency
* timer as certain crappy BIOSes forget to set it properly.
@@ -276,8 +285,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
/* Leave vm_pgoff as-is, the PCI space address is the physical
* address on this platform.
*/
- vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO);
-
prot = pgprot_val(vma->vm_page_prot);
if (boot_cpu_data.x86 > 3)
prot |= _PAGE_PCD | _PAGE_PWT;
diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c
index 06dab00..8ce6950 100644
--- a/arch/i386/pci/irq.c
+++ b/arch/i386/pci/irq.c
@@ -198,14 +198,14 @@ static void write_config_nybble(struct pci_dev *router, unsigned offset, unsigne
*/
static int pirq_ali_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
{
- static unsigned char irqmap[16] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };
+ static const unsigned char irqmap[16] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };
return irqmap[read_config_nybble(router, 0x48, pirq-1)];
}
static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
{
- static unsigned char irqmap[16] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
+ static const unsigned char irqmap[16] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
unsigned int val = irqmap[irq];
if (val) {
@@ -256,13 +256,13 @@ static int pirq_via_set(struct pci_dev *router, struct pci_dev *dev, int pirq, i
*/
static int pirq_via586_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
{
- static unsigned int pirqmap[4] = { 3, 2, 5, 1 };
+ static const unsigned int pirqmap[4] = { 3, 2, 5, 1 };
return read_config_nybble(router, 0x55, pirqmap[pirq-1]);
}
static int pirq_via586_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
{
- static unsigned int pirqmap[4] = { 3, 2, 5, 1 };
+ static const unsigned int pirqmap[4] = { 3, 2, 5, 1 };
write_config_nybble(router, 0x55, pirqmap[pirq-1], irq);
return 1;
}
@@ -274,13 +274,13 @@ static int pirq_via586_set(struct pci_dev *router, struct pci_dev *dev, int pirq
*/
static int pirq_ite_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
{
- static unsigned char pirqmap[4] = { 1, 0, 2, 3 };
+ static const unsigned char pirqmap[4] = { 1, 0, 2, 3 };
return read_config_nybble(router,0x43, pirqmap[pirq-1]);
}
static int pirq_ite_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
{
- static unsigned char pirqmap[4] = { 1, 0, 2, 3 };
+ static const unsigned char pirqmap[4] = { 1, 0, 2, 3 };
write_config_nybble(router, 0x43, pirqmap[pirq-1], irq);
return 1;
}
@@ -505,7 +505,7 @@ static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq,
static __init int intel_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
- static struct pci_device_id pirq_440gx[] = {
+ static struct pci_device_id __initdata pirq_440gx[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_2) },
{ },
@@ -880,6 +880,7 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
((!(pci_probe & PCI_USE_PIRQ_MASK)) || ((1 << irq) & mask)) ) {
DBG(" -> got IRQ %d\n", irq);
msg = "Found";
+ eisa_set_level_irq(irq);
} else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
DBG(" -> assigning IRQ %d", newirq);
if (r->set(pirq_router_dev, dev, pirq, newirq)) {
diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c
index 6b1ea0c..e545b09 100644
--- a/arch/i386/pci/mmconfig.c
+++ b/arch/i386/pci/mmconfig.c
@@ -15,7 +15,9 @@
#include <asm/e820.h>
#include "pci.h"
-#define MMCONFIG_APER_SIZE (256*1024*1024)
+/* aperture is up to 256MB but BIOS may reserve less */
+#define MMCONFIG_APER_MIN (2 * 1024*1024)
+#define MMCONFIG_APER_MAX (256 * 1024*1024)
/* Assume systems with more busses have correct MCFG */
#define MAX_CHECK_BUS 16
@@ -197,9 +199,10 @@ void __init pci_mmcfg_init(void)
return;
if (!e820_all_mapped(pci_mmcfg_config[0].base_address,
- pci_mmcfg_config[0].base_address + MMCONFIG_APER_SIZE,
+ pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN,
E820_RESERVED)) {
- printk(KERN_ERR "PCI: BIOS Bug: MCFG area is not E820-reserved\n");
+ printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n",
+ pci_mmcfg_config[0].base_address);
printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
return;
}
diff --git a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h
index 12035e2..12bf3d8 100644
--- a/arch/i386/pci/pci.h
+++ b/arch/i386/pci/pci.h
@@ -35,6 +35,7 @@ extern unsigned int pcibios_max_latency;
void pcibios_resource_survey(void);
int pcibios_enable_resources(struct pci_dev *, int);
+void pcibios_disable_resources(struct pci_dev *);
/* pci-pc.c */
diff --git a/arch/i386/power/cpu.c b/arch/i386/power/cpu.c
index 79b2370..e651791 100644
--- a/arch/i386/power/cpu.c
+++ b/arch/i386/power/cpu.c
@@ -10,6 +10,8 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/suspend.h>
+#include <asm/mtrr.h>
+#include <asm/mce.h>
static struct saved_context saved_context;
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 0f3076a..1831874 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -77,6 +77,7 @@ choice
config IA64_GENERIC
bool "generic"
select ACPI
+ select PCI
select NUMA
select ACPI_NUMA
help
@@ -273,7 +274,6 @@ config HOTPLUG_CPU
config SCHED_SMT
bool "SMT scheduler support"
depends on SMP
- default off
help
Improves the CPU scheduler's decision making when dealing with
Intel IA64 chips with MultiThreading at a cost of slightly increased
@@ -449,6 +449,8 @@ config PCI_DOMAINS
bool
default PCI
+source "drivers/pci/pcie/Kconfig"
+
source "drivers/pci/Kconfig"
source "drivers/pci/hotplug/Kconfig"
diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile
index 80ea750..21033ed 100644
--- a/arch/ia64/Makefile
+++ b/arch/ia64/Makefile
@@ -71,6 +71,8 @@ all: compressed unwcheck
compressed: vmlinux.gz
+vmlinuz: vmlinux.gz
+
vmlinux.gz: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $@
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
index bdccd0b..5825dde 100644
--- a/arch/ia64/hp/common/sba_iommu.c
+++ b/arch/ia64/hp/common/sba_iommu.c
@@ -1958,7 +1958,7 @@ sba_map_ioc_to_node(struct ioc *ioc, acpi_handle handle)
if (pxm < 0)
return;
- node = pxm_to_nid_map[pxm];
+ node = pxm_to_node(pxm);
if (node >= MAX_NUMNODES || !node_online(node))
return;
@@ -1999,7 +1999,7 @@ acpi_sba_ioc_add(struct acpi_device *device)
if (!iovp_shift)
iovp_shift = min(PAGE_SHIFT, 16);
}
- ACPI_MEM_FREE(dev_info);
+ kfree(dev_info);
/*
* default anything not caught above or specified on cmdline to 4k
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index 58c93a3..ca16d95 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -68,8 +68,6 @@ EXPORT_SYMBOL(pm_power_off);
unsigned char acpi_kbd_controller_present = 1;
unsigned char acpi_legacy_devices;
-static unsigned int __initdata acpi_madt_rev;
-
unsigned int acpi_cpei_override;
unsigned int acpi_cpei_phys_cpuid;
@@ -243,6 +241,8 @@ acpi_parse_iosapic(acpi_table_entry_header * header, const unsigned long end)
return iosapic_init(iosapic->address, iosapic->global_irq_base);
}
+static unsigned int __initdata acpi_madt_rev;
+
static int __init
acpi_parse_plat_int_src(acpi_table_entry_header * header,
const unsigned long end)
@@ -415,9 +415,6 @@ static int __initdata srat_num_cpus; /* number of cpus */
static u32 __devinitdata pxm_flag[PXM_FLAG_LEN];
#define pxm_bit_set(bit) (set_bit(bit,(void *)pxm_flag))
#define pxm_bit_test(bit) (test_bit(bit,(void *)pxm_flag))
-/* maps to convert between proximity domain and logical node ID */
-int __devinitdata pxm_to_nid_map[MAX_PXM_DOMAINS];
-int __initdata nid_to_pxm_map[MAX_NUMNODES];
static struct acpi_table_slit __initdata *slit_table;
static int get_processor_proximity_domain(struct acpi_table_processor_affinity *pa)
@@ -533,22 +530,17 @@ void __init acpi_numa_arch_fixup(void)
* MCD - This can probably be dropped now. No need for pxm ID to node ID
* mapping with sparse node numbering iff MAX_PXM_DOMAINS <= MAX_NUMNODES.
*/
- /* calculate total number of nodes in system from PXM bitmap */
- memset(pxm_to_nid_map, -1, sizeof(pxm_to_nid_map));
- memset(nid_to_pxm_map, -1, sizeof(nid_to_pxm_map));
nodes_clear(node_online_map);
for (i = 0; i < MAX_PXM_DOMAINS; i++) {
if (pxm_bit_test(i)) {
- int nid = num_online_nodes();
- pxm_to_nid_map[i] = nid;
- nid_to_pxm_map[nid] = i;
+ int nid = acpi_map_pxm_to_node(i);
node_set_online(nid);
}
}
/* set logical node id in memory chunk structure */
for (i = 0; i < num_node_memblks; i++)
- node_memblk[i].nid = pxm_to_nid_map[node_memblk[i].nid];
+ node_memblk[i].nid = pxm_to_node(node_memblk[i].nid);
/* assign memory bank numbers for each chunk on each node */
for_each_online_node(i) {
@@ -562,7 +554,7 @@ void __init acpi_numa_arch_fixup(void)
/* set logical node id in cpu structure */
for (i = 0; i < srat_num_cpus; i++)
- node_cpuid[i].nid = pxm_to_nid_map[node_cpuid[i].nid];
+ node_cpuid[i].nid = pxm_to_node(node_cpuid[i].nid);
printk(KERN_INFO "Number of logical nodes in system = %d\n",
num_online_nodes());
@@ -575,11 +567,11 @@ void __init acpi_numa_arch_fixup(void)
for (i = 0; i < slit_table->localities; i++) {
if (!pxm_bit_test(i))
continue;
- node_from = pxm_to_nid_map[i];
+ node_from = pxm_to_node(i);
for (j = 0; j < slit_table->localities; j++) {
if (!pxm_bit_test(j))
continue;
- node_to = pxm_to_nid_map[j];
+ node_to = pxm_to_node(j);
node_distance(node_from, node_to) =
slit_table->entry[i * slit_table->localities + j];
}
@@ -626,7 +618,7 @@ EXPORT_SYMBOL(acpi_unregister_gsi);
static int __init acpi_parse_fadt(unsigned long phys_addr, unsigned long size)
{
struct acpi_table_header *fadt_header;
- struct fadt_descriptor_rev2 *fadt;
+ struct fadt_descriptor *fadt;
if (!phys_addr || !size)
return -EINVAL;
@@ -635,7 +627,7 @@ static int __init acpi_parse_fadt(unsigned long phys_addr, unsigned long size)
if (fadt_header->revision != 3)
return -ENODEV; /* Only deal with ACPI 2.0 FADT */
- fadt = (struct fadt_descriptor_rev2 *)fadt_header;
+ fadt = (struct fadt_descriptor *)fadt_header;
if (!(fadt->iapc_boot_arch & BAF_8042_KEYBOARD_CONTROLLER))
acpi_kbd_controller_present = 0;
@@ -785,9 +777,9 @@ int acpi_map_cpu2node(acpi_handle handle, int cpu, long physid)
/*
* Assuming that the container driver would have set the proximity
- * domain and would have initialized pxm_to_nid_map[pxm_id] && pxm_flag
+ * domain and would have initialized pxm_to_node(pxm_id) && pxm_flag
*/
- node_cpuid[cpu].nid = (pxm_id < 0) ? 0 : pxm_to_nid_map[pxm_id];
+ node_cpuid[cpu].nid = (pxm_id < 0) ? 0 : pxm_to_node(pxm_id);
node_cpuid[cpu].phys_id = physid;
#endif
@@ -966,7 +958,7 @@ acpi_map_iosapic(acpi_handle handle, u32 depth, void *context, void **ret)
if (pxm < 0)
return AE_OK;
- node = pxm_to_nid_map[pxm];
+ node = pxm_to_node(pxm);
if (node >= MAX_NUMNODES || !node_online(node) ||
cpus_empty(node_to_cpumask(node)))
diff --git a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c
index 7722565..16e7b66 100644
--- a/arch/ia64/kernel/asm-offsets.c
+++ b/arch/ia64/kernel/asm-offsets.c
@@ -217,16 +217,24 @@ void foo(void)
DEFINE(IA64_MCA_CPU_INIT_STACK_OFFSET,
offsetof (struct ia64_mca_cpu, init_stack));
BLANK();
- DEFINE(IA64_SAL_OS_STATE_COMMON_OFFSET,
- offsetof (struct ia64_sal_os_state, sal_ra));
DEFINE(IA64_SAL_OS_STATE_OS_GP_OFFSET,
offsetof (struct ia64_sal_os_state, os_gp));
- DEFINE(IA64_SAL_OS_STATE_PAL_MIN_STATE_OFFSET,
- offsetof (struct ia64_sal_os_state, pal_min_state));
DEFINE(IA64_SAL_OS_STATE_PROC_STATE_PARAM_OFFSET,
offsetof (struct ia64_sal_os_state, proc_state_param));
+ DEFINE(IA64_SAL_OS_STATE_SAL_RA_OFFSET,
+ offsetof (struct ia64_sal_os_state, sal_ra));
+ DEFINE(IA64_SAL_OS_STATE_SAL_GP_OFFSET,
+ offsetof (struct ia64_sal_os_state, sal_gp));
+ DEFINE(IA64_SAL_OS_STATE_PAL_MIN_STATE_OFFSET,
+ offsetof (struct ia64_sal_os_state, pal_min_state));
+ DEFINE(IA64_SAL_OS_STATE_OS_STATUS_OFFSET,
+ offsetof (struct ia64_sal_os_state, os_status));
+ DEFINE(IA64_SAL_OS_STATE_CONTEXT_OFFSET,
+ offsetof (struct ia64_sal_os_state, context));
DEFINE(IA64_SAL_OS_STATE_SIZE,
sizeof (struct ia64_sal_os_state));
+ BLANK();
+
DEFINE(IA64_PMSA_GR_OFFSET,
offsetof (struct pal_min_state_area_s, pmsa_gr));
DEFINE(IA64_PMSA_BANK1_GR_OFFSET,
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index 12cfedc..c33d0ba 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -8,6 +8,8 @@
* Copyright (C) 1999-2003 Hewlett-Packard Co.
* David Mosberger-Tang <davidm@hpl.hp.com>
* Stephane Eranian <eranian@hpl.hp.com>
+ * (c) Copyright 2006 Hewlett-Packard Development Company, L.P.
+ * Bjorn Helgaas <bjorn.helgaas@hp.com>
*
* All EFI Runtime Services are not implemented yet as EFI only
* supports physical mode addressing on SoftSDV. This is to be fixed
@@ -622,28 +624,20 @@ efi_get_iobase (void)
return 0;
}
-static efi_memory_desc_t *
-efi_memory_descriptor (unsigned long phys_addr)
+static struct kern_memdesc *
+kern_memory_descriptor (unsigned long phys_addr)
{
- void *efi_map_start, *efi_map_end, *p;
- efi_memory_desc_t *md;
- u64 efi_desc_size;
-
- efi_map_start = __va(ia64_boot_param->efi_memmap);
- efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size;
- efi_desc_size = ia64_boot_param->efi_memdesc_size;
+ struct kern_memdesc *md;
- for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
- md = p;
-
- if (phys_addr - md->phys_addr < (md->num_pages << EFI_PAGE_SHIFT))
+ for (md = kern_memmap; md->start != ~0UL; md++) {
+ if (phys_addr - md->start < (md->num_pages << EFI_PAGE_SHIFT))
return md;
}
return 0;
}
-static int
-efi_memmap_has_mmio (void)
+static efi_memory_desc_t *
+efi_memory_descriptor (unsigned long phys_addr)
{
void *efi_map_start, *efi_map_end, *p;
efi_memory_desc_t *md;
@@ -656,8 +650,8 @@ efi_memmap_has_mmio (void)
for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
md = p;
- if (md->type == EFI_MEMORY_MAPPED_IO)
- return 1;
+ if (phys_addr - md->phys_addr < (md->num_pages << EFI_PAGE_SHIFT))
+ return md;
}
return 0;
}
@@ -683,71 +677,125 @@ efi_mem_attributes (unsigned long phys_addr)
}
EXPORT_SYMBOL(efi_mem_attributes);
-/*
- * Determines whether the memory at phys_addr supports the desired
- * attribute (WB, UC, etc). If this returns 1, the caller can safely
- * access size bytes at phys_addr with the specified attribute.
- */
-int
-efi_mem_attribute_range (unsigned long phys_addr, unsigned long size, u64 attr)
+u64
+efi_mem_attribute (unsigned long phys_addr, unsigned long size)
{
unsigned long end = phys_addr + size;
efi_memory_desc_t *md = efi_memory_descriptor(phys_addr);
+ u64 attr;
+
+ if (!md)
+ return 0;
+
+ /*
+ * EFI_MEMORY_RUNTIME is not a memory attribute; it just tells
+ * the kernel that firmware needs this region mapped.
+ */
+ attr = md->attribute & ~EFI_MEMORY_RUNTIME;
+ do {
+ unsigned long md_end = efi_md_end(md);
+
+ if (end <= md_end)
+ return attr;
+
+ md = efi_memory_descriptor(md_end);
+ if (!md || (md->attribute & ~EFI_MEMORY_RUNTIME) != attr)
+ return 0;
+ } while (md);
+ return 0;
+}
+
+u64
+kern_mem_attribute (unsigned long phys_addr, unsigned long size)
+{
+ unsigned long end = phys_addr + size;
+ struct kern_memdesc *md;
+ u64 attr;
/*
- * Some firmware doesn't report MMIO regions in the EFI memory
- * map. The Intel BigSur (a.k.a. HP i2000) has this problem.
- * On those platforms, we have to assume UC is valid everywhere.
+ * This is a hack for ioremap calls before we set up kern_memmap.
+ * Maybe we should do efi_memmap_init() earlier instead.
*/
- if (!md || (md->attribute & attr) != attr) {
- if (attr == EFI_MEMORY_UC && !efi_memmap_has_mmio())
- return 1;
+ if (!kern_memmap) {
+ attr = efi_mem_attribute(phys_addr, size);
+ if (attr & EFI_MEMORY_WB)
+ return EFI_MEMORY_WB;
return 0;
}
+ md = kern_memory_descriptor(phys_addr);
+ if (!md)
+ return 0;
+
+ attr = md->attribute;
do {
- unsigned long md_end = efi_md_end(md);
+ unsigned long md_end = kmd_end(md);
if (end <= md_end)
- return 1;
+ return attr;
- md = efi_memory_descriptor(md_end);
- if (!md || (md->attribute & attr) != attr)
+ md = kern_memory_descriptor(md_end);
+ if (!md || md->attribute != attr)
return 0;
} while (md);
return 0;
}
+EXPORT_SYMBOL(kern_mem_attribute);
-/*
- * For /dev/mem, we only allow read & write system calls to access
- * write-back memory, because read & write don't allow the user to
- * control access size.
- */
int
valid_phys_addr_range (unsigned long phys_addr, unsigned long size)
{
- return efi_mem_attribute_range(phys_addr, size, EFI_MEMORY_WB);
+ u64 attr;
+
+ /*
+ * /dev/mem reads and writes use copy_to_user(), which implicitly
+ * uses a granule-sized kernel identity mapping. It's really
+ * only safe to do this for regions in kern_memmap. For more
+ * details, see Documentation/ia64/aliasing.txt.
+ */
+ attr = kern_mem_attribute(phys_addr, size);
+ if (attr & EFI_MEMORY_WB || attr & EFI_MEMORY_UC)
+ return 1;
+ return 0;
}
-/*
- * We allow mmap of anything in the EFI memory map that supports
- * either write-back or uncacheable access. For uncacheable regions,
- * the supported access sizes are system-dependent, and the user is
- * responsible for using the correct size.
- *
- * Note that this doesn't currently allow access to hot-added memory,
- * because that doesn't appear in the boot-time EFI memory map.
- */
int
valid_mmap_phys_addr_range (unsigned long phys_addr, unsigned long size)
{
- if (efi_mem_attribute_range(phys_addr, size, EFI_MEMORY_WB))
- return 1;
+ /*
+ * MMIO regions are often missing from the EFI memory map.
+ * We must allow mmap of them for programs like X, so we
+ * currently can't do any useful validation.
+ */
+ return 1;
+}
- if (efi_mem_attribute_range(phys_addr, size, EFI_MEMORY_UC))
- return 1;
+pgprot_t
+phys_mem_access_prot(struct file *file, unsigned long pfn, unsigned long size,
+ pgprot_t vma_prot)
+{
+ unsigned long phys_addr = pfn << PAGE_SHIFT;
+ u64 attr;
- return 0;
+ /*
+ * For /dev/mem mmap, we use user mappings, but if the region is
+ * in kern_memmap (and hence may be covered by a kernel mapping),
+ * we must use the same attribute as the kernel mapping.
+ */
+ attr = kern_mem_attribute(phys_addr, size);
+ if (attr & EFI_MEMORY_WB)
+ return pgprot_cacheable(vma_prot);
+ else if (attr & EFI_MEMORY_UC)
+ return pgprot_noncached(vma_prot);
+
+ /*
+ * Some chipsets don't support UC access to memory. If
+ * WB is supported, we prefer that.
+ */
+ if (efi_mem_attribute(phys_addr, size) & EFI_MEMORY_WB)
+ return pgprot_cacheable(vma_prot);
+
+ return pgprot_noncached(vma_prot);
}
int __init
diff --git a/arch/ia64/kernel/efi_stub.S b/arch/ia64/kernel/efi_stub.S
index 5a7fe70..a56e161 100644
--- a/arch/ia64/kernel/efi_stub.S
+++ b/arch/ia64/kernel/efi_stub.S
@@ -61,7 +61,7 @@ GLOBAL_ENTRY(efi_call_phys)
or loc3=loc3,r17
mov b6=r2
;;
- andcm r16=loc3,r16 // get psr with IT, DT, and RT bits cleared
+ andcm r16=loc3,r16 // get psr with IT, DT, and RT bits cleared
br.call.sptk.many rp=ia64_switch_mode_phys
.ret0: mov out4=in5
mov out0=in1
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index bcb80ca..32c999f 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -1584,7 +1584,7 @@ sys_call_table:
data8 sys_keyctl
data8 sys_ioprio_set
data8 sys_ioprio_get // 1275
- data8 sys_ni_syscall
+ data8 sys_move_pages
data8 sys_inotify_init
data8 sys_inotify_add_watch
data8 sys_inotify_rm_watch
diff --git a/arch/ia64/kernel/entry.h b/arch/ia64/kernel/entry.h
index 78eeb07..ebc3dfb 100644
--- a/arch/ia64/kernel/entry.h
+++ b/arch/ia64/kernel/entry.h
@@ -23,6 +23,7 @@
#define PT(f) (IA64_PT_REGS_##f##_OFFSET)
#define SW(f) (IA64_SWITCH_STACK_##f##_OFFSET)
+#define SOS(f) (IA64_SAL_OS_STATE_##f##_OFFSET)
#define PT_REGS_SAVES(off) \
.unwabi 3, 'i'; \
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
index 6c4d59f..ef9a2b4 100644
--- a/arch/ia64/kernel/irq_ia64.c
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -46,6 +46,10 @@
#define IRQ_DEBUG 0
+/* These can be overridden in platform_irq_init */
+int ia64_first_device_vector = IA64_DEF_FIRST_DEVICE_VECTOR;
+int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR;
+
/* default base addr of IPI table */
void __iomem *ipi_base_addr = ((void __iomem *)
(__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR));
@@ -60,7 +64,7 @@ __u8 isa_irq_to_vector_map[16] = {
};
EXPORT_SYMBOL(isa_irq_to_vector_map);
-static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)];
+static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_MAX_DEVICE_VECTORS)];
int
assign_irq_vector (int irq)
@@ -89,6 +93,19 @@ free_irq_vector (int vector)
printk(KERN_WARNING "%s: double free!\n", __FUNCTION__);
}
+int
+reserve_irq_vector (int vector)
+{
+ int pos;
+
+ if (vector < IA64_FIRST_DEVICE_VECTOR ||
+ vector > IA64_LAST_DEVICE_VECTOR)
+ return -EINVAL;
+
+ pos = vector - IA64_FIRST_DEVICE_VECTOR;
+ return test_and_set_bit(pos, ia64_vector_mask);
+}
+
#ifdef CONFIG_SMP
# define IS_RESCHEDULE(vec) (vec == IA64_IPI_RESCHEDULE)
#else
diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S
index 6dff024..c1bd1fe 100644
--- a/arch/ia64/kernel/mca_asm.S
+++ b/arch/ia64/kernel/mca_asm.S
@@ -159,7 +159,7 @@ ia64_os_mca_spin:
GET_IA64_MCA_DATA(r2)
// Using MCA stack, struct ia64_sal_os_state, variable proc_state_param
;;
- add r3=IA64_MCA_CPU_MCA_STACK_OFFSET+MCA_SOS_OFFSET+IA64_SAL_OS_STATE_PROC_STATE_PARAM_OFFSET, r2
+ add r3=IA64_MCA_CPU_MCA_STACK_OFFSET+MCA_SOS_OFFSET+SOS(PROC_STATE_PARAM), r2
;;
ld8 r18=[r3] // Get processor state parameter on existing PALE_CHECK.
;;
@@ -479,9 +479,11 @@ ia64_state_save:
st8 [temp2]=r11,16 // rv_rc
mov r11=cr.iipa
;;
- st8 [temp1]=r18,16 // proc_state_param
- st8 [temp2]=r19,16 // monarch
+ st8 [temp1]=r18 // proc_state_param
+ st8 [temp2]=r19 // monarch
mov r6=IA64_KR(CURRENT)
+ add temp1=SOS(SAL_RA), regs
+ add temp2=SOS(SAL_GP), regs
;;
st8 [temp1]=r12,16 // sal_ra
st8 [temp2]=r10,16 // sal_gp
@@ -503,12 +505,14 @@ ia64_state_save:
st8 [temp2]=r11,16 // cr.iipa
mov r12=cr.iim
;;
- st8 [temp1]=r12,16 // cr.iim
+ st8 [temp1]=r12 // cr.iim
(p1) mov r12=IA64_MCA_COLD_BOOT
(p2) mov r12=IA64_INIT_WARM_BOOT
mov r6=cr.iha
+ add temp1=SOS(OS_STATUS), regs
;;
- st8 [temp2]=r6,16 // cr.iha
+ st8 [temp2]=r6 // cr.iha
+ add temp2=SOS(CONTEXT), regs
st8 [temp1]=r12 // os_status, default is cold boot
mov r6=IA64_MCA_SAME_CONTEXT
;;
@@ -820,8 +824,8 @@ ia64_state_restore:
// Restore the SAL to OS state. The previous code left regs at pt_regs.
add regs=MCA_SOS_OFFSET-MCA_PT_REGS_OFFSET, regs
;;
- add temp1=IA64_SAL_OS_STATE_COMMON_OFFSET, regs
- add temp2=IA64_SAL_OS_STATE_COMMON_OFFSET+8, regs
+ add temp1=SOS(SAL_RA), regs
+ add temp2=SOS(SAL_GP), regs
;;
ld8 r12=[temp1],16 // sal_ra
ld8 r9=[temp2],16 // sal_gp
@@ -842,8 +846,10 @@ ia64_state_restore:
;;
mov cr.itir=temp3
mov cr.iipa=temp4
- ld8 temp3=[temp1],16 // cr.iim
- ld8 temp4=[temp2],16 // cr.iha
+ ld8 temp3=[temp1] // cr.iim
+ ld8 temp4=[temp2] // cr.iha
+ add temp1=SOS(OS_STATUS), regs
+ add temp2=SOS(CONTEXT), regs
;;
mov cr.iim=temp3
mov cr.iha=temp4
@@ -916,7 +922,7 @@ ia64_state_restore:
ia64_new_stack:
add regs=MCA_PT_REGS_OFFSET, r3
- add temp2=MCA_SOS_OFFSET+IA64_SAL_OS_STATE_PAL_MIN_STATE_OFFSET, r3
+ add temp2=MCA_SOS_OFFSET+SOS(PAL_MIN_STATE), r3
mov b0=r2 // save return address
GET_IA64_MCA_DATA(temp1)
invala
@@ -1020,7 +1026,7 @@ ia64_old_stack:
ia64_set_kernel_registers:
add temp3=MCA_SP_OFFSET, r3
- add temp4=MCA_SOS_OFFSET+IA64_SAL_OS_STATE_OS_GP_OFFSET, r3
+ add temp4=MCA_SOS_OFFSET+SOS(OS_GP), r3
mov b0=r2 // save return address
GET_IA64_MCA_DATA(temp1)
;;
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index 077f212..6d7bc8f 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -532,7 +532,6 @@ static ctl_table pfm_sysctl_root[] = {
static struct ctl_table_header *pfm_sysctl_header;
static int pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs);
-static int pfm_flush(struct file *filp);
#define pfm_get_cpu_var(v) __ia64_per_cpu_var(v)
#define pfm_get_cpu_data(a,b) per_cpu(a, b)
@@ -595,10 +594,11 @@ pfm_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
}
-static struct super_block *
-pfmfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data)
+static int
+pfmfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data,
+ struct vfsmount *mnt)
{
- return get_sb_pseudo(fs_type, "pfm:", NULL, PFMFS_MAGIC);
+ return get_sb_pseudo(fs_type, "pfm:", NULL, PFMFS_MAGIC, mnt);
}
static struct file_system_type pfm_fs_type = {
@@ -1773,7 +1773,7 @@ pfm_syswide_cleanup_other_cpu(pfm_context_t *ctx)
* When caller is self-monitoring, the context is unloaded.
*/
static int
-pfm_flush(struct file *filp)
+pfm_flush(struct file *filp, fl_owner_t id)
{
pfm_context_t *ctx;
struct task_struct *task;
diff --git a/arch/ia64/kernel/sal.c b/arch/ia64/kernel/sal.c
index 056f7a6..77fa659 100644
--- a/arch/ia64/kernel/sal.c
+++ b/arch/ia64/kernel/sal.c
@@ -227,7 +227,7 @@ static int sal_cache_flush_drops_interrupts;
static void __init
check_sal_cache_flush (void)
{
- unsigned long flags, itv;
+ unsigned long flags;
int cpu;
u64 vector;
@@ -238,9 +238,6 @@ check_sal_cache_flush (void)
* Schedule a timer interrupt, wait until it's reported, and see if
* SAL_CACHE_FLUSH drops it.
*/
- itv = ia64_get_itv();
- BUG_ON((itv & (1 << 16)) == 0);
-
ia64_set_itv(IA64_TIMER_VECTOR);
ia64_set_itm(ia64_get_itc() + 1000);
@@ -260,7 +257,6 @@ check_sal_cache_flush (void)
ia64_eoi();
}
- ia64_set_itv(itv);
local_irq_restore(flags);
put_cpu();
}
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index e4dfda1..6dba2d6 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -260,6 +260,7 @@ reserve_memory (void)
n++;
num_rsvd_regions = n;
+ BUG_ON(IA64_MAX_RSVD_REGIONS + 1 < n);
sort_regions(rsvd_region, num_rsvd_regions);
}
diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c
index 4f3a16b..879edb5 100644
--- a/arch/ia64/kernel/topology.c
+++ b/arch/ia64/kernel/topology.c
@@ -166,7 +166,7 @@ static void cache_shared_cpu_map_setup( unsigned int cpu,
num_shared = (int) csi.num_shared;
do {
- for_each_cpu(j)
+ for_each_possible_cpu(j)
if (cpu_data(cpu)->socket_id == cpu_data(j)->socket_id
&& cpu_data(j)->core_id == csi.log1_cid
&& cpu_data(j)->thread_id == csi.log1_tid)
diff --git a/arch/ia64/kernel/uncached.c b/arch/ia64/kernel/uncached.c
index fcd2bad..5f03b9e 100644
--- a/arch/ia64/kernel/uncached.c
+++ b/arch/ia64/kernel/uncached.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2001-2005 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2001-2006 Silicon Graphics, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License
@@ -29,15 +29,8 @@
#include <asm/tlbflush.h>
#include <asm/sn/arch.h>
-#define DEBUG 0
-#if DEBUG
-#define dprintk printk
-#else
-#define dprintk(x...) do { } while (0)
-#endif
-
-void __init efi_memmap_walk_uc (efi_freemem_callback_t callback);
+extern void __init efi_memmap_walk_uc(efi_freemem_callback_t, void *);
#define MAX_UNCACHED_GRANULES 5
static int allocated_granules;
@@ -60,6 +53,7 @@ static void uncached_ipi_visibility(void *data)
static void uncached_ipi_mc_drain(void *data)
{
int status;
+
status = ia64_pal_mc_drain();
if (status)
printk(KERN_WARNING "ia64_pal_mc_drain() failed with %i on "
@@ -67,30 +61,35 @@ static void uncached_ipi_mc_drain(void *data)
}
-static unsigned long
-uncached_get_new_chunk(struct gen_pool *poolp)
+/*
+ * Add a new chunk of uncached memory pages to the specified pool.
+ *
+ * @pool: pool to add new chunk of uncached memory to
+ * @nid: node id of node to allocate memory from, or -1
+ *
+ * This is accomplished by first allocating a granule of cached memory pages
+ * and then converting them to uncached memory pages.
+ */
+static int uncached_add_chunk(struct gen_pool *pool, int nid)
{
struct page *page;
- void *tmp;
int status, i;
- unsigned long addr, node;
+ unsigned long c_addr, uc_addr;
if (allocated_granules >= MAX_UNCACHED_GRANULES)
- return 0;
+ return -1;
+
+ /* attempt to allocate a granule's worth of cached memory pages */
- node = poolp->private;
- page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO,
+ page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO,
IA64_GRANULE_SHIFT-PAGE_SHIFT);
+ if (!page)
+ return -1;
- dprintk(KERN_INFO "get_new_chunk page %p, addr %lx\n",
- page, (unsigned long)(page-vmem_map) << PAGE_SHIFT);
+ /* convert the memory pages from cached to uncached */
- /*
- * Do magic if no mem on local node! XXX
- */
- if (!page)
- return 0;
- tmp = page_address(page);
+ c_addr = (unsigned long)page_address(page);
+ uc_addr = c_addr - PAGE_OFFSET + __IA64_UNCACHED_OFFSET;
/*
* There's a small race here where it's possible for someone to
@@ -100,76 +99,90 @@ uncached_get_new_chunk(struct gen_pool *poolp)
for (i = 0; i < (IA64_GRANULE_SIZE / PAGE_SIZE); i++)
SetPageUncached(&page[i]);
- flush_tlb_kernel_range(tmp, tmp + IA64_GRANULE_SIZE);
+ flush_tlb_kernel_range(uc_addr, uc_adddr + IA64_GRANULE_SIZE);
status = ia64_pal_prefetch_visibility(PAL_VISIBILITY_PHYSICAL);
-
- dprintk(KERN_INFO "pal_prefetch_visibility() returns %i on cpu %i\n",
- status, raw_smp_processor_id());
-
if (!status) {
status = smp_call_function(uncached_ipi_visibility, NULL, 0, 1);
if (status)
- printk(KERN_WARNING "smp_call_function failed for "
- "uncached_ipi_visibility! (%i)\n", status);
+ goto failed;
}
+ preempt_disable();
+
if (ia64_platform_is("sn2"))
- sn_flush_all_caches((unsigned long)tmp, IA64_GRANULE_SIZE);
+ sn_flush_all_caches(uc_addr, IA64_GRANULE_SIZE);
else
- flush_icache_range((unsigned long)tmp,
- (unsigned long)tmp+IA64_GRANULE_SIZE);
+ flush_icache_range(uc_addr, uc_addr + IA64_GRANULE_SIZE);
+
+ /* flush the just introduced uncached translation from the TLB */
+ local_flush_tlb_all();
+
+ preempt_enable();
ia64_pal_mc_drain();
status = smp_call_function(uncached_ipi_mc_drain, NULL, 0, 1);
if (status)
- printk(KERN_WARNING "smp_call_function failed for "
- "uncached_ipi_mc_drain! (%i)\n", status);
+ goto failed;
- addr = (unsigned long)tmp - PAGE_OFFSET + __IA64_UNCACHED_OFFSET;
+ /*
+ * The chunk of memory pages has been converted to uncached so now we
+ * can add it to the pool.
+ */
+ status = gen_pool_add(pool, uc_addr, IA64_GRANULE_SIZE, nid);
+ if (status)
+ goto failed;
allocated_granules++;
- return addr;
+ return 0;
+
+ /* failed to convert or add the chunk so give it back to the kernel */
+failed:
+ for (i = 0; i < (IA64_GRANULE_SIZE / PAGE_SIZE); i++)
+ ClearPageUncached(&page[i]);
+
+ free_pages(c_addr, IA64_GRANULE_SHIFT-PAGE_SHIFT);
+ return -1;
}
/*
* uncached_alloc_page
*
+ * @starting_nid: node id of node to start with, or -1
+ *
* Allocate 1 uncached page. Allocates on the requested node. If no
* uncached pages are available on the requested node, roundrobin starting
- * with higher nodes.
+ * with the next higher node.
*/
-unsigned long
-uncached_alloc_page(int nid)
+unsigned long uncached_alloc_page(int starting_nid)
{
- unsigned long maddr;
+ unsigned long uc_addr;
+ struct gen_pool *pool;
+ int nid;
- maddr = gen_pool_alloc(uncached_pool[nid], PAGE_SIZE);
+ if (unlikely(starting_nid >= MAX_NUMNODES))
+ return 0;
- dprintk(KERN_DEBUG "uncached_alloc_page returns %lx on node %i\n",
- maddr, nid);
+ if (starting_nid < 0)
+ starting_nid = numa_node_id();
+ nid = starting_nid;
- /*
- * If no memory is availble on our local node, try the
- * remaining nodes in the system.
- */
- if (!maddr) {
- int i;
-
- for (i = MAX_NUMNODES - 1; i >= 0; i--) {
- if (i == nid || !node_online(i))
- continue;
- maddr = gen_pool_alloc(uncached_pool[i], PAGE_SIZE);
- dprintk(KERN_DEBUG "uncached_alloc_page alternate search "
- "returns %lx on node %i\n", maddr, i);
- if (maddr) {
- break;
- }
- }
- }
+ do {
+ if (!node_online(nid))
+ continue;
+ pool = uncached_pool[nid];
+ if (pool == NULL)
+ continue;
+ do {
+ uc_addr = gen_pool_alloc(pool, PAGE_SIZE);
+ if (uc_addr != 0)
+ return uc_addr;
+ } while (uncached_add_chunk(pool, nid) == 0);
+
+ } while ((nid = (nid + 1) % MAX_NUMNODES) != starting_nid);
- return maddr;
+ return 0;
}
EXPORT_SYMBOL(uncached_alloc_page);
@@ -177,21 +190,22 @@ EXPORT_SYMBOL(uncached_alloc_page);
/*
* uncached_free_page
*
+ * @uc_addr: uncached address of page to free
+ *
* Free a single uncached page.
*/
-void
-uncached_free_page(unsigned long maddr)
+void uncached_free_page(unsigned long uc_addr)
{
- int node;
-
- node = paddr_to_nid(maddr - __IA64_UNCACHED_OFFSET);
+ int nid = paddr_to_nid(uc_addr - __IA64_UNCACHED_OFFSET);
+ struct gen_pool *pool = uncached_pool[nid];
- dprintk(KERN_DEBUG "uncached_free_page(%lx) on node %i\n", maddr, node);
+ if (unlikely(pool == NULL))
+ return;
- if ((maddr & (0XFUL << 60)) != __IA64_UNCACHED_OFFSET)
- panic("uncached_free_page invalid address %lx\n", maddr);
+ if ((uc_addr & (0XFUL << 60)) != __IA64_UNCACHED_OFFSET)
+ panic("uncached_free_page invalid address %lx\n", uc_addr);
- gen_pool_free(uncached_pool[node], maddr, PAGE_SIZE);
+ gen_pool_free(pool, uc_addr, PAGE_SIZE);
}
EXPORT_SYMBOL(uncached_free_page);
@@ -199,43 +213,39 @@ EXPORT_SYMBOL(uncached_free_page);
/*
* uncached_build_memmap,
*
+ * @uc_start: uncached starting address of a chunk of uncached memory
+ * @uc_end: uncached ending address of a chunk of uncached memory
+ * @arg: ignored, (NULL argument passed in on call to efi_memmap_walk_uc())
+ *
* Called at boot time to build a map of pages that can be used for
* memory special operations.
*/
-static int __init
-uncached_build_memmap(unsigned long start, unsigned long end, void *arg)
+static int __init uncached_build_memmap(unsigned long uc_start,
+ unsigned long uc_end, void *arg)
{
- long length = end - start;
- int node;
-
- dprintk(KERN_ERR "uncached_build_memmap(%lx %lx)\n", start, end);
+ int nid = paddr_to_nid(uc_start - __IA64_UNCACHED_OFFSET);
+ struct gen_pool *pool = uncached_pool[nid];
+ size_t size = uc_end - uc_start;
touch_softlockup_watchdog();
- memset((char *)start, 0, length);
- node = paddr_to_nid(start - __IA64_UNCACHED_OFFSET);
-
- for (; start < end ; start += PAGE_SIZE) {
- dprintk(KERN_INFO "sticking %lx into the pool!\n", start);
- gen_pool_free(uncached_pool[node], start, PAGE_SIZE);
+ if (pool != NULL) {
+ memset((char *)uc_start, 0, size);
+ (void) gen_pool_add(pool, uc_start, size, nid);
}
-
return 0;
}
-static int __init uncached_init(void) {
- int i;
+static int __init uncached_init(void)
+{
+ int nid;
- for (i = 0; i < MAX_NUMNODES; i++) {
- if (!node_online(i))
- continue;
- uncached_pool[i] = gen_pool_create(0, IA64_GRANULE_SHIFT,
- &uncached_get_new_chunk, i);
+ for_each_online_node(nid) {
+ uncached_pool[nid] = gen_pool_create(PAGE_SHIFT, nid);
}
- efi_memmap_walk_uc(uncached_build_memmap);
-
+ efi_memmap_walk_uc(uncached_build_memmap, NULL);
return 0;
}
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index cafa877..11f0800 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -671,9 +671,11 @@ int add_memory(u64 start, u64 size)
return ret;
}
+EXPORT_SYMBOL_GPL(add_memory);
int remove_memory(u64 start, u64 size)
{
return -EINVAL;
}
+EXPORT_SYMBOL_GPL(remove_memory);
#endif
diff --git a/arch/ia64/mm/ioremap.c b/arch/ia64/mm/ioremap.c
index 643ccc6..07bd02b 100644
--- a/arch/ia64/mm/ioremap.c
+++ b/arch/ia64/mm/ioremap.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/efi.h>
#include <asm/io.h>
+#include <asm/meminit.h>
static inline void __iomem *
__ioremap (unsigned long offset, unsigned long size)
@@ -21,16 +22,29 @@ __ioremap (unsigned long offset, unsigned long size)
void __iomem *
ioremap (unsigned long offset, unsigned long size)
{
- if (efi_mem_attribute_range(offset, size, EFI_MEMORY_WB))
- return phys_to_virt(offset);
+ u64 attr;
+ unsigned long gran_base, gran_size;
- if (efi_mem_attribute_range(offset, size, EFI_MEMORY_UC))
+ /*
+ * For things in kern_memmap, we must use the same attribute
+ * as the rest of the kernel. For more details, see
+ * Documentation/ia64/aliasing.txt.
+ */
+ attr = kern_mem_attribute(offset, size);
+ if (attr & EFI_MEMORY_WB)
+ return phys_to_virt(offset);
+ else if (attr & EFI_MEMORY_UC)
return __ioremap(offset, size);
/*
- * Someday this should check ACPI resources so we
- * can do the right thing for hot-plugged regions.
+ * Some chipsets don't support UC access to memory. If
+ * WB is supported for the whole granule, we prefer that.
*/
+ gran_base = GRANULEROUNDDOWN(offset);
+ gran_size = GRANULEROUNDUP(offset + size) - gran_base;
+ if (efi_mem_attribute(gran_base, gran_size) & EFI_MEMORY_WB)
+ return phys_to_virt(offset);
+
return __ioremap(offset, size);
}
EXPORT_SYMBOL(ioremap);
@@ -38,6 +52,9 @@ EXPORT_SYMBOL(ioremap);
void __iomem *
ioremap_nocache (unsigned long offset, unsigned long size)
{
+ if (kern_mem_attribute(offset, size) & EFI_MEMORY_WB)
+ return 0;
+
return __ioremap(offset, size);
}
EXPORT_SYMBOL(ioremap_nocache);
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index ab829a2..77375a5 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -352,7 +352,7 @@ pci_acpi_scan_root(struct acpi_device *device, int domain, int bus)
pxm = acpi_get_pxm(controller->acpi_handle);
#ifdef CONFIG_NUMA
if (pxm >= 0)
- controller->node = pxm_to_nid_map[pxm];
+ controller->node = pxm_to_node(pxm);
#endif
acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window,
@@ -602,8 +602,6 @@ pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
* Leave vm_pgoff as-is, the PCI space address is the physical
* address on this platform.
*/
- vma->vm_flags |= (VM_SHM | VM_RESERVED | VM_IO);
-
if (write_combine && efi_range_is_wc(vma->vm_start,
vma->vm_end - vma->vm_start))
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
@@ -645,18 +643,30 @@ char *ia64_pci_get_legacy_mem(struct pci_bus *bus)
int
pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma)
{
+ unsigned long size = vma->vm_end - vma->vm_start;
+ pgprot_t prot;
char *addr;
+ /*
+ * Avoid attribute aliasing. See Documentation/ia64/aliasing.txt
+ * for more details.
+ */
+ if (!valid_mmap_phys_addr_range(vma->vm_pgoff << PAGE_SHIFT, size))
+ return -EINVAL;
+ prot = phys_mem_access_prot(NULL, vma->vm_pgoff, size,
+ vma->vm_page_prot);
+ if (pgprot_val(prot) != pgprot_val(pgprot_noncached(vma->vm_page_prot)))
+ return -EINVAL;
+
addr = pci_get_legacy_mem(bus);
if (IS_ERR(addr))
return PTR_ERR(addr);
vma->vm_pgoff += (unsigned long)addr >> PAGE_SHIFT;
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- vma->vm_flags |= (VM_SHM | VM_RESERVED | VM_IO);
+ vma->vm_page_prot = prot;
if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
- vma->vm_end - vma->vm_start, vma->vm_page_prot))
+ size, vma->vm_page_prot))
return -EAGAIN;
return 0;
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
index 5101ac4..dc09a6a 100644
--- a/arch/ia64/sn/kernel/io_init.c
+++ b/arch/ia64/sn/kernel/io_init.c
@@ -58,7 +58,7 @@ static int max_pcibus_number = 255; /* Default highest pci bus number */
*/
static dma_addr_t
-sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size)
+sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size, int type)
{
return 0;
}
@@ -457,13 +457,6 @@ void sn_pci_fixup_slot(struct pci_dev *dev)
pcidev_info->pdi_sn_irq_info = NULL;
kfree(sn_irq_info);
}
-
- /*
- * MSI currently not supported on altix. Remove this when
- * the MSI abstraction patches are integrated into the kernel
- * (sometime after 2.6.16 releases)
- */
- dev->no_msi = 1;
}
/*
diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c
index c265e02..dc8e2b6 100644
--- a/arch/ia64/sn/kernel/irq.c
+++ b/arch/ia64/sn/kernel/irq.c
@@ -26,11 +26,11 @@ static void unregister_intr_pda(struct sn_irq_info *sn_irq_info);
int sn_force_interrupt_flag = 1;
extern int sn_ioif_inited;
-static struct list_head **sn_irq_lh;
+struct list_head **sn_irq_lh;
static spinlock_t sn_irq_info_lock = SPIN_LOCK_UNLOCKED; /* non-IRQ lock */
-static inline u64 sn_intr_alloc(nasid_t local_nasid, int local_widget,
- u64 sn_irq_info,
+u64 sn_intr_alloc(nasid_t local_nasid, int local_widget,
+ struct sn_irq_info *sn_irq_info,
int req_irq, nasid_t req_nasid,
int req_slice)
{
@@ -40,12 +40,13 @@ static inline u64 sn_intr_alloc(nasid_t local_nasid, int local_widget,
SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT,
(u64) SAL_INTR_ALLOC, (u64) local_nasid,
- (u64) local_widget, (u64) sn_irq_info, (u64) req_irq,
+ (u64) local_widget, __pa(sn_irq_info), (u64) req_irq,
(u64) req_nasid, (u64) req_slice);
+
return ret_stuff.status;
}
-static inline void sn_intr_free(nasid_t local_nasid, int local_widget,
+void sn_intr_free(nasid_t local_nasid, int local_widget,
struct sn_irq_info *sn_irq_info)
{
struct ia64_sal_retval ret_stuff;
@@ -112,73 +113,91 @@ static void sn_end_irq(unsigned int irq)
static void sn_irq_info_free(struct rcu_head *head);
-static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
+struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info,
+ nasid_t nasid, int slice)
{
- struct sn_irq_info *sn_irq_info, *sn_irq_info_safe;
- int cpuid, cpuphys;
+ int vector;
+ int cpuphys;
+ int64_t bridge;
+ int local_widget, status;
+ nasid_t local_nasid;
+ struct sn_irq_info *new_irq_info;
+ struct sn_pcibus_provider *pci_provider;
- cpuid = first_cpu(mask);
- cpuphys = cpu_physical_id(cpuid);
+ new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
+ if (new_irq_info == NULL)
+ return NULL;
- list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe,
- sn_irq_lh[irq], list) {
- u64 bridge;
- int local_widget, status;
- nasid_t local_nasid;
- struct sn_irq_info *new_irq_info;
- struct sn_pcibus_provider *pci_provider;
-
- new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
- if (new_irq_info == NULL)
- break;
- memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info));
-
- bridge = (u64) new_irq_info->irq_bridge;
- if (!bridge) {
- kfree(new_irq_info);
- break; /* irq is not a device interrupt */
- }
+ memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info));
+
+ bridge = (u64) new_irq_info->irq_bridge;
+ if (!bridge) {
+ kfree(new_irq_info);
+ return NULL; /* irq is not a device interrupt */
+ }
- local_nasid = NASID_GET(bridge);
+ local_nasid = NASID_GET(bridge);
- if (local_nasid & 1)
- local_widget = TIO_SWIN_WIDGETNUM(bridge);
- else
- local_widget = SWIN_WIDGETNUM(bridge);
+ if (local_nasid & 1)
+ local_widget = TIO_SWIN_WIDGETNUM(bridge);
+ else
+ local_widget = SWIN_WIDGETNUM(bridge);
- /* Free the old PROM new_irq_info structure */
- sn_intr_free(local_nasid, local_widget, new_irq_info);
- /* Update kernels new_irq_info with new target info */
- unregister_intr_pda(new_irq_info);
+ vector = sn_irq_info->irq_irq;
+ /* Free the old PROM new_irq_info structure */
+ sn_intr_free(local_nasid, local_widget, new_irq_info);
+ /* Update kernels new_irq_info with new target info */
+ unregister_intr_pda(new_irq_info);
- /* allocate a new PROM new_irq_info struct */
- status = sn_intr_alloc(local_nasid, local_widget,
- __pa(new_irq_info), irq,
- cpuid_to_nasid(cpuid),
- cpuid_to_slice(cpuid));
+ /* allocate a new PROM new_irq_info struct */
+ status = sn_intr_alloc(local_nasid, local_widget,
+ new_irq_info, vector,
+ nasid, slice);
- /* SAL call failed */
- if (status) {
- kfree(new_irq_info);
- break;
- }
+ /* SAL call failed */
+ if (status) {
+ kfree(new_irq_info);
+ return NULL;
+ }
- new_irq_info->irq_cpuid = cpuid;
- register_intr_pda(new_irq_info);
+ cpuphys = nasid_slice_to_cpuid(nasid, slice);
+ new_irq_info->irq_cpuid = cpuphys;
+ register_intr_pda(new_irq_info);
- pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type];
- if (pci_provider && pci_provider->target_interrupt)
- (pci_provider->target_interrupt)(new_irq_info);
+ pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type];
- spin_lock(&sn_irq_info_lock);
- list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
- spin_unlock(&sn_irq_info_lock);
- call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
+ /*
+ * If this represents a line interrupt, target it. If it's
+ * an msi (irq_int_bit < 0), it's already targeted.
+ */
+ if (new_irq_info->irq_int_bit >= 0 &&
+ pci_provider && pci_provider->target_interrupt)
+ (pci_provider->target_interrupt)(new_irq_info);
+
+ spin_lock(&sn_irq_info_lock);
+ list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
+ spin_unlock(&sn_irq_info_lock);
+ call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
#ifdef CONFIG_SMP
- set_irq_affinity_info((irq & 0xff), cpuphys, 0);
+ set_irq_affinity_info((vector & 0xff), cpuphys, 0);
#endif
- }
+
+ return new_irq_info;
+}
+
+static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
+{
+ struct sn_irq_info *sn_irq_info, *sn_irq_info_safe;
+ nasid_t nasid;
+ int slice;
+
+ nasid = cpuid_to_nasid(first_cpu(mask));
+ slice = cpuid_to_slice(first_cpu(mask));
+
+ list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe,
+ sn_irq_lh[irq], list)
+ (void)sn_retarget_vector(sn_irq_info, nasid, slice);
}
struct hw_interrupt_type irq_type_sn = {
@@ -202,6 +221,9 @@ void sn_irq_init(void)
int i;
irq_desc_t *base_desc = irq_desc;
+ ia64_first_device_vector = IA64_SN2_FIRST_DEVICE_VECTOR;
+ ia64_last_device_vector = IA64_SN2_LAST_DEVICE_VECTOR;
+
for (i = 0; i < NR_IRQS; i++) {
if (base_desc[i].handler == &no_irq_type) {
base_desc[i].handler = &irq_type_sn;
@@ -285,6 +307,7 @@ void sn_irq_fixup(struct pci_dev *pci_dev, struct sn_irq_info *sn_irq_info)
/* link it into the sn_irq[irq] list */
spin_lock(&sn_irq_info_lock);
list_add_rcu(&sn_irq_info->list, sn_irq_lh[sn_irq_info->irq_irq]);
+ reserve_irq_vector(sn_irq_info->irq_irq);
spin_unlock(&sn_irq_info_lock);
register_intr_pda(sn_irq_info);
@@ -310,8 +333,11 @@ void sn_irq_unfixup(struct pci_dev *pci_dev)
spin_lock(&sn_irq_info_lock);
list_del_rcu(&sn_irq_info->list);
spin_unlock(&sn_irq_info_lock);
+ if (list_empty(sn_irq_lh[sn_irq_info->irq_irq]))
+ free_irq_vector(sn_irq_info->irq_irq);
call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
pci_dev_put(pci_dev);
+
}
static inline void
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
index 30988df..93577ab 100644
--- a/arch/ia64/sn/kernel/setup.c
+++ b/arch/ia64/sn/kernel/setup.c
@@ -139,7 +139,7 @@ static int __init pxm_to_nasid(int pxm)
int i;
int nid;
- nid = pxm_to_nid_map[pxm];
+ nid = pxm_to_node(pxm);
for (i = 0; i < num_node_memblks; i++) {
if (node_memblk[i].nid == nid) {
return NASID_GET(node_memblk[i].start_paddr);
@@ -704,7 +704,7 @@ void __init build_cnode_tables(void)
* cnode == node for all C & M bricks.
*/
for_each_online_node(node) {
- nasid = pxm_to_nasid(nid_to_pxm_map[node]);
+ nasid = pxm_to_nasid(node_to_pxm(node));
sn_cnodeid_to_nasid[node] = nasid;
physical_node_map[nasid] = node;
}
diff --git a/arch/ia64/sn/kernel/sn2/cache.c b/arch/ia64/sn/kernel/sn2/cache.c
index bc3cfa1..2862cb3 100644
--- a/arch/ia64/sn/kernel/sn2/cache.c
+++ b/arch/ia64/sn/kernel/sn2/cache.c
@@ -3,11 +3,12 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2001-2003, 2006 Silicon Graphics, Inc. All rights reserved.
*
*/
#include <linux/module.h>
#include <asm/pgalloc.h>
+#include <asm/sn/arch.h>
/**
* sn_flush_all_caches - flush a range of address from all caches (incl. L4)
@@ -17,18 +18,24 @@
* Flush a range of addresses from all caches including L4.
* All addresses fully or partially contained within
* @flush_addr to @flush_addr + @bytes are flushed
- * from the all caches.
+ * from all caches.
*/
void
sn_flush_all_caches(long flush_addr, long bytes)
{
- flush_icache_range(flush_addr, flush_addr+bytes);
+ unsigned long addr = flush_addr;
+
+ /* SHub1 requires a cached address */
+ if (is_shub1() && (addr & RGN_BITS) == RGN_BASE(RGN_UNCACHED))
+ addr = (addr - RGN_BASE(RGN_UNCACHED)) + RGN_BASE(RGN_KERNEL);
+
+ flush_icache_range(addr, addr + bytes);
/*
* The last call may have returned before the caches
* were actually flushed, so we call it again to make
* sure.
*/
- flush_icache_range(flush_addr, flush_addr+bytes);
+ flush_icache_range(addr, addr + bytes);
mb();
}
EXPORT_SYMBOL(sn_flush_all_caches);
diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
index 739c948..9a8a293 100644
--- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c
+++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
@@ -51,6 +51,8 @@ static nasid_t sn_hwperf_master_nasid = INVALID_NASID;
static int sn_hwperf_init(void);
static DECLARE_MUTEX(sn_hwperf_init_mutex);
+#define cnode_possible(n) ((n) < num_cnodes)
+
static int sn_hwperf_enum_objects(int *nobj, struct sn_hwperf_object_info **ret)
{
int e;
@@ -127,14 +129,14 @@ static int sn_hwperf_geoid_to_cnode(char *location)
}
}
- return node_possible(cnode) ? cnode : -1;
+ return cnode_possible(cnode) ? cnode : -1;
}
static int sn_hwperf_obj_to_cnode(struct sn_hwperf_object_info * obj)
{
if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj))
BUG();
- if (!obj->sn_hwp_this_part)
+ if (SN_HWPERF_FOREIGN(obj))
return -1;
return sn_hwperf_geoid_to_cnode(obj->location);
}
@@ -199,12 +201,12 @@ static void print_pci_topology(struct seq_file *s)
static inline int sn_hwperf_has_cpus(cnodeid_t node)
{
- return node_online(node) && nr_cpus_node(node);
+ return node < MAX_NUMNODES && node_online(node) && nr_cpus_node(node);
}
static inline int sn_hwperf_has_mem(cnodeid_t node)
{
- return node_online(node) && NODE_DATA(node)->node_present_pages;
+ return node < MAX_NUMNODES && node_online(node) && NODE_DATA(node)->node_present_pages;
}
static struct sn_hwperf_object_info *
@@ -237,7 +239,7 @@ static int sn_hwperf_get_nearest_node_objdata(struct sn_hwperf_object_info *objb
int found_mem = 0;
int found_cpu = 0;
- if (!node_possible(node))
+ if (!cnode_possible(node))
return -EINVAL;
if (sn_hwperf_has_cpus(node)) {
@@ -442,7 +444,7 @@ static int sn_topology_show(struct seq_file *s, void *d)
seq_printf(s, "%s %d %s %s asic %s", slabname, ordinal, obj->location,
obj->sn_hwp_this_part ? "local" : "shared", obj->name);
- if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj))
+ if (ordinal < 0 || (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj)))
seq_putc(s, '\n');
else {
cnodeid_t near_mem = -1;
@@ -468,22 +470,24 @@ static int sn_topology_show(struct seq_file *s, void *d)
/*
* CPUs on this node, if any
*/
- cpumask = node_to_cpumask(ordinal);
- for_each_online_cpu(i) {
- if (cpu_isset(i, cpumask)) {
- slice = 'a' + cpuid_to_slice(i);
- c = cpu_data(i);
- seq_printf(s, "cpu %d %s%c local"
- " freq %luMHz, arch ia64",
- i, obj->location, slice,
- c->proc_freq / 1000000);
- for_each_online_cpu(j) {
- seq_printf(s, j ? ":%d" : ", dist %d",
- node_distance(
- cpu_to_node(i),
- cpu_to_node(j)));
+ if (!SN_HWPERF_IS_IONODE(obj)) {
+ cpumask = node_to_cpumask(ordinal);
+ for_each_online_cpu(i) {
+ if (cpu_isset(i, cpumask)) {
+ slice = 'a' + cpuid_to_slice(i);
+ c = cpu_data(i);
+ seq_printf(s, "cpu %d %s%c local"
+ " freq %luMHz, arch ia64",
+ i, obj->location, slice,
+ c->proc_freq / 1000000);
+ for_each_online_cpu(j) {
+ seq_printf(s, j ? ":%d" : ", dist %d",
+ node_distance(
+ cpu_to_node(i),
+ cpu_to_node(j)));
+ }
+ seq_putc(s, '\n');
}
- seq_putc(s, '\n');
}
}
}
@@ -523,7 +527,7 @@ static int sn_topology_show(struct seq_file *s, void *d)
if (obj->sn_hwp_this_part && p->sn_hwp_this_part)
/* both ends local to this partition */
seq_puts(s, " local");
- else if (!obj->sn_hwp_this_part && !p->sn_hwp_this_part)
+ else if (SN_HWPERF_FOREIGN(p))
/* both ends of the link in foreign partiton */
seq_puts(s, " foreign");
else
@@ -776,7 +780,7 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg)
case SN_HWPERF_GET_NODE_NASID:
if (a.sz != sizeof(u64) ||
- (node = a.arg) < 0 || !node_possible(node)) {
+ (node = a.arg) < 0 || !cnode_possible(node)) {
r = -EINVAL;
goto error;
}
diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c
index b4b84c2..7a291a2 100644
--- a/arch/ia64/sn/pci/pci_dma.c
+++ b/arch/ia64/sn/pci/pci_dma.c
@@ -11,7 +11,7 @@
#include <linux/module.h>
#include <asm/dma.h>
-#include <asm/sn/pcibr_provider.h>
+#include <asm/sn/intr.h>
#include <asm/sn/pcibus_provider_defs.h>
#include <asm/sn/pcidev.h>
#include <asm/sn/sn_sal.h>
@@ -113,7 +113,8 @@ void *sn_dma_alloc_coherent(struct device *dev, size_t size,
* resources.
*/
- *dma_handle = provider->dma_map_consistent(pdev, phys_addr, size);
+ *dma_handle = provider->dma_map_consistent(pdev, phys_addr, size,
+ SN_DMA_ADDR_PHYS);
if (!*dma_handle) {
printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__);
free_pages((unsigned long)cpuaddr, get_order(size));
@@ -176,7 +177,7 @@ dma_addr_t sn_dma_map_single(struct device *dev, void *cpu_addr, size_t size,
BUG_ON(dev->bus != &pci_bus_type);
phys_addr = __pa(cpu_addr);
- dma_addr = provider->dma_map(pdev, phys_addr, size);
+ dma_addr = provider->dma_map(pdev, phys_addr, size, SN_DMA_ADDR_PHYS);
if (!dma_addr) {
printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__);
return 0;
@@ -260,7 +261,8 @@ int sn_dma_map_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
for (i = 0; i < nhwentries; i++, sg++) {
phys_addr = SG_ENT_PHYS_ADDRESS(sg);
sg->dma_address = provider->dma_map(pdev,
- phys_addr, sg->length);
+ phys_addr, sg->length,
+ SN_DMA_ADDR_PHYS);
if (!sg->dma_address) {
printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__);
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_dma.c b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
index 9f86bb6..a86c7b9 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_dma.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
@@ -41,7 +41,7 @@ extern int sn_ioif_inited;
static dma_addr_t
pcibr_dmamap_ate32(struct pcidev_info *info,
- u64 paddr, size_t req_size, u64 flags)
+ u64 paddr, size_t req_size, u64 flags, int dma_flags)
{
struct pcidev_info *pcidev_info = info->pdi_host_pcidev_info;
@@ -81,9 +81,12 @@ pcibr_dmamap_ate32(struct pcidev_info *info,
if (IS_PCIX(pcibus_info))
ate_flags &= ~(PCI32_ATE_PREF);
- xio_addr =
- IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
- PHYS_TO_TIODMA(paddr);
+ if (SN_DMA_ADDRTYPE(dma_flags == SN_DMA_ADDR_PHYS))
+ xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
+ PHYS_TO_TIODMA(paddr);
+ else
+ xio_addr = paddr;
+
offset = IOPGOFF(xio_addr);
ate = ate_flags | (xio_addr - offset);
@@ -91,6 +94,13 @@ pcibr_dmamap_ate32(struct pcidev_info *info,
if (IS_PIC_SOFT(pcibus_info)) {
ate |= (pcibus_info->pbi_hub_xid << PIC_ATE_TARGETID_SHFT);
}
+
+ /*
+ * If we're mapping for MSI, set the MSI bit in the ATE
+ */
+ if (dma_flags & SN_DMA_MSI)
+ ate |= PCI32_ATE_MSI;
+
ate_write(pcibus_info, ate_index, ate_count, ate);
/*
@@ -105,20 +115,27 @@ pcibr_dmamap_ate32(struct pcidev_info *info,
if (pcibus_info->pbi_devreg[internal_device] & PCIBR_DEV_SWAP_DIR)
ATE_SWAP_ON(pci_addr);
+
return pci_addr;
}
static dma_addr_t
pcibr_dmatrans_direct64(struct pcidev_info * info, u64 paddr,
- u64 dma_attributes)
+ u64 dma_attributes, int dma_flags)
{
struct pcibus_info *pcibus_info = (struct pcibus_info *)
((info->pdi_host_pcidev_info)->pdi_pcibus_info);
u64 pci_addr;
/* Translate to Crosstalk View of Physical Address */
- pci_addr = (IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
- PHYS_TO_TIODMA(paddr)) | dma_attributes;
+ if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS)
+ pci_addr = IS_PIC_SOFT(pcibus_info) ?
+ PHYS_TO_DMA(paddr) :
+ PHYS_TO_TIODMA(paddr) | dma_attributes;
+ else
+ pci_addr = IS_PIC_SOFT(pcibus_info) ?
+ paddr :
+ paddr | dma_attributes;
/* Handle Bus mode */
if (IS_PCIX(pcibus_info))
@@ -130,7 +147,9 @@ pcibr_dmatrans_direct64(struct pcidev_info * info, u64 paddr,
((u64) pcibus_info->
pbi_hub_xid << PIC_PCI64_ATTR_TARG_SHFT);
} else
- pci_addr |= TIOCP_PCI64_CMDTYPE_MEM;
+ pci_addr |= (dma_flags & SN_DMA_MSI) ?
+ TIOCP_PCI64_CMDTYPE_MSI :
+ TIOCP_PCI64_CMDTYPE_MEM;
/* If PCI mode, func zero uses VCHAN0, every other func uses VCHAN1 */
if (!IS_PCIX(pcibus_info) && PCI_FUNC(info->pdi_linux_pcidev->devfn))
@@ -141,7 +160,7 @@ pcibr_dmatrans_direct64(struct pcidev_info * info, u64 paddr,
static dma_addr_t
pcibr_dmatrans_direct32(struct pcidev_info * info,
- u64 paddr, size_t req_size, u64 flags)
+ u64 paddr, size_t req_size, u64 flags, int dma_flags)
{
struct pcidev_info *pcidev_info = info->pdi_host_pcidev_info;
struct pcibus_info *pcibus_info = (struct pcibus_info *)pcidev_info->
@@ -156,8 +175,14 @@ pcibr_dmatrans_direct32(struct pcidev_info * info,
return 0;
}
- xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
- PHYS_TO_TIODMA(paddr);
+ if (dma_flags & SN_DMA_MSI)
+ return 0;
+
+ if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS)
+ xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
+ PHYS_TO_TIODMA(paddr);
+ else
+ xio_addr = paddr;
xio_base = pcibus_info->pbi_dir_xbase;
offset = xio_addr - xio_base;
@@ -327,7 +352,7 @@ void sn_dma_flush(u64 addr)
*/
dma_addr_t
-pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size)
+pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size, int dma_flags)
{
dma_addr_t dma_handle;
struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev);
@@ -344,11 +369,11 @@ pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size)
*/
dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr,
- PCI64_ATTR_PREF);
+ PCI64_ATTR_PREF, dma_flags);
} else {
/* Handle 32-63 bit cards via direct mapping */
dma_handle = pcibr_dmatrans_direct32(pcidev_info, phys_addr,
- size, 0);
+ size, 0, dma_flags);
if (!dma_handle) {
/*
* It is a 32 bit card and we cannot do direct mapping,
@@ -356,7 +381,8 @@ pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size)
*/
dma_handle = pcibr_dmamap_ate32(pcidev_info, phys_addr,
- size, PCI32_ATE_PREF);
+ size, PCI32_ATE_PREF,
+ dma_flags);
}
}
@@ -365,18 +391,18 @@ pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size)
dma_addr_t
pcibr_dma_map_consistent(struct pci_dev * hwdev, unsigned long phys_addr,
- size_t size)
+ size_t size, int dma_flags)
{
dma_addr_t dma_handle;
struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev);
if (hwdev->dev.coherent_dma_mask == ~0UL) {
dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr,
- PCI64_ATTR_BAR);
+ PCI64_ATTR_BAR, dma_flags);
} else {
dma_handle = (dma_addr_t) pcibr_dmamap_ate32(pcidev_info,
phys_addr, size,
- PCI32_ATE_BAR);
+ PCI32_ATE_BAR, dma_flags);
}
return dma_handle;
diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c
index be01769..20de727 100644
--- a/arch/ia64/sn/pci/tioca_provider.c
+++ b/arch/ia64/sn/pci/tioca_provider.c
@@ -515,11 +515,17 @@ tioca_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir)
* use the GART mapped mode.
*/
static u64
-tioca_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count)
+tioca_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, int dma_flags)
{
u64 mapaddr;
/*
+ * Not supported for now ...
+ */
+ if (dma_flags & SN_DMA_MSI)
+ return 0;
+
+ /*
* If card is 64 or 48 bit addresable, use a direct mapping. 32
* bit direct is so restrictive w.r.t. where the memory resides that
* we don't use it even though CA has some support.
diff --git a/arch/ia64/sn/pci/tioce_provider.c b/arch/ia64/sn/pci/tioce_provider.c
index 8332956..2d79485 100644
--- a/arch/ia64/sn/pci/tioce_provider.c
+++ b/arch/ia64/sn/pci/tioce_provider.c
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2003-2005 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (C) 2003-2006 Silicon Graphics, Inc. All Rights Reserved.
*/
#include <linux/types.h>
@@ -170,7 +170,8 @@ tioce_mmr_war_post(struct tioce_kernel *kern, void *mmr_addr)
(ATE_PAGE((start)+(len)-1, pagesize) - ATE_PAGE(start, pagesize) + 1)
#define ATE_VALID(ate) ((ate) & (1UL << 63))
-#define ATE_MAKE(addr, ps) (((addr) & ~ATE_PAGEMASK(ps)) | (1UL << 63))
+#define ATE_MAKE(addr, ps, msi) \
+ (((addr) & ~ATE_PAGEMASK(ps)) | (1UL << 63) | ((msi)?(1UL << 62):0))
/*
* Flavors of ate-based mapping supported by tioce_alloc_map()
@@ -196,15 +197,17 @@ tioce_mmr_war_post(struct tioce_kernel *kern, void *mmr_addr)
*
* 63 - must be 1 to indicate d64 mode to CE hardware
* 62 - barrier bit ... controlled with tioce_dma_barrier()
- * 61 - 0 since this is not an MSI transaction
+ * 61 - msi bit ... specified through dma_flags
* 60:54 - reserved, MBZ
*/
static u64
-tioce_dma_d64(unsigned long ct_addr)
+tioce_dma_d64(unsigned long ct_addr, int dma_flags)
{
u64 bus_addr;
bus_addr = ct_addr | (1UL << 63);
+ if (dma_flags & SN_DMA_MSI)
+ bus_addr |= (1UL << 61);
return bus_addr;
}
@@ -261,7 +264,7 @@ pcidev_to_tioce(struct pci_dev *pdev, struct tioce **base,
*/
static u64
tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port,
- u64 ct_addr, int len)
+ u64 ct_addr, int len, int dma_flags)
{
int i;
int j;
@@ -270,6 +273,7 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port,
int entries;
int nates;
u64 pagesize;
+ int msi_capable, msi_wanted;
u64 *ate_shadow;
u64 *ate_reg;
u64 addr;
@@ -291,6 +295,7 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port,
ate_reg = ce_mmr->ce_ure_ate3240;
pagesize = ce_kern->ce_ate3240_pagesize;
bus_base = TIOCE_M32_MIN;
+ msi_capable = 1;
break;
case TIOCE_ATE_M40:
first = 0;
@@ -299,6 +304,7 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port,
ate_reg = ce_mmr->ce_ure_ate40;
pagesize = MB(64);
bus_base = TIOCE_M40_MIN;
+ msi_capable = 0;
break;
case TIOCE_ATE_M40S:
/*
@@ -311,11 +317,16 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port,
ate_reg = ce_mmr->ce_ure_ate3240;
pagesize = GB(16);
bus_base = TIOCE_M40S_MIN;
+ msi_capable = 0;
break;
default:
return 0;
}
+ msi_wanted = dma_flags & SN_DMA_MSI;
+ if (msi_wanted && !msi_capable)
+ return 0;
+
nates = ATE_NPAGES(ct_addr, len, pagesize);
if (nates > entries)
return 0;
@@ -344,7 +355,7 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port,
for (j = 0; j < nates; j++) {
u64 ate;
- ate = ATE_MAKE(addr, pagesize);
+ ate = ATE_MAKE(addr, pagesize, msi_wanted);
ate_shadow[i + j] = ate;
tioce_mmr_storei(ce_kern, &ate_reg[i + j], ate);
addr += pagesize;
@@ -371,7 +382,7 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port,
* Map @paddr into 32-bit bus space of the CE associated with @pcidev_info.
*/
static u64
-tioce_dma_d32(struct pci_dev *pdev, u64 ct_addr)
+tioce_dma_d32(struct pci_dev *pdev, u64 ct_addr, int dma_flags)
{
int dma_ok;
int port;
@@ -381,6 +392,9 @@ tioce_dma_d32(struct pci_dev *pdev, u64 ct_addr)
u64 ct_lower;
dma_addr_t bus_addr;
+ if (dma_flags & SN_DMA_MSI)
+ return 0;
+
ct_upper = ct_addr & ~0x3fffffffUL;
ct_lower = ct_addr & 0x3fffffffUL;
@@ -507,7 +521,7 @@ tioce_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir)
*/
static u64
tioce_do_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count,
- int barrier)
+ int barrier, int dma_flags)
{
unsigned long flags;
u64 ct_addr;
@@ -523,15 +537,18 @@ tioce_do_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count,
if (dma_mask < 0x7fffffffUL)
return 0;
- ct_addr = PHYS_TO_TIODMA(paddr);
+ if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS)
+ ct_addr = PHYS_TO_TIODMA(paddr);
+ else
+ ct_addr = paddr;
/*
* If the device can generate 64 bit addresses, create a D64 map.
- * Since this should never fail, bypass the rest of the checks.
*/
if (dma_mask == ~0UL) {
- mapaddr = tioce_dma_d64(ct_addr);
- goto dma_map_done;
+ mapaddr = tioce_dma_d64(ct_addr, dma_flags);
+ if (mapaddr)
+ goto dma_map_done;
}
pcidev_to_tioce(pdev, NULL, &ce_kern, &port);
@@ -574,18 +591,22 @@ tioce_do_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count,
if (byte_count > MB(64)) {
mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40S,
- port, ct_addr, byte_count);
+ port, ct_addr, byte_count,
+ dma_flags);
if (!mapaddr)
mapaddr =
tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1,
- ct_addr, byte_count);
+ ct_addr, byte_count,
+ dma_flags);
} else {
mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1,
- ct_addr, byte_count);
+ ct_addr, byte_count,
+ dma_flags);
if (!mapaddr)
mapaddr =
tioce_alloc_map(ce_kern, TIOCE_ATE_M40S,
- port, ct_addr, byte_count);
+ port, ct_addr, byte_count,
+ dma_flags);
}
}
@@ -593,7 +614,7 @@ tioce_do_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count,
* 32-bit direct is the next mode to try
*/
if (!mapaddr && dma_mask >= 0xffffffffUL)
- mapaddr = tioce_dma_d32(pdev, ct_addr);
+ mapaddr = tioce_dma_d32(pdev, ct_addr, dma_flags);
/*
* Last resort, try 32-bit ATE-based map.
@@ -601,7 +622,7 @@ tioce_do_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count,
if (!mapaddr)
mapaddr =
tioce_alloc_map(ce_kern, TIOCE_ATE_M32, -1, ct_addr,
- byte_count);
+ byte_count, dma_flags);
spin_unlock_irqrestore(&ce_kern->ce_lock, flags);
@@ -622,9 +643,9 @@ dma_map_done:
* in the address.
*/
static u64
-tioce_dma(struct pci_dev *pdev, u64 paddr, size_t byte_count)
+tioce_dma(struct pci_dev *pdev, u64 paddr, size_t byte_count, int dma_flags)
{
- return tioce_do_dma_map(pdev, paddr, byte_count, 0);
+ return tioce_do_dma_map(pdev, paddr, byte_count, 0, dma_flags);
}
/**
@@ -636,9 +657,9 @@ tioce_dma(struct pci_dev *pdev, u64 paddr, size_t byte_count)
* Simply call tioce_do_dma_map() to create a map with the barrier bit set
* in the address.
*/ static u64
-tioce_dma_consistent(struct pci_dev *pdev, u64 paddr, size_t byte_count)
+tioce_dma_consistent(struct pci_dev *pdev, u64 paddr, size_t byte_count, int dma_flags)
{
- return tioce_do_dma_map(pdev, paddr, byte_count, 1);
+ return tioce_do_dma_map(pdev, paddr, byte_count, 1, dma_flags);
}
/**
@@ -696,7 +717,7 @@ tioce_reserve_m32(struct tioce_kernel *ce_kern, u64 base, u64 limit)
while (ate_index <= last_ate) {
u64 ate;
- ate = ATE_MAKE(0xdeadbeef, ps);
+ ate = ATE_MAKE(0xdeadbeef, ps, 0);
ce_kern->ce_ate3240_shadow[ate_index] = ate;
tioce_mmr_storei(ce_kern, &ce_mmr->ce_ure_ate3240[ate_index],
ate);
@@ -1002,7 +1023,7 @@ tioce_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_adm_int_status_alias, ~0ULL);
tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_adm_error_summary_alias,
~0ULL);
- tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_dre_comp_err_addr, ~0ULL);
+ tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_dre_comp_err_addr, 0ULL);
if (request_irq(SGI_PCIASIC_ERROR,
tioce_error_intr_handler,
diff --git a/arch/m68k/amiga/amiga_ksyms.c b/arch/m68k/amiga/amiga_ksyms.c
index b7bd84c..8f2e058 100644
--- a/arch/m68k/amiga/amiga_ksyms.c
+++ b/arch/m68k/amiga/amiga_ksyms.c
@@ -23,8 +23,6 @@ EXPORT_SYMBOL(amiga_chip_avail);
EXPORT_SYMBOL(amiga_chip_size);
EXPORT_SYMBOL(amiga_audio_period);
EXPORT_SYMBOL(amiga_audio_min_period);
-EXPORT_SYMBOL(amiga_do_irq);
-EXPORT_SYMBOL(amiga_do_irq_list);
#ifdef CONFIG_AMIGA_PCMCIA
EXPORT_SYMBOL(pcmcia_reset);
diff --git a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c
index b0aa61b..f9403f4 100644
--- a/arch/m68k/amiga/amiints.c
+++ b/arch/m68k/amiga/amiints.c
@@ -35,61 +35,30 @@
* /Jes
*/
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/errno.h>
-#include <linux/seq_file.h>
-#include <asm/system.h>
#include <asm/irq.h>
#include <asm/traps.h>
#include <asm/amigahw.h>
#include <asm/amigaints.h>
#include <asm/amipcmcia.h>
-extern int cia_request_irq(struct ciabase *base,int irq,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
- unsigned long flags, const char *devname, void *dev_id);
-extern void cia_free_irq(struct ciabase *base, unsigned int irq, void *dev_id);
-extern void cia_init_IRQ(struct ciabase *base);
-extern int cia_get_irq_list(struct ciabase *base, struct seq_file *p);
-
-/* irq node variables for amiga interrupt sources */
-static irq_node_t *ami_irq_list[AMI_STD_IRQS];
-
-static unsigned short amiga_intena_vals[AMI_STD_IRQS] = {
- [IRQ_AMIGA_VERTB] = IF_VERTB,
- [IRQ_AMIGA_COPPER] = IF_COPER,
- [IRQ_AMIGA_AUD0] = IF_AUD0,
- [IRQ_AMIGA_AUD1] = IF_AUD1,
- [IRQ_AMIGA_AUD2] = IF_AUD2,
- [IRQ_AMIGA_AUD3] = IF_AUD3,
- [IRQ_AMIGA_BLIT] = IF_BLIT,
- [IRQ_AMIGA_DSKSYN] = IF_DSKSYN,
- [IRQ_AMIGA_DSKBLK] = IF_DSKBLK,
- [IRQ_AMIGA_RBF] = IF_RBF,
- [IRQ_AMIGA_TBE] = IF_TBE,
- [IRQ_AMIGA_SOFT] = IF_SOFT,
- [IRQ_AMIGA_PORTS] = IF_PORTS,
- [IRQ_AMIGA_EXTER] = IF_EXTER
-};
-static const unsigned char ami_servers[AMI_STD_IRQS] = {
- [IRQ_AMIGA_VERTB] = 1,
- [IRQ_AMIGA_PORTS] = 1,
- [IRQ_AMIGA_EXTER] = 1
+static void amiga_enable_irq(unsigned int irq);
+static void amiga_disable_irq(unsigned int irq);
+static irqreturn_t ami_int1(int irq, void *dev_id, struct pt_regs *fp);
+static irqreturn_t ami_int3(int irq, void *dev_id, struct pt_regs *fp);
+static irqreturn_t ami_int4(int irq, void *dev_id, struct pt_regs *fp);
+static irqreturn_t ami_int5(int irq, void *dev_id, struct pt_regs *fp);
+
+static struct irq_controller amiga_irq_controller = {
+ .name = "amiga",
+ .lock = SPIN_LOCK_UNLOCKED,
+ .enable = amiga_enable_irq,
+ .disable = amiga_disable_irq,
};
-static short ami_ablecount[AMI_IRQS];
-
-static irqreturn_t ami_badint(int irq, void *dev_id, struct pt_regs *fp)
-{
- num_spurious += 1;
- return IRQ_NONE;
-}
-
/*
* void amiga_init_IRQ(void)
*
@@ -103,23 +72,12 @@ static irqreturn_t ami_badint(int irq, void *dev_id, struct pt_regs *fp)
void __init amiga_init_IRQ(void)
{
- int i;
+ request_irq(IRQ_AUTO_1, ami_int1, 0, "int1", NULL);
+ request_irq(IRQ_AUTO_3, ami_int3, 0, "int3", NULL);
+ request_irq(IRQ_AUTO_4, ami_int4, 0, "int4", NULL);
+ request_irq(IRQ_AUTO_5, ami_int5, 0, "int5", NULL);
- /* initialize handlers */
- for (i = 0; i < AMI_STD_IRQS; i++) {
- if (ami_servers[i]) {
- ami_irq_list[i] = NULL;
- } else {
- ami_irq_list[i] = new_irq_node();
- ami_irq_list[i]->handler = ami_badint;
- ami_irq_list[i]->flags = 0;
- ami_irq_list[i]->dev_id = NULL;
- ami_irq_list[i]->devname = NULL;
- ami_irq_list[i]->next = NULL;
- }
- }
- for (i = 0; i < AMI_IRQS; i++)
- ami_ablecount[i] = 0;
+ m68k_setup_irq_controller(&amiga_irq_controller, IRQ_USER, AMI_STD_IRQS);
/* turn off PCMCIA interrupts */
if (AMIGAHW_PRESENT(PCMCIA))
@@ -134,249 +92,21 @@ void __init amiga_init_IRQ(void)
cia_init_IRQ(&ciab_base);
}
-static inline int amiga_insert_irq(irq_node_t **list, irq_node_t *node)
-{
- unsigned long flags;
- irq_node_t *cur;
-
- if (!node->dev_id)
- printk("%s: Warning: dev_id of %s is zero\n",
- __FUNCTION__, node->devname);
-
- local_irq_save(flags);
-
- cur = *list;
-
- if (node->flags & SA_INTERRUPT) {
- if (node->flags & SA_SHIRQ)
- return -EBUSY;
- /*
- * There should never be more than one
- */
- while (cur && cur->flags & SA_INTERRUPT) {
- list = &cur->next;
- cur = cur->next;
- }
- } else {
- while (cur) {
- list = &cur->next;
- cur = cur->next;
- }
- }
-
- node->next = cur;
- *list = node;
-
- local_irq_restore(flags);
- return 0;
-}
-
-static inline void amiga_delete_irq(irq_node_t **list, void *dev_id)
-{
- unsigned long flags;
- irq_node_t *node;
-
- local_irq_save(flags);
-
- for (node = *list; node; list = &node->next, node = *list) {
- if (node->dev_id == dev_id) {
- *list = node->next;
- /* Mark it as free. */
- node->handler = NULL;
- local_irq_restore(flags);
- return;
- }
- }
- local_irq_restore(flags);
- printk ("%s: tried to remove invalid irq\n", __FUNCTION__);
-}
-
-/*
- * amiga_request_irq : add an interrupt service routine for a particular
- * machine specific interrupt source.
- * If the addition was successful, it returns 0.
- */
-
-int amiga_request_irq(unsigned int irq,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
- unsigned long flags, const char *devname, void *dev_id)
-{
- irq_node_t *node;
- int error = 0;
-
- if (irq >= AMI_IRQS) {
- printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__,
- irq, devname);
- return -ENXIO;
- }
-
- if (irq >= IRQ_AMIGA_AUTO)
- return cpu_request_irq(irq - IRQ_AMIGA_AUTO, handler,
- flags, devname, dev_id);
-
- if (irq >= IRQ_AMIGA_CIAB)
- return cia_request_irq(&ciab_base, irq - IRQ_AMIGA_CIAB,
- handler, flags, devname, dev_id);
-
- if (irq >= IRQ_AMIGA_CIAA)
- return cia_request_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA,
- handler, flags, devname, dev_id);
-
- /*
- * IRQ_AMIGA_PORTS & IRQ_AMIGA_EXTER defaults to shared,
- * we could add a check here for the SA_SHIRQ flag but all drivers
- * should be aware of sharing anyway.
- */
- if (ami_servers[irq]) {
- if (!(node = new_irq_node()))
- return -ENOMEM;
- node->handler = handler;
- node->flags = flags;
- node->dev_id = dev_id;
- node->devname = devname;
- node->next = NULL;
- error = amiga_insert_irq(&ami_irq_list[irq], node);
- } else {
- ami_irq_list[irq]->handler = handler;
- ami_irq_list[irq]->flags = flags;
- ami_irq_list[irq]->dev_id = dev_id;
- ami_irq_list[irq]->devname = devname;
- }
-
- /* enable the interrupt */
- if (irq < IRQ_AMIGA_PORTS && !ami_ablecount[irq])
- amiga_custom.intena = IF_SETCLR | amiga_intena_vals[irq];
-
- return error;
-}
-
-void amiga_free_irq(unsigned int irq, void *dev_id)
-{
- if (irq >= AMI_IRQS) {
- printk ("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
- return;
- }
-
- if (irq >= IRQ_AMIGA_AUTO)
- cpu_free_irq(irq - IRQ_AMIGA_AUTO, dev_id);
-
- if (irq >= IRQ_AMIGA_CIAB) {
- cia_free_irq(&ciab_base, irq - IRQ_AMIGA_CIAB, dev_id);
- return;
- }
-
- if (irq >= IRQ_AMIGA_CIAA) {
- cia_free_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA, dev_id);
- return;
- }
-
- if (ami_servers[irq]) {
- amiga_delete_irq(&ami_irq_list[irq], dev_id);
- /* if server list empty, disable the interrupt */
- if (!ami_irq_list[irq] && irq < IRQ_AMIGA_PORTS)
- amiga_custom.intena = amiga_intena_vals[irq];
- } else {
- if (ami_irq_list[irq]->dev_id != dev_id)
- printk("%s: removing probably wrong IRQ %d from %s\n",
- __FUNCTION__, irq, ami_irq_list[irq]->devname);
- ami_irq_list[irq]->handler = ami_badint;
- ami_irq_list[irq]->flags = 0;
- ami_irq_list[irq]->dev_id = NULL;
- ami_irq_list[irq]->devname = NULL;
- amiga_custom.intena = amiga_intena_vals[irq];
- }
-}
-
/*
* Enable/disable a particular machine specific interrupt source.
* Note that this may affect other interrupts in case of a shared interrupt.
* This function should only be called for a _very_ short time to change some
* internal data, that may not be changed by the interrupt at the same time.
- * ami_(enable|disable)_irq calls may also be nested.
*/
-void amiga_enable_irq(unsigned int irq)
-{
- if (irq >= AMI_IRQS) {
- printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
- return;
- }
-
- if (--ami_ablecount[irq])
- return;
-
- /* No action for auto-vector interrupts */
- if (irq >= IRQ_AMIGA_AUTO){
- printk("%s: Trying to enable auto-vector IRQ %i\n",
- __FUNCTION__, irq - IRQ_AMIGA_AUTO);
- return;
- }
-
- if (irq >= IRQ_AMIGA_CIAB) {
- cia_set_irq(&ciab_base, (1 << (irq - IRQ_AMIGA_CIAB)));
- cia_able_irq(&ciab_base, CIA_ICR_SETCLR |
- (1 << (irq - IRQ_AMIGA_CIAB)));
- return;
- }
-
- if (irq >= IRQ_AMIGA_CIAA) {
- cia_set_irq(&ciaa_base, (1 << (irq - IRQ_AMIGA_CIAA)));
- cia_able_irq(&ciaa_base, CIA_ICR_SETCLR |
- (1 << (irq - IRQ_AMIGA_CIAA)));
- return;
- }
-
- /* enable the interrupt */
- amiga_custom.intena = IF_SETCLR | amiga_intena_vals[irq];
-}
-
-void amiga_disable_irq(unsigned int irq)
-{
- if (irq >= AMI_IRQS) {
- printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
- return;
- }
-
- if (ami_ablecount[irq]++)
- return;
-
- /* No action for auto-vector interrupts */
- if (irq >= IRQ_AMIGA_AUTO) {
- printk("%s: Trying to disable auto-vector IRQ %i\n",
- __FUNCTION__, irq - IRQ_AMIGA_AUTO);
- return;
- }
-
- if (irq >= IRQ_AMIGA_CIAB) {
- cia_able_irq(&ciab_base, 1 << (irq - IRQ_AMIGA_CIAB));
- return;
- }
-
- if (irq >= IRQ_AMIGA_CIAA) {
- cia_able_irq(&ciaa_base, 1 << (irq - IRQ_AMIGA_CIAA));
- return;
- }
-
- /* disable the interrupt */
- amiga_custom.intena = amiga_intena_vals[irq];
-}
-
-inline void amiga_do_irq(int irq, struct pt_regs *fp)
+static void amiga_enable_irq(unsigned int irq)
{
- kstat_cpu(0).irqs[SYS_IRQS + irq]++;
- ami_irq_list[irq]->handler(irq, ami_irq_list[irq]->dev_id, fp);
+ amiga_custom.intena = IF_SETCLR | (1 << (irq - IRQ_USER));
}
-void amiga_do_irq_list(int irq, struct pt_regs *fp)
+static void amiga_disable_irq(unsigned int irq)
{
- irq_node_t *node;
-
- kstat_cpu(0).irqs[SYS_IRQS + irq]++;
-
- amiga_custom.intreq = amiga_intena_vals[irq];
-
- for (node = ami_irq_list[irq]; node; node = node->next)
- node->handler(irq, node->dev_id, fp);
+ amiga_custom.intena = 1 << (irq - IRQ_USER);
}
/*
@@ -390,19 +120,19 @@ static irqreturn_t ami_int1(int irq, void *dev_id, struct pt_regs *fp)
/* if serial transmit buffer empty, interrupt */
if (ints & IF_TBE) {
amiga_custom.intreq = IF_TBE;
- amiga_do_irq(IRQ_AMIGA_TBE, fp);
+ m68k_handle_int(IRQ_AMIGA_TBE, fp);
}
/* if floppy disk transfer complete, interrupt */
if (ints & IF_DSKBLK) {
amiga_custom.intreq = IF_DSKBLK;
- amiga_do_irq(IRQ_AMIGA_DSKBLK, fp);
+ m68k_handle_int(IRQ_AMIGA_DSKBLK, fp);
}
/* if software interrupt set, interrupt */
if (ints & IF_SOFT) {
amiga_custom.intreq = IF_SOFT;
- amiga_do_irq(IRQ_AMIGA_SOFT, fp);
+ m68k_handle_int(IRQ_AMIGA_SOFT, fp);
}
return IRQ_HANDLED;
}
@@ -414,18 +144,20 @@ static irqreturn_t ami_int3(int irq, void *dev_id, struct pt_regs *fp)
/* if a blitter interrupt */
if (ints & IF_BLIT) {
amiga_custom.intreq = IF_BLIT;
- amiga_do_irq(IRQ_AMIGA_BLIT, fp);
+ m68k_handle_int(IRQ_AMIGA_BLIT, fp);
}
/* if a copper interrupt */
if (ints & IF_COPER) {
amiga_custom.intreq = IF_COPER;
- amiga_do_irq(IRQ_AMIGA_COPPER, fp);
+ m68k_handle_int(IRQ_AMIGA_COPPER, fp);
}
/* if a vertical blank interrupt */
- if (ints & IF_VERTB)
- amiga_do_irq_list(IRQ_AMIGA_VERTB, fp);
+ if (ints & IF_VERTB) {
+ amiga_custom.intreq = IF_VERTB;
+ m68k_handle_int(IRQ_AMIGA_VERTB, fp);
+ }
return IRQ_HANDLED;
}
@@ -436,25 +168,25 @@ static irqreturn_t ami_int4(int irq, void *dev_id, struct pt_regs *fp)
/* if audio 0 interrupt */
if (ints & IF_AUD0) {
amiga_custom.intreq = IF_AUD0;
- amiga_do_irq(IRQ_AMIGA_AUD0, fp);
+ m68k_handle_int(IRQ_AMIGA_AUD0, fp);
}
/* if audio 1 interrupt */
if (ints & IF_AUD1) {
amiga_custom.intreq = IF_AUD1;
- amiga_do_irq(IRQ_AMIGA_AUD1, fp);
+ m68k_handle_int(IRQ_AMIGA_AUD1, fp);
}
/* if audio 2 interrupt */
if (ints & IF_AUD2) {
amiga_custom.intreq = IF_AUD2;
- amiga_do_irq(IRQ_AMIGA_AUD2, fp);
+ m68k_handle_int(IRQ_AMIGA_AUD2, fp);
}
/* if audio 3 interrupt */
if (ints & IF_AUD3) {
amiga_custom.intreq = IF_AUD3;
- amiga_do_irq(IRQ_AMIGA_AUD3, fp);
+ m68k_handle_int(IRQ_AMIGA_AUD3, fp);
}
return IRQ_HANDLED;
}
@@ -466,55 +198,13 @@ static irqreturn_t ami_int5(int irq, void *dev_id, struct pt_regs *fp)
/* if serial receive buffer full interrupt */
if (ints & IF_RBF) {
/* acknowledge of IF_RBF must be done by the serial interrupt */
- amiga_do_irq(IRQ_AMIGA_RBF, fp);
+ m68k_handle_int(IRQ_AMIGA_RBF, fp);
}
/* if a disk sync interrupt */
if (ints & IF_DSKSYN) {
amiga_custom.intreq = IF_DSKSYN;
- amiga_do_irq(IRQ_AMIGA_DSKSYN, fp);
+ m68k_handle_int(IRQ_AMIGA_DSKSYN, fp);
}
return IRQ_HANDLED;
}
-
-static irqreturn_t ami_int7(int irq, void *dev_id, struct pt_regs *fp)
-{
- panic ("level 7 interrupt received\n");
-}
-
-irqreturn_t (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
- [0] = ami_badint,
- [1] = ami_int1,
- [2] = ami_badint,
- [3] = ami_int3,
- [4] = ami_int4,
- [5] = ami_int5,
- [6] = ami_badint,
- [7] = ami_int7
-};
-
-int show_amiga_interrupts(struct seq_file *p, void *v)
-{
- int i;
- irq_node_t *node;
-
- for (i = 0; i < AMI_STD_IRQS; i++) {
- if (!(node = ami_irq_list[i]))
- continue;
- seq_printf(p, "ami %2d: %10u ", i,
- kstat_cpu(0).irqs[SYS_IRQS + i]);
- do {
- if (node->flags & SA_INTERRUPT)
- seq_puts(p, "F ");
- else
- seq_puts(p, " ");
- seq_printf(p, "%s\n", node->devname);
- if ((node = node->next))
- seq_puts(p, " ");
- } while (node);
- }
-
- cia_get_irq_list(&ciaa_base, p);
- cia_get_irq_list(&ciab_base, p);
- return 0;
-}
diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c
index 9476eb9..0956e45 100644
--- a/arch/m68k/amiga/cia.c
+++ b/arch/m68k/amiga/cia.c
@@ -29,21 +29,18 @@ struct ciabase {
unsigned short int_mask;
int handler_irq, cia_irq, server_irq;
char *name;
- irq_handler_t irq_list[CIA_IRQS];
} ciaa_base = {
.cia = &ciaa,
.int_mask = IF_PORTS,
- .handler_irq = IRQ_AMIGA_AUTO_2,
+ .handler_irq = IRQ_AMIGA_PORTS,
.cia_irq = IRQ_AMIGA_CIAA,
- .server_irq = IRQ_AMIGA_PORTS,
- .name = "CIAA handler"
+ .name = "CIAA"
}, ciab_base = {
.cia = &ciab,
.int_mask = IF_EXTER,
- .handler_irq = IRQ_AMIGA_AUTO_6,
+ .handler_irq = IRQ_AMIGA_EXTER,
.cia_irq = IRQ_AMIGA_CIAB,
- .server_irq = IRQ_AMIGA_EXTER,
- .name = "CIAB handler"
+ .name = "CIAB"
};
/*
@@ -66,13 +63,11 @@ unsigned char cia_set_irq(struct ciabase *base, unsigned char mask)
/*
* Enable or disable CIA interrupts, return old interrupt mask,
- * interrupts will only be enabled if a handler exists
*/
unsigned char cia_able_irq(struct ciabase *base, unsigned char mask)
{
- unsigned char old, tmp;
- int i;
+ unsigned char old;
old = base->icr_mask;
base->icr_data |= base->cia->icr;
@@ -82,99 +77,104 @@ unsigned char cia_able_irq(struct ciabase *base, unsigned char mask)
else
base->icr_mask &= ~mask;
base->icr_mask &= CIA_ICR_ALL;
- for (i = 0, tmp = 1; i < CIA_IRQS; i++, tmp <<= 1) {
- if ((tmp & base->icr_mask) && !base->irq_list[i].handler) {
- base->icr_mask &= ~tmp;
- base->cia->icr = tmp;
- }
- }
if (base->icr_data & base->icr_mask)
amiga_custom.intreq = IF_SETCLR | base->int_mask;
return old;
}
-int cia_request_irq(struct ciabase *base, unsigned int irq,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
- unsigned long flags, const char *devname, void *dev_id)
-{
- unsigned char mask;
-
- base->irq_list[irq].handler = handler;
- base->irq_list[irq].flags = flags;
- base->irq_list[irq].dev_id = dev_id;
- base->irq_list[irq].devname = devname;
-
- /* enable the interrupt */
- mask = 1 << irq;
- cia_set_irq(base, mask);
- cia_able_irq(base, CIA_ICR_SETCLR | mask);
- return 0;
-}
-
-void cia_free_irq(struct ciabase *base, unsigned int irq, void *dev_id)
-{
- if (base->irq_list[irq].dev_id != dev_id)
- printk("%s: removing probably wrong IRQ %i from %s\n",
- __FUNCTION__, base->cia_irq + irq,
- base->irq_list[irq].devname);
-
- base->irq_list[irq].handler = NULL;
- base->irq_list[irq].flags = 0;
-
- cia_able_irq(base, 1 << irq);
-}
-
static irqreturn_t cia_handler(int irq, void *dev_id, struct pt_regs *fp)
{
struct ciabase *base = (struct ciabase *)dev_id;
- int mach_irq, i;
+ int mach_irq;
unsigned char ints;
mach_irq = base->cia_irq;
- irq = SYS_IRQS + mach_irq;
ints = cia_set_irq(base, CIA_ICR_ALL);
amiga_custom.intreq = base->int_mask;
- for (i = 0; i < CIA_IRQS; i++, irq++, mach_irq++) {
- if (ints & 1) {
- kstat_cpu(0).irqs[irq]++;
- base->irq_list[i].handler(mach_irq, base->irq_list[i].dev_id, fp);
- }
- ints >>= 1;
+ for (; ints; mach_irq++, ints >>= 1) {
+ if (ints & 1)
+ m68k_handle_int(mach_irq, fp);
}
- amiga_do_irq_list(base->server_irq, fp);
return IRQ_HANDLED;
}
-void __init cia_init_IRQ(struct ciabase *base)
+static void cia_enable_irq(unsigned int irq)
{
- int i;
+ unsigned char mask;
- /* init isr handlers */
- for (i = 0; i < CIA_IRQS; i++) {
- base->irq_list[i].handler = NULL;
- base->irq_list[i].flags = 0;
+ if (irq >= IRQ_AMIGA_CIAB) {
+ mask = 1 << (irq - IRQ_AMIGA_CIAB);
+ cia_set_irq(&ciab_base, mask);
+ cia_able_irq(&ciab_base, CIA_ICR_SETCLR | mask);
+ } else {
+ mask = 1 << (irq - IRQ_AMIGA_CIAA);
+ cia_set_irq(&ciaa_base, mask);
+ cia_able_irq(&ciaa_base, CIA_ICR_SETCLR | mask);
}
+}
- /* clear any pending interrupt and turn off all interrupts */
- cia_set_irq(base, CIA_ICR_ALL);
- cia_able_irq(base, CIA_ICR_ALL);
+static void cia_disable_irq(unsigned int irq)
+{
+ if (irq >= IRQ_AMIGA_CIAB)
+ cia_able_irq(&ciab_base, 1 << (irq - IRQ_AMIGA_CIAB));
+ else
+ cia_able_irq(&ciaa_base, 1 << (irq - IRQ_AMIGA_CIAA));
+}
- /* install CIA handler */
- request_irq(base->handler_irq, cia_handler, 0, base->name, base);
+static struct irq_controller cia_irq_controller = {
+ .name = "cia",
+ .lock = SPIN_LOCK_UNLOCKED,
+ .enable = cia_enable_irq,
+ .disable = cia_disable_irq,
+};
+
+/*
+ * Override auto irq 2 & 6 and use them as general chain
+ * for external interrupts, we link the CIA interrupt sources
+ * into this chain.
+ */
- amiga_custom.intena = IF_SETCLR | base->int_mask;
+static void auto_enable_irq(unsigned int irq)
+{
+ switch (irq) {
+ case IRQ_AUTO_2:
+ amiga_custom.intena = IF_SETCLR | IF_PORTS;
+ break;
+ case IRQ_AUTO_6:
+ amiga_custom.intena = IF_SETCLR | IF_EXTER;
+ break;
+ }
}
-int cia_get_irq_list(struct ciabase *base, struct seq_file *p)
+static void auto_disable_irq(unsigned int irq)
{
- int i, j;
-
- j = base->cia_irq;
- for (i = 0; i < CIA_IRQS; i++) {
- seq_printf(p, "cia %2d: %10d ", j + i,
- kstat_cpu(0).irqs[SYS_IRQS + j + i]);
- seq_puts(p, " ");
- seq_printf(p, "%s\n", base->irq_list[i].devname);
+ switch (irq) {
+ case IRQ_AUTO_2:
+ amiga_custom.intena = IF_PORTS;
+ break;
+ case IRQ_AUTO_6:
+ amiga_custom.intena = IF_EXTER;
+ break;
}
- return 0;
+}
+
+static struct irq_controller auto_irq_controller = {
+ .name = "auto",
+ .lock = SPIN_LOCK_UNLOCKED,
+ .enable = auto_enable_irq,
+ .disable = auto_disable_irq,
+};
+
+void __init cia_init_IRQ(struct ciabase *base)
+{
+ m68k_setup_irq_controller(&cia_irq_controller, base->cia_irq, CIA_IRQS);
+
+ /* clear any pending interrupt and turn off all interrupts */
+ cia_set_irq(base, CIA_ICR_ALL);
+ cia_able_irq(base, CIA_ICR_ALL);
+
+ /* override auto int and install CIA handler */
+ m68k_setup_irq_controller(&auto_irq_controller, base->handler_irq, 1);
+ m68k_irq_startup(base->handler_irq);
+ request_irq(base->handler_irq, cia_handler, SA_SHIRQ, base->name, base);
}
diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
index 12e3706..b5b8a41 100644
--- a/arch/m68k/amiga/config.c
+++ b/arch/m68k/amiga/config.c
@@ -87,17 +87,8 @@ extern char m68k_debug_device[];
static void amiga_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
/* amiga specific irq functions */
extern void amiga_init_IRQ (void);
-extern irqreturn_t (*amiga_default_handler[]) (int, void *, struct pt_regs *);
-extern int amiga_request_irq (unsigned int irq,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
- unsigned long flags, const char *devname,
- void *dev_id);
-extern void amiga_free_irq (unsigned int irq, void *dev_id);
-extern void amiga_enable_irq (unsigned int);
-extern void amiga_disable_irq (unsigned int);
static void amiga_get_model(char *model);
static int amiga_get_hardware_list(char *buffer);
-extern int show_amiga_interrupts (struct seq_file *, void *);
/* amiga specific timer functions */
static unsigned long amiga_gettimeoffset (void);
static int a3000_hwclk (int, struct rtc_time *);
@@ -392,14 +383,8 @@ void __init config_amiga(void)
mach_sched_init = amiga_sched_init;
mach_init_IRQ = amiga_init_IRQ;
- mach_default_handler = &amiga_default_handler;
- mach_request_irq = amiga_request_irq;
- mach_free_irq = amiga_free_irq;
- enable_irq = amiga_enable_irq;
- disable_irq = amiga_disable_irq;
mach_get_model = amiga_get_model;
mach_get_hardware_list = amiga_get_hardware_list;
- mach_get_irq_list = show_amiga_interrupts;
mach_gettimeoffset = amiga_gettimeoffset;
if (AMIGAHW_PRESENT(A3000_CLK)){
mach_hwclk = a3000_hwclk;
diff --git a/arch/m68k/apollo/Makefile b/arch/m68k/apollo/Makefile
index 39264f3..76a0579 100644
--- a/arch/m68k/apollo/Makefile
+++ b/arch/m68k/apollo/Makefile
@@ -2,4 +2,4 @@
# Makefile for Linux arch/m68k/amiga source directory
#
-obj-y := config.o dn_ints.o dma.o
+obj-y := config.o dn_ints.o
diff --git a/arch/m68k/apollo/config.c b/arch/m68k/apollo/config.c
index d401962..99c7097 100644
--- a/arch/m68k/apollo/config.c
+++ b/arch/m68k/apollo/config.c
@@ -28,11 +28,6 @@ u_long apollo_model;
extern void dn_sched_init(irqreturn_t (*handler)(int,void *,struct pt_regs *));
extern void dn_init_IRQ(void);
-extern int dn_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
-extern void dn_free_irq(unsigned int irq, void *dev_id);
-extern void dn_enable_irq(unsigned int);
-extern void dn_disable_irq(unsigned int);
-extern int show_dn_interrupts(struct seq_file *, void *);
extern unsigned long dn_gettimeoffset(void);
extern int dn_dummy_hwclk(int, struct rtc_time *);
extern int dn_dummy_set_clock_mmss(unsigned long);
@@ -40,13 +35,11 @@ extern void dn_dummy_reset(void);
extern void dn_dummy_waitbut(void);
extern struct fb_info *dn_fb_init(long *);
extern void dn_dummy_debug_init(void);
-extern void dn_dummy_video_setup(char *,int *);
extern irqreturn_t dn_process_int(int irq, struct pt_regs *fp);
#ifdef CONFIG_HEARTBEAT
static void dn_heartbeat(int on);
#endif
static irqreturn_t dn_timer_int(int irq,void *, struct pt_regs *);
-static irqreturn_t (*sched_timer_handler)(int, void *, struct pt_regs *)=NULL;
static void dn_get_model(char *model);
static const char *apollo_models[] = {
[APOLLO_DN3000-APOLLO_DN3000] = "DN3000 (Otter)",
@@ -164,17 +157,10 @@ void config_apollo(void) {
mach_sched_init=dn_sched_init; /* */
mach_init_IRQ=dn_init_IRQ;
- mach_default_handler=NULL;
- mach_request_irq = dn_request_irq;
- mach_free_irq = dn_free_irq;
- enable_irq = dn_enable_irq;
- disable_irq = dn_disable_irq;
- mach_get_irq_list = show_dn_interrupts;
mach_gettimeoffset = dn_gettimeoffset;
mach_max_dma_address = 0xffffffff;
mach_hwclk = dn_dummy_hwclk; /* */
mach_set_clock_mmss = dn_dummy_set_clock_mmss; /* */
- mach_process_int = dn_process_int;
mach_reset = dn_dummy_reset; /* */
#ifdef CONFIG_HEARTBEAT
mach_heartbeat = dn_heartbeat;
@@ -189,11 +175,13 @@ void config_apollo(void) {
}
-irqreturn_t dn_timer_int(int irq, void *dev_id, struct pt_regs *fp) {
+irqreturn_t dn_timer_int(int irq, void *dev_id, struct pt_regs *fp)
+{
+ irqreturn_t (*timer_handler)(int, void *, struct pt_regs *) = dev_id;
volatile unsigned char x;
- sched_timer_handler(irq,dev_id,fp);
+ timer_handler(irq, dev_id, fp);
x=*(volatile unsigned char *)(timer+3);
x=*(volatile unsigned char *)(timer+5);
@@ -217,9 +205,7 @@ void dn_sched_init(irqreturn_t (*timer_routine)(int, void *, struct pt_regs *))
printk("*(0x10803) %02x\n",*(volatile unsigned char *)(timer+0x3));
#endif
- sched_timer_handler=timer_routine;
- request_irq(0,dn_timer_int,0,NULL,NULL);
-
+ request_irq(IRQ_APOLLO, dn_timer_int, 0, "time", timer_routine);
}
unsigned long dn_gettimeoffset(void) {
diff --git a/arch/m68k/apollo/dn_ints.c b/arch/m68k/apollo/dn_ints.c
index a312593..9fe0780 100644
--- a/arch/m68k/apollo/dn_ints.c
+++ b/arch/m68k/apollo/dn_ints.c
@@ -1,125 +1,44 @@
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/kernel_stat.h>
-#include <linux/timer.h>
+#include <linux/interrupt.h>
-#include <asm/system.h>
#include <asm/irq.h>
#include <asm/traps.h>
-#include <asm/page.h>
-#include <asm/machdep.h>
#include <asm/apollohw.h>
-#include <asm/errno.h>
-static irq_handler_t dn_irqs[16];
-
-irqreturn_t dn_process_int(int irq, struct pt_regs *fp)
+void dn_process_int(unsigned int irq, struct pt_regs *fp)
{
- irqreturn_t res = IRQ_NONE;
-
- if(dn_irqs[irq-160].handler) {
- res = dn_irqs[irq-160].handler(irq,dn_irqs[irq-160].dev_id,fp);
- } else {
- printk("spurious irq %d occurred\n",irq);
- }
-
- *(volatile unsigned char *)(pica)=0x20;
- *(volatile unsigned char *)(picb)=0x20;
-
- return res;
-}
-
-void dn_init_IRQ(void) {
-
- int i;
-
- for(i=0;i<16;i++) {
- dn_irqs[i].handler=NULL;
- dn_irqs[i].flags=IRQ_FLG_STD;
- dn_irqs[i].dev_id=NULL;
- dn_irqs[i].devname=NULL;
- }
-
-}
-
-int dn_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id) {
-
- if((irq<0) || (irq>15)) {
- printk("Trying to request invalid IRQ\n");
- return -ENXIO;
- }
-
- if(!dn_irqs[irq].handler) {
- dn_irqs[irq].handler=handler;
- dn_irqs[irq].flags=IRQ_FLG_STD;
- dn_irqs[irq].dev_id=dev_id;
- dn_irqs[irq].devname=devname;
- if(irq<8)
- *(volatile unsigned char *)(pica+1)&=~(1<<irq);
- else
- *(volatile unsigned char *)(picb+1)&=~(1<<(irq-8));
-
- return 0;
- }
- else {
- printk("Trying to request already assigned irq %d\n",irq);
- return -ENXIO;
- }
-
-}
-
-void dn_free_irq(unsigned int irq, void *dev_id) {
-
- if((irq<0) || (irq>15)) {
- printk("Trying to free invalid IRQ\n");
- return ;
- }
-
- if(irq<8)
- *(volatile unsigned char *)(pica+1)|=(1<<irq);
- else
- *(volatile unsigned char *)(picb+1)|=(1<<(irq-8));
-
- dn_irqs[irq].handler=NULL;
- dn_irqs[irq].flags=IRQ_FLG_STD;
- dn_irqs[irq].dev_id=NULL;
- dn_irqs[irq].devname=NULL;
-
- return ;
-
-}
-
-void dn_enable_irq(unsigned int irq) {
-
- printk("dn enable irq\n");
-
-}
-
-void dn_disable_irq(unsigned int irq) {
-
- printk("dn disable irq\n");
+ m68k_handle_int(irq, fp);
+ *(volatile unsigned char *)(pica)=0x20;
+ *(volatile unsigned char *)(picb)=0x20;
}
-int show_dn_interrupts(struct seq_file *p, void *v) {
-
- printk("dn get irq list\n");
-
- return 0;
-
+int apollo_irq_startup(unsigned int irq)
+{
+ if (irq < 8)
+ *(volatile unsigned char *)(pica+1) &= ~(1 << irq);
+ else
+ *(volatile unsigned char *)(picb+1) &= ~(1 << (irq - 8));
+ return 0;
}
-struct fb_info *dn_dummy_fb_init(long *mem_start) {
-
- printk("fb init\n");
-
- return NULL;
-
+void apollo_irq_shutdown(unsigned int irq)
+{
+ if (irq < 8)
+ *(volatile unsigned char *)(pica+1) |= (1 << irq);
+ else
+ *(volatile unsigned char *)(picb+1) |= (1 << (irq - 8));
}
-void dn_dummy_video_setup(char *options,int *ints) {
+static struct irq_controller apollo_irq_controller = {
+ .name = "apollo",
+ .lock = SPIN_LOCK_UNLOCKED,
+ .startup = apollo_irq_startup,
+ .shutdown = apollo_irq_shutdown,
+};
- printk("no video yet\n");
+void dn_init_IRQ(void)
+{
+ m68k_setup_user_interrupt(VEC_USER + 96, 16, dn_process_int);
+ m68k_setup_irq_controller(&apollo_irq_controller, IRQ_APOLLO, 16);
}
diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c
index 076f479..ece13cb 100644
--- a/arch/m68k/atari/ataints.c
+++ b/arch/m68k/atari/ataints.c
@@ -104,6 +104,7 @@
* the sr copy in the frame.
*/
+#if 0
#define NUM_INT_SOURCES (8 + NUM_ATARI_SOURCES)
@@ -133,13 +134,6 @@ static struct irqhandler irq_handler[NUM_INT_SOURCES];
*/
static struct irqparam irq_param[NUM_INT_SOURCES];
-/*
- * Bitmap for free interrupt vector numbers
- * (new vectors starting from 0x70 can be allocated by
- * atari_register_vme_int())
- */
-static int free_vme_vec_bitmap;
-
/* check for valid int number (complex, sigh...) */
#define IS_VALID_INTNO(n) \
((n) > 0 && \
@@ -301,6 +295,14 @@ __asm__ (__ALIGN_STR "\n"
);
for (;;);
}
+#endif
+
+/*
+ * Bitmap for free interrupt vector numbers
+ * (new vectors starting from 0x70 can be allocated by
+ * atari_register_vme_int())
+ */
+static int free_vme_vec_bitmap;
/* GK:
* HBL IRQ handler for Falcon. Nobody needs it :-)
@@ -313,13 +315,34 @@ __ALIGN_STR "\n\t"
"orw #0x200,%sp@\n\t" /* set saved ipl to 2 */
"rte");
-/* Defined in entry.S; only increments 'num_spurious' */
-asmlinkage void bad_interrupt(void);
-
-extern void atari_microwire_cmd( int cmd );
+extern void atari_microwire_cmd(int cmd);
extern int atari_SCC_reset_done;
+static int atari_startup_irq(unsigned int irq)
+{
+ m68k_irq_startup(irq);
+ atari_turnon_irq(irq);
+ atari_enable_irq(irq);
+ return 0;
+}
+
+static void atari_shutdown_irq(unsigned int irq)
+{
+ atari_disable_irq(irq);
+ atari_turnoff_irq(irq);
+ m68k_irq_shutdown(irq);
+}
+
+static struct irq_controller atari_irq_controller = {
+ .name = "atari",
+ .lock = SPIN_LOCK_UNLOCKED,
+ .startup = atari_startup_irq,
+ .shutdown = atari_shutdown_irq,
+ .enable = atari_enable_irq,
+ .disable = atari_disable_irq,
+};
+
/*
* void atari_init_IRQ (void)
*
@@ -333,12 +356,8 @@ extern int atari_SCC_reset_done;
void __init atari_init_IRQ(void)
{
- int i;
-
- /* initialize the vector table */
- for (i = 0; i < NUM_INT_SOURCES; ++i) {
- vectors[IRQ_SOURCE_TO_VECTOR(i)] = bad_interrupt;
- }
+ m68k_setup_user_interrupt(VEC_USER, 192, NULL);
+ m68k_setup_irq_controller(&atari_irq_controller, 1, NUM_ATARI_SOURCES - 1);
/* Initialize the MFP(s) */
@@ -378,8 +397,7 @@ void __init atari_init_IRQ(void)
* enabled in VME mask
*/
tt_scu.vme_mask = 0x60; /* enable MFP and SCC ints */
- }
- else {
+ } else {
/* If no SCU and no Hades, the HSYNC interrupt needs to be
* disabled this way. (Else _inthandler in kernel/sys_call.S
* gets overruns)
@@ -404,184 +422,6 @@ void __init atari_init_IRQ(void)
}
-static irqreturn_t atari_call_irq_list( int irq, void *dev_id, struct pt_regs *fp )
-{
- irq_node_t *node;
-
- for (node = (irq_node_t *)dev_id; node; node = node->next)
- node->handler(irq, node->dev_id, fp);
- return IRQ_HANDLED;
-}
-
-
-/*
- * atari_request_irq : add an interrupt service routine for a particular
- * machine specific interrupt source.
- * If the addition was successful, it returns 0.
- */
-
-int atari_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
- unsigned long flags, const char *devname, void *dev_id)
-{
- int vector;
- unsigned long oflags = flags;
-
- /*
- * The following is a hack to make some PCI card drivers work,
- * which set the SA_SHIRQ flag.
- */
-
- flags &= ~SA_SHIRQ;
-
- if (flags == SA_INTERRUPT) {
- printk ("%s: SA_INTERRUPT changed to IRQ_TYPE_SLOW for %s\n",
- __FUNCTION__, devname);
- flags = IRQ_TYPE_SLOW;
- }
- if (flags < IRQ_TYPE_SLOW || flags > IRQ_TYPE_PRIO) {
- printk ("%s: Bad irq type 0x%lx <0x%lx> requested from %s\n",
- __FUNCTION__, flags, oflags, devname);
- return -EINVAL;
- }
- if (!IS_VALID_INTNO(irq)) {
- printk ("%s: Unknown irq %d requested from %s\n",
- __FUNCTION__, irq, devname);
- return -ENXIO;
- }
- vector = IRQ_SOURCE_TO_VECTOR(irq);
-
- /*
- * Check type/source combination: slow ints are (currently)
- * only possible for MFP-interrupts.
- */
- if (flags == IRQ_TYPE_SLOW &&
- (irq < STMFP_SOURCE_BASE || irq >= SCC_SOURCE_BASE)) {
- printk ("%s: Slow irq requested for non-MFP source %d from %s\n",
- __FUNCTION__, irq, devname);
- return -EINVAL;
- }
-
- if (vectors[vector] == bad_interrupt) {
- /* int has no handler yet */
- irq_handler[irq].handler = handler;
- irq_handler[irq].dev_id = dev_id;
- irq_param[irq].flags = flags;
- irq_param[irq].devname = devname;
- vectors[vector] =
- (flags == IRQ_TYPE_SLOW) ? slow_handlers[irq-STMFP_SOURCE_BASE] :
- (flags == IRQ_TYPE_FAST) ? atari_fast_irq_handler :
- atari_prio_irq_handler;
- /* If MFP int, also enable and umask it */
- atari_turnon_irq(irq);
- atari_enable_irq(irq);
-
- return 0;
- }
- else if (irq_param[irq].flags == flags) {
- /* old handler is of same type -> handlers can be chained */
- irq_node_t *node;
- unsigned long flags;
-
- local_irq_save(flags);
-
- if (irq_handler[irq].handler != atari_call_irq_list) {
- /* Only one handler yet, make a node for this first one */
- if (!(node = new_irq_node()))
- return -ENOMEM;
- node->handler = irq_handler[irq].handler;
- node->dev_id = irq_handler[irq].dev_id;
- node->devname = irq_param[irq].devname;
- node->next = NULL;
-
- irq_handler[irq].handler = atari_call_irq_list;
- irq_handler[irq].dev_id = node;
- irq_param[irq].devname = "chained";
- }
-
- if (!(node = new_irq_node()))
- return -ENOMEM;
- node->handler = handler;
- node->dev_id = dev_id;
- node->devname = devname;
- /* new handlers are put in front of the queue */
- node->next = irq_handler[irq].dev_id;
- irq_handler[irq].dev_id = node;
-
- local_irq_restore(flags);
- return 0;
- } else {
- printk ("%s: Irq %d allocated by other type int (call from %s)\n",
- __FUNCTION__, irq, devname);
- return -EBUSY;
- }
-}
-
-void atari_free_irq(unsigned int irq, void *dev_id)
-{
- unsigned long flags;
- int vector;
- irq_node_t **list, *node;
-
- if (!IS_VALID_INTNO(irq)) {
- printk("%s: Unknown irq %d\n", __FUNCTION__, irq);
- return;
- }
-
- vector = IRQ_SOURCE_TO_VECTOR(irq);
- if (vectors[vector] == bad_interrupt)
- goto not_found;
-
- local_irq_save(flags);
-
- if (irq_handler[irq].handler != atari_call_irq_list) {
- /* It's the only handler for the interrupt */
- if (irq_handler[irq].dev_id != dev_id) {
- local_irq_restore(flags);
- goto not_found;
- }
- irq_handler[irq].handler = NULL;
- irq_handler[irq].dev_id = NULL;
- irq_param[irq].devname = NULL;
- vectors[vector] = bad_interrupt;
- /* If MFP int, also disable it */
- atari_disable_irq(irq);
- atari_turnoff_irq(irq);
-
- local_irq_restore(flags);
- return;
- }
-
- /* The interrupt is chained, find the irq on the list */
- for(list = (irq_node_t **)&irq_handler[irq].dev_id; *list; list = &(*list)->next) {
- if ((*list)->dev_id == dev_id) break;
- }
- if (!*list) {
- local_irq_restore(flags);
- goto not_found;
- }
-
- (*list)->handler = NULL; /* Mark it as free for reallocation */
- *list = (*list)->next;
-
- /* If there's now only one handler, unchain the interrupt, i.e. plug in
- * the handler directly again and omit atari_call_irq_list */
- node = (irq_node_t *)irq_handler[irq].dev_id;
- if (node && !node->next) {
- irq_handler[irq].handler = node->handler;
- irq_handler[irq].dev_id = node->dev_id;
- irq_param[irq].devname = node->devname;
- node->handler = NULL; /* Mark it as free for reallocation */
- }
-
- local_irq_restore(flags);
- return;
-
-not_found:
- printk("%s: tried to remove invalid irq\n", __FUNCTION__);
- return;
-}
-
-
/*
* atari_register_vme_int() returns the number of a free interrupt vector for
* hardware with a programmable int vector (probably a VME board).
@@ -591,58 +431,24 @@ unsigned long atari_register_vme_int(void)
{
int i;
- for(i = 0; i < 32; i++)
- if((free_vme_vec_bitmap & (1 << i)) == 0)
+ for (i = 0; i < 32; i++)
+ if ((free_vme_vec_bitmap & (1 << i)) == 0)
break;
- if(i == 16)
+ if (i == 16)
return 0;
free_vme_vec_bitmap |= 1 << i;
- return (VME_SOURCE_BASE + i);
+ return VME_SOURCE_BASE + i;
}
void atari_unregister_vme_int(unsigned long irq)
{
- if(irq >= VME_SOURCE_BASE && irq < VME_SOURCE_BASE + VME_MAX_SOURCES) {
+ if (irq >= VME_SOURCE_BASE && irq < VME_SOURCE_BASE + VME_MAX_SOURCES) {
irq -= VME_SOURCE_BASE;
free_vme_vec_bitmap &= ~(1 << irq);
}
}
-int show_atari_interrupts(struct seq_file *p, void *v)
-{
- int i;
-
- for (i = 0; i < NUM_INT_SOURCES; ++i) {
- if (vectors[IRQ_SOURCE_TO_VECTOR(i)] == bad_interrupt)
- continue;
- if (i < STMFP_SOURCE_BASE)
- seq_printf(p, "auto %2d: %10u ",
- i, kstat_cpu(0).irqs[i]);
- else
- seq_printf(p, "vec $%02x: %10u ",
- IRQ_SOURCE_TO_VECTOR(i),
- kstat_cpu(0).irqs[i]);
-
- if (irq_handler[i].handler != atari_call_irq_list) {
- seq_printf(p, "%s\n", irq_param[i].devname);
- }
- else {
- irq_node_t *n;
- for( n = (irq_node_t *)irq_handler[i].dev_id; n; n = n->next ) {
- seq_printf(p, "%s\n", n->devname);
- if (n->next)
- seq_puts(p, " " );
- }
- }
- }
- if (num_spurious)
- seq_printf(p, "spurio.: %10u\n", num_spurious);
-
- return 0;
-}
-
-
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
index 1012b08e5..727289a 100644
--- a/arch/m68k/atari/config.c
+++ b/arch/m68k/atari/config.c
@@ -57,12 +57,6 @@ static int atari_get_hardware_list(char *buffer);
/* atari specific irq functions */
extern void atari_init_IRQ (void);
-extern int atari_request_irq (unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
- unsigned long flags, const char *devname, void *dev_id);
-extern void atari_free_irq (unsigned int irq, void *dev_id);
-extern void atari_enable_irq (unsigned int);
-extern void atari_disable_irq (unsigned int);
-extern int show_atari_interrupts (struct seq_file *, void *);
extern void atari_mksound( unsigned int count, unsigned int ticks );
#ifdef CONFIG_HEARTBEAT
static void atari_heartbeat( int on );
@@ -232,13 +226,8 @@ void __init config_atari(void)
mach_sched_init = atari_sched_init;
mach_init_IRQ = atari_init_IRQ;
- mach_request_irq = atari_request_irq;
- mach_free_irq = atari_free_irq;
- enable_irq = atari_enable_irq;
- disable_irq = atari_disable_irq;
mach_get_model = atari_get_model;
mach_get_hardware_list = atari_get_hardware_list;
- mach_get_irq_list = show_atari_interrupts;
mach_gettimeoffset = atari_gettimeoffset;
mach_reset = atari_reset;
mach_max_dma_address = 0xffffff;
diff --git a/arch/m68k/bvme6000/Makefile b/arch/m68k/bvme6000/Makefile
index 2348e6c..d817400 100644
--- a/arch/m68k/bvme6000/Makefile
+++ b/arch/m68k/bvme6000/Makefile
@@ -2,4 +2,4 @@
# Makefile for Linux arch/m68k/bvme6000 source directory
#
-obj-y := config.o bvmeints.o rtc.o
+obj-y := config.o rtc.o
diff --git a/arch/m68k/bvme6000/bvmeints.c b/arch/m68k/bvme6000/bvmeints.c
deleted file mode 100644
index 298a8df..0000000
--- a/arch/m68k/bvme6000/bvmeints.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * arch/m68k/bvme6000/bvmeints.c
- *
- * Copyright (C) 1997 Richard Hirst [richard@sleepie.demon.co.uk]
- *
- * based on amiints.c -- Amiga Linux interrupt handling code
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file README.legal in the main directory of this archive
- * for more details.
- *
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/seq_file.h>
-
-#include <asm/ptrace.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/traps.h>
-
-static irqreturn_t bvme6000_defhand (int irq, void *dev_id, struct pt_regs *fp);
-
-/*
- * This should ideally be 4 elements only, for speed.
- */
-
-static struct {
- irqreturn_t (*handler)(int, void *, struct pt_regs *);
- unsigned long flags;
- void *dev_id;
- const char *devname;
- unsigned count;
-} irq_tab[256];
-
-/*
- * void bvme6000_init_IRQ (void)
- *
- * Parameters: None
- *
- * Returns: Nothing
- *
- * This function is called during kernel startup to initialize
- * the bvme6000 IRQ handling routines.
- */
-
-void bvme6000_init_IRQ (void)
-{
- int i;
-
- for (i = 0; i < 256; i++) {
- irq_tab[i].handler = bvme6000_defhand;
- irq_tab[i].flags = IRQ_FLG_STD;
- irq_tab[i].dev_id = NULL;
- irq_tab[i].devname = NULL;
- irq_tab[i].count = 0;
- }
-}
-
-int bvme6000_request_irq(unsigned int irq,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
- unsigned long flags, const char *devname, void *dev_id)
-{
- if (irq > 255) {
- printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
- return -ENXIO;
- }
-#if 0
- /* Nothing special about auto-vectored devices for the BVME6000,
- * but treat it specially to avoid changes elsewhere.
- */
-
- if (irq >= VEC_INT1 && irq <= VEC_INT7)
- return cpu_request_irq(irq - VEC_SPUR, handler, flags,
- devname, dev_id);
-#endif
- if (!(irq_tab[irq].flags & IRQ_FLG_STD)) {
- if (irq_tab[irq].flags & IRQ_FLG_LOCK) {
- printk("%s: IRQ %d from %s is not replaceable\n",
- __FUNCTION__, irq, irq_tab[irq].devname);
- return -EBUSY;
- }
- if (flags & IRQ_FLG_REPLACE) {
- printk("%s: %s can't replace IRQ %d from %s\n",
- __FUNCTION__, devname, irq, irq_tab[irq].devname);
- return -EBUSY;
- }
- }
- irq_tab[irq].handler = handler;
- irq_tab[irq].flags = flags;
- irq_tab[irq].dev_id = dev_id;
- irq_tab[irq].devname = devname;
- return 0;
-}
-
-void bvme6000_free_irq(unsigned int irq, void *dev_id)
-{
- if (irq > 255) {
- printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
- return;
- }
-#if 0
- if (irq >= VEC_INT1 && irq <= VEC_INT7) {
- cpu_free_irq(irq - VEC_SPUR, dev_id);
- return;
- }
-#endif
- if (irq_tab[irq].dev_id != dev_id)
- printk("%s: Removing probably wrong IRQ %d from %s\n",
- __FUNCTION__, irq, irq_tab[irq].devname);
-
- irq_tab[irq].handler = bvme6000_defhand;
- irq_tab[irq].flags = IRQ_FLG_STD;
- irq_tab[irq].dev_id = NULL;
- irq_tab[irq].devname = NULL;
-}
-
-irqreturn_t bvme6000_process_int (unsigned long vec, struct pt_regs *fp)
-{
- if (vec > 255) {
- printk ("bvme6000_process_int: Illegal vector %ld", vec);
- return IRQ_NONE;
- } else {
- irq_tab[vec].count++;
- irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp);
- return IRQ_HANDLED;
- }
-}
-
-int show_bvme6000_interrupts(struct seq_file *p, void *v)
-{
- int i;
-
- for (i = 0; i < 256; i++) {
- if (irq_tab[i].count)
- seq_printf(p, "Vec 0x%02x: %8d %s\n",
- i, irq_tab[i].count,
- irq_tab[i].devname ? irq_tab[i].devname : "free");
- }
- return 0;
-}
-
-
-static irqreturn_t bvme6000_defhand (int irq, void *dev_id, struct pt_regs *fp)
-{
- printk ("Unknown interrupt 0x%02x\n", irq);
- return IRQ_NONE;
-}
-
-void bvme6000_enable_irq (unsigned int irq)
-{
-}
-
-
-void bvme6000_disable_irq (unsigned int irq)
-{
-}
-
diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c
index c90cb5f..d1e916a 100644
--- a/arch/m68k/bvme6000/config.c
+++ b/arch/m68k/bvme6000/config.c
@@ -36,15 +36,8 @@
#include <asm/machdep.h>
#include <asm/bvme6000hw.h>
-extern irqreturn_t bvme6000_process_int (int level, struct pt_regs *regs);
-extern void bvme6000_init_IRQ (void);
-extern void bvme6000_free_irq (unsigned int, void *);
-extern int show_bvme6000_interrupts(struct seq_file *, void *);
-extern void bvme6000_enable_irq (unsigned int);
-extern void bvme6000_disable_irq (unsigned int);
static void bvme6000_get_model(char *model);
static int bvme6000_get_hardware_list(char *buffer);
-extern int bvme6000_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
extern void bvme6000_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
extern unsigned long bvme6000_gettimeoffset (void);
extern int bvme6000_hwclk (int, struct rtc_time *);
@@ -100,6 +93,14 @@ static int bvme6000_get_hardware_list(char *buffer)
return 0;
}
+/*
+ * This function is called during kernel startup to initialize
+ * the bvme6000 IRQ handling routines.
+ */
+static void bvme6000_init_IRQ(void)
+{
+ m68k_setup_user_interrupt(VEC_USER, 192, NULL);
+}
void __init config_bvme6000(void)
{
@@ -127,12 +128,6 @@ void __init config_bvme6000(void)
mach_hwclk = bvme6000_hwclk;
mach_set_clock_mmss = bvme6000_set_clock_mmss;
mach_reset = bvme6000_reset;
- mach_free_irq = bvme6000_free_irq;
- mach_process_int = bvme6000_process_int;
- mach_get_irq_list = show_bvme6000_interrupts;
- mach_request_irq = bvme6000_request_irq;
- enable_irq = bvme6000_enable_irq;
- disable_irq = bvme6000_disable_irq;
mach_get_model = bvme6000_get_model;
mach_get_hardware_list = bvme6000_get_hardware_list;
diff --git a/arch/m68k/hp300/Makefile b/arch/m68k/hp300/Makefile
index 89b6317..288b9c6 100644
--- a/arch/m68k/hp300/Makefile
+++ b/arch/m68k/hp300/Makefile
@@ -2,4 +2,4 @@
# Makefile for Linux arch/m68k/hp300 source directory
#
-obj-y := ksyms.o config.o ints.o time.o reboot.o
+obj-y := ksyms.o config.o time.o reboot.o
diff --git a/arch/m68k/hp300/config.c b/arch/m68k/hp300/config.c
index 6d129ee..2ef271c 100644
--- a/arch/m68k/hp300/config.c
+++ b/arch/m68k/hp300/config.c
@@ -21,7 +21,6 @@
#include <asm/hp300hw.h>
#include <asm/rtc.h>
-#include "ints.h"
#include "time.h"
unsigned long hp300_model;
@@ -64,8 +63,6 @@ static char *hp300_models[] __initdata = {
static char hp300_model_name[13] = "HP9000/";
extern void hp300_reset(void);
-extern irqreturn_t (*hp300_default_handler[])(int, void *, struct pt_regs *);
-extern int show_hp300_interrupts(struct seq_file *, void *);
#ifdef CONFIG_SERIAL_8250_CONSOLE
extern int hp300_setup_serial_console(void) __init;
#endif
@@ -245,16 +242,16 @@ static unsigned int hp300_get_ss(void)
hp300_rtc_read(RTC_REG_SEC2);
}
+static void __init hp300_init_IRQ(void)
+{
+}
+
void __init config_hp300(void)
{
mach_sched_init = hp300_sched_init;
mach_init_IRQ = hp300_init_IRQ;
- mach_request_irq = hp300_request_irq;
- mach_free_irq = hp300_free_irq;
mach_get_model = hp300_get_model;
- mach_get_irq_list = show_hp300_interrupts;
mach_gettimeoffset = hp300_gettimeoffset;
- mach_default_handler = &hp300_default_handler;
mach_hwclk = hp300_hwclk;
mach_get_ss = hp300_get_ss;
mach_reset = hp300_reset;
diff --git a/arch/m68k/hp300/ints.c b/arch/m68k/hp300/ints.c
deleted file mode 100644
index 0c5bb40..0000000
--- a/arch/m68k/hp300/ints.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * linux/arch/m68k/hp300/ints.c
- *
- * Copyright (C) 1998 Philip Blundell <philb@gnu.org>
- *
- * This file contains the HP300-specific interrupt handling.
- * We only use the autovector interrupts, and therefore we need to
- * maintain lists of devices sharing each ipl.
- * [ipl list code added by Peter Maydell <pmaydell@chiark.greenend.org.uk> 06/1998]
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <asm/machdep.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/traps.h>
-#include <asm/ptrace.h>
-#include <asm/errno.h>
-#include "ints.h"
-
-/* Each ipl has a linked list of interrupt service routines.
- * Service routines are added via hp300_request_irq() and removed
- * via hp300_free_irq(). The device driver should set IRQ_FLG_FAST
- * if it needs to be serviced early (eg FIFOless UARTs); this will
- * cause it to be added at the front of the queue rather than
- * the back.
- * Currently IRQ_FLG_SLOW and flags=0 are treated identically; if
- * we needed three levels of priority we could distinguish them
- * but this strikes me as mildly ugly...
- */
-
-/* we start with no entries in any list */
-static irq_node_t *hp300_irq_list[HP300_NUM_IRQS];
-
-static spinlock_t irqlist_lock;
-
-/* This handler receives all interrupts, dispatching them to the registered handlers */
-static irqreturn_t hp300_int_handler(int irq, void *dev_id, struct pt_regs *fp)
-{
- irq_node_t *t;
- /* We just give every handler on the chain an opportunity to handle
- * the interrupt, in priority order.
- */
- for(t = hp300_irq_list[irq]; t; t=t->next)
- t->handler(irq, t->dev_id, fp);
- /* We could put in some accounting routines, checks for stray interrupts,
- * etc, in here. Note that currently we can't tell whether or not
- * a handler handles the interrupt, though.
- */
- return IRQ_HANDLED;
-}
-
-static irqreturn_t hp300_badint(int irq, void *dev_id, struct pt_regs *fp)
-{
- num_spurious += 1;
- return IRQ_NONE;
-}
-
-irqreturn_t (*hp300_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
- [0] = hp300_badint,
- [1] = hp300_int_handler,
- [2] = hp300_int_handler,
- [3] = hp300_int_handler,
- [4] = hp300_int_handler,
- [5] = hp300_int_handler,
- [6] = hp300_int_handler,
- [7] = hp300_int_handler
-};
-
-/* dev_id had better be unique to each handler because it's the only way we have
- * to distinguish handlers when removing them...
- *
- * It would be pretty easy to support IRQ_FLG_LOCK (handler is not replacable)
- * and IRQ_FLG_REPLACE (handler replaces existing one with this dev_id)
- * if we wanted to. IRQ_FLG_FAST is needed for devices where interrupt latency
- * matters (eg the dreaded FIFOless UART...)
- */
-int hp300_request_irq(unsigned int irq,
- irqreturn_t (*handler) (int, void *, struct pt_regs *),
- unsigned long flags, const char *devname, void *dev_id)
-{
- irq_node_t *t, *n = new_irq_node();
-
- if (!n) /* oops, no free nodes */
- return -ENOMEM;
-
- spin_lock_irqsave(&irqlist_lock, flags);
-
- if (!hp300_irq_list[irq]) {
- /* no list yet */
- hp300_irq_list[irq] = n;
- n->next = NULL;
- } else if (flags & IRQ_FLG_FAST) {
- /* insert at head of list */
- n->next = hp300_irq_list[irq];
- hp300_irq_list[irq] = n;
- } else {
- /* insert at end of list */
- for(t = hp300_irq_list[irq]; t->next; t = t->next)
- /* do nothing */;
- n->next = NULL;
- t->next = n;
- }
-
- /* Fill in n appropriately */
- n->handler = handler;
- n->flags = flags;
- n->dev_id = dev_id;
- n->devname = devname;
- spin_unlock_irqrestore(&irqlist_lock, flags);
- return 0;
-}
-
-void hp300_free_irq(unsigned int irq, void *dev_id)
-{
- irq_node_t *t;
- unsigned long flags;
-
- spin_lock_irqsave(&irqlist_lock, flags);
-
- t = hp300_irq_list[irq];
- if (!t) /* no handlers at all for that IRQ */
- {
- printk(KERN_ERR "hp300_free_irq: attempt to remove nonexistent handler for IRQ %d\n", irq);
- spin_unlock_irqrestore(&irqlist_lock, flags);
- return;
- }
-
- if (t->dev_id == dev_id)
- { /* removing first handler on chain */
- t->flags = IRQ_FLG_STD; /* we probably don't really need these */
- t->dev_id = NULL;
- t->devname = NULL;
- t->handler = NULL; /* frees this irq_node_t */
- hp300_irq_list[irq] = t->next;
- spin_unlock_irqrestore(&irqlist_lock, flags);
- return;
- }
-
- /* OK, must be removing from middle of the chain */
-
- for (t = hp300_irq_list[irq]; t->next && t->next->dev_id != dev_id; t = t->next)
- /* do nothing */;
- if (!t->next)
- {
- printk(KERN_ERR "hp300_free_irq: attempt to remove nonexistent handler for IRQ %d\n", irq);
- spin_unlock_irqrestore(&irqlist_lock, flags);
- return;
- }
- /* remove the entry after t: */
- t->next->flags = IRQ_FLG_STD;
- t->next->dev_id = NULL;
- t->next->devname = NULL;
- t->next->handler = NULL;
- t->next = t->next->next;
-
- spin_unlock_irqrestore(&irqlist_lock, flags);
-}
-
-int show_hp300_interrupts(struct seq_file *p, void *v)
-{
- return 0;
-}
-
-void __init hp300_init_IRQ(void)
-{
- spin_lock_init(&irqlist_lock);
-}
diff --git a/arch/m68k/hp300/ints.h b/arch/m68k/hp300/ints.h
deleted file mode 100644
index 8cfabe2..0000000
--- a/arch/m68k/hp300/ints.h
+++ /dev/null
@@ -1,9 +0,0 @@
-extern void hp300_init_IRQ(void);
-extern void (*hp300_handlers[8])(int, void *, struct pt_regs *);
-extern void hp300_free_irq(unsigned int irq, void *dev_id);
-extern int hp300_request_irq(unsigned int irq,
- irqreturn_t (*handler) (int, void *, struct pt_regs *),
- unsigned long flags, const char *devname, void *dev_id);
-
-/* number of interrupts, includes 0 (what's that?) */
-#define HP300_NUM_IRQS 8
diff --git a/arch/m68k/hp300/time.c b/arch/m68k/hp300/time.c
index 8da5b1b..7df0566 100644
--- a/arch/m68k/hp300/time.c
+++ b/arch/m68k/hp300/time.c
@@ -18,7 +18,6 @@
#include <asm/system.h>
#include <asm/traps.h>
#include <asm/blinken.h>
-#include "ints.h"
/* Clock hardware definitions */
@@ -71,7 +70,7 @@ void __init hp300_sched_init(irqreturn_t (*vector)(int, void *, struct pt_regs *
asm volatile(" movpw %0,%1@(5)" : : "d" (INTVAL), "a" (CLOCKBASE));
- cpu_request_irq(6, hp300_tick, IRQ_FLG_STD, "timer tick", vector);
+ request_irq(IRQ_AUTO_6, hp300_tick, IRQ_FLG_STD, "timer tick", vector);
out_8(CLOCKBASE + CLKCR2, 0x1); /* select CR1 */
out_8(CLOCKBASE + CLKCR1, 0x40); /* enable irq */
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile
index 458925c..dae6097 100644
--- a/arch/m68k/kernel/Makefile
+++ b/arch/m68k/kernel/Makefile
@@ -9,8 +9,8 @@ else
endif
extra-y += vmlinux.lds
-obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o \
- sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o
+obj-y := entry.o process.o traps.o ints.o dma.o signal.o ptrace.o \
+ sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o
obj-$(CONFIG_PCI) += bios32.o
obj-$(CONFIG_MODULES) += module.o
diff --git a/arch/m68k/kernel/dma.c b/arch/m68k/kernel/dma.c
new file mode 100644
index 0000000..fc449f8
--- /dev/null
+++ b/arch/m68k/kernel/dma.c
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+#undef DEBUG
+
+#include <linux/dma-mapping.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+
+#include <asm/pgalloc.h>
+#include <asm/scatterlist.h>
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *handle, int flag)
+{
+ struct page *page, **map;
+ pgprot_t pgprot;
+ void *addr;
+ int i, order;
+
+ pr_debug("dma_alloc_coherent: %d,%x\n", size, flag);
+
+ size = PAGE_ALIGN(size);
+ order = get_order(size);
+
+ page = alloc_pages(flag, order);
+ if (!page)
+ return NULL;
+
+ *handle = page_to_phys(page);
+ map = kmalloc(sizeof(struct page *) << order, flag & ~__GFP_DMA);
+ if (!map) {
+ __free_pages(page, order);
+ return NULL;
+ }
+ split_page(page, order);
+
+ order = 1 << order;
+ size >>= PAGE_SHIFT;
+ map[0] = page;
+ for (i = 1; i < size; i++)
+ map[i] = page + i;
+ for (; i < order; i++)
+ __free_page(page + i);
+ pgprot = __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
+ if (CPU_IS_040_OR_060)
+ pgprot_val(pgprot) |= _PAGE_GLOBAL040 | _PAGE_NOCACHE_S;
+ else
+ pgprot_val(pgprot) |= _PAGE_NOCACHE030;
+ addr = vmap(map, size, flag, pgprot);
+ kfree(map);
+
+ return addr;
+}
+EXPORT_SYMBOL(dma_alloc_coherent);
+
+void dma_free_coherent(struct device *dev, size_t size,
+ void *addr, dma_addr_t handle)
+{
+ pr_debug("dma_free_coherent: %p, %x\n", addr, handle);
+ vfree(addr);
+}
+EXPORT_SYMBOL(dma_free_coherent);
+
+inline void dma_sync_single_for_device(struct device *dev, dma_addr_t handle, size_t size,
+ enum dma_data_direction dir)
+{
+ switch (dir) {
+ case DMA_TO_DEVICE:
+ cache_push(handle, size);
+ break;
+ case DMA_FROM_DEVICE:
+ cache_clear(handle, size);
+ break;
+ default:
+ if (printk_ratelimit())
+ printk("dma_sync_single_for_device: unsupported dir %u\n", dir);
+ break;
+ }
+}
+EXPORT_SYMBOL(dma_sync_single_for_device);
+
+void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction dir)
+{
+ int i;
+
+ for (i = 0; i < nents; sg++, i++)
+ dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir);
+}
+EXPORT_SYMBOL(dma_sync_sg_for_device);
+
+dma_addr_t dma_map_single(struct device *dev, void *addr, size_t size,
+ enum dma_data_direction dir)
+{
+ dma_addr_t handle = virt_to_bus(addr);
+
+ dma_sync_single_for_device(dev, handle, size, dir);
+ return handle;
+}
+EXPORT_SYMBOL(dma_map_single);
+
+dma_addr_t dma_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction dir)
+{
+ dma_addr_t handle = page_to_phys(page) + offset;
+
+ dma_sync_single_for_device(dev, handle, size, dir);
+ return handle;
+}
+EXPORT_SYMBOL(dma_map_page);
+
+int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction dir)
+{
+ int i;
+
+ for (i = 0; i < nents; sg++, i++) {
+ sg->dma_address = page_to_phys(sg->page) + sg->offset;
+ dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir);
+ }
+ return nents;
+}
+EXPORT_SYMBOL(dma_map_sg);
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 320fde0..449b62b 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -45,9 +45,11 @@
#include <asm/asm-offsets.h>
.globl system_call, buserr, trap, resume
-.globl inthandler, sys_call_table
+.globl sys_call_table
.globl sys_fork, sys_clone, sys_vfork
.globl ret_from_interrupt, bad_interrupt
+.globl auto_irqhandler_fixup
+.globl user_irqvec_fixup, user_irqhandler_fixup
.text
ENTRY(buserr)
@@ -191,65 +193,29 @@ do_delayed_trace:
jbra resume_userspace
-#if 0
-#ifdef CONFIG_AMIGA
-ami_inthandler:
- addql #1,irq_stat+CPUSTAT_LOCAL_IRQ_COUNT
- SAVE_ALL_INT
- GET_CURRENT(%d0)
+/* This is the main interrupt handler for autovector interrupts */
- bfextu %sp@(PT_VECTOR){#4,#12},%d0
- movel %d0,%a0
- addql #1,%a0@(kstat+STAT_IRQ-VECOFF(VEC_SPUR))
- movel %a0@(autoirq_list-VECOFF(VEC_SPUR)),%a0
-
-| amiga vector int handler get the req mask instead of irq vector
- lea CUSTOMBASE,%a1
- movew %a1@(C_INTREQR),%d0
- andw %a1@(C_INTENAR),%d0
-
-| prepare stack (push frame pointer, dev_id & req mask)
- pea %sp@
- movel %a0@(IRQ_DEVID),%sp@-
- movel %d0,%sp@-
- pea %pc@(ret_from_interrupt:w)
- jbra @(IRQ_HANDLER,%a0)@(0)
-
-ENTRY(nmi_handler)
- rte
-#endif
-#endif
-
-/*
-** This is the main interrupt handler, responsible for calling process_int()
-*/
-inthandler:
+ENTRY(auto_inthandler)
SAVE_ALL_INT
GET_CURRENT(%d0)
- addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+2)
+ addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
| put exception # in d0
- bfextu %sp@(PT_VECTOR){#4,#10},%d0
+ bfextu %sp@(PT_VECTOR){#4,#10},%d0
+ subw #VEC_SPUR,%d0
movel %sp,%sp@-
movel %d0,%sp@- | put vector # on stack
-#if defined(MACH_Q40_ONLY) && defined(CONFIG_BLK_DEV_FD)
- btstb #4,0xff000000 | Q40 floppy needs very special treatment ...
- jbeq 1f
- btstb #3,0xff000004
- jbeq 1f
- jbsr floppy_hardint
- jbra 3f
-1:
-#endif
- jbsr process_int | process the IRQ
-3: addql #8,%sp | pop parameters off stack
+auto_irqhandler_fixup = . + 2
+ jsr m68k_handle_int | process the IRQ
+ addql #8,%sp | pop parameters off stack
ret_from_interrupt:
- subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+2)
- jeq 1f
-2:
- RESTORE_ALL
-1:
+ subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
+ jeq ret_from_last_interrupt
+2: RESTORE_ALL
+
+ ALIGN
+ret_from_last_interrupt:
moveq #(~ALLOWINT>>8)&0xff,%d0
andb %sp@(PT_SR),%d0
jne 2b
@@ -260,12 +226,42 @@ ret_from_interrupt:
pea ret_from_exception
jra do_softirq
+/* Handler for user defined interrupt vectors */
+
+ENTRY(user_inthandler)
+ SAVE_ALL_INT
+ GET_CURRENT(%d0)
+ addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
+ | put exception # in d0
+ bfextu %sp@(PT_VECTOR){#4,#10},%d0
+user_irqvec_fixup = . + 2
+ subw #VEC_USER,%d0
+
+ movel %sp,%sp@-
+ movel %d0,%sp@- | put vector # on stack
+user_irqhandler_fixup = . + 2
+ jsr m68k_handle_int | process the IRQ
+ addql #8,%sp | pop parameters off stack
+
+ subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
+ jeq ret_from_last_interrupt
+ RESTORE_ALL
/* Handler for uninitialized and spurious interrupts */
-bad_interrupt:
- addql #1,num_spurious
- rte
+ENTRY(bad_inthandler)
+ SAVE_ALL_INT
+ GET_CURRENT(%d0)
+ addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
+
+ movel %sp,%sp@-
+ jsr handle_badint
+ addql #4,%sp
+
+ subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
+ jeq ret_from_last_interrupt
+ RESTORE_ALL
+
ENTRY(sys_fork)
SAVE_SWITCH_STACK
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c
index 514d323..5a8344b 100644
--- a/arch/m68k/kernel/ints.c
+++ b/arch/m68k/kernel/ints.c
@@ -39,47 +39,40 @@
#include <asm/traps.h>
#include <asm/page.h>
#include <asm/machdep.h>
+#include <asm/cacheflush.h>
#ifdef CONFIG_Q40
#include <asm/q40ints.h>
#endif
+extern u32 auto_irqhandler_fixup[];
+extern u32 user_irqhandler_fixup[];
+extern u16 user_irqvec_fixup[];
+
/* table for system interrupt handlers */
-static irq_handler_t irq_list[SYS_IRQS];
-
-static const char *default_names[SYS_IRQS] = {
- [0] = "spurious int",
- [1] = "int1 handler",
- [2] = "int2 handler",
- [3] = "int3 handler",
- [4] = "int4 handler",
- [5] = "int5 handler",
- [6] = "int6 handler",
- [7] = "int7 handler"
+static struct irq_node *irq_list[NR_IRQS];
+static struct irq_controller *irq_controller[NR_IRQS];
+static int irq_depth[NR_IRQS];
+
+static int m68k_first_user_vec;
+
+static struct irq_controller auto_irq_controller = {
+ .name = "auto",
+ .lock = SPIN_LOCK_UNLOCKED,
+ .startup = m68k_irq_startup,
+ .shutdown = m68k_irq_shutdown,
};
-/* The number of spurious interrupts */
-volatile unsigned int num_spurious;
+static struct irq_controller user_irq_controller = {
+ .name = "user",
+ .lock = SPIN_LOCK_UNLOCKED,
+ .startup = m68k_irq_startup,
+ .shutdown = m68k_irq_shutdown,
+};
#define NUM_IRQ_NODES 100
static irq_node_t nodes[NUM_IRQ_NODES];
-static void dummy_enable_irq(unsigned int irq);
-static void dummy_disable_irq(unsigned int irq);
-static int dummy_request_irq(unsigned int irq,
- irqreturn_t (*handler) (int, void *, struct pt_regs *),
- unsigned long flags, const char *devname, void *dev_id);
-static void dummy_free_irq(unsigned int irq, void *dev_id);
-
-void (*enable_irq) (unsigned int) = dummy_enable_irq;
-void (*disable_irq) (unsigned int) = dummy_disable_irq;
-
-int (*mach_request_irq) (unsigned int, irqreturn_t (*)(int, void *, struct pt_regs *),
- unsigned long, const char *, void *) = dummy_request_irq;
-void (*mach_free_irq) (unsigned int, void *) = dummy_free_irq;
-
-void init_irq_proc(void);
-
/*
* void init_IRQ(void)
*
@@ -95,18 +88,76 @@ void __init init_IRQ(void)
{
int i;
- for (i = 0; i < SYS_IRQS; i++) {
- if (mach_default_handler)
- irq_list[i].handler = (*mach_default_handler)[i];
- irq_list[i].flags = 0;
- irq_list[i].dev_id = NULL;
- irq_list[i].devname = default_names[i];
+ /* assembly irq entry code relies on this... */
+ if (HARDIRQ_MASK != 0x00ff0000) {
+ extern void hardirq_mask_is_broken(void);
+ hardirq_mask_is_broken();
}
- for (i = 0; i < NUM_IRQ_NODES; i++)
- nodes[i].handler = NULL;
+ for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++)
+ irq_controller[i] = &auto_irq_controller;
+
+ mach_init_IRQ();
+}
+
+/**
+ * m68k_setup_auto_interrupt
+ * @handler: called from auto vector interrupts
+ *
+ * setup the handler to be called from auto vector interrupts instead of the
+ * standard m68k_handle_int(), it will be called with irq numbers in the range
+ * from IRQ_AUTO_1 - IRQ_AUTO_7.
+ */
+void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *))
+{
+ if (handler)
+ *auto_irqhandler_fixup = (u32)handler;
+ flush_icache();
+}
+
+/**
+ * m68k_setup_user_interrupt
+ * @vec: first user vector interrupt to handle
+ * @cnt: number of active user vector interrupts
+ * @handler: called from user vector interrupts
+ *
+ * setup user vector interrupts, this includes activating the specified range
+ * of interrupts, only then these interrupts can be requested (note: this is
+ * different from auto vector interrupts). An optional handler can be installed
+ * to be called instead of the default m68k_handle_int(), it will be called
+ * with irq numbers starting from IRQ_USER.
+ */
+void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt,
+ void (*handler)(unsigned int, struct pt_regs *))
+{
+ int i;
+
+ m68k_first_user_vec = vec;
+ for (i = 0; i < cnt; i++)
+ irq_controller[IRQ_USER + i] = &user_irq_controller;
+ *user_irqvec_fixup = vec - IRQ_USER;
+ if (handler)
+ *user_irqhandler_fixup = (u32)handler;
+ flush_icache();
+}
+
+/**
+ * m68k_setup_irq_controller
+ * @contr: irq controller which controls specified irq
+ * @irq: first irq to be managed by the controller
+ *
+ * Change the controller for the specified range of irq, which will be used to
+ * manage these irq. auto/user irq already have a default controller, which can
+ * be changed as well, but the controller probably should use m68k_irq_startup/
+ * m68k_irq_shutdown.
+ */
+void m68k_setup_irq_controller(struct irq_controller *contr, unsigned int irq,
+ unsigned int cnt)
+{
+ int i;
- mach_init_IRQ ();
+ for (i = 0; i < cnt; i++)
+ irq_controller[irq + i] = contr;
}
irq_node_t *new_irq_node(void)
@@ -114,84 +165,183 @@ irq_node_t *new_irq_node(void)
irq_node_t *node;
short i;
- for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--)
- if (!node->handler)
+ for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) {
+ if (!node->handler) {
+ memset(node, 0, sizeof(*node));
return node;
+ }
+ }
printk ("new_irq_node: out of nodes\n");
return NULL;
}
-/*
- * We will keep these functions until I have convinced Linus to move
- * the declaration of them from include/linux/sched.h to
- * include/asm/irq.h.
- */
+int setup_irq(unsigned int irq, struct irq_node *node)
+{
+ struct irq_controller *contr;
+ struct irq_node **prev;
+ unsigned long flags;
+
+ if (irq >= NR_IRQS || !(contr = irq_controller[irq])) {
+ printk("%s: Incorrect IRQ %d from %s\n",
+ __FUNCTION__, irq, node->devname);
+ return -ENXIO;
+ }
+
+ spin_lock_irqsave(&contr->lock, flags);
+
+ prev = irq_list + irq;
+ if (*prev) {
+ /* Can't share interrupts unless both agree to */
+ if (!((*prev)->flags & node->flags & SA_SHIRQ)) {
+ spin_unlock_irqrestore(&contr->lock, flags);
+ return -EBUSY;
+ }
+ while (*prev)
+ prev = &(*prev)->next;
+ }
+
+ if (!irq_list[irq]) {
+ if (contr->startup)
+ contr->startup(irq);
+ else
+ contr->enable(irq);
+ }
+ node->next = NULL;
+ *prev = node;
+
+ spin_unlock_irqrestore(&contr->lock, flags);
+
+ return 0;
+}
+
int request_irq(unsigned int irq,
irqreturn_t (*handler) (int, void *, struct pt_regs *),
unsigned long flags, const char *devname, void *dev_id)
{
- return mach_request_irq(irq, handler, flags, devname, dev_id);
+ struct irq_node *node;
+ int res;
+
+ node = new_irq_node();
+ if (!node)
+ return -ENOMEM;
+
+ node->handler = handler;
+ node->flags = flags;
+ node->dev_id = dev_id;
+ node->devname = devname;
+
+ res = setup_irq(irq, node);
+ if (res)
+ node->handler = NULL;
+
+ return res;
}
EXPORT_SYMBOL(request_irq);
void free_irq(unsigned int irq, void *dev_id)
{
- mach_free_irq(irq, dev_id);
+ struct irq_controller *contr;
+ struct irq_node **p, *node;
+ unsigned long flags;
+
+ if (irq >= NR_IRQS || !(contr = irq_controller[irq])) {
+ printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
+ return;
+ }
+
+ spin_lock_irqsave(&contr->lock, flags);
+
+ p = irq_list + irq;
+ while ((node = *p)) {
+ if (node->dev_id == dev_id)
+ break;
+ p = &node->next;
+ }
+
+ if (node) {
+ *p = node->next;
+ node->handler = NULL;
+ } else
+ printk("%s: Removing probably wrong IRQ %d\n",
+ __FUNCTION__, irq);
+
+ if (!irq_list[irq]) {
+ if (contr->shutdown)
+ contr->shutdown(irq);
+ else
+ contr->disable(irq);
+ }
+
+ spin_unlock_irqrestore(&contr->lock, flags);
}
EXPORT_SYMBOL(free_irq);
-int cpu_request_irq(unsigned int irq,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
- unsigned long flags, const char *devname, void *dev_id)
+void enable_irq(unsigned int irq)
{
- if (irq < IRQ1 || irq > IRQ7) {
- printk("%s: Incorrect IRQ %d from %s\n",
- __FUNCTION__, irq, devname);
- return -ENXIO;
- }
+ struct irq_controller *contr;
+ unsigned long flags;
-#if 0
- if (!(irq_list[irq].flags & IRQ_FLG_STD)) {
- if (irq_list[irq].flags & IRQ_FLG_LOCK) {
- printk("%s: IRQ %d from %s is not replaceable\n",
- __FUNCTION__, irq, irq_list[irq].devname);
- return -EBUSY;
- }
- if (!(flags & IRQ_FLG_REPLACE)) {
- printk("%s: %s can't replace IRQ %d from %s\n",
- __FUNCTION__, devname, irq, irq_list[irq].devname);
- return -EBUSY;
- }
+ if (irq >= NR_IRQS || !(contr = irq_controller[irq])) {
+ printk("%s: Incorrect IRQ %d\n",
+ __FUNCTION__, irq);
+ return;
}
-#endif
- irq_list[irq].handler = handler;
- irq_list[irq].flags = flags;
- irq_list[irq].dev_id = dev_id;
- irq_list[irq].devname = devname;
- return 0;
+ spin_lock_irqsave(&contr->lock, flags);
+ if (irq_depth[irq]) {
+ if (!--irq_depth[irq]) {
+ if (contr->enable)
+ contr->enable(irq);
+ }
+ } else
+ WARN_ON(1);
+ spin_unlock_irqrestore(&contr->lock, flags);
}
-void cpu_free_irq(unsigned int irq, void *dev_id)
+EXPORT_SYMBOL(enable_irq);
+
+void disable_irq(unsigned int irq)
{
- if (irq < IRQ1 || irq > IRQ7) {
- printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
+ struct irq_controller *contr;
+ unsigned long flags;
+
+ if (irq >= NR_IRQS || !(contr = irq_controller[irq])) {
+ printk("%s: Incorrect IRQ %d\n",
+ __FUNCTION__, irq);
return;
}
- if (irq_list[irq].dev_id != dev_id)
- printk("%s: Removing probably wrong IRQ %d from %s\n",
- __FUNCTION__, irq, irq_list[irq].devname);
+ spin_lock_irqsave(&contr->lock, flags);
+ if (!irq_depth[irq]++) {
+ if (contr->disable)
+ contr->disable(irq);
+ }
+ spin_unlock_irqrestore(&contr->lock, flags);
+}
- irq_list[irq].handler = (*mach_default_handler)[irq];
- irq_list[irq].flags = 0;
- irq_list[irq].dev_id = NULL;
- irq_list[irq].devname = default_names[irq];
+EXPORT_SYMBOL(disable_irq);
+
+int m68k_irq_startup(unsigned int irq)
+{
+ if (irq <= IRQ_AUTO_7)
+ vectors[VEC_SPUR + irq] = auto_inthandler;
+ else
+ vectors[m68k_first_user_vec + irq - IRQ_USER] = user_inthandler;
+ return 0;
}
+void m68k_irq_shutdown(unsigned int irq)
+{
+ if (irq <= IRQ_AUTO_7)
+ vectors[VEC_SPUR + irq] = bad_inthandler;
+ else
+ vectors[m68k_first_user_vec + irq - IRQ_USER] = bad_inthandler;
+}
+
+
/*
* Do we need these probe functions on the m68k?
*
@@ -219,58 +369,50 @@ int probe_irq_off (unsigned long irqs)
EXPORT_SYMBOL(probe_irq_off);
-static void dummy_enable_irq(unsigned int irq)
-{
- printk("calling uninitialized enable_irq()\n");
-}
-
-static void dummy_disable_irq(unsigned int irq)
+unsigned int irq_canonicalize(unsigned int irq)
{
- printk("calling uninitialized disable_irq()\n");
+#ifdef CONFIG_Q40
+ if (MACH_IS_Q40 && irq == 11)
+ irq = 10;
+#endif
+ return irq;
}
-static int dummy_request_irq(unsigned int irq,
- irqreturn_t (*handler) (int, void *, struct pt_regs *),
- unsigned long flags, const char *devname, void *dev_id)
-{
- printk("calling uninitialized request_irq()\n");
- return 0;
-}
+EXPORT_SYMBOL(irq_canonicalize);
-static void dummy_free_irq(unsigned int irq, void *dev_id)
+asmlinkage void m68k_handle_int(unsigned int irq, struct pt_regs *regs)
{
- printk("calling uninitialized disable_irq()\n");
+ struct irq_node *node;
+
+ kstat_cpu(0).irqs[irq]++;
+ node = irq_list[irq];
+ do {
+ node->handler(irq, node->dev_id, regs);
+ node = node->next;
+ } while (node);
}
-asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
+asmlinkage void handle_badint(struct pt_regs *regs)
{
- if (vec >= VEC_INT1 && vec <= VEC_INT7 && !MACH_IS_BVME6000) {
- vec -= VEC_SPUR;
- kstat_cpu(0).irqs[vec]++;
- irq_list[vec].handler(vec, irq_list[vec].dev_id, fp);
- } else {
- if (mach_process_int)
- mach_process_int(vec, fp);
- else
- panic("Can't process interrupt vector %ld\n", vec);
- return;
- }
+ kstat_cpu(0).irqs[0]++;
+ printk("unexpected interrupt from %u\n", regs->vector);
}
int show_interrupts(struct seq_file *p, void *v)
{
+ struct irq_controller *contr;
+ struct irq_node *node;
int i = *(loff_t *) v;
/* autovector interrupts */
- if (i < SYS_IRQS) {
- if (mach_default_handler) {
- seq_printf(p, "auto %2d: %10u ", i,
- i ? kstat_cpu(0).irqs[i] : num_spurious);
- seq_puts(p, " ");
- seq_printf(p, "%s\n", irq_list[i].devname);
- }
- } else if (i == SYS_IRQS)
- mach_get_irq_list(p, v);
+ if (irq_list[i]) {
+ contr = irq_controller[i];
+ node = irq_list[i];
+ seq_printf(p, "%-8s %3u: %10u %s", contr->name, i, kstat_cpu(0).irqs[i], node->devname);
+ while ((node = node->next))
+ seq_printf(p, ", %s", node->devname);
+ seq_puts(p, "\n");
+ }
return 0;
}
diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c
index 5b7952e..1f5e1b5 100644
--- a/arch/m68k/kernel/m68k_ksyms.c
+++ b/arch/m68k/kernel/m68k_ksyms.c
@@ -57,8 +57,6 @@ EXPORT_SYMBOL(dump_thread);
EXPORT_SYMBOL(strnlen);
EXPORT_SYMBOL(strrchr);
EXPORT_SYMBOL(strstr);
-EXPORT_SYMBOL(enable_irq);
-EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL(kernel_thread);
#ifdef CONFIG_VME
EXPORT_SYMBOL(vme_brdtype);
diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c
index 750d5b3..214a95f 100644
--- a/arch/m68k/kernel/setup.c
+++ b/arch/m68k/kernel/setup.c
@@ -68,11 +68,8 @@ char m68k_debug_device[6] = "";
void (*mach_sched_init) (irqreturn_t (*handler)(int, void *, struct pt_regs *)) __initdata = NULL;
/* machine dependent irq functions */
void (*mach_init_IRQ) (void) __initdata = NULL;
-irqreturn_t (*(*mach_default_handler)[]) (int, void *, struct pt_regs *);
void (*mach_get_model) (char *model);
int (*mach_get_hardware_list) (char *buffer);
-int (*mach_get_irq_list) (struct seq_file *, void *);
-irqreturn_t (*mach_process_int) (int, struct pt_regs *);
/* machine dependent timer functions */
unsigned long (*mach_gettimeoffset) (void);
int (*mach_hwclk) (int, struct rtc_time*);
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c
index 866917b..f9af893 100644
--- a/arch/m68k/kernel/signal.c
+++ b/arch/m68k/kernel/signal.c
@@ -763,7 +763,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
/* This is the X/Open sanctioned signal stack switching. */
if (ka->sa.sa_flags & SA_ONSTACK) {
- if (!on_sig_stack(usp))
+ if (!sas_ss_flags(usp))
usp = current->sas_ss_sp + current->sas_ss_size;
}
return (void __user *)((usp - frame_size) & -8UL);
diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c
index cdf58fb..e86de7b 100644
--- a/arch/m68k/kernel/traps.c
+++ b/arch/m68k/kernel/traps.c
@@ -45,7 +45,6 @@
asmlinkage void system_call(void);
asmlinkage void buserr(void);
asmlinkage void trap(void);
-asmlinkage void inthandler(void);
asmlinkage void nmihandler(void);
#ifdef CONFIG_M68KFPU_EMU
asmlinkage void fpu_emu(void);
@@ -53,51 +52,7 @@ asmlinkage void fpu_emu(void);
e_vector vectors[256] = {
[VEC_BUSERR] = buserr,
- [VEC_ADDRERR] = trap,
- [VEC_ILLEGAL] = trap,
- [VEC_ZERODIV] = trap,
- [VEC_CHK] = trap,
- [VEC_TRAP] = trap,
- [VEC_PRIV] = trap,
- [VEC_TRACE] = trap,
- [VEC_LINE10] = trap,
- [VEC_LINE11] = trap,
- [VEC_RESV12] = trap,
- [VEC_COPROC] = trap,
- [VEC_FORMAT] = trap,
- [VEC_UNINT] = trap,
- [VEC_RESV16] = trap,
- [VEC_RESV17] = trap,
- [VEC_RESV18] = trap,
- [VEC_RESV19] = trap,
- [VEC_RESV20] = trap,
- [VEC_RESV21] = trap,
- [VEC_RESV22] = trap,
- [VEC_RESV23] = trap,
- [VEC_SPUR] = inthandler,
- [VEC_INT1] = inthandler,
- [VEC_INT2] = inthandler,
- [VEC_INT3] = inthandler,
- [VEC_INT4] = inthandler,
- [VEC_INT5] = inthandler,
- [VEC_INT6] = inthandler,
- [VEC_INT7] = inthandler,
[VEC_SYS] = system_call,
- [VEC_TRAP1] = trap,
- [VEC_TRAP2] = trap,
- [VEC_TRAP3] = trap,
- [VEC_TRAP4] = trap,
- [VEC_TRAP5] = trap,
- [VEC_TRAP6] = trap,
- [VEC_TRAP7] = trap,
- [VEC_TRAP8] = trap,
- [VEC_TRAP9] = trap,
- [VEC_TRAP10] = trap,
- [VEC_TRAP11] = trap,
- [VEC_TRAP12] = trap,
- [VEC_TRAP13] = trap,
- [VEC_TRAP14] = trap,
- [VEC_TRAP15] = trap,
};
/* nmi handler for the Amiga */
@@ -114,7 +69,7 @@ void __init base_trap_init(void)
if(MACH_IS_SUN3X) {
extern e_vector *sun3x_prom_vbr;
- __asm__ volatile ("movec %%vbr, %0" : "=r" ((void*)sun3x_prom_vbr));
+ __asm__ volatile ("movec %%vbr, %0" : "=r" (sun3x_prom_vbr));
}
/* setup the exception vector table */
@@ -132,12 +87,15 @@ void __init trap_init (void)
{
int i;
- for (i = 48; i < 64; i++)
+ for (i = VEC_SPUR; i <= VEC_INT7; i++)
+ vectors[i] = bad_inthandler;
+
+ for (i = 0; i < VEC_USER; i++)
if (!vectors[i])
vectors[i] = trap;
- for (i = 64; i < 256; i++)
- vectors[i] = inthandler;
+ for (i = VEC_USER; i < 256; i++)
+ vectors[i] = bad_inthandler;
#ifdef CONFIG_M68KFPU_EMU
if (FPU_IS_EMU)
@@ -927,71 +885,94 @@ void show_trace(unsigned long *stack)
void show_registers(struct pt_regs *regs)
{
struct frame *fp = (struct frame *)regs;
+ mm_segment_t old_fs = get_fs();
+ u16 c, *cp;
unsigned long addr;
int i;
+ print_modules();
+ printk("PC: [<%08lx>]",regs->pc);
+ print_symbol(" %s", regs->pc);
+ printk("\nSR: %04x SP: %p a2: %08lx\n",
+ regs->sr, regs, regs->a2);
+ printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
+ regs->d0, regs->d1, regs->d2, regs->d3);
+ printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",
+ regs->d4, regs->d5, regs->a0, regs->a1);
+
+ printk("Process %s (pid: %d, task=%p)\n",
+ current->comm, current->pid, current);
addr = (unsigned long)&fp->un;
- printk("Frame format=%X ", fp->ptregs.format);
- switch (fp->ptregs.format) {
+ printk("Frame format=%X ", regs->format);
+ switch (regs->format) {
case 0x2:
- printk("instr addr=%08lx\n", fp->un.fmt2.iaddr);
- addr += sizeof(fp->un.fmt2);
- break;
+ printk("instr addr=%08lx\n", fp->un.fmt2.iaddr);
+ addr += sizeof(fp->un.fmt2);
+ break;
case 0x3:
- printk("eff addr=%08lx\n", fp->un.fmt3.effaddr);
- addr += sizeof(fp->un.fmt3);
- break;
+ printk("eff addr=%08lx\n", fp->un.fmt3.effaddr);
+ addr += sizeof(fp->un.fmt3);
+ break;
case 0x4:
- printk((CPU_IS_060 ? "fault addr=%08lx fslw=%08lx\n"
- : "eff addr=%08lx pc=%08lx\n"),
- fp->un.fmt4.effaddr, fp->un.fmt4.pc);
- addr += sizeof(fp->un.fmt4);
- break;
+ printk((CPU_IS_060 ? "fault addr=%08lx fslw=%08lx\n"
+ : "eff addr=%08lx pc=%08lx\n"),
+ fp->un.fmt4.effaddr, fp->un.fmt4.pc);
+ addr += sizeof(fp->un.fmt4);
+ break;
case 0x7:
- printk("eff addr=%08lx ssw=%04x faddr=%08lx\n",
- fp->un.fmt7.effaddr, fp->un.fmt7.ssw, fp->un.fmt7.faddr);
- printk("wb 1 stat/addr/data: %04x %08lx %08lx\n",
- fp->un.fmt7.wb1s, fp->un.fmt7.wb1a, fp->un.fmt7.wb1dpd0);
- printk("wb 2 stat/addr/data: %04x %08lx %08lx\n",
- fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d);
- printk("wb 3 stat/addr/data: %04x %08lx %08lx\n",
- fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d);
- printk("push data: %08lx %08lx %08lx %08lx\n",
- fp->un.fmt7.wb1dpd0, fp->un.fmt7.pd1, fp->un.fmt7.pd2,
- fp->un.fmt7.pd3);
- addr += sizeof(fp->un.fmt7);
- break;
+ printk("eff addr=%08lx ssw=%04x faddr=%08lx\n",
+ fp->un.fmt7.effaddr, fp->un.fmt7.ssw, fp->un.fmt7.faddr);
+ printk("wb 1 stat/addr/data: %04x %08lx %08lx\n",
+ fp->un.fmt7.wb1s, fp->un.fmt7.wb1a, fp->un.fmt7.wb1dpd0);
+ printk("wb 2 stat/addr/data: %04x %08lx %08lx\n",
+ fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d);
+ printk("wb 3 stat/addr/data: %04x %08lx %08lx\n",
+ fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d);
+ printk("push data: %08lx %08lx %08lx %08lx\n",
+ fp->un.fmt7.wb1dpd0, fp->un.fmt7.pd1, fp->un.fmt7.pd2,
+ fp->un.fmt7.pd3);
+ addr += sizeof(fp->un.fmt7);
+ break;
case 0x9:
- printk("instr addr=%08lx\n", fp->un.fmt9.iaddr);
- addr += sizeof(fp->un.fmt9);
- break;
+ printk("instr addr=%08lx\n", fp->un.fmt9.iaddr);
+ addr += sizeof(fp->un.fmt9);
+ break;
case 0xa:
- printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
- fp->un.fmta.ssw, fp->un.fmta.isc, fp->un.fmta.isb,
- fp->un.fmta.daddr, fp->un.fmta.dobuf);
- addr += sizeof(fp->un.fmta);
- break;
+ printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
+ fp->un.fmta.ssw, fp->un.fmta.isc, fp->un.fmta.isb,
+ fp->un.fmta.daddr, fp->un.fmta.dobuf);
+ addr += sizeof(fp->un.fmta);
+ break;
case 0xb:
- printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
- fp->un.fmtb.ssw, fp->un.fmtb.isc, fp->un.fmtb.isb,
- fp->un.fmtb.daddr, fp->un.fmtb.dobuf);
- printk("baddr=%08lx dibuf=%08lx ver=%x\n",
- fp->un.fmtb.baddr, fp->un.fmtb.dibuf, fp->un.fmtb.ver);
- addr += sizeof(fp->un.fmtb);
- break;
+ printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
+ fp->un.fmtb.ssw, fp->un.fmtb.isc, fp->un.fmtb.isb,
+ fp->un.fmtb.daddr, fp->un.fmtb.dobuf);
+ printk("baddr=%08lx dibuf=%08lx ver=%x\n",
+ fp->un.fmtb.baddr, fp->un.fmtb.dibuf, fp->un.fmtb.ver);
+ addr += sizeof(fp->un.fmtb);
+ break;
default:
- printk("\n");
+ printk("\n");
}
show_stack(NULL, (unsigned long *)addr);
- printk("Code: ");
- for (i = 0; i < 10; i++)
- printk("%04x ", 0xffff & ((short *) fp->ptregs.pc)[i]);
+ printk("Code:");
+ set_fs(KERNEL_DS);
+ cp = (u16 *)regs->pc;
+ for (i = -8; i < 16; i++) {
+ if (get_user(c, cp + i) && i >= 0) {
+ printk(" Bad PC value.");
+ break;
+ }
+ printk(i ? " %04x" : " <%04x>", c);
+ }
+ set_fs(old_fs);
printk ("\n");
}
void show_stack(struct task_struct *task, unsigned long *stack)
{
+ unsigned long *p;
unsigned long *endstack;
int i;
@@ -1004,12 +985,13 @@ void show_stack(struct task_struct *task, unsigned long *stack)
endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) & -THREAD_SIZE);
printk("Stack from %08lx:", (unsigned long)stack);
+ p = stack;
for (i = 0; i < kstack_depth_to_print; i++) {
- if (stack + 1 > endstack)
+ if (p + 1 > endstack)
break;
if (i % 8 == 0)
printk("\n ");
- printk(" %08lx", *stack++);
+ printk(" %08lx", *p++);
}
printk("\n");
show_trace(stack);
@@ -1188,19 +1170,7 @@ void die_if_kernel (char *str, struct pt_regs *fp, int nr)
console_verbose();
printk("%s: %08x\n",str,nr);
- print_modules();
- printk("PC: [<%08lx>]",fp->pc);
- print_symbol(" %s\n", fp->pc);
- printk("\nSR: %04x SP: %p a2: %08lx\n",
- fp->sr, fp, fp->a2);
- printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
- fp->d0, fp->d1, fp->d2, fp->d3);
- printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",
- fp->d4, fp->d5, fp->a0, fp->a1);
-
- printk("Process %s (pid: %d, stackpage=%08lx)\n",
- current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
- show_stack(NULL, (unsigned long *)fp);
+ show_registers(fp);
do_exit(SIGSEGV);
}
diff --git a/arch/m68k/lib/Makefile b/arch/m68k/lib/Makefile
index ebe51a5..6bbf19f 100644
--- a/arch/m68k/lib/Makefile
+++ b/arch/m68k/lib/Makefile
@@ -4,5 +4,5 @@
EXTRA_AFLAGS := -traditional
-lib-y := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
- checksum.o string.o semaphore.o
+lib-y := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
+ checksum.o string.o semaphore.o uaccess.o
diff --git a/arch/m68k/lib/uaccess.c b/arch/m68k/lib/uaccess.c
new file mode 100644
index 0000000..1bc188c
--- /dev/null
+++ b/arch/m68k/lib/uaccess.c
@@ -0,0 +1,222 @@
+/*
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+unsigned long __generic_copy_from_user(void *to, const void __user *from,
+ unsigned long n)
+{
+ unsigned long tmp, res;
+
+ asm volatile ("\n"
+ " tst.l %0\n"
+ " jeq 2f\n"
+ "1: moves.l (%1)+,%3\n"
+ " move.l %3,(%2)+\n"
+ " subq.l #1,%0\n"
+ " jne 1b\n"
+ "2: btst #1,%5\n"
+ " jeq 4f\n"
+ "3: moves.w (%1)+,%3\n"
+ " move.w %3,(%2)+\n"
+ "4: btst #0,%5\n"
+ " jeq 6f\n"
+ "5: moves.b (%1)+,%3\n"
+ " move.b %3,(%2)+\n"
+ "6:\n"
+ " .section .fixup,\"ax\"\n"
+ " .even\n"
+ "10: move.l %0,%3\n"
+ "7: clr.l (%2)+\n"
+ " subq.l #1,%3\n"
+ " jne 7b\n"
+ " lsl.l #2,%0\n"
+ " btst #1,%5\n"
+ " jeq 8f\n"
+ "30: clr.w (%2)+\n"
+ " addq.l #2,%0\n"
+ "8: btst #0,%5\n"
+ " jeq 6b\n"
+ "50: clr.b (%2)+\n"
+ " addq.l #1,%0\n"
+ " jra 6b\n"
+ " .previous\n"
+ "\n"
+ " .section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .long 1b,10b\n"
+ " .long 3b,30b\n"
+ " .long 5b,50b\n"
+ " .previous"
+ : "=d" (res), "+a" (from), "+a" (to), "=&r" (tmp)
+ : "0" (n / 4), "d" (n & 3));
+
+ return res;
+}
+EXPORT_SYMBOL(__generic_copy_from_user);
+
+unsigned long __generic_copy_to_user(void __user *to, const void *from,
+ unsigned long n)
+{
+ unsigned long tmp, res;
+
+ asm volatile ("\n"
+ " tst.l %0\n"
+ " jeq 4f\n"
+ "1: move.l (%1)+,%3\n"
+ "2: moves.l %3,(%2)+\n"
+ "3: subq.l #1,%0\n"
+ " jne 1b\n"
+ "4: btst #1,%5\n"
+ " jeq 6f\n"
+ " move.w (%1)+,%3\n"
+ "5: moves.w %3,(%2)+\n"
+ "6: btst #0,%5\n"
+ " jeq 8f\n"
+ " move.b (%1)+,%3\n"
+ "7: moves.b %3,(%2)+\n"
+ "8:\n"
+ " .section .fixup,\"ax\"\n"
+ " .even\n"
+ "20: lsl.l #2,%0\n"
+ "50: add.l %5,%0\n"
+ " jra 7b\n"
+ " .previous\n"
+ "\n"
+ " .section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .long 2b,20b\n"
+ " .long 3b,20b\n"
+ " .long 5b,50b\n"
+ " .long 6b,50b\n"
+ " .long 7b,50b\n"
+ " .long 8b,50b\n"
+ " .previous"
+ : "=d" (res), "+a" (from), "+a" (to), "=&r" (tmp)
+ : "0" (n / 4), "d" (n & 3));
+
+ return res;
+}
+EXPORT_SYMBOL(__generic_copy_to_user);
+
+/*
+ * Copy a null terminated string from userspace.
+ */
+long strncpy_from_user(char *dst, const char __user *src, long count)
+{
+ long res;
+ char c;
+
+ if (count <= 0)
+ return count;
+
+ asm volatile ("\n"
+ "1: moves.b (%2)+,%4\n"
+ " move.b %4,(%1)+\n"
+ " jeq 2f\n"
+ " subq.l #1,%3\n"
+ " jne 1b\n"
+ "2: sub.l %3,%0\n"
+ "3:\n"
+ " .section .fixup,\"ax\"\n"
+ " .even\n"
+ "10: move.l %5,%0\n"
+ " jra 3b\n"
+ " .previous\n"
+ "\n"
+ " .section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .long 1b,10b\n"
+ " .previous"
+ : "=d" (res), "+a" (dst), "+a" (src), "+r" (count), "=&d" (c)
+ : "i" (-EFAULT), "0" (count));
+
+ return res;
+}
+EXPORT_SYMBOL(strncpy_from_user);
+
+/*
+ * Return the size of a string (including the ending 0)
+ *
+ * Return 0 on exception, a value greater than N if too long
+ */
+long strnlen_user(const char __user *src, long n)
+{
+ char c;
+ long res;
+
+ asm volatile ("\n"
+ "1: subq.l #1,%1\n"
+ " jmi 3f\n"
+ "2: moves.b (%0)+,%2\n"
+ " tst.b %2\n"
+ " jne 1b\n"
+ " jra 4f\n"
+ "\n"
+ "3: addq.l #1,%0\n"
+ "4: sub.l %4,%0\n"
+ "5:\n"
+ " .section .fixup,\"ax\"\n"
+ " .even\n"
+ "20: sub.l %0,%0\n"
+ " jra 5b\n"
+ " .previous\n"
+ "\n"
+ " .section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .long 2b,20b\n"
+ " .previous\n"
+ : "=&a" (res), "+d" (n), "=&d" (c)
+ : "0" (src), "r" (src));
+
+ return res;
+}
+EXPORT_SYMBOL(strnlen_user);
+
+/*
+ * Zero Userspace
+ */
+
+unsigned long clear_user(void __user *to, unsigned long n)
+{
+ unsigned long res;
+
+ asm volatile ("\n"
+ " tst.l %0\n"
+ " jeq 3f\n"
+ "1: moves.l %2,(%1)+\n"
+ "2: subq.l #1,%0\n"
+ " jne 1b\n"
+ "3: btst #1,%4\n"
+ " jeq 5f\n"
+ "4: moves.w %2,(%1)+\n"
+ "5: btst #0,%4\n"
+ " jeq 7f\n"
+ "6: moves.b %2,(%1)\n"
+ "7:\n"
+ " .section .fixup,\"ax\"\n"
+ " .even\n"
+ "10: lsl.l #2,%0\n"
+ "40: add.l %4,%0\n"
+ " jra 7b\n"
+ " .previous\n"
+ "\n"
+ " .section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .long 1b,10b\n"
+ " .long 2b,10b\n"
+ " .long 4b,40b\n"
+ " .long 5b,40b\n"
+ " .long 6b,40b\n"
+ " .long 7b,40b\n"
+ " .previous"
+ : "=d" (res), "+a" (to)
+ : "r" (0), "0" (n / 4), "d" (n & 3));
+
+ return res;
+}
+EXPORT_SYMBOL(clear_user);
diff --git a/arch/m68k/mac/baboon.c b/arch/m68k/mac/baboon.c
index b19b7dd..6eaa881 100644
--- a/arch/m68k/mac/baboon.c
+++ b/arch/m68k/mac/baboon.c
@@ -81,7 +81,7 @@ irqreturn_t baboon_irq(int irq, void *dev_id, struct pt_regs *regs)
for (i = 0, irq_bit = 1 ; i < 3 ; i++, irq_bit <<= 1) {
if (events & irq_bit/* & baboon_active*/) {
baboon_active &= ~irq_bit;
- mac_do_irq_list(IRQ_BABOON_0 + i, regs);
+ m68k_handle_int(IRQ_BABOON_0 + i, regs);
baboon_active |= irq_bit;
baboon->mb_ifr &= ~irq_bit;
}
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index 14f8d3f4..5a9990e 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -89,38 +89,11 @@ extern void mac_debugging_long(int, long);
static void mac_get_model(char *str);
-void mac_bang(int irq, void *vector, struct pt_regs *p)
-{
- printk(KERN_INFO "Resetting ...\n");
- mac_reset();
-}
-
static void mac_sched_init(irqreturn_t (*vector)(int, void *, struct pt_regs *))
{
via_init_clock(vector);
}
-#if 0
-void mac_waitbut (void)
-{
- ;
-}
-#endif
-
-extern irqreturn_t mac_default_handler(int, void *, struct pt_regs *);
-
-irqreturn_t (*mac_handlers[8])(int, void *, struct pt_regs *)=
-{
- mac_default_handler,
- mac_default_handler,
- mac_default_handler,
- mac_default_handler,
- mac_default_handler,
- mac_default_handler,
- mac_default_handler,
- mac_default_handler
-};
-
/*
* Parse a Macintosh-specific record in the bootinfo
*/
@@ -196,13 +169,7 @@ void __init config_mac(void)
mach_sched_init = mac_sched_init;
mach_init_IRQ = mac_init_IRQ;
- mach_request_irq = mac_request_irq;
- mach_free_irq = mac_free_irq;
- enable_irq = mac_enable_irq;
- disable_irq = mac_disable_irq;
mach_get_model = mac_get_model;
- mach_default_handler = &mac_handlers;
- mach_get_irq_list = show_mac_interrupts;
mach_gettimeoffset = mac_gettimeoffset;
#warning move to adb/via init
#if 0
diff --git a/arch/m68k/mac/iop.c b/arch/m68k/mac/iop.c
index 9179a37..4c8ece7 100644
--- a/arch/m68k/mac/iop.c
+++ b/arch/m68k/mac/iop.c
@@ -317,7 +317,7 @@ void __init iop_register_interrupts(void)
{
if (iop_ism_present) {
if (oss_present) {
- cpu_request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq,
+ request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq,
IRQ_FLG_LOCK, "ISM IOP",
(void *) IOP_NUM_ISM);
oss_irq_enable(IRQ_MAC_ADB);
diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c
index 1809601..694b14b 100644
--- a/arch/m68k/mac/macints.c
+++ b/arch/m68k/mac/macints.c
@@ -137,14 +137,6 @@
#define DEBUG_SPURIOUS
#define SHUTUP_SONIC
-/*
- * The mac_irq_list array is an array of linked lists of irq_node_t nodes.
- * Each node contains one handler to be called whenever the interrupt
- * occurs, with fast handlers listed before slow handlers.
- */
-
-irq_node_t *mac_irq_list[NUM_MAC_SOURCES];
-
/* SCC interrupt mask */
static int scc_mask;
@@ -209,34 +201,37 @@ extern int baboon_irq_pending(int);
* SCC interrupt routines
*/
-static void scc_irq_enable(int);
-static void scc_irq_disable(int);
+static void scc_irq_enable(unsigned int);
+static void scc_irq_disable(unsigned int);
/*
* console_loglevel determines NMI handler function
*/
-extern irqreturn_t mac_bang(int, void *, struct pt_regs *);
irqreturn_t mac_nmi_handler(int, void *, struct pt_regs *);
irqreturn_t mac_debug_handler(int, void *, struct pt_regs *);
/* #define DEBUG_MACINTS */
+static void mac_enable_irq(unsigned int irq);
+static void mac_disable_irq(unsigned int irq);
+
+static struct irq_controller mac_irq_controller = {
+ .name = "mac",
+ .lock = SPIN_LOCK_UNLOCKED,
+ .enable = mac_enable_irq,
+ .disable = mac_disable_irq,
+};
+
void mac_init_IRQ(void)
{
- int i;
-
#ifdef DEBUG_MACINTS
printk("mac_init_IRQ(): Setting things up...\n");
#endif
- /* Initialize the IRQ handler lists. Initially each list is empty, */
-
- for (i = 0; i < NUM_MAC_SOURCES; i++) {
- mac_irq_list[i] = NULL;
- }
-
scc_mask = 0;
+ m68k_setup_irq_controller(&mac_irq_controller, IRQ_USER,
+ NUM_MAC_SOURCES - IRQ_USER);
/* Make sure the SONIC interrupt is cleared or things get ugly */
#ifdef SHUTUP_SONIC
printk("Killing onboard sonic... ");
@@ -253,15 +248,16 @@ void mac_init_IRQ(void)
* at levels 1-7. Most of the work is done elsewhere.
*/
- if (oss_present) {
+ if (oss_present)
oss_register_interrupts();
- } else {
+ else
via_register_interrupts();
- }
- if (psc_present) psc_register_interrupts();
- if (baboon_present) baboon_register_interrupts();
+ if (psc_present)
+ psc_register_interrupts();
+ if (baboon_present)
+ baboon_register_interrupts();
iop_register_interrupts();
- cpu_request_irq(7, mac_nmi_handler, IRQ_FLG_LOCK, "NMI",
+ request_irq(IRQ_AUTO_7, mac_nmi_handler, 0, "NMI",
mac_nmi_handler);
#ifdef DEBUG_MACINTS
printk("mac_init_IRQ(): Done!\n");
@@ -269,104 +265,6 @@ void mac_init_IRQ(void)
}
/*
- * Routines to work with irq_node_t's on linked lists lifted from
- * the Amiga code written by Roman Zippel.
- */
-
-static inline void mac_insert_irq(irq_node_t **list, irq_node_t *node)
-{
- unsigned long flags;
- irq_node_t *cur;
-
- if (!node->dev_id)
- printk("%s: Warning: dev_id of %s is zero\n",
- __FUNCTION__, node->devname);
-
- local_irq_save(flags);
-
- cur = *list;
-
- if (node->flags & IRQ_FLG_FAST) {
- node->flags &= ~IRQ_FLG_SLOW;
- while (cur && cur->flags & IRQ_FLG_FAST) {
- list = &cur->next;
- cur = cur->next;
- }
- } else if (node->flags & IRQ_FLG_SLOW) {
- while (cur) {
- list = &cur->next;
- cur = cur->next;
- }
- } else {
- while (cur && !(cur->flags & IRQ_FLG_SLOW)) {
- list = &cur->next;
- cur = cur->next;
- }
- }
-
- node->next = cur;
- *list = node;
-
- local_irq_restore(flags);
-}
-
-static inline void mac_delete_irq(irq_node_t **list, void *dev_id)
-{
- unsigned long flags;
- irq_node_t *node;
-
- local_irq_save(flags);
-
- for (node = *list; node; list = &node->next, node = *list) {
- if (node->dev_id == dev_id) {
- *list = node->next;
- /* Mark it as free. */
- node->handler = NULL;
- local_irq_restore(flags);
- return;
- }
- }
- local_irq_restore(flags);
- printk ("%s: tried to remove invalid irq\n", __FUNCTION__);
-}
-
-/*
- * Call all the handlers for a given interrupt. Fast handlers are called
- * first followed by slow handlers.
- *
- * This code taken from the original Amiga code written by Roman Zippel.
- */
-
-void mac_do_irq_list(int irq, struct pt_regs *fp)
-{
- irq_node_t *node, *slow_nodes;
- unsigned long flags;
-
- kstat_cpu(0).irqs[irq]++;
-
-#ifdef DEBUG_SPURIOUS
- if (!mac_irq_list[irq] && (console_loglevel > 7)) {
- printk("mac_do_irq_list: spurious interrupt %d!\n", irq);
- return;
- }
-#endif
-
- /* serve first fast and normal handlers */
- for (node = mac_irq_list[irq];
- node && (!(node->flags & IRQ_FLG_SLOW));
- node = node->next)
- node->handler(irq, node->dev_id, fp);
- if (!node) return;
- local_save_flags(flags);
- local_irq_restore((flags & ~0x0700) | (fp->sr & 0x0700));
- /* if slow handlers exists, serve them now */
- slow_nodes = node;
- for (; node; node = node->next) {
- node->handler(irq, node->dev_id, fp);
- }
-}
-
-/*
* mac_enable_irq - enable an interrupt source
* mac_disable_irq - disable an interrupt source
* mac_clear_irq - clears a pending interrupt
@@ -375,276 +273,124 @@ void mac_do_irq_list(int irq, struct pt_regs *fp)
* These routines are just dispatchers to the VIA/OSS/PSC routines.
*/
-void mac_enable_irq (unsigned int irq)
+static void mac_enable_irq(unsigned int irq)
{
- int irq_src = IRQ_SRC(irq);
+ int irq_src = IRQ_SRC(irq);
switch(irq_src) {
- case 1: via_irq_enable(irq);
- break;
- case 2:
- case 7: if (oss_present) {
- oss_irq_enable(irq);
- } else {
- via_irq_enable(irq);
- }
- break;
- case 3:
- case 4:
- case 5:
- case 6: if (psc_present) {
- psc_irq_enable(irq);
- } else if (oss_present) {
- oss_irq_enable(irq);
- } else if (irq_src == 4) {
- scc_irq_enable(irq);
- }
- break;
- case 8: if (baboon_present) {
- baboon_irq_enable(irq);
- }
- break;
+ case 1:
+ via_irq_enable(irq);
+ break;
+ case 2:
+ case 7:
+ if (oss_present)
+ oss_irq_enable(irq);
+ else
+ via_irq_enable(irq);
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ if (psc_present)
+ psc_irq_enable(irq);
+ else if (oss_present)
+ oss_irq_enable(irq);
+ else if (irq_src == 4)
+ scc_irq_enable(irq);
+ break;
+ case 8:
+ if (baboon_present)
+ baboon_irq_enable(irq);
+ break;
}
}
-void mac_disable_irq (unsigned int irq)
+static void mac_disable_irq(unsigned int irq)
{
- int irq_src = IRQ_SRC(irq);
+ int irq_src = IRQ_SRC(irq);
switch(irq_src) {
- case 1: via_irq_disable(irq);
- break;
- case 2:
- case 7: if (oss_present) {
- oss_irq_disable(irq);
- } else {
- via_irq_disable(irq);
- }
- break;
- case 3:
- case 4:
- case 5:
- case 6: if (psc_present) {
- psc_irq_disable(irq);
- } else if (oss_present) {
- oss_irq_disable(irq);
- } else if (irq_src == 4) {
- scc_irq_disable(irq);
- }
- break;
- case 8: if (baboon_present) {
- baboon_irq_disable(irq);
- }
- break;
+ case 1:
+ via_irq_disable(irq);
+ break;
+ case 2:
+ case 7:
+ if (oss_present)
+ oss_irq_disable(irq);
+ else
+ via_irq_disable(irq);
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ if (psc_present)
+ psc_irq_disable(irq);
+ else if (oss_present)
+ oss_irq_disable(irq);
+ else if (irq_src == 4)
+ scc_irq_disable(irq);
+ break;
+ case 8:
+ if (baboon_present)
+ baboon_irq_disable(irq);
+ break;
}
}
-void mac_clear_irq( unsigned int irq )
+void mac_clear_irq(unsigned int irq)
{
switch(IRQ_SRC(irq)) {
- case 1: via_irq_clear(irq);
- break;
- case 2:
- case 7: if (oss_present) {
- oss_irq_clear(irq);
- } else {
- via_irq_clear(irq);
- }
- break;
- case 3:
- case 4:
- case 5:
- case 6: if (psc_present) {
- psc_irq_clear(irq);
- } else if (oss_present) {
- oss_irq_clear(irq);
- }
- break;
- case 8: if (baboon_present) {
- baboon_irq_clear(irq);
- }
- break;
+ case 1:
+ via_irq_clear(irq);
+ break;
+ case 2:
+ case 7:
+ if (oss_present)
+ oss_irq_clear(irq);
+ else
+ via_irq_clear(irq);
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ if (psc_present)
+ psc_irq_clear(irq);
+ else if (oss_present)
+ oss_irq_clear(irq);
+ break;
+ case 8:
+ if (baboon_present)
+ baboon_irq_clear(irq);
+ break;
}
}
-int mac_irq_pending( unsigned int irq )
+int mac_irq_pending(unsigned int irq)
{
switch(IRQ_SRC(irq)) {
- case 1: return via_irq_pending(irq);
- case 2:
- case 7: if (oss_present) {
- return oss_irq_pending(irq);
- } else {
- return via_irq_pending(irq);
- }
- case 3:
- case 4:
- case 5:
- case 6: if (psc_present) {
- return psc_irq_pending(irq);
- } else if (oss_present) {
- return oss_irq_pending(irq);
- }
- }
- return 0;
-}
-
-/*
- * Add an interrupt service routine to an interrupt source.
- * Returns 0 on success.
- *
- * FIXME: You can register interrupts on nonexistent source (ie PSC4 on a
- * non-PSC machine). We should return -EINVAL in those cases.
- */
-
-int mac_request_irq(unsigned int irq,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
- unsigned long flags, const char *devname, void *dev_id)
-{
- irq_node_t *node;
-
-#ifdef DEBUG_MACINTS
- printk ("%s: irq %d requested for %s\n", __FUNCTION__, irq, devname);
-#endif
-
- if (irq < VIA1_SOURCE_BASE) {
- return cpu_request_irq(irq, handler, flags, devname, dev_id);
+ case 1:
+ return via_irq_pending(irq);
+ case 2:
+ case 7:
+ if (oss_present)
+ return oss_irq_pending(irq);
+ else
+ return via_irq_pending(irq);
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ if (psc_present)
+ return psc_irq_pending(irq);
+ else if (oss_present)
+ return oss_irq_pending(irq);
}
-
- if (irq >= NUM_MAC_SOURCES) {
- printk ("%s: unknown irq %d requested by %s\n",
- __FUNCTION__, irq, devname);
- }
-
- /* Get a node and stick it onto the right list */
-
- if (!(node = new_irq_node())) return -ENOMEM;
-
- node->handler = handler;
- node->flags = flags;
- node->dev_id = dev_id;
- node->devname = devname;
- node->next = NULL;
- mac_insert_irq(&mac_irq_list[irq], node);
-
- /* Now enable the IRQ source */
-
- mac_enable_irq(irq);
-
return 0;
}
-/*
- * Removes an interrupt service routine from an interrupt source.
- */
-
-void mac_free_irq(unsigned int irq, void *dev_id)
-{
-#ifdef DEBUG_MACINTS
- printk ("%s: irq %d freed by %p\n", __FUNCTION__, irq, dev_id);
-#endif
-
- if (irq < VIA1_SOURCE_BASE) {
- cpu_free_irq(irq, dev_id);
- return;
- }
-
- if (irq >= NUM_MAC_SOURCES) {
- printk ("%s: unknown irq %d freed\n",
- __FUNCTION__, irq);
- return;
- }
-
- mac_delete_irq(&mac_irq_list[irq], dev_id);
-
- /* If the list for this interrupt is */
- /* empty then disable the source. */
-
- if (!mac_irq_list[irq]) {
- mac_disable_irq(irq);
- }
-}
-
-/*
- * Generate a pretty listing for /proc/interrupts
- *
- * By the time we're called the autovector interrupt list has already been
- * generated, so we just need to do the machspec interrupts.
- *
- * 990506 (jmt) - rewritten to handle chained machspec interrupt handlers.
- * Also removed display of num_spurious it is already
- * displayed for us as autovector irq 0.
- */
-
-int show_mac_interrupts(struct seq_file *p, void *v)
-{
- int i;
- irq_node_t *node;
- char *base;
-
- /* Don't do Nubus interrupts in this loop; we do them separately */
- /* below so that we can print slot numbers instead of IRQ numbers */
-
- for (i = VIA1_SOURCE_BASE ; i < NUM_MAC_SOURCES ; ++i) {
-
- /* Nonexistant interrupt or nothing registered; skip it. */
-
- if ((node = mac_irq_list[i]) == NULL) continue;
- if (node->flags & IRQ_FLG_STD) continue;
-
- base = "";
- switch(IRQ_SRC(i)) {
- case 1: base = "via1";
- break;
- case 2: if (oss_present) {
- base = "oss";
- } else {
- base = "via2";
- }
- break;
- case 3:
- case 4:
- case 5:
- case 6: if (psc_present) {
- base = "psc";
- } else if (oss_present) {
- base = "oss";
- } else {
- if (IRQ_SRC(i) == 4) base = "scc";
- }
- break;
- case 7: base = "nbus";
- break;
- case 8: base = "bbn";
- break;
- }
- seq_printf(p, "%4s %2d: %10u ", base, i, kstat_cpu(0).irqs[i]);
-
- do {
- if (node->flags & IRQ_FLG_FAST) {
- seq_puts(p, "F ");
- } else if (node->flags & IRQ_FLG_SLOW) {
- seq_puts(p, "S ");
- } else {
- seq_puts(p, " ");
- }
- seq_printf(p, "%s\n", node->devname);
- if ((node = node->next)) {
- seq_puts(p, " ");
- }
- } while(node);
-
- }
- return 0;
-}
-
-void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs)
-{
-#ifdef DEBUG_SPURIOUS
- printk("Unexpected IRQ %d on device %p\n", irq, dev_id);
-#endif
-}
-
static int num_debug[8];
irqreturn_t mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs)
@@ -684,7 +430,7 @@ irqreturn_t mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
while (nmi_hold == 1)
udelay(1000);
- if ( console_loglevel >= 8 ) {
+ if (console_loglevel >= 8) {
#if 0
show_state();
printk("PC: %08lx\nSR: %04x SP: %p\n", fp->pc, fp->sr, fp);
@@ -713,14 +459,16 @@ irqreturn_t mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
* done in hardware (only the PSC can do that.)
*/
-static void scc_irq_enable(int irq) {
- int irq_idx = IRQ_IDX(irq);
+static void scc_irq_enable(unsigned int irq)
+{
+ int irq_idx = IRQ_IDX(irq);
scc_mask |= (1 << irq_idx);
}
-static void scc_irq_disable(int irq) {
- int irq_idx = IRQ_IDX(irq);
+static void scc_irq_disable(unsigned int irq)
+{
+ int irq_idx = IRQ_IDX(irq);
scc_mask &= ~(1 << irq_idx);
}
@@ -755,6 +503,8 @@ void mac_scc_dispatch(int irq, void *dev_id, struct pt_regs *regs)
/* and since they're autovector interrupts they */
/* pretty much kill the system. */
- if (reg & 0x38) mac_do_irq_list(IRQ_SCCA, regs);
- if (reg & 0x07) mac_do_irq_list(IRQ_SCCB, regs);
+ if (reg & 0x38)
+ m68k_handle_int(IRQ_SCCA, regs);
+ if (reg & 0x07)
+ m68k_handle_int(IRQ_SCCB, regs);
}
diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c
index 3335476..63e0436 100644
--- a/arch/m68k/mac/oss.c
+++ b/arch/m68k/mac/oss.c
@@ -67,15 +67,15 @@ void __init oss_init(void)
void __init oss_register_interrupts(void)
{
- cpu_request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK,
+ request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK,
"scsi", (void *) oss);
- cpu_request_irq(OSS_IRQLEV_IOPSCC, mac_scc_dispatch, IRQ_FLG_LOCK,
+ request_irq(OSS_IRQLEV_IOPSCC, mac_scc_dispatch, IRQ_FLG_LOCK,
"scc", mac_scc_dispatch);
- cpu_request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK,
+ request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK,
"nubus", (void *) oss);
- cpu_request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK,
+ request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK,
"sound", (void *) oss);
- cpu_request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK,
+ request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK,
"via1", (void *) via1);
}
@@ -113,7 +113,7 @@ irqreturn_t oss_irq(int irq, void *dev_id, struct pt_regs *regs)
oss->irq_pending &= ~OSS_IP_SOUND;
} else if (events & OSS_IP_SCSI) {
oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED;
- mac_do_irq_list(IRQ_MAC_SCSI, regs);
+ m68k_handle_int(IRQ_MAC_SCSI, regs);
oss->irq_pending &= ~OSS_IP_SCSI;
oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI;
} else {
@@ -146,7 +146,7 @@ irqreturn_t oss_nubus_irq(int irq, void *dev_id, struct pt_regs *regs)
for (i = 0, irq_bit = 1 ; i < 6 ; i++, irq_bit <<= 1) {
if (events & irq_bit) {
oss->irq_level[i] = OSS_IRQLEV_DISABLED;
- mac_do_irq_list(NUBUS_SOURCE_BASE + i, regs);
+ m68k_handle_int(NUBUS_SOURCE_BASE + i, regs);
oss->irq_pending &= ~irq_bit;
oss->irq_level[i] = OSS_IRQLEV_NUBUS;
}
diff --git a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c
index e72384e..e262180 100644
--- a/arch/m68k/mac/psc.c
+++ b/arch/m68k/mac/psc.c
@@ -117,10 +117,10 @@ void __init psc_init(void)
void __init psc_register_interrupts(void)
{
- cpu_request_irq(3, psc_irq, IRQ_FLG_LOCK, "psc3", (void *) 0x30);
- cpu_request_irq(4, psc_irq, IRQ_FLG_LOCK, "psc4", (void *) 0x40);
- cpu_request_irq(5, psc_irq, IRQ_FLG_LOCK, "psc5", (void *) 0x50);
- cpu_request_irq(6, psc_irq, IRQ_FLG_LOCK, "psc6", (void *) 0x60);
+ request_irq(IRQ_AUTO_3, psc_irq, 0, "psc3", (void *) 0x30);
+ request_irq(IRQ_AUTO_4, psc_irq, 0, "psc4", (void *) 0x40);
+ request_irq(IRQ_AUTO_5, psc_irq, 0, "psc5", (void *) 0x50);
+ request_irq(IRQ_AUTO_6, psc_irq, 0, "psc6", (void *) 0x60);
}
/*
@@ -149,7 +149,7 @@ irqreturn_t psc_irq(int irq, void *dev_id, struct pt_regs *regs)
for (i = 0, irq_bit = 1 ; i < 4 ; i++, irq_bit <<= 1) {
if (events & irq_bit) {
psc_write_byte(pIER, irq_bit);
- mac_do_irq_list(base_irq + i, regs);
+ m68k_handle_int(base_irq + i, regs);
psc_write_byte(pIFR, irq_bit);
psc_write_byte(pIER, irq_bit | 0x80);
}
diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c
index cd528bf..c4aa345 100644
--- a/arch/m68k/mac/via.c
+++ b/arch/m68k/mac/via.c
@@ -25,7 +25,6 @@
#include <linux/init.h>
#include <linux/ide.h>
-#include <asm/traps.h>
#include <asm/bootinfo.h>
#include <asm/macintosh.h>
#include <asm/macints.h>
@@ -71,7 +70,6 @@ void via_irq_enable(int irq);
void via_irq_disable(int irq);
void via_irq_clear(int irq);
-extern irqreturn_t mac_bang(int, void *, struct pt_regs *);
extern irqreturn_t mac_scc_dispatch(int, void *, struct pt_regs *);
extern int oss_present;
@@ -212,11 +210,6 @@ void __init via_init(void)
break;
}
#else
- /* The alernate IRQ mapping seems to just not work. Anyone with a */
- /* supported machine is welcome to take a stab at fixing it. It */
- /* _should_ work on the following Quadras: 610,650,700,800,900,950 */
- /* - 1999-06-12 (jmt) */
-
via_alt_mapping = 0;
#endif
@@ -260,27 +253,21 @@ void __init via_init_clock(irqreturn_t (*func)(int, void *, struct pt_regs *))
void __init via_register_interrupts(void)
{
if (via_alt_mapping) {
- cpu_request_irq(IRQ_AUTO_1, via1_irq,
+ request_irq(IRQ_AUTO_1, via1_irq,
IRQ_FLG_LOCK|IRQ_FLG_FAST, "software",
(void *) via1);
- cpu_request_irq(IRQ_AUTO_6, via1_irq,
+ request_irq(IRQ_AUTO_6, via1_irq,
IRQ_FLG_LOCK|IRQ_FLG_FAST, "via1",
(void *) via1);
} else {
- cpu_request_irq(IRQ_AUTO_1, via1_irq,
+ request_irq(IRQ_AUTO_1, via1_irq,
IRQ_FLG_LOCK|IRQ_FLG_FAST, "via1",
(void *) via1);
-#if 0 /* interferes with serial on some machines */
- if (!psc_present) {
- cpu_request_irq(IRQ_AUTO_6, mac_bang, IRQ_FLG_LOCK,
- "Off Switch", mac_bang);
- }
-#endif
}
- cpu_request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
+ request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
"via2", (void *) via2);
if (!psc_present) {
- cpu_request_irq(IRQ_AUTO_4, mac_scc_dispatch, IRQ_FLG_LOCK,
+ request_irq(IRQ_AUTO_4, mac_scc_dispatch, IRQ_FLG_LOCK,
"scc", mac_scc_dispatch);
}
request_irq(IRQ_MAC_NUBUS, via_nubus_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
@@ -437,7 +424,7 @@ irqreturn_t via1_irq(int irq, void *dev_id, struct pt_regs *regs)
for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1)
if (events & irq_bit) {
via1[vIER] = irq_bit;
- mac_do_irq_list(VIA1_SOURCE_BASE + i, regs);
+ m68k_handle_int(VIA1_SOURCE_BASE + i, regs);
via1[vIFR] = irq_bit;
via1[vIER] = irq_bit | 0x80;
}
@@ -452,7 +439,7 @@ irqreturn_t via1_irq(int irq, void *dev_id, struct pt_regs *regs)
/* No, it won't be set. that's why we're doing this. */
via_irq_disable(IRQ_MAC_NUBUS);
via_irq_clear(IRQ_MAC_NUBUS);
- mac_do_irq_list(IRQ_MAC_NUBUS, regs);
+ m68k_handle_int(IRQ_MAC_NUBUS, regs);
via_irq_enable(IRQ_MAC_NUBUS);
}
#endif
@@ -471,8 +458,8 @@ irqreturn_t via2_irq(int irq, void *dev_id, struct pt_regs *regs)
for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1)
if (events & irq_bit) {
via2[gIER] = irq_bit;
- mac_do_irq_list(VIA2_SOURCE_BASE + i, regs);
via2[gIFR] = irq_bit | rbv_clear;
+ m68k_handle_int(VIA2_SOURCE_BASE + i, regs);
via2[gIER] = irq_bit | 0x80;
}
return IRQ_HANDLED;
@@ -494,7 +481,7 @@ irqreturn_t via_nubus_irq(int irq, void *dev_id, struct pt_regs *regs)
for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) {
if (events & irq_bit) {
via_irq_disable(NUBUS_SOURCE_BASE + i);
- mac_do_irq_list(NUBUS_SOURCE_BASE + i, regs);
+ m68k_handle_int(NUBUS_SOURCE_BASE + i, regs);
via_irq_enable(NUBUS_SOURCE_BASE + i);
}
}
@@ -529,6 +516,7 @@ void via_irq_enable(int irq) {
}
via2[gIER] = irq_bit | 0x80;
} else if (irq_src == 7) {
+ nubus_active |= irq_bit;
if (rbv_present) {
/* enable the slot interrupt. SIER works like IER. */
via2[rSIER] = IER_SET_BIT(irq_idx);
@@ -550,7 +538,6 @@ void via_irq_enable(int irq) {
}
}
}
- nubus_active |= irq_bit;
}
}
diff --git a/arch/m68k/mm/kmap.c b/arch/m68k/mm/kmap.c
index 85ad19a..43ffab0 100644
--- a/arch/m68k/mm/kmap.c
+++ b/arch/m68k/mm/kmap.c
@@ -259,13 +259,15 @@ void __iounmap(void *addr, unsigned long size)
if (CPU_IS_020_OR_030) {
int pmd_off = (virtaddr/PTRTREESIZE) & 15;
+ int pmd_type = pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK;
- if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
+ if (pmd_type == _PAGE_PRESENT) {
pmd_dir->pmd[pmd_off] = 0;
virtaddr += PTRTREESIZE;
size -= PTRTREESIZE;
continue;
- }
+ } else if (pmd_type == 0)
+ continue;
}
if (pmd_bad(*pmd_dir)) {
diff --git a/arch/m68k/mm/motorola.c b/arch/m68k/mm/motorola.c
index afb57ee..bdb1110 100644
--- a/arch/m68k/mm/motorola.c
+++ b/arch/m68k/mm/motorola.c
@@ -203,7 +203,7 @@ void __init paging_init(void)
{
int chunk;
unsigned long mem_avail = 0;
- unsigned long zones_size[3] = { 0, };
+ unsigned long zones_size[MAX_NR_ZONES] = { 0, };
#ifdef DEBUG
{
@@ -257,12 +257,12 @@ void __init paging_init(void)
#ifdef DEBUG
printk ("before free_area_init\n");
#endif
- zones_size[0] = (mach_max_dma_address < (unsigned long)high_memory ?
- (mach_max_dma_address+1) : (unsigned long)high_memory);
- zones_size[1] = (unsigned long)high_memory - zones_size[0];
+ zones_size[ZONE_DMA] = (mach_max_dma_address < (unsigned long)high_memory ?
+ (mach_max_dma_address+1) : (unsigned long)high_memory);
+ zones_size[ZONE_NORMAL] = (unsigned long)high_memory - zones_size[0];
- zones_size[0] = (zones_size[0] - PAGE_OFFSET) >> PAGE_SHIFT;
- zones_size[1] >>= PAGE_SHIFT;
+ zones_size[ZONE_DMA] = (zones_size[ZONE_DMA] - PAGE_OFFSET) >> PAGE_SHIFT;
+ zones_size[ZONE_NORMAL] >>= PAGE_SHIFT;
free_area_init(zones_size);
}
diff --git a/arch/m68k/mm/sun3mmu.c b/arch/m68k/mm/sun3mmu.c
index a47be19..ac6640a 100644
--- a/arch/m68k/mm/sun3mmu.c
+++ b/arch/m68k/mm/sun3mmu.c
@@ -46,7 +46,7 @@ void __init paging_init(void)
unsigned long address;
unsigned long next_pgtable;
unsigned long bootmem_end;
- unsigned long zones_size[3] = {0, 0, 0};
+ unsigned long zones_size[MAX_NR_ZONES] = { 0, };
unsigned long size;
@@ -92,8 +92,7 @@ void __init paging_init(void)
current->mm = NULL;
/* memory sizing is a hack stolen from motorola.c.. hope it works for us */
- zones_size[0] = ((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT;
- zones_size[1] = 0;
+ zones_size[ZONE_DMA] = ((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT;
free_area_init(zones_size);
diff --git a/arch/m68k/mvme147/147ints.c b/arch/m68k/mvme147/147ints.c
deleted file mode 100644
index 69a744e..0000000
--- a/arch/m68k/mvme147/147ints.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * arch/m68k/mvme147/147ints.c
- *
- * Copyright (C) 1997 Richard Hirst [richard@sleepie.demon.co.uk]
- *
- * based on amiints.c -- Amiga Linux interrupt handling code
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file README.legal in the main directory of this archive
- * for more details.
- *
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/seq_file.h>
-
-#include <asm/ptrace.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/traps.h>
-
-static irqreturn_t mvme147_defhand (int irq, void *dev_id, struct pt_regs *fp);
-
-/*
- * This should ideally be 4 elements only, for speed.
- */
-
-static struct {
- irqreturn_t (*handler)(int, void *, struct pt_regs *);
- unsigned long flags;
- void *dev_id;
- const char *devname;
- unsigned count;
-} irq_tab[256];
-
-/*
- * void mvme147_init_IRQ (void)
- *
- * Parameters: None
- *
- * Returns: Nothing
- *
- * This function is called during kernel startup to initialize
- * the mvme147 IRQ handling routines.
- */
-
-void mvme147_init_IRQ (void)
-{
- int i;
-
- for (i = 0; i < 256; i++) {
- irq_tab[i].handler = mvme147_defhand;
- irq_tab[i].flags = IRQ_FLG_STD;
- irq_tab[i].dev_id = NULL;
- irq_tab[i].devname = NULL;
- irq_tab[i].count = 0;
- }
-}
-
-int mvme147_request_irq(unsigned int irq,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
- unsigned long flags, const char *devname, void *dev_id)
-{
- if (irq > 255) {
- printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
- return -ENXIO;
- }
- if (!(irq_tab[irq].flags & IRQ_FLG_STD)) {
- if (irq_tab[irq].flags & IRQ_FLG_LOCK) {
- printk("%s: IRQ %d from %s is not replaceable\n",
- __FUNCTION__, irq, irq_tab[irq].devname);
- return -EBUSY;
- }
- if (flags & IRQ_FLG_REPLACE) {
- printk("%s: %s can't replace IRQ %d from %s\n",
- __FUNCTION__, devname, irq, irq_tab[irq].devname);
- return -EBUSY;
- }
- }
- irq_tab[irq].handler = handler;
- irq_tab[irq].flags = flags;
- irq_tab[irq].dev_id = dev_id;
- irq_tab[irq].devname = devname;
- return 0;
-}
-
-void mvme147_free_irq(unsigned int irq, void *dev_id)
-{
- if (irq > 255) {
- printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
- return;
- }
- if (irq_tab[irq].dev_id != dev_id)
- printk("%s: Removing probably wrong IRQ %d from %s\n",
- __FUNCTION__, irq, irq_tab[irq].devname);
-
- irq_tab[irq].handler = mvme147_defhand;
- irq_tab[irq].flags = IRQ_FLG_STD;
- irq_tab[irq].dev_id = NULL;
- irq_tab[irq].devname = NULL;
-}
-
-irqreturn_t mvme147_process_int (unsigned long vec, struct pt_regs *fp)
-{
- if (vec > 255) {
- printk ("mvme147_process_int: Illegal vector %ld\n", vec);
- return IRQ_NONE;
- } else {
- irq_tab[vec].count++;
- irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp);
- return IRQ_HANDLED;
- }
-}
-
-int show_mvme147_interrupts (struct seq_file *p, void *v)
-{
- int i;
-
- for (i = 0; i < 256; i++) {
- if (irq_tab[i].count)
- seq_printf(p, "Vec 0x%02x: %8d %s\n",
- i, irq_tab[i].count,
- irq_tab[i].devname ? irq_tab[i].devname : "free");
- }
- return 0;
-}
-
-
-static irqreturn_t mvme147_defhand (int irq, void *dev_id, struct pt_regs *fp)
-{
- printk ("Unknown interrupt 0x%02x\n", irq);
- return IRQ_NONE;
-}
-
-void mvme147_enable_irq (unsigned int irq)
-{
-}
-
-
-void mvme147_disable_irq (unsigned int irq)
-{
-}
-
diff --git a/arch/m68k/mvme147/Makefile b/arch/m68k/mvme147/Makefile
index f0153ed..a36d38d 100644
--- a/arch/m68k/mvme147/Makefile
+++ b/arch/m68k/mvme147/Makefile
@@ -2,4 +2,4 @@
# Makefile for Linux arch/m68k/mvme147 source directory
#
-obj-y := config.o 147ints.o
+obj-y := config.o
diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c
index 0fcf972..0cd0e5b 100644
--- a/arch/m68k/mvme147/config.c
+++ b/arch/m68k/mvme147/config.c
@@ -36,15 +36,8 @@
#include <asm/mvme147hw.h>
-extern irqreturn_t mvme147_process_int (int level, struct pt_regs *regs);
-extern void mvme147_init_IRQ (void);
-extern void mvme147_free_irq (unsigned int, void *);
-extern int show_mvme147_interrupts (struct seq_file *, void *);
-extern void mvme147_enable_irq (unsigned int);
-extern void mvme147_disable_irq (unsigned int);
static void mvme147_get_model(char *model);
static int mvme147_get_hardware_list(char *buffer);
-extern int mvme147_request_irq (unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
extern void mvme147_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
extern unsigned long mvme147_gettimeoffset (void);
extern int mvme147_hwclk (int, struct rtc_time *);
@@ -91,6 +84,15 @@ static int mvme147_get_hardware_list(char *buffer)
return 0;
}
+/*
+ * This function is called during kernel startup to initialize
+ * the mvme147 IRQ handling routines.
+ */
+
+void mvme147_init_IRQ(void)
+{
+ m68k_setup_user_interrupt(VEC_USER, 192, NULL);
+}
void __init config_mvme147(void)
{
@@ -101,12 +103,6 @@ void __init config_mvme147(void)
mach_hwclk = mvme147_hwclk;
mach_set_clock_mmss = mvme147_set_clock_mmss;
mach_reset = mvme147_reset;
- mach_free_irq = mvme147_free_irq;
- mach_process_int = mvme147_process_int;
- mach_get_irq_list = show_mvme147_interrupts;
- mach_request_irq = mvme147_request_irq;
- enable_irq = mvme147_enable_irq;
- disable_irq = mvme147_disable_irq;
mach_get_model = mvme147_get_model;
mach_get_hardware_list = mvme147_get_hardware_list;
diff --git a/arch/m68k/mvme16x/16xints.c b/arch/m68k/mvme16x/16xints.c
deleted file mode 100644
index 793ef73..0000000
--- a/arch/m68k/mvme16x/16xints.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * arch/m68k/mvme16x/16xints.c
- *
- * Copyright (C) 1995 Richard Hirst [richard@sleepie.demon.co.uk]
- *
- * based on amiints.c -- Amiga Linux interrupt handling code
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file README.legal in the main directory of this archive
- * for more details.
- *
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/seq_file.h>
-
-#include <asm/system.h>
-#include <asm/ptrace.h>
-#include <asm/irq.h>
-
-static irqreturn_t mvme16x_defhand (int irq, void *dev_id, struct pt_regs *fp);
-
-/*
- * This should ideally be 4 elements only, for speed.
- */
-
-static struct {
- irqreturn_t (*handler)(int, void *, struct pt_regs *);
- unsigned long flags;
- void *dev_id;
- const char *devname;
- unsigned count;
-} irq_tab[192];
-
-/*
- * void mvme16x_init_IRQ (void)
- *
- * Parameters: None
- *
- * Returns: Nothing
- *
- * This function is called during kernel startup to initialize
- * the mvme16x IRQ handling routines. Should probably ensure
- * that the base vectors for the VMEChip2 and PCCChip2 are valid.
- */
-
-void mvme16x_init_IRQ (void)
-{
- int i;
-
- for (i = 0; i < 192; i++) {
- irq_tab[i].handler = mvme16x_defhand;
- irq_tab[i].flags = IRQ_FLG_STD;
- irq_tab[i].dev_id = NULL;
- irq_tab[i].devname = NULL;
- irq_tab[i].count = 0;
- }
-}
-
-int mvme16x_request_irq(unsigned int irq,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
- unsigned long flags, const char *devname, void *dev_id)
-{
- if (irq < 64 || irq > 255) {
- printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
- return -ENXIO;
- }
-
- if (!(irq_tab[irq-64].flags & IRQ_FLG_STD)) {
- if (irq_tab[irq-64].flags & IRQ_FLG_LOCK) {
- printk("%s: IRQ %d from %s is not replaceable\n",
- __FUNCTION__, irq, irq_tab[irq-64].devname);
- return -EBUSY;
- }
- if (flags & IRQ_FLG_REPLACE) {
- printk("%s: %s can't replace IRQ %d from %s\n",
- __FUNCTION__, devname, irq, irq_tab[irq-64].devname);
- return -EBUSY;
- }
- }
- irq_tab[irq-64].handler = handler;
- irq_tab[irq-64].flags = flags;
- irq_tab[irq-64].dev_id = dev_id;
- irq_tab[irq-64].devname = devname;
- return 0;
-}
-
-void mvme16x_free_irq(unsigned int irq, void *dev_id)
-{
- if (irq < 64 || irq > 255) {
- printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
- return;
- }
-
- if (irq_tab[irq-64].dev_id != dev_id)
- printk("%s: Removing probably wrong IRQ %d from %s\n",
- __FUNCTION__, irq, irq_tab[irq-64].devname);
-
- irq_tab[irq-64].handler = mvme16x_defhand;
- irq_tab[irq-64].flags = IRQ_FLG_STD;
- irq_tab[irq-64].dev_id = NULL;
- irq_tab[irq-64].devname = NULL;
-}
-
-irqreturn_t mvme16x_process_int (unsigned long vec, struct pt_regs *fp)
-{
- if (vec < 64 || vec > 255) {
- printk ("mvme16x_process_int: Illegal vector %ld", vec);
- return IRQ_NONE;
- } else {
- irq_tab[vec-64].count++;
- irq_tab[vec-64].handler(vec, irq_tab[vec-64].dev_id, fp);
- return IRQ_HANDLED;
- }
-}
-
-int show_mvme16x_interrupts (struct seq_file *p, void *v)
-{
- int i;
-
- for (i = 0; i < 192; i++) {
- if (irq_tab[i].count)
- seq_printf(p, "Vec 0x%02x: %8d %s\n",
- i+64, irq_tab[i].count,
- irq_tab[i].devname ? irq_tab[i].devname : "free");
- }
- return 0;
-}
-
-
-static irqreturn_t mvme16x_defhand (int irq, void *dev_id, struct pt_regs *fp)
-{
- printk ("Unknown interrupt 0x%02x\n", irq);
- return IRQ_NONE;
-}
-
-
-void mvme16x_enable_irq (unsigned int irq)
-{
-}
-
-
-void mvme16x_disable_irq (unsigned int irq)
-{
-}
-
-
diff --git a/arch/m68k/mvme16x/Makefile b/arch/m68k/mvme16x/Makefile
index 5129f56..950e82f 100644
--- a/arch/m68k/mvme16x/Makefile
+++ b/arch/m68k/mvme16x/Makefile
@@ -2,4 +2,4 @@
# Makefile for Linux arch/m68k/mvme16x source directory
#
-obj-y := config.o 16xints.o rtc.o mvme16x_ksyms.o
+obj-y := config.o rtc.o mvme16x_ksyms.o
diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c
index 26ce81c..ce2727e 100644
--- a/arch/m68k/mvme16x/config.c
+++ b/arch/m68k/mvme16x/config.c
@@ -40,15 +40,8 @@ extern t_bdid mvme_bdid;
static MK48T08ptr_t volatile rtc = (MK48T08ptr_t)MVME_RTC_BASE;
-extern irqreturn_t mvme16x_process_int (int level, struct pt_regs *regs);
-extern void mvme16x_init_IRQ (void);
-extern void mvme16x_free_irq (unsigned int, void *);
-extern int show_mvme16x_interrupts (struct seq_file *, void *);
-extern void mvme16x_enable_irq (unsigned int);
-extern void mvme16x_disable_irq (unsigned int);
static void mvme16x_get_model(char *model);
static int mvme16x_get_hardware_list(char *buffer);
-extern int mvme16x_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
extern void mvme16x_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
extern unsigned long mvme16x_gettimeoffset (void);
extern int mvme16x_hwclk (int, struct rtc_time *);
@@ -120,6 +113,16 @@ static int mvme16x_get_hardware_list(char *buffer)
return (len);
}
+/*
+ * This function is called during kernel startup to initialize
+ * the mvme16x IRQ handling routines. Should probably ensure
+ * that the base vectors for the VMEChip2 and PCCChip2 are valid.
+ */
+
+static void mvme16x_init_IRQ (void)
+{
+ m68k_setup_user_interrupt(VEC_USER, 192, NULL);
+}
#define pcc2chip ((volatile u_char *)0xfff42000)
#define PccSCCMICR 0x1d
@@ -138,12 +141,6 @@ void __init config_mvme16x(void)
mach_hwclk = mvme16x_hwclk;
mach_set_clock_mmss = mvme16x_set_clock_mmss;
mach_reset = mvme16x_reset;
- mach_free_irq = mvme16x_free_irq;
- mach_process_int = mvme16x_process_int;
- mach_get_irq_list = show_mvme16x_interrupts;
- mach_request_irq = mvme16x_request_irq;
- enable_irq = mvme16x_enable_irq;
- disable_irq = mvme16x_disable_irq;
mach_get_model = mvme16x_get_model;
mach_get_hardware_list = mvme16x_get_hardware_list;
diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
index 5e0f9b0..efa52d3 100644
--- a/arch/m68k/q40/config.c
+++ b/arch/m68k/q40/config.c
@@ -37,15 +37,9 @@
#include <asm/q40_master.h>
extern irqreturn_t q40_process_int (int level, struct pt_regs *regs);
-extern irqreturn_t (*q40_default_handler[]) (int, void *, struct pt_regs *); /* added just for debugging */
extern void q40_init_IRQ (void);
-extern void q40_free_irq (unsigned int, void *);
-extern int show_q40_interrupts (struct seq_file *, void *);
-extern void q40_enable_irq (unsigned int);
-extern void q40_disable_irq (unsigned int);
static void q40_get_model(char *model);
static int q40_get_hardware_list(char *buffer);
-extern int q40_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
extern void q40_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
extern unsigned long q40_gettimeoffset (void);
@@ -175,13 +169,6 @@ void __init config_q40(void)
mach_set_clock_mmss = q40_set_clock_mmss;
mach_reset = q40_reset;
- mach_free_irq = q40_free_irq;
- mach_process_int = q40_process_int;
- mach_get_irq_list = show_q40_interrupts;
- mach_request_irq = q40_request_irq;
- enable_irq = q40_enable_irq;
- disable_irq = q40_disable_irq;
- mach_default_handler = &q40_default_handler;
mach_get_model = q40_get_model;
mach_get_hardware_list = q40_get_hardware_list;
diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c
index f8ecc26..472f41c 100644
--- a/arch/m68k/q40/q40ints.c
+++ b/arch/m68k/q40/q40ints.c
@@ -14,13 +14,8 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/sched.h>
-#include <linux/seq_file.h>
#include <linux/interrupt.h>
-#include <linux/hardirq.h>
-#include <asm/rtc.h>
#include <asm/ptrace.h>
#include <asm/system.h>
#include <asm/irq.h>
@@ -39,29 +34,37 @@
*
*/
-extern int ints_inited;
+static void q40_irq_handler(unsigned int, struct pt_regs *fp);
+static void q40_enable_irq(unsigned int);
+static void q40_disable_irq(unsigned int);
+unsigned short q40_ablecount[35];
+unsigned short q40_state[35];
-irqreturn_t q40_irq2_handler (int, void *, struct pt_regs *fp);
-
-
-static irqreturn_t q40_defhand (int irq, void *dev_id, struct pt_regs *fp);
-static irqreturn_t default_handler(int lev, void *dev_id, struct pt_regs *regs);
-
-
-#define DEVNAME_SIZE 24
+static int q40_irq_startup(unsigned int irq)
+{
+ /* test for ISA ints not implemented by HW */
+ switch (irq) {
+ case 1: case 2: case 8: case 9:
+ case 11: case 12: case 13:
+ printk("%s: ISA IRQ %d not implemented by HW\n", __FUNCTION__, irq);
+ return -ENXIO;
+ }
+ return 0;
+}
-static struct q40_irq_node {
- irqreturn_t (*handler)(int, void *, struct pt_regs *);
- unsigned long flags;
- void *dev_id;
- /* struct q40_irq_node *next;*/
- char devname[DEVNAME_SIZE];
- unsigned count;
- unsigned short state;
-} irq_tab[Q40_IRQ_MAX+1];
+static void q40_irq_shutdown(unsigned int irq)
+{
+}
-short unsigned q40_ablecount[Q40_IRQ_MAX+1];
+static struct irq_controller q40_irq_controller = {
+ .name = "q40",
+ .lock = SPIN_LOCK_UNLOCKED,
+ .startup = q40_irq_startup,
+ .shutdown = q40_irq_shutdown,
+ .enable = q40_enable_irq,
+ .disable = q40_disable_irq,
+};
/*
* void q40_init_IRQ (void)
@@ -74,139 +77,29 @@ short unsigned q40_ablecount[Q40_IRQ_MAX+1];
* the q40 IRQ handling routines.
*/
-static int disabled=0;
+static int disabled;
-void q40_init_IRQ (void)
+void q40_init_IRQ(void)
{
- int i;
-
- disabled=0;
- for (i = 0; i <= Q40_IRQ_MAX; i++) {
- irq_tab[i].handler = q40_defhand;
- irq_tab[i].flags = 0;
- irq_tab[i].dev_id = NULL;
- /* irq_tab[i].next = NULL;*/
- irq_tab[i].devname[0] = 0;
- irq_tab[i].count = 0;
- irq_tab[i].state =0;
- q40_ablecount[i]=0; /* all enabled */
- }
+ m68k_setup_irq_controller(&q40_irq_controller, 1, Q40_IRQ_MAX);
/* setup handler for ISA ints */
- cpu_request_irq(IRQ2, q40_irq2_handler, 0, "q40 ISA and master chip",
- NULL);
+ m68k_setup_auto_interrupt(q40_irq_handler);
+
+ m68k_irq_startup(IRQ_AUTO_2);
+ m68k_irq_startup(IRQ_AUTO_4);
/* now enable some ints.. */
- master_outb(1,EXT_ENABLE_REG); /* ISA IRQ 5-15 */
+ master_outb(1, EXT_ENABLE_REG); /* ISA IRQ 5-15 */
/* make sure keyboard IRQ is disabled */
- master_outb(0,KEY_IRQ_ENABLE_REG);
+ master_outb(0, KEY_IRQ_ENABLE_REG);
}
-int q40_request_irq(unsigned int irq,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
- unsigned long flags, const char *devname, void *dev_id)
-{
- /*printk("q40_request_irq %d, %s\n",irq,devname);*/
-
- if (irq > Q40_IRQ_MAX || (irq>15 && irq<32)) {
- printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
- return -ENXIO;
- }
-
- /* test for ISA ints not implemented by HW */
- switch (irq)
- {
- case 1: case 2: case 8: case 9:
- case 12: case 13:
- printk("%s: ISA IRQ %d from %s not implemented by HW\n", __FUNCTION__, irq, devname);
- return -ENXIO;
- case 11:
- printk("warning IRQ 10 and 11 not distinguishable\n");
- irq=10;
- default:
- ;
- }
-
- if (irq<Q40_IRQ_SAMPLE)
- {
- if (irq_tab[irq].dev_id != NULL)
- {
- printk("%s: IRQ %d from %s is not replaceable\n",
- __FUNCTION__, irq, irq_tab[irq].devname);
- return -EBUSY;
- }
- /*printk("IRQ %d set to handler %p\n",irq,handler);*/
- if (dev_id==NULL)
- {
- printk("WARNING: dev_id == NULL in request_irq\n");
- dev_id=(void*)1;
- }
- irq_tab[irq].handler = handler;
- irq_tab[irq].flags = flags;
- irq_tab[irq].dev_id = dev_id;
- strlcpy(irq_tab[irq].devname,devname,sizeof(irq_tab[irq].devname));
- irq_tab[irq].state = 0;
- return 0;
- }
- else {
- /* Q40_IRQ_SAMPLE :somewhat special actions required here ..*/
- cpu_request_irq(4, handler, flags, devname, dev_id);
- cpu_request_irq(6, handler, flags, devname, dev_id);
- return 0;
- }
-}
-
-void q40_free_irq(unsigned int irq, void *dev_id)
-{
- if (irq > Q40_IRQ_MAX || (irq>15 && irq<32)) {
- printk("%s: Incorrect IRQ %d, dev_id %x \n", __FUNCTION__, irq, (unsigned)dev_id);
- return;
- }
-
- /* test for ISA ints not implemented by HW */
- switch (irq)
- {
- case 1: case 2: case 8: case 9:
- case 12: case 13:
- printk("%s: ISA IRQ %d from %x invalid\n", __FUNCTION__, irq, (unsigned)dev_id);
- return;
- case 11: irq=10;
- default:
- ;
- }
-
- if (irq<Q40_IRQ_SAMPLE)
- {
- if (irq_tab[irq].dev_id != dev_id)
- printk("%s: Removing probably wrong IRQ %d from %s\n",
- __FUNCTION__, irq, irq_tab[irq].devname);
-
- irq_tab[irq].handler = q40_defhand;
- irq_tab[irq].flags = 0;
- irq_tab[irq].dev_id = NULL;
- /* irq_tab[irq].devname = NULL; */
- /* do not reset state !! */
- }
- else
- { /* == Q40_IRQ_SAMPLE */
- cpu_free_irq(4, dev_id);
- cpu_free_irq(6, dev_id);
- }
-}
-
-
-irqreturn_t q40_process_int (int level, struct pt_regs *fp)
-{
- printk("unexpected interrupt vec=%x, pc=%lx, d0=%lx, d0_orig=%lx, d1=%lx, d2=%lx\n",
- level, fp->pc, fp->d0, fp->orig_d0, fp->d1, fp->d2);
- printk("\tIIRQ_REG = %x, EIRQ_REG = %x\n",master_inb(IIRQ_REG),master_inb(EIRQ_REG));
- return IRQ_HANDLED;
-}
/*
* this stuff doesn't really belong here..
-*/
+ */
int ql_ticks; /* 200Hz ticks since last jiffie */
static int sound_ticks;
@@ -215,54 +108,53 @@ static int sound_ticks;
void q40_mksound(unsigned int hz, unsigned int ticks)
{
- /* for now ignore hz, except that hz==0 switches off sound */
- /* simply alternate the ampl (128-SVOL)-(128+SVOL)-..-.. at 200Hz */
- if (hz==0)
- {
- if (sound_ticks)
- sound_ticks=1;
-
- *DAC_LEFT=128;
- *DAC_RIGHT=128;
-
- return;
- }
- /* sound itself is done in q40_timer_int */
- if (sound_ticks == 0) sound_ticks=1000; /* pretty long beep */
- sound_ticks=ticks<<1;
+ /* for now ignore hz, except that hz==0 switches off sound */
+ /* simply alternate the ampl (128-SVOL)-(128+SVOL)-..-.. at 200Hz */
+ if (hz == 0) {
+ if (sound_ticks)
+ sound_ticks = 1;
+
+ *DAC_LEFT = 128;
+ *DAC_RIGHT = 128;
+
+ return;
+ }
+ /* sound itself is done in q40_timer_int */
+ if (sound_ticks == 0)
+ sound_ticks = 1000; /* pretty long beep */
+ sound_ticks = ticks << 1;
}
static irqreturn_t (*q40_timer_routine)(int, void *, struct pt_regs *);
static irqreturn_t q40_timer_int (int irq, void * dev, struct pt_regs * regs)
{
- ql_ticks = ql_ticks ? 0 : 1;
- if (sound_ticks)
- {
- unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL;
- sound_ticks--;
- *DAC_LEFT=sval;
- *DAC_RIGHT=sval;
- }
-
- if (!ql_ticks)
- q40_timer_routine(irq, dev, regs);
- return IRQ_HANDLED;
+ ql_ticks = ql_ticks ? 0 : 1;
+ if (sound_ticks) {
+ unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL;
+ sound_ticks--;
+ *DAC_LEFT=sval;
+ *DAC_RIGHT=sval;
+ }
+
+ if (!ql_ticks)
+ q40_timer_routine(irq, dev, regs);
+ return IRQ_HANDLED;
}
void q40_sched_init (irqreturn_t (*timer_routine)(int, void *, struct pt_regs *))
{
- int timer_irq;
+ int timer_irq;
- q40_timer_routine = timer_routine;
- timer_irq=Q40_IRQ_FRAME;
+ q40_timer_routine = timer_routine;
+ timer_irq = Q40_IRQ_FRAME;
- if (request_irq(timer_irq, q40_timer_int, 0,
+ if (request_irq(timer_irq, q40_timer_int, 0,
"timer", q40_timer_int))
- panic ("Couldn't register timer int");
+ panic("Couldn't register timer int");
- master_outb(-1,FRAME_CLEAR_REG);
- master_outb( 1,FRAME_RATE_REG);
+ master_outb(-1, FRAME_CLEAR_REG);
+ master_outb( 1, FRAME_RATE_REG);
}
@@ -308,169 +200,132 @@ static int mext_disabled=0; /* ext irq disabled by master chip? */
static int aliased_irq=0; /* how many times inside handler ?*/
-/* got level 2 interrupt, dispatch to ISA or keyboard/timer IRQs */
-irqreturn_t q40_irq2_handler (int vec, void *devname, struct pt_regs *fp)
+/* got interrupt, dispatch to ISA or keyboard/timer IRQs */
+static void q40_irq_handler(unsigned int irq, struct pt_regs *fp)
{
- unsigned mir, mer;
- int irq,i;
+ unsigned mir, mer;
+ int i;
//repeat:
- mir=master_inb(IIRQ_REG);
- if (mir&Q40_IRQ_FRAME_MASK) {
- irq_tab[Q40_IRQ_FRAME].count++;
- irq_tab[Q40_IRQ_FRAME].handler(Q40_IRQ_FRAME,irq_tab[Q40_IRQ_FRAME].dev_id,fp);
- master_outb(-1,FRAME_CLEAR_REG);
- }
- if ((mir&Q40_IRQ_SER_MASK) || (mir&Q40_IRQ_EXT_MASK)) {
- mer=master_inb(EIRQ_REG);
- for (i=0; eirqs[i].mask; i++) {
- if (mer&(eirqs[i].mask)) {
- irq=eirqs[i].irq;
+ mir = master_inb(IIRQ_REG);
+#ifdef CONFIG_BLK_DEV_FD
+ if ((mir & Q40_IRQ_EXT_MASK) &&
+ (master_inb(EIRQ_REG) & Q40_IRQ6_MASK)) {
+ floppy_hardint();
+ return;
+ }
+#endif
+ switch (irq) {
+ case 4:
+ case 6:
+ m68k_handle_int(Q40_IRQ_SAMPLE, fp);
+ return;
+ }
+ if (mir & Q40_IRQ_FRAME_MASK) {
+ m68k_handle_int(Q40_IRQ_FRAME, fp);
+ master_outb(-1, FRAME_CLEAR_REG);
+ }
+ if ((mir & Q40_IRQ_SER_MASK) || (mir & Q40_IRQ_EXT_MASK)) {
+ mer = master_inb(EIRQ_REG);
+ for (i = 0; eirqs[i].mask; i++) {
+ if (mer & eirqs[i].mask) {
+ irq = eirqs[i].irq;
/*
* There is a little mess wrt which IRQ really caused this irq request. The
* main problem is that IIRQ_REG and EIRQ_REG reflect the state when they
* are read - which is long after the request came in. In theory IRQs should
* not just go away but they occassionally do
*/
- if (irq>4 && irq<=15 && mext_disabled) {
- /*aliased_irq++;*/
- goto iirq;
- }
- if (irq_tab[irq].handler == q40_defhand ) {
- printk("handler for IRQ %d not defined\n",irq);
- continue; /* ignore uninited INTs :-( */
- }
- if ( irq_tab[irq].state & IRQ_INPROGRESS ) {
- /* some handlers do local_irq_enable() for irq latency reasons, */
- /* however reentering an active irq handler is not permitted */
+ if (irq > 4 && irq <= 15 && mext_disabled) {
+ /*aliased_irq++;*/
+ goto iirq;
+ }
+ if (q40_state[irq] & IRQ_INPROGRESS) {
+ /* some handlers do local_irq_enable() for irq latency reasons, */
+ /* however reentering an active irq handler is not permitted */
#ifdef IP_USE_DISABLE
- /* in theory this is the better way to do it because it still */
- /* lets through eg the serial irqs, unfortunately it crashes */
- disable_irq(irq);
- disabled=1;
+ /* in theory this is the better way to do it because it still */
+ /* lets through eg the serial irqs, unfortunately it crashes */
+ disable_irq(irq);
+ disabled = 1;
#else
- /*printk("IRQ_INPROGRESS detected for irq %d, disabling - %s disabled\n",irq,disabled ? "already" : "not yet"); */
- fp->sr = (((fp->sr) & (~0x700))+0x200);
- disabled=1;
+ /*printk("IRQ_INPROGRESS detected for irq %d, disabling - %s disabled\n",
+ irq, disabled ? "already" : "not yet"); */
+ fp->sr = (((fp->sr) & (~0x700))+0x200);
+ disabled = 1;
#endif
- goto iirq;
- }
- irq_tab[irq].count++;
- irq_tab[irq].state |= IRQ_INPROGRESS;
- irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp);
- irq_tab[irq].state &= ~IRQ_INPROGRESS;
-
- /* naively enable everything, if that fails than */
- /* this function will be reentered immediately thus */
- /* getting another chance to disable the IRQ */
-
- if ( disabled ) {
+ goto iirq;
+ }
+ q40_state[irq] |= IRQ_INPROGRESS;
+ m68k_handle_int(irq, fp);
+ q40_state[irq] &= ~IRQ_INPROGRESS;
+
+ /* naively enable everything, if that fails than */
+ /* this function will be reentered immediately thus */
+ /* getting another chance to disable the IRQ */
+
+ if (disabled) {
#ifdef IP_USE_DISABLE
- if (irq>4){
- disabled=0;
- enable_irq(irq);}
+ if (irq > 4) {
+ disabled = 0;
+ enable_irq(irq);
+ }
#else
- disabled=0;
- /*printk("reenabling irq %d\n",irq); */
+ disabled = 0;
+ /*printk("reenabling irq %d\n", irq); */
#endif
- }
+ }
// used to do 'goto repeat;' here, this delayed bh processing too long
- return IRQ_HANDLED;
- }
- }
- if (mer && ccleirq>0 && !aliased_irq)
- printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer),ccleirq--;
- }
- iirq:
- mir=master_inb(IIRQ_REG);
- /* should test whether keyboard irq is really enabled, doing it in defhand */
- if (mir&Q40_IRQ_KEYB_MASK) {
- irq_tab[Q40_IRQ_KEYBOARD].count++;
- irq_tab[Q40_IRQ_KEYBOARD].handler(Q40_IRQ_KEYBOARD,irq_tab[Q40_IRQ_KEYBOARD].dev_id,fp);
- }
- return IRQ_HANDLED;
-}
-
-int show_q40_interrupts (struct seq_file *p, void *v)
-{
- int i;
-
- for (i = 0; i <= Q40_IRQ_MAX; i++) {
- if (irq_tab[i].count)
- seq_printf(p, "%sIRQ %02d: %8d %s%s\n",
- (i<=15) ? "ISA-" : " " ,
- i, irq_tab[i].count,
- irq_tab[i].devname[0] ? irq_tab[i].devname : "?",
- irq_tab[i].handler == q40_defhand ?
- " (now unassigned)" : "");
+ return;
+ }
+ }
+ if (mer && ccleirq > 0 && !aliased_irq) {
+ printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer);
+ ccleirq--;
+ }
}
- return 0;
-}
-
+ iirq:
+ mir = master_inb(IIRQ_REG);
+ /* should test whether keyboard irq is really enabled, doing it in defhand */
+ if (mir & Q40_IRQ_KEYB_MASK)
+ m68k_handle_int(Q40_IRQ_KEYBOARD, fp);
-static irqreturn_t q40_defhand (int irq, void *dev_id, struct pt_regs *fp)
-{
- if (irq!=Q40_IRQ_KEYBOARD)
- printk ("Unknown q40 interrupt %d\n", irq);
- else master_outb(-1,KEYBOARD_UNLOCK_REG);
- return IRQ_NONE;
+ return;
}
-static irqreturn_t default_handler(int lev, void *dev_id, struct pt_regs *regs)
-{
- printk ("Uninitialised interrupt level %d\n", lev);
- return IRQ_NONE;
-}
-
-irqreturn_t (*q40_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
- [0] = default_handler,
- [1] = default_handler,
- [2] = default_handler,
- [3] = default_handler,
- [4] = default_handler,
- [5] = default_handler,
- [6] = default_handler,
- [7] = default_handler
-};
-
-void q40_enable_irq (unsigned int irq)
+void q40_enable_irq(unsigned int irq)
{
- if ( irq>=5 && irq<=15 )
- {
- mext_disabled--;
- if (mext_disabled>0)
- printk("q40_enable_irq : nested disable/enable\n");
- if (mext_disabled==0)
- master_outb(1,EXT_ENABLE_REG);
- }
+ if (irq >= 5 && irq <= 15) {
+ mext_disabled--;
+ if (mext_disabled > 0)
+ printk("q40_enable_irq : nested disable/enable\n");
+ if (mext_disabled == 0)
+ master_outb(1, EXT_ENABLE_REG);
+ }
}
-void q40_disable_irq (unsigned int irq)
+void q40_disable_irq(unsigned int irq)
{
- /* disable ISA iqs : only do something if the driver has been
- * verified to be Q40 "compatible" - right now IDE, NE2K
- * Any driver should not attempt to sleep across disable_irq !!
- */
-
- if ( irq>=5 && irq<=15 ) {
- master_outb(0,EXT_ENABLE_REG);
- mext_disabled++;
- if (mext_disabled>1) printk("disable_irq nesting count %d\n",mext_disabled);
- }
+ /* disable ISA iqs : only do something if the driver has been
+ * verified to be Q40 "compatible" - right now IDE, NE2K
+ * Any driver should not attempt to sleep across disable_irq !!
+ */
+
+ if (irq >= 5 && irq <= 15) {
+ master_outb(0, EXT_ENABLE_REG);
+ mext_disabled++;
+ if (mext_disabled > 1)
+ printk("disable_irq nesting count %d\n",mext_disabled);
+ }
}
-unsigned long q40_probe_irq_on (void)
+unsigned long q40_probe_irq_on(void)
{
- printk("irq probing not working - reconfigure the driver to avoid this\n");
- return -1;
+ printk("irq probing not working - reconfigure the driver to avoid this\n");
+ return -1;
}
-int q40_probe_irq_off (unsigned long irqs)
+int q40_probe_irq_off(unsigned long irqs)
{
- return -1;
+ return -1;
}
-/*
- * Local variables:
- * compile-command: "m68k-linux-gcc -D__KERNEL__ -I/home/rz/lx/linux-2.2.6/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -m68040 -c -o q40ints.o q40ints.c"
- * End:
- */
diff --git a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c
index f1ca0df..553c304 100644
--- a/arch/m68k/sun3/config.c
+++ b/arch/m68k/sun3/config.c
@@ -36,7 +36,6 @@ extern char _text, _end;
char sun3_reserved_pmeg[SUN3_PMEGS_NUM];
extern unsigned long sun3_gettimeoffset(void);
-extern int show_sun3_interrupts (struct seq_file *, void *);
extern void sun3_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
extern void sun3_get_model (char* model);
extern void idprom_init (void);
@@ -147,13 +146,6 @@ void __init config_sun3(void)
mach_sched_init = sun3_sched_init;
mach_init_IRQ = sun3_init_IRQ;
- mach_default_handler = &sun3_default_handler;
- mach_request_irq = sun3_request_irq;
- mach_free_irq = sun3_free_irq;
- enable_irq = sun3_enable_irq;
- disable_irq = sun3_disable_irq;
- mach_process_int = sun3_process_int;
- mach_get_irq_list = show_sun3_interrupts;
mach_reset = sun3_reboot;
mach_gettimeoffset = sun3_gettimeoffset;
mach_get_model = sun3_get_model;
diff --git a/arch/m68k/sun3/sun3ints.c b/arch/m68k/sun3/sun3ints.c
index e62a033..0912435 100644
--- a/arch/m68k/sun3/sun3ints.c
+++ b/arch/m68k/sun3/sun3ints.c
@@ -19,7 +19,6 @@
#include <linux/seq_file.h>
extern void sun3_leds (unsigned char);
-static irqreturn_t sun3_inthandle(int irq, void *dev_id, struct pt_regs *fp);
void sun3_disable_interrupts(void)
{
@@ -40,48 +39,30 @@ int led_pattern[8] = {
volatile unsigned char* sun3_intreg;
-void sun3_insert_irq(irq_node_t **list, irq_node_t *node)
-{
-}
-
-void sun3_delete_irq(irq_node_t **list, void *dev_id)
-{
-}
-
void sun3_enable_irq(unsigned int irq)
{
- *sun3_intreg |= (1<<irq);
+ *sun3_intreg |= (1 << irq);
}
void sun3_disable_irq(unsigned int irq)
{
- *sun3_intreg &= ~(1<<irq);
-}
-
-inline void sun3_do_irq(int irq, struct pt_regs *fp)
-{
- kstat_cpu(0).irqs[SYS_IRQS + irq]++;
- *sun3_intreg &= ~(1<<irq);
- *sun3_intreg |= (1<<irq);
+ *sun3_intreg &= ~(1 << irq);
}
static irqreturn_t sun3_int7(int irq, void *dev_id, struct pt_regs *fp)
{
- sun3_do_irq(irq,fp);
- if(!(kstat_cpu(0).irqs[SYS_IRQS + irq] % 2000))
- sun3_leds(led_pattern[(kstat_cpu(0).irqs[SYS_IRQS+irq]%16000)
- /2000]);
+ *sun3_intreg |= (1 << irq);
+ if (!(kstat_cpu(0).irqs[irq] % 2000))
+ sun3_leds(led_pattern[(kstat_cpu(0).irqs[irq] % 16000) / 2000]);
return IRQ_HANDLED;
}
static irqreturn_t sun3_int5(int irq, void *dev_id, struct pt_regs *fp)
{
- kstat_cpu(0).irqs[SYS_IRQS + irq]++;
#ifdef CONFIG_SUN3
intersil_clear();
#endif
- *sun3_intreg &= ~(1<<irq);
- *sun3_intreg |= (1<<irq);
+ *sun3_intreg |= (1 << irq);
#ifdef CONFIG_SUN3
intersil_clear();
#endif
@@ -89,65 +70,8 @@ static irqreturn_t sun3_int5(int irq, void *dev_id, struct pt_regs *fp)
#ifndef CONFIG_SMP
update_process_times(user_mode(fp));
#endif
- if(!(kstat_cpu(0).irqs[SYS_IRQS + irq] % 20))
- sun3_leds(led_pattern[(kstat_cpu(0).irqs[SYS_IRQS+irq]%160)
- /20]);
- return IRQ_HANDLED;
-}
-
-/* handle requested ints, excepting 5 and 7, which always do the same
- thing */
-irqreturn_t (*sun3_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
- [0] = sun3_inthandle,
- [1] = sun3_inthandle,
- [2] = sun3_inthandle,
- [3] = sun3_inthandle,
- [4] = sun3_inthandle,
- [5] = sun3_int5,
- [6] = sun3_inthandle,
- [7] = sun3_int7
-};
-
-static const char *dev_names[SYS_IRQS] = {
- [5] = "timer",
- [7] = "int7 handler"
-};
-static void *dev_ids[SYS_IRQS];
-static irqreturn_t (*sun3_inthandler[SYS_IRQS])(int, void *, struct pt_regs *) = {
- [5] = sun3_int5,
- [7] = sun3_int7
-};
-static irqreturn_t (*sun3_vechandler[SUN3_INT_VECS])(int, void *, struct pt_regs *);
-static void *vec_ids[SUN3_INT_VECS];
-static const char *vec_names[SUN3_INT_VECS];
-static int vec_ints[SUN3_INT_VECS];
-
-
-int show_sun3_interrupts(struct seq_file *p, void *v)
-{
- int i;
-
- for(i = 0; i < (SUN3_INT_VECS-1); i++) {
- if(sun3_vechandler[i] != NULL) {
- seq_printf(p, "vec %3d: %10u %s\n", i+64,
- vec_ints[i],
- (vec_names[i]) ? vec_names[i] :
- "sun3_vechandler");
- }
- }
-
- return 0;
-}
-
-static irqreturn_t sun3_inthandle(int irq, void *dev_id, struct pt_regs *fp)
-{
- if(sun3_inthandler[irq] == NULL)
- panic ("bad interrupt %d received (id %p)\n",irq, dev_id);
-
- kstat_cpu(0).irqs[SYS_IRQS + irq]++;
- *sun3_intreg &= ~(1<<irq);
-
- sun3_inthandler[irq](irq, dev_ids[irq], fp);
+ if (!(kstat_cpu(0).irqs[irq] % 20))
+ sun3_leds(led_pattern[(kstat_cpu(0).irqs[irq] % 160) / 20]);
return IRQ_HANDLED;
}
@@ -157,109 +81,31 @@ static irqreturn_t sun3_vec255(int irq, void *dev_id, struct pt_regs *fp)
return IRQ_HANDLED;
}
-void sun3_init_IRQ(void)
+static void sun3_inthandle(unsigned int irq, struct pt_regs *fp)
{
- int i;
-
- *sun3_intreg = 1;
-
- for(i = 0; i < SYS_IRQS; i++)
- {
- if(dev_names[i])
- cpu_request_irq(i, sun3_default_handler[i], 0,
- dev_names[i], NULL);
- }
-
- for(i = 0; i < 192; i++)
- sun3_vechandler[i] = NULL;
-
- sun3_vechandler[191] = sun3_vec255;
-}
-
-int sun3_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
- unsigned long flags, const char *devname, void *dev_id)
-{
-
- if(irq < SYS_IRQS) {
- if(sun3_inthandler[irq] != NULL) {
- printk("sun3_request_irq: request for irq %d -- already taken!\n", irq);
- return 1;
- }
-
- sun3_inthandler[irq] = handler;
- dev_ids[irq] = dev_id;
- dev_names[irq] = devname;
-
- /* setting devname would be nice */
- cpu_request_irq(irq, sun3_default_handler[irq], 0, devname,
- NULL);
-
- return 0;
- } else {
- if((irq >= 64) && (irq <= 255)) {
- int vec;
-
- vec = irq - 64;
- if(sun3_vechandler[vec] != NULL) {
- printk("sun3_request_irq: request for vec %d -- already taken!\n", irq);
- return 1;
- }
-
- sun3_vechandler[vec] = handler;
- vec_ids[vec] = dev_id;
- vec_names[vec] = devname;
- vec_ints[vec] = 0;
-
- return 0;
- }
- }
-
- printk("sun3_request_irq: invalid irq %d\n", irq);
- return 1;
+ *sun3_intreg &= ~(1 << irq);
+ m68k_handle_int(irq, fp);
}
-void sun3_free_irq(unsigned int irq, void *dev_id)
-{
-
- if(irq < SYS_IRQS) {
- if(sun3_inthandler[irq] == NULL)
- panic("sun3_free_int: attempt to free unused irq %d\n", irq);
- if(dev_ids[irq] != dev_id)
- panic("sun3_free_int: incorrect dev_id for irq %d\n", irq);
-
- sun3_inthandler[irq] = NULL;
- return;
- } else if((irq >= 64) && (irq <= 255)) {
- int vec;
-
- vec = irq - 64;
- if(sun3_vechandler[vec] == NULL)
- panic("sun3_free_int: attempt to free unused vector %d\n", irq);
- if(vec_ids[irq] != dev_id)
- panic("sun3_free_int: incorrect dev_id for vec %d\n", irq);
-
- sun3_vechandler[vec] = NULL;
- return;
- } else {
- panic("sun3_free_irq: invalid irq %d\n", irq);
- }
-}
+static struct irq_controller sun3_irq_controller = {
+ .name = "sun3",
+ .lock = SPIN_LOCK_UNLOCKED,
+ .startup = m68k_irq_startup,
+ .shutdown = m68k_irq_shutdown,
+ .enable = sun3_enable_irq,
+ .disable = sun3_disable_irq,
+};
-irqreturn_t sun3_process_int(int irq, struct pt_regs *regs)
+void sun3_init_IRQ(void)
{
+ *sun3_intreg = 1;
- if((irq >= 64) && (irq <= 255)) {
- int vec;
-
- vec = irq - 64;
- if(sun3_vechandler[vec] == NULL)
- panic ("bad interrupt vector %d received\n",irq);
+ m68k_setup_auto_interrupt(sun3_inthandle);
+ m68k_setup_irq_controller(&sun3_irq_controller, IRQ_AUTO_1, 7);
+ m68k_setup_user_interrupt(VEC_USER, 192, NULL);
- vec_ints[vec]++;
- return sun3_vechandler[vec](irq, vec_ids[vec], regs);
- } else {
- panic("sun3_process_int: unable to handle interrupt vector %d\n",
- irq);
- }
+ request_irq(IRQ_AUTO_5, sun3_int5, 0, "int5", NULL);
+ request_irq(IRQ_AUTO_7, sun3_int7, 0, "int7", NULL);
+ request_irq(IRQ_USER+127, sun3_vec255, 0, "vec255", NULL);
}
diff --git a/arch/m68k/sun3x/config.c b/arch/m68k/sun3x/config.c
index 0920f5d..52fb174 100644
--- a/arch/m68k/sun3x/config.c
+++ b/arch/m68k/sun3x/config.c
@@ -52,17 +52,10 @@ void __init config_sun3x(void)
sun3x_prom_init();
- mach_get_irq_list = show_sun3_interrupts;
mach_max_dma_address = 0xffffffff; /* we can DMA anywhere, whee */
- mach_default_handler = &sun3_default_handler;
mach_sched_init = sun3x_sched_init;
mach_init_IRQ = sun3_init_IRQ;
- enable_irq = sun3_enable_irq;
- disable_irq = sun3_disable_irq;
- mach_request_irq = sun3_request_irq;
- mach_free_irq = sun3_free_irq;
- mach_process_int = sun3_process_int;
mach_gettimeoffset = sun3x_gettimeoffset;
mach_reset = sun3x_reboot;
diff --git a/arch/m68knommu/kernel/signal.c b/arch/m68knommu/kernel/signal.c
index e1b3aa3..8e2c5a8 100644
--- a/arch/m68knommu/kernel/signal.c
+++ b/arch/m68knommu/kernel/signal.c
@@ -553,7 +553,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
/* This is the X/Open sanctioned signal stack switching. */
if (ka->sa.sa_flags & SA_ONSTACK) {
- if (!on_sig_stack(usp))
+ if (!sas_ss_flags(usp))
usp = current->sas_ss_sp + current->sas_ss_size;
}
return (void *)((usp - frame_size) & -8UL);
diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c
index a9bf6cc..676e868 100644
--- a/arch/mips/kernel/irixsig.c
+++ b/arch/mips/kernel/irixsig.c
@@ -13,6 +13,7 @@
#include <linux/smp_lock.h>
#include <linux/time.h>
#include <linux/ptrace.h>
+#include <linux/resource.h>
#include <asm/ptrace.h>
#include <asm/uaccess.h>
@@ -540,8 +541,6 @@ out:
#define IRIX_P_PGID 2
#define IRIX_P_ALL 7
-extern int getrusage(struct task_struct *, int, struct rusage __user *);
-
#define W_EXITED 1
#define W_TRAPPED 2
#define W_STOPPED 4
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index a0ac0e5..2d2fdf7 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -497,7 +497,7 @@ einval: li v0, -EINVAL
sys sys_sched_get_priority_min 1
sys sys_sched_rr_get_interval 2 /* 4165 */
sys sys_nanosleep, 2
- sys sys_mremap, 4
+ sys sys_mremap, 5
sys sys_accept 3
sys sys_bind 3
sys sys_connect 3 /* 4170 */
diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
index 5407b78..1137dd6 100644
--- a/arch/mips/kernel/sysirix.c
+++ b/arch/mips/kernel/sysirix.c
@@ -31,6 +31,7 @@
#include <linux/socket.h>
#include <linux/security.h>
#include <linux/syscalls.h>
+#include <linux/resource.h>
#include <asm/ptrace.h>
#include <asm/page.h>
@@ -235,7 +236,6 @@ asmlinkage int irix_prctl(unsigned option, ...)
#undef DEBUG_PROCGRPS
extern unsigned long irix_mapelf(int fd, struct elf_phdr __user *user_phdrp, int cnt);
-extern int getrusage(struct task_struct *p, int who, struct rusage __user *ru);
extern char *prom_getenv(char *name);
extern long prom_setenv(char *name, char *value);
@@ -694,7 +694,7 @@ asmlinkage int irix_statfs(const char __user *path,
if (error)
goto out;
- error = vfs_statfs(nd.dentry->d_inode->i_sb, &kbuf);
+ error = vfs_statfs(nd.dentry, &kbuf);
if (error)
goto dput_and_out;
@@ -732,7 +732,7 @@ asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs __user *buf)
goto out;
}
- error = vfs_statfs(file->f_dentry->d_inode->i_sb, &kbuf);
+ error = vfs_statfs(file->f_dentry, &kbuf);
if (error)
goto out_f;
@@ -1360,7 +1360,7 @@ asmlinkage int irix_statvfs(char __user *fname, struct irix_statvfs __user *buf)
error = user_path_walk(fname, &nd);
if (error)
goto out;
- error = vfs_statfs(nd.dentry->d_inode->i_sb, &kbuf);
+ error = vfs_statfs(nd.dentry, &kbuf);
if (error)
goto dput_and_out;
@@ -1406,7 +1406,7 @@ asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs __user *buf)
error = -EBADF;
goto out;
}
- error = vfs_statfs(file->f_dentry->d_inode->i_sb, &kbuf);
+ error = vfs_statfs(file->f_dentry, &kbuf);
if (error)
goto out_f;
@@ -1611,7 +1611,7 @@ asmlinkage int irix_statvfs64(char __user *fname, struct irix_statvfs64 __user *
error = user_path_walk(fname, &nd);
if (error)
goto out;
- error = vfs_statfs(nd.dentry->d_inode->i_sb, &kbuf);
+ error = vfs_statfs(nd.dentry, &kbuf);
if (error)
goto dput_and_out;
@@ -1658,7 +1658,7 @@ asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs __user *buf)
error = -EBADF;
goto out;
}
- error = vfs_statfs(file->f_dentry->d_inode->i_sb, &kbuf);
+ error = vfs_statfs(file->f_dentry, &kbuf);
if (error)
goto out_f;
diff --git a/arch/parisc/hpux/sys_hpux.c b/arch/parisc/hpux/sys_hpux.c
index 05273cc..cb69727 100644
--- a/arch/parisc/hpux/sys_hpux.c
+++ b/arch/parisc/hpux/sys_hpux.c
@@ -145,7 +145,7 @@ static int hpux_ustat(dev_t dev, struct hpux_ustat __user *ubuf)
s = user_get_super(dev);
if (s == NULL)
goto out;
- err = vfs_statfs(s, &sbuf);
+ err = vfs_statfs(s->s_root, &sbuf);
drop_super(s);
if (err)
goto out;
@@ -186,12 +186,12 @@ struct hpux_statfs {
int16_t f_pad;
};
-static int vfs_statfs_hpux(struct super_block *sb, struct hpux_statfs *buf)
+static int vfs_statfs_hpux(struct dentry *dentry, struct hpux_statfs *buf)
{
struct kstatfs st;
int retval;
- retval = vfs_statfs(sb, &st);
+ retval = vfs_statfs(dentry, &st);
if (retval)
return retval;
@@ -219,7 +219,7 @@ asmlinkage long hpux_statfs(const char __user *path,
error = user_path_walk(path, &nd);
if (!error) {
struct hpux_statfs tmp;
- error = vfs_statfs_hpux(nd.dentry->d_inode->i_sb, &tmp);
+ error = vfs_statfs_hpux(nd.dentry, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
path_release(&nd);
@@ -237,7 +237,7 @@ asmlinkage long hpux_fstatfs(unsigned int fd, struct hpux_statfs __user * buf)
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs_hpux(file->f_dentry->d_inode->i_sb, &tmp);
+ error = vfs_statfs_hpux(file->f_dentry, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
fput(file);
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index 05767e8..cc38edf 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -248,7 +248,7 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
DBG(1,"get_sigframe: ka = %#lx, sp = %#lx, frame_size = %#lx\n",
(unsigned long)ka, sp, frame_size);
- if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp))
+ if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp))
sp = current->sas_ss_sp; /* Stacks grow up! */
DBG(1,"get_sigframe: Returning sp = %#lx\n", (unsigned long)sp);
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 6729c98..e922a88 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -45,6 +45,10 @@ config GENERIC_CALIBRATE_DELAY
bool
default y
+config GENERIC_FIND_NEXT_BIT
+ bool
+ default y
+
config PPC
bool
default y
@@ -137,6 +141,15 @@ config PPC_85xx
select FSL_SOC
select 85xx
+config PPC_86xx
+ bool "Freescale 86xx"
+ select 6xx
+ select FSL_SOC
+ select PPC_FPU
+ select ALTIVEC
+ help
+ The Freescale E600 SoCs have 74xx cores.
+
config 40x
bool "AMCC 40x"
@@ -336,7 +349,7 @@ endchoice
config PPC_PSERIES
depends on PPC_MULTIPLATFORM && PPC64
- bool " IBM pSeries & new (POWER5-based) iSeries"
+ bool "IBM pSeries & new (POWER5-based) iSeries"
select PPC_I8259
select PPC_RTAS
select RTAS_ERROR_LOGGING
@@ -344,7 +357,7 @@ config PPC_PSERIES
default y
config PPC_CHRP
- bool " Common Hardware Reference Platform (CHRP) based machines"
+ bool "Common Hardware Reference Platform (CHRP) based machines"
depends on PPC_MULTIPLATFORM && PPC32
select PPC_I8259
select PPC_INDIRECT_PCI
@@ -354,7 +367,7 @@ config PPC_CHRP
default y
config PPC_PMAC
- bool " Apple PowerMac based machines"
+ bool "Apple PowerMac based machines"
depends on PPC_MULTIPLATFORM
select PPC_INDIRECT_PCI if PPC32
select PPC_MPC106 if PPC32
@@ -370,7 +383,7 @@ config PPC_PMAC64
default y
config PPC_PREP
- bool " PowerPC Reference Platform (PReP) based machines"
+ bool "PowerPC Reference Platform (PReP) based machines"
depends on PPC_MULTIPLATFORM && PPC32 && BROKEN
select PPC_I8259
select PPC_INDIRECT_PCI
@@ -379,7 +392,7 @@ config PPC_PREP
config PPC_MAPLE
depends on PPC_MULTIPLATFORM && PPC64
- bool " Maple 970FX Evaluation Board"
+ bool "Maple 970FX Evaluation Board"
select U3_DART
select MPIC_BROKEN_U3
select GENERIC_TBSYNC
@@ -391,8 +404,18 @@ config PPC_MAPLE
For more informations, refer to <http://www.970eval.com>
config PPC_CELL
- bool " Cell Broadband Processor Architecture"
+ bool
+ default n
+
+config PPC_CELL_NATIVE
+ bool
+ select PPC_CELL
+ default n
+
+config PPC_IBM_CELL_BLADE
+ bool " IBM Cell Blade"
depends on PPC_MULTIPLATFORM && PPC64
+ select PPC_CELL_NATIVE
select PPC_RTAS
select MMIO_NVRAM
select PPC_UDBG_16550
@@ -439,11 +462,6 @@ config MPIC_BROKEN_U3
depends on PPC_MAPLE
default y
-config CELL_IIC
- depends on PPC_CELL
- bool
- default y
-
config IBMVIO
depends on PPC_PSERIES || PPC_ISERIES
bool
@@ -545,6 +563,7 @@ source arch/powerpc/platforms/embedded6xx/Kconfig
source arch/powerpc/platforms/4xx/Kconfig
source arch/powerpc/platforms/83xx/Kconfig
source arch/powerpc/platforms/85xx/Kconfig
+source arch/powerpc/platforms/86xx/Kconfig
source arch/powerpc/platforms/8xx/Kconfig
source arch/powerpc/platforms/cell/Kconfig
@@ -699,7 +718,6 @@ config PPC_64K_PAGES
config SCHED_SMT
bool "SMT (Hyperthreading) scheduler support"
depends on PPC64 && SMP
- default off
help
SMT scheduler support improves the CPU scheduler's decision making
when dealing with POWER5 cpus at a cost of slightly increased
@@ -776,6 +794,7 @@ config GENERIC_ISA_DMA
config PPC_I8259
bool
+ default y if MPC8641_HPCN
default n
config PPC_INDIRECT_PCI
@@ -798,8 +817,8 @@ config MCA
bool
config PCI
- bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_MPC52xx || (EMBEDDED && PPC_ISERIES)
- default y if !40x && !CPM2 && !8xx && !APUS && !PPC_83xx && !PPC_85xx
+ bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx || PPC_MPC52xx || (EMBEDDED && PPC_ISERIES)
+ default y if !40x && !CPM2 && !8xx && !APUS && !PPC_83xx && !PPC_85xx && !PPC_86xx
default PCI_PERMEDIA if !4xx && !CPM2 && !8xx && APUS
default PCI_QSPAN if !4xx && !CPM2 && 8xx
help
@@ -827,12 +846,12 @@ config PCI_8260
default y
config 8260_PCI9
- bool " Enable workaround for MPC826x erratum PCI 9"
+ bool "Enable workaround for MPC826x erratum PCI 9"
depends on PCI_8260 && !ADS8272
default y
choice
- prompt " IDMA channel for PCI 9 workaround"
+ prompt "IDMA channel for PCI 9 workaround"
depends on 8260_PCI9
config 8260_PCI9_IDMA1
@@ -849,6 +868,8 @@ config 8260_PCI9_IDMA4
endchoice
+source "drivers/pci/pcie/Kconfig"
+
source "drivers/pci/Kconfig"
source "drivers/pcmcia/Kconfig"
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
index 8d48e9e..c69006a 100644
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -110,13 +110,16 @@ config SERIAL_TEXT_DEBUG
depends on 4xx || LOPEC || MV64X60 || PPLUS || PRPMC800 || \
PPC_GEN550 || PPC_MPC52xx
+config PPC_EARLY_DEBUG
+ bool "Early debugging (dangerous)"
+
choice
- prompt "Early debugging (dangerous)"
- bool
- optional
+ prompt "Early debugging console"
+ depends on PPC_EARLY_DEBUG
help
- Enable early debugging. Careful, if you enable debugging for the
- wrong type of machine your kernel _will not boot_.
+ Use the selected console for early debugging. Careful, if you
+ enable debugging for the wrong type of machine your kernel
+ _will not boot_.
config PPC_EARLY_DEBUG_LPAR
bool "LPAR HV Console"
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index ed5b26a..01667d1 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -108,7 +108,6 @@ ifeq ($(CONFIG_6xx),y)
CFLAGS += -mcpu=powerpc
endif
-cpu-as-$(CONFIG_PPC64BRIDGE) += -Wa,-mppc64bridge
cpu-as-$(CONFIG_4xx) += -Wa,-m405
cpu-as-$(CONFIG_6xx) += -Wa,-maltivec
cpu-as-$(CONFIG_POWER4) += -Wa,-maltivec
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 840ae59..d961bfe 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -29,8 +29,8 @@ OBJCOPYFLAGS := contents,alloc,load,readonly,data
OBJCOPY_COFF_ARGS := -O aixcoff-rs6000 --set-start 0x500000
OBJCOPY_MIB_ARGS := -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment
-zlib := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c
-zlibheader := infblock.h infcodes.h inffast.h inftrees.h infutil.h
+zlib := inffast.c inflate.c inftrees.c
+zlibheader := inffast.h inffixed.h inflate.h inftrees.h infutil.h
zliblinuxheader := zlib.h zconf.h zutil.h
$(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
diff --git a/arch/powerpc/boot/main.c b/arch/powerpc/boot/main.c
index 816446f..b66634c 100644
--- a/arch/powerpc/boot/main.c
+++ b/arch/powerpc/boot/main.c
@@ -33,6 +33,14 @@ extern char _vmlinux_end[];
extern char _initrd_start[];
extern char _initrd_end[];
+/* A buffer that may be edited by tools operating on a zImage binary so as to
+ * edit the command line passed to vmlinux (by setting /chosen/bootargs).
+ * The buffer is put in it's own section so that tools may locate it easier.
+ */
+static char builtin_cmdline[512]
+ __attribute__((section("__builtin_cmdline")));
+
+
struct addr_range {
unsigned long addr;
unsigned long size;
@@ -204,6 +212,23 @@ static int is_elf32(void *hdr)
return 1;
}
+void export_cmdline(void* chosen_handle)
+{
+ int len;
+ char cmdline[2] = { 0, 0 };
+
+ if (builtin_cmdline[0] == 0)
+ return;
+
+ len = getprop(chosen_handle, "bootargs", cmdline, sizeof(cmdline));
+ if (len > 0 && cmdline[0] != 0)
+ return;
+
+ setprop(chosen_handle, "bootargs", builtin_cmdline,
+ strlen(builtin_cmdline) + 1);
+}
+
+
void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
{
int len;
@@ -289,6 +314,8 @@ void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
memmove((void *)vmlinux.addr,(void *)vmlinuz.addr,vmlinuz.size);
}
+ export_cmdline(chosen_handle);
+
/* Skip over the ELF header */
#ifdef DEBUG
printf("... skipping 0x%lx bytes of ELF header\n\r",
diff --git a/arch/powerpc/boot/prom.h b/arch/powerpc/boot/prom.h
index 3e2ddd4..a57b184 100644
--- a/arch/powerpc/boot/prom.h
+++ b/arch/powerpc/boot/prom.h
@@ -31,4 +31,11 @@ static inline int getprop(void *phandle, const char *name,
return call_prom("getprop", 4, 1, phandle, name, buf, buflen);
}
+
+static inline int setprop(void *phandle, const char *name,
+ void *buf, int buflen)
+{
+ return call_prom("setprop", 4, 1, phandle, name, buf, buflen);
+}
+
#endif /* _PPC_BOOT_PROM_H_ */
diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig
index dbe421d..b8b8d46 100644
--- a/arch/powerpc/configs/cell_defconfig
+++ b/arch/powerpc/configs/cell_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.16
-# Thu Mar 23 20:48:09 2006
+# Linux kernel version: 2.6.17
+# Mon Jun 19 17:23:03 2006
#
CONFIG_PPC64=y
CONFIG_64BIT=y
@@ -11,6 +11,7 @@ CONFIG_GENERIC_HARDIRQS=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_PPC=y
CONFIG_EARLY_PRINTK=y
CONFIG_COMPAT=y
@@ -55,7 +56,7 @@ CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
-# CONFIG_CPUSETS is not set
+CONFIG_CPUSETS=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -116,13 +117,15 @@ CONFIG_PPC_MULTIPLATFORM=y
# CONFIG_PPC_PMAC is not set
# CONFIG_PPC_MAPLE is not set
CONFIG_PPC_CELL=y
+CONFIG_PPC_CELL_NATIVE=y
+CONFIG_PPC_IBM_CELL_BLADE=y
+CONFIG_PPC_SYSTEMSIM=y
# CONFIG_U3_DART is not set
CONFIG_PPC_RTAS=y
# CONFIG_RTAS_ERROR_LOGGING is not set
CONFIG_RTAS_PROC=y
CONFIG_RTAS_FLASH=y
CONFIG_MMIO_NVRAM=y
-CONFIG_CELL_IIC=y
# CONFIG_PPC_MPC106 is not set
# CONFIG_PPC_970_NAP is not set
# CONFIG_CPU_FREQ is not set
@@ -132,7 +135,9 @@ CONFIG_CELL_IIC=y
# Cell Broadband Engine options
#
CONFIG_SPU_FS=m
+CONFIG_SPU_BASE=y
CONFIG_SPUFS_MMAP=y
+CONFIG_CBE_RAS=y
#
# Kernel options
@@ -152,20 +157,24 @@ CONFIG_FORCE_MAX_ZONEORDER=13
CONFIG_KEXEC=y
# CONFIG_CRASH_DUMP is not set
CONFIG_IRQ_ALL_CPUS=y
-# CONFIG_NUMA is not set
+CONFIG_NUMA=y
+CONFIG_NODES_SHIFT=4
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
-CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
CONFIG_SELECT_MEMORY_MODEL=y
# CONFIG_FLATMEM_MANUAL is not set
# CONFIG_DISCONTIGMEM_MANUAL is not set
CONFIG_SPARSEMEM_MANUAL=y
CONFIG_SPARSEMEM=y
+CONFIG_NEED_MULTIPLE_NODES=y
CONFIG_HAVE_MEMORY_PRESENT=y
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPARSEMEM_EXTREME=y
-# CONFIG_MEMORY_HOTPLUG is not set
+CONFIG_MEMORY_HOTPLUG=y
CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
+CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
+CONFIG_ARCH_MEMORY_PROBE=y
# CONFIG_PPC_64K_PAGES is not set
CONFIG_SCHED_SMT=y
CONFIG_PROC_DEVICETREE=y
@@ -182,6 +191,7 @@ CONFIG_GENERIC_ISA_DMA=y
# CONFIG_PPC_INDIRECT_PCI is not set
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
+CONFIG_PCIEPORTBUS=y
# CONFIG_PCI_DEBUG is not set
#
@@ -476,7 +486,7 @@ CONFIG_DM_MULTIPATH=m
#
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
+CONFIG_BONDING=y
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
@@ -624,6 +634,7 @@ CONFIG_SERIAL_NONSTANDARD=y
# CONFIG_N_HDLC is not set
# CONFIG_SPECIALIX is not set
# CONFIG_SX is not set
+# CONFIG_RIO is not set
# CONFIG_STALDRV is not set
#
@@ -766,6 +777,7 @@ CONFIG_I2C_ALGOBIT=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -1054,11 +1066,7 @@ CONFIG_DEBUGGER=y
# CONFIG_XMON is not set
CONFIG_IRQSTACKS=y
# CONFIG_BOOTX_TEXT is not set
-# CONFIG_PPC_EARLY_DEBUG_LPAR is not set
-# CONFIG_PPC_EARLY_DEBUG_G5 is not set
-# CONFIG_PPC_EARLY_DEBUG_RTAS is not set
-# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set
-# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
#
# Security options
diff --git a/arch/powerpc/configs/mpc85xx_cds_defconfig b/arch/powerpc/configs/mpc85xx_cds_defconfig
new file mode 100644
index 0000000..9bb022a
--- /dev/null
+++ b/arch/powerpc/configs/mpc85xx_cds_defconfig
@@ -0,0 +1,846 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.16
+# Sun Apr 2 11:23:42 2006
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+# CONFIG_DEFAULT_UIMAGE is not set
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 is not set
+# CONFIG_PPC_52xx is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PPC_83xx is not set
+CONFIG_PPC_85xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_85xx=y
+CONFIG_E500=y
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_SPE=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_MPIC=y
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Platform support
+#
+# CONFIG_MPC8540_ADS is not set
+CONFIG_MPC85xx_CDS=y
+CONFIG_MPC8540=y
+CONFIG_PPC_INDIRECT_PCI_BE=y
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+CONFIG_MATH_EMULATION=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+# CONFIG_SECCOMP is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_PPC_I8259=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_DEBUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+# CONFIG_BLK_DEV_IDEDISK is not set
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+CONFIG_E1000_NAPI=y
+# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+CONFIG_GFAR_NAPI=y
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_UNWIND_INFO is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUGGER is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG_LPAR is not set
+# CONFIG_PPC_EARLY_DEBUG_G5 is not set
+# CONFIG_PPC_EARLY_DEBUG_RTAS is not set
+# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set
+# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/powerpc/configs/mpc8641_hpcn_defconfig b/arch/powerpc/configs/mpc8641_hpcn_defconfig
new file mode 100644
index 0000000..d7a30f9
--- /dev/null
+++ b/arch/powerpc/configs/mpc8641_hpcn_defconfig
@@ -0,0 +1,921 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.17-rc3
+# Fri Jun 16 10:47:09 2006
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_PPC_UDBG_16550=y
+CONFIG_GENERIC_TBSYNC=y
+# CONFIG_DEFAULT_UIMAGE is not set
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 is not set
+# CONFIG_PPC_52xx is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PPC_83xx is not set
+# CONFIG_PPC_85xx is not set
+CONFIG_PPC_86xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_6xx=y
+CONFIG_PPC_FPU=y
+CONFIG_ALTIVEC=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+# CONFIG_SYSVIPC is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_CPUSETS is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+# CONFIG_SLAB is not set
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_SLOB=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+CONFIG_MPIC=y
+# CONFIG_WANT_EARLY_SERIAL is not set
+CONFIG_PPC_INDIRECT_PCI_BE=y
+
+#
+# Platform Support
+#
+CONFIG_MPC8641_HPCN=y
+CONFIG_MPC8641=y
+
+#
+# Kernel options
+#
+CONFIG_HIGHMEM=y
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_BKL=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_IRQ_ALL_CPUS is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SECCOMP is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PPC_I8259=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_DEBUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=131072
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+CONFIG_VITESSE_PHY=y
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+# CONFIG_GFAR_NAPI is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+CONFIG_SENSORS_EEPROM=y
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+# CONFIG_NFSD_V3 is not set
+CONFIG_NFSD_TCP=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+CONFIG_LDM_PARTITION=y
+# CONFIG_LDM_DEBUG is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_UNWIND_INFO is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUGGER is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG_LPAR is not set
+# CONFIG_PPC_EARLY_DEBUG_G5 is not set
+# CONFIG_PPC_EARLY_DEBUG_RTAS is not set
+# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set
+# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/powerpc/configs/pmac32_defconfig b/arch/powerpc/configs/pmac32_defconfig
index 57a0279..addc793 100644
--- a/arch/powerpc/configs/pmac32_defconfig
+++ b/arch/powerpc/configs/pmac32_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.16-rc6
-# Wed Mar 15 16:21:32 2006
+# Linux kernel version: 2.6.17-rc5
+# Mon May 29 14:47:49 2006
#
# CONFIG_PPC64 is not set
CONFIG_PPC32=y
@@ -9,6 +9,7 @@ CONFIG_PPC_MERGE=y
CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_PPC=y
CONFIG_EARLY_PRINTK=y
@@ -27,11 +28,11 @@ CONFIG_CLASSIC32=y
# CONFIG_PPC_52xx is not set
# CONFIG_PPC_82xx is not set
# CONFIG_PPC_83xx is not set
+# CONFIG_PPC_85xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_8xx is not set
# CONFIG_E200 is not set
-# CONFIG_E500 is not set
CONFIG_6xx=y
CONFIG_PPC_FPU=y
CONFIG_ALTIVEC=y
@@ -59,6 +60,7 @@ CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
+# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_EMBEDDED is not set
@@ -73,10 +75,6 @@ CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
CONFIG_SLAB=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
@@ -88,7 +86,6 @@ CONFIG_BASE_SMALL=0
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_OBSOLETE_MODPARM=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
@@ -97,6 +94,8 @@ CONFIG_KMOD=y
# Block layer
#
CONFIG_LBD=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+CONFIG_LSF=y
#
# IO Schedulers
@@ -124,6 +123,7 @@ CONFIG_MPIC=y
# CONFIG_PPC_RTAS is not set
# CONFIG_MMIO_NVRAM is not set
CONFIG_PPC_MPC106=y
+# CONFIG_PPC_970_NAP is not set
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_TABLE=y
# CONFIG_CPU_FREQ_DEBUG is not set
@@ -182,7 +182,6 @@ CONFIG_GENERIC_ISA_DMA=y
CONFIG_PPC_INDIRECT_PCI=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
-CONFIG_PCI_LEGACY_PROC=y
# CONFIG_PCI_DEBUG is not set
#
@@ -239,7 +238,9 @@ CONFIG_NET=y
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
@@ -250,9 +251,10 @@ CONFIG_IP_FIB_HASH=y
# CONFIG_IP_MROUTE is not set
# CONFIG_ARPD is not set
CONFIG_SYN_COOKIES=y
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
# CONFIG_INET_TUNNEL is not set
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
@@ -264,6 +266,8 @@ CONFIG_TCP_CONG_BIC=y
#
# CONFIG_IP_VS is not set
# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
CONFIG_NETFILTER=y
# CONFIG_NETFILTER_DEBUG is not set
@@ -278,12 +282,15 @@ CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
CONFIG_NETFILTER_XT_MATCH_COMMENT=m
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
CONFIG_NETFILTER_XT_MATCH_MAC=m
CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
CONFIG_NETFILTER_XT_MATCH_REALM=m
CONFIG_NETFILTER_XT_MATCH_SCTP=m
@@ -305,15 +312,15 @@ CONFIG_IP_NF_NETBIOS_NS=m
CONFIG_IP_NF_TFTP=m
CONFIG_IP_NF_AMANDA=m
CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_H323=m
# CONFIG_IP_NF_QUEUE is not set
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_IPRANGE=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
CONFIG_IP_NF_MATCH_TOS=m
CONFIG_IP_NF_MATCH_RECENT=m
CONFIG_IP_NF_MATCH_ECN=m
CONFIG_IP_NF_MATCH_DSCP=m
-CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_TTL=m
CONFIG_IP_NF_MATCH_OWNER=m
CONFIG_IP_NF_MATCH_ADDRTYPE=m
@@ -335,6 +342,7 @@ CONFIG_IP_NF_NAT_FTP=m
CONFIG_IP_NF_NAT_TFTP=m
CONFIG_IP_NF_NAT_AMANDA=m
CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_NAT_H323=m
CONFIG_IP_NF_MANGLE=m
CONFIG_IP_NF_TARGET_TOS=m
CONFIG_IP_NF_TARGET_ECN=m
@@ -350,10 +358,12 @@ CONFIG_IP_NF_ARP_MANGLE=m
#
CONFIG_IP_DCCP=m
CONFIG_INET_DCCP_DIAG=m
+CONFIG_IP_DCCP_ACKVEC=y
#
# DCCP CCIDs Configuration (EXPERIMENTAL)
#
+CONFIG_IP_DCCP_CCID2=m
CONFIG_IP_DCCP_CCID3=m
CONFIG_IP_DCCP_TFRC_LIB=m
@@ -361,7 +371,6 @@ CONFIG_IP_DCCP_TFRC_LIB=m
# DCCP Kernel Hacking
#
# CONFIG_IP_DCCP_DEBUG is not set
-# CONFIG_IP_DCCP_UNLOAD_HACK is not set
#
# SCTP Configuration (EXPERIMENTAL)
@@ -477,6 +486,8 @@ CONFIG_IEEE80211=m
CONFIG_IEEE80211_CRYPT_WEP=m
CONFIG_IEEE80211_CRYPT_CCMP=m
CONFIG_IEEE80211_CRYPT_TKIP=m
+# CONFIG_IEEE80211_SOFTMAC is not set
+CONFIG_WIRELESS_EXT=y
#
# Device Drivers
@@ -662,9 +673,8 @@ CONFIG_SCSI_SYM53C8XX_2=y
CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+CONFIG_SCSI_SYM53C8XX_MMIO=y
# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
# CONFIG_SCSI_QLA_FC is not set
# CONFIG_SCSI_LPFC is not set
@@ -694,16 +704,17 @@ CONFIG_BLK_DEV_MD=m
CONFIG_MD_LINEAR=m
CONFIG_MD_RAID0=m
CONFIG_MD_RAID1=m
-# CONFIG_MD_RAID10 is not set
+CONFIG_MD_RAID10=m
CONFIG_MD_RAID5=m
+CONFIG_MD_RAID5_RESHAPE=y
CONFIG_MD_RAID6=m
CONFIG_MD_MULTIPATH=m
CONFIG_MD_FAULTY=m
CONFIG_BLK_DEV_DM=m
CONFIG_DM_CRYPT=m
-# CONFIG_DM_SNAPSHOT is not set
-# CONFIG_DM_MIRROR is not set
-# CONFIG_DM_ZERO is not set
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
# CONFIG_DM_MULTIPATH is not set
#
@@ -740,7 +751,7 @@ CONFIG_IEEE1394_OHCI1394=m
CONFIG_IEEE1394_VIDEO1394=m
CONFIG_IEEE1394_SBP2=m
# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
-CONFIG_IEEE1394_ETH1394=m
+# CONFIG_IEEE1394_ETH1394 is not set
CONFIG_IEEE1394_DV1394=m
CONFIG_IEEE1394_RAWIO=m
@@ -769,10 +780,10 @@ CONFIG_THERM_ADT746X=m
# Network device support
#
CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
+CONFIG_DUMMY=m
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
+CONFIG_TUN=m
#
# ARCnet devices
@@ -857,6 +868,7 @@ CONFIG_PCNET32=y
# Wireless LAN (non-hamradio)
#
CONFIG_NET_RADIO=y
+# CONFIG_NET_WIRELESS_RTNETLINK is not set
#
# Obsolete Wireless cards support (pre-802.11)
@@ -992,6 +1004,7 @@ CONFIG_HW_CONSOLE=y
# Serial drivers
#
CONFIG_SERIAL_8250=m
+CONFIG_SERIAL_8250_PCI=m
# CONFIG_SERIAL_8250_CS is not set
CONFIG_SERIAL_8250_NR_UARTS=4
CONFIG_SERIAL_8250_RUNTIME_UARTS=4
@@ -1027,6 +1040,7 @@ CONFIG_GEN_RTC=y
# Ftape, the floppy tape device driver
#
CONFIG_AGP=m
+# CONFIG_AGP_VIA is not set
CONFIG_AGP_UNINORTH=m
CONFIG_DRM=m
# CONFIG_DRM_TDFX is not set
@@ -1081,7 +1095,6 @@ CONFIG_I2C_POWERMAC=y
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PROSAVAGE is not set
# CONFIG_I2C_SAVAGE4 is not set
-# CONFIG_SCx200_ACB is not set
# CONFIG_I2C_SIS5595 is not set
# CONFIG_I2C_SIS630 is not set
# CONFIG_I2C_SIS96X is not set
@@ -1100,10 +1113,8 @@ CONFIG_I2C_POWERMAC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_RTC8564 is not set
# CONFIG_SENSORS_M41T00 is not set
# CONFIG_SENSORS_MAX6875 is not set
-# CONFIG_RTC_X1205_I2C is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
@@ -1131,18 +1142,16 @@ CONFIG_I2C_POWERMAC=y
#
#
-# Multimedia Capabilities Port drivers
-#
-
-#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
#
# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
#
# Graphics support
@@ -1152,6 +1161,7 @@ CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
CONFIG_FB_MACMODES=y
+CONFIG_FB_FIRMWARE_EDID=y
CONFIG_FB_MODE_HELPERS=y
CONFIG_FB_TILEBLITTING=y
# CONFIG_FB_CIRRUS is not set
@@ -1175,7 +1185,6 @@ CONFIG_FB_MATROX_MYSTIQUE=y
# CONFIG_FB_MATROX_G is not set
# CONFIG_FB_MATROX_I2C is not set
# CONFIG_FB_MATROX_MULTIHEAD is not set
-# CONFIG_FB_RADEON_OLD is not set
CONFIG_FB_RADEON=y
CONFIG_FB_RADEON_I2C=y
# CONFIG_FB_RADEON_DEBUG is not set
@@ -1234,9 +1243,11 @@ CONFIG_SND_SEQ_DUMMY=m
CONFIG_SND_OSSEMUL=y
CONFIG_SND_MIXER_OSS=m
CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
CONFIG_SND_SEQUENCER_OSS=y
# CONFIG_SND_DYNAMIC_MINORS is not set
CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
# CONFIG_SND_VERBOSE_PRINTK is not set
# CONFIG_SND_DEBUG is not set
@@ -1253,6 +1264,7 @@ CONFIG_SND_DUMMY=m
# PCI devices
#
# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS300 is not set
# CONFIG_SND_ALS4000 is not set
# CONFIG_SND_ALI5451 is not set
# CONFIG_SND_ATIIXP is not set
@@ -1285,6 +1297,7 @@ CONFIG_SND_DUMMY=m
# CONFIG_SND_MIXART is not set
# CONFIG_SND_NM256 is not set
# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RIPTIDE is not set
# CONFIG_SND_RME32 is not set
# CONFIG_SND_RME96 is not set
# CONFIG_SND_RME9652 is not set
@@ -1310,6 +1323,8 @@ CONFIG_SND_USB_AUDIO=m
#
# PCMCIA devices
#
+# CONFIG_SND_VXPOCKET is not set
+# CONFIG_SND_PDAUDIOCF is not set
#
# Open Sound System
@@ -1321,6 +1336,7 @@ CONFIG_SND_USB_AUDIO=m
#
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
CONFIG_USB=y
# CONFIG_USB_DEBUG is not set
@@ -1336,7 +1352,9 @@ CONFIG_USB_DYNAMIC_MINORS=y
#
# USB Host Controller Drivers
#
-# CONFIG_USB_EHCI_HCD is not set
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_EHCI_SPLIT_ISO=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
# CONFIG_USB_ISP116X_HCD is not set
CONFIG_USB_OHCI_HCD=y
# CONFIG_USB_OHCI_BIG_ENDIAN is not set
@@ -1347,7 +1365,6 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
#
# USB Device Class drivers
#
-# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
CONFIG_USB_ACM=m
CONFIG_USB_PRINTER=m
@@ -1358,7 +1375,17 @@ CONFIG_USB_PRINTER=m
#
# may also be needed; see USB_STORAGE Help for more information
#
-# CONFIG_USB_STORAGE is not set
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
# CONFIG_USB_LIBUSUAL is not set
#
@@ -1374,9 +1401,7 @@ CONFIG_USB_HIDINPUT_POWERBOOK=y
# CONFIG_USB_ACECAD is not set
# CONFIG_USB_KBTAB is not set
# CONFIG_USB_POWERMATE is not set
-# CONFIG_USB_MTOUCH is not set
-# CONFIG_USB_ITMTOUCH is not set
-# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_TOUCHSCREEN is not set
# CONFIG_USB_YEALINK is not set
# CONFIG_USB_XPAD is not set
# CONFIG_USB_ATI_REMOTE is not set
@@ -1391,15 +1416,6 @@ CONFIG_USB_APPLETOUCH=y
# CONFIG_USB_MICROTEK is not set
#
-# USB Multimedia devices
-#
-# CONFIG_USB_DABUSB is not set
-
-#
-# Video4Linux support is needed for USB Multimedia device support
-#
-
-#
# USB Network Adapters
#
# CONFIG_USB_CATC is not set
@@ -1429,6 +1445,7 @@ CONFIG_USB_SERIAL=m
# CONFIG_USB_SERIAL_GENERIC is not set
# CONFIG_USB_SERIAL_AIRPRIME is not set
# CONFIG_USB_SERIAL_ANYDATA is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
# CONFIG_USB_SERIAL_BELKIN is not set
# CONFIG_USB_SERIAL_WHITEHEAT is not set
# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
@@ -1436,6 +1453,7 @@ CONFIG_USB_SERIAL=m
# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
# CONFIG_USB_SERIAL_EMPEG is not set
# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_FUNSOFT is not set
CONFIG_USB_SERIAL_VISOR=m
CONFIG_USB_SERIAL_IPAQ=m
# CONFIG_USB_SERIAL_IR is not set
@@ -1460,6 +1478,7 @@ CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
# CONFIG_USB_SERIAL_KLSI is not set
# CONFIG_USB_SERIAL_KOBIL_SCT is not set
# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
# CONFIG_USB_SERIAL_PL2303 is not set
# CONFIG_USB_SERIAL_HP4X is not set
# CONFIG_USB_SERIAL_SAFE is not set
@@ -1484,6 +1503,7 @@ CONFIG_USB_EZUSB=y
# CONFIG_USB_PHIDGETKIT is not set
# CONFIG_USB_PHIDGETSERVO is not set
# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
# CONFIG_USB_TEST is not set
@@ -1502,6 +1522,19 @@ CONFIG_USB_EZUSB=y
# CONFIG_MMC is not set
#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
# InfiniBand support
#
# CONFIG_INFINIBAND is not set
@@ -1511,6 +1544,11 @@ CONFIG_USB_EZUSB=y
#
#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -1518,14 +1556,14 @@ CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
+CONFIG_EXT3_FS_POSIX_ACL=y
# CONFIG_EXT3_FS_SECURITY is not set
CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
-# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FS_POSIX_ACL=y
# CONFIG_XFS_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
@@ -1534,7 +1572,7 @@ CONFIG_INOTIFY=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
+CONFIG_AUTOFS4_FS=m
CONFIG_FUSE_FS=m
#
@@ -1566,7 +1604,6 @@ CONFIG_SYSFS=y
CONFIG_TMPFS=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
-CONFIG_RELAYFS_FS=m
# CONFIG_CONFIGFS_FS is not set
#
@@ -1590,17 +1627,24 @@ CONFIG_HFSPLUS_FS=m
# Network File Systems
#
CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
# CONFIG_NFS_DIRECTIO is not set
-CONFIG_NFSD=y
-# CONFIG_NFSD_V3 is not set
-# CONFIG_NFSD_TCP is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V2_ACL=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
CONFIG_LOCKD=y
-CONFIG_EXPORTFS=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_ACL_SUPPORT=y
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
# CONFIG_RPCSEC_GSS_SPKM3 is not set
CONFIG_SMB_FS=m
# CONFIG_SMB_NLS_DEFAULT is not set
@@ -1681,7 +1725,7 @@ CONFIG_NLS_UTF8=m
CONFIG_CRC_CCITT=y
CONFIG_CRC16=y
CONFIG_CRC32=y
-# CONFIG_LIBCRC32C is not set
+CONFIG_LIBCRC32C=m
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_TEXTSEARCH=y
@@ -1735,29 +1779,29 @@ CONFIG_BOOTX_TEXT=y
# Cryptographic options
#
CONFIG_CRYPTO=y
-# CONFIG_CRYPTO_HMAC is not set
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_MD4 is not set
-# CONFIG_CRYPTO_MD5 is not set
-# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_WP512 is not set
-# CONFIG_CRYPTO_TGR192 is not set
-# CONFIG_CRYPTO_DES is not set
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_AES=m
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_ARC4=m
-# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_DEFLATE is not set
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
CONFIG_CRYPTO_MICHAEL_MIC=m
-# CONFIG_CRYPTO_CRC32C is not set
+CONFIG_CRYPTO_CRC32C=m
# CONFIG_CRYPTO_TEST is not set
#
diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig
index 58e68ce..31708ad 100644
--- a/arch/powerpc/configs/pseries_defconfig
+++ b/arch/powerpc/configs/pseries_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.17-rc1
-# Wed Apr 19 11:48:00 2006
+# Linux kernel version: 2.6.17-rc4
+# Sun May 28 07:26:56 2006
#
CONFIG_PPC64=y
CONFIG_64BIT=y
@@ -11,6 +11,7 @@ CONFIG_GENERIC_HARDIRQS=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_PPC=y
CONFIG_EARLY_PRINTK=y
CONFIG_COMPAT=y
@@ -126,8 +127,9 @@ CONFIG_RTAS_PROC=y
CONFIG_RTAS_FLASH=m
# CONFIG_MMIO_NVRAM is not set
CONFIG_IBMVIO=y
-# CONFIG_IBMEBUS is not set
+CONFIG_IBMEBUS=y
# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
# CONFIG_CPU_FREQ is not set
# CONFIG_WANT_EARLY_SERIAL is not set
@@ -143,7 +145,7 @@ CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT is not set
# CONFIG_PREEMPT_BKL is not set
CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_MISC=m
CONFIG_FORCE_MAX_ZONEORDER=13
CONFIG_IOMMU_VMERGE=y
CONFIG_HOTPLUG_CPU=y
@@ -155,6 +157,7 @@ CONFIG_EEH=y
CONFIG_SCANLOG=m
CONFIG_LPARCFG=y
CONFIG_NUMA=y
+CONFIG_NODES_SHIFT=4
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
CONFIG_ARCH_SPARSEMEM_DEFAULT=y
@@ -467,7 +470,7 @@ CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_SPI_ATTRS=y
CONFIG_SCSI_FC_ATTRS=y
CONFIG_SCSI_ISCSI_ATTRS=m
-# CONFIG_SCSI_SAS_ATTRS is not set
+CONFIG_SCSI_SAS_ATTRS=m
#
# SCSI low-level drivers
@@ -499,13 +502,18 @@ CONFIG_SCSI_SYM53C8XX_2=y
CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+CONFIG_SCSI_SYM53C8XX_MMIO=y
CONFIG_SCSI_IPR=y
CONFIG_SCSI_IPR_TRACE=y
CONFIG_SCSI_IPR_DUMP=y
-# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLA_FC is not set
+CONFIG_SCSI_QLA_FC=m
+CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE=y
+CONFIG_SCSI_QLA21XX=m
+CONFIG_SCSI_QLA22XX=m
+CONFIG_SCSI_QLA2300=m
+CONFIG_SCSI_QLA2322=m
+CONFIG_SCSI_QLA24XX=m
CONFIG_SCSI_LPFC=m
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
@@ -521,7 +529,7 @@ CONFIG_MD_RAID0=y
CONFIG_MD_RAID1=y
CONFIG_MD_RAID10=m
CONFIG_MD_RAID5=y
-# CONFIG_MD_RAID5_RESHAPE is not set
+CONFIG_MD_RAID5_RESHAPE=y
CONFIG_MD_RAID6=m
CONFIG_MD_MULTIPATH=m
CONFIG_MD_FAULTY=m
@@ -764,7 +772,7 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_ICOM=m
-# CONFIG_SERIAL_JSM is not set
+CONFIG_SERIAL_JSM=m
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -773,7 +781,7 @@ CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_TIPAR is not set
CONFIG_HVC_DRIVER=y
CONFIG_HVC_CONSOLE=y
-# CONFIG_HVC_RTAS is not set
+CONFIG_HVC_RTAS=y
CONFIG_HVCS=m
#
@@ -1031,9 +1039,7 @@ CONFIG_USB_HIDDEV=y
# CONFIG_USB_ACECAD is not set
# CONFIG_USB_KBTAB is not set
# CONFIG_USB_POWERMATE is not set
-# CONFIG_USB_MTOUCH is not set
-# CONFIG_USB_ITMTOUCH is not set
-# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_TOUCHSCREEN is not set
# CONFIG_USB_YEALINK is not set
# CONFIG_USB_XPAD is not set
# CONFIG_USB_ATI_REMOTE is not set
@@ -1105,16 +1111,25 @@ CONFIG_USB_MON=y
# CONFIG_NEW_LEDS is not set
#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
# InfiniBand support
#
CONFIG_INFINIBAND=m
-# CONFIG_INFINIBAND_USER_MAD is not set
-# CONFIG_INFINIBAND_USER_ACCESS is not set
+CONFIG_INFINIBAND_USER_MAD=m
+CONFIG_INFINIBAND_USER_ACCESS=m
CONFIG_INFINIBAND_MTHCA=m
-# CONFIG_INFINIBAND_MTHCA_DEBUG is not set
+CONFIG_INFINIBAND_MTHCA_DEBUG=y
CONFIG_INFINIBAND_IPOIB=m
-# CONFIG_INFINIBAND_IPOIB_DEBUG is not set
-# CONFIG_INFINIBAND_SRP is not set
+CONFIG_INFINIBAND_IPOIB_DEBUG=y
+# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set
+CONFIG_INFINIBAND_SRP=m
#
# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
@@ -1159,15 +1174,15 @@ CONFIG_XFS_EXPORT=y
CONFIG_XFS_SECURITY=y
CONFIG_XFS_POSIX_ACL=y
# CONFIG_XFS_RT is not set
-# CONFIG_OCFS2_FS is not set
+CONFIG_OCFS2_FS=m
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_INOTIFY=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
-CONFIG_AUTOFS_FS=m
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_FUSE_FS is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
#
# CD-ROM/DVD Filesystems
@@ -1199,7 +1214,7 @@ CONFIG_TMPFS=y
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y
CONFIG_RAMFS=y
-# CONFIG_CONFIGFS_FS is not set
+CONFIG_CONFIGFS_FS=m
#
# Miscellaneous filesystems
@@ -1317,7 +1332,7 @@ CONFIG_ZLIB_DEFLATE=m
#
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
-# CONFIG_KPROBES is not set
+CONFIG_KPROBES=y
#
# Kernel hacking
@@ -1329,7 +1344,7 @@ CONFIG_LOG_BUF_SHIFT=17
CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_SCHEDSTATS is not set
# CONFIG_DEBUG_SLAB is not set
-CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_MUTEXES is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1339,17 +1354,13 @@ CONFIG_DEBUG_FS=y
CONFIG_FORCED_INLINING=y
# CONFIG_RCU_TORTURE_TEST is not set
CONFIG_DEBUG_STACKOVERFLOW=y
-CONFIG_DEBUG_STACK_USAGE=y
+# CONFIG_DEBUG_STACK_USAGE is not set
CONFIG_DEBUGGER=y
CONFIG_XMON=y
CONFIG_XMON_DEFAULT=y
CONFIG_IRQSTACKS=y
# CONFIG_BOOTX_TEXT is not set
-# CONFIG_PPC_EARLY_DEBUG_LPAR is not set
-# CONFIG_PPC_EARLY_DEBUG_G5 is not set
-# CONFIG_PPC_EARLY_DEBUG_RTAS is not set
-# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set
-# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
#
# Security options
diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c
index faaec9c..4734b5d 100644
--- a/arch/powerpc/kernel/align.c
+++ b/arch/powerpc/kernel/align.c
@@ -35,17 +35,19 @@ struct aligninfo {
#define INVALID { 0, 0 }
-#define LD 1 /* load */
-#define ST 2 /* store */
-#define SE 4 /* sign-extend value */
-#define F 8 /* to/from fp regs */
-#define U 0x10 /* update index register */
-#define M 0x20 /* multiple load/store */
-#define SW 0x40 /* byte swap int or ... */
-#define S 0x40 /* ... single-precision fp */
-#define SX 0x40 /* byte count in XER */
+/* Bits in the flags field */
+#define LD 0 /* load */
+#define ST 1 /* store */
+#define SE 2 /* sign-extend value */
+#define F 4 /* to/from fp regs */
+#define U 8 /* update index register */
+#define M 0x10 /* multiple load/store */
+#define SW 0x20 /* byte swap */
+#define S 0x40 /* single-precision fp or... */
+#define SX 0x40 /* ... byte count in XER */
#define HARD 0x80 /* string, stwcx. */
+/* DSISR bits reported for a DCBZ instruction: */
#define DCBZ 0x5f /* 8xx/82xx dcbz faults when cache not enabled */
#define SWAP(a, b) (t = (a), (a) = (b), (b) = t)
@@ -256,12 +258,16 @@ static int emulate_dcbz(struct pt_regs *regs, unsigned char __user *addr)
#define REG_BYTE(rp, i) *((u8 *)(rp) + (i))
#endif
+#define SWIZ_PTR(p) ((unsigned char __user *)((p) ^ swiz))
+
static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
unsigned int reg, unsigned int nb,
- unsigned int flags, unsigned int instr)
+ unsigned int flags, unsigned int instr,
+ unsigned long swiz)
{
unsigned long *rptr;
- unsigned int nb0, i;
+ unsigned int nb0, i, bswiz;
+ unsigned long p;
/*
* We do not try to emulate 8 bytes multiple as they aren't really
@@ -280,9 +286,12 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
if (nb == 0)
return 1;
} else {
- if (__get_user(instr,
- (unsigned int __user *)regs->nip))
+ unsigned long pc = regs->nip ^ (swiz & 4);
+
+ if (__get_user(instr, (unsigned int __user *)pc))
return -EFAULT;
+ if (swiz == 0 && (flags & SW))
+ instr = cpu_to_le32(instr);
nb = (instr >> 11) & 0x1f;
if (nb == 0)
nb = 32;
@@ -300,7 +309,10 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
return -EFAULT; /* bad address */
rptr = &regs->gpr[reg];
- if (flags & LD) {
+ p = (unsigned long) addr;
+ bswiz = (flags & SW)? 3: 0;
+
+ if (!(flags & ST)) {
/*
* This zeroes the top 4 bytes of the affected registers
* in 64-bit mode, and also zeroes out any remaining
@@ -311,26 +323,28 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
memset(&regs->gpr[0], 0,
((nb0 + 3) / 4) * sizeof(unsigned long));
- for (i = 0; i < nb; ++i)
- if (__get_user(REG_BYTE(rptr, i), addr + i))
+ for (i = 0; i < nb; ++i, ++p)
+ if (__get_user(REG_BYTE(rptr, i ^ bswiz), SWIZ_PTR(p)))
return -EFAULT;
if (nb0 > 0) {
rptr = &regs->gpr[0];
addr += nb;
- for (i = 0; i < nb0; ++i)
- if (__get_user(REG_BYTE(rptr, i), addr + i))
+ for (i = 0; i < nb0; ++i, ++p)
+ if (__get_user(REG_BYTE(rptr, i ^ bswiz),
+ SWIZ_PTR(p)))
return -EFAULT;
}
} else {
- for (i = 0; i < nb; ++i)
- if (__put_user(REG_BYTE(rptr, i), addr + i))
+ for (i = 0; i < nb; ++i, ++p)
+ if (__put_user(REG_BYTE(rptr, i ^ bswiz), SWIZ_PTR(p)))
return -EFAULT;
if (nb0 > 0) {
rptr = &regs->gpr[0];
addr += nb;
- for (i = 0; i < nb0; ++i)
- if (__put_user(REG_BYTE(rptr, i), addr + i))
+ for (i = 0; i < nb0; ++i, ++p)
+ if (__put_user(REG_BYTE(rptr, i ^ bswiz),
+ SWIZ_PTR(p)))
return -EFAULT;
}
}
@@ -352,7 +366,7 @@ int fix_alignment(struct pt_regs *regs)
unsigned int reg, areg;
unsigned int dsisr;
unsigned char __user *addr;
- unsigned char __user *p;
+ unsigned long p, swiz;
int ret, t;
union {
u64 ll;
@@ -380,11 +394,15 @@ int fix_alignment(struct pt_regs *regs)
* let's make one up from the instruction
*/
if (cpu_has_feature(CPU_FTR_NODSISRALIGN)) {
- unsigned int real_instr;
- if (unlikely(__get_user(real_instr,
- (unsigned int __user *)regs->nip)))
+ unsigned long pc = regs->nip;
+
+ if (cpu_has_feature(CPU_FTR_PPC_LE) && (regs->msr & MSR_LE))
+ pc ^= 4;
+ if (unlikely(__get_user(instr, (unsigned int __user *)pc)))
return -EFAULT;
- dsisr = make_dsisr(real_instr);
+ if (cpu_has_feature(CPU_FTR_REAL_LE) && (regs->msr & MSR_LE))
+ instr = cpu_to_le32(instr);
+ dsisr = make_dsisr(instr);
}
/* extract the operation and registers from the dsisr */
@@ -397,6 +415,24 @@ int fix_alignment(struct pt_regs *regs)
nb = aligninfo[instr].len;
flags = aligninfo[instr].flags;
+ /* Byteswap little endian loads and stores */
+ swiz = 0;
+ if (regs->msr & MSR_LE) {
+ flags ^= SW;
+ /*
+ * So-called "PowerPC little endian" mode works by
+ * swizzling addresses rather than by actually doing
+ * any byte-swapping. To emulate this, we XOR each
+ * byte address with 7. We also byte-swap, because
+ * the processor's address swizzling depends on the
+ * operand size (it xors the address with 7 for bytes,
+ * 6 for halfwords, 4 for words, 0 for doublewords) but
+ * we will xor with 7 and load/store each byte separately.
+ */
+ if (cpu_has_feature(CPU_FTR_PPC_LE))
+ swiz = 7;
+ }
+
/* DAR has the operand effective address */
addr = (unsigned char __user *)regs->dar;
@@ -412,7 +448,8 @@ int fix_alignment(struct pt_regs *regs)
* function
*/
if (flags & M)
- return emulate_multiple(regs, addr, reg, nb, flags, instr);
+ return emulate_multiple(regs, addr, reg, nb,
+ flags, instr, swiz);
/* Verify the address of the operand */
if (unlikely(user_mode(regs) &&
@@ -431,51 +468,71 @@ int fix_alignment(struct pt_regs *regs)
/* If we are loading, get the data from user space, else
* get it from register values
*/
- if (flags & LD) {
+ if (!(flags & ST)) {
data.ll = 0;
ret = 0;
- p = addr;
+ p = (unsigned long) addr;
switch (nb) {
case 8:
- ret |= __get_user(data.v[0], p++);
- ret |= __get_user(data.v[1], p++);
- ret |= __get_user(data.v[2], p++);
- ret |= __get_user(data.v[3], p++);
+ ret |= __get_user(data.v[0], SWIZ_PTR(p++));
+ ret |= __get_user(data.v[1], SWIZ_PTR(p++));
+ ret |= __get_user(data.v[2], SWIZ_PTR(p++));
+ ret |= __get_user(data.v[3], SWIZ_PTR(p++));
case 4:
- ret |= __get_user(data.v[4], p++);
- ret |= __get_user(data.v[5], p++);
+ ret |= __get_user(data.v[4], SWIZ_PTR(p++));
+ ret |= __get_user(data.v[5], SWIZ_PTR(p++));
case 2:
- ret |= __get_user(data.v[6], p++);
- ret |= __get_user(data.v[7], p++);
+ ret |= __get_user(data.v[6], SWIZ_PTR(p++));
+ ret |= __get_user(data.v[7], SWIZ_PTR(p++));
if (unlikely(ret))
return -EFAULT;
}
- } else if (flags & F)
+ } else if (flags & F) {
data.dd = current->thread.fpr[reg];
- else
+ if (flags & S) {
+ /* Single-precision FP store requires conversion... */
+#ifdef CONFIG_PPC_FPU
+ preempt_disable();
+ enable_kernel_fp();
+ cvt_df(&data.dd, (float *)&data.v[4], &current->thread);
+ preempt_enable();
+#else
+ return 0;
+#endif
+ }
+ } else
data.ll = regs->gpr[reg];
- /* Perform other misc operations like sign extension, byteswap,
+ if (flags & SW) {
+ switch (nb) {
+ case 8:
+ SWAP(data.v[0], data.v[7]);
+ SWAP(data.v[1], data.v[6]);
+ SWAP(data.v[2], data.v[5]);
+ SWAP(data.v[3], data.v[4]);
+ break;
+ case 4:
+ SWAP(data.v[4], data.v[7]);
+ SWAP(data.v[5], data.v[6]);
+ break;
+ case 2:
+ SWAP(data.v[6], data.v[7]);
+ break;
+ }
+ }
+
+ /* Perform other misc operations like sign extension
* or floating point single precision conversion
*/
- switch (flags & ~U) {
+ switch (flags & ~(U|SW)) {
case LD+SE: /* sign extend */
if ( nb == 2 )
data.ll = data.x16.low16;
else /* nb must be 4 */
data.ll = data.x32.low32;
break;
- case LD+S: /* byte-swap */
- case ST+S:
- if (nb == 2) {
- SWAP(data.v[6], data.v[7]);
- } else {
- SWAP(data.v[4], data.v[7]);
- SWAP(data.v[5], data.v[6]);
- }
- break;
- /* Single-precision FP load and store require conversions... */
+ /* Single-precision FP load requires conversion... */
case LD+F+S:
#ifdef CONFIG_PPC_FPU
preempt_disable();
@@ -486,34 +543,24 @@ int fix_alignment(struct pt_regs *regs)
return 0;
#endif
break;
- case ST+F+S:
-#ifdef CONFIG_PPC_FPU
- preempt_disable();
- enable_kernel_fp();
- cvt_df(&data.dd, (float *)&data.v[4], &current->thread);
- preempt_enable();
-#else
- return 0;
-#endif
- break;
}
/* Store result to memory or update registers */
if (flags & ST) {
ret = 0;
- p = addr;
+ p = (unsigned long) addr;
switch (nb) {
case 8:
- ret |= __put_user(data.v[0], p++);
- ret |= __put_user(data.v[1], p++);
- ret |= __put_user(data.v[2], p++);
- ret |= __put_user(data.v[3], p++);
+ ret |= __put_user(data.v[0], SWIZ_PTR(p++));
+ ret |= __put_user(data.v[1], SWIZ_PTR(p++));
+ ret |= __put_user(data.v[2], SWIZ_PTR(p++));
+ ret |= __put_user(data.v[3], SWIZ_PTR(p++));
case 4:
- ret |= __put_user(data.v[4], p++);
- ret |= __put_user(data.v[5], p++);
+ ret |= __put_user(data.v[4], SWIZ_PTR(p++));
+ ret |= __put_user(data.v[5], SWIZ_PTR(p++));
case 2:
- ret |= __put_user(data.v[6], p++);
- ret |= __put_user(data.v[7], p++);
+ ret |= __put_user(data.v[6], SWIZ_PTR(p++));
+ ret |= __put_user(data.v[7], SWIZ_PTR(p++));
}
if (unlikely(ret))
return -EFAULT;
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 8f85c5e..ff29405 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -122,9 +122,8 @@ int main(void)
DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache));
DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr));
DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id));
-#ifdef CONFIG_PPC_64K_PAGES
- DEFINE(PACAPGDIR, offsetof(struct paca_struct, pgdir));
-#endif
+ DEFINE(PACACONTEXTSLLP, offsetof(struct paca_struct, context.sllp));
+ DEFINE(PACAVMALLOCSLLP, offsetof(struct paca_struct, vmalloc_sllp));
#ifdef CONFIG_HUGETLB_PAGE
DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas));
DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas));
diff --git a/arch/powerpc/kernel/cpu_setup_6xx.S b/arch/powerpc/kernel/cpu_setup_6xx.S
index 55ed771..365381f 100644
--- a/arch/powerpc/kernel/cpu_setup_6xx.S
+++ b/arch/powerpc/kernel/cpu_setup_6xx.S
@@ -210,9 +210,11 @@ setup_745x_specifics:
* the firmware. If any, we disable NAP capability as
* it's known to be bogus on rev 2.1 and earlier
*/
+BEGIN_FTR_SECTION
mfspr r11,SPRN_L3CR
andis. r11,r11,L3CR_L3E@h
beq 1f
+END_FTR_SECTION_IFSET(CPU_FTR_L3CR)
lwz r6,CPU_SPEC_FEATURES(r5)
andi. r0,r6,CPU_FTR_L3_DISABLE_NAP
beq 1f
diff --git a/arch/powerpc/kernel/cpu_setup_power4.S b/arch/powerpc/kernel/cpu_setup_power4.S
index b61d86e..2714183 100644
--- a/arch/powerpc/kernel/cpu_setup_power4.S
+++ b/arch/powerpc/kernel/cpu_setup_power4.S
@@ -73,23 +73,6 @@ _GLOBAL(__970_cpu_preinit)
isync
blr
-_GLOBAL(__setup_cpu_power4)
- blr
-
-_GLOBAL(__setup_cpu_be)
- /* Set large page sizes LP=0: 16MB, LP=1: 64KB */
- addi r3, 0, 0
- ori r3, r3, HID6_LB
- sldi r3, r3, 32
- nor r3, r3, r3
- mfspr r4, SPRN_HID6
- and r4, r4, r3
- addi r3, 0, 0x02000
- sldi r3, r3, 32
- or r4, r4, r3
- mtspr SPRN_HID6, r4
- blr
-
_GLOBAL(__setup_cpu_ppc970)
mfspr r0,SPRN_HID0
li r11,5 /* clear DOZE and SLEEP */
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 3f7182d..1c11488 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -30,11 +30,7 @@ EXPORT_SYMBOL(cur_cpu_spec);
* part of the cputable though. That has to be fixed for both ppc32
* and ppc64
*/
-#ifdef CONFIG_PPC64
-extern void __setup_cpu_power3(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_power4(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_be(unsigned long offset, struct cpu_spec* spec);
-#else
+#ifdef CONFIG_PPC32
extern void __setup_cpu_603(unsigned long offset, struct cpu_spec* spec);
extern void __setup_cpu_604(unsigned long offset, struct cpu_spec* spec);
extern void __setup_cpu_750(unsigned long offset, struct cpu_spec* spec);
@@ -58,7 +54,8 @@ extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec);
#define COMMON_USER_POWER5_PLUS (COMMON_USER_PPC64 | PPC_FEATURE_POWER5_PLUS|\
PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP)
#define COMMON_USER_POWER6 (COMMON_USER_PPC64 | PPC_FEATURE_ARCH_2_05 |\
- PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP)
+ PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | \
+ PPC_FEATURE_TRUE_LE)
#define COMMON_USER_BOOKE (PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | \
PPC_FEATURE_BOOKE)
@@ -78,11 +75,10 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x00400000,
.cpu_name = "POWER3 (630)",
.cpu_features = CPU_FTRS_POWER3,
- .cpu_user_features = COMMON_USER_PPC64,
+ .cpu_user_features = COMMON_USER_PPC64|PPC_FEATURE_PPC_LE,
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
- .cpu_setup = __setup_cpu_power3,
.oprofile_cpu_type = "ppc64/power3",
.oprofile_type = PPC_OPROFILE_RS64,
.platform = "power3",
@@ -92,11 +88,10 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x00410000,
.cpu_name = "POWER3 (630+)",
.cpu_features = CPU_FTRS_POWER3,
- .cpu_user_features = COMMON_USER_PPC64,
+ .cpu_user_features = COMMON_USER_PPC64|PPC_FEATURE_PPC_LE,
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
- .cpu_setup = __setup_cpu_power3,
.oprofile_cpu_type = "ppc64/power3",
.oprofile_type = PPC_OPROFILE_RS64,
.platform = "power3",
@@ -110,7 +105,6 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
- .cpu_setup = __setup_cpu_power3,
.oprofile_cpu_type = "ppc64/rs64",
.oprofile_type = PPC_OPROFILE_RS64,
.platform = "rs64",
@@ -124,7 +118,6 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
- .cpu_setup = __setup_cpu_power3,
.oprofile_cpu_type = "ppc64/rs64",
.oprofile_type = PPC_OPROFILE_RS64,
.platform = "rs64",
@@ -138,7 +131,6 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
- .cpu_setup = __setup_cpu_power3,
.oprofile_cpu_type = "ppc64/rs64",
.oprofile_type = PPC_OPROFILE_RS64,
.platform = "rs64",
@@ -152,7 +144,6 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
- .cpu_setup = __setup_cpu_power3,
.oprofile_cpu_type = "ppc64/rs64",
.oprofile_type = PPC_OPROFILE_RS64,
.platform = "rs64",
@@ -166,7 +157,6 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
- .cpu_setup = __setup_cpu_power4,
.oprofile_cpu_type = "ppc64/power4",
.oprofile_type = PPC_OPROFILE_POWER4,
.platform = "power4",
@@ -180,7 +170,6 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
- .cpu_setup = __setup_cpu_power4,
.oprofile_cpu_type = "ppc64/power4",
.oprofile_type = PPC_OPROFILE_POWER4,
.platform = "power4",
@@ -200,17 +189,11 @@ struct cpu_spec cpu_specs[] = {
.oprofile_type = PPC_OPROFILE_POWER4,
.platform = "ppc970",
},
-#endif /* CONFIG_PPC64 */
-#if defined(CONFIG_PPC64) || defined(CONFIG_POWER4)
{ /* PPC970FX */
.pvr_mask = 0xffff0000,
.pvr_value = 0x003c0000,
.cpu_name = "PPC970FX",
-#ifdef CONFIG_PPC32
- .cpu_features = CPU_FTRS_970_32,
-#else
.cpu_features = CPU_FTRS_PPC970,
-#endif
.cpu_user_features = COMMON_USER_POWER4 |
PPC_FEATURE_HAS_ALTIVEC_COMP,
.icache_bsize = 128,
@@ -221,8 +204,6 @@ struct cpu_spec cpu_specs[] = {
.oprofile_type = PPC_OPROFILE_POWER4,
.platform = "ppc970",
},
-#endif /* defined(CONFIG_PPC64) || defined(CONFIG_POWER4) */
-#ifdef CONFIG_PPC64
{ /* PPC970MP */
.pvr_mask = 0xffff0000,
.pvr_value = 0x00440000,
@@ -232,6 +213,7 @@ struct cpu_spec cpu_specs[] = {
PPC_FEATURE_HAS_ALTIVEC_COMP,
.icache_bsize = 128,
.dcache_bsize = 128,
+ .num_pmcs = 8,
.cpu_setup = __setup_cpu_ppc970,
.oprofile_cpu_type = "ppc64/970",
.oprofile_type = PPC_OPROFILE_POWER4,
@@ -246,9 +228,13 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 6,
- .cpu_setup = __setup_cpu_power4,
.oprofile_cpu_type = "ppc64/power5",
.oprofile_type = PPC_OPROFILE_POWER4,
+ /* SIHV / SIPR bits are implemented on POWER4+ (GQ)
+ * and above but only works on POWER5 and above
+ */
+ .oprofile_mmcra_sihv = MMCRA_SIHV,
+ .oprofile_mmcra_sipr = MMCRA_SIPR,
.platform = "power5",
},
{ /* Power5 GS */
@@ -260,9 +246,10 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 6,
- .cpu_setup = __setup_cpu_power4,
.oprofile_cpu_type = "ppc64/power5+",
.oprofile_type = PPC_OPROFILE_POWER4,
+ .oprofile_mmcra_sihv = MMCRA_SIHV,
+ .oprofile_mmcra_sipr = MMCRA_SIPR,
.platform = "power5+",
},
{ /* Power6 */
@@ -273,10 +260,13 @@ struct cpu_spec cpu_specs[] = {
.cpu_user_features = COMMON_USER_POWER6,
.icache_bsize = 128,
.dcache_bsize = 128,
- .num_pmcs = 6,
- .cpu_setup = __setup_cpu_power4,
+ .num_pmcs = 8,
.oprofile_cpu_type = "ppc64/power6",
.oprofile_type = PPC_OPROFILE_POWER4,
+ .oprofile_mmcra_sihv = POWER6_MMCRA_SIHV,
+ .oprofile_mmcra_sipr = POWER6_MMCRA_SIPR,
+ .oprofile_mmcra_clear = POWER6_MMCRA_THRM |
+ POWER6_MMCRA_OTHER,
.platform = "power6",
},
{ /* Cell Broadband Engine */
@@ -289,7 +279,6 @@ struct cpu_spec cpu_specs[] = {
PPC_FEATURE_SMT,
.icache_bsize = 128,
.dcache_bsize = 128,
- .cpu_setup = __setup_cpu_be,
.platform = "ppc-cell-be",
},
{ /* default match */
@@ -301,7 +290,6 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 6,
- .cpu_setup = __setup_cpu_power4,
.platform = "power4",
}
#endif /* CONFIG_PPC64 */
@@ -323,7 +311,7 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x00030000,
.cpu_name = "603",
.cpu_features = CPU_FTRS_603,
- .cpu_user_features = COMMON_USER,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.cpu_setup = __setup_cpu_603,
@@ -334,7 +322,7 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x00060000,
.cpu_name = "603e",
.cpu_features = CPU_FTRS_603,
- .cpu_user_features = COMMON_USER,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.cpu_setup = __setup_cpu_603,
@@ -345,7 +333,7 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x00070000,
.cpu_name = "603ev",
.cpu_features = CPU_FTRS_603,
- .cpu_user_features = COMMON_USER,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.cpu_setup = __setup_cpu_603,
@@ -356,7 +344,7 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x00040000,
.cpu_name = "604",
.cpu_features = CPU_FTRS_604,
- .cpu_user_features = COMMON_USER,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 2,
@@ -368,7 +356,7 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x00090000,
.cpu_name = "604e",
.cpu_features = CPU_FTRS_604,
- .cpu_user_features = COMMON_USER,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
@@ -380,7 +368,7 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x00090000,
.cpu_name = "604r",
.cpu_features = CPU_FTRS_604,
- .cpu_user_features = COMMON_USER,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
@@ -392,7 +380,7 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x000a0000,
.cpu_name = "604ev",
.cpu_features = CPU_FTRS_604,
- .cpu_user_features = COMMON_USER,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
@@ -404,7 +392,7 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x00084202,
.cpu_name = "740/750",
.cpu_features = CPU_FTRS_740_NOTAU,
- .cpu_user_features = COMMON_USER,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
@@ -416,7 +404,7 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x00080100,
.cpu_name = "750CX",
.cpu_features = CPU_FTRS_750,
- .cpu_user_features = COMMON_USER,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
@@ -428,7 +416,7 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x00082200,
.cpu_name = "750CX",
.cpu_features = CPU_FTRS_750,
- .cpu_user_features = COMMON_USER,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
@@ -440,7 +428,7 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x00082210,
.cpu_name = "750CXe",
.cpu_features = CPU_FTRS_750,
- .cpu_user_features = COMMON_USER,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
@@ -452,7 +440,7 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x00083214,
.cpu_name = "750CXe",
.cpu_features = CPU_FTRS_750,
- .cpu_user_features = COMMON_USER,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
@@ -464,7 +452,7 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x00083000,
.cpu_name = "745/755",
.cpu_features = CPU_FTRS_750,
- .cpu_user_features = COMMON_USER,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
@@ -476,7 +464,7 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x70000100,
.cpu_name = "750FX",
.cpu_features = CPU_FTRS_750FX1,
- .cpu_user_features = COMMON_USER,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
@@ -488,7 +476,7 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x70000200,
.cpu_name = "750FX",
.cpu_features = CPU_FTRS_750FX2,
- .cpu_user_features = COMMON_USER,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
@@ -500,7 +488,7 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x70000000,
.cpu_name = "750FX",
.cpu_features = CPU_FTRS_750FX,
- .cpu_user_features = COMMON_USER,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
@@ -512,7 +500,7 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x70020000,
.cpu_name = "750GX",
.cpu_features = CPU_FTRS_750GX,
- .cpu_user_features = COMMON_USER,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
@@ -524,7 +512,7 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x00080000,
.cpu_name = "740/750",
.cpu_features = CPU_FTRS_740,
- .cpu_user_features = COMMON_USER,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
@@ -536,7 +524,8 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x000c1101,
.cpu_name = "7400 (1.1)",
.cpu_features = CPU_FTRS_7400_NOTAU,
- .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP,
+ .cpu_user_features = COMMON_USER |
+ PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
@@ -548,7 +537,8 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x000c0000,
.cpu_name = "7400",
.cpu_features = CPU_FTRS_7400,
- .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP,
+ .cpu_user_features = COMMON_USER |
+ PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
@@ -560,7 +550,8 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x800c0000,
.cpu_name = "7410",
.cpu_features = CPU_FTRS_7400,
- .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP,
+ .cpu_user_features = COMMON_USER |
+ PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
@@ -572,7 +563,8 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x80000200,
.cpu_name = "7450",
.cpu_features = CPU_FTRS_7450_20,
- .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP,
+ .cpu_user_features = COMMON_USER |
+ PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
@@ -586,7 +578,8 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x80000201,
.cpu_name = "7450",
.cpu_features = CPU_FTRS_7450_21,
- .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP,
+ .cpu_user_features = COMMON_USER |
+ PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
@@ -600,7 +593,8 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x80000000,
.cpu_name = "7450",
.cpu_features = CPU_FTRS_7450_23,
- .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP,
+ .cpu_user_features = COMMON_USER |
+ PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
@@ -614,7 +608,8 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x80010100,
.cpu_name = "7455",
.cpu_features = CPU_FTRS_7455_1,
- .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP,
+ .cpu_user_features = COMMON_USER |
+ PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
@@ -628,7 +623,8 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x80010200,
.cpu_name = "7455",
.cpu_features = CPU_FTRS_7455_20,
- .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP,
+ .cpu_user_features = COMMON_USER |
+ PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
@@ -642,7 +638,8 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x80010000,
.cpu_name = "7455",
.cpu_features = CPU_FTRS_7455,
- .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP,
+ .cpu_user_features = COMMON_USER |
+ PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
@@ -656,7 +653,8 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x80020100,
.cpu_name = "7447/7457",
.cpu_features = CPU_FTRS_7447_10,
- .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP,
+ .cpu_user_features = COMMON_USER |
+ PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
@@ -670,7 +668,8 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x80020101,
.cpu_name = "7447/7457",
.cpu_features = CPU_FTRS_7447_10,
- .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP,
+ .cpu_user_features = COMMON_USER |
+ PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
@@ -684,7 +683,7 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x80020000,
.cpu_name = "7447/7457",
.cpu_features = CPU_FTRS_7447,
- .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
@@ -698,7 +697,8 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x80030000,
.cpu_name = "7447A",
.cpu_features = CPU_FTRS_7447A,
- .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP,
+ .cpu_user_features = COMMON_USER |
+ PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
@@ -712,7 +712,8 @@ struct cpu_spec cpu_specs[] = {
.pvr_value = 0x80040000,
.cpu_name = "7448",
.cpu_features = CPU_FTRS_7447A,
- .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP,
+ .cpu_user_features = COMMON_USER |
+ PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
@@ -721,6 +722,18 @@ struct cpu_spec cpu_specs[] = {
.oprofile_type = PPC_OPROFILE_G4,
.platform = "ppc7450",
},
+ { /* 8641 */
+ .pvr_mask = 0xffffffff,
+ .pvr_value = 0x80040010,
+ .cpu_name = "8641",
+ .cpu_features = CPU_FTRS_7447A,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .num_pmcs = 6,
+ .cpu_setup = __setup_cpu_745x
+ },
+
{ /* 82xx (8240, 8245, 8260 are all 603e cores) */
.pvr_mask = 0x7fff0000,
.pvr_value = 0x00810000,
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
index 778f22f..dbcb859 100644
--- a/arch/powerpc/kernel/crash.c
+++ b/arch/powerpc/kernel/crash.c
@@ -22,6 +22,7 @@
#include <linux/elf.h>
#include <linux/elfcore.h>
#include <linux/init.h>
+#include <linux/irq.h>
#include <linux/types.h>
#include <asm/processor.h>
@@ -174,6 +175,8 @@ static void crash_kexec_prepare_cpus(void)
void default_machine_crash_shutdown(struct pt_regs *regs)
{
+ unsigned int irq;
+
/*
* This function is only called after the system
* has paniced or is otherwise in a critical state.
@@ -186,6 +189,16 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
*/
local_irq_disable();
+ for_each_irq(irq) {
+ struct irq_desc *desc = irq_descp(irq);
+
+ if (desc->status & IRQ_INPROGRESS)
+ desc->handler->end(irq);
+
+ if (!(desc->status & IRQ_DISABLED))
+ desc->handler->disable(irq);
+ }
+
if (ppc_md.kexec_cpu_down)
ppc_md.kexec_cpu_down(1, 0);
diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c
index 764d073..371973b 100644
--- a/arch/powerpc/kernel/crash_dump.c
+++ b/arch/powerpc/kernel/crash_dump.c
@@ -25,6 +25,11 @@
#define DBG(fmt...)
#endif
+void reserve_kdump_trampoline(void)
+{
+ lmb_reserve(0, KDUMP_RESERVE_LIMIT);
+}
+
static void __init create_trampoline(unsigned long addr)
{
/* The maximum range of a single instruction branch, is the current
@@ -39,11 +44,11 @@ static void __init create_trampoline(unsigned long addr)
create_branch(addr + 4, addr + PHYSICAL_START, 0);
}
-void __init kdump_setup(void)
+void __init setup_kdump_trampoline(void)
{
unsigned long i;
- DBG(" -> kdump_setup()\n");
+ DBG(" -> setup_kdump_trampoline()\n");
for (i = KDUMP_TRAMPOLINE_START; i < KDUMP_TRAMPOLINE_END; i += 8) {
create_trampoline(i);
@@ -52,7 +57,7 @@ void __init kdump_setup(void)
create_trampoline(__pa(system_reset_fwnmi) - PHYSICAL_START);
create_trampoline(__pa(machine_check_fwnmi) - PHYSICAL_START);
- DBG(" <- kdump_setup()\n");
+ DBG(" <- setup_kdump_trampoline()\n");
}
#ifdef CONFIG_PROC_VMCORE
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 19ad5c6..221062c 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -57,6 +57,7 @@ system_call_common:
beq- 1f
ld r1,PACAKSAVE(r13)
1: std r10,0(r1)
+ crclr so
std r11,_NIP(r1)
std r12,_MSR(r1)
std r0,GPR0(r1)
@@ -75,7 +76,6 @@ system_call_common:
std r11,GPR11(r1)
std r11,GPR12(r1)
std r9,GPR13(r1)
- crclr so
mfcr r9
mflr r10
li r11,0xc01
diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S
index 340730f..01f7120 100644
--- a/arch/powerpc/kernel/fpu.S
+++ b/arch/powerpc/kernel/fpu.S
@@ -72,7 +72,7 @@ _GLOBAL(load_up_fpu)
std r12,_MSR(r1)
#endif
lfd fr0,THREAD_FPSCR(r5)
- mtfsf 0xff,fr0
+ MTFSF_L(fr0)
REST_32FPRS(0, r5)
#ifndef CONFIG_SMP
subi r4,r5,THREAD
@@ -127,7 +127,7 @@ _GLOBAL(giveup_fpu)
_GLOBAL(cvt_fd)
lfd 0,THREAD_FPSCR(r5) /* load up fpscr value */
- mtfsf 0xff,0
+ MTFSF_L(0)
lfs 0,0(r3)
stfd 0,0(r4)
mffs 0
@@ -136,7 +136,7 @@ _GLOBAL(cvt_fd)
_GLOBAL(cvt_df)
lfd 0,THREAD_FPSCR(r5) /* load up fpscr value */
- mtfsf 0xff,0
+ MTFSF_L(0)
lfd 0,0(r3)
stfs 0,0(r4)
mffs 0
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index a0579e8..b25b259 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -973,6 +973,13 @@ __secondary_start_gemini:
b __secondary_start
#endif /* CONFIG_GEMINI */
+ .globl __secondary_start_mpc86xx
+__secondary_start_mpc86xx:
+ mfspr r3, SPRN_PIR
+ stw r3, __secondary_hold_acknowledge@l(0)
+ mr r24, r3 /* cpu # */
+ b __secondary_start
+
.globl __secondary_start_pmac_0
__secondary_start_pmac_0:
/* NB the entries for cpus 0, 1, 2 must each occupy 8 bytes. */
@@ -1088,7 +1095,12 @@ load_up_mmu:
LOAD_BAT(1,r3,r4,r5)
LOAD_BAT(2,r3,r4,r5)
LOAD_BAT(3,r3,r4,r5)
-
+BEGIN_FTR_SECTION
+ LOAD_BAT(4,r3,r4,r5)
+ LOAD_BAT(5,r3,r4,r5)
+ LOAD_BAT(6,r3,r4,r5)
+ LOAD_BAT(7,r3,r4,r5)
+END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS)
blr
/*
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index b7d1404..831acbd 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -316,6 +316,21 @@ label##_pSeries: \
mtspr SPRN_SPRG1,r13; /* save r13 */ \
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common)
+#define HSTD_EXCEPTION_PSERIES(n, label) \
+ . = n; \
+ .globl label##_pSeries; \
+label##_pSeries: \
+ HMT_MEDIUM; \
+ mtspr SPRN_SPRG1,r20; /* save r20 */ \
+ mfspr r20,SPRN_HSRR0; /* copy HSRR0 to SRR0 */ \
+ mtspr SPRN_SRR0,r20; \
+ mfspr r20,SPRN_HSRR1; /* copy HSRR0 to SRR0 */ \
+ mtspr SPRN_SRR1,r20; \
+ mfspr r20,SPRN_SPRG1; /* restore r20 */ \
+ mtspr SPRN_SPRG1,r13; /* save r13 */ \
+ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common)
+
+
#define STD_EXCEPTION_ISERIES(n, label, area) \
.globl label##_iSeries; \
label##_iSeries: \
@@ -544,8 +559,17 @@ system_call_pSeries:
STD_EXCEPTION_PSERIES(0xf20, altivec_unavailable)
+#ifdef CONFIG_CBE_RAS
+ HSTD_EXCEPTION_PSERIES(0x1200, cbe_system_error)
+#endif /* CONFIG_CBE_RAS */
STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint)
+#ifdef CONFIG_CBE_RAS
+ HSTD_EXCEPTION_PSERIES(0x1600, cbe_maintenance)
+#endif /* CONFIG_CBE_RAS */
STD_EXCEPTION_PSERIES(0x1700, altivec_assist)
+#ifdef CONFIG_CBE_RAS
+ HSTD_EXCEPTION_PSERIES(0x1800, cbe_thermal)
+#endif /* CONFIG_CBE_RAS */
. = 0x3000
@@ -827,6 +851,11 @@ machine_check_common:
#else
STD_EXCEPTION_COMMON(0x1700, altivec_assist, .unknown_exception)
#endif
+#ifdef CONFIG_CBE_RAS
+ STD_EXCEPTION_COMMON(0x1200, cbe_system_error, .cbe_system_error_exception)
+ STD_EXCEPTION_COMMON(0x1600, cbe_maintenance, .cbe_maintenance_exception)
+ STD_EXCEPTION_COMMON(0x1800, cbe_thermal, .cbe_thermal_exception)
+#endif /* CONFIG_CBE_RAS */
/*
* Here we have detected that the kernel stack pointer is bad.
diff --git a/arch/powerpc/kernel/iomap.c b/arch/powerpc/kernel/iomap.c
index fd8214c..a13a93d 100644
--- a/arch/powerpc/kernel/iomap.c
+++ b/arch/powerpc/kernel/iomap.c
@@ -106,8 +106,6 @@ EXPORT_SYMBOL(iowrite32_rep);
void __iomem *ioport_map(unsigned long port, unsigned int len)
{
- if (!_IO_IS_VALID(port))
- return NULL;
return (void __iomem *) (port+pci_io_base);
}
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index 4eba60a..7cb77c2 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -418,10 +418,11 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
* Build a iommu_table structure. This contains a bit map which
* is used to manage allocation of the tce space.
*/
-struct iommu_table *iommu_init_table(struct iommu_table *tbl)
+struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
{
unsigned long sz;
static int welcomed = 0;
+ struct page *page;
/* Set aside 1/4 of the table for large allocations. */
tbl->it_halfpoint = tbl->it_size * 3 / 4;
@@ -429,10 +430,10 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl)
/* number of bytes needed for the bitmap */
sz = (tbl->it_size + 7) >> 3;
- tbl->it_map = (unsigned long *)__get_free_pages(GFP_ATOMIC, get_order(sz));
- if (!tbl->it_map)
+ page = alloc_pages_node(nid, GFP_ATOMIC, get_order(sz));
+ if (!page)
panic("iommu_init_table: Can't allocate %ld bytes\n", sz);
-
+ tbl->it_map = page_address(page);
memset(tbl->it_map, 0, sz);
tbl->it_hint = 0;
@@ -536,11 +537,12 @@ void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle,
* to the dma address (mapping) of the first page.
*/
void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size,
- dma_addr_t *dma_handle, unsigned long mask, gfp_t flag)
+ dma_addr_t *dma_handle, unsigned long mask, gfp_t flag, int node)
{
void *ret = NULL;
dma_addr_t mapping;
unsigned int npages, order;
+ struct page *page;
size = PAGE_ALIGN(size);
npages = size >> PAGE_SHIFT;
@@ -560,9 +562,10 @@ void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size,
return NULL;
/* Alloc enough pages (and possibly more) */
- ret = (void *)__get_free_pages(flag, order);
- if (!ret)
+ page = alloc_pages_node(node, flag, order);
+ if (!page)
return NULL;
+ ret = page_address(page);
memset(ret, 0, size);
/* Set up tces to cover the allocated range */
@@ -570,9 +573,9 @@ void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size,
mask >> PAGE_SHIFT, order);
if (mapping == DMA_ERROR_CODE) {
free_pages((unsigned long)ret, order);
- ret = NULL;
- } else
- *dma_handle = mapping;
+ return NULL;
+ }
+ *dma_handle = mapping;
return ret;
}
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 57d560c..40d4c14 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -47,6 +47,7 @@
#include <linux/cpumask.h>
#include <linux/profile.h>
#include <linux/bitops.h>
+#include <linux/pci.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -379,8 +380,8 @@ unsigned int real_irq_to_virt_slowpath(unsigned int real_irq)
#endif /* CONFIG_PPC64 */
#ifdef CONFIG_IRQSTACKS
-struct thread_info *softirq_ctx[NR_CPUS];
-struct thread_info *hardirq_ctx[NR_CPUS];
+struct thread_info *softirq_ctx[NR_CPUS] __read_mostly;
+struct thread_info *hardirq_ctx[NR_CPUS] __read_mostly;
void irq_ctx_init(void)
{
@@ -436,6 +437,30 @@ void do_softirq(void)
}
EXPORT_SYMBOL(do_softirq);
+#ifdef CONFIG_PCI_MSI
+int pci_enable_msi(struct pci_dev * pdev)
+{
+ if (ppc_md.enable_msi)
+ return ppc_md.enable_msi(pdev);
+ else
+ return -1;
+}
+
+void pci_disable_msi(struct pci_dev * pdev)
+{
+ if (ppc_md.disable_msi)
+ ppc_md.disable_msi(pdev);
+}
+
+void pci_scan_msi_device(struct pci_dev *dev) {}
+int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) {return -1;}
+void pci_disable_msix(struct pci_dev *dev) {}
+void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
+void disable_msi_mode(struct pci_dev *dev, int pos, int type) {}
+void pci_no_msi(void) {}
+
+#endif
+
#ifdef CONFIG_PPC64
static int __init setup_noirqdistrib(char *str)
{
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
index 2cbde86..c02deaa 100644
--- a/arch/powerpc/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -521,10 +521,10 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf,
current_weight = (resource >> 5 * 8) & 0xFF;
- pr_debug("%s: current_entitled = %lu, current_weight = %lu\n",
+ pr_debug("%s: current_entitled = %lu, current_weight = %u\n",
__FUNCTION__, current_entitled, current_weight);
- pr_debug("%s: new_entitled = %lu, new_weight = %lu\n",
+ pr_debug("%s: new_entitled = %lu, new_weight = %u\n",
__FUNCTION__, *new_entitled_ptr, *new_weight_ptr);
retval = plpar_hcall_norets(H_SET_PPP, *new_entitled_ptr,
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
index ee166c5..a8fa04e 100644
--- a/arch/powerpc/kernel/machine_kexec_64.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -21,6 +21,7 @@
#include <asm/machdep.h>
#include <asm/cacheflush.h>
#include <asm/paca.h>
+#include <asm/lmb.h>
#include <asm/mmu.h>
#include <asm/sections.h> /* _end */
#include <asm/prom.h>
@@ -335,7 +336,105 @@ static void __init export_htab_values(void)
of_node_put(node);
}
+static struct property crashk_base_prop = {
+ .name = "linux,crashkernel-base",
+ .length = sizeof(unsigned long),
+ .value = (unsigned char *)&crashk_res.start,
+};
+
+static unsigned long crashk_size;
+
+static struct property crashk_size_prop = {
+ .name = "linux,crashkernel-size",
+ .length = sizeof(unsigned long),
+ .value = (unsigned char *)&crashk_size,
+};
+
+static void __init export_crashk_values(void)
+{
+ struct device_node *node;
+ struct property *prop;
+
+ node = of_find_node_by_path("/chosen");
+ if (!node)
+ return;
+
+ /* There might be existing crash kernel properties, but we can't
+ * be sure what's in them, so remove them. */
+ prop = of_find_property(node, "linux,crashkernel-base", NULL);
+ if (prop)
+ prom_remove_property(node, prop);
+
+ prop = of_find_property(node, "linux,crashkernel-size", NULL);
+ if (prop)
+ prom_remove_property(node, prop);
+
+ if (crashk_res.start != 0) {
+ prom_add_property(node, &crashk_base_prop);
+ crashk_size = crashk_res.end - crashk_res.start + 1;
+ prom_add_property(node, &crashk_size_prop);
+ }
+
+ of_node_put(node);
+}
+
void __init kexec_setup(void)
{
export_htab_values();
+ export_crashk_values();
+}
+
+static int __init early_parse_crashk(char *p)
+{
+ unsigned long size;
+
+ if (!p)
+ return 1;
+
+ size = memparse(p, &p);
+
+ if (*p == '@')
+ crashk_res.start = memparse(p + 1, &p);
+ else
+ crashk_res.start = KDUMP_KERNELBASE;
+
+ crashk_res.end = crashk_res.start + size - 1;
+
+ return 0;
+}
+early_param("crashkernel", early_parse_crashk);
+
+void __init reserve_crashkernel(void)
+{
+ unsigned long size;
+
+ if (crashk_res.start == 0)
+ return;
+
+ /* We might have got these values via the command line or the
+ * device tree, either way sanitise them now. */
+
+ size = crashk_res.end - crashk_res.start + 1;
+
+ if (crashk_res.start != KDUMP_KERNELBASE)
+ printk("Crash kernel location must be 0x%x\n",
+ KDUMP_KERNELBASE);
+
+ crashk_res.start = KDUMP_KERNELBASE;
+ size = PAGE_ALIGN(size);
+ crashk_res.end = crashk_res.start + size - 1;
+
+ /* Crash kernel trumps memory limit */
+ if (memory_limit && memory_limit <= crashk_res.end) {
+ memory_limit = crashk_res.end + 1;
+ printk("Adjusted memory limit for crashkernel, now 0x%lx\n",
+ memory_limit);
+ }
+
+ lmb_reserve(crashk_res.start, size);
+}
+
+int overlaps_crashkernel(unsigned long start, unsigned long size)
+{
+ return (start + size) > crashk_res.start && start <= crashk_res.end;
}
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index be98202..01d3916 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -216,7 +216,7 @@ _GLOBAL(call_setup_cpu)
lwz r4,0(r4)
add r4,r4,r3
lwz r5,CPU_SPEC_SETUP(r4)
- cmpi 0,r5,0
+ cmpwi 0,r5,0
add r5,r5,r3
beqlr
mtctr r5
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index 2778cce..e8883d4 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -482,7 +482,9 @@ _GLOBAL(identify_cpu)
sub r0,r3,r5
std r0,0(r4)
ld r4,CPU_SPEC_SETUP(r3)
+ cmpdi 0,r4,0
add r4,r4,r5
+ beqlr
ld r4,0(r4)
add r4,r4,r5
mtctr r4
@@ -768,9 +770,6 @@ _GLOBAL(giveup_altivec)
#endif /* CONFIG_ALTIVEC */
-_GLOBAL(__setup_cpu_power3)
- blr
-
_GLOBAL(execve)
li r0,__NR_execve
sc
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index ada50aa..6960f09 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -204,7 +204,7 @@ static void nvram_print_partitions(char * label)
printk(KERN_WARNING "indx\t\tsig\tchks\tlen\tname\n");
list_for_each(p, &nvram_part->partition) {
tmp_part = list_entry(p, struct nvram_partition, partition);
- printk(KERN_WARNING "%d \t%02x\t%02x\t%d\t%s\n",
+ printk(KERN_WARNING "%4d \t%02x\t%02x\t%d\t%s\n",
tmp_part->index, tmp_part->header.signature,
tmp_part->header.checksum, tmp_part->header.length,
tmp_part->header.name);
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index b129d2e..b5431cc 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -1113,9 +1113,10 @@ check_for_io_childs(struct pci_bus *bus, struct resource* res, int *found_vga)
int i;
int rc = 0;
-#define push_end(res, size) do { unsigned long __sz = (size) ; \
- res->end = ((res->end + __sz) / (__sz + 1)) * (__sz + 1) + __sz; \
- } while (0)
+#define push_end(res, mask) do { \
+ BUG_ON((mask+1) & mask); \
+ res->end = (res->end + mask) | mask; \
+} while (0)
list_for_each_entry(dev, &bus->devices, bus_list) {
u16 class = dev->class >> 8;
@@ -1653,7 +1654,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
return -EINVAL;
vma->vm_pgoff = offset >> PAGE_SHIFT;
- vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
vma->vm_page_prot,
mmap_state, write_combine);
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 4c4449b..247937d 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -42,14 +42,6 @@
unsigned long pci_probe_only = 1;
int pci_assign_all_buses = 0;
-/*
- * legal IO pages under MAX_ISA_PORT. This is to ensure we don't touch
- * devices we don't have access to.
- */
-unsigned long io_page_mask;
-
-EXPORT_SYMBOL(io_page_mask);
-
#ifdef CONFIG_PPC_MULTIPLATFORM
static void fixup_resource(struct resource *res, struct pci_dev *dev);
static void do_bus_setup(struct pci_bus *bus);
@@ -235,8 +227,10 @@ struct pci_controller * pcibios_alloc_controller(struct device_node *dev)
pci_setup_pci_controller(phb);
phb->arch_data = dev;
phb->is_dynamic = mem_init_done;
- if (dev)
+ if (dev) {
+ PHB_SET_NODE(phb, of_node_to_nid(dev));
add_linux_pci_domain(dev, phb);
+ }
return phb;
}
@@ -396,7 +390,7 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
dev->current_state = 4; /* unknown power state */
- if (!strcmp(type, "pci")) {
+ if (!strcmp(type, "pci") || !strcmp(type, "pciex")) {
/* a PCI-PCI bridge */
dev->hdr_type = PCI_HEADER_TYPE_BRIDGE;
dev->rom_base_reg = PCI_ROM_ADDRESS1;
@@ -605,7 +599,7 @@ static int __init pcibios_init(void)
iSeries_pcibios_init();
#endif
- printk("PCI: Probing PCI hardware\n");
+ printk(KERN_DEBUG "PCI: Probing PCI hardware\n");
/* Scan all of the recorded PCI controllers. */
list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
@@ -630,14 +624,14 @@ static int __init pcibios_init(void)
/* Cache the location of the ISA bridge (if we have one) */
ppc64_isabridge_dev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
if (ppc64_isabridge_dev != NULL)
- printk("ISA bridge at %s\n", pci_name(ppc64_isabridge_dev));
+ printk(KERN_DEBUG "ISA bridge at %s\n", pci_name(ppc64_isabridge_dev));
#ifdef CONFIG_PPC_MULTIPLATFORM
/* map in PCI I/O space */
phbs_remap_io();
#endif
- printk("PCI: Probing PCI hardware done\n");
+ printk(KERN_DEBUG "PCI: Probing PCI hardware done\n");
return 0;
}
@@ -804,7 +798,7 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
else
prot |= _PAGE_GUARDED;
- printk("PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start,
+ printk(KERN_DEBUG "PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start,
prot);
return __pgprot(prot);
@@ -883,7 +877,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
return -EINVAL;
vma->vm_pgoff = offset >> PAGE_SHIFT;
- vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
vma->vm_page_prot,
mmap_state, write_combine);
@@ -894,8 +887,8 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
return ret;
}
-#ifdef CONFIG_PPC_MULTIPLATFORM
-static ssize_t pci_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t pci_show_devspec(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct pci_dev *pdev;
struct device_node *np;
@@ -907,13 +900,10 @@ static ssize_t pci_show_devspec(struct device *dev, struct device_attribute *att
return sprintf(buf, "%s", np->full_name);
}
static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL);
-#endif /* CONFIG_PPC_MULTIPLATFORM */
void pcibios_add_platform_entries(struct pci_dev *pdev)
{
-#ifdef CONFIG_PPC_MULTIPLATFORM
device_create_file(&pdev->dev, &dev_attr_devspec);
-#endif /* CONFIG_PPC_MULTIPLATFORM */
}
#ifdef CONFIG_PPC_MULTIPLATFORM
@@ -1104,8 +1094,6 @@ void __init pci_setup_phb_io(struct pci_controller *hose, int primary)
pci_process_ISA_OF_ranges(isa_dn, hose->io_base_phys,
hose->io_base_virt);
of_node_put(isa_dn);
- /* Allow all IO */
- io_page_mask = -1;
}
}
@@ -1212,7 +1200,7 @@ int remap_bus_range(struct pci_bus *bus)
return 1;
if (start_phys == 0)
return 1;
- printk("mapping IO %lx -> %lx, size: %lx\n", start_phys, start_virt, size);
+ printk(KERN_DEBUG "mapping IO %lx -> %lx, size: %lx\n", start_phys, start_virt, size);
if (__ioremap_explicit(start_phys, start_virt, size,
_PAGE_NO_CACHE | _PAGE_GUARDED))
return 1;
@@ -1232,27 +1220,13 @@ static void phbs_remap_io(void)
static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
{
struct pci_controller *hose = pci_bus_to_host(dev->bus);
- unsigned long start, end, mask, offset;
+ unsigned long offset;
if (res->flags & IORESOURCE_IO) {
offset = (unsigned long)hose->io_base_virt - pci_io_base;
- start = res->start += offset;
- end = res->end += offset;
-
- /* Need to allow IO access to pages that are in the
- ISA range */
- if (start < MAX_ISA_PORT) {
- if (end > MAX_ISA_PORT)
- end = MAX_ISA_PORT;
-
- start >>= PAGE_SHIFT;
- end >>= PAGE_SHIFT;
-
- /* get the range of pages for the map */
- mask = ((1 << (end+1)) - 1) ^ ((1 << start) - 1);
- io_page_mask |= mask;
- }
+ res->start += offset;
+ res->end += offset;
} else if (res->flags & IORESOURCE_MEM) {
res->start += hose->pci_mem_offset;
res->end += hose->pci_mem_offset;
@@ -1442,3 +1416,12 @@ long sys_pciconfig_iobase(long which, unsigned long in_bus,
return -EOPNOTSUPP;
}
+
+#ifdef CONFIG_NUMA
+int pcibus_to_node(struct pci_bus *bus)
+{
+ struct pci_controller *phb = pci_bus_to_host(bus);
+ return phb->node;
+}
+EXPORT_SYMBOL(pcibus_to_node);
+#endif
diff --git a/arch/powerpc/kernel/pci_direct_iommu.c b/arch/powerpc/kernel/pci_direct_iommu.c
index e1a32f8..72ce082 100644
--- a/arch/powerpc/kernel/pci_direct_iommu.c
+++ b/arch/powerpc/kernel/pci_direct_iommu.c
@@ -82,13 +82,17 @@ static int pci_direct_dma_supported(struct device *dev, u64 mask)
return mask < 0x100000000ull;
}
+static struct dma_mapping_ops pci_direct_ops = {
+ .alloc_coherent = pci_direct_alloc_coherent,
+ .free_coherent = pci_direct_free_coherent,
+ .map_single = pci_direct_map_single,
+ .unmap_single = pci_direct_unmap_single,
+ .map_sg = pci_direct_map_sg,
+ .unmap_sg = pci_direct_unmap_sg,
+ .dma_supported = pci_direct_dma_supported,
+};
+
void __init pci_direct_iommu_init(void)
{
- pci_dma_ops.alloc_coherent = pci_direct_alloc_coherent;
- pci_dma_ops.free_coherent = pci_direct_free_coherent;
- pci_dma_ops.map_single = pci_direct_map_single;
- pci_dma_ops.unmap_single = pci_direct_unmap_single;
- pci_dma_ops.map_sg = pci_direct_map_sg;
- pci_dma_ops.unmap_sg = pci_direct_unmap_sg;
- pci_dma_ops.dma_supported = pci_direct_dma_supported;
+ pci_dma_ops = pci_direct_ops;
}
diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c
index 12c4c9e..1c18953 100644
--- a/arch/powerpc/kernel/pci_dn.c
+++ b/arch/powerpc/kernel/pci_dn.c
@@ -31,6 +31,7 @@
#include <asm/pci-bridge.h>
#include <asm/pSeries_reconfig.h>
#include <asm/ppc-pci.h>
+#include <asm/firmware.h>
/*
* Traverse_func that inits the PCI fields of the device node.
@@ -59,6 +60,11 @@ static void * __devinit update_dn_pci_info(struct device_node *dn, void *data)
pdn->busno = (regs[0] >> 16) & 0xff;
pdn->devfn = (regs[0] >> 8) & 0xff;
}
+ if (firmware_has_feature(FW_FEATURE_ISERIES)) {
+ u32 *busp = (u32 *)get_property(dn, "linux,subbus", NULL);
+ if (busp)
+ pdn->bussubno = *busp;
+ }
pdn->pci_ext_config_space = (type && *type == 1);
return NULL;
diff --git a/arch/powerpc/kernel/pci_iommu.c b/arch/powerpc/kernel/pci_iommu.c
index c1d95e1..0688b25 100644
--- a/arch/powerpc/kernel/pci_iommu.c
+++ b/arch/powerpc/kernel/pci_iommu.c
@@ -44,16 +44,16 @@
*/
#define PCI_GET_DN(dev) ((struct device_node *)((dev)->sysdata))
-static inline struct iommu_table *devnode_table(struct device *dev)
+static inline struct iommu_table *device_to_table(struct device *hwdev)
{
struct pci_dev *pdev;
- if (!dev) {
+ if (!hwdev) {
pdev = ppc64_isabridge_dev;
if (!pdev)
return NULL;
} else
- pdev = to_pci_dev(dev);
+ pdev = to_pci_dev(hwdev);
return PCI_DN(PCI_GET_DN(pdev))->iommu_table;
}
@@ -85,14 +85,15 @@ static inline unsigned long device_to_mask(struct device *hwdev)
static void *pci_iommu_alloc_coherent(struct device *hwdev, size_t size,
dma_addr_t *dma_handle, gfp_t flag)
{
- return iommu_alloc_coherent(devnode_table(hwdev), size, dma_handle,
- device_to_mask(hwdev), flag);
+ return iommu_alloc_coherent(device_to_table(hwdev), size, dma_handle,
+ device_to_mask(hwdev), flag,
+ pcibus_to_node(to_pci_dev(hwdev)->bus));
}
static void pci_iommu_free_coherent(struct device *hwdev, size_t size,
void *vaddr, dma_addr_t dma_handle)
{
- iommu_free_coherent(devnode_table(hwdev), size, vaddr, dma_handle);
+ iommu_free_coherent(device_to_table(hwdev), size, vaddr, dma_handle);
}
/* Creates TCEs for a user provided buffer. The user buffer must be
@@ -104,7 +105,7 @@ static void pci_iommu_free_coherent(struct device *hwdev, size_t size,
static dma_addr_t pci_iommu_map_single(struct device *hwdev, void *vaddr,
size_t size, enum dma_data_direction direction)
{
- return iommu_map_single(devnode_table(hwdev), vaddr, size,
+ return iommu_map_single(device_to_table(hwdev), vaddr, size,
device_to_mask(hwdev), direction);
}
@@ -112,27 +113,27 @@ static dma_addr_t pci_iommu_map_single(struct device *hwdev, void *vaddr,
static void pci_iommu_unmap_single(struct device *hwdev, dma_addr_t dma_handle,
size_t size, enum dma_data_direction direction)
{
- iommu_unmap_single(devnode_table(hwdev), dma_handle, size, direction);
+ iommu_unmap_single(device_to_table(hwdev), dma_handle, size, direction);
}
static int pci_iommu_map_sg(struct device *pdev, struct scatterlist *sglist,
int nelems, enum dma_data_direction direction)
{
- return iommu_map_sg(pdev, devnode_table(pdev), sglist,
+ return iommu_map_sg(pdev, device_to_table(pdev), sglist,
nelems, device_to_mask(pdev), direction);
}
static void pci_iommu_unmap_sg(struct device *pdev, struct scatterlist *sglist,
int nelems, enum dma_data_direction direction)
{
- iommu_unmap_sg(devnode_table(pdev), sglist, nelems, direction);
+ iommu_unmap_sg(device_to_table(pdev), sglist, nelems, direction);
}
/* We support DMA to/from any memory page via the iommu */
static int pci_iommu_dma_supported(struct device *dev, u64 mask)
{
- struct iommu_table *tbl = devnode_table(dev);
+ struct iommu_table *tbl = device_to_table(dev);
if (!tbl || tbl->it_offset > mask) {
printk(KERN_INFO "Warning: IOMMU table offset too big for device mask\n");
@@ -147,13 +148,17 @@ static int pci_iommu_dma_supported(struct device *dev, u64 mask)
return 1;
}
+struct dma_mapping_ops pci_iommu_ops = {
+ .alloc_coherent = pci_iommu_alloc_coherent,
+ .free_coherent = pci_iommu_free_coherent,
+ .map_single = pci_iommu_map_single,
+ .unmap_single = pci_iommu_unmap_single,
+ .map_sg = pci_iommu_map_sg,
+ .unmap_sg = pci_iommu_unmap_sg,
+ .dma_supported = pci_iommu_dma_supported,
+};
+
void pci_iommu_init(void)
{
- pci_dma_ops.alloc_coherent = pci_iommu_alloc_coherent;
- pci_dma_ops.free_coherent = pci_iommu_free_coherent;
- pci_dma_ops.map_single = pci_iommu_map_single;
- pci_dma_ops.unmap_single = pci_iommu_unmap_single;
- pci_dma_ops.map_sg = pci_iommu_map_sg;
- pci_dma_ops.unmap_sg = pci_iommu_unmap_sg;
- pci_dma_ops.dma_supported = pci_iommu_dma_supported;
+ pci_dma_ops = pci_iommu_ops;
}
diff --git a/arch/powerpc/kernel/proc_ppc64.c b/arch/powerpc/kernel/proc_ppc64.c
index 3c2cf66..2ab8f2b 100644
--- a/arch/powerpc/kernel/proc_ppc64.c
+++ b/arch/powerpc/kernel/proc_ppc64.c
@@ -52,7 +52,7 @@ static int __init proc_ppc64_create(void)
if (!root)
return 1;
- if (!machine_is(pseries) && !machine_is(cell))
+ if (!of_find_node_by_path("/rtas"))
return 0;
if (!proc_mkdir("rtas", root))
@@ -115,8 +115,6 @@ static int page_map_mmap( struct file *file, struct vm_area_struct *vma )
{
struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
- vma->vm_flags |= VM_SHM | VM_LOCKED;
-
if ((vma->vm_end - vma->vm_start) > dp->size)
return -EINVAL;
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 2dd47d2d..e473245 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -708,6 +708,61 @@ int get_fpexc_mode(struct task_struct *tsk, unsigned long adr)
return put_user(val, (unsigned int __user *) adr);
}
+int set_endian(struct task_struct *tsk, unsigned int val)
+{
+ struct pt_regs *regs = tsk->thread.regs;
+
+ if ((val == PR_ENDIAN_LITTLE && !cpu_has_feature(CPU_FTR_REAL_LE)) ||
+ (val == PR_ENDIAN_PPC_LITTLE && !cpu_has_feature(CPU_FTR_PPC_LE)))
+ return -EINVAL;
+
+ if (regs == NULL)
+ return -EINVAL;
+
+ if (val == PR_ENDIAN_BIG)
+ regs->msr &= ~MSR_LE;
+ else if (val == PR_ENDIAN_LITTLE || val == PR_ENDIAN_PPC_LITTLE)
+ regs->msr |= MSR_LE;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+int get_endian(struct task_struct *tsk, unsigned long adr)
+{
+ struct pt_regs *regs = tsk->thread.regs;
+ unsigned int val;
+
+ if (!cpu_has_feature(CPU_FTR_PPC_LE) &&
+ !cpu_has_feature(CPU_FTR_REAL_LE))
+ return -EINVAL;
+
+ if (regs == NULL)
+ return -EINVAL;
+
+ if (regs->msr & MSR_LE) {
+ if (cpu_has_feature(CPU_FTR_REAL_LE))
+ val = PR_ENDIAN_LITTLE;
+ else
+ val = PR_ENDIAN_PPC_LITTLE;
+ } else
+ val = PR_ENDIAN_BIG;
+
+ return put_user(val, (unsigned int __user *)adr);
+}
+
+int set_unalign_ctl(struct task_struct *tsk, unsigned int val)
+{
+ tsk->thread.align_ctl = val;
+ return 0;
+}
+
+int get_unalign_ctl(struct task_struct *tsk, unsigned long adr)
+{
+ return put_user(tsk->thread.align_ctl, (unsigned int __user *)adr);
+}
+
#define TRUNC_PTR(x) ((typeof(x))(((unsigned long)(x)) & 0xffffffff))
int sys_clone(unsigned long clone_flags, unsigned long usp,
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 9a07f97..483455c 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -50,6 +50,7 @@
#include <asm/machdep.h>
#include <asm/pSeries_reconfig.h>
#include <asm/pci-bridge.h>
+#include <asm/kexec.h>
#ifdef DEBUG
#define DBG(fmt...) printk(KERN_ERR fmt)
@@ -836,6 +837,42 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
return mem;
}
+static int __init early_parse_mem(char *p)
+{
+ if (!p)
+ return 1;
+
+ memory_limit = PAGE_ALIGN(memparse(p, &p));
+ DBG("memory limit = 0x%lx\n", memory_limit);
+
+ return 0;
+}
+early_param("mem", early_parse_mem);
+
+/*
+ * The device tree may be allocated below our memory limit, or inside the
+ * crash kernel region for kdump. If so, move it out now.
+ */
+static void move_device_tree(void)
+{
+ unsigned long start, size;
+ void *p;
+
+ DBG("-> move_device_tree\n");
+
+ start = __pa(initial_boot_params);
+ size = initial_boot_params->totalsize;
+
+ if ((memory_limit && (start + size) > memory_limit) ||
+ overlaps_crashkernel(start, size)) {
+ p = __va(lmb_alloc_base(size, PAGE_SIZE, lmb.rmo_size));
+ memcpy(p, initial_boot_params, size);
+ initial_boot_params = (struct boot_param_header *)p;
+ DBG("Moved device tree to 0x%p\n", p);
+ }
+
+ DBG("<- move_device_tree\n");
+}
/**
* unflattens the device-tree passed by the firmware, creating the
@@ -911,7 +948,10 @@ static struct ibm_pa_feature {
{CPU_FTR_CTRL, 0, 0, 3, 0},
{CPU_FTR_NOEXECUTE, 0, 0, 6, 0},
{CPU_FTR_NODSISRALIGN, 0, 1, 1, 1},
+#if 0
+ /* put this back once we know how to test if firmware does 64k IO */
{CPU_FTR_CI_LARGE_PAGE, 0, 1, 2, 0},
+#endif
};
static void __init check_cpu_pa_features(unsigned long node)
@@ -1070,6 +1110,7 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
iommu_force_on = 1;
#endif
+ /* mem=x on the command line is the preferred mechanism */
lprop = of_get_flat_dt_prop(node, "linux,memory-limit", NULL);
if (lprop)
memory_limit = *lprop;
@@ -1123,17 +1164,6 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
DBG("Command line is: %s\n", cmd_line);
- if (strstr(cmd_line, "mem=")) {
- char *p, *q;
-
- for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) {
- q = p + 4;
- if (p > cmd_line && p[-1] != ' ')
- continue;
- memory_limit = memparse(q, &q);
- }
- }
-
/* break now */
return 1;
}
@@ -1237,9 +1267,17 @@ static void __init early_reserve_mem(void)
{
u64 base, size;
u64 *reserve_map;
+ unsigned long self_base;
+ unsigned long self_size;
reserve_map = (u64 *)(((unsigned long)initial_boot_params) +
initial_boot_params->off_mem_rsvmap);
+
+ /* before we do anything, lets reserve the dt blob */
+ self_base = __pa((unsigned long)initial_boot_params);
+ self_size = initial_boot_params->totalsize;
+ lmb_reserve(self_base, self_size);
+
#ifdef CONFIG_PPC32
/*
* Handle the case where we might be booting from an old kexec
@@ -1254,6 +1292,9 @@ static void __init early_reserve_mem(void)
size_32 = *(reserve_map_32++);
if (size_32 == 0)
break;
+ /* skip if the reservation is for the blob */
+ if (base_32 == self_base && size_32 == self_size)
+ continue;
DBG("reserving: %x -> %x\n", base_32, size_32);
lmb_reserve(base_32, size_32);
}
@@ -1265,6 +1306,9 @@ static void __init early_reserve_mem(void)
size = *(reserve_map++);
if (size == 0)
break;
+ /* skip if the reservation is for the blob */
+ if (base == self_base && size == self_size)
+ continue;
DBG("reserving: %llx -> %llx\n", base, size);
lmb_reserve(base, size);
}
@@ -1292,18 +1336,26 @@ void __init early_init_devtree(void *params)
lmb_init();
of_scan_flat_dt(early_init_dt_scan_root, NULL);
of_scan_flat_dt(early_init_dt_scan_memory, NULL);
- lmb_enforce_memory_limit(memory_limit);
- lmb_analyze();
- DBG("Phys. mem: %lx\n", lmb_phys_mem_size());
+ /* Save command line for /proc/cmdline and then parse parameters */
+ strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE);
+ parse_early_param();
/* Reserve LMB regions used by kernel, initrd, dt, etc... */
lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START);
-#ifdef CONFIG_CRASH_DUMP
- lmb_reserve(0, KDUMP_RESERVE_LIMIT);
-#endif
+ reserve_kdump_trampoline();
+ reserve_crashkernel();
early_reserve_mem();
+ lmb_enforce_memory_limit(memory_limit);
+ lmb_analyze();
+
+ DBG("Phys. mem: %lx\n", lmb_phys_mem_size());
+
+ /* We may need to relocate the flat tree, do it now.
+ * FIXME .. and the initrd too? */
+ move_device_tree();
+
DBG("Scanning CPUs ...\n");
/* Retreive CPU related informations from the flat tree
@@ -2053,29 +2105,46 @@ int prom_update_property(struct device_node *np,
return 0;
}
-#ifdef CONFIG_KEXEC
-/* We may have allocated the flat device tree inside the crash kernel region
- * in prom_init. If so we need to move it out into regular memory. */
-void kdump_move_device_tree(void)
-{
- unsigned long start, end;
- struct boot_param_header *new;
-
- start = __pa((unsigned long)initial_boot_params);
- end = start + initial_boot_params->totalsize;
-
- if (end < crashk_res.start || start > crashk_res.end)
- return;
- new = (struct boot_param_header*)
- __va(lmb_alloc(initial_boot_params->totalsize, PAGE_SIZE));
-
- memcpy(new, initial_boot_params, initial_boot_params->totalsize);
+/* Find the device node for a given logical cpu number, also returns the cpu
+ * local thread number (index in ibm,interrupt-server#s) if relevant and
+ * asked for (non NULL)
+ */
+struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
+{
+ int hardid;
+ struct device_node *np;
- initial_boot_params = new;
+ hardid = get_hard_smp_processor_id(cpu);
- DBG("Flat device tree blob moved to %p\n", initial_boot_params);
+ for_each_node_by_type(np, "cpu") {
+ u32 *intserv;
+ unsigned int plen, t;
- /* XXX should we unreserve the old DT? */
+ /* Check for ibm,ppc-interrupt-server#s. If it doesn't exist
+ * fallback to "reg" property and assume no threads
+ */
+ intserv = (u32 *)get_property(np, "ibm,ppc-interrupt-server#s",
+ &plen);
+ if (intserv == NULL) {
+ u32 *reg = (u32 *)get_property(np, "reg", NULL);
+ if (reg == NULL)
+ continue;
+ if (*reg == hardid) {
+ if (thread)
+ *thread = 0;
+ return np;
+ }
+ } else {
+ plen /= sizeof(u32);
+ for (t = 0; t < plen; t++) {
+ if (hardid == intserv[t]) {
+ if (thread)
+ *thread = t;
+ return np;
+ }
+ }
+ }
+ }
+ return NULL;
}
-#endif /* CONFIG_KEXEC */
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index f70bd09..8c28eb0 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -194,19 +194,12 @@ static int __initdata of_platform;
static char __initdata prom_cmd_line[COMMAND_LINE_SIZE];
-static unsigned long __initdata prom_memory_limit;
-
static unsigned long __initdata alloc_top;
static unsigned long __initdata alloc_top_high;
static unsigned long __initdata alloc_bottom;
static unsigned long __initdata rmo_top;
static unsigned long __initdata ram_top;
-#ifdef CONFIG_KEXEC
-static unsigned long __initdata prom_crashk_base;
-static unsigned long __initdata prom_crashk_size;
-#endif
-
static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE];
static int __initdata mem_reserve_cnt;
@@ -574,7 +567,7 @@ static void __init early_cmdline_parse(void)
if ((long)_prom->chosen > 0)
l = prom_getprop(_prom->chosen, "bootargs", p, COMMAND_LINE_SIZE-1);
#ifdef CONFIG_CMDLINE
- if (l == 0) /* dbl check */
+ if (l <= 0 || p[0] == '\0') /* dbl check */
strlcpy(RELOC(prom_cmd_line),
RELOC(CONFIG_CMDLINE), sizeof(prom_cmd_line));
#endif /* CONFIG_CMDLINE */
@@ -593,45 +586,6 @@ static void __init early_cmdline_parse(void)
RELOC(iommu_force_on) = 1;
}
#endif
-
- opt = strstr(RELOC(prom_cmd_line), RELOC("mem="));
- if (opt) {
- opt += 4;
- RELOC(prom_memory_limit) = prom_memparse(opt, (const char **)&opt);
-#ifdef CONFIG_PPC64
- /* Align to 16 MB == size of ppc64 large page */
- RELOC(prom_memory_limit) = ALIGN(RELOC(prom_memory_limit), 0x1000000);
-#endif
- }
-
-#ifdef CONFIG_KEXEC
- /*
- * crashkernel=size@addr specifies the location to reserve for
- * crash kernel.
- */
- opt = strstr(RELOC(prom_cmd_line), RELOC("crashkernel="));
- if (opt) {
- opt += 12;
- RELOC(prom_crashk_size) =
- prom_memparse(opt, (const char **)&opt);
-
- if (ALIGN(RELOC(prom_crashk_size), 0x1000000) !=
- RELOC(prom_crashk_size)) {
- prom_printf("Warning: crashkernel size is not "
- "aligned to 16MB\n");
- }
-
- /*
- * At present, the crash kernel always run at 32MB.
- * Just ignore whatever user passed.
- */
- RELOC(prom_crashk_base) = 0x2000000;
- if (*opt == '@') {
- prom_printf("Warning: PPC64 kdump kernel always runs "
- "at 32 MB\n");
- }
- }
-#endif
}
#ifdef CONFIG_PPC_PSERIES
@@ -1116,29 +1070,6 @@ static void __init prom_init_mem(void)
}
/*
- * If prom_memory_limit is set we reduce the upper limits *except* for
- * alloc_top_high. This must be the real top of RAM so we can put
- * TCE's up there.
- */
-
- RELOC(alloc_top_high) = RELOC(ram_top);
-
- if (RELOC(prom_memory_limit)) {
- if (RELOC(prom_memory_limit) <= RELOC(alloc_bottom)) {
- prom_printf("Ignoring mem=%x <= alloc_bottom.\n",
- RELOC(prom_memory_limit));
- RELOC(prom_memory_limit) = 0;
- } else if (RELOC(prom_memory_limit) >= RELOC(ram_top)) {
- prom_printf("Ignoring mem=%x >= ram_top.\n",
- RELOC(prom_memory_limit));
- RELOC(prom_memory_limit) = 0;
- } else {
- RELOC(ram_top) = RELOC(prom_memory_limit);
- RELOC(rmo_top) = min(RELOC(rmo_top), RELOC(prom_memory_limit));
- }
- }
-
- /*
* Setup our top alloc point, that is top of RMO or top of
* segment 0 when running non-LPAR.
* Some RS64 machines have buggy firmware where claims up at
@@ -1150,20 +1081,14 @@ static void __init prom_init_mem(void)
RELOC(rmo_top) = RELOC(ram_top);
RELOC(rmo_top) = min(0x30000000ul, RELOC(rmo_top));
RELOC(alloc_top) = RELOC(rmo_top);
+ RELOC(alloc_top_high) = RELOC(ram_top);
prom_printf("memory layout at init:\n");
- prom_printf(" memory_limit : %x (16 MB aligned)\n", RELOC(prom_memory_limit));
prom_printf(" alloc_bottom : %x\n", RELOC(alloc_bottom));
prom_printf(" alloc_top : %x\n", RELOC(alloc_top));
prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high));
prom_printf(" rmo_top : %x\n", RELOC(rmo_top));
prom_printf(" ram_top : %x\n", RELOC(ram_top));
-#ifdef CONFIG_KEXEC
- if (RELOC(prom_crashk_base)) {
- prom_printf(" crashk_base : %x\n", RELOC(prom_crashk_base));
- prom_printf(" crashk_size : %x\n", RELOC(prom_crashk_size));
- }
-#endif
}
@@ -1349,16 +1274,10 @@ static void __init prom_initialize_tce_table(void)
reserve_mem(local_alloc_bottom, local_alloc_top - local_alloc_bottom);
- if (RELOC(prom_memory_limit)) {
- /*
- * We align the start to a 16MB boundary so we can map
- * the TCE area using large pages if possible.
- * The end should be the top of RAM so no need to align it.
- */
- RELOC(prom_tce_alloc_start) = _ALIGN_DOWN(local_alloc_bottom,
- 0x1000000);
- RELOC(prom_tce_alloc_end) = local_alloc_top;
- }
+ /* These are only really needed if there is a memory limit in
+ * effect, but we don't know so export them always. */
+ RELOC(prom_tce_alloc_start) = local_alloc_bottom;
+ RELOC(prom_tce_alloc_end) = local_alloc_top;
/* Flag the first invalid entry */
prom_debug("ending prom_initialize_tce_table\n");
@@ -2041,11 +1960,7 @@ static void __init flatten_device_tree(void)
/* Version 16 is not backward compatible */
hdr->last_comp_version = 0x10;
- /* Reserve the whole thing and copy the reserve map in, we
- * also bump mem_reserve_cnt to cause further reservations to
- * fail since it's too late.
- */
- reserve_mem(RELOC(dt_header_start), hdr->totalsize);
+ /* Copy the reserve map in */
memcpy(rsvmap, RELOC(mem_reserve_map), sizeof(mem_reserve_map));
#ifdef DEBUG_PROM
@@ -2058,6 +1973,9 @@ static void __init flatten_device_tree(void)
RELOC(mem_reserve_map)[i].size);
}
#endif
+ /* Bump mem_reserve_cnt to cause further reservations to fail
+ * since it's too late.
+ */
RELOC(mem_reserve_cnt) = MEM_RESERVE_MAP_SIZE;
prom_printf("Device tree strings 0x%x -> 0x%x\n",
@@ -2280,10 +2198,6 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
*/
prom_init_mem();
-#ifdef CONFIG_KEXEC
- if (RELOC(prom_crashk_base))
- reserve_mem(RELOC(prom_crashk_base), RELOC(prom_crashk_size));
-#endif
/*
* Determine which cpu is actually running right _now_
*/
@@ -2317,10 +2231,6 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
/*
* Fill in some infos for use by the kernel later on
*/
- if (RELOC(prom_memory_limit))
- prom_setprop(_prom->chosen, "/chosen", "linux,memory-limit",
- &RELOC(prom_memory_limit),
- sizeof(prom_memory_limit));
#ifdef CONFIG_PPC64
if (RELOC(ppc64_iommu_off))
prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off",
@@ -2340,16 +2250,6 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
}
#endif
-#ifdef CONFIG_KEXEC
- if (RELOC(prom_crashk_base)) {
- prom_setprop(_prom->chosen, "/chosen", "linux,crashkernel-base",
- PTRRELOC(&prom_crashk_base),
- sizeof(RELOC(prom_crashk_base)));
- prom_setprop(_prom->chosen, "/chosen", "linux,crashkernel-size",
- PTRRELOC(&prom_crashk_size),
- sizeof(RELOC(prom_crashk_size)));
- }
-#endif
/*
* Fixup any known bugs in the device-tree
*/
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
index 3934c22..45df420 100644
--- a/arch/powerpc/kernel/prom_parse.c
+++ b/arch/powerpc/kernel/prom_parse.c
@@ -548,3 +548,28 @@ int of_pci_address_to_resource(struct device_node *dev, int bar,
return __of_address_to_resource(dev, addrp, size, flags, r);
}
EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
+
+void of_parse_dma_window(struct device_node *dn, unsigned char *dma_window_prop,
+ unsigned long *busno, unsigned long *phys, unsigned long *size)
+{
+ u32 *dma_window, cells;
+ unsigned char *prop;
+
+ dma_window = (u32 *)dma_window_prop;
+
+ /* busno is always one cell */
+ *busno = *(dma_window++);
+
+ prop = get_property(dn, "ibm,#dma-address-cells", NULL);
+ if (!prop)
+ prop = get_property(dn, "#address-cells", NULL);
+
+ cells = prop ? *(u32 *)prop : prom_n_addr_cells(dn);
+ *phys = of_read_addr(dma_window, cells);
+
+ dma_window += cells;
+
+ prop = get_property(dn, "ibm,#dma-size-cells", NULL);
+ cells = prop ? *(u32 *)prop : prom_n_size_cells(dn);
+ *size = of_read_addr(dma_window, cells);
+}
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 4a677d1..5563e2e 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -404,7 +404,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
ret = ptrace_detach(child, data);
break;
-#ifdef CONFIG_PPC64
case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
int i;
unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
@@ -468,7 +467,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
}
break;
}
-#endif /* CONFIG_PPC64 */
#ifdef CONFIG_ALTIVEC
case PTRACE_GETVRREGS:
diff --git a/arch/powerpc/kernel/rtas-rtc.c b/arch/powerpc/kernel/rtas-rtc.c
index 34d073fb..77578c0 100644
--- a/arch/powerpc/kernel/rtas-rtc.c
+++ b/arch/powerpc/kernel/rtas-rtc.c
@@ -14,19 +14,20 @@
unsigned long __init rtas_get_boot_time(void)
{
int ret[8];
- int error, wait_time;
+ int error;
+ unsigned int wait_time;
u64 max_wait_tb;
max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
do {
error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
- if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) {
- wait_time = rtas_extended_busy_delay_time(error);
+
+ wait_time = rtas_busy_delay_time(error);
+ if (wait_time) {
/* This is boot time so we spin. */
udelay(wait_time*1000);
- error = RTAS_CLOCK_BUSY;
}
- } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb));
+ } while (wait_time && (get_tb() < max_wait_tb));
if (error != 0 && printk_ratelimit()) {
printk(KERN_WARNING "error: reading the clock failed (%d)\n",
@@ -44,24 +45,25 @@ unsigned long __init rtas_get_boot_time(void)
void rtas_get_rtc_time(struct rtc_time *rtc_tm)
{
int ret[8];
- int error, wait_time;
+ int error;
+ unsigned int wait_time;
u64 max_wait_tb;
max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
do {
error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
- if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) {
+
+ wait_time = rtas_busy_delay_time(error);
+ if (wait_time) {
if (in_interrupt() && printk_ratelimit()) {
memset(rtc_tm, 0, sizeof(struct rtc_time));
printk(KERN_WARNING "error: reading clock"
" would delay interrupt\n");
return; /* delay not allowed */
}
- wait_time = rtas_extended_busy_delay_time(error);
msleep(wait_time);
- error = RTAS_CLOCK_BUSY;
}
- } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb));
+ } while (wait_time && (get_tb() < max_wait_tb));
if (error != 0 && printk_ratelimit()) {
printk(KERN_WARNING "error: reading the clock failed (%d)\n",
@@ -88,14 +90,14 @@ int rtas_set_rtc_time(struct rtc_time *tm)
tm->tm_year + 1900, tm->tm_mon + 1,
tm->tm_mday, tm->tm_hour, tm->tm_min,
tm->tm_sec, 0);
- if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) {
+
+ wait_time = rtas_busy_delay_time(error);
+ if (wait_time) {
if (in_interrupt())
return 1; /* probably decrementer */
- wait_time = rtas_extended_busy_delay_time(error);
msleep(wait_time);
- error = RTAS_CLOCK_BUSY;
}
- } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb));
+ } while (wait_time && (get_tb() < max_wait_tb));
if (error != 0 && printk_ratelimit())
printk(KERN_WARNING "error: setting the clock failed (%d)\n",
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 0112318..17dc791 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -370,24 +370,36 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...)
return ret;
}
-/* Given an RTAS status code of 990n compute the hinted delay of 10^n
- * (last digit) milliseconds. For now we bound at n=5 (100 sec).
+/* For RTAS_BUSY (-2), delay for 1 millisecond. For an extended busy status
+ * code of 990n, perform the hinted delay of 10^n (last digit) milliseconds.
*/
-unsigned int rtas_extended_busy_delay_time(int status)
+unsigned int rtas_busy_delay_time(int status)
{
- int order = status - 9900;
- unsigned long ms;
+ int order;
+ unsigned int ms = 0;
+
+ if (status == RTAS_BUSY) {
+ ms = 1;
+ } else if (status >= 9900 && status <= 9905) {
+ order = status - 9900;
+ for (ms = 1; order > 0; order--)
+ ms *= 10;
+ }
- if (order < 0)
- order = 0; /* RTC depends on this for -2 clock busy */
- else if (order > 5)
- order = 5; /* bound */
+ return ms;
+}
- /* Use microseconds for reasonable accuracy */
- for (ms = 1; order > 0; order--)
- ms *= 10;
+/* For an RTAS busy status code, perform the hinted delay. */
+unsigned int rtas_busy_delay(int status)
+{
+ unsigned int ms;
- return ms;
+ might_sleep();
+ ms = rtas_busy_delay_time(status);
+ if (ms)
+ msleep(ms);
+
+ return ms;
}
int rtas_error_rc(int rtas_rc)
@@ -438,22 +450,14 @@ int rtas_get_power_level(int powerdomain, int *level)
int rtas_set_power_level(int powerdomain, int level, int *setlevel)
{
int token = rtas_token("set-power-level");
- unsigned int wait_time;
int rc;
if (token == RTAS_UNKNOWN_SERVICE)
return -ENOENT;
- while (1) {
+ do {
rc = rtas_call(token, 2, 2, setlevel, powerdomain, level);
- if (rc == RTAS_BUSY)
- udelay(1);
- else if (rtas_is_extended_busy(rc)) {
- wait_time = rtas_extended_busy_delay_time(rc);
- udelay(wait_time * 1000);
- } else
- break;
- }
+ } while (rtas_busy_delay(rc));
if (rc < 0)
return rtas_error_rc(rc);
@@ -463,22 +467,14 @@ int rtas_set_power_level(int powerdomain, int level, int *setlevel)
int rtas_get_sensor(int sensor, int index, int *state)
{
int token = rtas_token("get-sensor-state");
- unsigned int wait_time;
int rc;
if (token == RTAS_UNKNOWN_SERVICE)
return -ENOENT;
- while (1) {
+ do {
rc = rtas_call(token, 2, 2, state, sensor, index);
- if (rc == RTAS_BUSY)
- udelay(1);
- else if (rtas_is_extended_busy(rc)) {
- wait_time = rtas_extended_busy_delay_time(rc);
- udelay(wait_time * 1000);
- } else
- break;
- }
+ } while (rtas_busy_delay(rc));
if (rc < 0)
return rtas_error_rc(rc);
@@ -488,23 +484,14 @@ int rtas_get_sensor(int sensor, int index, int *state)
int rtas_set_indicator(int indicator, int index, int new_value)
{
int token = rtas_token("set-indicator");
- unsigned int wait_time;
int rc;
if (token == RTAS_UNKNOWN_SERVICE)
return -ENOENT;
- while (1) {
+ do {
rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value);
- if (rc == RTAS_BUSY)
- udelay(1);
- else if (rtas_is_extended_busy(rc)) {
- wait_time = rtas_extended_busy_delay_time(rc);
- udelay(wait_time * 1000);
- }
- else
- break;
- }
+ } while (rtas_busy_delay(rc));
if (rc < 0)
return rtas_error_rc(rc);
@@ -555,13 +542,11 @@ void rtas_os_term(char *str)
do {
status = rtas_call(rtas_token("ibm,os-term"), 1, 1, NULL,
__pa(rtas_os_term_buf));
+ } while (rtas_busy_delay(status));
- if (status == RTAS_BUSY)
- udelay(1);
- else if (status != 0)
- printk(KERN_EMERG "ibm,os-term call failed %d\n",
+ if (status != 0)
+ printk(KERN_EMERG "ibm,os-term call failed %d\n",
status);
- } while (status == RTAS_BUSY);
}
static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE;
@@ -608,9 +593,31 @@ out:
static int rtas_ibm_suspend_me(struct rtas_args *args)
{
int i;
+ long state;
+ long rc;
+ unsigned long dummy;
struct rtas_suspend_me_data data;
+ /* Make sure the state is valid */
+ rc = plpar_hcall(H_VASI_STATE,
+ ((u64)args->args[0] << 32) | args->args[1],
+ 0, 0, 0,
+ &state, &dummy, &dummy);
+
+ if (rc) {
+ printk(KERN_ERR "rtas_ibm_suspend_me: vasi_state returned %ld\n",rc);
+ return rc;
+ } else if (state == H_VASI_ENABLED) {
+ args->args[args->nargs] = RTAS_NOT_SUSPENDABLE;
+ return 0;
+ } else if (state != H_VASI_SUSPENDING) {
+ printk(KERN_ERR "rtas_ibm_suspend_me: vasi_state returned state %ld\n",
+ state);
+ args->args[args->nargs] = -1;
+ return 0;
+ }
+
data.waiting = 1;
data.args = args;
@@ -789,7 +796,8 @@ EXPORT_SYMBOL(rtas_token);
EXPORT_SYMBOL(rtas_call);
EXPORT_SYMBOL(rtas_data_buf);
EXPORT_SYMBOL(rtas_data_buf_lock);
-EXPORT_SYMBOL(rtas_extended_busy_delay_time);
+EXPORT_SYMBOL(rtas_busy_delay_time);
+EXPORT_SYMBOL(rtas_busy_delay);
EXPORT_SYMBOL(rtas_get_sensor);
EXPORT_SYMBOL(rtas_get_power_level);
EXPORT_SYMBOL(rtas_set_power_level);
diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c
index aaf384c..1442b63 100644
--- a/arch/powerpc/kernel/rtas_flash.c
+++ b/arch/powerpc/kernel/rtas_flash.c
@@ -365,20 +365,12 @@ static int rtas_excl_release(struct inode *inode, struct file *file)
static void manage_flash(struct rtas_manage_flash_t *args_buf)
{
- unsigned int wait_time;
s32 rc;
- while (1) {
+ do {
rc = rtas_call(rtas_token("ibm,manage-flash-image"), 1,
1, NULL, args_buf->op);
- if (rc == RTAS_RC_BUSY)
- udelay(1);
- else if (rtas_is_extended_busy(rc)) {
- wait_time = rtas_extended_busy_delay_time(rc);
- udelay(wait_time * 1000);
- } else
- break;
- }
+ } while (rtas_busy_delay(rc));
args_buf->status = rc;
}
@@ -451,27 +443,18 @@ static ssize_t manage_flash_write(struct file *file, const char __user *buf,
static void validate_flash(struct rtas_validate_flash_t *args_buf)
{
int token = rtas_token("ibm,validate-flash-image");
- unsigned int wait_time;
int update_results;
s32 rc;
rc = 0;
- while(1) {
+ do {
spin_lock(&rtas_data_buf_lock);
memcpy(rtas_data_buf, args_buf->buf, VALIDATE_BUF_SIZE);
rc = rtas_call(token, 2, 2, &update_results,
(u32) __pa(rtas_data_buf), args_buf->buf_size);
memcpy(args_buf->buf, rtas_data_buf, VALIDATE_BUF_SIZE);
spin_unlock(&rtas_data_buf_lock);
-
- if (rc == RTAS_RC_BUSY)
- udelay(1);
- else if (rtas_is_extended_busy(rc)) {
- wait_time = rtas_extended_busy_delay_time(rc);
- udelay(wait_time * 1000);
- } else
- break;
- }
+ } while (rtas_busy_delay(rc));
args_buf->status = rc;
args_buf->update_results = update_results;
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c
index 57b539a..6eb7e49 100644
--- a/arch/powerpc/kernel/rtas_pci.c
+++ b/arch/powerpc/kernel/rtas_pci.c
@@ -313,7 +313,9 @@ unsigned long __init find_and_init_phbs(void)
for (node = of_get_next_child(root, NULL);
node != NULL;
node = of_get_next_child(root, node)) {
- if (node->type == NULL || strcmp(node->type, "pci") != 0)
+
+ if (node->type == NULL || (strcmp(node->type, "pci") != 0 &&
+ strcmp(node->type, "pciex") != 0))
continue;
phb = pcibios_alloc_controller(node);
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index 684ab1d..bd32812 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -443,6 +443,7 @@ void __init smp_setup_cpu_maps(void)
}
#endif /* CONFIG_SMP */
+int __initdata do_early_xmon;
#ifdef CONFIG_XMON
static int __init early_xmon(char *p)
{
@@ -456,7 +457,7 @@ static int __init early_xmon(char *p)
return 0;
}
xmon_init(1);
- debugger(NULL);
+ do_early_xmon = 1;
return 0;
}
@@ -524,3 +525,20 @@ int check_legacy_ioport(unsigned long base_port)
return ppc_md.check_legacy_ioport(base_port);
}
EXPORT_SYMBOL(check_legacy_ioport);
+
+static int ppc_panic_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ ppc_md.panic(ptr); /* May not return */
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block ppc_panic_block = {
+ .notifier_call = ppc_panic_event,
+ .priority = INT_MIN /* may not return; must be done last */
+};
+
+void __init setup_panic(void)
+{
+ atomic_notifier_chain_register(&panic_notifier_list, &ppc_panic_block);
+}
diff --git a/arch/powerpc/kernel/setup.h b/arch/powerpc/kernel/setup.h
index 2ebba75..4c67ad7 100644
--- a/arch/powerpc/kernel/setup.h
+++ b/arch/powerpc/kernel/setup.h
@@ -2,5 +2,8 @@
#define _POWERPC_KERNEL_SETUP_H
void check_for_initrd(void);
+void do_init_bootmem(void);
+void setup_panic(void);
+extern int do_early_xmon;
#endif /* _POWERPC_KERNEL_SETUP_H */
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 69ac257..e5a4481 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -131,12 +131,6 @@ void __init machine_init(unsigned long dt_ptr, unsigned long phys)
/* Do some early initialization based on the flat device tree */
early_init_devtree(__va(dt_ptr));
- /* Check default command line */
-#ifdef CONFIG_CMDLINE
- if (cmd_line[0] == 0)
- strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line));
-#endif /* CONFIG_CMDLINE */
-
probe_machine();
#ifdef CONFIG_6xx
@@ -235,7 +229,7 @@ arch_initcall(ppc_init);
/* Warning, IO base is not yet inited */
void __init setup_arch(char **cmdline_p)
{
- extern void do_init_bootmem(void);
+ *cmdline_p = cmd_line;
/* so udelay does something sensible, assume <= 1000 bogomips */
loops_per_jiffy = 500000000 / HZ;
@@ -285,16 +279,16 @@ void __init setup_arch(char **cmdline_p)
/* reboot on panic */
panic_timeout = 180;
+ if (ppc_md.panic)
+ setup_panic();
+
init_mm.start_code = PAGE_OFFSET;
init_mm.end_code = (unsigned long) _etext;
init_mm.end_data = (unsigned long) _edata;
init_mm.brk = klimit;
- /* Save unparsed command line copy for /proc/cmdline */
- strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE);
- *cmdline_p = cmd_line;
-
- parse_early_param();
+ if (do_early_xmon)
+ debugger(NULL);
/* set up the bootmem stuff with available memory */
do_init_bootmem();
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 4467c49..78f3a5f 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -100,12 +100,6 @@ unsigned long SYSRQ_KEY;
#endif /* CONFIG_MAGIC_SYSRQ */
-static int ppc64_panic_event(struct notifier_block *, unsigned long, void *);
-static struct notifier_block ppc64_panic_block = {
- .notifier_call = ppc64_panic_event,
- .priority = INT_MIN /* may not return; must be done last */
-};
-
#ifdef CONFIG_SMP
static int smt_enabled_cmdline;
@@ -199,9 +193,7 @@ void __init early_setup(unsigned long dt_ptr)
/* Probe the machine type */
probe_machine();
-#ifdef CONFIG_CRASH_DUMP
- kdump_setup();
-#endif
+ setup_kdump_trampoline();
DBG("Found, Initializing memory management...\n");
@@ -353,9 +345,6 @@ void __init setup_system(void)
{
DBG(" -> setup_system()\n");
-#ifdef CONFIG_KEXEC
- kdump_move_device_tree();
-#endif
/*
* Unflatten the device-tree passed by prom_init or kexec
*/
@@ -420,10 +409,8 @@ void __init setup_system(void)
*/
register_early_udbg_console();
- /* Save unparsed command line copy for /proc/cmdline */
- strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE);
-
- parse_early_param();
+ if (do_early_xmon)
+ debugger(NULL);
check_smt_enabled();
smp_setup_cpu_maps();
@@ -456,13 +443,6 @@ void __init setup_system(void)
DBG(" <- setup_system()\n");
}
-static int ppc64_panic_event(struct notifier_block *this,
- unsigned long event, void *ptr)
-{
- ppc_md.panic((char *)ptr); /* May not return */
- return NOTIFY_DONE;
-}
-
#ifdef CONFIG_IRQSTACKS
static void __init irqstack_early_init(void)
{
@@ -517,8 +497,6 @@ static void __init emergency_stack_init(void)
*/
void __init setup_arch(char **cmdline_p)
{
- extern void do_init_bootmem(void);
-
ppc64_boot_msg(0x12, "Setup Arch");
*cmdline_p = cmd_line;
@@ -535,8 +513,7 @@ void __init setup_arch(char **cmdline_p)
panic_timeout = 180;
if (ppc_md.panic)
- atomic_notifier_chain_register(&panic_notifier_list,
- &ppc64_panic_block);
+ setup_panic();
init_mm.start_code = PAGE_OFFSET;
init_mm.end_code = (unsigned long) _etext;
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 8fdeca2..d73b25e 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -419,9 +419,7 @@ static long restore_user_regs(struct pt_regs *regs,
{
long err;
unsigned int save_r2 = 0;
-#if defined(CONFIG_ALTIVEC) || defined(CONFIG_SPE)
unsigned long msr;
-#endif
/*
* restore general registers but not including MSR or SOFTE. Also
@@ -430,11 +428,16 @@ static long restore_user_regs(struct pt_regs *regs,
if (!sig)
save_r2 = (unsigned int)regs->gpr[2];
err = restore_general_regs(regs, sr);
+ err |= __get_user(msr, &sr->mc_gregs[PT_MSR]);
if (!sig)
regs->gpr[2] = (unsigned long) save_r2;
if (err)
return 1;
+ /* if doing signal return, restore the previous little-endian mode */
+ if (sig)
+ regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE);
+
/*
* Do this before updating the thread state in
* current->thread.fpr/vr/evr. That way, if we get preempted
@@ -455,7 +458,7 @@ static long restore_user_regs(struct pt_regs *regs,
/* force the process to reload the altivec registers from
current->thread when it next does altivec instructions */
regs->msr &= ~MSR_VEC;
- if (!__get_user(msr, &sr->mc_gregs[PT_MSR]) && (msr & MSR_VEC) != 0) {
+ if (msr & MSR_VEC) {
/* restore altivec registers from the stack */
if (__copy_from_user(current->thread.vr, &sr->mc_vregs,
sizeof(sr->mc_vregs)))
@@ -472,7 +475,7 @@ static long restore_user_regs(struct pt_regs *regs,
/* force the process to reload the spe registers from
current->thread when it next does spe instructions */
regs->msr &= ~MSR_SPE;
- if (!__get_user(msr, &sr->mc_gregs[PT_MSR]) && (msr & MSR_SPE) != 0) {
+ if (msr & MSR_SPE) {
/* restore spe registers from the stack */
if (__copy_from_user(current->thread.evr, &sr->mc_vregs,
ELF_NEVRREG * sizeof(u32)))
@@ -757,10 +760,10 @@ static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka,
/* Save user registers on the stack */
frame = &rt_sf->uc.uc_mcontext;
- if (vdso32_rt_sigtramp && current->thread.vdso_base) {
+ if (vdso32_rt_sigtramp && current->mm->context.vdso_base) {
if (save_user_regs(regs, frame, 0))
goto badframe;
- regs->link = current->thread.vdso_base + vdso32_rt_sigtramp;
+ regs->link = current->mm->context.vdso_base + vdso32_rt_sigtramp;
} else {
if (save_user_regs(regs, frame, __NR_rt_sigreturn))
goto badframe;
@@ -777,6 +780,8 @@ static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka,
regs->gpr[5] = (unsigned long) &rt_sf->uc;
regs->gpr[6] = (unsigned long) rt_sf;
regs->nip = (unsigned long) ka->sa.sa_handler;
+ /* enter the signal handler in big-endian mode */
+ regs->msr &= ~MSR_LE;
regs->trap = 0;
return 1;
@@ -1038,10 +1043,10 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka,
|| __put_user(sig, &sc->signal))
goto badframe;
- if (vdso32_sigtramp && current->thread.vdso_base) {
+ if (vdso32_sigtramp && current->mm->context.vdso_base) {
if (save_user_regs(regs, &frame->mctx, 0))
goto badframe;
- regs->link = current->thread.vdso_base + vdso32_sigtramp;
+ regs->link = current->mm->context.vdso_base + vdso32_sigtramp;
} else {
if (save_user_regs(regs, &frame->mctx, __NR_sigreturn))
goto badframe;
@@ -1056,6 +1061,8 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka,
regs->gpr[3] = sig;
regs->gpr[4] = (unsigned long) sc;
regs->nip = (unsigned long) ka->sa.sa_handler;
+ /* enter the signal handler in big-endian mode */
+ regs->msr &= ~MSR_LE;
regs->trap = 0;
return 1;
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index c2db642..6e75d7a 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -141,9 +141,7 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
unsigned long err = 0;
unsigned long save_r13 = 0;
elf_greg_t *gregs = (elf_greg_t *)regs;
-#ifdef CONFIG_ALTIVEC
unsigned long msr;
-#endif
int i;
/* If this is not a signal return, we preserve the TLS in r13 */
@@ -154,7 +152,12 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
err |= __copy_from_user(regs, &sc->gp_regs,
PT_MSR*sizeof(unsigned long));
- /* skip MSR and SOFTE */
+ /* get MSR separately, transfer the LE bit if doing signal return */
+ err |= __get_user(msr, &sc->gp_regs[PT_MSR]);
+ if (sig)
+ regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE);
+
+ /* skip SOFTE */
for (i = PT_MSR+1; i <= PT_RESULT; i++) {
if (i == PT_SOFTE)
continue;
@@ -179,7 +182,6 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
#ifdef CONFIG_ALTIVEC
err |= __get_user(v_regs, &sc->v_regs);
- err |= __get_user(msr, &sc->gp_regs[PT_MSR]);
if (err)
return err;
if (v_regs && !access_ok(VERIFY_READ, v_regs, 34 * sizeof(vector128)))
@@ -396,8 +398,8 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
current->thread.fpscr.val = 0;
/* Set up to return from userspace. */
- if (vdso64_rt_sigtramp && current->thread.vdso_base) {
- regs->link = current->thread.vdso_base + vdso64_rt_sigtramp;
+ if (vdso64_rt_sigtramp && current->mm->context.vdso_base) {
+ regs->link = current->mm->context.vdso_base + vdso64_rt_sigtramp;
} else {
err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]);
if (err)
@@ -412,6 +414,8 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
/* Set up "regs" so we "return" to the signal handler. */
err |= get_user(regs->nip, &funct_desc_ptr->entry);
+ /* enter the signal handler in big-endian mode */
+ regs->msr &= ~MSR_LE;
regs->gpr[1] = newsp;
err |= get_user(regs->gpr[2], &funct_desc_ptr->toc);
regs->gpr[3] = signr;
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 530f7db..c5d179d 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -492,7 +492,7 @@ int __devinit __cpu_up(unsigned int cpu)
* -- Cort
*/
if (system_state < SYSTEM_RUNNING)
- for (c = 5000; c && !cpu_callin_map[cpu]; c--)
+ for (c = 50000; c && !cpu_callin_map[cpu]; c--)
udelay(100);
#ifdef CONFIG_HOTPLUG_CPU
else
diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S
index 26ed1f5..ee75ccf 100644
--- a/arch/powerpc/kernel/systbl.S
+++ b/arch/powerpc/kernel/systbl.S
@@ -32,6 +32,10 @@
#define SYS32ONLY(func) .long sys_##func
#define SYSX(f, f3264, f32) .long f32
#endif
+#define SYSCALL_SPU(func) SYSCALL(func)
+#define COMPAT_SYS_SPU(func) COMPAT_SYS(func)
+#define PPC_SYS_SPU(func) PPC_SYS(func)
+#define SYSX_SPU(f, f3264, f32) SYSX(f, f3264, f32)
#ifdef CONFIG_PPC64
#define sys_sigpending sys_ni_syscall
@@ -39,309 +43,4 @@
#endif
_GLOBAL(sys_call_table)
-SYSCALL(restart_syscall)
-SYSCALL(exit)
-PPC_SYS(fork)
-SYSCALL(read)
-SYSCALL(write)
-COMPAT_SYS(open)
-SYSCALL(close)
-COMPAT_SYS(waitpid)
-COMPAT_SYS(creat)
-SYSCALL(link)
-SYSCALL(unlink)
-COMPAT_SYS(execve)
-SYSCALL(chdir)
-COMPAT_SYS(time)
-SYSCALL(mknod)
-SYSCALL(chmod)
-SYSCALL(lchown)
-SYSCALL(ni_syscall)
-OLDSYS(stat)
-SYSX(sys_lseek,ppc32_lseek,sys_lseek)
-SYSCALL(getpid)
-COMPAT_SYS(mount)
-SYSX(sys_ni_syscall,sys_oldumount,sys_oldumount)
-SYSCALL(setuid)
-SYSCALL(getuid)
-COMPAT_SYS(stime)
-COMPAT_SYS(ptrace)
-SYSCALL(alarm)
-OLDSYS(fstat)
-COMPAT_SYS(pause)
-COMPAT_SYS(utime)
-SYSCALL(ni_syscall)
-SYSCALL(ni_syscall)
-COMPAT_SYS(access)
-COMPAT_SYS(nice)
-SYSCALL(ni_syscall)
-SYSCALL(sync)
-COMPAT_SYS(kill)
-SYSCALL(rename)
-COMPAT_SYS(mkdir)
-SYSCALL(rmdir)
-SYSCALL(dup)
-SYSCALL(pipe)
-COMPAT_SYS(times)
-SYSCALL(ni_syscall)
-SYSCALL(brk)
-SYSCALL(setgid)
-SYSCALL(getgid)
-SYSCALL(signal)
-SYSCALL(geteuid)
-SYSCALL(getegid)
-SYSCALL(acct)
-SYSCALL(umount)
-SYSCALL(ni_syscall)
-COMPAT_SYS(ioctl)
-COMPAT_SYS(fcntl)
-SYSCALL(ni_syscall)
-COMPAT_SYS(setpgid)
-SYSCALL(ni_syscall)
-SYSX(sys_ni_syscall,sys_olduname, sys_olduname)
-COMPAT_SYS(umask)
-SYSCALL(chroot)
-SYSCALL(ustat)
-SYSCALL(dup2)
-SYSCALL(getppid)
-SYSCALL(getpgrp)
-SYSCALL(setsid)
-SYS32ONLY(sigaction)
-SYSCALL(sgetmask)
-COMPAT_SYS(ssetmask)
-SYSCALL(setreuid)
-SYSCALL(setregid)
-SYS32ONLY(sigsuspend)
-COMPAT_SYS(sigpending)
-COMPAT_SYS(sethostname)
-COMPAT_SYS(setrlimit)
-COMPAT_SYS(old_getrlimit)
-COMPAT_SYS(getrusage)
-COMPAT_SYS(gettimeofday)
-COMPAT_SYS(settimeofday)
-COMPAT_SYS(getgroups)
-COMPAT_SYS(setgroups)
-SYSX(sys_ni_syscall,sys_ni_syscall,ppc_select)
-SYSCALL(symlink)
-OLDSYS(lstat)
-COMPAT_SYS(readlink)
-SYSCALL(uselib)
-SYSCALL(swapon)
-SYSCALL(reboot)
-SYSX(sys_ni_syscall,old32_readdir,old_readdir)
-SYSCALL(mmap)
-SYSCALL(munmap)
-SYSCALL(truncate)
-SYSCALL(ftruncate)
-SYSCALL(fchmod)
-SYSCALL(fchown)
-COMPAT_SYS(getpriority)
-COMPAT_SYS(setpriority)
-SYSCALL(ni_syscall)
-COMPAT_SYS(statfs)
-COMPAT_SYS(fstatfs)
-SYSCALL(ni_syscall)
-COMPAT_SYS(socketcall)
-COMPAT_SYS(syslog)
-COMPAT_SYS(setitimer)
-COMPAT_SYS(getitimer)
-COMPAT_SYS(newstat)
-COMPAT_SYS(newlstat)
-COMPAT_SYS(newfstat)
-SYSX(sys_ni_syscall,sys_uname,sys_uname)
-SYSCALL(ni_syscall)
-SYSCALL(vhangup)
-SYSCALL(ni_syscall)
-SYSCALL(ni_syscall)
-COMPAT_SYS(wait4)
-SYSCALL(swapoff)
-COMPAT_SYS(sysinfo)
-COMPAT_SYS(ipc)
-SYSCALL(fsync)
-SYS32ONLY(sigreturn)
-PPC_SYS(clone)
-COMPAT_SYS(setdomainname)
-PPC_SYS(newuname)
-SYSCALL(ni_syscall)
-COMPAT_SYS(adjtimex)
-SYSCALL(mprotect)
-SYSX(sys_ni_syscall,compat_sys_sigprocmask,sys_sigprocmask)
-SYSCALL(ni_syscall)
-SYSCALL(init_module)
-SYSCALL(delete_module)
-SYSCALL(ni_syscall)
-SYSCALL(quotactl)
-COMPAT_SYS(getpgid)
-SYSCALL(fchdir)
-SYSCALL(bdflush)
-COMPAT_SYS(sysfs)
-SYSX(ppc64_personality,ppc64_personality,sys_personality)
-SYSCALL(ni_syscall)
-SYSCALL(setfsuid)
-SYSCALL(setfsgid)
-SYSCALL(llseek)
-COMPAT_SYS(getdents)
-SYSX(sys_select,ppc32_select,ppc_select)
-SYSCALL(flock)
-SYSCALL(msync)
-COMPAT_SYS(readv)
-COMPAT_SYS(writev)
-COMPAT_SYS(getsid)
-SYSCALL(fdatasync)
-COMPAT_SYS(sysctl)
-SYSCALL(mlock)
-SYSCALL(munlock)
-SYSCALL(mlockall)
-SYSCALL(munlockall)
-COMPAT_SYS(sched_setparam)
-COMPAT_SYS(sched_getparam)
-COMPAT_SYS(sched_setscheduler)
-COMPAT_SYS(sched_getscheduler)
-SYSCALL(sched_yield)
-COMPAT_SYS(sched_get_priority_max)
-COMPAT_SYS(sched_get_priority_min)
-COMPAT_SYS(sched_rr_get_interval)
-COMPAT_SYS(nanosleep)
-SYSCALL(mremap)
-SYSCALL(setresuid)
-SYSCALL(getresuid)
-SYSCALL(ni_syscall)
-SYSCALL(poll)
-COMPAT_SYS(nfsservctl)
-SYSCALL(setresgid)
-SYSCALL(getresgid)
-COMPAT_SYS(prctl)
-COMPAT_SYS(rt_sigreturn)
-COMPAT_SYS(rt_sigaction)
-COMPAT_SYS(rt_sigprocmask)
-COMPAT_SYS(rt_sigpending)
-COMPAT_SYS(rt_sigtimedwait)
-COMPAT_SYS(rt_sigqueueinfo)
-COMPAT_SYS(rt_sigsuspend)
-COMPAT_SYS(pread64)
-COMPAT_SYS(pwrite64)
-SYSCALL(chown)
-SYSCALL(getcwd)
-SYSCALL(capget)
-SYSCALL(capset)
-COMPAT_SYS(sigaltstack)
-SYSX(sys_sendfile64,compat_sys_sendfile,sys_sendfile)
-SYSCALL(ni_syscall)
-SYSCALL(ni_syscall)
-PPC_SYS(vfork)
-COMPAT_SYS(getrlimit)
-COMPAT_SYS(readahead)
-SYS32ONLY(mmap2)
-SYS32ONLY(truncate64)
-SYS32ONLY(ftruncate64)
-SYSX(sys_ni_syscall,sys_stat64,sys_stat64)
-SYSX(sys_ni_syscall,sys_lstat64,sys_lstat64)
-SYSX(sys_ni_syscall,sys_fstat64,sys_fstat64)
-SYSCALL(pciconfig_read)
-SYSCALL(pciconfig_write)
-SYSCALL(pciconfig_iobase)
-SYSCALL(ni_syscall)
-SYSCALL(getdents64)
-SYSCALL(pivot_root)
-SYSX(sys_ni_syscall,compat_sys_fcntl64,sys_fcntl64)
-SYSCALL(madvise)
-SYSCALL(mincore)
-SYSCALL(gettid)
-SYSCALL(tkill)
-SYSCALL(setxattr)
-SYSCALL(lsetxattr)
-SYSCALL(fsetxattr)
-SYSCALL(getxattr)
-SYSCALL(lgetxattr)
-SYSCALL(fgetxattr)
-SYSCALL(listxattr)
-SYSCALL(llistxattr)
-SYSCALL(flistxattr)
-SYSCALL(removexattr)
-SYSCALL(lremovexattr)
-SYSCALL(fremovexattr)
-COMPAT_SYS(futex)
-COMPAT_SYS(sched_setaffinity)
-COMPAT_SYS(sched_getaffinity)
-SYSCALL(ni_syscall)
-SYSCALL(ni_syscall)
-SYS32ONLY(sendfile64)
-COMPAT_SYS(io_setup)
-SYSCALL(io_destroy)
-COMPAT_SYS(io_getevents)
-COMPAT_SYS(io_submit)
-SYSCALL(io_cancel)
-SYSCALL(set_tid_address)
-SYSX(sys_fadvise64,ppc32_fadvise64,sys_fadvise64)
-SYSCALL(exit_group)
-SYSX(sys_lookup_dcookie,ppc32_lookup_dcookie,sys_lookup_dcookie)
-SYSCALL(epoll_create)
-SYSCALL(epoll_ctl)
-SYSCALL(epoll_wait)
-SYSCALL(remap_file_pages)
-SYSX(sys_timer_create,compat_sys_timer_create,sys_timer_create)
-COMPAT_SYS(timer_settime)
-COMPAT_SYS(timer_gettime)
-SYSCALL(timer_getoverrun)
-SYSCALL(timer_delete)
-COMPAT_SYS(clock_settime)
-COMPAT_SYS(clock_gettime)
-COMPAT_SYS(clock_getres)
-COMPAT_SYS(clock_nanosleep)
-SYSX(ppc64_swapcontext,ppc32_swapcontext,ppc_swapcontext)
-COMPAT_SYS(tgkill)
-COMPAT_SYS(utimes)
-COMPAT_SYS(statfs64)
-COMPAT_SYS(fstatfs64)
-SYSX(sys_ni_syscall, ppc_fadvise64_64, ppc_fadvise64_64)
-PPC_SYS(rtas)
-OLDSYS(debug_setcontext)
-SYSCALL(ni_syscall)
-SYSCALL(ni_syscall)
-COMPAT_SYS(mbind)
-COMPAT_SYS(get_mempolicy)
-COMPAT_SYS(set_mempolicy)
-COMPAT_SYS(mq_open)
-SYSCALL(mq_unlink)
-COMPAT_SYS(mq_timedsend)
-COMPAT_SYS(mq_timedreceive)
-COMPAT_SYS(mq_notify)
-COMPAT_SYS(mq_getsetattr)
-COMPAT_SYS(kexec_load)
-COMPAT_SYS(add_key)
-COMPAT_SYS(request_key)
-COMPAT_SYS(keyctl)
-COMPAT_SYS(waitid)
-COMPAT_SYS(ioprio_set)
-COMPAT_SYS(ioprio_get)
-SYSCALL(inotify_init)
-SYSCALL(inotify_add_watch)
-SYSCALL(inotify_rm_watch)
-SYSCALL(spu_run)
-SYSCALL(spu_create)
-COMPAT_SYS(pselect6)
-COMPAT_SYS(ppoll)
-SYSCALL(unshare)
-SYSCALL(splice)
-SYSCALL(tee)
-SYSCALL(vmsplice)
-COMPAT_SYS(openat)
-SYSCALL(mkdirat)
-SYSCALL(mknodat)
-SYSCALL(fchownat)
-COMPAT_SYS(futimesat)
-SYSX(sys_newfstatat, sys_fstatat64, sys_fstatat64)
-SYSCALL(unlinkat)
-SYSCALL(renameat)
-SYSCALL(linkat)
-SYSCALL(symlinkat)
-SYSCALL(readlinkat)
-SYSCALL(fchmodat)
-SYSCALL(faccessat)
-COMPAT_SYS(get_robust_list)
-COMPAT_SYS(set_robust_list)
-
-/*
- * please add new calls to arch/powerpc/platforms/cell/spu_callbacks.c
- * as well when appropriate.
- */
+#include <asm/systbl.h>
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 24e3ad7..d209075 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -76,7 +76,6 @@
/* keep track of when we need to update the rtc */
time_t last_rtc_update;
-extern int piranha_simulator;
#ifdef CONFIG_PPC_ISERIES
unsigned long iSeries_recal_titan = 0;
unsigned long iSeries_recal_tb = 0;
@@ -858,42 +857,50 @@ int do_settimeofday(struct timespec *tv)
EXPORT_SYMBOL(do_settimeofday);
-void __init generic_calibrate_decr(void)
+static int __init get_freq(char *name, int cells, unsigned long *val)
{
struct device_node *cpu;
unsigned int *fp;
- int node_found;
+ int found = 0;
- /*
- * The cpu node should have a timebase-frequency property
- * to tell us the rate at which the decrementer counts.
- */
+ /* The cpu node should have timebase and clock frequency properties */
cpu = of_find_node_by_type(NULL, "cpu");
- ppc_tb_freq = DEFAULT_TB_FREQ; /* hardcoded default */
- node_found = 0;
if (cpu) {
- fp = (unsigned int *)get_property(cpu, "timebase-frequency",
- NULL);
+ fp = (unsigned int *)get_property(cpu, name, NULL);
if (fp) {
- node_found = 1;
- ppc_tb_freq = *fp;
+ found = 1;
+ *val = 0;
+ while (cells--)
+ *val = (*val << 32) | *fp++;
}
+
+ of_node_put(cpu);
}
- if (!node_found)
+
+ return found;
+}
+
+void __init generic_calibrate_decr(void)
+{
+ ppc_tb_freq = DEFAULT_TB_FREQ; /* hardcoded default */
+
+ if (!get_freq("ibm,extended-timebase-frequency", 2, &ppc_tb_freq) &&
+ !get_freq("timebase-frequency", 1, &ppc_tb_freq)) {
+
printk(KERN_ERR "WARNING: Estimating decrementer frequency "
"(not found)\n");
+ }
- ppc_proc_freq = DEFAULT_PROC_FREQ;
- node_found = 0;
- if (cpu) {
- fp = (unsigned int *)get_property(cpu, "clock-frequency",
- NULL);
- if (fp) {
- node_found = 1;
- ppc_proc_freq = *fp;
- }
+ ppc_proc_freq = DEFAULT_PROC_FREQ; /* hardcoded default */
+
+ if (!get_freq("ibm,extended-clock-frequency", 2, &ppc_proc_freq) &&
+ !get_freq("clock-frequency", 1, &ppc_proc_freq)) {
+
+ printk(KERN_ERR "WARNING: Estimating processor frequency "
+ "(not found)\n");
}
+
#ifdef CONFIG_BOOKE
/* Set the time base to zero */
mtspr(SPRN_TBWL, 0);
@@ -905,11 +912,6 @@ void __init generic_calibrate_decr(void)
/* Enable decrementer interrupt */
mtspr(SPRN_TCR, TCR_DIE);
#endif
- if (!node_found)
- printk(KERN_ERR "WARNING: Estimating processor frequency "
- "(not found)\n");
-
- of_node_put(cpu);
}
unsigned long get_boot_time(void)
@@ -945,9 +947,9 @@ void __init time_init(void)
} else {
/* Normal PowerPC with timebase register */
ppc_md.calibrate_decr();
- printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n",
+ printk(KERN_DEBUG "time_init: decrementer frequency = %lu.%.6lu MHz\n",
ppc_tb_freq / 1000000, ppc_tb_freq % 1000000);
- printk(KERN_INFO "time_init: processor frequency = %lu.%.6lu MHz\n",
+ printk(KERN_DEBUG "time_init: processor frequency = %lu.%.6lu MHz\n",
ppc_proc_freq / 1000000, ppc_proc_freq % 1000000);
tb_last_stamp = tb_last_jiffy = get_tb();
}
@@ -1010,10 +1012,7 @@ void __init time_init(void)
tb_to_ns_scale = scale;
tb_to_ns_shift = shift;
-#ifdef CONFIG_PPC_ISERIES
- if (!piranha_simulator)
-#endif
- tm = get_boot_time();
+ tm = get_boot_time();
write_seqlock_irqsave(&xtime_lock, flags);
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 064a525..52f5659 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -32,6 +32,7 @@
#include <linux/delay.h>
#include <linux/kprobes.h>
#include <linux/kexec.h>
+#include <linux/backlight.h>
#include <asm/kdebug.h>
#include <asm/pgtable.h>
@@ -105,10 +106,18 @@ int die(const char *str, struct pt_regs *regs, long err)
spin_lock_irq(&die_lock);
bust_spinlocks(1);
#ifdef CONFIG_PMAC_BACKLIGHT
- if (machine_is(powermac)) {
- set_backlight_enable(1);
- set_backlight_level(BACKLIGHT_MAX);
+ mutex_lock(&pmac_backlight_mutex);
+ if (machine_is(powermac) && pmac_backlight) {
+ struct backlight_properties *props;
+
+ down(&pmac_backlight->sem);
+ props = pmac_backlight->props;
+ props->brightness = props->max_brightness;
+ props->power = FB_BLANK_UNBLANK;
+ props->update_status(pmac_backlight);
+ up(&pmac_backlight->sem);
}
+ mutex_unlock(&pmac_backlight_mutex);
#endif
printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
#ifdef CONFIG_PREEMPT
@@ -658,7 +667,7 @@ static int emulate_instruction(struct pt_regs *regs)
u32 instword;
u32 rd;
- if (!user_mode(regs))
+ if (!user_mode(regs) || (regs->msr & MSR_LE))
return -EINVAL;
CHECK_FULL_REGS(regs);
@@ -805,9 +814,11 @@ void __kprobes program_check_exception(struct pt_regs *regs)
void alignment_exception(struct pt_regs *regs)
{
- int fixed;
+ int fixed = 0;
- fixed = fix_alignment(regs);
+ /* we don't implement logging of alignment exceptions */
+ if (!(current->thread.align_ctl & PR_UNALIGN_SIGBUS))
+ fixed = fix_alignment(regs);
if (fixed == 1) {
regs->nip += 4; /* skip over emulated instruction */
diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c
index 3774e80..67d9fd9 100644
--- a/arch/powerpc/kernel/udbg.c
+++ b/arch/powerpc/kernel/udbg.c
@@ -14,6 +14,7 @@
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/console.h>
+#include <linux/init.h>
#include <asm/processor.h>
#include <asm/udbg.h>
@@ -141,12 +142,14 @@ static int early_console_initialized;
void __init disable_early_printk(void)
{
-#if 1
if (!early_console_initialized)
return;
+ if (strstr(saved_command_line, "udbg-immortal")) {
+ printk(KERN_INFO "early console immortal !\n");
+ return;
+ }
unregister_console(&udbg_console);
early_console_initialized = 0;
-#endif
}
/* called by setup_system */
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index 573afb6..bc3e15b 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -223,6 +223,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
struct vm_area_struct *vma;
unsigned long vdso_pages;
unsigned long vdso_base;
+ int rc;
#ifdef CONFIG_PPC64
if (test_thread_flag(TIF_32BIT)) {
@@ -237,20 +238,13 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
vdso_base = VDSO32_MBASE;
#endif
- current->thread.vdso_base = 0;
+ current->mm->context.vdso_base = 0;
/* vDSO has a problem and was disabled, just don't "enable" it for the
* process
*/
if (vdso_pages == 0)
return 0;
-
- vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
- if (vma == NULL)
- return -ENOMEM;
-
- memset(vma, 0, sizeof(*vma));
-
/* Add a page to the vdso size for the data page */
vdso_pages ++;
@@ -259,17 +253,23 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
* at vdso_base which is the "natural" base for it, but we might fail
* and end up putting it elsewhere.
*/
+ down_write(&mm->mmap_sem);
vdso_base = get_unmapped_area(NULL, vdso_base,
vdso_pages << PAGE_SHIFT, 0, 0);
- if (vdso_base & ~PAGE_MASK) {
- kmem_cache_free(vm_area_cachep, vma);
- return (int)vdso_base;
+ if (IS_ERR_VALUE(vdso_base)) {
+ rc = vdso_base;
+ goto fail_mmapsem;
}
- current->thread.vdso_base = vdso_base;
+ /* Allocate a VMA structure and fill it up */
+ vma = kmem_cache_zalloc(vm_area_cachep, SLAB_KERNEL);
+ if (vma == NULL) {
+ rc = -ENOMEM;
+ goto fail_mmapsem;
+ }
vma->vm_mm = mm;
- vma->vm_start = current->thread.vdso_base;
+ vma->vm_start = vdso_base;
vma->vm_end = vma->vm_start + (vdso_pages << PAGE_SHIFT);
/*
@@ -282,23 +282,38 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
* It's fine to use that for setting breakpoints in the vDSO code
* pages though
*/
- vma->vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
+ vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC;
vma->vm_flags |= mm->def_flags;
vma->vm_page_prot = protection_map[vma->vm_flags & 0x7];
vma->vm_ops = &vdso_vmops;
- down_write(&mm->mmap_sem);
- if (insert_vm_struct(mm, vma)) {
- up_write(&mm->mmap_sem);
- kmem_cache_free(vm_area_cachep, vma);
- return -ENOMEM;
- }
+ /* Insert new VMA */
+ rc = insert_vm_struct(mm, vma);
+ if (rc)
+ goto fail_vma;
+
+ /* Put vDSO base into mm struct and account for memory usage */
+ current->mm->context.vdso_base = vdso_base;
mm->total_vm += (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
up_write(&mm->mmap_sem);
-
return 0;
+
+ fail_vma:
+ kmem_cache_free(vm_area_cachep, vma);
+ fail_mmapsem:
+ up_write(&mm->mmap_sem);
+ return rc;
+}
+
+const char *arch_vma_name(struct vm_area_struct *vma)
+{
+ if (vma->vm_mm && vma->vm_start == vma->vm_mm->context.vdso_base)
+ return "[vdso]";
+ return NULL;
}
+
+
static void * __init find_section32(Elf32_Ehdr *ehdr, const char *secname,
unsigned long *size)
{
diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S
index 66b3d03..9416b4a 100644
--- a/arch/powerpc/kernel/vector.S
+++ b/arch/powerpc/kernel/vector.S
@@ -53,12 +53,12 @@ fpenable:
stfd fr31,8(r1)
LDCONST(fr1, fpzero)
mffs fr31
- mtfsf 0xff,fr1
+ MTFSF_L(fr1)
blr
fpdisable:
mtlr r12
- mtfsf 0xff,fr31
+ MTFSF_L(fr31)
lfd fr31,8(r1)
lfd fr1,16(r1)
lfd fr0,24(r1)
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index 971020c..cdf5867 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -13,27 +13,116 @@
* 2 of the License, or (at your option) any later version.
*/
+#include <linux/types.h>
+#include <linux/device.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
+#include <linux/kobject.h>
+
#include <asm/iommu.h>
#include <asm/dma.h>
#include <asm/vio.h>
#include <asm/prom.h>
-
-static const struct vio_device_id *vio_match_device(
- const struct vio_device_id *, const struct vio_dev *);
-
-struct vio_dev vio_bus_device = { /* fake "parent" device */
+#include <asm/firmware.h>
+#include <asm/tce.h>
+#include <asm/abs_addr.h>
+#include <asm/page.h>
+#include <asm/hvcall.h>
+#include <asm/iseries/vio.h>
+#include <asm/iseries/hv_types.h>
+#include <asm/iseries/hv_lp_config.h>
+#include <asm/iseries/hv_call_xm.h>
+#include <asm/iseries/iommu.h>
+
+extern struct subsystem devices_subsys; /* needed for vio_find_name() */
+
+static struct vio_dev vio_bus_device = { /* fake "parent" device */
.name = vio_bus_device.dev.bus_id,
.type = "",
.dev.bus_id = "vio",
.dev.bus = &vio_bus_type,
};
-static struct vio_bus_ops vio_bus_ops;
+#ifdef CONFIG_PPC_ISERIES
+struct device *iSeries_vio_dev = &vio_bus_device.dev;
+EXPORT_SYMBOL(iSeries_vio_dev);
+
+static struct iommu_table veth_iommu_table;
+static struct iommu_table vio_iommu_table;
+
+static void __init iommu_vio_init(void)
+{
+ iommu_table_getparms_iSeries(255, 0, 0xff, &veth_iommu_table);
+ veth_iommu_table.it_size /= 2;
+ vio_iommu_table = veth_iommu_table;
+ vio_iommu_table.it_offset += veth_iommu_table.it_size;
+
+ if (!iommu_init_table(&veth_iommu_table, -1))
+ printk("Virtual Bus VETH TCE table failed.\n");
+ if (!iommu_init_table(&vio_iommu_table, -1))
+ printk("Virtual Bus VIO TCE table failed.\n");
+}
+#endif
+
+static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
+{
+#ifdef CONFIG_PPC_ISERIES
+ if (firmware_has_feature(FW_FEATURE_ISERIES)) {
+ if (strcmp(dev->type, "network") == 0)
+ return &veth_iommu_table;
+ return &vio_iommu_table;
+ } else
+#endif
+ {
+ unsigned char *dma_window;
+ struct iommu_table *tbl;
+ unsigned long offset, size;
+
+ dma_window = get_property(dev->dev.platform_data,
+ "ibm,my-dma-window", NULL);
+ if (!dma_window)
+ return NULL;
+
+ tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
+
+ of_parse_dma_window(dev->dev.platform_data, dma_window,
+ &tbl->it_index, &offset, &size);
+
+ /* TCE table size - measured in tce entries */
+ tbl->it_size = size >> PAGE_SHIFT;
+ /* offset for VIO should always be 0 */
+ tbl->it_offset = offset >> PAGE_SHIFT;
+ tbl->it_busno = 0;
+ tbl->it_type = TCE_VB;
+
+ return iommu_init_table(tbl, -1);
+ }
+}
+
+/**
+ * vio_match_device: - Tell if a VIO device has a matching
+ * VIO device id structure.
+ * @ids: array of VIO device id structures to search in
+ * @dev: the VIO device structure to match against
+ *
+ * Used by a driver to check whether a VIO device present in the
+ * system is in its list of supported devices. Returns the matching
+ * vio_device_id structure or NULL if there is no match.
+ */
+static const struct vio_device_id *vio_match_device(
+ const struct vio_device_id *ids, const struct vio_dev *dev)
+{
+ while (ids->type[0] != '\0') {
+ if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) &&
+ device_is_compatible(dev->dev.platform_data, ids->compat))
+ return ids;
+ ids++;
+ }
+ return NULL;
+}
/*
* Convert from struct device to struct vio_dev and pass to driver.
@@ -106,35 +195,110 @@ void vio_unregister_driver(struct vio_driver *viodrv)
}
EXPORT_SYMBOL(vio_unregister_driver);
+/* vio_dev refcount hit 0 */
+static void __devinit vio_dev_release(struct device *dev)
+{
+ if (dev->platform_data) {
+ /* XXX free TCE table */
+ of_node_put(dev->platform_data);
+ }
+ kfree(to_vio_dev(dev));
+}
+
/**
- * vio_match_device: - Tell if a VIO device has a matching
- * VIO device id structure.
- * @ids: array of VIO device id structures to search in
- * @dev: the VIO device structure to match against
+ * vio_register_device_node: - Register a new vio device.
+ * @of_node: The OF node for this device.
*
- * Used by a driver to check whether a VIO device present in the
- * system is in its list of supported devices. Returns the matching
- * vio_device_id structure or NULL if there is no match.
+ * Creates and initializes a vio_dev structure from the data in
+ * of_node (dev.platform_data) and adds it to the list of virtual devices.
+ * Returns a pointer to the created vio_dev or NULL if node has
+ * NULL device_type or compatible fields.
*/
-static const struct vio_device_id *vio_match_device(
- const struct vio_device_id *ids, const struct vio_dev *dev)
+struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
{
- while (ids->type[0] != '\0') {
- if (vio_bus_ops.match(ids, dev))
- return ids;
- ids++;
+ struct vio_dev *viodev;
+ unsigned int *unit_address;
+ unsigned int *irq_p;
+
+ /* we need the 'device_type' property, in order to match with drivers */
+ if (of_node->type == NULL) {
+ printk(KERN_WARNING "%s: node %s missing 'device_type'\n",
+ __FUNCTION__,
+ of_node->name ? of_node->name : "<unknown>");
+ return NULL;
}
- return NULL;
+
+ unit_address = (unsigned int *)get_property(of_node, "reg", NULL);
+ if (unit_address == NULL) {
+ printk(KERN_WARNING "%s: node %s missing 'reg'\n",
+ __FUNCTION__,
+ of_node->name ? of_node->name : "<unknown>");
+ return NULL;
+ }
+
+ /* allocate a vio_dev for this node */
+ viodev = kzalloc(sizeof(struct vio_dev), GFP_KERNEL);
+ if (viodev == NULL)
+ return NULL;
+
+ viodev->dev.platform_data = of_node_get(of_node);
+
+ viodev->irq = NO_IRQ;
+ irq_p = (unsigned int *)get_property(of_node, "interrupts", NULL);
+ if (irq_p) {
+ int virq = virt_irq_create_mapping(*irq_p);
+ if (virq == NO_IRQ) {
+ printk(KERN_ERR "Unable to allocate interrupt "
+ "number for %s\n", of_node->full_name);
+ } else
+ viodev->irq = irq_offset_up(virq);
+ }
+
+ snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address);
+ viodev->name = of_node->name;
+ viodev->type = of_node->type;
+ viodev->unit_address = *unit_address;
+ if (firmware_has_feature(FW_FEATURE_ISERIES)) {
+ unit_address = (unsigned int *)get_property(of_node,
+ "linux,unit_address", NULL);
+ if (unit_address != NULL)
+ viodev->unit_address = *unit_address;
+ }
+ viodev->iommu_table = vio_build_iommu_table(viodev);
+
+ /* init generic 'struct device' fields: */
+ viodev->dev.parent = &vio_bus_device.dev;
+ viodev->dev.bus = &vio_bus_type;
+ viodev->dev.release = vio_dev_release;
+
+ /* register with generic device framework */
+ if (device_register(&viodev->dev)) {
+ printk(KERN_ERR "%s: failed to register device %s\n",
+ __FUNCTION__, viodev->dev.bus_id);
+ /* XXX free TCE table */
+ kfree(viodev);
+ return NULL;
+ }
+
+ return viodev;
}
+EXPORT_SYMBOL(vio_register_device_node);
/**
* vio_bus_init: - Initialize the virtual IO bus
*/
-int __init vio_bus_init(struct vio_bus_ops *ops)
+static int __init vio_bus_init(void)
{
int err;
+ struct device_node *node_vroot;
- vio_bus_ops = *ops;
+#ifdef CONFIG_PPC_ISERIES
+ if (firmware_has_feature(FW_FEATURE_ISERIES)) {
+ iommu_vio_init();
+ vio_bus_device.iommu_table = &vio_iommu_table;
+ iSeries_vio_dev = &vio_bus_device.dev;
+ }
+#endif
err = bus_register(&vio_bus_type);
if (err) {
@@ -153,47 +317,48 @@ int __init vio_bus_init(struct vio_bus_ops *ops)
return err;
}
- return 0;
-}
+ node_vroot = find_devices("vdevice");
+ if (node_vroot) {
+ struct device_node *of_node;
+
+ /*
+ * Create struct vio_devices for each virtual device in
+ * the device tree. Drivers will associate with them later.
+ */
+ for (of_node = node_vroot->child; of_node != NULL;
+ of_node = of_node->sibling) {
+ printk(KERN_DEBUG "%s: processing %p\n",
+ __FUNCTION__, of_node);
+ vio_register_device_node(of_node);
+ }
+ }
-/* vio_dev refcount hit 0 */
-static void __devinit vio_dev_release(struct device *dev)
-{
- if (vio_bus_ops.release_device)
- vio_bus_ops.release_device(dev);
- kfree(to_vio_dev(dev));
+ return 0;
}
+__initcall(vio_bus_init);
-static ssize_t viodev_show_name(struct device *dev,
+static ssize_t name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%s\n", to_vio_dev(dev)->name);
}
-DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_name, NULL);
-struct vio_dev * __devinit vio_register_device(struct vio_dev *viodev)
+static ssize_t devspec_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- /* init generic 'struct device' fields: */
- viodev->dev.parent = &vio_bus_device.dev;
- viodev->dev.bus = &vio_bus_type;
- viodev->dev.release = vio_dev_release;
-
- /* register with generic device framework */
- if (device_register(&viodev->dev)) {
- printk(KERN_ERR "%s: failed to register device %s\n",
- __FUNCTION__, viodev->dev.bus_id);
- return NULL;
- }
- device_create_file(&viodev->dev, &dev_attr_name);
+ struct device_node *of_node = dev->platform_data;
- return viodev;
+ return sprintf(buf, "%s\n", of_node ? of_node->full_name : "none");
}
+static struct device_attribute vio_dev_attrs[] = {
+ __ATTR_RO(name),
+ __ATTR_RO(devspec),
+ __ATTR_NULL
+};
+
void __devinit vio_unregister_device(struct vio_dev *viodev)
{
- if (vio_bus_ops.unregister_device)
- vio_bus_ops.unregister_device(viodev);
- device_remove_file(&viodev->dev, &dev_attr_name);
device_unregister(&viodev->dev);
}
EXPORT_SYMBOL(vio_unregister_device);
@@ -229,7 +394,7 @@ static void *vio_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t flag)
{
return iommu_alloc_coherent(to_vio_dev(dev)->iommu_table, size,
- dma_handle, ~0ul, flag);
+ dma_handle, ~0ul, flag, -1);
}
static void vio_free_coherent(struct device *dev, size_t size,
@@ -267,22 +432,23 @@ static int vio_hotplug(struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{
const struct vio_dev *vio_dev = to_vio_dev(dev);
+ struct device_node *dn = dev->platform_data;
char *cp;
int length;
if (!num_envp)
return -ENOMEM;
- if (!vio_dev->dev.platform_data)
+ if (!dn)
return -ENODEV;
- cp = (char *)get_property(vio_dev->dev.platform_data, "compatible", &length);
+ cp = (char *)get_property(dn, "compatible", &length);
if (!cp)
return -ENODEV;
envp[0] = buffer;
length = scnprintf(buffer, buffer_size, "MODALIAS=vio:T%sS%s",
vio_dev->type, cp);
- if (buffer_size - length <= 0)
+ if ((buffer_size - length) <= 0)
return -ENOMEM;
envp[1] = NULL;
return 0;
@@ -290,9 +456,81 @@ static int vio_hotplug(struct device *dev, char **envp, int num_envp,
struct bus_type vio_bus_type = {
.name = "vio",
+ .dev_attrs = vio_dev_attrs,
.uevent = vio_hotplug,
.match = vio_bus_match,
.probe = vio_bus_probe,
.remove = vio_bus_remove,
.shutdown = vio_bus_shutdown,
};
+
+/**
+ * vio_get_attribute: - get attribute for virtual device
+ * @vdev: The vio device to get property.
+ * @which: The property/attribute to be extracted.
+ * @length: Pointer to length of returned data size (unused if NULL).
+ *
+ * Calls prom.c's get_property() to return the value of the
+ * attribute specified by @which
+*/
+const void *vio_get_attribute(struct vio_dev *vdev, char *which, int *length)
+{
+ return get_property(vdev->dev.platform_data, which, length);
+}
+EXPORT_SYMBOL(vio_get_attribute);
+
+#ifdef CONFIG_PPC_PSERIES
+/* vio_find_name() - internal because only vio.c knows how we formatted the
+ * kobject name
+ * XXX once vio_bus_type.devices is actually used as a kset in
+ * drivers/base/bus.c, this function should be removed in favor of
+ * "device_find(kobj_name, &vio_bus_type)"
+ */
+static struct vio_dev *vio_find_name(const char *kobj_name)
+{
+ struct kobject *found;
+
+ found = kset_find_obj(&devices_subsys.kset, kobj_name);
+ if (!found)
+ return NULL;
+
+ return to_vio_dev(container_of(found, struct device, kobj));
+}
+
+/**
+ * vio_find_node - find an already-registered vio_dev
+ * @vnode: device_node of the virtual device we're looking for
+ */
+struct vio_dev *vio_find_node(struct device_node *vnode)
+{
+ uint32_t *unit_address;
+ char kobj_name[BUS_ID_SIZE];
+
+ /* construct the kobject name from the device node */
+ unit_address = (uint32_t *)get_property(vnode, "reg", NULL);
+ if (!unit_address)
+ return NULL;
+ snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address);
+
+ return vio_find_name(kobj_name);
+}
+EXPORT_SYMBOL(vio_find_node);
+
+int vio_enable_interrupts(struct vio_dev *dev)
+{
+ int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE);
+ if (rc != H_SUCCESS)
+ printk(KERN_ERR "vio: Error 0x%x enabling interrupts\n", rc);
+ return rc;
+}
+EXPORT_SYMBOL(vio_enable_interrupts);
+
+int vio_disable_interrupts(struct vio_dev *dev)
+{
+ int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE);
+ if (rc != H_SUCCESS)
+ printk(KERN_ERR "vio: Error 0x%x disabling interrupts\n", rc);
+ return rc;
+}
+EXPORT_SYMBOL(vio_disable_interrupts);
+#endif /* CONFIG_PPC_PSERIES */
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index fe79c258..8b25953 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -93,6 +93,11 @@ SECTIONS
__ptov_table_begin = .;
*(.ptov_fixup);
__ptov_table_end = .;
+#ifdef CONFIG_PPC_ISERIES
+ __dt_strings_start = .;
+ *(.dt_strings);
+ __dt_strings_end = .;
+#endif
}
. = ALIGN(16);
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index 34f5c2e..ff70964 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -2,12 +2,15 @@
# Makefile for ppc-specific library files..
#
+ifeq ($(CONFIG_PPC64),y)
+EXTRA_CFLAGS += -mno-minimal-toc
+endif
+
ifeq ($(CONFIG_PPC_MERGE),y)
obj-y := string.o strcase.o
obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o
endif
-obj-y += bitops.o
obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o \
memcpy_64.o usercopy_64.o mem_64.o string.o \
strcase.o
diff --git a/arch/powerpc/lib/bitops.c b/arch/powerpc/lib/bitops.c
deleted file mode 100644
index f68ad71..0000000
--- a/arch/powerpc/lib/bitops.c
+++ /dev/null
@@ -1,150 +0,0 @@
-#include <linux/types.h>
-#include <linux/module.h>
-#include <asm/byteorder.h>
-#include <asm/bitops.h>
-
-/**
- * find_next_bit - find the next set bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
- */
-unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
- unsigned long offset)
-{
- const unsigned long *p = addr + BITOP_WORD(offset);
- unsigned long result = offset & ~(BITS_PER_LONG-1);
- unsigned long tmp;
-
- if (offset >= size)
- return size;
- size -= result;
- offset %= BITS_PER_LONG;
- if (offset) {
- tmp = *(p++);
- tmp &= (~0UL << offset);
- if (size < BITS_PER_LONG)
- goto found_first;
- if (tmp)
- goto found_middle;
- size -= BITS_PER_LONG;
- result += BITS_PER_LONG;
- }
- while (size & ~(BITS_PER_LONG-1)) {
- if ((tmp = *(p++)))
- goto found_middle;
- result += BITS_PER_LONG;
- size -= BITS_PER_LONG;
- }
- if (!size)
- return result;
- tmp = *p;
-
-found_first:
- tmp &= (~0UL >> (BITS_PER_LONG - size));
- if (tmp == 0UL) /* Are any bits set? */
- return result + size; /* Nope. */
-found_middle:
- return result + __ffs(tmp);
-}
-EXPORT_SYMBOL(find_next_bit);
-
-/*
- * This implementation of find_{first,next}_zero_bit was stolen from
- * Linus' asm-alpha/bitops.h.
- */
-unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
- unsigned long offset)
-{
- const unsigned long *p = addr + BITOP_WORD(offset);
- unsigned long result = offset & ~(BITS_PER_LONG-1);
- unsigned long tmp;
-
- if (offset >= size)
- return size;
- size -= result;
- offset %= BITS_PER_LONG;
- if (offset) {
- tmp = *(p++);
- tmp |= ~0UL >> (BITS_PER_LONG - offset);
- if (size < BITS_PER_LONG)
- goto found_first;
- if (~tmp)
- goto found_middle;
- size -= BITS_PER_LONG;
- result += BITS_PER_LONG;
- }
- while (size & ~(BITS_PER_LONG-1)) {
- if (~(tmp = *(p++)))
- goto found_middle;
- result += BITS_PER_LONG;
- size -= BITS_PER_LONG;
- }
- if (!size)
- return result;
- tmp = *p;
-
-found_first:
- tmp |= ~0UL << size;
- if (tmp == ~0UL) /* Are any bits zero? */
- return result + size; /* Nope. */
-found_middle:
- return result + ffz(tmp);
-}
-EXPORT_SYMBOL(find_next_zero_bit);
-
-static inline unsigned int ext2_ilog2(unsigned int x)
-{
- int lz;
-
- asm("cntlzw %0,%1": "=r"(lz):"r"(x));
- return 31 - lz;
-}
-
-static inline unsigned int ext2_ffz(unsigned int x)
-{
- u32 rc;
- if ((x = ~x) == 0)
- return 32;
- rc = ext2_ilog2(x & -x);
- return rc;
-}
-
-unsigned long find_next_zero_le_bit(const unsigned long *addr,
- unsigned long size, unsigned long offset)
-{
- const unsigned int *p = ((const unsigned int *)addr) + (offset >> 5);
- unsigned int result = offset & ~31;
- unsigned int tmp;
-
- if (offset >= size)
- return size;
- size -= result;
- offset &= 31;
- if (offset) {
- tmp = cpu_to_le32p(p++);
- tmp |= ~0U >> (32 - offset); /* bug or feature ? */
- if (size < 32)
- goto found_first;
- if (tmp != ~0)
- goto found_middle;
- size -= 32;
- result += 32;
- }
- while (size >= 32) {
- if ((tmp = cpu_to_le32p(p++)) != ~0)
- goto found_middle;
- result += 32;
- size -= 32;
- }
- if (!size)
- return result;
- tmp = cpu_to_le32p(p);
-found_first:
- tmp |= ~0 << size;
- if (tmp == ~0) /* Are any bits zero? */
- return result + size; /* Nope. */
-found_middle:
- return result + ext2_ffz(tmp);
-}
-EXPORT_SYMBOL(find_next_zero_le_bit);
diff --git a/arch/powerpc/mm/hash_low_32.S b/arch/powerpc/mm/hash_low_32.S
index ea469ee..94255be 100644
--- a/arch/powerpc/mm/hash_low_32.S
+++ b/arch/powerpc/mm/hash_low_32.S
@@ -74,12 +74,6 @@ _GLOBAL(hash_page_sync)
*/
.text
_GLOBAL(hash_page)
-#ifdef CONFIG_PPC64BRIDGE
- mfmsr r0
- clrldi r0,r0,1 /* make sure it's in 32-bit mode */
- MTMSRD(r0)
- isync
-#endif
tophys(r7,0) /* gets -KERNELBASE into r7 */
#ifdef CONFIG_SMP
addis r8,r7,mmu_hash_lock@h
@@ -285,7 +279,6 @@ Hash_base = 0xc0180000
Hash_bits = 12 /* e.g. 256kB hash table */
Hash_msk = (((1 << Hash_bits) - 1) * 64)
-#ifndef CONFIG_PPC64BRIDGE
/* defines for the PTE format for 32-bit PPCs */
#define PTE_SIZE 8
#define PTEG_SIZE 64
@@ -299,21 +292,6 @@ Hash_msk = (((1 << Hash_bits) - 1) * 64)
#define SET_V(r) oris r,r,PTE_V@h
#define CLR_V(r,t) rlwinm r,r,0,1,31
-#else
-/* defines for the PTE format for 64-bit PPCs */
-#define PTE_SIZE 16
-#define PTEG_SIZE 128
-#define LG_PTEG_SIZE 7
-#define LDPTEu ldu
-#define STPTE std
-#define CMPPTE cmpd
-#define PTE_H 2
-#define PTE_V 1
-#define TST_V(r) andi. r,r,PTE_V
-#define SET_V(r) ori r,r,PTE_V
-#define CLR_V(r,t) li t,PTE_V; andc r,r,t
-#endif /* CONFIG_PPC64BRIDGE */
-
#define HASH_LEFT 31-(LG_PTEG_SIZE+Hash_bits-1)
#define HASH_RIGHT 31-LG_PTEG_SIZE
@@ -331,14 +309,8 @@ BEGIN_FTR_SECTION
END_FTR_SECTION_IFSET(CPU_FTR_NEED_COHERENT)
/* Construct the high word of the PPC-style PTE (r5) */
-#ifndef CONFIG_PPC64BRIDGE
rlwinm r5,r3,7,1,24 /* put VSID in 0x7fffff80 bits */
rlwimi r5,r4,10,26,31 /* put in API (abbrev page index) */
-#else /* CONFIG_PPC64BRIDGE */
- clrlwi r3,r3,8 /* reduce vsid to 24 bits */
- sldi r5,r3,12 /* shift vsid into position */
- rlwimi r5,r4,16,20,24 /* put in API (abbrev page index) */
-#endif /* CONFIG_PPC64BRIDGE */
SET_V(r5) /* set V (valid) bit */
/* Get the address of the primary PTE group in the hash table (r3) */
@@ -516,14 +488,8 @@ _GLOBAL(flush_hash_pages)
add r3,r3,r0 /* note code below trims to 24 bits */
/* Construct the high word of the PPC-style PTE (r11) */
-#ifndef CONFIG_PPC64BRIDGE
rlwinm r11,r3,7,1,24 /* put VSID in 0x7fffff80 bits */
rlwimi r11,r4,10,26,31 /* put in API (abbrev page index) */
-#else /* CONFIG_PPC64BRIDGE */
- clrlwi r3,r3,8 /* reduce vsid to 24 bits */
- sldi r11,r3,12 /* shift vsid into position */
- rlwimi r11,r4,16,20,24 /* put in API (abbrev page index) */
-#endif /* CONFIG_PPC64BRIDGE */
SET_V(r11) /* set V (valid) bit */
#ifdef CONFIG_SMP
diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S
index e0d02c4..52e9142 100644
--- a/arch/powerpc/mm/hash_low_64.S
+++ b/arch/powerpc/mm/hash_low_64.S
@@ -136,6 +136,7 @@ _GLOBAL(__hash_page_4K)
and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
andc r0,r30,r0 /* r0 = pte & ~r0 */
rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */
+ ori r3,r3,HPTE_R_C /* Always add "C" bit for perf. */
/* We eventually do the icache sync here (maybe inline that
* code rather than call a C function...)
@@ -368,6 +369,7 @@ _GLOBAL(__hash_page_4K)
rlwinm r30,r4,32-9+7,31-7,31-7 /* _PAGE_RW -> _PAGE_DIRTY */
or r30,r30,r31
ori r30,r30,_PAGE_BUSY | _PAGE_ACCESSED | _PAGE_HASHPTE
+ oris r30,r30,_PAGE_COMBO@h
/* Write the linux PTE atomically (setting busy) */
stdcx. r30,0,r6
bne- 1b
@@ -400,6 +402,7 @@ _GLOBAL(__hash_page_4K)
and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
andc r0,r30,r0 /* r0 = pte & ~r0 */
rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */
+ ori r3,r3,HPTE_R_C /* Always add "C" bit for perf. */
/* We eventually do the icache sync here (maybe inline that
* code rather than call a C function...)
@@ -426,6 +429,14 @@ END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
andi. r0,r31,_PAGE_HASHPTE
li r26,0 /* Default hidx */
beq htab_insert_pte
+
+ /*
+ * Check if the pte was already inserted into the hash table
+ * as a 64k HW page, and invalidate the 64k HPTE if so.
+ */
+ andis. r0,r31,_PAGE_COMBO@h
+ beq htab_inval_old_hpte
+
ld r6,STK_PARM(r6)(r1)
ori r26,r6,0x8000 /* Load the hidx mask */
ld r26,0(r26)
@@ -496,6 +507,19 @@ _GLOBAL(htab_call_hpte_remove)
/* Try all again */
b htab_insert_pte
+ /*
+ * Call out to C code to invalidate an 64k HW HPTE that is
+ * useless now that the segment has been switched to 4k pages.
+ */
+htab_inval_old_hpte:
+ mr r3,r29 /* virtual addr */
+ mr r4,r31 /* PTE.pte */
+ li r5,0 /* PTE.hidx */
+ li r6,MMU_PAGE_64K /* psize */
+ ld r7,STK_PARM(r8)(r1) /* local */
+ bl .flush_hash_page
+ b htab_insert_pte
+
htab_bail_ok:
li r3,0
b htab_bail
@@ -636,6 +660,12 @@ _GLOBAL(__hash_page_64K)
* is changing this PTE anyway and might hash it.
*/
bne- ht64_bail_ok
+BEGIN_FTR_SECTION
+ /* Check if PTE has the cache-inhibit bit set */
+ andi. r0,r31,_PAGE_NO_CACHE
+ /* If so, bail out and refault as a 4k page */
+ bne- ht64_bail_ok
+END_FTR_SECTION_IFCLR(CPU_FTR_CI_LARGE_PAGE)
/* Prepare new PTE value (turn access RW into DIRTY, then
* add BUSY,HASHPTE and ACCESSED)
*/
@@ -671,6 +701,7 @@ _GLOBAL(__hash_page_64K)
and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
andc r0,r30,r0 /* r0 = pte & ~r0 */
rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */
+ ori r3,r3,HPTE_R_C /* Always add "C" bit for perf. */
/* We eventually do the icache sync here (maybe inline that
* code rather than call a C function...)
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c
index 994856e..a0f3cbd 100644
--- a/arch/powerpc/mm/hash_native_64.c
+++ b/arch/powerpc/mm/hash_native_64.c
@@ -238,7 +238,7 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
DBG_LOW(" -> hit\n");
/* Update the HPTE */
hptep->r = (hptep->r & ~(HPTE_R_PP | HPTE_R_N)) |
- (newpp & (HPTE_R_PP | HPTE_R_N));
+ (newpp & (HPTE_R_PP | HPTE_R_N | HPTE_R_C));
native_unlock_hpte(hptep);
}
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index c006d90..d03fd2b 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -92,10 +92,15 @@ unsigned long htab_size_bytes;
unsigned long htab_hash_mask;
int mmu_linear_psize = MMU_PAGE_4K;
int mmu_virtual_psize = MMU_PAGE_4K;
+int mmu_vmalloc_psize = MMU_PAGE_4K;
+int mmu_io_psize = MMU_PAGE_4K;
#ifdef CONFIG_HUGETLB_PAGE
int mmu_huge_psize = MMU_PAGE_16M;
unsigned int HPAGE_SHIFT;
#endif
+#ifdef CONFIG_PPC_64K_PAGES
+int mmu_ci_restrictions;
+#endif
/* There are definitions of page sizes arrays to be used when none
* is provided by the firmware.
@@ -308,20 +313,31 @@ static void __init htab_init_page_sizes(void)
else if (mmu_psize_defs[MMU_PAGE_1M].shift)
mmu_linear_psize = MMU_PAGE_1M;
+#ifdef CONFIG_PPC_64K_PAGES
/*
* Pick a size for the ordinary pages. Default is 4K, we support
- * 64K if cache inhibited large pages are supported by the
- * processor
+ * 64K for user mappings and vmalloc if supported by the processor.
+ * We only use 64k for ioremap if the processor
+ * (and firmware) support cache-inhibited large pages.
+ * If not, we use 4k and set mmu_ci_restrictions so that
+ * hash_page knows to switch processes that use cache-inhibited
+ * mappings to 4k pages.
*/
-#ifdef CONFIG_PPC_64K_PAGES
- if (mmu_psize_defs[MMU_PAGE_64K].shift &&
- cpu_has_feature(CPU_FTR_CI_LARGE_PAGE))
+ if (mmu_psize_defs[MMU_PAGE_64K].shift) {
mmu_virtual_psize = MMU_PAGE_64K;
+ mmu_vmalloc_psize = MMU_PAGE_64K;
+ if (cpu_has_feature(CPU_FTR_CI_LARGE_PAGE))
+ mmu_io_psize = MMU_PAGE_64K;
+ else
+ mmu_ci_restrictions = 1;
+ }
#endif
- printk(KERN_INFO "Page orders: linear mapping = %d, others = %d\n",
+ printk(KERN_DEBUG "Page orders: linear mapping = %d, "
+ "virtual = %d, io = %d\n",
mmu_psize_defs[mmu_linear_psize].shift,
- mmu_psize_defs[mmu_virtual_psize].shift);
+ mmu_psize_defs[mmu_virtual_psize].shift,
+ mmu_psize_defs[mmu_io_psize].shift);
#ifdef CONFIG_HUGETLB_PAGE
/* Init large page size. Currently, we pick 16M or 1M depending
@@ -556,6 +572,7 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
pte_t *ptep;
cpumask_t tmp;
int rc, user_region = 0, local = 0;
+ int psize;
DBG_LOW("hash_page(ea=%016lx, access=%lx, trap=%lx\n",
ea, access, trap);
@@ -575,10 +592,15 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
return 1;
}
vsid = get_vsid(mm->context.id, ea);
+ psize = mm->context.user_psize;
break;
case VMALLOC_REGION_ID:
mm = &init_mm;
vsid = get_kernel_vsid(ea);
+ if (ea < VMALLOC_END)
+ psize = mmu_vmalloc_psize;
+ else
+ psize = mmu_io_psize;
break;
default:
/* Not a valid range
@@ -629,7 +651,40 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
#ifndef CONFIG_PPC_64K_PAGES
rc = __hash_page_4K(ea, access, vsid, ptep, trap, local);
#else
- if (mmu_virtual_psize == MMU_PAGE_64K)
+ if (mmu_ci_restrictions) {
+ /* If this PTE is non-cacheable, switch to 4k */
+ if (psize == MMU_PAGE_64K &&
+ (pte_val(*ptep) & _PAGE_NO_CACHE)) {
+ if (user_region) {
+ psize = MMU_PAGE_4K;
+ mm->context.user_psize = MMU_PAGE_4K;
+ mm->context.sllp = SLB_VSID_USER |
+ mmu_psize_defs[MMU_PAGE_4K].sllp;
+ } else if (ea < VMALLOC_END) {
+ /*
+ * some driver did a non-cacheable mapping
+ * in vmalloc space, so switch vmalloc
+ * to 4k pages
+ */
+ printk(KERN_ALERT "Reducing vmalloc segment "
+ "to 4kB pages because of "
+ "non-cacheable mapping\n");
+ psize = mmu_vmalloc_psize = MMU_PAGE_4K;
+ }
+ }
+ if (user_region) {
+ if (psize != get_paca()->context.user_psize) {
+ get_paca()->context = mm->context;
+ slb_flush_and_rebolt();
+ }
+ } else if (get_paca()->vmalloc_sllp !=
+ mmu_psize_defs[mmu_vmalloc_psize].sllp) {
+ get_paca()->vmalloc_sllp =
+ mmu_psize_defs[mmu_vmalloc_psize].sllp;
+ slb_flush_and_rebolt();
+ }
+ }
+ if (psize == MMU_PAGE_64K)
rc = __hash_page_64K(ea, access, vsid, ptep, trap, local);
else
rc = __hash_page_4K(ea, access, vsid, ptep, trap, local);
@@ -681,7 +736,18 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
#ifndef CONFIG_PPC_64K_PAGES
__hash_page_4K(ea, access, vsid, ptep, trap, local);
#else
- if (mmu_virtual_psize == MMU_PAGE_64K)
+ if (mmu_ci_restrictions) {
+ /* If this PTE is non-cacheable, switch to 4k */
+ if (mm->context.user_psize == MMU_PAGE_64K &&
+ (pte_val(*ptep) & _PAGE_NO_CACHE)) {
+ mm->context.user_psize = MMU_PAGE_4K;
+ mm->context.sllp = SLB_VSID_USER |
+ mmu_psize_defs[MMU_PAGE_4K].sllp;
+ get_paca()->context = mm->context;
+ slb_flush_and_rebolt();
+ }
+ }
+ if (mm->context.user_psize == MMU_PAGE_64K)
__hash_page_64K(ea, access, vsid, ptep, trap, local);
else
__hash_page_4K(ea, access, vsid, ptep, trap, local);
diff --git a/arch/powerpc/mm/lmb.c b/arch/powerpc/mm/lmb.c
index 417d585..8b6f522 100644
--- a/arch/powerpc/mm/lmb.c
+++ b/arch/powerpc/mm/lmb.c
@@ -89,20 +89,25 @@ static long __init lmb_regions_adjacent(struct lmb_region *rgn,
return lmb_addrs_adjacent(base1, size1, base2, size2);
}
-/* Assumption: base addr of region 1 < base addr of region 2 */
-static void __init lmb_coalesce_regions(struct lmb_region *rgn,
- unsigned long r1, unsigned long r2)
+static void __init lmb_remove_region(struct lmb_region *rgn, unsigned long r)
{
unsigned long i;
- rgn->region[r1].size += rgn->region[r2].size;
- for (i=r2; i < rgn->cnt-1; i++) {
- rgn->region[i].base = rgn->region[i+1].base;
- rgn->region[i].size = rgn->region[i+1].size;
+ for (i = r; i < rgn->cnt - 1; i++) {
+ rgn->region[i].base = rgn->region[i + 1].base;
+ rgn->region[i].size = rgn->region[i + 1].size;
}
rgn->cnt--;
}
+/* Assumption: base addr of region 1 < base addr of region 2 */
+static void __init lmb_coalesce_regions(struct lmb_region *rgn,
+ unsigned long r1, unsigned long r2)
+{
+ rgn->region[r1].size += rgn->region[r2].size;
+ lmb_remove_region(rgn, r2);
+}
+
/* This routine called with relocation disabled. */
void __init lmb_init(void)
{
@@ -294,17 +299,16 @@ unsigned long __init lmb_end_of_DRAM(void)
return (lmb.memory.region[idx].base + lmb.memory.region[idx].size);
}
-/*
- * Truncate the lmb list to memory_limit if it's set
- * You must call lmb_analyze() after this.
- */
+/* You must call lmb_analyze() after this. */
void __init lmb_enforce_memory_limit(unsigned long memory_limit)
{
unsigned long i, limit;
+ struct lmb_property *p;
if (! memory_limit)
return;
+ /* Truncate the lmb regions to satisfy the memory limit. */
limit = memory_limit;
for (i = 0; i < lmb.memory.cnt; i++) {
if (limit > lmb.memory.region[i].size) {
@@ -316,4 +320,21 @@ void __init lmb_enforce_memory_limit(unsigned long memory_limit)
lmb.memory.cnt = i + 1;
break;
}
+
+ lmb.rmo_size = lmb.memory.region[0].size;
+
+ /* And truncate any reserves above the limit also. */
+ for (i = 0; i < lmb.reserved.cnt; i++) {
+ p = &lmb.reserved.region[i];
+
+ if (p->base > memory_limit)
+ p->size = 0;
+ else if ((p->base + p->size) > memory_limit)
+ p->size = memory_limit - p->base;
+
+ if (p->size == 0) {
+ lmb_remove_region(&lmb.reserved, i);
+ i--;
+ }
+ }
}
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 741dd88..69f3b9a 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -299,9 +299,9 @@ void __init paging_init(void)
kmap_prot = PAGE_KERNEL;
#endif /* CONFIG_HIGHMEM */
- printk(KERN_INFO "Top of RAM: 0x%lx, Total RAM: 0x%lx\n",
+ printk(KERN_DEBUG "Top of RAM: 0x%lx, Total RAM: 0x%lx\n",
top_of_ram, total_ram);
- printk(KERN_INFO "Memory hole size: %ldMB\n",
+ printk(KERN_DEBUG "Memory hole size: %ldMB\n",
(top_of_ram - total_ram) >> 20);
/*
* All pages are DMA-able so we put them all in the DMA zone.
@@ -380,7 +380,7 @@ void __init mem_init(void)
totalhigh_pages++;
}
totalram_pages += totalhigh_pages;
- printk(KERN_INFO "High memory: %luk\n",
+ printk(KERN_DEBUG "High memory: %luk\n",
totalhigh_pages << (PAGE_SHIFT-10));
}
#endif /* CONFIG_HIGHMEM */
diff --git a/arch/powerpc/mm/mmu_context_32.c b/arch/powerpc/mm/mmu_context_32.c
index a8816e0..e326e424 100644
--- a/arch/powerpc/mm/mmu_context_32.c
+++ b/arch/powerpc/mm/mmu_context_32.c
@@ -30,7 +30,7 @@
#include <asm/mmu_context.h>
#include <asm/tlbflush.h>
-mm_context_t next_mmu_context;
+unsigned long next_mmu_context;
unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1];
#ifdef FEW_CONTEXTS
atomic_t nr_free_contexts;
diff --git a/arch/powerpc/mm/mmu_context_64.c b/arch/powerpc/mm/mmu_context_64.c
index 714a84d..65d18dc 100644
--- a/arch/powerpc/mm/mmu_context_64.c
+++ b/arch/powerpc/mm/mmu_context_64.c
@@ -49,6 +49,9 @@ again:
}
mm->context.id = index;
+ mm->context.user_psize = mmu_virtual_psize;
+ mm->context.sllp = SLB_VSID_USER |
+ mmu_psize_defs[mmu_virtual_psize].sllp;
return 0;
}
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 092355f..aa98cb3 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -487,9 +487,9 @@ static void __init setup_nonnuma(void)
unsigned long total_ram = lmb_phys_mem_size();
unsigned int i;
- printk(KERN_INFO "Top of RAM: 0x%lx, Total RAM: 0x%lx\n",
+ printk(KERN_DEBUG "Top of RAM: 0x%lx, Total RAM: 0x%lx\n",
top_of_ram, total_ram);
- printk(KERN_INFO "Memory hole size: %ldMB\n",
+ printk(KERN_DEBUG "Memory hole size: %ldMB\n",
(top_of_ram - total_ram) >> 20);
for (i = 0; i < lmb.memory.cnt; ++i)
@@ -507,7 +507,7 @@ void __init dump_numa_cpu_topology(void)
return;
for_each_online_node(node) {
- printk(KERN_INFO "Node %d CPUs:", node);
+ printk(KERN_DEBUG "Node %d CPUs:", node);
count = 0;
/*
@@ -543,7 +543,7 @@ static void __init dump_numa_memory_topology(void)
for_each_online_node(node) {
unsigned long i;
- printk(KERN_INFO "Node %d Memory:", node);
+ printk(KERN_DEBUG "Node %d Memory:", node);
count = 0;
diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c
index ed7fcfe..2ed43a4 100644
--- a/arch/powerpc/mm/ppc_mmu_32.c
+++ b/arch/powerpc/mm/ppc_mmu_32.c
@@ -42,18 +42,14 @@ unsigned long _SDR1;
union ubat { /* BAT register values to be loaded */
BAT bat;
-#ifdef CONFIG_PPC64BRIDGE
- u64 word[2];
-#else
u32 word[2];
-#endif
-} BATS[4][2]; /* 4 pairs of IBAT, DBAT */
+} BATS[8][2]; /* 8 pairs of IBAT, DBAT */
struct batrange { /* stores address ranges mapped by BATs */
unsigned long start;
unsigned long limit;
unsigned long phys;
-} bat_addrs[4];
+} bat_addrs[8];
/*
* Return PA for this VA if it is mapped by a BAT, or 0
@@ -190,7 +186,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
return;
pmd = pmd_offset(pgd_offset(mm, ea), ea);
if (!pmd_none(*pmd))
- add_hash_page(mm->context, ea, pmd_val(*pmd));
+ add_hash_page(mm->context.id, ea, pmd_val(*pmd));
}
/*
@@ -220,15 +216,9 @@ void __init MMU_init_hw(void)
if ( ppc_md.progress ) ppc_md.progress("hash:enter", 0x105);
-#ifdef CONFIG_PPC64BRIDGE
-#define LG_HPTEG_SIZE 7 /* 128 bytes per HPTEG */
-#define SDR1_LOW_BITS (lg_n_hpteg - 11)
-#define MIN_N_HPTEG 2048 /* min 256kB hash table */
-#else
#define LG_HPTEG_SIZE 6 /* 64 bytes per HPTEG */
#define SDR1_LOW_BITS ((n_hpteg - 1) >> 10)
#define MIN_N_HPTEG 1024 /* min 64kB hash table */
-#endif
/*
* Allow 1 HPTE (1/8 HPTEG) for each page of memory.
diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c
index ffc8ed4..6a8bf6c 100644
--- a/arch/powerpc/mm/slb.c
+++ b/arch/powerpc/mm/slb.c
@@ -60,19 +60,19 @@ static inline void create_slbe(unsigned long ea, unsigned long flags,
: "memory" );
}
-static void slb_flush_and_rebolt(void)
+void slb_flush_and_rebolt(void)
{
/* If you change this make sure you change SLB_NUM_BOLTED
* appropriately too. */
- unsigned long linear_llp, virtual_llp, lflags, vflags;
+ unsigned long linear_llp, vmalloc_llp, lflags, vflags;
unsigned long ksp_esid_data;
WARN_ON(!irqs_disabled());
linear_llp = mmu_psize_defs[mmu_linear_psize].sllp;
- virtual_llp = mmu_psize_defs[mmu_virtual_psize].sllp;
+ vmalloc_llp = mmu_psize_defs[mmu_vmalloc_psize].sllp;
lflags = SLB_VSID_KERNEL | linear_llp;
- vflags = SLB_VSID_KERNEL | virtual_llp;
+ vflags = SLB_VSID_KERNEL | vmalloc_llp;
ksp_esid_data = mk_esid_data(get_paca()->kstack, 2);
if ((ksp_esid_data & ESID_MASK) == PAGE_OFFSET)
@@ -122,9 +122,6 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm)
get_paca()->slb_cache_ptr = 0;
get_paca()->context = mm->context;
-#ifdef CONFIG_PPC_64K_PAGES
- get_paca()->pgdir = mm->pgd;
-#endif /* CONFIG_PPC_64K_PAGES */
/*
* preload some userspace segments into the SLB.
@@ -167,11 +164,10 @@ static inline void patch_slb_encoding(unsigned int *insn_addr,
void slb_initialize(void)
{
- unsigned long linear_llp, virtual_llp;
+ unsigned long linear_llp, vmalloc_llp, io_llp;
static int slb_encoding_inited;
extern unsigned int *slb_miss_kernel_load_linear;
- extern unsigned int *slb_miss_kernel_load_virtual;
- extern unsigned int *slb_miss_user_load_normal;
+ extern unsigned int *slb_miss_kernel_load_io;
#ifdef CONFIG_HUGETLB_PAGE
extern unsigned int *slb_miss_user_load_huge;
unsigned long huge_llp;
@@ -181,18 +177,19 @@ void slb_initialize(void)
/* Prepare our SLB miss handler based on our page size */
linear_llp = mmu_psize_defs[mmu_linear_psize].sllp;
- virtual_llp = mmu_psize_defs[mmu_virtual_psize].sllp;
+ io_llp = mmu_psize_defs[mmu_io_psize].sllp;
+ vmalloc_llp = mmu_psize_defs[mmu_vmalloc_psize].sllp;
+ get_paca()->vmalloc_sllp = SLB_VSID_KERNEL | vmalloc_llp;
+
if (!slb_encoding_inited) {
slb_encoding_inited = 1;
patch_slb_encoding(slb_miss_kernel_load_linear,
SLB_VSID_KERNEL | linear_llp);
- patch_slb_encoding(slb_miss_kernel_load_virtual,
- SLB_VSID_KERNEL | virtual_llp);
- patch_slb_encoding(slb_miss_user_load_normal,
- SLB_VSID_USER | virtual_llp);
+ patch_slb_encoding(slb_miss_kernel_load_io,
+ SLB_VSID_KERNEL | io_llp);
DBG("SLB: linear LLP = %04x\n", linear_llp);
- DBG("SLB: virtual LLP = %04x\n", virtual_llp);
+ DBG("SLB: io LLP = %04x\n", io_llp);
#ifdef CONFIG_HUGETLB_PAGE
patch_slb_encoding(slb_miss_user_load_huge,
SLB_VSID_USER | huge_llp);
@@ -207,7 +204,7 @@ void slb_initialize(void)
unsigned long lflags, vflags;
lflags = SLB_VSID_KERNEL | linear_llp;
- vflags = SLB_VSID_KERNEL | virtual_llp;
+ vflags = SLB_VSID_KERNEL | vmalloc_llp;
/* Invalidate the entire SLB (even slot 0) & all the ERATS */
asm volatile("isync":::"memory");
@@ -215,7 +212,6 @@ void slb_initialize(void)
asm volatile("isync; slbia; isync":::"memory");
create_slbe(PAGE_OFFSET, lflags, 0);
- /* VMALLOC space has 4K pages always for now */
create_slbe(VMALLOC_START, vflags, 1);
/* We don't bolt the stack for the time being - we're in boot,
diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S
index abfaabf6..8548dcf 100644
--- a/arch/powerpc/mm/slb_low.S
+++ b/arch/powerpc/mm/slb_low.S
@@ -59,10 +59,19 @@ _GLOBAL(slb_miss_kernel_load_linear)
li r11,0
b slb_finish_load
-1: /* vmalloc/ioremap mapping encoding bits, the "li" instruction below
+1: /* vmalloc/ioremap mapping encoding bits, the "li" instructions below
* will be patched by the kernel at boot
*/
-_GLOBAL(slb_miss_kernel_load_virtual)
+BEGIN_FTR_SECTION
+ /* check whether this is in vmalloc or ioremap space */
+ clrldi r11,r10,48
+ cmpldi r11,(VMALLOC_SIZE >> 28) - 1
+ bgt 5f
+ lhz r11,PACAVMALLOCSLLP(r13)
+ b slb_finish_load
+5:
+END_FTR_SECTION_IFCLR(CPU_FTR_CI_LARGE_PAGE)
+_GLOBAL(slb_miss_kernel_load_io)
li r11,0
b slb_finish_load
@@ -96,9 +105,7 @@ _GLOBAL(slb_miss_user_load_huge)
1:
#endif /* CONFIG_HUGETLB_PAGE */
-_GLOBAL(slb_miss_user_load_normal)
- li r11,0
-
+ lhz r11,PACACONTEXTSLLP(r13)
2:
ld r9,PACACONTEXTID(r13)
rldimi r10,r9,USER_ESID_BITS,0
diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c
index 4a9291d9..691320c 100644
--- a/arch/powerpc/mm/stab.c
+++ b/arch/powerpc/mm/stab.c
@@ -200,10 +200,6 @@ void switch_stab(struct task_struct *tsk, struct mm_struct *mm)
__get_cpu_var(stab_cache_ptr) = 0;
-#ifdef CONFIG_PPC_64K_PAGES
- get_paca()->pgdir = mm->pgd;
-#endif /* CONFIG_PPC_64K_PAGES */
-
/* Now preload some entries for the new task */
if (test_tsk_thread_flag(tsk, TIF_32BIT))
unmapped_base = TASK_UNMAPPED_BASE_USER32;
diff --git a/arch/powerpc/mm/tlb_32.c b/arch/powerpc/mm/tlb_32.c
index ad580f3..02eb23e 100644
--- a/arch/powerpc/mm/tlb_32.c
+++ b/arch/powerpc/mm/tlb_32.c
@@ -42,7 +42,7 @@ void flush_hash_entry(struct mm_struct *mm, pte_t *ptep, unsigned long addr)
if (Hash != 0) {
ptephys = __pa(ptep) & PAGE_MASK;
- flush_hash_pages(mm->context, addr, ptephys, 1);
+ flush_hash_pages(mm->context.id, addr, ptephys, 1);
}
}
@@ -102,7 +102,7 @@ static void flush_range(struct mm_struct *mm, unsigned long start,
pmd_t *pmd;
unsigned long pmd_end;
int count;
- unsigned int ctx = mm->context;
+ unsigned int ctx = mm->context.id;
if (Hash == 0) {
_tlbia();
@@ -172,7 +172,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
mm = (vmaddr < TASK_SIZE)? vma->vm_mm: &init_mm;
pmd = pmd_offset(pgd_offset(mm, vmaddr), vmaddr);
if (!pmd_none(*pmd))
- flush_hash_pages(mm->context, vmaddr, pmd_val(*pmd), 1);
+ flush_hash_pages(mm->context.id, vmaddr, pmd_val(*pmd), 1);
FINISH_FLUSH;
}
diff --git a/arch/powerpc/mm/tlb_64.c b/arch/powerpc/mm/tlb_64.c
index f734b11..e7449b0 100644
--- a/arch/powerpc/mm/tlb_64.c
+++ b/arch/powerpc/mm/tlb_64.c
@@ -131,7 +131,7 @@ void hpte_update(struct mm_struct *mm, unsigned long addr,
{
struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
unsigned long vsid;
- unsigned int psize = mmu_virtual_psize;
+ unsigned int psize;
int i;
i = batch->index;
@@ -148,7 +148,8 @@ void hpte_update(struct mm_struct *mm, unsigned long addr,
#else
BUG();
#endif
- }
+ } else
+ psize = pte_pagesize_index(pte);
/*
* This can happen when we are in the middle of a TLB batch and
diff --git a/arch/powerpc/oprofile/Kconfig b/arch/powerpc/oprofile/Kconfig
index d03c0e5..eb2dece 100644
--- a/arch/powerpc/oprofile/Kconfig
+++ b/arch/powerpc/oprofile/Kconfig
@@ -1,5 +1,4 @@
config PROFILING
- depends on !PPC_ISERIES
bool "Profiling support (EXPERIMENTAL)"
help
Say Y here to enable the extended profiling support mechanisms used
diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile
index f5f9859..3145d61 100644
--- a/arch/powerpc/oprofile/Makefile
+++ b/arch/powerpc/oprofile/Makefile
@@ -1,3 +1,7 @@
+ifeq ($(CONFIG_PPC64),y)
+EXTRA_CFLAGS += -mno-minimal-toc
+endif
+
obj-$(CONFIG_OPROFILE) += oprofile.o
DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \
diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c
index 5b1de7e..27ad56b 100644
--- a/arch/powerpc/oprofile/common.c
+++ b/arch/powerpc/oprofile/common.c
@@ -22,6 +22,7 @@
#include <asm/pmc.h>
#include <asm/cputable.h>
#include <asm/oprofile_impl.h>
+#include <asm/firmware.h>
static struct op_powerpc_model *model;
@@ -130,6 +131,9 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
if (!cur_cpu_spec->oprofile_cpu_type)
return -ENODEV;
+ if (firmware_has_feature(FW_FEATURE_ISERIES))
+ return -ENODEV;
+
switch (cur_cpu_spec->oprofile_type) {
#ifdef CONFIG_PPC64
case PPC_OPROFILE_RS64:
@@ -162,7 +166,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
ops->stop = op_powerpc_stop;
ops->backtrace = op_powerpc_backtrace;
- printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
+ printk(KERN_DEBUG "oprofile: using %s performance monitoring.\n",
ops->cpu_type);
return 0;
diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c
index 4c2beab1..506f6b7 100644
--- a/arch/powerpc/oprofile/op_model_power4.c
+++ b/arch/powerpc/oprofile/op_model_power4.c
@@ -24,10 +24,6 @@
static unsigned long reset_value[OP_MAX_COUNTER];
static int oprofile_running;
-static int mmcra_has_sihv;
-/* Unfortunately these bits vary between CPUs */
-static unsigned long mmcra_sihv = MMCRA_SIHV;
-static unsigned long mmcra_sipr = MMCRA_SIPR;
/* mmcr values are set in power4_reg_setup, used in power4_cpu_setup */
static u32 mmcr0_val;
@@ -41,16 +37,6 @@ static void power4_reg_setup(struct op_counter_config *ctr,
int i;
/*
- * SIHV / SIPR bits are only implemented on POWER4+ (GQ) and above.
- * However we disable it on all POWER4 until we verify it works
- * (I was seeing some strange behaviour last time I tried).
- *
- * It has been verified to work on POWER5 so we enable it there.
- */
- if (cpu_has_feature(CPU_FTR_MMCRA_SIHV))
- mmcra_has_sihv = 1;
-
- /*
* The performance counter event settings are given in the mmcr0,
* mmcr1 and mmcra values passed from the user in the
* op_system_config structure (sys variable).
@@ -202,18 +188,19 @@ static unsigned long get_pc(struct pt_regs *regs)
unsigned long mmcra;
/* Cant do much about it */
- if (!mmcra_has_sihv)
+ if (!cur_cpu_spec->oprofile_mmcra_sihv)
return pc;
mmcra = mfspr(SPRN_MMCRA);
/* Were we in the hypervisor? */
- if (firmware_has_feature(FW_FEATURE_LPAR) && (mmcra & mmcra_sihv))
+ if (firmware_has_feature(FW_FEATURE_LPAR) &&
+ (mmcra & cur_cpu_spec->oprofile_mmcra_sihv))
/* function descriptor madness */
return *((unsigned long *)hypervisor_bucket);
/* We were in userspace, nothing to do */
- if (mmcra & mmcra_sipr)
+ if (mmcra & cur_cpu_spec->oprofile_mmcra_sipr)
return pc;
#ifdef CONFIG_PPC_RTAS
@@ -235,15 +222,14 @@ static unsigned long get_pc(struct pt_regs *regs)
return pc;
}
-static int get_kernel(unsigned long pc)
+static int get_kernel(unsigned long pc, unsigned long mmcra)
{
int is_kernel;
- if (!mmcra_has_sihv) {
+ if (!cur_cpu_spec->oprofile_mmcra_sihv) {
is_kernel = is_kernel_addr(pc);
} else {
- unsigned long mmcra = mfspr(SPRN_MMCRA);
- is_kernel = ((mmcra & mmcra_sipr) == 0);
+ is_kernel = ((mmcra & cur_cpu_spec->oprofile_mmcra_sipr) == 0);
}
return is_kernel;
@@ -257,9 +243,12 @@ static void power4_handle_interrupt(struct pt_regs *regs,
int val;
int i;
unsigned int mmcr0;
+ unsigned long mmcra;
+
+ mmcra = mfspr(SPRN_MMCRA);
pc = get_pc(regs);
- is_kernel = get_kernel(pc);
+ is_kernel = get_kernel(pc, mmcra);
/* set the PMM bit (see comment below) */
mtmsrd(mfmsr() | MSR_PMM);
@@ -287,6 +276,10 @@ static void power4_handle_interrupt(struct pt_regs *regs,
*/
mmcr0 &= ~MMCR0_PMAO;
+ /* Clear the appropriate bits in the MMCRA */
+ mmcra &= ~cur_cpu_spec->oprofile_mmcra_clear;
+ mtspr(SPRN_MMCRA, mmcra);
+
/*
* now clear the freeze bit, counting will not start until we
* rfid from this exception, because only at that point will
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index 06e3712..454fc53 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -11,13 +11,20 @@ config MPC8540_ADS
help
This option enables support for the MPC 8540 ADS board
+config MPC85xx_CDS
+ bool "Freescale MPC85xx CDS"
+ select DEFAULT_UIMAGE
+ select PPC_I8259 if PCI
+ help
+ This option enables support for the MPC85xx CDS board
+
endchoice
config MPC8540
bool
select PPC_UDBG_16550
select PPC_INDIRECT_PCI
- default y if MPC8540_ADS
+ default y if MPC8540_ADS || MPC85xx_CDS
config PPC_INDIRECT_PCI_BE
bool
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index ffc4139..7615aa5 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -3,3 +3,4 @@
#
obj-$(CONFIG_PPC_85xx) += misc.o pci.o
obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o
+obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
new file mode 100644
index 0000000..18e6e11
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
@@ -0,0 +1,359 @@
+/*
+ * MPC85xx setup and early boot code plus other random bits.
+ *
+ * Maintained by Kumar Gala (see MAINTAINERS for contact information)
+ *
+ * Copyright 2005 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/ipic.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc85xx.h>
+#include <asm/irq.h>
+#include <mm/mmu_decl.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <asm/mpic.h>
+#include <asm/i8259.h>
+
+#include <sysdev/fsl_soc.h>
+#include "mpc85xx.h"
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+#endif
+
+static int cds_pci_slot = 2;
+static volatile u8 *cadmus;
+
+/*
+ * Internal interrupts are all Level Sensitive, and Positive Polarity
+ *
+ * Note: Likely, this table and the following function should be
+ * obtained and derived from the OF Device Tree.
+ */
+static u_char mpc85xx_cds_openpic_initsenses[] __initdata = {
+ MPC85XX_INTERNAL_IRQ_SENSES,
+#if defined(CONFIG_PCI)
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Ext 0: PCI slot 0 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext 1: PCI slot 1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext 2: PCI slot 2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext 3: PCI slot 3 */
+#else
+ 0x0, /* External 0: */
+ 0x0, /* External 1: */
+ 0x0, /* External 2: */
+ 0x0, /* External 3: */
+#endif
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 5: PHY */
+ 0x0, /* External 6: */
+ 0x0, /* External 7: */
+ 0x0, /* External 8: */
+ 0x0, /* External 9: */
+ 0x0, /* External 10: */
+#ifdef CONFIG_PCI
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext 11: PCI2 slot 0 */
+#else
+ 0x0, /* External 11: */
+#endif
+};
+
+
+#ifdef CONFIG_PCI
+/*
+ * interrupt routing
+ */
+int
+mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
+
+ if (!hose->index)
+ {
+ /* Handle PCI1 interrupts */
+ char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+
+ /* Note IRQ assignment for slots is based on which slot the elysium is
+ * in -- in this setup elysium is in slot #2 (this PIRQA as first
+ * interrupt on slot */
+ {
+ { 0, 1, 2, 3 }, /* 16 - PMC */
+ { 0, 1, 2, 3 }, /* 17 P2P (Tsi320) */
+ { 0, 1, 2, 3 }, /* 18 - Slot 1 */
+ { 1, 2, 3, 0 }, /* 19 - Slot 2 */
+ { 2, 3, 0, 1 }, /* 20 - Slot 3 */
+ { 3, 0, 1, 2 }, /* 21 - Slot 4 */
+ };
+
+ const long min_idsel = 16, max_idsel = 21, irqs_per_slot = 4;
+ int i, j;
+
+ for (i = 0; i < 6; i++)
+ for (j = 0; j < 4; j++)
+ pci_irq_table[i][j] =
+ ((pci_irq_table[i][j] + 5 -
+ cds_pci_slot) & 0x3) + PIRQ0A;
+
+ return PCI_IRQ_TABLE_LOOKUP;
+ } else {
+ /* Handle PCI2 interrupts (if we have one) */
+ char pci_irq_table[][4] =
+ {
+ /*
+ * We only have one slot and one interrupt
+ * going to PIRQA - PIRQD */
+ { PIRQ1A, PIRQ1A, PIRQ1A, PIRQ1A }, /* 21 - slot 0 */
+ };
+
+ const long min_idsel = 21, max_idsel = 21, irqs_per_slot = 4;
+
+ return PCI_IRQ_TABLE_LOOKUP;
+ }
+}
+
+#define ARCADIA_HOST_BRIDGE_IDSEL 17
+#define ARCADIA_2ND_BRIDGE_IDSEL 3
+
+extern int mpc85xx_pci2_busno;
+
+int
+mpc85xx_exclude_device(u_char bus, u_char devfn)
+{
+ if (bus == 0 && PCI_SLOT(devfn) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (mpc85xx_pci2_busno)
+ if (bus == (mpc85xx_pci2_busno) && PCI_SLOT(devfn) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ /* We explicitly do not go past the Tundra 320 Bridge */
+ if ((bus == 1) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if ((bus == 0) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ else
+ return PCIBIOS_SUCCESSFUL;
+}
+
+void __init
+mpc85xx_cds_pcibios_fixup(void)
+{
+ struct pci_dev *dev;
+ u_char c;
+
+ if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
+ PCI_DEVICE_ID_VIA_82C586_1, NULL))) {
+ /*
+ * U-Boot does not set the enable bits
+ * for the IDE device. Force them on here.
+ */
+ pci_read_config_byte(dev, 0x40, &c);
+ c |= 0x03; /* IDE: Chip Enable Bits */
+ pci_write_config_byte(dev, 0x40, c);
+
+ /*
+ * Since only primary interface works, force the
+ * IDE function to standard primary IDE interrupt
+ * w/ 8259 offset
+ */
+ dev->irq = 14;
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+ pci_dev_put(dev);
+ }
+
+ /*
+ * Force legacy USB interrupt routing
+ */
+ if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
+ PCI_DEVICE_ID_VIA_82C586_2, NULL))) {
+ dev->irq = 10;
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 10);
+ pci_dev_put(dev);
+ }
+
+ if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
+ PCI_DEVICE_ID_VIA_82C586_2, dev))) {
+ dev->irq = 11;
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
+ pci_dev_put(dev);
+ }
+}
+#endif /* CONFIG_PCI */
+
+void __init mpc85xx_cds_pic_init(void)
+{
+ struct mpic *mpic1;
+ phys_addr_t OpenPIC_PAddr;
+
+ /* Determine the Physical Address of the OpenPIC regs */
+ OpenPIC_PAddr = get_immrbase() + MPC85xx_OPENPIC_OFFSET;
+
+ mpic1 = mpic_alloc(OpenPIC_PAddr,
+ MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+ 4, MPC85xx_OPENPIC_IRQ_OFFSET, 0, 250,
+ mpc85xx_cds_openpic_initsenses,
+ sizeof(mpc85xx_cds_openpic_initsenses), " OpenPIC ");
+ BUG_ON(mpic1 == NULL);
+ mpic_assign_isu(mpic1, 0, OpenPIC_PAddr + 0x10200);
+ mpic_assign_isu(mpic1, 1, OpenPIC_PAddr + 0x10280);
+ mpic_assign_isu(mpic1, 2, OpenPIC_PAddr + 0x10300);
+ mpic_assign_isu(mpic1, 3, OpenPIC_PAddr + 0x10380);
+ mpic_assign_isu(mpic1, 4, OpenPIC_PAddr + 0x10400);
+ mpic_assign_isu(mpic1, 5, OpenPIC_PAddr + 0x10480);
+ mpic_assign_isu(mpic1, 6, OpenPIC_PAddr + 0x10500);
+ mpic_assign_isu(mpic1, 7, OpenPIC_PAddr + 0x10580);
+
+ /* dummy mappings to get to 48 */
+ mpic_assign_isu(mpic1, 8, OpenPIC_PAddr + 0x10600);
+ mpic_assign_isu(mpic1, 9, OpenPIC_PAddr + 0x10680);
+ mpic_assign_isu(mpic1, 10, OpenPIC_PAddr + 0x10700);
+ mpic_assign_isu(mpic1, 11, OpenPIC_PAddr + 0x10780);
+
+ /* External ints */
+ mpic_assign_isu(mpic1, 12, OpenPIC_PAddr + 0x10000);
+ mpic_assign_isu(mpic1, 13, OpenPIC_PAddr + 0x10080);
+ mpic_assign_isu(mpic1, 14, OpenPIC_PAddr + 0x10100);
+
+ mpic_init(mpic1);
+
+#ifdef CONFIG_PCI
+ mpic_setup_cascade(PIRQ0A, i8259_irq_cascade, NULL);
+
+ i8259_init(0,0);
+#endif
+}
+
+
+/*
+ * Setup the architecture
+ */
+static void __init
+mpc85xx_cds_setup_arch(void)
+{
+ struct device_node *cpu;
+#ifdef CONFIG_PCI
+ struct device_node *np;
+#endif
+
+ if (ppc_md.progress)
+ ppc_md.progress("mpc85xx_cds_setup_arch()", 0);
+
+ cpu = of_find_node_by_type(NULL, "cpu");
+ if (cpu != 0) {
+ unsigned int *fp;
+
+ fp = (int *)get_property(cpu, "clock-frequency", NULL);
+ if (fp != 0)
+ loops_per_jiffy = *fp / HZ;
+ else
+ loops_per_jiffy = 500000000 / HZ;
+ of_node_put(cpu);
+ }
+
+ cadmus = ioremap(CADMUS_BASE, CADMUS_SIZE);
+ cds_pci_slot = ((cadmus[CM_CSR] >> 6) & 0x3) + 1;
+
+ if (ppc_md.progress) {
+ char buf[40];
+ snprintf(buf, 40, "CDS Version = 0x%x in slot %d\n",
+ cadmus[CM_VER], cds_pci_slot);
+ ppc_md.progress(buf, 0);
+ }
+
+#ifdef CONFIG_PCI
+ for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
+ add_bridge(np);
+
+ ppc_md.pcibios_fixup = mpc85xx_cds_pcibios_fixup;
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = mpc85xx_map_irq;
+ ppc_md.pci_exclude_device = mpc85xx_exclude_device;
+#endif
+
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_HDA1;
+#endif
+}
+
+
+void
+mpc85xx_cds_show_cpuinfo(struct seq_file *m)
+{
+ uint pvid, svid, phid1;
+ uint memsize = total_memory;
+
+ pvid = mfspr(SPRN_PVR);
+ svid = mfspr(SPRN_SVR);
+
+ seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
+ seq_printf(m, "Machine\t\t: MPC85xx CDS (0x%x)\n", cadmus[CM_VER]);
+ seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
+ seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+
+ /* Display cpu Pll setting */
+ phid1 = mfspr(SPRN_HID1);
+ seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
+
+ /* Display the amount of memory */
+ seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
+}
+
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init mpc85xx_cds_probe(void)
+{
+ /* We always match for now, eventually we should look at
+ * the flat dev tree to ensure this is the board we are
+ * supposed to run on
+ */
+ return 1;
+}
+
+define_machine(mpc85xx_cds) {
+ .name = "MPC85xx CDS",
+ .probe = mpc85xx_cds_probe,
+ .setup_arch = mpc85xx_cds_setup_arch,
+ .init_IRQ = mpc85xx_cds_pic_init,
+ .show_cpuinfo = mpc85xx_cds_show_cpuinfo,
+ .get_irq = mpic_get_irq,
+ .restart = mpc85xx_restart,
+ .calibrate_decr = generic_calibrate_decr,
+ .progress = udbg_progress,
+};
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.h b/arch/powerpc/platforms/85xx/mpc85xx_cds.h
new file mode 100644
index 0000000..671f54f
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.h
@@ -0,0 +1,43 @@
+/*
+ * arch/ppc/platforms/85xx/mpc85xx_cds_common.h
+ *
+ * MPC85xx CDS board definitions
+ *
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
+ *
+ * Copyright 2004 Freescale Semiconductor, Inc
+ *
+ * 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.
+ *
+ */
+
+#ifndef __MACH_MPC85XX_CDS_H__
+#define __MACH_MPC85XX_CDS_H__
+
+/* CADMUS info */
+#define CADMUS_BASE (0xf8004000)
+#define CADMUS_SIZE (256)
+#define CM_VER (0)
+#define CM_CSR (1)
+#define CM_RST (2)
+
+/* CDS NVRAM/RTC */
+#define CDS_RTC_ADDR (0xf8000000)
+#define CDS_RTC_SIZE (8 * 1024)
+
+/* PCI interrupt controller */
+#define PIRQ0A MPC85xx_IRQ_EXT0
+#define PIRQ0B MPC85xx_IRQ_EXT1
+#define PIRQ0C MPC85xx_IRQ_EXT2
+#define PIRQ0D MPC85xx_IRQ_EXT3
+#define PIRQ1A MPC85xx_IRQ_EXT11
+
+#define NR_8259_INTS 16
+#define CPM_IRQ_OFFSET NR_8259_INTS
+
+#define MPC85xx_OPENPIC_IRQ_OFFSET 80
+
+#endif /* __MACH_MPC85XX_CDS_H__ */
diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig
new file mode 100644
index 0000000..3a87863
--- /dev/null
+++ b/arch/powerpc/platforms/86xx/Kconfig
@@ -0,0 +1,36 @@
+menu "Platform Support"
+ depends on PPC_86xx
+
+choice
+ prompt "Machine Type"
+ default MPC8641_HPCN
+
+config MPC8641_HPCN
+ bool "Freescale MPC8641 HPCN"
+ help
+ This option enables support for the MPC8641 HPCN board.
+
+endchoice
+
+
+config MPC8641
+ bool
+ select PPC_INDIRECT_PCI
+ select PPC_UDBG_16550
+ default y if MPC8641_HPCN
+
+config MPIC
+ bool
+ default y
+
+config PPC_INDIRECT_PCI_BE
+ bool
+ depends on PPC_86xx
+ default y
+
+config PPC_STD_MMU
+ bool
+ depends on PPC_86xx
+ default y
+
+endmenu
diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile
new file mode 100644
index 0000000..7be796c
--- /dev/null
+++ b/arch/powerpc/platforms/86xx/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the PowerPC 86xx linux kernel.
+#
+
+
+ifeq ($(CONFIG_PPC_86xx),y)
+obj-$(CONFIG_SMP) += mpc86xx_smp.o
+endif
+obj-$(CONFIG_MPC8641_HPCN) += mpc86xx_hpcn.o
+obj-$(CONFIG_PCI) += pci.o mpc86xx_pcie.o
diff --git a/arch/powerpc/platforms/86xx/mpc8641_hpcn.h b/arch/powerpc/platforms/86xx/mpc8641_hpcn.h
new file mode 100644
index 0000000..5042253
--- /dev/null
+++ b/arch/powerpc/platforms/86xx/mpc8641_hpcn.h
@@ -0,0 +1,54 @@
+/*
+ * MPC8641 HPCN board definitions
+ *
+ * Copyright 2006 Freescale Semiconductor Inc.
+ *
+ * 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.
+ *
+ * Author: Xianghua Xiao <x.xiao@freescale.com>
+ */
+
+#ifndef __MPC8641_HPCN_H__
+#define __MPC8641_HPCN_H__
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+/* PCI interrupt controller */
+#define PIRQA 3
+#define PIRQB 4
+#define PIRQC 5
+#define PIRQD 6
+#define PIRQ7 7
+#define PIRQE 9
+#define PIRQF 10
+#define PIRQG 11
+#define PIRQH 12
+
+/* PCI-Express memory map */
+#define MPC86XX_PCIE_LOWER_IO 0x00000000
+#define MPC86XX_PCIE_UPPER_IO 0x00ffffff
+
+#define MPC86XX_PCIE_LOWER_MEM 0x80000000
+#define MPC86XX_PCIE_UPPER_MEM 0x9fffffff
+
+#define MPC86XX_PCIE_IO_BASE 0xe2000000
+#define MPC86XX_PCIE_MEM_OFFSET 0x00000000
+
+#define MPC86XX_PCIE_IO_SIZE 0x01000000
+
+#define PCIE1_CFG_ADDR_OFFSET (0x8000)
+#define PCIE1_CFG_DATA_OFFSET (0x8004)
+
+#define PCIE2_CFG_ADDR_OFFSET (0x9000)
+#define PCIE2_CFG_DATA_OFFSET (0x9004)
+
+#define MPC86xx_PCIE_OFFSET PCIE1_CFG_ADDR_OFFSET
+#define MPC86xx_PCIE_SIZE (0x1000)
+
+#define MPC86XX_RSTCR_OFFSET (0xe00b0) /* Reset Control Register */
+
+#endif /* __MPC8641_HPCN_H__ */
diff --git a/arch/powerpc/platforms/86xx/mpc86xx.h b/arch/powerpc/platforms/86xx/mpc86xx.h
new file mode 100644
index 0000000..e3c9e4f
--- /dev/null
+++ b/arch/powerpc/platforms/86xx/mpc86xx.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2006 Freescale Semiconductor Inc.
+ *
+ * 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.
+ */
+
+#ifndef __MPC86XX_H__
+#define __MPC86XX_H__
+
+/*
+ * Declaration for the various functions exported by the
+ * mpc86xx_* files. Mostly for use by mpc86xx_setup().
+ */
+
+extern int __init add_bridge(struct device_node *dev);
+
+extern void __init setup_indirect_pcie(struct pci_controller *hose,
+ u32 cfg_addr, u32 cfg_data);
+extern void __init setup_indirect_pcie_nomap(struct pci_controller *hose,
+ void __iomem *cfg_addr,
+ void __iomem *cfg_data);
+
+extern void __init mpc86xx_smp_init(void);
+
+#endif /* __MPC86XX_H__ */
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
new file mode 100644
index 0000000..483c21d
--- /dev/null
+++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
@@ -0,0 +1,326 @@
+/*
+ * MPC86xx HPCN board specific routines
+ *
+ * Recode: ZHANG WEI <wei.zhang@freescale.com>
+ * Initial author: Xianghua Xiao <x.xiao@freescale.com>
+ *
+ * Copyright 2006 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc86xx.h>
+#include <asm/prom.h>
+#include <mm/mmu_decl.h>
+#include <asm/udbg.h>
+#include <asm/i8259.h>
+
+#include <asm/mpic.h>
+
+#include <sysdev/fsl_soc.h>
+
+#include "mpc86xx.h"
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+unsigned long pci_dram_offset = 0;
+#endif
+
+
+/*
+ * Internal interrupts are all Level Sensitive, and Positive Polarity
+ */
+
+static u_char mpc86xx_hpcn_openpic_initsenses[] __initdata = {
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: Reserved */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: MCM */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 2: DDR DRAM */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 3: LBIU */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 4: DMA 0 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 5: DMA 1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 6: DMA 2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 7: DMA 3 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 8: PCIE1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: PCIE2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: Reserved */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: Reserved */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: DUART2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 1 Transmit */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 1 Receive */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: TSEC 3 transmit */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: TSEC 3 receive */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: TSEC 3 error */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 1 Receive/Transmit Error */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 2 Transmit */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 2 Receive */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: TSEC 4 transmit */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: TSEC 4 receive */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: TSEC 4 error */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 2 Receive/Transmit Error */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 27: I2C */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 28: Performance Monitor */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 29: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 30: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 32: SRIO error/write-port unit */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 33: SRIO outbound doorbell */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 34: SRIO inbound doorbell */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 35: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 36: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 37: SRIO outbound message unit 1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 38: SRIO inbound message unit 1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 39: SRIO outbound message unit 2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 40: SRIO inbound message unit 2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 41: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 42: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 43: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 44: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 45: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 46: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 47: Unused */
+ 0x0, /* External 0: */
+ 0x0, /* External 1: */
+ 0x0, /* External 2: */
+ 0x0, /* External 3: */
+ 0x0, /* External 4: */
+ 0x0, /* External 5: */
+ 0x0, /* External 6: */
+ 0x0, /* External 7: */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 8: Pixis FPGA */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* External 9: ULI 8259 INTR Cascade */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 10: Quad ETH PHY */
+ 0x0, /* External 11: */
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+};
+
+
+void __init
+mpc86xx_hpcn_init_irq(void)
+{
+ struct mpic *mpic1;
+ phys_addr_t openpic_paddr;
+
+ /* Determine the Physical Address of the OpenPIC regs */
+ openpic_paddr = get_immrbase() + MPC86xx_OPENPIC_OFFSET;
+
+ /* Alloc mpic structure and per isu has 16 INT entries. */
+ mpic1 = mpic_alloc(openpic_paddr,
+ MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+ 16, MPC86xx_OPENPIC_IRQ_OFFSET, 0, 250,
+ mpc86xx_hpcn_openpic_initsenses,
+ sizeof(mpc86xx_hpcn_openpic_initsenses),
+ " MPIC ");
+ BUG_ON(mpic1 == NULL);
+
+ /* 48 Internal Interrupts */
+ mpic_assign_isu(mpic1, 0, openpic_paddr + 0x10200);
+ mpic_assign_isu(mpic1, 1, openpic_paddr + 0x10400);
+ mpic_assign_isu(mpic1, 2, openpic_paddr + 0x10600);
+
+ /* 16 External interrupts */
+ mpic_assign_isu(mpic1, 3, openpic_paddr + 0x10000);
+
+ mpic_init(mpic1);
+
+#ifdef CONFIG_PCI
+ mpic_setup_cascade(MPC86xx_IRQ_EXT9, i8259_irq_cascade, NULL);
+ i8259_init(0, I8259_OFFSET);
+#endif
+}
+
+
+
+#ifdef CONFIG_PCI
+/*
+ * interrupt routing
+ */
+
+int
+mpc86xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] = {
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {PIRQA, PIRQB, PIRQC, PIRQD}, /* IDSEL 17 -- PCI Slot 1 */
+ {PIRQB, PIRQC, PIRQD, PIRQA}, /* IDSEL 18 -- PCI Slot 2 */
+ {0, 0, 0, 0}, /* IDSEL 19 */
+ {0, 0, 0, 0}, /* IDSEL 20 */
+ {0, 0, 0, 0}, /* IDSEL 21 */
+ {0, 0, 0, 0}, /* IDSEL 22 */
+ {0, 0, 0, 0}, /* IDSEL 23 */
+ {0, 0, 0, 0}, /* IDSEL 24 */
+ {0, 0, 0, 0}, /* IDSEL 25 */
+ {PIRQD, PIRQA, PIRQB, PIRQC}, /* IDSEL 26 -- PCI Bridge*/
+ {PIRQC, 0, 0, 0}, /* IDSEL 27 -- LAN */
+ {PIRQE, PIRQF, PIRQH, PIRQ7}, /* IDSEL 28 -- USB 1.1 */
+ {PIRQE, PIRQF, PIRQG, 0}, /* IDSEL 29 -- Audio & Modem */
+ {PIRQH, 0, 0, 0}, /* IDSEL 30 -- LPC & PMU*/
+ {PIRQD, 0, 0, 0}, /* IDSEL 31 -- ATA */
+ };
+
+ const long min_idsel = 17, max_idsel = 31, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP + I8259_OFFSET;
+}
+
+
+int
+mpc86xx_exclude_device(u_char bus, u_char devfn)
+{
+#if !defined(CONFIG_PCI)
+ if (bus == 0 && PCI_SLOT(devfn) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+#endif
+
+ return PCIBIOS_SUCCESSFUL;
+}
+#endif /* CONFIG_PCI */
+
+
+static void __init
+mpc86xx_hpcn_setup_arch(void)
+{
+ struct device_node *np;
+
+ if (ppc_md.progress)
+ ppc_md.progress("mpc86xx_hpcn_setup_arch()", 0);
+
+ np = of_find_node_by_type(NULL, "cpu");
+ if (np != 0) {
+ unsigned int *fp;
+
+ fp = (int *)get_property(np, "clock-frequency", NULL);
+ if (fp != 0)
+ loops_per_jiffy = *fp / HZ;
+ else
+ loops_per_jiffy = 50000000 / HZ;
+ of_node_put(np);
+ }
+
+#ifdef CONFIG_PCI
+ for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
+ add_bridge(np);
+
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = mpc86xx_map_irq;
+ ppc_md.pci_exclude_device = mpc86xx_exclude_device;
+#endif
+
+ printk("MPC86xx HPCN board from Freescale Semiconductor\n");
+
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_HDA1;
+#endif
+
+#ifdef CONFIG_SMP
+ mpc86xx_smp_init();
+#endif
+}
+
+
+void
+mpc86xx_hpcn_show_cpuinfo(struct seq_file *m)
+{
+ struct device_node *root;
+ uint memsize = total_memory;
+ const char *model = "";
+ uint svid = mfspr(SPRN_SVR);
+
+ seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
+
+ root = of_find_node_by_path("/");
+ if (root)
+ model = get_property(root, "model", NULL);
+ seq_printf(m, "Machine\t\t: %s\n", model);
+ of_node_put(root);
+
+ seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+ seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
+}
+
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init mpc86xx_hpcn_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ if (of_flat_dt_is_compatible(root, "mpc86xx"))
+ return 1; /* Looks good */
+
+ return 0;
+}
+
+
+void
+mpc86xx_restart(char *cmd)
+{
+ void __iomem *rstcr;
+
+ rstcr = ioremap(get_immrbase() + MPC86XX_RSTCR_OFFSET, 0x100);
+
+ local_irq_disable();
+
+ /* Assert reset request to Reset Control Register */
+ out_be32(rstcr, 0x2);
+
+ /* not reached */
+}
+
+
+long __init
+mpc86xx_time_init(void)
+{
+ unsigned int temp;
+
+ /* Set the time base to zero */
+ mtspr(SPRN_TBWL, 0);
+ mtspr(SPRN_TBWU, 0);
+
+ temp = mfspr(SPRN_HID0);
+ temp |= HID0_TBEN;
+ mtspr(SPRN_HID0, temp);
+ asm volatile("isync");
+
+ return 0;
+}
+
+
+define_machine(mpc86xx_hpcn) {
+ .name = "MPC86xx HPCN",
+ .probe = mpc86xx_hpcn_probe,
+ .setup_arch = mpc86xx_hpcn_setup_arch,
+ .init_IRQ = mpc86xx_hpcn_init_irq,
+ .show_cpuinfo = mpc86xx_hpcn_show_cpuinfo,
+ .get_irq = mpic_get_irq,
+ .restart = mpc86xx_restart,
+ .time_init = mpc86xx_time_init,
+ .calibrate_decr = generic_calibrate_decr,
+ .progress = udbg_progress,
+};
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_pcie.c b/arch/powerpc/platforms/86xx/mpc86xx_pcie.c
new file mode 100644
index 0000000..a2f4f73
--- /dev/null
+++ b/arch/powerpc/platforms/86xx/mpc86xx_pcie.c
@@ -0,0 +1,173 @@
+/*
+ * Support for indirect PCI bridges.
+ *
+ * Copyright (C) 1998 Gabriel Paubert.
+ *
+ * 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.
+ *
+ * "Temporary" MPC8548 Errata file -
+ * The standard indirect_pci code should work with future silicon versions.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+
+#include "mpc86xx.h"
+
+#define PCI_CFG_OUT out_be32
+
+/* ERRATA PCI-Ex 14 PCIE Controller timeout */
+#define PCIE_FIX out_be32(hose->cfg_addr+0x4, 0x0400ffff)
+
+
+static int
+indirect_read_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset,
+ int len, u32 *val)
+{
+ struct pci_controller *hose = bus->sysdata;
+ volatile void __iomem *cfg_data;
+ u32 temp;
+
+ if (ppc_md.pci_exclude_device)
+ if (ppc_md.pci_exclude_device(bus->number, devfn))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /* Possible artifact of CDCpp50937 needs further investigation */
+ if (devfn != 0x0 && bus->number == 0xff)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ PCIE_FIX;
+ if (bus->number == 0xff) {
+ PCI_CFG_OUT(hose->cfg_addr,
+ (0x80000000 | ((offset & 0xf00) << 16) |
+ ((bus->number - hose->bus_offset) << 16)
+ | (devfn << 8) | ((offset & 0xfc) )));
+ } else {
+ PCI_CFG_OUT(hose->cfg_addr,
+ (0x80000001 | ((offset & 0xf00) << 16) |
+ ((bus->number - hose->bus_offset) << 16)
+ | (devfn << 8) | ((offset & 0xfc) )));
+ }
+
+ /*
+ * Note: the caller has already checked that offset is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ /* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */
+ cfg_data = hose->cfg_data;
+ PCIE_FIX;
+ temp = in_le32(cfg_data);
+ switch (len) {
+ case 1:
+ *val = (temp >> (((offset & 3))*8)) & 0xff;
+ break;
+ case 2:
+ *val = (temp >> (((offset & 3))*8)) & 0xffff;
+ break;
+ default:
+ *val = temp;
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+indirect_write_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset,
+ int len, u32 val)
+{
+ struct pci_controller *hose = bus->sysdata;
+ volatile void __iomem *cfg_data;
+ u32 temp;
+
+ if (ppc_md.pci_exclude_device)
+ if (ppc_md.pci_exclude_device(bus->number, devfn))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /* Possible artifact of CDCpp50937 needs further investigation */
+ if (devfn != 0x0 && bus->number == 0xff)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ PCIE_FIX;
+ if (bus->number == 0xff) {
+ PCI_CFG_OUT(hose->cfg_addr,
+ (0x80000000 | ((offset & 0xf00) << 16) |
+ ((bus->number - hose->bus_offset) << 16)
+ | (devfn << 8) | ((offset & 0xfc) )));
+ } else {
+ PCI_CFG_OUT(hose->cfg_addr,
+ (0x80000001 | ((offset & 0xf00) << 16) |
+ ((bus->number - hose->bus_offset) << 16)
+ | (devfn << 8) | ((offset & 0xfc) )));
+ }
+
+ /*
+ * Note: the caller has already checked that offset is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ /* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */
+ cfg_data = hose->cfg_data;
+ switch (len) {
+ case 1:
+ PCIE_FIX;
+ temp = in_le32(cfg_data);
+ temp = (temp & ~(0xff << ((offset & 3) * 8))) |
+ (val << ((offset & 3) * 8));
+ PCIE_FIX;
+ out_le32(cfg_data, temp);
+ break;
+ case 2:
+ PCIE_FIX;
+ temp = in_le32(cfg_data);
+ temp = (temp & ~(0xffff << ((offset & 3) * 8)));
+ temp |= (val << ((offset & 3) * 8)) ;
+ PCIE_FIX;
+ out_le32(cfg_data, temp);
+ break;
+ default:
+ PCIE_FIX;
+ out_le32(cfg_data, val);
+ break;
+ }
+ PCIE_FIX;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops indirect_pcie_ops = {
+ indirect_read_config_pcie,
+ indirect_write_config_pcie
+};
+
+void __init
+setup_indirect_pcie_nomap(struct pci_controller* hose, void __iomem * cfg_addr,
+ void __iomem * cfg_data)
+{
+ hose->cfg_addr = cfg_addr;
+ hose->cfg_data = cfg_data;
+ hose->ops = &indirect_pcie_ops;
+}
+
+void __init
+setup_indirect_pcie(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
+{
+ unsigned long base = cfg_addr & PAGE_MASK;
+ void __iomem *mbase, *addr, *data;
+
+ mbase = ioremap(base, PAGE_SIZE);
+ addr = mbase + (cfg_addr & ~PAGE_MASK);
+ if ((cfg_data & PAGE_MASK) != base)
+ mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE);
+ data = mbase + (cfg_data & ~PAGE_MASK);
+ setup_indirect_pcie_nomap(hose, addr, data);
+}
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_smp.c b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
new file mode 100644
index 0000000..944ec4b
--- /dev/null
+++ b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
@@ -0,0 +1,117 @@
+/*
+ * Author: Xianghua Xiao <x.xiao@freescale.com>
+ * Zhang Wei <wei.zhang@freescale.com>
+ *
+ * Copyright 2006 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/pci-bridge.h>
+#include <asm-powerpc/mpic.h>
+#include <asm/mpc86xx.h>
+#include <asm/cacheflush.h>
+
+#include <sysdev/fsl_soc.h>
+
+#include "mpc86xx.h"
+
+extern void __secondary_start_mpc86xx(void);
+extern unsigned long __secondary_hold_acknowledge;
+
+
+static void __init
+smp_86xx_release_core(int nr)
+{
+ void *mcm_vaddr;
+ unsigned long vaddr, pcr;
+
+ if (nr < 0 || nr >= NR_CPUS)
+ return;
+
+ /*
+ * Startup Core #nr.
+ */
+ mcm_vaddr = ioremap(get_immrbase() + MPC86xx_MCM_OFFSET,
+ MPC86xx_MCM_SIZE);
+ vaddr = (unsigned long)mcm_vaddr + MCM_PORT_CONFIG_OFFSET;
+ pcr = in_be32((volatile unsigned *)vaddr);
+ pcr |= 1 << (nr + 24);
+ out_be32((volatile unsigned *)vaddr, pcr);
+}
+
+
+static void __init
+smp_86xx_kick_cpu(int nr)
+{
+ unsigned int save_vector;
+ unsigned long target, flags;
+ int n = 0;
+ volatile unsigned int *vector
+ = (volatile unsigned int *)(KERNELBASE + 0x100);
+
+ if (nr < 0 || nr >= NR_CPUS)
+ return;
+
+ pr_debug("smp_86xx_kick_cpu: kick CPU #%d\n", nr);
+
+ local_irq_save(flags);
+ local_irq_disable();
+
+ /* Save reset vector */
+ save_vector = *vector;
+
+ /* Setup fake reset vector to call __secondary_start_mpc86xx. */
+ target = (unsigned long) __secondary_start_mpc86xx;
+ create_branch((unsigned long)vector, target, BRANCH_SET_LINK);
+
+ /* Kick that CPU */
+ smp_86xx_release_core(nr);
+
+ /* Wait a bit for the CPU to take the exception. */
+ while ((__secondary_hold_acknowledge != nr) && (n++, n < 1000))
+ mdelay(1);
+
+ /* Restore the exception vector */
+ *vector = save_vector;
+ flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
+
+ local_irq_restore(flags);
+
+ pr_debug("wait CPU #%d for %d msecs.\n", nr, n);
+}
+
+
+static void __init
+smp_86xx_setup_cpu(int cpu_nr)
+{
+ mpic_setup_this_cpu();
+}
+
+
+struct smp_ops_t smp_86xx_ops = {
+ .message_pass = smp_mpic_message_pass,
+ .probe = smp_mpic_probe,
+ .kick_cpu = smp_86xx_kick_cpu,
+ .setup_cpu = smp_86xx_setup_cpu,
+ .take_timebase = smp_generic_take_timebase,
+ .give_timebase = smp_generic_give_timebase,
+};
+
+
+void __init
+mpc86xx_smp_init(void)
+{
+ smp_ops = &smp_86xx_ops;
+}
diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c
new file mode 100644
index 0000000..5180df7
--- /dev/null
+++ b/arch/powerpc/platforms/86xx/pci.c
@@ -0,0 +1,325 @@
+/*
+ * MPC86XX pci setup code
+ *
+ * Recode: ZHANG WEI <wei.zhang@freescale.com>
+ * Initial author: Xianghua Xiao <x.xiao@freescale.com>
+ *
+ * Copyright 2006 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/serial.h>
+
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/immap_86xx.h>
+#include <asm/pci-bridge.h>
+#include <sysdev/fsl_soc.h>
+
+#include "mpc86xx.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args)
+#else
+#define DBG(fmt, args...)
+#endif
+
+struct pcie_outbound_window_regs {
+ uint pexotar; /* 0x.0 - PCI Express outbound translation address register */
+ uint pexotear; /* 0x.4 - PCI Express outbound translation extended address register */
+ uint pexowbar; /* 0x.8 - PCI Express outbound window base address register */
+ char res1[4];
+ uint pexowar; /* 0x.10 - PCI Express outbound window attributes register */
+ char res2[12];
+};
+
+struct pcie_inbound_window_regs {
+ uint pexitar; /* 0x.0 - PCI Express inbound translation address register */
+ char res1[4];
+ uint pexiwbar; /* 0x.8 - PCI Express inbound window base address register */
+ uint pexiwbear; /* 0x.c - PCI Express inbound window base extended address register */
+ uint pexiwar; /* 0x.10 - PCI Express inbound window attributes register */
+ char res2[12];
+};
+
+static void __init setup_pcie_atmu(struct pci_controller *hose, struct resource *rsrc)
+{
+ volatile struct ccsr_pex *pcie;
+ volatile struct pcie_outbound_window_regs *pcieow;
+ volatile struct pcie_inbound_window_regs *pcieiw;
+ int i = 0;
+
+ DBG("PCIE memory map start 0x%x, size 0x%x\n", rsrc->start,
+ rsrc->end - rsrc->start + 1);
+ pcie = ioremap(rsrc->start, rsrc->end - rsrc->start + 1);
+
+ /* Disable all windows (except pexowar0 since its ignored) */
+ pcie->pexowar1 = 0;
+ pcie->pexowar2 = 0;
+ pcie->pexowar3 = 0;
+ pcie->pexowar4 = 0;
+ pcie->pexiwar1 = 0;
+ pcie->pexiwar2 = 0;
+ pcie->pexiwar3 = 0;
+
+ pcieow = (struct pcie_outbound_window_regs *)&pcie->pexotar1;
+ pcieiw = (struct pcie_inbound_window_regs *)&pcie->pexitar1;
+
+ /* Setup outbound MEM window */
+ for(i = 0; i < 3; i++)
+ if (hose->mem_resources[i].flags & IORESOURCE_MEM){
+ DBG("PCIE MEM resource start 0x%08x, size 0x%08x.\n",
+ hose->mem_resources[i].start,
+ hose->mem_resources[i].end
+ - hose->mem_resources[i].start + 1);
+ pcieow->pexotar = (hose->mem_resources[i].start) >> 12
+ & 0x000fffff;
+ pcieow->pexotear = 0;
+ pcieow->pexowbar = (hose->mem_resources[i].start) >> 12
+ & 0x000fffff;
+ /* Enable, Mem R/W */
+ pcieow->pexowar = 0x80044000 |
+ (__ilog2(hose->mem_resources[i].end
+ - hose->mem_resources[i].start + 1)
+ - 1);
+ pcieow++;
+ }
+
+ /* Setup outbound IO window */
+ if (hose->io_resource.flags & IORESOURCE_IO){
+ DBG("PCIE IO resource start 0x%08x, size 0x%08x, phy base 0x%08x.\n",
+ hose->io_resource.start,
+ hose->io_resource.end - hose->io_resource.start + 1,
+ hose->io_base_phys);
+ pcieow->pexotar = (hose->io_resource.start) >> 12 & 0x000fffff;
+ pcieow->pexotear = 0;
+ pcieow->pexowbar = (hose->io_base_phys) >> 12 & 0x000fffff;
+ /* Enable, IO R/W */
+ pcieow->pexowar = 0x80088000 | (__ilog2(hose->io_resource.end
+ - hose->io_resource.start + 1) - 1);
+ }
+
+ /* Setup 2G inbound Memory Window @ 0 */
+ pcieiw->pexitar = 0x00000000;
+ pcieiw->pexiwbar = 0x00000000;
+ /* Enable, Prefetch, Local Mem, Snoop R/W, 2G */
+ pcieiw->pexiwar = 0xa0f5501e;
+}
+
+static void __init
+mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size)
+{
+ volatile struct ccsr_pex *pcie;
+ u16 cmd;
+ unsigned int temps;
+
+ DBG("PCIE host controller register offset 0x%08x, size 0x%08x.\n",
+ pcie_offset, pcie_size);
+
+ pcie = ioremap(pcie_offset, pcie_size);
+
+ early_read_config_word(hose, 0, 0, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY
+ | PCI_COMMAND_IO;
+ early_write_config_word(hose, 0, 0, PCI_COMMAND, cmd);
+
+ early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80);
+
+ /* PCIE Bus, Fix the MPC8641D host bridge's location to bus 0xFF. */
+ early_read_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, &temps);
+ temps = (temps & 0xff000000) | (0xff) | (0x0 << 8) | (0xfe << 16);
+ early_write_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, temps);
+}
+
+int __init add_bridge(struct device_node *dev)
+{
+ int len;
+ struct pci_controller *hose;
+ struct resource rsrc;
+ int *bus_range;
+ int has_address = 0;
+ int primary = 0;
+
+ DBG("Adding PCIE host bridge %s\n", dev->full_name);
+
+ /* Fetch host bridge registers address */
+ has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
+
+ /* Get bus range if any */
+ bus_range = (int *) get_property(dev, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int))
+ printk(KERN_WARNING "Can't get bus-range for %s, assume"
+ " bus 0\n", dev->full_name);
+
+ hose = pcibios_alloc_controller();
+ if (!hose)
+ return -ENOMEM;
+ hose->arch_data = dev;
+ hose->set_cfg_type = 1;
+
+ /* last_busno = 0xfe cause by MPC8641 PCIE bug */
+ hose->first_busno = bus_range ? bus_range[0] : 0x0;
+ hose->last_busno = bus_range ? bus_range[1] : 0xfe;
+
+ setup_indirect_pcie(hose, rsrc.start, rsrc.start + 0x4);
+
+ /* Setup the PCIE host controller. */
+ mpc86xx_setup_pcie(hose, rsrc.start, rsrc.end - rsrc.start + 1);
+
+ if ((rsrc.start & 0xfffff) == 0x8000)
+ primary = 1;
+
+ printk(KERN_INFO "Found MPC86xx PCIE host bridge at 0x%08lx. "
+ "Firmware bus number: %d->%d\n",
+ rsrc.start, hose->first_busno, hose->last_busno);
+
+ DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
+ hose, hose->cfg_addr, hose->cfg_data);
+
+ /* Interpret the "ranges" property */
+ /* This also maps the I/O region and sets isa_io/mem_base */
+ pci_process_bridge_OF_ranges(hose, dev, primary);
+
+ /* Setup PEX window registers */
+ setup_pcie_atmu(hose, &rsrc);
+
+ return 0;
+}
+
+static void __devinit quirk_ali1575(struct pci_dev *dev)
+{
+ unsigned short temp;
+
+ /*
+ * ALI1575 interrupts route table setup:
+ *
+ * IRQ pin IRQ#
+ * PIRQA ---- 3
+ * PIRQB ---- 4
+ * PIRQC ---- 5
+ * PIRQD ---- 6
+ * PIRQE ---- 9
+ * PIRQF ---- 10
+ * PIRQG ---- 11
+ * PIRQH ---- 12
+ *
+ * interrupts for PCI slot0 -- PIRQA / PIRQB / PIRQC / PIRQD
+ * PCI slot1 -- PIRQB / PIRQC / PIRQD / PIRQA
+ */
+ pci_write_config_dword(dev, 0x48, 0xb9317542);
+
+ /* USB 1.1 OHCI controller 1, interrupt: PIRQE */
+ pci_write_config_byte(dev, 0x86, 0x0c);
+
+ /* USB 1.1 OHCI controller 2, interrupt: PIRQF */
+ pci_write_config_byte(dev, 0x87, 0x0d);
+
+ /* USB 1.1 OHCI controller 3, interrupt: PIRQH */
+ pci_write_config_byte(dev, 0x88, 0x0f);
+
+ /* USB 2.0 controller, interrupt: PIRQ7 */
+ pci_write_config_byte(dev, 0x74, 0x06);
+
+ /* Audio controller, interrupt: PIRQE */
+ pci_write_config_byte(dev, 0x8a, 0x0c);
+
+ /* Modem controller, interrupt: PIRQF */
+ pci_write_config_byte(dev, 0x8b, 0x0d);
+
+ /* HD audio controller, interrupt: PIRQG */
+ pci_write_config_byte(dev, 0x8c, 0x0e);
+
+ /* Serial ATA interrupt: PIRQD */
+ pci_write_config_byte(dev, 0x8d, 0x0b);
+
+ /* SMB interrupt: PIRQH */
+ pci_write_config_byte(dev, 0x8e, 0x0f);
+
+ /* PMU ACPI SCI interrupt: PIRQH */
+ pci_write_config_byte(dev, 0x8f, 0x0f);
+
+ /* Primary PATA IDE IRQ: 14
+ * Secondary PATA IDE IRQ: 15
+ */
+ pci_write_config_byte(dev, 0x44, 0x3d);
+ pci_write_config_byte(dev, 0x75, 0x0f);
+
+ /* Set IRQ14 and IRQ15 to legacy IRQs */
+ pci_read_config_word(dev, 0x46, &temp);
+ temp |= 0xc000;
+ pci_write_config_word(dev, 0x46, temp);
+
+ /* Set i8259 interrupt trigger
+ * IRQ 3: Level
+ * IRQ 4: Level
+ * IRQ 5: Level
+ * IRQ 6: Level
+ * IRQ 7: Level
+ * IRQ 9: Level
+ * IRQ 10: Level
+ * IRQ 11: Level
+ * IRQ 12: Level
+ * IRQ 14: Edge
+ * IRQ 15: Edge
+ */
+ outb(0xfa, 0x4d0);
+ outb(0x1e, 0x4d1);
+}
+
+static void __devinit quirk_uli5288(struct pci_dev *dev)
+{
+ unsigned char c;
+
+ pci_read_config_byte(dev,0x83,&c);
+ c |= 0x80;
+ pci_write_config_byte(dev, 0x83, c);
+
+ pci_write_config_byte(dev, 0x09, 0x01);
+ pci_write_config_byte(dev, 0x0a, 0x06);
+
+ pci_read_config_byte(dev,0x83,&c);
+ c &= 0x7f;
+ pci_write_config_byte(dev, 0x83, c);
+
+ pci_read_config_byte(dev,0x84,&c);
+ c |= 0x01;
+ pci_write_config_byte(dev, 0x84, c);
+}
+
+static void __devinit quirk_uli5229(struct pci_dev *dev)
+{
+ unsigned short temp;
+ pci_write_config_word(dev, 0x04, 0x0405);
+ pci_read_config_word(dev, 0x4a, &temp);
+ temp |= 0x1000;
+ pci_write_config_word(dev, 0x4a, temp);
+}
+
+static void __devinit early_uli5249(struct pci_dev *dev)
+{
+ unsigned char temp;
+ pci_write_config_word(dev, 0x04, 0x0007);
+ pci_read_config_byte(dev, 0x7c, &temp);
+ pci_write_config_byte(dev, 0x7c, 0x80);
+ pci_write_config_byte(dev, 0x09, 0x01);
+ pci_write_config_byte(dev, 0x7c, temp);
+ dev->class |= 0x1;
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x1575, quirk_ali1575);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5288, quirk_uli5288);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5229, quirk_uli5229);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AL, 0x5249, early_uli5249);
diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile
index c4f6b0d..2928636 100644
--- a/arch/powerpc/platforms/Makefile
+++ b/arch/powerpc/platforms/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_PPC_CHRP) += chrp/
obj-$(CONFIG_4xx) += 4xx/
obj-$(CONFIG_PPC_83xx) += 83xx/
obj-$(CONFIG_PPC_85xx) += 85xx/
+obj-$(CONFIG_PPC_86xx) += 86xx/
obj-$(CONFIG_PPC_PSERIES) += pseries/
obj-$(CONFIG_PPC_ISERIES) += iseries/
obj-$(CONFIG_PPC_MAPLE) += maple/
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index 6a02d51..352bbba 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -5,15 +5,24 @@ config SPU_FS
tristate "SPU file system"
default m
depends on PPC_CELL
+ select SPU_BASE
help
The SPU file system is used to access Synergistic Processing
Units on machines implementing the Broadband Processor
Architecture.
+config SPU_BASE
+ bool
+ default n
+
config SPUFS_MMAP
bool
depends on SPU_FS && SPARSEMEM
select MEMORY_HOTPLUG
default y
+config CBE_RAS
+ bool "RAS features for bare metal Cell BE"
+ default y
+
endmenu
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index e570bad..c89cdd6 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -1,16 +1,15 @@
-obj-y += interrupt.o iommu.o setup.o spider-pic.o
-obj-y += pervasive.o
+obj-$(CONFIG_PPC_CELL_NATIVE) += interrupt.o iommu.o setup.o \
+ cbe_regs.o spider-pic.o pervasive.o
+obj-$(CONFIG_CBE_RAS) += ras.o
-obj-$(CONFIG_SMP) += smp.o
-obj-$(CONFIG_SPU_FS) += spu-base.o spufs/
-
-spu-base-y += spu_base.o spu_priv1.o
+ifeq ($(CONFIG_SMP),y)
+obj-$(CONFIG_PPC_CELL_NATIVE) += smp.o
+endif
# needed only when building loadable spufs.ko
-spufs-modular-$(CONFIG_SPU_FS) += spu_syscalls.o
-obj-y += $(spufs-modular-m)
-
-# always needed in kernel
-spufs-builtin-$(CONFIG_SPU_FS) += spu_callbacks.o
-obj-y += $(spufs-builtin-y) $(spufs-builtin-m)
+spufs-modular-$(CONFIG_SPU_FS) += spu_syscalls.o
+spu-priv1-$(CONFIG_PPC_CELL_NATIVE) += spu_priv1_mmio.o
+obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \
+ $(spufs-modular-m) \
+ $(spu-priv1-y) spufs/
diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c
new file mode 100644
index 0000000..ce696c1
--- /dev/null
+++ b/arch/powerpc/platforms/cell/cbe_regs.c
@@ -0,0 +1,128 @@
+/*
+ * cbe_regs.c
+ *
+ * Accessor routines for the various MMIO register blocks of the CBE
+ *
+ * (c) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
+ */
+
+
+#include <linux/config.h>
+#include <linux/percpu.h>
+#include <linux/types.h>
+
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/prom.h>
+#include <asm/ptrace.h>
+
+#include "cbe_regs.h"
+
+#define MAX_CBE 2
+
+/*
+ * Current implementation uses "cpu" nodes. We build our own mapping
+ * array of cpu numbers to cpu nodes locally for now to allow interrupt
+ * time code to have a fast path rather than call of_get_cpu_node(). If
+ * we implement cpu hotplug, we'll have to install an appropriate norifier
+ * in order to release references to the cpu going away
+ */
+static struct cbe_regs_map
+{
+ struct device_node *cpu_node;
+ struct cbe_pmd_regs __iomem *pmd_regs;
+ struct cbe_iic_regs __iomem *iic_regs;
+} cbe_regs_maps[MAX_CBE];
+static int cbe_regs_map_count;
+
+static struct cbe_thread_map
+{
+ struct device_node *cpu_node;
+ struct cbe_regs_map *regs;
+} cbe_thread_map[NR_CPUS];
+
+static struct cbe_regs_map *cbe_find_map(struct device_node *np)
+{
+ int i;
+
+ for (i = 0; i < cbe_regs_map_count; i++)
+ if (cbe_regs_maps[i].cpu_node == np)
+ return &cbe_regs_maps[i];
+ return NULL;
+}
+
+struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np)
+{
+ struct cbe_regs_map *map = cbe_find_map(np);
+ if (map == NULL)
+ return NULL;
+ return map->pmd_regs;
+}
+
+struct cbe_pmd_regs __iomem *cbe_get_cpu_pmd_regs(int cpu)
+{
+ struct cbe_regs_map *map = cbe_thread_map[cpu].regs;
+ if (map == NULL)
+ return NULL;
+ return map->pmd_regs;
+}
+
+
+struct cbe_iic_regs __iomem *cbe_get_iic_regs(struct device_node *np)
+{
+ struct cbe_regs_map *map = cbe_find_map(np);
+ if (map == NULL)
+ return NULL;
+ return map->iic_regs;
+}
+struct cbe_iic_regs __iomem *cbe_get_cpu_iic_regs(int cpu)
+{
+ struct cbe_regs_map *map = cbe_thread_map[cpu].regs;
+ if (map == NULL)
+ return NULL;
+ return map->iic_regs;
+}
+
+void __init cbe_regs_init(void)
+{
+ int i;
+ struct device_node *cpu;
+
+ /* Build local fast map of CPUs */
+ for_each_possible_cpu(i)
+ cbe_thread_map[i].cpu_node = of_get_cpu_node(i, NULL);
+
+ /* Find maps for each device tree CPU */
+ for_each_node_by_type(cpu, "cpu") {
+ struct cbe_regs_map *map = &cbe_regs_maps[cbe_regs_map_count++];
+
+ /* That hack must die die die ! */
+ struct address_prop {
+ unsigned long address;
+ unsigned int len;
+ } __attribute__((packed)) *prop;
+
+
+ if (cbe_regs_map_count > MAX_CBE) {
+ printk(KERN_ERR "cbe_regs: More BE chips than supported"
+ "!\n");
+ cbe_regs_map_count--;
+ return;
+ }
+ map->cpu_node = cpu;
+ for_each_possible_cpu(i)
+ if (cbe_thread_map[i].cpu_node == cpu)
+ cbe_thread_map[i].regs = map;
+
+ prop = (struct address_prop *)get_property(cpu, "pervasive",
+ NULL);
+ if (prop != NULL)
+ map->pmd_regs = ioremap(prop->address, prop->len);
+
+ prop = (struct address_prop *)get_property(cpu, "iic",
+ NULL);
+ if (prop != NULL)
+ map->iic_regs = ioremap(prop->address, prop->len);
+ }
+}
+
diff --git a/arch/powerpc/platforms/cell/cbe_regs.h b/arch/powerpc/platforms/cell/cbe_regs.h
new file mode 100644
index 0000000..e76e4a6
--- /dev/null
+++ b/arch/powerpc/platforms/cell/cbe_regs.h
@@ -0,0 +1,129 @@
+/*
+ * cbe_regs.h
+ *
+ * This file is intended to hold the various register definitions for CBE
+ * on-chip system devices (memory controller, IO controller, etc...)
+ *
+ * (c) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
+ */
+
+#ifndef CBE_REGS_H
+#define CBE_REGS_H
+
+/*
+ *
+ * Some HID register definitions
+ *
+ */
+
+/* CBE specific HID0 bits */
+#define HID0_CBE_THERM_WAKEUP 0x0000020000000000ul
+#define HID0_CBE_SYSERR_WAKEUP 0x0000008000000000ul
+#define HID0_CBE_THERM_INT_EN 0x0000000400000000ul
+#define HID0_CBE_SYSERR_INT_EN 0x0000000200000000ul
+
+
+/*
+ *
+ * Pervasive unit register definitions
+ *
+ */
+
+struct cbe_pmd_regs {
+ u8 pad_0x0000_0x0800[0x0800 - 0x0000]; /* 0x0000 */
+
+ /* Thermal Sensor Registers */
+ u64 ts_ctsr1; /* 0x0800 */
+ u64 ts_ctsr2; /* 0x0808 */
+ u64 ts_mtsr1; /* 0x0810 */
+ u64 ts_mtsr2; /* 0x0818 */
+ u64 ts_itr1; /* 0x0820 */
+ u64 ts_itr2; /* 0x0828 */
+ u64 ts_gitr; /* 0x0830 */
+ u64 ts_isr; /* 0x0838 */
+ u64 ts_imr; /* 0x0840 */
+ u64 tm_cr1; /* 0x0848 */
+ u64 tm_cr2; /* 0x0850 */
+ u64 tm_simr; /* 0x0858 */
+ u64 tm_tpr; /* 0x0860 */
+ u64 tm_str1; /* 0x0868 */
+ u64 tm_str2; /* 0x0870 */
+ u64 tm_tsr; /* 0x0878 */
+
+ /* Power Management */
+ u64 pm_control; /* 0x0880 */
+#define CBE_PMD_PAUSE_ZERO_CONTROL 0x10000
+ u64 pm_status; /* 0x0888 */
+
+ /* Time Base Register */
+ u64 tbr; /* 0x0890 */
+
+ u8 pad_0x0898_0x0c00 [0x0c00 - 0x0898]; /* 0x0898 */
+
+ /* Fault Isolation Registers */
+ u64 checkstop_fir; /* 0x0c00 */
+ u64 recoverable_fir;
+ u64 spec_att_mchk_fir;
+ u64 fir_mode_reg;
+ u64 fir_enable_mask;
+
+ u8 pad_0x0c28_0x1000 [0x1000 - 0x0c28]; /* 0x0c28 */
+};
+
+extern struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np);
+extern struct cbe_pmd_regs __iomem *cbe_get_cpu_pmd_regs(int cpu);
+
+/*
+ *
+ * IIC unit register definitions
+ *
+ */
+
+struct cbe_iic_pending_bits {
+ u32 data;
+ u8 flags;
+ u8 class;
+ u8 source;
+ u8 prio;
+};
+
+#define CBE_IIC_IRQ_VALID 0x80
+#define CBE_IIC_IRQ_IPI 0x40
+
+struct cbe_iic_thread_regs {
+ struct cbe_iic_pending_bits pending;
+ struct cbe_iic_pending_bits pending_destr;
+ u64 generate;
+ u64 prio;
+};
+
+struct cbe_iic_regs {
+ u8 pad_0x0000_0x0400[0x0400 - 0x0000]; /* 0x0000 */
+
+ /* IIC interrupt registers */
+ struct cbe_iic_thread_regs thread[2]; /* 0x0400 */
+ u64 iic_ir; /* 0x0440 */
+ u64 iic_is; /* 0x0448 */
+
+ u8 pad_0x0450_0x0500[0x0500 - 0x0450]; /* 0x0450 */
+
+ /* IOC FIR */
+ u64 ioc_fir_reset; /* 0x0500 */
+ u64 ioc_fir_set;
+ u64 ioc_checkstop_enable;
+ u64 ioc_fir_error_mask;
+ u64 ioc_syserr_enable;
+ u64 ioc_fir;
+
+ u8 pad_0x0530_0x1000[0x1000 - 0x0530]; /* 0x0530 */
+};
+
+extern struct cbe_iic_regs __iomem *cbe_get_iic_regs(struct device_node *np);
+extern struct cbe_iic_regs __iomem *cbe_get_cpu_iic_regs(int cpu);
+
+
+/* Init this module early */
+extern void cbe_regs_init(void);
+
+
+#endif /* CBE_REGS_H */
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 978be1c..1bbf822 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -33,29 +33,10 @@
#include <asm/ptrace.h>
#include "interrupt.h"
-
-struct iic_pending_bits {
- u32 data;
- u8 flags;
- u8 class;
- u8 source;
- u8 prio;
-};
-
-enum iic_pending_flags {
- IIC_VALID = 0x80,
- IIC_IPI = 0x40,
-};
-
-struct iic_regs {
- struct iic_pending_bits pending;
- struct iic_pending_bits pending_destr;
- u64 generate;
- u64 prio;
-};
+#include "cbe_regs.h"
struct iic {
- struct iic_regs __iomem *regs;
+ struct cbe_iic_thread_regs __iomem *regs;
u8 target_id;
};
@@ -115,7 +96,7 @@ static struct hw_interrupt_type iic_pic = {
.end = iic_end,
};
-static int iic_external_get_irq(struct iic_pending_bits pending)
+static int iic_external_get_irq(struct cbe_iic_pending_bits pending)
{
int irq;
unsigned char node, unit;
@@ -136,8 +117,7 @@ static int iic_external_get_irq(struct iic_pending_bits pending)
* One of these units can be connected
* to an external interrupt controller.
*/
- if (pending.prio > 0x3f ||
- pending.class != 2)
+ if (pending.class != 2)
break;
irq = IIC_EXT_OFFSET
+ spider_get_irq(node)
@@ -168,15 +148,15 @@ int iic_get_irq(struct pt_regs *regs)
{
struct iic *iic;
int irq;
- struct iic_pending_bits pending;
+ struct cbe_iic_pending_bits pending;
iic = &__get_cpu_var(iic);
*(unsigned long *) &pending =
in_be64((unsigned long __iomem *) &iic->regs->pending_destr);
irq = -1;
- if (pending.flags & IIC_VALID) {
- if (pending.flags & IIC_IPI) {
+ if (pending.flags & CBE_IIC_IRQ_VALID) {
+ if (pending.flags & CBE_IIC_IRQ_IPI) {
irq = IIC_IPI_OFFSET + (pending.prio >> 4);
/*
if (irq > 0x80)
@@ -200,7 +180,7 @@ static int setup_iic_hardcoded(void)
unsigned long regs;
struct iic *iic;
- for_each_cpu(cpu) {
+ for_each_possible_cpu(cpu) {
iic = &per_cpu(iic, cpu);
nodeid = cpu/2;
@@ -226,7 +206,7 @@ static int setup_iic_hardcoded(void)
regs += 0x20;
printk(KERN_INFO "IIC for CPU %d at %lx\n", cpu, regs);
- iic->regs = ioremap(regs, sizeof(struct iic_regs));
+ iic->regs = ioremap(regs, sizeof(struct cbe_iic_thread_regs));
iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe);
}
@@ -267,12 +247,12 @@ static int setup_iic(void)
}
iic = &per_cpu(iic, np[0]);
- iic->regs = ioremap(regs[0], sizeof(struct iic_regs));
+ iic->regs = ioremap(regs[0], sizeof(struct cbe_iic_thread_regs));
iic->target_id = ((np[0] & 2) << 3) + ((np[0] & 1) ? 0xf : 0xe);
printk("IIC for CPU %d at %lx mapped to %p\n", np[0], regs[0], iic->regs);
iic = &per_cpu(iic, np[1]);
- iic->regs = ioremap(regs[2], sizeof(struct iic_regs));
+ iic->regs = ioremap(regs[2], sizeof(struct cbe_iic_thread_regs));
iic->target_id = ((np[1] & 2) << 3) + ((np[1] & 1) ? 0xf : 0xe);
printk("IIC for CPU %d at %lx mapped to %p\n", np[1], regs[2], iic->regs);
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index a49ceb7..a35004e 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -473,6 +473,16 @@ static int cell_dma_supported(struct device *dev, u64 mask)
return mask < 0x100000000ull;
}
+static struct dma_mapping_ops cell_iommu_ops = {
+ .alloc_coherent = cell_alloc_coherent,
+ .free_coherent = cell_free_coherent,
+ .map_single = cell_map_single,
+ .unmap_single = cell_unmap_single,
+ .map_sg = cell_map_sg,
+ .unmap_sg = cell_unmap_sg,
+ .dma_supported = cell_dma_supported,
+};
+
void cell_init_iommu(void)
{
int setup_bus = 0;
@@ -498,11 +508,5 @@ void cell_init_iommu(void)
}
}
- pci_dma_ops.alloc_coherent = cell_alloc_coherent;
- pci_dma_ops.free_coherent = cell_free_coherent;
- pci_dma_ops.map_single = cell_map_single;
- pci_dma_ops.unmap_single = cell_unmap_single;
- pci_dma_ops.map_sg = cell_map_sg;
- pci_dma_ops.unmap_sg = cell_unmap_sg;
- pci_dma_ops.dma_supported = cell_dma_supported;
+ pci_dma_ops = cell_iommu_ops;
}
diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c
index 7eed8c6..695ac4e 100644
--- a/arch/powerpc/platforms/cell/pervasive.c
+++ b/arch/powerpc/platforms/cell/pervasive.c
@@ -37,36 +37,28 @@
#include <asm/reg.h>
#include "pervasive.h"
+#include "cbe_regs.h"
static DEFINE_SPINLOCK(cbe_pervasive_lock);
-struct cbe_pervasive {
- struct pmd_regs __iomem *regs;
- unsigned int thread;
-};
-
-/* can't use per_cpu from setup_arch */
-static struct cbe_pervasive cbe_pervasive[NR_CPUS];
static void __init cbe_enable_pause_zero(void)
{
unsigned long thread_switch_control;
unsigned long temp_register;
- struct cbe_pervasive *p;
- int thread;
+ struct cbe_pmd_regs __iomem *pregs;
spin_lock_irq(&cbe_pervasive_lock);
- p = &cbe_pervasive[smp_processor_id()];
-
- if (!cbe_pervasive->regs)
+ pregs = cbe_get_cpu_pmd_regs(smp_processor_id());
+ if (pregs == NULL)
goto out;
pr_debug("Power Management: CPU %d\n", smp_processor_id());
/* Enable Pause(0) control bit */
- temp_register = in_be64(&p->regs->pm_control);
+ temp_register = in_be64(&pregs->pm_control);
- out_be64(&p->regs->pm_control,
- temp_register|PMD_PAUSE_ZERO_CONTROL);
+ out_be64(&pregs->pm_control,
+ temp_register | CBE_PMD_PAUSE_ZERO_CONTROL);
/* Enable DEC and EE interrupt request */
thread_switch_control = mfspr(SPRN_TSC_CELL);
@@ -75,25 +67,16 @@ static void __init cbe_enable_pause_zero(void)
switch ((mfspr(SPRN_CTRLF) & CTRL_CT)) {
case CTRL_CT0:
thread_switch_control |= TSC_CELL_DEC_ENABLE_0;
- thread = 0;
break;
case CTRL_CT1:
thread_switch_control |= TSC_CELL_DEC_ENABLE_1;
- thread = 1;
break;
default:
printk(KERN_WARNING "%s: unknown configuration\n",
__FUNCTION__);
- thread = -1;
break;
}
- if (p->thread != thread)
- printk(KERN_WARNING "%s: device tree inconsistant, "
- "cpu %i: %d/%d\n", __FUNCTION__,
- smp_processor_id(),
- p->thread, thread);
-
mtspr(SPRN_TSC_CELL, thread_switch_control);
out:
@@ -104,6 +87,11 @@ static void cbe_idle(void)
{
unsigned long ctrl;
+ /* Why do we do that on every idle ? Couldn't that be done once for
+ * all or do we lose the state some way ? Also, the pm_control
+ * register setting, that can't be set once at boot ? We really want
+ * to move that away in order to implement a simple powersave
+ */
cbe_enable_pause_zero();
while (1) {
@@ -152,8 +140,15 @@ static int cbe_system_reset_exception(struct pt_regs *regs)
timer_interrupt(regs);
break;
case SRR1_WAKEMT:
- /* no action required */
break;
+#ifdef CONFIG_CBE_RAS
+ case SRR1_WAKESYSERR:
+ cbe_system_error_exception(regs);
+ break;
+ case SRR1_WAKETHERM:
+ cbe_thermal_exception(regs);
+ break;
+#endif /* CONFIG_CBE_RAS */
default:
/* do system reset */
return 0;
@@ -162,68 +157,11 @@ static int cbe_system_reset_exception(struct pt_regs *regs)
return 1;
}
-static int __init cbe_find_pmd_mmio(int cpu, struct cbe_pervasive *p)
-{
- struct device_node *node;
- unsigned int *int_servers;
- char *addr;
- unsigned long real_address;
- unsigned int size;
-
- struct pmd_regs __iomem *pmd_mmio_area;
- int hardid, thread;
- int proplen;
-
- pmd_mmio_area = NULL;
- hardid = get_hard_smp_processor_id(cpu);
- for (node = NULL; (node = of_find_node_by_type(node, "cpu"));) {
- int_servers = (void *) get_property(node,
- "ibm,ppc-interrupt-server#s", &proplen);
- if (!int_servers) {
- printk(KERN_WARNING "%s misses "
- "ibm,ppc-interrupt-server#s property",
- node->full_name);
- continue;
- }
- for (thread = 0; thread < proplen / sizeof (int); thread++) {
- if (hardid == int_servers[thread]) {
- addr = get_property(node, "pervasive", NULL);
- goto found;
- }
- }
- }
-
- printk(KERN_WARNING "%s: CPU %d not found\n", __FUNCTION__, cpu);
- return -EINVAL;
-
-found:
- real_address = *(unsigned long*) addr;
- addr += sizeof (unsigned long);
- size = *(unsigned int*) addr;
-
- pr_debug("pervasive area for CPU %d at %lx, size %x\n",
- cpu, real_address, size);
- p->regs = ioremap(real_address, size);
- p->thread = thread;
- return 0;
-}
-
-void __init cell_pervasive_init(void)
+void __init cbe_pervasive_init(void)
{
- struct cbe_pervasive *p;
- int cpu;
- int ret;
-
if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO))
return;
- for_each_possible_cpu(cpu) {
- p = &cbe_pervasive[cpu];
- ret = cbe_find_pmd_mmio(cpu, p);
- if (ret)
- return;
- }
-
ppc_md.idle_loop = cbe_idle;
ppc_md.system_reset_exception = cbe_system_reset_exception;
}
diff --git a/arch/powerpc/platforms/cell/pervasive.h b/arch/powerpc/platforms/cell/pervasive.h
index da1fb85..7b50947 100644
--- a/arch/powerpc/platforms/cell/pervasive.h
+++ b/arch/powerpc/platforms/cell/pervasive.h
@@ -25,38 +25,9 @@
#ifndef PERVASIVE_H
#define PERVASIVE_H
-struct pmd_regs {
- u8 pad_0x0000_0x0800[0x0800 - 0x0000]; /* 0x0000 */
-
- /* Thermal Sensor Registers */
- u64 ts_ctsr1; /* 0x0800 */
- u64 ts_ctsr2; /* 0x0808 */
- u64 ts_mtsr1; /* 0x0810 */
- u64 ts_mtsr2; /* 0x0818 */
- u64 ts_itr1; /* 0x0820 */
- u64 ts_itr2; /* 0x0828 */
- u64 ts_gitr; /* 0x0830 */
- u64 ts_isr; /* 0x0838 */
- u64 ts_imr; /* 0x0840 */
- u64 tm_cr1; /* 0x0848 */
- u64 tm_cr2; /* 0x0850 */
- u64 tm_simr; /* 0x0858 */
- u64 tm_tpr; /* 0x0860 */
- u64 tm_str1; /* 0x0868 */
- u64 tm_str2; /* 0x0870 */
- u64 tm_tsr; /* 0x0878 */
-
- /* Power Management */
- u64 pm_control; /* 0x0880 */
-#define PMD_PAUSE_ZERO_CONTROL 0x10000
- u64 pm_status; /* 0x0888 */
-
- /* Time Base Register */
- u64 tbr; /* 0x0890 */
-
- u8 pad_0x0898_0x1000 [0x1000 - 0x0898]; /* 0x0898 */
-};
-
-void __init cell_pervasive_init(void);
+extern void cbe_pervasive_init(void);
+extern void cbe_system_error_exception(struct pt_regs *regs);
+extern void cbe_maintenance_exception(struct pt_regs *regs);
+extern void cbe_thermal_exception(struct pt_regs *regs);
#endif
diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c
new file mode 100644
index 0000000..033ad6e
--- /dev/null
+++ b/arch/powerpc/platforms/cell/ras.c
@@ -0,0 +1,112 @@
+#define DEBUG
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+
+#include <asm/reg.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+
+#include "ras.h"
+#include "cbe_regs.h"
+
+
+static void dump_fir(int cpu)
+{
+ struct cbe_pmd_regs __iomem *pregs = cbe_get_cpu_pmd_regs(cpu);
+ struct cbe_iic_regs __iomem *iregs = cbe_get_cpu_iic_regs(cpu);
+
+ if (pregs == NULL)
+ return;
+
+ /* Todo: do some nicer parsing of bits and based on them go down
+ * to other sub-units FIRs and not only IIC
+ */
+ printk(KERN_ERR "Global Checkstop FIR : 0x%016lx\n",
+ in_be64(&pregs->checkstop_fir));
+ printk(KERN_ERR "Global Recoverable FIR : 0x%016lx\n",
+ in_be64(&pregs->checkstop_fir));
+ printk(KERN_ERR "Global MachineCheck FIR : 0x%016lx\n",
+ in_be64(&pregs->spec_att_mchk_fir));
+
+ if (iregs == NULL)
+ return;
+ printk(KERN_ERR "IOC FIR : 0x%016lx\n",
+ in_be64(&iregs->ioc_fir));
+
+}
+
+void cbe_system_error_exception(struct pt_regs *regs)
+{
+ int cpu = smp_processor_id();
+
+ printk(KERN_ERR "System Error Interrupt on CPU %d !\n", cpu);
+ dump_fir(cpu);
+ dump_stack();
+}
+
+void cbe_maintenance_exception(struct pt_regs *regs)
+{
+ int cpu = smp_processor_id();
+
+ /*
+ * Nothing implemented for the maintenance interrupt at this point
+ */
+
+ printk(KERN_ERR "Unhandled Maintenance interrupt on CPU %d !\n", cpu);
+ dump_stack();
+}
+
+void cbe_thermal_exception(struct pt_regs *regs)
+{
+ int cpu = smp_processor_id();
+
+ /*
+ * Nothing implemented for the thermal interrupt at this point
+ */
+
+ printk(KERN_ERR "Unhandled Thermal interrupt on CPU %d !\n", cpu);
+ dump_stack();
+}
+
+static int cbe_machine_check_handler(struct pt_regs *regs)
+{
+ int cpu = smp_processor_id();
+
+ printk(KERN_ERR "Machine Check Interrupt on CPU %d !\n", cpu);
+ dump_fir(cpu);
+
+ /* No recovery from this code now, lets continue */
+ return 0;
+}
+
+void __init cbe_ras_init(void)
+{
+ unsigned long hid0;
+
+ /*
+ * Enable System Error & thermal interrupts and wakeup conditions
+ */
+
+ hid0 = mfspr(SPRN_HID0);
+ hid0 |= HID0_CBE_THERM_INT_EN | HID0_CBE_THERM_WAKEUP |
+ HID0_CBE_SYSERR_INT_EN | HID0_CBE_SYSERR_WAKEUP;
+ mtspr(SPRN_HID0, hid0);
+ mb();
+
+ /*
+ * Install machine check handler. Leave setting of precise mode to
+ * what the firmware did for now
+ */
+ ppc_md.machine_check_exception = cbe_machine_check_handler;
+ mb();
+
+ /*
+ * For now, we assume that IOC_FIR is already set to forward some
+ * error conditions to the System Error handler. If that is not true
+ * then it will have to be fixed up here.
+ */
+}
diff --git a/arch/powerpc/platforms/cell/ras.h b/arch/powerpc/platforms/cell/ras.h
new file mode 100644
index 0000000..eb7ee54
--- /dev/null
+++ b/arch/powerpc/platforms/cell/ras.h
@@ -0,0 +1,9 @@
+#ifndef RAS_H
+#define RAS_H
+
+extern void cbe_system_error_exception(struct pt_regs *regs);
+extern void cbe_maintenance_exception(struct pt_regs *regs);
+extern void cbe_thermal_exception(struct pt_regs *regs);
+extern void cbe_ras_init(void);
+
+#endif /* RAS_H */
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index fd3e560..3d1831d 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -49,10 +49,13 @@
#include <asm/ppc-pci.h>
#include <asm/irq.h>
#include <asm/spu.h>
+#include <asm/spu_priv1.h>
#include "interrupt.h"
#include "iommu.h"
+#include "cbe_regs.h"
#include "pervasive.h"
+#include "ras.h"
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
@@ -81,6 +84,15 @@ static void __init cell_setup_arch(void)
{
ppc_md.init_IRQ = iic_init_IRQ;
ppc_md.get_irq = iic_get_irq;
+#ifdef CONFIG_SPU_BASE
+ spu_priv1_ops = &spu_priv1_mmio_ops;
+#endif
+
+ cbe_regs_init();
+
+#ifdef CONFIG_CBE_RAS
+ cbe_ras_init();
+#endif
#ifdef CONFIG_SMP
smp_init_cell();
@@ -98,7 +110,7 @@ static void __init cell_setup_arch(void)
init_pci_config_tokens();
find_and_init_phbs();
spider_init_IRQ();
- cell_pervasive_init();
+ cbe_pervasive_init();
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
#endif
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index ad141fe..db82f50 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -34,10 +34,15 @@
#include <asm/prom.h>
#include <linux/mutex.h>
#include <asm/spu.h>
+#include <asm/spu_priv1.h>
#include <asm/mmu_context.h>
#include "interrupt.h"
+const struct spu_priv1_ops *spu_priv1_ops;
+
+EXPORT_SYMBOL_GPL(spu_priv1_ops);
+
static int __spu_trap_invalid_dma(struct spu *spu)
{
pr_debug("%s\n", __FUNCTION__);
@@ -71,7 +76,7 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
{
struct spu_priv2 __iomem *priv2 = spu->priv2;
struct mm_struct *mm = spu->mm;
- u64 esid, vsid;
+ u64 esid, vsid, llp;
pr_debug("%s\n", __FUNCTION__);
@@ -91,9 +96,14 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
}
esid = (ea & ESID_MASK) | SLB_ESID_V;
- vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) | SLB_VSID_USER;
+#ifdef CONFIG_HUGETLB_PAGE
if (in_hugepage_area(mm->context, ea))
- vsid |= SLB_VSID_L;
+ llp = mmu_psize_defs[mmu_huge_psize].sllp;
+ else
+#endif
+ llp = mmu_psize_defs[mmu_virtual_psize].sllp;
+ vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) |
+ SLB_VSID_USER | llp;
out_be64(&priv2->slb_index_W, spu->slb_replace);
out_be64(&priv2->slb_vsid_RW, vsid);
@@ -130,57 +140,7 @@ static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr)
spu->dar = ea;
spu->dsisr = dsisr;
mb();
- if (spu->stop_callback)
- spu->stop_callback(spu);
- return 0;
-}
-
-static int __spu_trap_mailbox(struct spu *spu)
-{
- if (spu->ibox_callback)
- spu->ibox_callback(spu);
-
- /* atomically disable SPU mailbox interrupts */
- spin_lock(&spu->register_lock);
- spu_int_mask_and(spu, 2, ~0x1);
- spin_unlock(&spu->register_lock);
- return 0;
-}
-
-static int __spu_trap_stop(struct spu *spu)
-{
- pr_debug("%s\n", __FUNCTION__);
- spu->stop_code = in_be32(&spu->problem->spu_status_R);
- if (spu->stop_callback)
- spu->stop_callback(spu);
- return 0;
-}
-
-static int __spu_trap_halt(struct spu *spu)
-{
- pr_debug("%s\n", __FUNCTION__);
- spu->stop_code = in_be32(&spu->problem->spu_status_R);
- if (spu->stop_callback)
- spu->stop_callback(spu);
- return 0;
-}
-
-static int __spu_trap_tag_group(struct spu *spu)
-{
- pr_debug("%s\n", __FUNCTION__);
- spu->mfc_callback(spu);
- return 0;
-}
-
-static int __spu_trap_spubox(struct spu *spu)
-{
- if (spu->wbox_callback)
- spu->wbox_callback(spu);
-
- /* atomically disable SPU mailbox interrupts */
- spin_lock(&spu->register_lock);
- spu_int_mask_and(spu, 2, ~0x10);
- spin_unlock(&spu->register_lock);
+ spu->stop_callback(spu);
return 0;
}
@@ -191,8 +151,7 @@ spu_irq_class_0(int irq, void *data, struct pt_regs *regs)
spu = data;
spu->class_0_pending = 1;
- if (spu->stop_callback)
- spu->stop_callback(spu);
+ spu->stop_callback(spu);
return IRQ_HANDLED;
}
@@ -270,29 +229,38 @@ spu_irq_class_2(int irq, void *data, struct pt_regs *regs)
unsigned long mask;
spu = data;
+ spin_lock(&spu->register_lock);
stat = spu_int_stat_get(spu, 2);
mask = spu_int_mask_get(spu, 2);
+ /* ignore interrupts we're not waiting for */
+ stat &= mask;
+ /*
+ * mailbox interrupts (0x1 and 0x10) are level triggered.
+ * mask them now before acknowledging.
+ */
+ if (stat & 0x11)
+ spu_int_mask_and(spu, 2, ~(stat & 0x11));
+ /* acknowledge all interrupts before the callbacks */
+ spu_int_stat_clear(spu, 2, stat);
+ spin_unlock(&spu->register_lock);
pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat, mask);
- stat &= mask;
-
if (stat & 1) /* PPC core mailbox */
- __spu_trap_mailbox(spu);
+ spu->ibox_callback(spu);
if (stat & 2) /* SPU stop-and-signal */
- __spu_trap_stop(spu);
+ spu->stop_callback(spu);
if (stat & 4) /* SPU halted */
- __spu_trap_halt(spu);
+ spu->stop_callback(spu);
if (stat & 8) /* DMA tag group complete */
- __spu_trap_tag_group(spu);
+ spu->mfc_callback(spu);
if (stat & 0x10) /* SPU mailbox threshold */
- __spu_trap_spubox(spu);
+ spu->wbox_callback(spu);
- spu_int_stat_clear(spu, 2, stat);
return stat ? IRQ_HANDLED : IRQ_NONE;
}
@@ -512,14 +480,6 @@ int spu_irq_class_1_bottom(struct spu *spu)
return ret;
}
-void spu_irq_setaffinity(struct spu *spu, int cpu)
-{
- u64 target = iic_get_target_id(cpu);
- u64 route = target << 48 | target << 32 | target << 16;
- spu_int_route_set(spu, route);
-}
-EXPORT_SYMBOL_GPL(spu_irq_setaffinity);
-
static int __init find_spu_node_id(struct device_node *spe)
{
unsigned int *id;
@@ -649,6 +609,46 @@ out:
return ret;
}
+struct sysdev_class spu_sysdev_class = {
+ set_kset_name("spu")
+};
+
+static ssize_t spu_show_isrc(struct sys_device *sysdev, char *buf)
+{
+ struct spu *spu = container_of(sysdev, struct spu, sysdev);
+ return sprintf(buf, "%d\n", spu->isrc);
+
+}
+static SYSDEV_ATTR(isrc, 0400, spu_show_isrc, NULL);
+
+extern int attach_sysdev_to_node(struct sys_device *dev, int nid);
+
+static int spu_create_sysdev(struct spu *spu)
+{
+ int ret;
+
+ spu->sysdev.id = spu->number;
+ spu->sysdev.cls = &spu_sysdev_class;
+ ret = sysdev_register(&spu->sysdev);
+ if (ret) {
+ printk(KERN_ERR "Can't register SPU %d with sysfs\n",
+ spu->number);
+ return ret;
+ }
+
+ sysdev_create_file(&spu->sysdev, &attr_isrc);
+ sysfs_add_device_to_node(&spu->sysdev, spu->nid);
+
+ return 0;
+}
+
+static void spu_destroy_sysdev(struct spu *spu)
+{
+ sysdev_remove_file(&spu->sysdev, &attr_isrc);
+ sysfs_remove_device_from_node(&spu->sysdev, spu->nid);
+ sysdev_unregister(&spu->sysdev);
+}
+
static int __init create_spu(struct device_node *spe)
{
struct spu *spu;
@@ -656,7 +656,7 @@ static int __init create_spu(struct device_node *spe)
static int number;
ret = -ENOMEM;
- spu = kmalloc(sizeof (*spu), GFP_KERNEL);
+ spu = kzalloc(sizeof (*spu), GFP_KERNEL);
if (!spu)
goto out;
@@ -668,33 +668,20 @@ static int __init create_spu(struct device_node *spe)
spu->nid = of_node_to_nid(spe);
if (spu->nid == -1)
spu->nid = 0;
-
- spu->stop_code = 0;
- spu->slb_replace = 0;
- spu->mm = NULL;
- spu->ctx = NULL;
- spu->rq = NULL;
- spu->pid = 0;
- spu->class_0_pending = 0;
- spu->flags = 0UL;
- spu->dar = 0UL;
- spu->dsisr = 0UL;
spin_lock_init(&spu->register_lock);
-
spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1));
spu_mfc_sr1_set(spu, 0x33);
-
- spu->ibox_callback = NULL;
- spu->wbox_callback = NULL;
- spu->stop_callback = NULL;
- spu->mfc_callback = NULL;
-
mutex_lock(&spu_mutex);
+
spu->number = number++;
ret = spu_request_irqs(spu);
if (ret)
goto out_unmap;
+ ret = spu_create_sysdev(spu);
+ if (ret)
+ goto out_free_irqs;
+
list_add(&spu->list, &spu_list);
mutex_unlock(&spu_mutex);
@@ -703,6 +690,9 @@ static int __init create_spu(struct device_node *spe)
spu->problem, spu->priv1, spu->priv2, spu->number);
goto out;
+out_free_irqs:
+ spu_free_irqs(spu);
+
out_unmap:
mutex_unlock(&spu_mutex);
spu_unmap(spu);
@@ -716,6 +706,7 @@ static void destroy_spu(struct spu *spu)
{
list_del_init(&spu->list);
+ spu_destroy_sysdev(spu);
spu_free_irqs(spu);
spu_unmap(spu);
kfree(spu);
@@ -728,6 +719,7 @@ static void cleanup_spu_base(void)
list_for_each_entry_safe(spu, tmp, &spu_list, list)
destroy_spu(spu);
mutex_unlock(&spu_mutex);
+ sysdev_class_unregister(&spu_sysdev_class);
}
module_exit(cleanup_spu_base);
@@ -736,6 +728,11 @@ static int __init init_spu_base(void)
struct device_node *node;
int ret;
+ /* create sysdev class for spus */
+ ret = sysdev_class_register(&spu_sysdev_class);
+ if (ret)
+ return ret;
+
ret = -ENODEV;
for (node = of_find_node_by_type(NULL, "spe");
node; node = of_find_node_by_type(node, "spe")) {
diff --git a/arch/powerpc/platforms/cell/spu_callbacks.c b/arch/powerpc/platforms/cell/spu_callbacks.c
index b47fcc5..47ec3be 100644
--- a/arch/powerpc/platforms/cell/spu_callbacks.c
+++ b/arch/powerpc/platforms/cell/spu_callbacks.c
@@ -34,307 +34,19 @@
*/
void *spu_syscall_table[] = {
- [__NR_restart_syscall] sys_ni_syscall, /* sys_restart_syscall */
- [__NR_exit] sys_ni_syscall, /* sys_exit */
- [__NR_fork] sys_ni_syscall, /* ppc_fork */
- [__NR_read] sys_read,
- [__NR_write] sys_write,
- [__NR_open] sys_open,
- [__NR_close] sys_close,
- [__NR_waitpid] sys_waitpid,
- [__NR_creat] sys_creat,
- [__NR_link] sys_link,
- [__NR_unlink] sys_unlink,
- [__NR_execve] sys_ni_syscall, /* sys_execve */
- [__NR_chdir] sys_chdir,
- [__NR_time] sys_time,
- [__NR_mknod] sys_mknod,
- [__NR_chmod] sys_chmod,
- [__NR_lchown] sys_lchown,
- [__NR_break] sys_ni_syscall,
- [__NR_oldstat] sys_ni_syscall,
- [__NR_lseek] sys_lseek,
- [__NR_getpid] sys_getpid,
- [__NR_mount] sys_ni_syscall, /* sys_mount */
- [__NR_umount] sys_ni_syscall,
- [__NR_setuid] sys_setuid,
- [__NR_getuid] sys_getuid,
- [__NR_stime] sys_stime,
- [__NR_ptrace] sys_ni_syscall, /* sys_ptrace */
- [__NR_alarm] sys_alarm,
- [__NR_oldfstat] sys_ni_syscall,
- [__NR_pause] sys_ni_syscall, /* sys_pause */
- [__NR_utime] sys_ni_syscall, /* sys_utime */
- [__NR_stty] sys_ni_syscall,
- [__NR_gtty] sys_ni_syscall,
- [__NR_access] sys_access,
- [__NR_nice] sys_nice,
- [__NR_ftime] sys_ni_syscall,
- [__NR_sync] sys_sync,
- [__NR_kill] sys_kill,
- [__NR_rename] sys_rename,
- [__NR_mkdir] sys_mkdir,
- [__NR_rmdir] sys_rmdir,
- [__NR_dup] sys_dup,
- [__NR_pipe] sys_pipe,
- [__NR_times] sys_times,
- [__NR_prof] sys_ni_syscall,
- [__NR_brk] sys_brk,
- [__NR_setgid] sys_setgid,
- [__NR_getgid] sys_getgid,
- [__NR_signal] sys_ni_syscall, /* sys_signal */
- [__NR_geteuid] sys_geteuid,
- [__NR_getegid] sys_getegid,
- [__NR_acct] sys_ni_syscall, /* sys_acct */
- [__NR_umount2] sys_ni_syscall, /* sys_umount */
- [__NR_lock] sys_ni_syscall,
- [__NR_ioctl] sys_ioctl,
- [__NR_fcntl] sys_fcntl,
- [__NR_mpx] sys_ni_syscall,
- [__NR_setpgid] sys_setpgid,
- [__NR_ulimit] sys_ni_syscall,
- [__NR_oldolduname] sys_ni_syscall,
- [__NR_umask] sys_umask,
- [__NR_chroot] sys_chroot,
- [__NR_ustat] sys_ni_syscall, /* sys_ustat */
- [__NR_dup2] sys_dup2,
- [__NR_getppid] sys_getppid,
- [__NR_getpgrp] sys_getpgrp,
- [__NR_setsid] sys_setsid,
- [__NR_sigaction] sys_ni_syscall,
- [__NR_sgetmask] sys_sgetmask,
- [__NR_ssetmask] sys_ssetmask,
- [__NR_setreuid] sys_setreuid,
- [__NR_setregid] sys_setregid,
- [__NR_sigsuspend] sys_ni_syscall,
- [__NR_sigpending] sys_ni_syscall,
- [__NR_sethostname] sys_sethostname,
- [__NR_setrlimit] sys_setrlimit,
- [__NR_getrlimit] sys_ni_syscall,
- [__NR_getrusage] sys_getrusage,
- [__NR_gettimeofday] sys_gettimeofday,
- [__NR_settimeofday] sys_settimeofday,
- [__NR_getgroups] sys_getgroups,
- [__NR_setgroups] sys_setgroups,
- [__NR_select] sys_ni_syscall,
- [__NR_symlink] sys_symlink,
- [__NR_oldlstat] sys_ni_syscall,
- [__NR_readlink] sys_readlink,
- [__NR_uselib] sys_ni_syscall, /* sys_uselib */
- [__NR_swapon] sys_ni_syscall, /* sys_swapon */
- [__NR_reboot] sys_ni_syscall, /* sys_reboot */
- [__NR_readdir] sys_ni_syscall,
- [__NR_mmap] sys_mmap,
- [__NR_munmap] sys_munmap,
- [__NR_truncate] sys_truncate,
- [__NR_ftruncate] sys_ftruncate,
- [__NR_fchmod] sys_fchmod,
- [__NR_fchown] sys_fchown,
- [__NR_getpriority] sys_getpriority,
- [__NR_setpriority] sys_setpriority,
- [__NR_profil] sys_ni_syscall,
- [__NR_statfs] sys_ni_syscall, /* sys_statfs */
- [__NR_fstatfs] sys_ni_syscall, /* sys_fstatfs */
- [__NR_ioperm] sys_ni_syscall,
- [__NR_socketcall] sys_socketcall,
- [__NR_syslog] sys_syslog,
- [__NR_setitimer] sys_setitimer,
- [__NR_getitimer] sys_getitimer,
- [__NR_stat] sys_newstat,
- [__NR_lstat] sys_newlstat,
- [__NR_fstat] sys_newfstat,
- [__NR_olduname] sys_ni_syscall,
- [__NR_iopl] sys_ni_syscall,
- [__NR_vhangup] sys_vhangup,
- [__NR_idle] sys_ni_syscall,
- [__NR_vm86] sys_ni_syscall,
- [__NR_wait4] sys_wait4,
- [__NR_swapoff] sys_ni_syscall, /* sys_swapoff */
- [__NR_sysinfo] sys_sysinfo,
- [__NR_ipc] sys_ni_syscall, /* sys_ipc */
- [__NR_fsync] sys_fsync,
- [__NR_sigreturn] sys_ni_syscall,
- [__NR_clone] sys_ni_syscall, /* ppc_clone */
- [__NR_setdomainname] sys_setdomainname,
- [__NR_uname] ppc_newuname,
- [__NR_modify_ldt] sys_ni_syscall,
- [__NR_adjtimex] sys_adjtimex,
- [__NR_mprotect] sys_mprotect,
- [__NR_sigprocmask] sys_ni_syscall,
- [__NR_create_module] sys_ni_syscall,
- [__NR_init_module] sys_ni_syscall, /* sys_init_module */
- [__NR_delete_module] sys_ni_syscall, /* sys_delete_module */
- [__NR_get_kernel_syms] sys_ni_syscall,
- [__NR_quotactl] sys_ni_syscall, /* sys_quotactl */
- [__NR_getpgid] sys_getpgid,
- [__NR_fchdir] sys_fchdir,
- [__NR_bdflush] sys_bdflush,
- [__NR_sysfs] sys_ni_syscall, /* sys_sysfs */
- [__NR_personality] ppc64_personality,
- [__NR_afs_syscall] sys_ni_syscall,
- [__NR_setfsuid] sys_setfsuid,
- [__NR_setfsgid] sys_setfsgid,
- [__NR__llseek] sys_llseek,
- [__NR_getdents] sys_getdents,
- [__NR__newselect] sys_select,
- [__NR_flock] sys_flock,
- [__NR_msync] sys_msync,
- [__NR_readv] sys_readv,
- [__NR_writev] sys_writev,
- [__NR_getsid] sys_getsid,
- [__NR_fdatasync] sys_fdatasync,
- [__NR__sysctl] sys_ni_syscall, /* sys_sysctl */
- [__NR_mlock] sys_mlock,
- [__NR_munlock] sys_munlock,
- [__NR_mlockall] sys_mlockall,
- [__NR_munlockall] sys_munlockall,
- [__NR_sched_setparam] sys_sched_setparam,
- [__NR_sched_getparam] sys_sched_getparam,
- [__NR_sched_setscheduler] sys_sched_setscheduler,
- [__NR_sched_getscheduler] sys_sched_getscheduler,
- [__NR_sched_yield] sys_sched_yield,
- [__NR_sched_get_priority_max] sys_sched_get_priority_max,
- [__NR_sched_get_priority_min] sys_sched_get_priority_min,
- [__NR_sched_rr_get_interval] sys_sched_rr_get_interval,
- [__NR_nanosleep] sys_nanosleep,
- [__NR_mremap] sys_mremap,
- [__NR_setresuid] sys_setresuid,
- [__NR_getresuid] sys_getresuid,
- [__NR_query_module] sys_ni_syscall,
- [__NR_poll] sys_poll,
- [__NR_nfsservctl] sys_ni_syscall, /* sys_nfsservctl */
- [__NR_setresgid] sys_setresgid,
- [__NR_getresgid] sys_getresgid,
- [__NR_prctl] sys_prctl,
- [__NR_rt_sigreturn] sys_ni_syscall, /* ppc64_rt_sigreturn */
- [__NR_rt_sigaction] sys_ni_syscall, /* sys_rt_sigaction */
- [__NR_rt_sigprocmask] sys_ni_syscall, /* sys_rt_sigprocmask */
- [__NR_rt_sigpending] sys_ni_syscall, /* sys_rt_sigpending */
- [__NR_rt_sigtimedwait] sys_ni_syscall, /* sys_rt_sigtimedwait */
- [__NR_rt_sigqueueinfo] sys_ni_syscall, /* sys_rt_sigqueueinfo */
- [__NR_rt_sigsuspend] sys_ni_syscall, /* sys_rt_sigsuspend */
- [__NR_pread64] sys_pread64,
- [__NR_pwrite64] sys_pwrite64,
- [__NR_chown] sys_chown,
- [__NR_getcwd] sys_getcwd,
- [__NR_capget] sys_capget,
- [__NR_capset] sys_capset,
- [__NR_sigaltstack] sys_ni_syscall, /* sys_sigaltstack */
- [__NR_sendfile] sys_sendfile64,
- [__NR_getpmsg] sys_ni_syscall,
- [__NR_putpmsg] sys_ni_syscall,
- [__NR_vfork] sys_ni_syscall, /* ppc_vfork */
- [__NR_ugetrlimit] sys_getrlimit,
- [__NR_readahead] sys_readahead,
- [192] sys_ni_syscall,
- [193] sys_ni_syscall,
- [194] sys_ni_syscall,
- [195] sys_ni_syscall,
- [196] sys_ni_syscall,
- [197] sys_ni_syscall,
- [__NR_pciconfig_read] sys_ni_syscall, /* sys_pciconfig_read */
- [__NR_pciconfig_write] sys_ni_syscall, /* sys_pciconfig_write */
- [__NR_pciconfig_iobase] sys_ni_syscall, /* sys_pciconfig_iobase */
- [__NR_multiplexer] sys_ni_syscall,
- [__NR_getdents64] sys_getdents64,
- [__NR_pivot_root] sys_pivot_root,
- [204] sys_ni_syscall,
- [__NR_madvise] sys_madvise,
- [__NR_mincore] sys_mincore,
- [__NR_gettid] sys_gettid,
- [__NR_tkill] sys_tkill,
- [__NR_setxattr] sys_setxattr,
- [__NR_lsetxattr] sys_lsetxattr,
- [__NR_fsetxattr] sys_fsetxattr,
- [__NR_getxattr] sys_getxattr,
- [__NR_lgetxattr] sys_lgetxattr,
- [__NR_fgetxattr] sys_fgetxattr,
- [__NR_listxattr] sys_listxattr,
- [__NR_llistxattr] sys_llistxattr,
- [__NR_flistxattr] sys_flistxattr,
- [__NR_removexattr] sys_removexattr,
- [__NR_lremovexattr] sys_lremovexattr,
- [__NR_fremovexattr] sys_fremovexattr,
- [__NR_futex] sys_futex,
- [__NR_sched_setaffinity] sys_sched_setaffinity,
- [__NR_sched_getaffinity] sys_sched_getaffinity,
- [224] sys_ni_syscall,
- [__NR_tuxcall] sys_ni_syscall,
- [226] sys_ni_syscall,
- [__NR_io_setup] sys_io_setup,
- [__NR_io_destroy] sys_io_destroy,
- [__NR_io_getevents] sys_io_getevents,
- [__NR_io_submit] sys_io_submit,
- [__NR_io_cancel] sys_io_cancel,
- [__NR_set_tid_address] sys_ni_syscall, /* sys_set_tid_address */
- [__NR_fadvise64] sys_fadvise64,
- [__NR_exit_group] sys_ni_syscall, /* sys_exit_group */
- [__NR_lookup_dcookie] sys_ni_syscall, /* sys_lookup_dcookie */
- [__NR_epoll_create] sys_epoll_create,
- [__NR_epoll_ctl] sys_epoll_ctl,
- [__NR_epoll_wait] sys_epoll_wait,
- [__NR_remap_file_pages] sys_remap_file_pages,
- [__NR_timer_create] sys_timer_create,
- [__NR_timer_settime] sys_timer_settime,
- [__NR_timer_gettime] sys_timer_gettime,
- [__NR_timer_getoverrun] sys_timer_getoverrun,
- [__NR_timer_delete] sys_timer_delete,
- [__NR_clock_settime] sys_clock_settime,
- [__NR_clock_gettime] sys_clock_gettime,
- [__NR_clock_getres] sys_clock_getres,
- [__NR_clock_nanosleep] sys_clock_nanosleep,
- [__NR_swapcontext] sys_ni_syscall, /* ppc64_swapcontext */
- [__NR_tgkill] sys_tgkill,
- [__NR_utimes] sys_utimes,
- [__NR_statfs64] sys_statfs64,
- [__NR_fstatfs64] sys_fstatfs64,
- [254] sys_ni_syscall,
- [__NR_rtas] ppc_rtas,
- [256] sys_ni_syscall,
- [257] sys_ni_syscall,
- [258] sys_ni_syscall,
- [__NR_mbind] sys_ni_syscall, /* sys_mbind */
- [__NR_get_mempolicy] sys_ni_syscall, /* sys_get_mempolicy */
- [__NR_set_mempolicy] sys_ni_syscall, /* sys_set_mempolicy */
- [__NR_mq_open] sys_ni_syscall, /* sys_mq_open */
- [__NR_mq_unlink] sys_ni_syscall, /* sys_mq_unlink */
- [__NR_mq_timedsend] sys_ni_syscall, /* sys_mq_timedsend */
- [__NR_mq_timedreceive] sys_ni_syscall, /* sys_mq_timedreceive */
- [__NR_mq_notify] sys_ni_syscall, /* sys_mq_notify */
- [__NR_mq_getsetattr] sys_ni_syscall, /* sys_mq_getsetattr */
- [__NR_kexec_load] sys_ni_syscall, /* sys_kexec_load */
- [__NR_add_key] sys_ni_syscall, /* sys_add_key */
- [__NR_request_key] sys_ni_syscall, /* sys_request_key */
- [__NR_keyctl] sys_ni_syscall, /* sys_keyctl */
- [__NR_waitid] sys_ni_syscall, /* sys_waitid */
- [__NR_ioprio_set] sys_ni_syscall, /* sys_ioprio_set */
- [__NR_ioprio_get] sys_ni_syscall, /* sys_ioprio_get */
- [__NR_inotify_init] sys_ni_syscall, /* sys_inotify_init */
- [__NR_inotify_add_watch] sys_ni_syscall, /* sys_inotify_add_watch */
- [__NR_inotify_rm_watch] sys_ni_syscall, /* sys_inotify_rm_watch */
- [__NR_spu_run] sys_ni_syscall, /* sys_spu_run */
- [__NR_spu_create] sys_ni_syscall, /* sys_spu_create */
- [__NR_pselect6] sys_ni_syscall, /* sys_pselect */
- [__NR_ppoll] sys_ni_syscall, /* sys_ppoll */
- [__NR_unshare] sys_unshare,
- [__NR_splice] sys_splice,
- [__NR_tee] sys_tee,
- [__NR_vmsplice] sys_vmsplice,
- [__NR_openat] sys_openat,
- [__NR_mkdirat] sys_mkdirat,
- [__NR_mknodat] sys_mknodat,
- [__NR_fchownat] sys_fchownat,
- [__NR_futimesat] sys_futimesat,
- [__NR_newfstatat] sys_newfstatat,
- [__NR_unlinkat] sys_unlinkat,
- [__NR_renameat] sys_renameat,
- [__NR_linkat] sys_linkat,
- [__NR_symlinkat] sys_symlinkat,
- [__NR_readlinkat] sys_readlinkat,
- [__NR_fchmodat] sys_fchmodat,
- [__NR_faccessat] sys_faccessat,
- [__NR_get_robust_list] sys_get_robust_list,
- [__NR_set_robust_list] sys_set_robust_list,
+#define SYSCALL(func) sys_ni_syscall,
+#define COMPAT_SYS(func) sys_ni_syscall,
+#define PPC_SYS(func) sys_ni_syscall,
+#define OLDSYS(func) sys_ni_syscall,
+#define SYS32ONLY(func) sys_ni_syscall,
+#define SYSX(f, f3264, f32) sys_ni_syscall,
+
+#define SYSCALL_SPU(func) sys_##func,
+#define COMPAT_SYS_SPU(func) sys_##func,
+#define PPC_SYS_SPU(func) ppc_##func,
+#define SYSX_SPU(f, f3264, f32) f,
+
+#include <asm/systbl.h>
};
long spu_sys_callback(struct spu_syscall_block *s)
diff --git a/arch/powerpc/platforms/cell/spu_priv1.c b/arch/powerpc/platforms/cell/spu_priv1.c
deleted file mode 100644
index b265642..0000000
--- a/arch/powerpc/platforms/cell/spu_priv1.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * access to SPU privileged registers
- */
-#include <linux/module.h>
-
-#include <asm/io.h>
-#include <asm/spu.h>
-
-void spu_int_mask_and(struct spu *spu, int class, u64 mask)
-{
- u64 old_mask;
-
- old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
- out_be64(&spu->priv1->int_mask_RW[class], old_mask & mask);
-}
-EXPORT_SYMBOL_GPL(spu_int_mask_and);
-
-void spu_int_mask_or(struct spu *spu, int class, u64 mask)
-{
- u64 old_mask;
-
- old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
- out_be64(&spu->priv1->int_mask_RW[class], old_mask | mask);
-}
-EXPORT_SYMBOL_GPL(spu_int_mask_or);
-
-void spu_int_mask_set(struct spu *spu, int class, u64 mask)
-{
- out_be64(&spu->priv1->int_mask_RW[class], mask);
-}
-EXPORT_SYMBOL_GPL(spu_int_mask_set);
-
-u64 spu_int_mask_get(struct spu *spu, int class)
-{
- return in_be64(&spu->priv1->int_mask_RW[class]);
-}
-EXPORT_SYMBOL_GPL(spu_int_mask_get);
-
-void spu_int_stat_clear(struct spu *spu, int class, u64 stat)
-{
- out_be64(&spu->priv1->int_stat_RW[class], stat);
-}
-EXPORT_SYMBOL_GPL(spu_int_stat_clear);
-
-u64 spu_int_stat_get(struct spu *spu, int class)
-{
- return in_be64(&spu->priv1->int_stat_RW[class]);
-}
-EXPORT_SYMBOL_GPL(spu_int_stat_get);
-
-void spu_int_route_set(struct spu *spu, u64 route)
-{
- out_be64(&spu->priv1->int_route_RW, route);
-}
-EXPORT_SYMBOL_GPL(spu_int_route_set);
-
-u64 spu_mfc_dar_get(struct spu *spu)
-{
- return in_be64(&spu->priv1->mfc_dar_RW);
-}
-EXPORT_SYMBOL_GPL(spu_mfc_dar_get);
-
-u64 spu_mfc_dsisr_get(struct spu *spu)
-{
- return in_be64(&spu->priv1->mfc_dsisr_RW);
-}
-EXPORT_SYMBOL_GPL(spu_mfc_dsisr_get);
-
-void spu_mfc_dsisr_set(struct spu *spu, u64 dsisr)
-{
- out_be64(&spu->priv1->mfc_dsisr_RW, dsisr);
-}
-EXPORT_SYMBOL_GPL(spu_mfc_dsisr_set);
-
-void spu_mfc_sdr_set(struct spu *spu, u64 sdr)
-{
- out_be64(&spu->priv1->mfc_sdr_RW, sdr);
-}
-EXPORT_SYMBOL_GPL(spu_mfc_sdr_set);
-
-void spu_mfc_sr1_set(struct spu *spu, u64 sr1)
-{
- out_be64(&spu->priv1->mfc_sr1_RW, sr1);
-}
-EXPORT_SYMBOL_GPL(spu_mfc_sr1_set);
-
-u64 spu_mfc_sr1_get(struct spu *spu)
-{
- return in_be64(&spu->priv1->mfc_sr1_RW);
-}
-EXPORT_SYMBOL_GPL(spu_mfc_sr1_get);
-
-void spu_mfc_tclass_id_set(struct spu *spu, u64 tclass_id)
-{
- out_be64(&spu->priv1->mfc_tclass_id_RW, tclass_id);
-}
-EXPORT_SYMBOL_GPL(spu_mfc_tclass_id_set);
-
-u64 spu_mfc_tclass_id_get(struct spu *spu)
-{
- return in_be64(&spu->priv1->mfc_tclass_id_RW);
-}
-EXPORT_SYMBOL_GPL(spu_mfc_tclass_id_get);
-
-void spu_tlb_invalidate(struct spu *spu)
-{
- out_be64(&spu->priv1->tlb_invalidate_entry_W, 0ul);
-}
-EXPORT_SYMBOL_GPL(spu_tlb_invalidate);
-
-void spu_resource_allocation_groupID_set(struct spu *spu, u64 id)
-{
- out_be64(&spu->priv1->resource_allocation_groupID_RW, id);
-}
-EXPORT_SYMBOL_GPL(spu_resource_allocation_groupID_set);
-
-u64 spu_resource_allocation_groupID_get(struct spu *spu)
-{
- return in_be64(&spu->priv1->resource_allocation_groupID_RW);
-}
-EXPORT_SYMBOL_GPL(spu_resource_allocation_groupID_get);
-
-void spu_resource_allocation_enable_set(struct spu *spu, u64 enable)
-{
- out_be64(&spu->priv1->resource_allocation_enable_RW, enable);
-}
-EXPORT_SYMBOL_GPL(spu_resource_allocation_enable_set);
-
-u64 spu_resource_allocation_enable_get(struct spu *spu)
-{
- return in_be64(&spu->priv1->resource_allocation_enable_RW);
-}
-EXPORT_SYMBOL_GPL(spu_resource_allocation_enable_get);
diff --git a/arch/powerpc/platforms/cell/spu_priv1_mmio.c b/arch/powerpc/platforms/cell/spu_priv1_mmio.c
new file mode 100644
index 0000000..71b69f0
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spu_priv1_mmio.c
@@ -0,0 +1,159 @@
+/*
+ * spu hypervisor abstraction for direct hardware access.
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ * Copyright 2006 Sony Corp.
+ *
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+
+#include <asm/io.h>
+#include <asm/spu.h>
+#include <asm/spu_priv1.h>
+
+#include "interrupt.h"
+
+static void int_mask_and(struct spu *spu, int class, u64 mask)
+{
+ u64 old_mask;
+
+ old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
+ out_be64(&spu->priv1->int_mask_RW[class], old_mask & mask);
+}
+
+static void int_mask_or(struct spu *spu, int class, u64 mask)
+{
+ u64 old_mask;
+
+ old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
+ out_be64(&spu->priv1->int_mask_RW[class], old_mask | mask);
+}
+
+static void int_mask_set(struct spu *spu, int class, u64 mask)
+{
+ out_be64(&spu->priv1->int_mask_RW[class], mask);
+}
+
+static u64 int_mask_get(struct spu *spu, int class)
+{
+ return in_be64(&spu->priv1->int_mask_RW[class]);
+}
+
+static void int_stat_clear(struct spu *spu, int class, u64 stat)
+{
+ out_be64(&spu->priv1->int_stat_RW[class], stat);
+}
+
+static u64 int_stat_get(struct spu *spu, int class)
+{
+ return in_be64(&spu->priv1->int_stat_RW[class]);
+}
+
+static void cpu_affinity_set(struct spu *spu, int cpu)
+{
+ u64 target = iic_get_target_id(cpu);
+ u64 route = target << 48 | target << 32 | target << 16;
+ out_be64(&spu->priv1->int_route_RW, route);
+}
+
+static u64 mfc_dar_get(struct spu *spu)
+{
+ return in_be64(&spu->priv1->mfc_dar_RW);
+}
+
+static u64 mfc_dsisr_get(struct spu *spu)
+{
+ return in_be64(&spu->priv1->mfc_dsisr_RW);
+}
+
+static void mfc_dsisr_set(struct spu *spu, u64 dsisr)
+{
+ out_be64(&spu->priv1->mfc_dsisr_RW, dsisr);
+}
+
+static void mfc_sdr_set(struct spu *spu, u64 sdr)
+{
+ out_be64(&spu->priv1->mfc_sdr_RW, sdr);
+}
+
+static void mfc_sr1_set(struct spu *spu, u64 sr1)
+{
+ out_be64(&spu->priv1->mfc_sr1_RW, sr1);
+}
+
+static u64 mfc_sr1_get(struct spu *spu)
+{
+ return in_be64(&spu->priv1->mfc_sr1_RW);
+}
+
+static void mfc_tclass_id_set(struct spu *spu, u64 tclass_id)
+{
+ out_be64(&spu->priv1->mfc_tclass_id_RW, tclass_id);
+}
+
+static u64 mfc_tclass_id_get(struct spu *spu)
+{
+ return in_be64(&spu->priv1->mfc_tclass_id_RW);
+}
+
+static void tlb_invalidate(struct spu *spu)
+{
+ out_be64(&spu->priv1->tlb_invalidate_entry_W, 0ul);
+}
+
+static void resource_allocation_groupID_set(struct spu *spu, u64 id)
+{
+ out_be64(&spu->priv1->resource_allocation_groupID_RW, id);
+}
+
+static u64 resource_allocation_groupID_get(struct spu *spu)
+{
+ return in_be64(&spu->priv1->resource_allocation_groupID_RW);
+}
+
+static void resource_allocation_enable_set(struct spu *spu, u64 enable)
+{
+ out_be64(&spu->priv1->resource_allocation_enable_RW, enable);
+}
+
+static u64 resource_allocation_enable_get(struct spu *spu)
+{
+ return in_be64(&spu->priv1->resource_allocation_enable_RW);
+}
+
+const struct spu_priv1_ops spu_priv1_mmio_ops =
+{
+ .int_mask_and = int_mask_and,
+ .int_mask_or = int_mask_or,
+ .int_mask_set = int_mask_set,
+ .int_mask_get = int_mask_get,
+ .int_stat_clear = int_stat_clear,
+ .int_stat_get = int_stat_get,
+ .cpu_affinity_set = cpu_affinity_set,
+ .mfc_dar_get = mfc_dar_get,
+ .mfc_dsisr_get = mfc_dsisr_get,
+ .mfc_dsisr_set = mfc_dsisr_set,
+ .mfc_sdr_set = mfc_sdr_set,
+ .mfc_sr1_set = mfc_sr1_set,
+ .mfc_sr1_get = mfc_sr1_get,
+ .mfc_tclass_id_set = mfc_tclass_id_set,
+ .mfc_tclass_id_get = mfc_tclass_id_get,
+ .tlb_invalidate = tlb_invalidate,
+ .resource_allocation_groupID_set = resource_allocation_groupID_set,
+ .resource_allocation_groupID_get = resource_allocation_groupID_get,
+ .resource_allocation_enable_set = resource_allocation_enable_set,
+ .resource_allocation_enable_get = resource_allocation_enable_get,
+};
diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile
index a7cddf4..bb5dc63 100644
--- a/arch/powerpc/platforms/cell/spufs/Makefile
+++ b/arch/powerpc/platforms/cell/spufs/Makefile
@@ -1,5 +1,7 @@
+obj-y += switch.o
+
obj-$(CONFIG_SPU_FS) += spufs.o
-spufs-y += inode.o file.o context.o switch.o syscalls.o
+spufs-y += inode.o file.o context.o syscalls.o
spufs-y += sched.o backing_ops.o hw_ops.o run.o
# Rules to build switch.o with the help of SPU tool chain
@@ -8,11 +10,14 @@ SPU_CC := $(SPU_CROSS)gcc
SPU_AS := $(SPU_CROSS)gcc
SPU_LD := $(SPU_CROSS)ld
SPU_OBJCOPY := $(SPU_CROSS)objcopy
-SPU_CFLAGS := -O2 -Wall -I$(srctree)/include -I$(objtree)/include2
-SPU_AFLAGS := -c -D__ASSEMBLY__ -I$(srctree)/include -I$(objtree)/include2
+SPU_CFLAGS := -O2 -Wall -I$(srctree)/include \
+ -I$(objtree)/include2 -D__KERNEL__
+SPU_AFLAGS := -c -D__ASSEMBLY__ -I$(srctree)/include \
+ -I$(objtree)/include2 -D__KERNEL__
SPU_LDFLAGS := -N -Ttext=0x0
$(obj)/switch.o: $(obj)/spu_save_dump.h $(obj)/spu_restore_dump.h
+clean-files := spu_save_dump.h spu_restore_dump.h
# Compile SPU files
cmd_spu_cc = $(SPU_CC) $(SPU_CFLAGS) -c -o $@ $<
@@ -45,7 +50,8 @@ cmd_hexdump = ( \
echo " * Hex-dump auto generated from $*.c." ; \
echo " * Do not edit!" ; \
echo " */" ; \
- echo "static unsigned int $*_code[] __page_aligned = {" ; \
+ echo "static unsigned int $*_code[] " \
+ "__attribute__((__aligned__(128))) = {" ; \
hexdump -v -e '"0x" 4/1 "%02x" "," "\n"' $< ; \
echo "};" ; \
) > $@
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
index 8bb33ab..36439c5 100644
--- a/arch/powerpc/platforms/cell/spufs/context.c
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -30,7 +30,7 @@
struct spu_context *alloc_spu_context(void)
{
struct spu_context *ctx;
- ctx = kmalloc(sizeof *ctx, GFP_KERNEL);
+ ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
if (!ctx)
goto out;
/* Binding to physical processor deferred
@@ -48,17 +48,7 @@ struct spu_context *alloc_spu_context(void)
init_waitqueue_head(&ctx->wbox_wq);
init_waitqueue_head(&ctx->stop_wq);
init_waitqueue_head(&ctx->mfc_wq);
- ctx->ibox_fasync = NULL;
- ctx->wbox_fasync = NULL;
- ctx->mfc_fasync = NULL;
- ctx->mfc = NULL;
- ctx->tagwait = 0;
ctx->state = SPU_STATE_SAVED;
- ctx->local_store = NULL;
- ctx->cntl = NULL;
- ctx->signal1 = NULL;
- ctx->signal2 = NULL;
- ctx->spu = NULL;
ctx->ops = &spu_backing_ops;
ctx->owner = get_task_mm(current);
goto out;
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index 366185e..80c0266 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -825,6 +825,55 @@ DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
spufs_signal2_type_set, "%llu");
#ifdef CONFIG_SPUFS_MMAP
+static struct page *spufs_mss_mmap_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ return spufs_ps_nopage(vma, address, type, 0x0000);
+}
+
+static struct vm_operations_struct spufs_mss_mmap_vmops = {
+ .nopage = spufs_mss_mmap_nopage,
+};
+
+/*
+ * mmap support for problem state MFC DMA area [0x0000 - 0x0fff].
+ * Mapping this area requires that the application have CAP_SYS_RAWIO,
+ * as these registers require special care when read/writing.
+ */
+static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ if (!(vma->vm_flags & VM_SHARED))
+ return -EINVAL;
+
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
+ | _PAGE_NO_CACHE);
+
+ vma->vm_ops = &spufs_mss_mmap_vmops;
+ return 0;
+}
+#endif
+
+static int spufs_mss_open(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+
+ file->private_data = i->i_ctx;
+ return nonseekable_open(inode, file);
+}
+
+static struct file_operations spufs_mss_fops = {
+ .open = spufs_mss_open,
+#ifdef CONFIG_SPUFS_MMAP
+ .mmap = spufs_mss_mmap,
+#endif
+};
+
+
+#ifdef CONFIG_SPUFS_MMAP
static struct page *spufs_mfc_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type)
{
@@ -1279,6 +1328,22 @@ static u64 spufs_srr0_get(void *data)
DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set,
"%llx\n")
+static u64 spufs_id_get(void *data)
+{
+ struct spu_context *ctx = data;
+ u64 num;
+
+ spu_acquire(ctx);
+ if (ctx->state == SPU_STATE_RUNNABLE)
+ num = ctx->spu->number;
+ else
+ num = (unsigned int)-1;
+ spu_release(ctx);
+
+ return num;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_id_ops, spufs_id_get, 0, "0x%llx\n")
+
struct tree_descr spufs_dir_contents[] = {
{ "mem", &spufs_mem_fops, 0666, },
{ "regs", &spufs_regs_fops, 0666, },
@@ -1292,6 +1357,7 @@ struct tree_descr spufs_dir_contents[] = {
{ "signal2", &spufs_signal2_fops, 0666, },
{ "signal1_type", &spufs_signal1_type, 0666, },
{ "signal2_type", &spufs_signal2_type, 0666, },
+ { "mss", &spufs_mss_fops, 0666, },
{ "mfc", &spufs_mfc_fops, 0666, },
{ "cntl", &spufs_cntl_fops, 0666, },
{ "npc", &spufs_npc_ops, 0666, },
@@ -1301,5 +1367,6 @@ struct tree_descr spufs_dir_contents[] = {
{ "spu_tag_mask", &spufs_spu_tag_mask_ops, 0666, },
{ "event_mask", &spufs_event_mask_ops, 0666, },
{ "srr0", &spufs_srr0_ops, 0666, },
+ { "phys-id", &spufs_id_ops, 0666, },
{},
};
diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c
index a13a8b5..ede2cac 100644
--- a/arch/powerpc/platforms/cell/spufs/hw_ops.c
+++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c
@@ -32,6 +32,7 @@
#include <asm/io.h>
#include <asm/spu.h>
+#include <asm/spu_priv1.h>
#include <asm/spu_csa.h>
#include <asm/mmu_context.h>
#include "spufs.h"
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index d955419..7b45728 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -157,20 +157,12 @@ static void spufs_prune_dir(struct dentry *dir)
mutex_unlock(&dir->d_inode->i_mutex);
}
+/* Caller must hold root->i_mutex */
static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry)
{
- struct spu_context *ctx;
-
/* remove all entries */
- mutex_lock(&root->i_mutex);
spufs_prune_dir(dir_dentry);
- mutex_unlock(&root->i_mutex);
-
- /* We have to give up the mm_struct */
- ctx = SPUFS_I(dir_dentry->d_inode)->i_ctx;
- spu_forget(ctx);
- /* XXX Do we need to hold i_mutex here ? */
return simple_rmdir(root, dir_dentry);
}
@@ -199,16 +191,23 @@ out:
static int spufs_dir_close(struct inode *inode, struct file *file)
{
+ struct spu_context *ctx;
struct inode *dir;
struct dentry *dentry;
int ret;
dentry = file->f_dentry;
dir = dentry->d_parent->d_inode;
+ ctx = SPUFS_I(dentry->d_inode)->i_ctx;
+ mutex_lock(&dir->i_mutex);
ret = spufs_rmdir(dir, dentry);
+ mutex_unlock(&dir->i_mutex);
WARN_ON(ret);
+ /* We have to give up the mm_struct */
+ spu_forget(ctx);
+
return dcache_dir_close(inode, file);
}
@@ -305,6 +304,10 @@ long spufs_create_thread(struct nameidata *nd,
nd->dentry != nd->dentry->d_sb->s_root)
goto out;
+ /* all flags are reserved */
+ if (flags)
+ goto out;
+
dentry = lookup_create(nd, 1);
ret = PTR_ERR(dentry);
if (IS_ERR(dentry))
@@ -324,8 +327,13 @@ long spufs_create_thread(struct nameidata *nd,
* in error path of *_open().
*/
ret = spufs_context_open(dget(dentry), mntget(nd->mnt));
- if (ret < 0)
- spufs_rmdir(nd->dentry->d_inode, dentry);
+ if (ret < 0) {
+ WARN_ON(spufs_rmdir(nd->dentry->d_inode, dentry));
+ mutex_unlock(&nd->dentry->d_inode->i_mutex);
+ spu_forget(SPUFS_I(dentry->d_inode)->i_ctx);
+ dput(dentry);
+ goto out;
+ }
out_dput:
dput(dentry);
@@ -428,11 +436,11 @@ spufs_fill_super(struct super_block *sb, void *data, int silent)
return spufs_create_root(sb, data);
}
-static struct super_block *
+static int
spufs_get_sb(struct file_system_type *fstype, int flags,
- const char *name, void *data)
+ const char *name, void *data, struct vfsmount *mnt)
{
- return get_sb_single(fstype, flags, data, spufs_fill_super);
+ return get_sb_single(fstype, flags, data, spufs_fill_super, mnt);
}
static struct file_system_type spufs_type = {
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index bf652cd..3dcc5d8 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -43,6 +43,7 @@
#include <asm/mmu_context.h>
#include <asm/spu.h>
#include <asm/spu_csa.h>
+#include <asm/spu_priv1.h>
#include "spufs.h"
#define SPU_MIN_TIMESLICE (100 * HZ / 1000)
@@ -363,7 +364,7 @@ int spu_activate(struct spu_context *ctx, u64 flags)
* We're likely to wait for interrupts on the same
* CPU that we are now on, so send them here.
*/
- spu_irq_setaffinity(spu, raw_smp_processor_id());
+ spu_cpu_affinity_set(spu, raw_smp_processor_id());
put_active_spu(spu);
return 0;
}
diff --git a/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped b/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped
index 1b2355f..15183d2 100644
--- a/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped
+++ b/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped
@@ -3,229 +3,901 @@
* Hex-dump auto generated from spu_restore.c.
* Do not edit!
*/
-static unsigned int spu_restore_code[] __page_aligned = {
-0x40800000, 0x409ff801, 0x24000080, 0x24fd8081,
-0x1cd80081, 0x33001180, 0x42030003, 0x33800284,
-0x1c010204, 0x40200000, 0x40200000, 0x40200000,
-0x34000190, 0x34004191, 0x34008192, 0x3400c193,
-0x141fc205, 0x23fffd84, 0x1c100183, 0x217ffa85,
-0x3080a000, 0x3080a201, 0x3080a402, 0x3080a603,
-0x3080a804, 0x3080aa05, 0x3080ac06, 0x3080ae07,
-0x3080b008, 0x3080b209, 0x3080b40a, 0x3080b60b,
-0x3080b80c, 0x3080ba0d, 0x3080bc0e, 0x3080be0f,
-0x00003ffc, 0x00000000, 0x00000000, 0x00000000,
-0x01a00182, 0x3ec00083, 0xb0a14103, 0x01a00204,
-0x3ec10082, 0x4202800e, 0x04000703, 0xb0a14202,
-0x21a00803, 0x3fbf028d, 0x3f20068d, 0x3fbe0682,
-0x3fe30102, 0x21a00882, 0x3f82028f, 0x3fe3078f,
-0x3fbf0784, 0x3f200204, 0x3fbe0204, 0x3fe30204,
-0x04000203, 0x21a00903, 0x40848002, 0x21a00982,
-0x40800003, 0x21a00a03, 0x40802002, 0x21a00a82,
-0x21a00083, 0x40800082, 0x21a00b02, 0x10002818,
-0x40a80002, 0x32800007, 0x4207000c, 0x18008208,
-0x40a0000b, 0x4080020a, 0x40800709, 0x00200000,
-0x42070002, 0x3ac30384, 0x1cffc489, 0x00200000,
-0x18008383, 0x38830382, 0x4cffc486, 0x3ac28185,
-0xb0408584, 0x28830382, 0x1c020387, 0x38828182,
-0xb0408405, 0x1802c408, 0x28828182, 0x217ff886,
-0x04000583, 0x21a00803, 0x3fbe0682, 0x3fe30102,
-0x04000106, 0x21a00886, 0x04000603, 0x21a00903,
-0x40803c02, 0x21a00982, 0x40800003, 0x04000184,
-0x21a00a04, 0x40802202, 0x21a00a82, 0x42028005,
-0x34208702, 0x21002282, 0x21a00804, 0x21a00886,
-0x3fbf0782, 0x3f200102, 0x3fbe0102, 0x3fe30102,
-0x21a00902, 0x40804003, 0x21a00983, 0x21a00a04,
-0x40805a02, 0x21a00a82, 0x40800083, 0x21a00b83,
-0x01a00c02, 0x01a00d83, 0x3420c282, 0x21a00e02,
-0x34210283, 0x21a00f03, 0x34200284, 0x77400200,
-0x3421c282, 0x21a00702, 0x34218283, 0x21a00083,
-0x34214282, 0x21a00b02, 0x4200480c, 0x00200000,
-0x1c010286, 0x34220284, 0x34220302, 0x0f608203,
-0x5c024204, 0x3b81810b, 0x42013c02, 0x00200000,
-0x18008185, 0x38808183, 0x3b814182, 0x21004e84,
-0x4020007f, 0x35000100, 0x000004e0, 0x000002a0,
-0x000002e8, 0x00000428, 0x00000360, 0x000002e8,
-0x000004a0, 0x00000468, 0x000003c8, 0x00000360,
-0x409ffe02, 0x30801203, 0x40800204, 0x3ec40085,
-0x10009c09, 0x3ac10606, 0xb060c105, 0x4020007f,
-0x4020007f, 0x20801203, 0x38810602, 0xb0408586,
-0x28810602, 0x32004180, 0x34204702, 0x21a00382,
-0x4020007f, 0x327fdc80, 0x409ffe02, 0x30801203,
-0x40800204, 0x3ec40087, 0x40800405, 0x00200000,
-0x40800606, 0x3ac10608, 0x3ac14609, 0x3ac1860a,
-0xb060c107, 0x20801203, 0x41004003, 0x38810602,
-0x4020007f, 0xb0408188, 0x4020007f, 0x28810602,
-0x41201002, 0x38814603, 0x10009c09, 0xb060c109,
-0x4020007f, 0x28814603, 0x41193f83, 0x38818602,
-0x60ffc003, 0xb040818a, 0x28818602, 0x32003080,
-0x409ffe02, 0x30801203, 0x40800204, 0x3ec40087,
-0x41201008, 0x10009c14, 0x40800405, 0x3ac10609,
-0x40800606, 0x3ac1460a, 0xb060c107, 0x3ac1860b,
-0x20801203, 0x38810602, 0xb0408409, 0x28810602,
-0x38814603, 0xb060c40a, 0x4020007f, 0x28814603,
-0x41193f83, 0x38818602, 0x60ffc003, 0xb040818b,
-0x28818602, 0x32002380, 0x409ffe02, 0x30801204,
-0x40800205, 0x3ec40083, 0x40800406, 0x3ac14607,
-0x3ac18608, 0xb0810103, 0x41004002, 0x20801204,
-0x4020007f, 0x38814603, 0x10009c0b, 0xb060c107,
-0x4020007f, 0x4020007f, 0x28814603, 0x38818602,
-0x4020007f, 0x4020007f, 0xb0408588, 0x28818602,
-0x4020007f, 0x32001780, 0x409ffe02, 0x1000640e,
-0x40800204, 0x30801203, 0x40800405, 0x3ec40087,
-0x40800606, 0x3ac10608, 0x3ac14609, 0x3ac1860a,
-0xb060c107, 0x20801203, 0x413d8003, 0x38810602,
-0x4020007f, 0x327fd780, 0x409ffe02, 0x10007f0c,
-0x40800205, 0x30801204, 0x40800406, 0x3ec40083,
-0x3ac14607, 0x3ac18608, 0xb0810103, 0x413d8002,
-0x20801204, 0x38814603, 0x4020007f, 0x327feb80,
-0x409ffe02, 0x30801203, 0x40800204, 0x3ec40087,
-0x40800405, 0x1000650a, 0x40800606, 0x3ac10608,
-0x3ac14609, 0x3ac1860a, 0xb060c107, 0x20801203,
-0x38810602, 0xb0408588, 0x4020007f, 0x327fc980,
-0x00400000, 0x40800003, 0x4020007f, 0x35000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
+static unsigned int spu_restore_code[] __attribute__((__aligned__(128))) = {
+0x40800000,
+0x409ff801,
+0x24000080,
+0x24fd8081,
+0x1cd80081,
+0x33001180,
+0x42030003,
+0x33800284,
+0x1c010204,
+0x40200000,
+0x40200000,
+0x40200000,
+0x34000190,
+0x34004191,
+0x34008192,
+0x3400c193,
+0x141fc205,
+0x23fffd84,
+0x1c100183,
+0x217ffa85,
+0x3080a000,
+0x3080a201,
+0x3080a402,
+0x3080a603,
+0x3080a804,
+0x3080aa05,
+0x3080ac06,
+0x3080ae07,
+0x3080b008,
+0x3080b209,
+0x3080b40a,
+0x3080b60b,
+0x3080b80c,
+0x3080ba0d,
+0x3080bc0e,
+0x3080be0f,
+0x00003ffc,
+0x00000000,
+0x00000000,
+0x00000000,
+0x01a00182,
+0x3ec00083,
+0xb0a14103,
+0x01a00204,
+0x3ec10082,
+0x4202800e,
+0x04000703,
+0xb0a14202,
+0x21a00803,
+0x3fbf028d,
+0x3f20068d,
+0x3fbe0682,
+0x3fe30102,
+0x21a00882,
+0x3f82028f,
+0x3fe3078f,
+0x3fbf0784,
+0x3f200204,
+0x3fbe0204,
+0x3fe30204,
+0x04000203,
+0x21a00903,
+0x40848002,
+0x21a00982,
+0x40800003,
+0x21a00a03,
+0x40802002,
+0x21a00a82,
+0x21a00083,
+0x40800082,
+0x21a00b02,
+0x10002818,
+0x42a00002,
+0x32800007,
+0x4207000c,
+0x18008208,
+0x40a0000b,
+0x4080020a,
+0x40800709,
+0x00200000,
+0x42070002,
+0x3ac30384,
+0x1cffc489,
+0x00200000,
+0x18008383,
+0x38830382,
+0x4cffc486,
+0x3ac28185,
+0xb0408584,
+0x28830382,
+0x1c020387,
+0x38828182,
+0xb0408405,
+0x1802c408,
+0x28828182,
+0x217ff886,
+0x04000583,
+0x21a00803,
+0x3fbe0682,
+0x3fe30102,
+0x04000106,
+0x21a00886,
+0x04000603,
+0x21a00903,
+0x40803c02,
+0x21a00982,
+0x40800003,
+0x04000184,
+0x21a00a04,
+0x40802202,
+0x21a00a82,
+0x42028005,
+0x34208702,
+0x21002282,
+0x21a00804,
+0x21a00886,
+0x3fbf0782,
+0x3f200102,
+0x3fbe0102,
+0x3fe30102,
+0x21a00902,
+0x40804003,
+0x21a00983,
+0x21a00a04,
+0x40805a02,
+0x21a00a82,
+0x40800083,
+0x21a00b83,
+0x01a00c02,
+0x01a00d83,
+0x3420c282,
+0x21a00e02,
+0x34210283,
+0x21a00f03,
+0x34200284,
+0x77400200,
+0x3421c282,
+0x21a00702,
+0x34218283,
+0x21a00083,
+0x34214282,
+0x21a00b02,
+0x4200480c,
+0x00200000,
+0x1c010286,
+0x34220284,
+0x34220302,
+0x0f608203,
+0x5c024204,
+0x3b81810b,
+0x42013c02,
+0x00200000,
+0x18008185,
+0x38808183,
+0x3b814182,
+0x21004e84,
+0x4020007f,
+0x35000100,
+0x000004e0,
+0x000002a0,
+0x000002e8,
+0x00000428,
+0x00000360,
+0x000002e8,
+0x000004a0,
+0x00000468,
+0x000003c8,
+0x00000360,
+0x409ffe02,
+0x30801203,
+0x40800204,
+0x3ec40085,
+0x10009c09,
+0x3ac10606,
+0xb060c105,
+0x4020007f,
+0x4020007f,
+0x20801203,
+0x38810602,
+0xb0408586,
+0x28810602,
+0x32004180,
+0x34204702,
+0x21a00382,
+0x4020007f,
+0x327fdc80,
+0x409ffe02,
+0x30801203,
+0x40800204,
+0x3ec40087,
+0x40800405,
+0x00200000,
+0x40800606,
+0x3ac10608,
+0x3ac14609,
+0x3ac1860a,
+0xb060c107,
+0x20801203,
+0x41004003,
+0x38810602,
+0x4020007f,
+0xb0408188,
+0x4020007f,
+0x28810602,
+0x41201002,
+0x38814603,
+0x10009c09,
+0xb060c109,
+0x4020007f,
+0x28814603,
+0x41193f83,
+0x38818602,
+0x60ffc003,
+0xb040818a,
+0x28818602,
+0x32003080,
+0x409ffe02,
+0x30801203,
+0x40800204,
+0x3ec40087,
+0x41201008,
+0x10009c14,
+0x40800405,
+0x3ac10609,
+0x40800606,
+0x3ac1460a,
+0xb060c107,
+0x3ac1860b,
+0x20801203,
+0x38810602,
+0xb0408409,
+0x28810602,
+0x38814603,
+0xb060c40a,
+0x4020007f,
+0x28814603,
+0x41193f83,
+0x38818602,
+0x60ffc003,
+0xb040818b,
+0x28818602,
+0x32002380,
+0x409ffe02,
+0x30801204,
+0x40800205,
+0x3ec40083,
+0x40800406,
+0x3ac14607,
+0x3ac18608,
+0xb0810103,
+0x41004002,
+0x20801204,
+0x4020007f,
+0x38814603,
+0x10009c0b,
+0xb060c107,
+0x4020007f,
+0x4020007f,
+0x28814603,
+0x38818602,
+0x4020007f,
+0x4020007f,
+0xb0408588,
+0x28818602,
+0x4020007f,
+0x32001780,
+0x409ffe02,
+0x1000640e,
+0x40800204,
+0x30801203,
+0x40800405,
+0x3ec40087,
+0x40800606,
+0x3ac10608,
+0x3ac14609,
+0x3ac1860a,
+0xb060c107,
+0x20801203,
+0x413d8003,
+0x38810602,
+0x4020007f,
+0x327fd780,
+0x409ffe02,
+0x10007f0c,
+0x40800205,
+0x30801204,
+0x40800406,
+0x3ec40083,
+0x3ac14607,
+0x3ac18608,
+0xb0810103,
+0x413d8002,
+0x20801204,
+0x38814603,
+0x4020007f,
+0x327feb80,
+0x409ffe02,
+0x30801203,
+0x40800204,
+0x3ec40087,
+0x40800405,
+0x1000650a,
+0x40800606,
+0x3ac10608,
+0x3ac14609,
+0x3ac1860a,
+0xb060c107,
+0x20801203,
+0x38810602,
+0xb0408588,
+0x4020007f,
+0x327fc980,
+0x00400000,
+0x40800003,
+0x4020007f,
+0x35000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
};
diff --git a/arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped b/arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped
index 39e5400..b9f81ac 100644
--- a/arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped
+++ b/arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped
@@ -3,189 +3,741 @@
* Hex-dump auto generated from spu_save.c.
* Do not edit!
*/
-static unsigned int spu_save_code[] __page_aligned = {
-0x20805000, 0x20805201, 0x20805402, 0x20805603,
-0x20805804, 0x20805a05, 0x20805c06, 0x20805e07,
-0x20806008, 0x20806209, 0x2080640a, 0x2080660b,
-0x2080680c, 0x20806a0d, 0x20806c0e, 0x20806e0f,
-0x4201c003, 0x33800184, 0x1c010204, 0x40200000,
-0x24000190, 0x24004191, 0x24008192, 0x2400c193,
-0x141fc205, 0x23fffd84, 0x1c100183, 0x217ffb85,
-0x40800000, 0x409ff801, 0x24000080, 0x24fd8081,
-0x1cd80081, 0x33000180, 0x00000000, 0x00000000,
-0x01a00182, 0x3ec00083, 0xb1c38103, 0x01a00204,
-0x3ec10082, 0x4201400d, 0xb1c38202, 0x01a00583,
-0x34218682, 0x3ed80684, 0xb0408184, 0x24218682,
-0x01a00603, 0x00200000, 0x34214682, 0x3ed40684,
-0xb0408184, 0x40800003, 0x24214682, 0x21a00083,
-0x40800082, 0x21a00b02, 0x4020007f, 0x1000251e,
-0x40a80002, 0x32800008, 0x4205c00c, 0x00200000,
-0x40a0000b, 0x3f82070f, 0x4080020a, 0x40800709,
-0x3fe3078f, 0x3fbf0783, 0x3f200183, 0x3fbe0183,
-0x3fe30187, 0x18008387, 0x4205c002, 0x3ac30404,
-0x1cffc489, 0x00200000, 0x18008403, 0x38830402,
-0x4cffc486, 0x3ac28185, 0xb0408584, 0x28830402,
-0x1c020408, 0x38828182, 0xb0408385, 0x1802c387,
-0x28828182, 0x217ff886, 0x04000582, 0x32800007,
-0x21a00802, 0x3fbf0705, 0x3f200285, 0x3fbe0285,
-0x3fe30285, 0x21a00885, 0x04000603, 0x21a00903,
-0x40803c02, 0x21a00982, 0x04000386, 0x21a00a06,
-0x40801202, 0x21a00a82, 0x73000003, 0x24200683,
-0x01a00404, 0x00200000, 0x34204682, 0x3ec40683,
-0xb0408203, 0x24204682, 0x01a00783, 0x00200000,
-0x3421c682, 0x3edc0684, 0xb0408184, 0x2421c682,
-0x21a00806, 0x21a00885, 0x3fbf0784, 0x3f200204,
-0x3fbe0204, 0x3fe30204, 0x21a00904, 0x40804002,
-0x21a00982, 0x21a00a06, 0x40805a02, 0x21a00a82,
-0x04000683, 0x21a00803, 0x21a00885, 0x21a00904,
-0x40848002, 0x21a00982, 0x21a00a06, 0x40801002,
-0x21a00a82, 0x21a00a06, 0x40806602, 0x00200000,
-0x35800009, 0x21a00a82, 0x40800083, 0x21a00b83,
-0x01a00c02, 0x01a00d83, 0x00003ffb, 0x40800003,
-0x4020007f, 0x35000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
+static unsigned int spu_save_code[] __attribute__((__aligned__(128))) = {
+0x20805000,
+0x20805201,
+0x20805402,
+0x20805603,
+0x20805804,
+0x20805a05,
+0x20805c06,
+0x20805e07,
+0x20806008,
+0x20806209,
+0x2080640a,
+0x2080660b,
+0x2080680c,
+0x20806a0d,
+0x20806c0e,
+0x20806e0f,
+0x4201c003,
+0x33800184,
+0x1c010204,
+0x40200000,
+0x24000190,
+0x24004191,
+0x24008192,
+0x2400c193,
+0x141fc205,
+0x23fffd84,
+0x1c100183,
+0x217ffb85,
+0x40800000,
+0x409ff801,
+0x24000080,
+0x24fd8081,
+0x1cd80081,
+0x33000180,
+0x00000000,
+0x00000000,
+0x01a00182,
+0x3ec00083,
+0xb1c38103,
+0x01a00204,
+0x3ec10082,
+0x4201400d,
+0xb1c38202,
+0x01a00583,
+0x34218682,
+0x3ed80684,
+0xb0408184,
+0x24218682,
+0x01a00603,
+0x00200000,
+0x34214682,
+0x3ed40684,
+0xb0408184,
+0x40800003,
+0x24214682,
+0x21a00083,
+0x40800082,
+0x21a00b02,
+0x4020007f,
+0x1000251e,
+0x42a00002,
+0x32800008,
+0x4205c00c,
+0x00200000,
+0x40a0000b,
+0x3f82070f,
+0x4080020a,
+0x40800709,
+0x3fe3078f,
+0x3fbf0783,
+0x3f200183,
+0x3fbe0183,
+0x3fe30187,
+0x18008387,
+0x4205c002,
+0x3ac30404,
+0x1cffc489,
+0x00200000,
+0x18008403,
+0x38830402,
+0x4cffc486,
+0x3ac28185,
+0xb0408584,
+0x28830402,
+0x1c020408,
+0x38828182,
+0xb0408385,
+0x1802c387,
+0x28828182,
+0x217ff886,
+0x04000582,
+0x32800007,
+0x21a00802,
+0x3fbf0705,
+0x3f200285,
+0x3fbe0285,
+0x3fe30285,
+0x21a00885,
+0x04000603,
+0x21a00903,
+0x40803c02,
+0x21a00982,
+0x04000386,
+0x21a00a06,
+0x40801202,
+0x21a00a82,
+0x73000003,
+0x24200683,
+0x01a00404,
+0x00200000,
+0x34204682,
+0x3ec40683,
+0xb0408203,
+0x24204682,
+0x01a00783,
+0x00200000,
+0x3421c682,
+0x3edc0684,
+0xb0408184,
+0x2421c682,
+0x21a00806,
+0x21a00885,
+0x3fbf0784,
+0x3f200204,
+0x3fbe0204,
+0x3fe30204,
+0x21a00904,
+0x40804002,
+0x21a00982,
+0x21a00a06,
+0x40805a02,
+0x21a00a82,
+0x04000683,
+0x21a00803,
+0x21a00885,
+0x21a00904,
+0x40848002,
+0x21a00982,
+0x21a00a06,
+0x40801002,
+0x21a00a82,
+0x21a00a06,
+0x40806602,
+0x00200000,
+0x35800009,
+0x21a00a82,
+0x40800083,
+0x21a00b83,
+0x01a00c02,
+0x01a00d83,
+0x00003ffb,
+0x40800003,
+0x4020007f,
+0x35000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
};
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c
index 1726bfe..b30e55d 100644
--- a/arch/powerpc/platforms/cell/spufs/switch.c
+++ b/arch/powerpc/platforms/cell/spufs/switch.c
@@ -46,6 +46,7 @@
#include <asm/io.h>
#include <asm/spu.h>
+#include <asm/spu_priv1.h>
#include <asm/spu_csa.h>
#include <asm/mmu_context.h>
@@ -622,12 +623,17 @@ static inline void save_ppuint_mb(struct spu_state *csa, struct spu *spu)
static inline void save_ch_part1(struct spu_state *csa, struct spu *spu)
{
struct spu_priv2 __iomem *priv2 = spu->priv2;
- u64 idx, ch_indices[7] = { 0UL, 1UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+ u64 idx, ch_indices[7] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
int i;
/* Save, Step 42:
- * Save the following CH: [0,1,3,4,24,25,27]
*/
+
+ /* Save CH 1, without channel count */
+ out_be64(&priv2->spu_chnlcntptr_RW, 1);
+ csa->spu_chnldata_RW[1] = in_be64(&priv2->spu_chnldata_RW);
+
+ /* Save the following CH: [0,3,4,24,25,27] */
for (i = 0; i < 7; i++) {
idx = ch_indices[i];
out_be64(&priv2->spu_chnlcntptr_RW, idx);
@@ -718,13 +724,15 @@ static inline void invalidate_slbs(struct spu_state *csa, struct spu *spu)
static inline void get_kernel_slb(u64 ea, u64 slb[2])
{
- slb[0] = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | SLB_VSID_KERNEL;
- slb[1] = (ea & ESID_MASK) | SLB_ESID_V;
+ u64 llp;
- /* Large pages are used for kernel text/data, but not vmalloc. */
- if (cpu_has_feature(CPU_FTR_16M_PAGE)
- && REGION_ID(ea) == KERNEL_REGION_ID)
- slb[0] |= SLB_VSID_L;
+ if (REGION_ID(ea) == KERNEL_REGION_ID)
+ llp = mmu_psize_defs[mmu_linear_psize].sllp;
+ else
+ llp = mmu_psize_defs[mmu_virtual_psize].sllp;
+ slb[0] = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) |
+ SLB_VSID_KERNEL | llp;
+ slb[1] = (ea & ESID_MASK) | SLB_ESID_V;
}
static inline void load_mfc_slb(struct spu *spu, u64 slb[2], int slbe)
@@ -1103,13 +1111,18 @@ static inline void clear_spu_status(struct spu_state *csa, struct spu *spu)
static inline void reset_ch_part1(struct spu_state *csa, struct spu *spu)
{
struct spu_priv2 __iomem *priv2 = spu->priv2;
- u64 ch_indices[7] = { 0UL, 1UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+ u64 ch_indices[7] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
u64 idx;
int i;
/* Restore, Step 20:
- * Reset the following CH: [0,1,3,4,24,25,27]
*/
+
+ /* Reset CH 1 */
+ out_be64(&priv2->spu_chnlcntptr_RW, 1);
+ out_be64(&priv2->spu_chnldata_RW, 0UL);
+
+ /* Reset the following CH: [0,3,4,24,25,27] */
for (i = 0; i < 7; i++) {
idx = ch_indices[i];
out_be64(&priv2->spu_chnlcntptr_RW, idx);
@@ -1570,12 +1583,17 @@ static inline void restore_decr_wrapped(struct spu_state *csa, struct spu *spu)
static inline void restore_ch_part1(struct spu_state *csa, struct spu *spu)
{
struct spu_priv2 __iomem *priv2 = spu->priv2;
- u64 idx, ch_indices[7] = { 0UL, 1UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+ u64 idx, ch_indices[7] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
int i;
/* Restore, Step 59:
- * Restore the following CH: [0,1,3,4,24,25,27]
*/
+
+ /* Restore CH 1 without count */
+ out_be64(&priv2->spu_chnlcntptr_RW, 1);
+ out_be64(&priv2->spu_chnldata_RW, csa->spu_chnldata_RW[1]);
+
+ /* Restore the following CH: [0,3,4,24,25,27] */
for (i = 0; i < 7; i++) {
idx = ch_indices[i];
out_be64(&priv2->spu_chnlcntptr_RW, idx);
@@ -2074,6 +2092,7 @@ int spu_save(struct spu_state *prev, struct spu *spu)
}
return rc;
}
+EXPORT_SYMBOL_GPL(spu_save);
/**
* spu_restore - SPU context restore, with harvest and locking.
@@ -2090,7 +2109,6 @@ int spu_restore(struct spu_state *new, struct spu *spu)
acquire_spu_lock(spu);
harvest(NULL, spu);
- spu->stop_code = 0;
spu->dar = 0;
spu->dsisr = 0;
spu->slb_replace = 0;
@@ -2103,6 +2121,7 @@ int spu_restore(struct spu_state *new, struct spu *spu)
}
return rc;
}
+EXPORT_SYMBOL_GPL(spu_restore);
/**
* spu_harvest - SPU harvest (reset) operation
@@ -2125,6 +2144,7 @@ static void init_prob(struct spu_state *csa)
csa->spu_chnlcnt_RW[28] = 1;
csa->spu_chnlcnt_RW[30] = 1;
csa->prob.spu_runcntl_RW = SPU_RUNCNTL_STOP;
+ csa->prob.mb_stat_R = 0x000400;
}
static void init_priv1(struct spu_state *csa)
@@ -2193,6 +2213,7 @@ void spu_init_csa(struct spu_state *csa)
init_priv1(csa);
init_priv2(csa);
}
+EXPORT_SYMBOL_GPL(spu_init_csa);
void spu_fini_csa(struct spu_state *csa)
{
@@ -2203,3 +2224,4 @@ void spu_fini_csa(struct spu_state *csa)
vfree(csa->lscsa);
}
+EXPORT_SYMBOL_GPL(spu_fini_csa);
diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile
index ce8c0b9..dee4eb4 100644
--- a/arch/powerpc/platforms/iseries/Makefile
+++ b/arch/powerpc/platforms/iseries/Makefile
@@ -1,9 +1,11 @@
EXTRA_CFLAGS += -mno-minimal-toc
-obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o \
+obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt_mod.o mf.o lpevents.o \
hvcall.o proc.o htab.o iommu.o misc.o irq.o
obj-$(CONFIG_PCI) += pci.o vpdinfo.o
-obj-$(CONFIG_IBMVIO) += vio.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_VIOPATH) += viopath.o
obj-$(CONFIG_MODULES) += ksyms.o
+
+$(obj)/dt_mod.o: $(obj)/dt.o
+ @$(OBJCOPY) --rename-section .rodata.str1.8=.dt_strings $(obj)/dt.o $(obj)/dt_mod.o
diff --git a/arch/powerpc/platforms/iseries/call_pci.h b/arch/powerpc/platforms/iseries/call_pci.h
index 59d4e0a..dbdf698 100644
--- a/arch/powerpc/platforms/iseries/call_pci.h
+++ b/arch/powerpc/platforms/iseries/call_pci.h
@@ -145,6 +145,25 @@ static inline u64 HvCallPci_configLoad16(u16 busNumber, u8 subBusNumber,
return retVal.rc;
}
+static inline u64 HvCallPci_configLoad32(u16 busNumber, u8 subBusNumber,
+ u8 deviceId, u32 offset, u32 *value)
+{
+ struct HvCallPci_DsaAddr dsa;
+ struct HvCallPci_LoadReturn retVal;
+
+ *((u64*)&dsa) = 0;
+
+ dsa.busNumber = busNumber;
+ dsa.subBusNumber = subBusNumber;
+ dsa.deviceId = deviceId;
+
+ HvCall3Ret16(HvCallPciConfigLoad32, &retVal, *(u64 *)&dsa, offset, 0);
+
+ *value = retVal.value;
+
+ return retVal.rc;
+}
+
static inline u64 HvCallPci_configStore8(u16 busNumber, u8 subBusNumber,
u8 deviceId, u32 offset, u8 value)
{
diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c
new file mode 100644
index 0000000..d3444aa
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/dt.c
@@ -0,0 +1,615 @@
+/*
+ * Copyright (c) 2005-2006 Michael Ellerman, IBM Corporation
+ *
+ * Description:
+ * This file contains all the routines to build a flattened device
+ * tree for a legacy iSeries machine.
+ *
+ * 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.
+ */
+
+#undef DEBUG
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_regs.h>
+#include <linux/pci_ids.h>
+#include <linux/threads.h>
+#include <linux/bitops.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/if_ether.h> /* ETH_ALEN */
+
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/lppaca.h>
+#include <asm/cputable.h>
+#include <asm/abs_addr.h>
+#include <asm/system.h>
+#include <asm/iseries/hv_types.h>
+#include <asm/iseries/hv_lp_config.h>
+#include <asm/iseries/hv_call_xm.h>
+#include <asm/iseries/it_exp_vpd_panel.h>
+#include <asm/udbg.h>
+
+#include "processor_vpd.h"
+#include "call_hpt.h"
+#include "call_pci.h"
+#include "pci.h"
+
+#ifdef DEBUG
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+/*
+ * These are created by the linker script at the start and end
+ * of the section containing all the strings from this file.
+ */
+extern char __dt_strings_start[];
+extern char __dt_strings_end[];
+
+struct iseries_flat_dt {
+ struct boot_param_header header;
+ u64 reserve_map[2];
+};
+
+static void * __initdata dt_data;
+
+/*
+ * Putting these strings here keeps them out of the section
+ * that we rename to .dt_strings using objcopy and capture
+ * for the strings blob of the flattened device tree.
+ */
+static char __initdata device_type_cpu[] = "cpu";
+static char __initdata device_type_memory[] = "memory";
+static char __initdata device_type_serial[] = "serial";
+static char __initdata device_type_network[] = "network";
+static char __initdata device_type_block[] = "block";
+static char __initdata device_type_byte[] = "byte";
+static char __initdata device_type_pci[] = "pci";
+static char __initdata device_type_vdevice[] = "vdevice";
+static char __initdata device_type_vscsi[] = "vscsi";
+
+static struct iseries_flat_dt * __init dt_init(void)
+{
+ struct iseries_flat_dt *dt;
+ unsigned long str_len;
+
+ str_len = __dt_strings_end - __dt_strings_start;
+ dt = (struct iseries_flat_dt *)ALIGN(klimit, 8);
+ dt->header.off_mem_rsvmap =
+ offsetof(struct iseries_flat_dt, reserve_map);
+ dt->header.off_dt_strings = ALIGN(sizeof(*dt), 8);
+ dt->header.off_dt_struct = dt->header.off_dt_strings
+ + ALIGN(str_len, 8);
+ dt_data = (void *)((unsigned long)dt + dt->header.off_dt_struct);
+ dt->header.dt_strings_size = str_len;
+
+ /* There is no notion of hardware cpu id on iSeries */
+ dt->header.boot_cpuid_phys = smp_processor_id();
+
+ memcpy((char *)dt + dt->header.off_dt_strings, __dt_strings_start,
+ str_len);
+
+ dt->header.magic = OF_DT_HEADER;
+ dt->header.version = 0x10;
+ dt->header.last_comp_version = 0x10;
+
+ dt->reserve_map[0] = 0;
+ dt->reserve_map[1] = 0;
+
+ return dt;
+}
+
+static void __init dt_push_u32(struct iseries_flat_dt *dt, u32 value)
+{
+ *((u32 *)dt_data) = value;
+ dt_data += sizeof(u32);
+}
+
+#ifdef notyet
+static void __init dt_push_u64(struct iseries_flat_dt *dt, u64 value)
+{
+ *((u64 *)dt_data) = value;
+ dt_data += sizeof(u64);
+}
+#endif
+
+static void __init dt_push_bytes(struct iseries_flat_dt *dt, const char *data,
+ int len)
+{
+ memcpy(dt_data, data, len);
+ dt_data += ALIGN(len, 4);
+}
+
+static void __init dt_start_node(struct iseries_flat_dt *dt, const char *name)
+{
+ dt_push_u32(dt, OF_DT_BEGIN_NODE);
+ dt_push_bytes(dt, name, strlen(name) + 1);
+}
+
+#define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE)
+
+static void __init dt_prop(struct iseries_flat_dt *dt, const char *name,
+ const void *data, int len)
+{
+ unsigned long offset;
+
+ dt_push_u32(dt, OF_DT_PROP);
+
+ /* Length of the data */
+ dt_push_u32(dt, len);
+
+ offset = name - __dt_strings_start;
+
+ /* The offset of the properties name in the string blob. */
+ dt_push_u32(dt, (u32)offset);
+
+ /* The actual data. */
+ dt_push_bytes(dt, data, len);
+}
+
+static void __init dt_prop_str(struct iseries_flat_dt *dt, const char *name,
+ const char *data)
+{
+ dt_prop(dt, name, data, strlen(data) + 1); /* + 1 for NULL */
+}
+
+static void __init dt_prop_u32(struct iseries_flat_dt *dt, const char *name,
+ u32 data)
+{
+ dt_prop(dt, name, &data, sizeof(u32));
+}
+
+#ifdef notyet
+static void __init dt_prop_u64(struct iseries_flat_dt *dt, const char *name,
+ u64 data)
+{
+ dt_prop(dt, name, &data, sizeof(u64));
+}
+#endif
+
+static void __init dt_prop_u64_list(struct iseries_flat_dt *dt,
+ const char *name, u64 *data, int n)
+{
+ dt_prop(dt, name, data, sizeof(u64) * n);
+}
+
+static void __init dt_prop_u32_list(struct iseries_flat_dt *dt,
+ const char *name, u32 *data, int n)
+{
+ dt_prop(dt, name, data, sizeof(u32) * n);
+}
+
+#ifdef notyet
+static void __init dt_prop_empty(struct iseries_flat_dt *dt, const char *name)
+{
+ dt_prop(dt, name, NULL, 0);
+}
+#endif
+
+static void __init dt_cpus(struct iseries_flat_dt *dt)
+{
+ unsigned char buf[32];
+ unsigned char *p;
+ unsigned int i, index;
+ struct IoHriProcessorVpd *d;
+ u32 pft_size[2];
+
+ /* yuck */
+ snprintf(buf, 32, "PowerPC,%s", cur_cpu_spec->cpu_name);
+ p = strchr(buf, ' ');
+ if (!p) p = buf + strlen(buf);
+
+ dt_start_node(dt, "cpus");
+ dt_prop_u32(dt, "#address-cells", 1);
+ dt_prop_u32(dt, "#size-cells", 0);
+
+ pft_size[0] = 0; /* NUMA CEC cookie, 0 for non NUMA */
+ pft_size[1] = __ilog2(HvCallHpt_getHptPages() * HW_PAGE_SIZE);
+
+ for (i = 0; i < NR_CPUS; i++) {
+ if (lppaca[i].dyn_proc_status >= 2)
+ continue;
+
+ snprintf(p, 32 - (p - buf), "@%d", i);
+ dt_start_node(dt, buf);
+
+ dt_prop_str(dt, "device_type", device_type_cpu);
+
+ index = lppaca[i].dyn_hv_phys_proc_index;
+ d = &xIoHriProcessorVpd[index];
+
+ dt_prop_u32(dt, "i-cache-size", d->xInstCacheSize * 1024);
+ dt_prop_u32(dt, "i-cache-line-size", d->xInstCacheOperandSize);
+
+ dt_prop_u32(dt, "d-cache-size", d->xDataL1CacheSizeKB * 1024);
+ dt_prop_u32(dt, "d-cache-line-size", d->xDataCacheOperandSize);
+
+ /* magic conversions to Hz copied from old code */
+ dt_prop_u32(dt, "clock-frequency",
+ ((1UL << 34) * 1000000) / d->xProcFreq);
+ dt_prop_u32(dt, "timebase-frequency",
+ ((1UL << 32) * 1000000) / d->xTimeBaseFreq);
+
+ dt_prop_u32(dt, "reg", i);
+
+ dt_prop_u32_list(dt, "ibm,pft-size", pft_size, 2);
+
+ dt_end_node(dt);
+ }
+
+ dt_end_node(dt);
+}
+
+static void __init dt_model(struct iseries_flat_dt *dt)
+{
+ char buf[16] = "IBM,";
+
+ /* "IBM," + mfgId[2:3] + systemSerial[1:5] */
+ strne2a(buf + 4, xItExtVpdPanel.mfgID + 2, 2);
+ strne2a(buf + 6, xItExtVpdPanel.systemSerial + 1, 5);
+ buf[11] = '\0';
+ dt_prop_str(dt, "system-id", buf);
+
+ /* "IBM," + machineType[0:4] */
+ strne2a(buf + 4, xItExtVpdPanel.machineType, 4);
+ buf[8] = '\0';
+ dt_prop_str(dt, "model", buf);
+
+ dt_prop_str(dt, "compatible", "IBM,iSeries");
+}
+
+static void __init dt_do_vdevice(struct iseries_flat_dt *dt,
+ const char *name, u32 reg, int unit,
+ const char *type, const char *compat, int end)
+{
+ char buf[32];
+
+ snprintf(buf, 32, "%s@%08x", name, reg + ((unit >= 0) ? unit : 0));
+ dt_start_node(dt, buf);
+ dt_prop_str(dt, "device_type", type);
+ if (compat)
+ dt_prop_str(dt, "compatible", compat);
+ dt_prop_u32(dt, "reg", reg + ((unit >= 0) ? unit : 0));
+ if (unit >= 0)
+ dt_prop_u32(dt, "linux,unit_address", unit);
+ if (end)
+ dt_end_node(dt);
+}
+
+static void __init dt_vdevices(struct iseries_flat_dt *dt)
+{
+ u32 reg = 0;
+ HvLpIndexMap vlan_map;
+ int i;
+
+ dt_start_node(dt, "vdevice");
+ dt_prop_str(dt, "device_type", device_type_vdevice);
+ dt_prop_str(dt, "compatible", "IBM,iSeries-vdevice");
+ dt_prop_u32(dt, "#address-cells", 1);
+ dt_prop_u32(dt, "#size-cells", 0);
+
+ dt_do_vdevice(dt, "vty", reg, -1, device_type_serial, NULL, 1);
+ reg++;
+
+ dt_do_vdevice(dt, "v-scsi", reg, -1, device_type_vscsi,
+ "IBM,v-scsi", 1);
+ reg++;
+
+ vlan_map = HvLpConfig_getVirtualLanIndexMap();
+ for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
+ unsigned char mac_addr[ETH_ALEN];
+
+ if ((vlan_map & (0x8000 >> i)) == 0)
+ continue;
+ dt_do_vdevice(dt, "l-lan", reg, i, device_type_network,
+ "IBM,iSeries-l-lan", 0);
+ mac_addr[0] = 0x02;
+ mac_addr[1] = 0x01;
+ mac_addr[2] = 0xff;
+ mac_addr[3] = i;
+ mac_addr[4] = 0xff;
+ mac_addr[5] = HvLpConfig_getLpIndex_outline();
+ dt_prop(dt, "local-mac-address", (char *)mac_addr, ETH_ALEN);
+ dt_prop(dt, "mac-address", (char *)mac_addr, ETH_ALEN);
+ dt_prop_u32(dt, "max-frame-size", 9000);
+ dt_prop_u32(dt, "address-bits", 48);
+
+ dt_end_node(dt);
+ }
+ reg += HVMAXARCHITECTEDVIRTUALLANS;
+
+ for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++)
+ dt_do_vdevice(dt, "viodasd", reg, i, device_type_block,
+ "IBM,iSeries-viodasd", 1);
+ reg += HVMAXARCHITECTEDVIRTUALDISKS;
+
+ for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++)
+ dt_do_vdevice(dt, "viocd", reg, i, device_type_block,
+ "IBM,iSeries-viocd", 1);
+ reg += HVMAXARCHITECTEDVIRTUALCDROMS;
+
+ for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++)
+ dt_do_vdevice(dt, "viotape", reg, i, device_type_byte,
+ "IBM,iSeries-viotape", 1);
+
+ dt_end_node(dt);
+}
+
+struct pci_class_name {
+ u16 code;
+ const char *name;
+ const char *type;
+};
+
+static struct pci_class_name __initdata pci_class_name[] = {
+ { PCI_CLASS_NETWORK_ETHERNET, "ethernet", device_type_network },
+};
+
+static struct pci_class_name * __init dt_find_pci_class_name(u16 class_code)
+{
+ struct pci_class_name *cp;
+
+ for (cp = pci_class_name;
+ cp < &pci_class_name[ARRAY_SIZE(pci_class_name)]; cp++)
+ if (cp->code == class_code)
+ return cp;
+ return NULL;
+}
+
+/*
+ * This assumes that the node slot is always on the primary bus!
+ */
+static void __init scan_bridge_slot(struct iseries_flat_dt *dt,
+ HvBusNumber bus, struct HvCallPci_BridgeInfo *bridge_info)
+{
+ HvSubBusNumber sub_bus = bridge_info->subBusNumber;
+ u16 vendor_id;
+ u16 device_id;
+ u32 class_id;
+ int err;
+ char buf[32];
+ u32 reg[5];
+ int id_sel = ISERIES_GET_DEVICE_FROM_SUBBUS(sub_bus);
+ int function = ISERIES_GET_FUNCTION_FROM_SUBBUS(sub_bus);
+ HvAgentId eads_id_sel = ISERIES_PCI_AGENTID(id_sel, function);
+ u8 devfn;
+ struct pci_class_name *cp;
+
+ /*
+ * Connect all functions of any device found.
+ */
+ for (id_sel = 1; id_sel <= bridge_info->maxAgents; id_sel++) {
+ for (function = 0; function < 8; function++) {
+ HvAgentId agent_id = ISERIES_PCI_AGENTID(id_sel,
+ function);
+ err = HvCallXm_connectBusUnit(bus, sub_bus,
+ agent_id, 0);
+ if (err) {
+ if (err != 0x302)
+ DBG("connectBusUnit(%x, %x, %x) %x\n",
+ bus, sub_bus, agent_id, err);
+ continue;
+ }
+
+ err = HvCallPci_configLoad16(bus, sub_bus, agent_id,
+ PCI_VENDOR_ID, &vendor_id);
+ if (err) {
+ DBG("ReadVendor(%x, %x, %x) %x\n",
+ bus, sub_bus, agent_id, err);
+ continue;
+ }
+ err = HvCallPci_configLoad16(bus, sub_bus, agent_id,
+ PCI_DEVICE_ID, &device_id);
+ if (err) {
+ DBG("ReadDevice(%x, %x, %x) %x\n",
+ bus, sub_bus, agent_id, err);
+ continue;
+ }
+ err = HvCallPci_configLoad32(bus, sub_bus, agent_id,
+ PCI_CLASS_REVISION , &class_id);
+ if (err) {
+ DBG("ReadClass(%x, %x, %x) %x\n",
+ bus, sub_bus, agent_id, err);
+ continue;
+ }
+
+ devfn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(eads_id_sel),
+ function);
+ cp = dt_find_pci_class_name(class_id >> 16);
+ if (cp && cp->name)
+ strncpy(buf, cp->name, sizeof(buf) - 1);
+ else
+ snprintf(buf, sizeof(buf), "pci%x,%x",
+ vendor_id, device_id);
+ buf[sizeof(buf) - 1] = '\0';
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+ "@%x", PCI_SLOT(devfn));
+ buf[sizeof(buf) - 1] = '\0';
+ if (function != 0)
+ snprintf(buf + strlen(buf),
+ sizeof(buf) - strlen(buf),
+ ",%x", function);
+ dt_start_node(dt, buf);
+ reg[0] = (bus << 16) | (devfn << 8);
+ reg[1] = 0;
+ reg[2] = 0;
+ reg[3] = 0;
+ reg[4] = 0;
+ dt_prop_u32_list(dt, "reg", reg, 5);
+ if (cp && (cp->type || cp->name))
+ dt_prop_str(dt, "device_type",
+ cp->type ? cp->type : cp->name);
+ dt_prop_u32(dt, "vendor-id", vendor_id);
+ dt_prop_u32(dt, "device-id", device_id);
+ dt_prop_u32(dt, "class-code", class_id >> 8);
+ dt_prop_u32(dt, "revision-id", class_id & 0xff);
+ dt_prop_u32(dt, "linux,subbus", sub_bus);
+ dt_prop_u32(dt, "linux,agent-id", agent_id);
+ dt_prop_u32(dt, "linux,logical-slot-number",
+ bridge_info->logicalSlotNumber);
+ dt_end_node(dt);
+
+ }
+ }
+}
+
+static void __init scan_bridge(struct iseries_flat_dt *dt, HvBusNumber bus,
+ HvSubBusNumber sub_bus, int id_sel)
+{
+ struct HvCallPci_BridgeInfo bridge_info;
+ HvAgentId agent_id;
+ int function;
+ int ret;
+
+ /* Note: hvSubBus and irq is always be 0 at this level! */
+ for (function = 0; function < 8; ++function) {
+ agent_id = ISERIES_PCI_AGENTID(id_sel, function);
+ ret = HvCallXm_connectBusUnit(bus, sub_bus, agent_id, 0);
+ if (ret != 0) {
+ if (ret != 0xb)
+ DBG("connectBusUnit(%x, %x, %x) %x\n",
+ bus, sub_bus, agent_id, ret);
+ continue;
+ }
+ DBG("found device at bus %d idsel %d func %d (AgentId %x)\n",
+ bus, id_sel, function, agent_id);
+ ret = HvCallPci_getBusUnitInfo(bus, sub_bus, agent_id,
+ iseries_hv_addr(&bridge_info),
+ sizeof(struct HvCallPci_BridgeInfo));
+ if (ret != 0)
+ continue;
+ DBG("bridge info: type %x subbus %x "
+ "maxAgents %x maxsubbus %x logslot %x\n",
+ bridge_info.busUnitInfo.deviceType,
+ bridge_info.subBusNumber,
+ bridge_info.maxAgents,
+ bridge_info.maxSubBusNumber,
+ bridge_info.logicalSlotNumber);
+ if (bridge_info.busUnitInfo.deviceType ==
+ HvCallPci_BridgeDevice)
+ scan_bridge_slot(dt, bus, &bridge_info);
+ else
+ DBG("PCI: Invalid Bridge Configuration(0x%02X)",
+ bridge_info.busUnitInfo.deviceType);
+ }
+}
+
+static void __init scan_phb(struct iseries_flat_dt *dt, HvBusNumber bus)
+{
+ struct HvCallPci_DeviceInfo dev_info;
+ const HvSubBusNumber sub_bus = 0; /* EADs is always 0. */
+ int err;
+ int id_sel;
+ const int max_agents = 8;
+
+ /*
+ * Probe for EADs Bridges
+ */
+ for (id_sel = 1; id_sel < max_agents; ++id_sel) {
+ err = HvCallPci_getDeviceInfo(bus, sub_bus, id_sel,
+ iseries_hv_addr(&dev_info),
+ sizeof(struct HvCallPci_DeviceInfo));
+ if (err) {
+ if (err != 0x302)
+ DBG("getDeviceInfo(%x, %x, %x) %x\n",
+ bus, sub_bus, id_sel, err);
+ continue;
+ }
+ if (dev_info.deviceType != HvCallPci_NodeDevice) {
+ DBG("PCI: Invalid System Configuration"
+ "(0x%02X) for bus 0x%02x id 0x%02x.\n",
+ dev_info.deviceType, bus, id_sel);
+ continue;
+ }
+ scan_bridge(dt, bus, sub_bus, id_sel);
+ }
+}
+
+static void __init dt_pci_devices(struct iseries_flat_dt *dt)
+{
+ HvBusNumber bus;
+ char buf[32];
+ u32 buses[2];
+ int phb_num = 0;
+
+ /* Check all possible buses. */
+ for (bus = 0; bus < 256; bus++) {
+ int err = HvCallXm_testBus(bus);
+
+ if (err) {
+ /*
+ * Check for Unexpected Return code, a clue that
+ * something has gone wrong.
+ */
+ if (err != 0x0301)
+ DBG("Unexpected Return on Probe(0x%02X) "
+ "0x%04X\n", bus, err);
+ continue;
+ }
+ DBG("bus %d appears to exist\n", bus);
+ snprintf(buf, 32, "pci@%d", phb_num);
+ dt_start_node(dt, buf);
+ dt_prop_str(dt, "device_type", device_type_pci);
+ dt_prop_str(dt, "compatible", "IBM,iSeries-Logical-PHB");
+ dt_prop_u32(dt, "#address-cells", 3);
+ dt_prop_u32(dt, "#size-cells", 2);
+ buses[0] = buses[1] = bus;
+ dt_prop_u32_list(dt, "bus-range", buses, 2);
+ scan_phb(dt, bus);
+ dt_end_node(dt);
+ phb_num++;
+ }
+}
+
+static void dt_finish(struct iseries_flat_dt *dt)
+{
+ dt_push_u32(dt, OF_DT_END);
+ dt->header.totalsize = (unsigned long)dt_data - (unsigned long)dt;
+ klimit = ALIGN((unsigned long)dt_data, 8);
+}
+
+void * __init build_flat_dt(unsigned long phys_mem_size)
+{
+ struct iseries_flat_dt *iseries_dt;
+ u64 tmp[2];
+
+ iseries_dt = dt_init();
+
+ dt_start_node(iseries_dt, "");
+
+ dt_prop_u32(iseries_dt, "#address-cells", 2);
+ dt_prop_u32(iseries_dt, "#size-cells", 2);
+ dt_model(iseries_dt);
+
+ /* /memory */
+ dt_start_node(iseries_dt, "memory@0");
+ dt_prop_str(iseries_dt, "device_type", device_type_memory);
+ tmp[0] = 0;
+ tmp[1] = phys_mem_size;
+ dt_prop_u64_list(iseries_dt, "reg", tmp, 2);
+ dt_end_node(iseries_dt);
+
+ /* /chosen */
+ dt_start_node(iseries_dt, "chosen");
+ dt_prop_str(iseries_dt, "bootargs", cmd_line);
+ dt_end_node(iseries_dt);
+
+ dt_cpus(iseries_dt);
+
+ dt_vdevices(iseries_dt);
+ dt_pci_devices(iseries_dt);
+
+ dt_end_node(iseries_dt);
+
+ dt_finish(iseries_dt);
+
+ return iseries_dt;
+}
diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c
index bea0b70..e3bd201 100644
--- a/arch/powerpc/platforms/iseries/iommu.c
+++ b/arch/powerpc/platforms/iseries/iommu.c
@@ -4,6 +4,7 @@
* Rewrite, cleanup:
*
* Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation
+ * Copyright (C) 2006 Olof Johansson <olof@lixom.net>
*
* Dynamic DMA mapping support, iSeries-specific parts.
*
@@ -31,42 +32,37 @@
#include <asm/tce.h>
#include <asm/machdep.h>
#include <asm/abs_addr.h>
+#include <asm/prom.h>
#include <asm/pci-bridge.h>
#include <asm/iseries/hv_call_xm.h>
-
-#include "iommu.h"
-
-extern struct list_head iSeries_Global_Device_List;
-
+#include <asm/iseries/iommu.h>
static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages,
unsigned long uaddr, enum dma_data_direction direction)
{
u64 rc;
- union tce_entry tce;
+ u64 tce, rpn;
index <<= TCE_PAGE_FACTOR;
npages <<= TCE_PAGE_FACTOR;
while (npages--) {
- tce.te_word = 0;
- tce.te_bits.tb_rpn = virt_to_abs(uaddr) >> TCE_SHIFT;
+ rpn = virt_to_abs(uaddr) >> TCE_SHIFT;
+ tce = (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT;
if (tbl->it_type == TCE_VB) {
/* Virtual Bus */
- tce.te_bits.tb_valid = 1;
- tce.te_bits.tb_allio = 1;
+ tce |= TCE_VALID|TCE_ALLIO;
if (direction != DMA_TO_DEVICE)
- tce.te_bits.tb_rdwr = 1;
+ tce |= TCE_VB_WRITE;
} else {
/* PCI Bus */
- tce.te_bits.tb_rdwr = 1; /* Read allowed */
+ tce |= TCE_PCI_READ; /* Read allowed */
if (direction != DMA_TO_DEVICE)
- tce.te_bits.tb_pciwr = 1;
+ tce |= TCE_PCI_WRITE;
}
- rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index,
- tce.te_word);
+ rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, tce);
if (rc)
panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n",
rc);
@@ -124,7 +120,7 @@ void iommu_table_getparms_iSeries(unsigned long busno,
/* itc_size is in pages worth of table, it_size is in # of entries */
tbl->it_size = ((parms->itc_size * TCE_PAGE_SIZE) /
- sizeof(union tce_entry)) >> TCE_PAGE_FACTOR;
+ TCE_ENTRY_SIZE) >> TCE_PAGE_FACTOR;
tbl->it_busno = parms->itc_busno;
tbl->it_offset = parms->itc_offset >> TCE_PAGE_FACTOR;
tbl->it_index = parms->itc_index;
@@ -142,10 +138,15 @@ void iommu_table_getparms_iSeries(unsigned long busno,
*/
static struct iommu_table *iommu_table_find(struct iommu_table * tbl)
{
- struct pci_dn *pdn;
+ struct device_node *node;
- list_for_each_entry(pdn, &iSeries_Global_Device_List, Device_List) {
- struct iommu_table *it = pdn->iommu_table;
+ for (node = NULL; (node = of_find_all_nodes(node)); ) {
+ struct pci_dn *pdn = PCI_DN(node);
+ struct iommu_table *it;
+
+ if (pdn == NULL)
+ continue;
+ it = pdn->iommu_table;
if ((it != NULL) &&
(it->it_type == TCE_PCI) &&
(it->it_offset == tbl->it_offset) &&
@@ -161,15 +162,18 @@ void iommu_devnode_init_iSeries(struct device_node *dn)
{
struct iommu_table *tbl;
struct pci_dn *pdn = PCI_DN(dn);
+ u32 *lsn = (u32 *)get_property(dn, "linux,logical-slot-number", NULL);
+
+ BUG_ON(lsn == NULL);
tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
- iommu_table_getparms_iSeries(pdn->busno, pdn->LogicalSlot, 0, tbl);
+ iommu_table_getparms_iSeries(pdn->busno, *lsn, 0, tbl);
/* Look for existing tce table */
pdn->iommu_table = iommu_table_find(tbl);
if (pdn->iommu_table == NULL)
- pdn->iommu_table = iommu_init_table(tbl);
+ pdn->iommu_table = iommu_init_table(tbl, -1);
else
kfree(tbl);
}
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
index be3fbfc..62bbbcf 100644
--- a/arch/powerpc/platforms/iseries/irq.c
+++ b/arch/powerpc/platforms/iseries/irq.c
@@ -42,6 +42,7 @@
#include <asm/iseries/it_lp_queue.h>
#include "irq.h"
+#include "pci.h"
#include "call_pci.h"
#if defined(CONFIG_SMP)
@@ -312,12 +313,12 @@ static hw_irq_controller iSeries_IRQ_handler = {
* Note that sub_bus is always 0 (at the moment at least).
*/
int __init iSeries_allocate_IRQ(HvBusNumber bus,
- HvSubBusNumber sub_bus, HvAgentId dev_id)
+ HvSubBusNumber sub_bus, u32 bsubbus)
{
int virtirq;
unsigned int realirq;
- u8 idsel = (dev_id >> 4);
- u8 function = dev_id & 7;
+ u8 idsel = ISERIES_GET_DEVICE_FROM_SUBBUS(bsubbus);
+ u8 function = ISERIES_GET_FUNCTION_FROM_SUBBUS(bsubbus);
realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3)
+ function;
diff --git a/arch/powerpc/platforms/iseries/irq.h b/arch/powerpc/platforms/iseries/irq.h
index b9c801b..188aa80 100644
--- a/arch/powerpc/platforms/iseries/irq.h
+++ b/arch/powerpc/platforms/iseries/irq.h
@@ -2,7 +2,7 @@
#define _ISERIES_IRQ_H
extern void iSeries_init_IRQ(void);
-extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, HvAgentId);
+extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, u32);
extern void iSeries_activate_IRQs(void);
extern int iSeries_get_irq(struct pt_regs *);
diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c
index d771b8e..1a2c2a5 100644
--- a/arch/powerpc/platforms/iseries/mf.c
+++ b/arch/powerpc/platforms/iseries/mf.c
@@ -45,7 +45,6 @@
#include "setup.h"
-extern int piranha_simulator;
static int mf_initialized;
/*
@@ -658,7 +657,7 @@ static void mf_clear_src(void)
void __init mf_display_progress(u16 value)
{
- if (piranha_simulator || !mf_initialized)
+ if (!mf_initialized)
return;
if (0xFFFF == value)
@@ -1295,9 +1294,6 @@ __initcall(mf_proc_init);
*/
void iSeries_get_rtc_time(struct rtc_time *rtc_tm)
{
- if (piranha_simulator)
- return;
-
mf_get_rtc(rtc_tm);
rtc_tm->tm_mon--;
}
@@ -1316,9 +1312,6 @@ unsigned long iSeries_get_boot_time(void)
{
struct rtc_time tm;
- if (piranha_simulator)
- return 0;
-
mf_get_boot_rtc(&tm);
return mktime(tm.tm_year + 1900, tm.tm_mon, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
index a19833b..35bcc98 100644
--- a/arch/powerpc/platforms/iseries/pci.c
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -37,36 +37,18 @@
#include <asm/iseries/hv_call_xm.h>
#include <asm/iseries/mf.h>
+#include <asm/iseries/iommu.h>
#include <asm/ppc-pci.h>
#include "irq.h"
#include "pci.h"
#include "call_pci.h"
-#include "iommu.h"
-
-extern unsigned long io_page_mask;
/*
* Forward declares of prototypes.
*/
static struct device_node *find_Device_Node(int bus, int devfn);
-static void scan_PHB_slots(struct pci_controller *Phb);
-static void scan_EADS_bridge(HvBusNumber Bus, HvSubBusNumber SubBus, int IdSel);
-static int scan_bridge_slot(HvBusNumber Bus, struct HvCallPci_BridgeInfo *Info);
-
-LIST_HEAD(iSeries_Global_Device_List);
-
-static int DeviceCount;
-
-/* Counters and control flags. */
-static long Pci_Io_Read_Count;
-static long Pci_Io_Write_Count;
-#if 0
-static long Pci_Cfg_Read_Count;
-static long Pci_Cfg_Write_Count;
-#endif
-static long Pci_Error_Count;
static int Pci_Retry_Max = 3; /* Only retry 3 times */
static int Pci_Error_Flag = 1; /* Set Retry Error on. */
@@ -81,41 +63,19 @@ static struct pci_ops iSeries_pci_ops;
#define IOMM_TABLE_ENTRY_SIZE 0x0000000000400000UL
#define BASE_IO_MEMORY 0xE000000000000000UL
-static unsigned long max_io_memory = 0xE000000000000000UL;
+static unsigned long max_io_memory = BASE_IO_MEMORY;
static long current_iomm_table_entry;
/*
* Lookup Tables.
*/
-static struct device_node **iomm_table;
-static u8 *iobar_table;
+static struct device_node *iomm_table[IOMM_TABLE_MAX_ENTRIES];
+static u8 iobar_table[IOMM_TABLE_MAX_ENTRIES];
-/*
- * Static and Global variables
- */
-static char *pci_io_text = "iSeries PCI I/O";
+static const char pci_io_text[] = "iSeries PCI I/O";
static DEFINE_SPINLOCK(iomm_table_lock);
/*
- * iomm_table_initialize
- *
- * Allocates and initalizes the Address Translation Table and Bar
- * Tables to get them ready for use. Must be called before any
- * I/O space is handed out to the device BARs.
- */
-static void iomm_table_initialize(void)
-{
- spin_lock(&iomm_table_lock);
- iomm_table = kmalloc(sizeof(*iomm_table) * IOMM_TABLE_MAX_ENTRIES,
- GFP_KERNEL);
- iobar_table = kmalloc(sizeof(*iobar_table) * IOMM_TABLE_MAX_ENTRIES,
- GFP_KERNEL);
- spin_unlock(&iomm_table_lock);
- if ((iomm_table == NULL) || (iobar_table == NULL))
- panic("PCI: I/O tables allocation failed.\n");
-}
-
-/*
* iomm_table_allocate_entry
*
* Adds pci_dev entry in address translation table
@@ -142,9 +102,8 @@ static void iomm_table_allocate_entry(struct pci_dev *dev, int bar_num)
*/
spin_lock(&iomm_table_lock);
bar_res->name = pci_io_text;
- bar_res->start =
+ bar_res->start = BASE_IO_MEMORY +
IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry;
- bar_res->start += BASE_IO_MEMORY;
bar_res->end = bar_res->start + bar_size - 1;
/*
* Allocate the number of table entries needed for BAR.
@@ -156,7 +115,7 @@ static void iomm_table_allocate_entry(struct pci_dev *dev, int bar_num)
++current_iomm_table_entry;
}
max_io_memory = BASE_IO_MEMORY +
- (IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry);
+ IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry;
spin_unlock(&iomm_table_lock);
}
@@ -173,13 +132,10 @@ static void iomm_table_allocate_entry(struct pci_dev *dev, int bar_num)
*/
static void allocate_device_bars(struct pci_dev *dev)
{
- struct resource *bar_res;
int bar_num;
- for (bar_num = 0; bar_num <= PCI_ROM_RESOURCE; ++bar_num) {
- bar_res = &dev->resource[bar_num];
+ for (bar_num = 0; bar_num <= PCI_ROM_RESOURCE; ++bar_num)
iomm_table_allocate_entry(dev, bar_num);
- }
}
/*
@@ -199,34 +155,7 @@ static void pci_Log_Error(char *Error_Text, int Bus, int SubBus,
}
/*
- * build_device_node(u16 Bus, int SubBus, u8 DevFn)
- */
-static struct device_node *build_device_node(HvBusNumber Bus,
- HvSubBusNumber SubBus, int AgentId, int Function)
-{
- struct device_node *node;
- struct pci_dn *pdn;
-
- node = kmalloc(sizeof(struct device_node), GFP_KERNEL);
- if (node == NULL)
- return NULL;
- memset(node, 0, sizeof(struct device_node));
- pdn = kzalloc(sizeof(*pdn), GFP_KERNEL);
- if (pdn == NULL) {
- kfree(node);
- return NULL;
- }
- node->data = pdn;
- pdn->node = node;
- list_add_tail(&pdn->Device_List, &iSeries_Global_Device_List);
- pdn->busno = Bus;
- pdn->bussubno = SubBus;
- pdn->devfn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(AgentId), Function);
- return node;
-}
-
-/*
- * unsigned long __init find_and_init_phbs(void)
+ * iSeries_pcibios_init
*
* Description:
* This function checks for all possible system PCI host bridges that connect
@@ -234,50 +163,42 @@ static struct device_node *build_device_node(HvBusNumber Bus,
* ownership status. A pci_controller is built for any bus which is partially
* owned or fully owned by this guest partition.
*/
-unsigned long __init find_and_init_phbs(void)
+void iSeries_pcibios_init(void)
{
struct pci_controller *phb;
- HvBusNumber bus;
-
- /* Check all possible buses. */
- for (bus = 0; bus < 256; bus++) {
- int ret = HvCallXm_testBus(bus);
- if (ret == 0) {
- printk("bus %d appears to exist\n", bus);
+ struct device_node *root = of_find_node_by_path("/");
+ struct device_node *node = NULL;
- phb = pcibios_alloc_controller(NULL);
- if (phb == NULL)
- return -ENOMEM;
-
- phb->pci_mem_offset = phb->local_number = bus;
- phb->first_busno = bus;
- phb->last_busno = bus;
- phb->ops = &iSeries_pci_ops;
-
- /* Find and connect the devices. */
- scan_PHB_slots(phb);
- }
- /*
- * Check for Unexpected Return code, a clue that something
- * has gone wrong.
- */
- else if (ret != 0x0301)
- printk(KERN_ERR "Unexpected Return on Probe(0x%04X): 0x%04X",
- bus, ret);
+ if (root == NULL) {
+ printk(KERN_CRIT "iSeries_pcibios_init: can't find root "
+ "of device tree\n");
+ return;
+ }
+ while ((node = of_get_next_child(root, node)) != NULL) {
+ HvBusNumber bus;
+ u32 *busp;
+
+ if ((node->type == NULL) || (strcmp(node->type, "pci") != 0))
+ continue;
+
+ busp = (u32 *)get_property(node, "bus-range", NULL);
+ if (busp == NULL)
+ continue;
+ bus = *busp;
+ printk("bus %d appears to exist\n", bus);
+ phb = pcibios_alloc_controller(node);
+ if (phb == NULL)
+ continue;
+
+ phb->pci_mem_offset = phb->local_number = bus;
+ phb->first_busno = bus;
+ phb->last_busno = bus;
+ phb->ops = &iSeries_pci_ops;
}
- return 0;
-}
-/*
- * iSeries_pcibios_init
- *
- * Chance to initialize and structures or variable before PCI Bus walk.
- */
-void iSeries_pcibios_init(void)
-{
- iomm_table_initialize();
- find_and_init_phbs();
- io_page_mask = -1;
+ of_node_put(root);
+
+ pci_devs_phb_init();
}
/*
@@ -299,6 +220,34 @@ void __init iSeries_pci_final_fixup(void)
pdev->bus->number, pdev->devfn, node);
if (node != NULL) {
+ struct pci_dn *pdn = PCI_DN(node);
+ u32 *agent;
+
+ agent = (u32 *)get_property(node, "linux,agent-id",
+ NULL);
+ if ((pdn != NULL) && (agent != NULL)) {
+ u8 irq = iSeries_allocate_IRQ(pdn->busno, 0,
+ pdn->bussubno);
+ int err;
+
+ err = HvCallXm_connectBusUnit(pdn->busno, pdn->bussubno,
+ *agent, irq);
+ if (err)
+ pci_Log_Error("Connect Bus Unit",
+ pdn->busno, pdn->bussubno, *agent, err);
+ else {
+ err = HvCallPci_configStore8(pdn->busno, pdn->bussubno,
+ *agent,
+ PCI_INTERRUPT_LINE,
+ irq);
+ if (err)
+ pci_Log_Error("PciCfgStore Irq Failed!",
+ pdn->busno, pdn->bussubno, *agent, err);
+ }
+ if (!err)
+ pdev->irq = irq;
+ }
+
++DeviceCount;
pdev->sysdata = (void *)node;
PCI_DN(node)->pcidev = pdev;
@@ -308,7 +257,6 @@ void __init iSeries_pci_final_fixup(void)
} else
printk("PCI: Device Tree not found for 0x%016lX\n",
(unsigned long)pdev);
- pdev->irq = PCI_DN(node)->Irq;
}
iSeries_activate_IRQs();
mf_display_src(0xC9000200);
@@ -323,148 +271,6 @@ void pcibios_fixup_resources(struct pci_dev *pdev)
}
/*
- * Loop through each node function to find usable EADs bridges.
- */
-static void scan_PHB_slots(struct pci_controller *Phb)
-{
- struct HvCallPci_DeviceInfo *DevInfo;
- HvBusNumber bus = Phb->local_number; /* System Bus */
- const HvSubBusNumber SubBus = 0; /* EADs is always 0. */
- int HvRc = 0;
- int IdSel;
- const int MaxAgents = 8;
-
- DevInfo = (struct HvCallPci_DeviceInfo*)
- kmalloc(sizeof(struct HvCallPci_DeviceInfo), GFP_KERNEL);
- if (DevInfo == NULL)
- return;
-
- /*
- * Probe for EADs Bridges
- */
- for (IdSel = 1; IdSel < MaxAgents; ++IdSel) {
- HvRc = HvCallPci_getDeviceInfo(bus, SubBus, IdSel,
- iseries_hv_addr(DevInfo),
- sizeof(struct HvCallPci_DeviceInfo));
- if (HvRc == 0) {
- if (DevInfo->deviceType == HvCallPci_NodeDevice)
- scan_EADS_bridge(bus, SubBus, IdSel);
- else
- printk("PCI: Invalid System Configuration(0x%02X)"
- " for bus 0x%02x id 0x%02x.\n",
- DevInfo->deviceType, bus, IdSel);
- }
- else
- pci_Log_Error("getDeviceInfo", bus, SubBus, IdSel, HvRc);
- }
- kfree(DevInfo);
-}
-
-static void scan_EADS_bridge(HvBusNumber bus, HvSubBusNumber SubBus,
- int IdSel)
-{
- struct HvCallPci_BridgeInfo *BridgeInfo;
- HvAgentId AgentId;
- int Function;
- int HvRc;
-
- BridgeInfo = (struct HvCallPci_BridgeInfo *)
- kmalloc(sizeof(struct HvCallPci_BridgeInfo), GFP_KERNEL);
- if (BridgeInfo == NULL)
- return;
-
- /* Note: hvSubBus and irq is always be 0 at this level! */
- for (Function = 0; Function < 8; ++Function) {
- AgentId = ISERIES_PCI_AGENTID(IdSel, Function);
- HvRc = HvCallXm_connectBusUnit(bus, SubBus, AgentId, 0);
- if (HvRc == 0) {
- printk("found device at bus %d idsel %d func %d (AgentId %x)\n",
- bus, IdSel, Function, AgentId);
- /* Connect EADs: 0x18.00.12 = 0x00 */
- HvRc = HvCallPci_getBusUnitInfo(bus, SubBus, AgentId,
- iseries_hv_addr(BridgeInfo),
- sizeof(struct HvCallPci_BridgeInfo));
- if (HvRc == 0) {
- printk("bridge info: type %x subbus %x maxAgents %x maxsubbus %x logslot %x\n",
- BridgeInfo->busUnitInfo.deviceType,
- BridgeInfo->subBusNumber,
- BridgeInfo->maxAgents,
- BridgeInfo->maxSubBusNumber,
- BridgeInfo->logicalSlotNumber);
- if (BridgeInfo->busUnitInfo.deviceType ==
- HvCallPci_BridgeDevice) {
- /* Scan_Bridge_Slot...: 0x18.00.12 */
- scan_bridge_slot(bus, BridgeInfo);
- } else
- printk("PCI: Invalid Bridge Configuration(0x%02X)",
- BridgeInfo->busUnitInfo.deviceType);
- }
- } else if (HvRc != 0x000B)
- pci_Log_Error("EADs Connect",
- bus, SubBus, AgentId, HvRc);
- }
- kfree(BridgeInfo);
-}
-
-/*
- * This assumes that the node slot is always on the primary bus!
- */
-static int scan_bridge_slot(HvBusNumber Bus,
- struct HvCallPci_BridgeInfo *BridgeInfo)
-{
- struct device_node *node;
- HvSubBusNumber SubBus = BridgeInfo->subBusNumber;
- u16 VendorId = 0;
- int HvRc = 0;
- u8 Irq = 0;
- int IdSel = ISERIES_GET_DEVICE_FROM_SUBBUS(SubBus);
- int Function = ISERIES_GET_FUNCTION_FROM_SUBBUS(SubBus);
- HvAgentId EADsIdSel = ISERIES_PCI_AGENTID(IdSel, Function);
-
- /* iSeries_allocate_IRQ.: 0x18.00.12(0xA3) */
- Irq = iSeries_allocate_IRQ(Bus, 0, EADsIdSel);
-
- /*
- * Connect all functions of any device found.
- */
- for (IdSel = 1; IdSel <= BridgeInfo->maxAgents; ++IdSel) {
- for (Function = 0; Function < 8; ++Function) {
- HvAgentId AgentId = ISERIES_PCI_AGENTID(IdSel, Function);
- HvRc = HvCallXm_connectBusUnit(Bus, SubBus,
- AgentId, Irq);
- if (HvRc != 0) {
- pci_Log_Error("Connect Bus Unit",
- Bus, SubBus, AgentId, HvRc);
- continue;
- }
-
- HvRc = HvCallPci_configLoad16(Bus, SubBus, AgentId,
- PCI_VENDOR_ID, &VendorId);
- if (HvRc != 0) {
- pci_Log_Error("Read Vendor",
- Bus, SubBus, AgentId, HvRc);
- continue;
- }
- printk("read vendor ID: %x\n", VendorId);
-
- /* FoundDevice: 0x18.28.10 = 0x12AE */
- HvRc = HvCallPci_configStore8(Bus, SubBus, AgentId,
- PCI_INTERRUPT_LINE, Irq);
- if (HvRc != 0)
- pci_Log_Error("PciCfgStore Irq Failed!",
- Bus, SubBus, AgentId, HvRc);
-
- ++DeviceCount;
- node = build_device_node(Bus, SubBus, EADsIdSel, Function);
- PCI_DN(node)->Irq = Irq;
- PCI_DN(node)->LogicalSlot = BridgeInfo->logicalSlotNumber;
-
- } /* for (Function = 0; Function < 8; ++Function) */
- } /* for (IdSel = 1; IdSel <= MaxAgents; ++IdSel) */
- return HvRc;
-}
-
-/*
* I/0 Memory copy MUST use mmio commands on iSeries
* To do; For performance, include the hv call directly
*/
@@ -509,11 +315,13 @@ EXPORT_SYMBOL(iSeries_memcpy_fromio);
*/
static struct device_node *find_Device_Node(int bus, int devfn)
{
- struct pci_dn *pdn;
+ struct device_node *node;
+
+ for (node = NULL; (node = of_find_all_nodes(node)); ) {
+ struct pci_dn *pdn = PCI_DN(node);
- list_for_each_entry(pdn, &iSeries_Global_Device_List, Device_List) {
- if ((bus == pdn->busno) && (devfn == pdn->devfn))
- return pdn->node;
+ if (pdn && (bus == pdn->busno) && (devfn == pdn->devfn))
+ return node;
}
return NULL;
}
@@ -625,7 +433,6 @@ static int CheckReturnCode(char *TextHdr, struct device_node *DevNode,
if (ret != 0) {
struct pci_dn *pdn = PCI_DN(DevNode);
- ++Pci_Error_Count;
(*retry)++;
printk("PCI: %s: Device 0x%04X:%02X I/O Error(%2d): 0x%04X\n",
TextHdr, pdn->busno, pdn->devfn,
@@ -707,7 +514,6 @@ u8 iSeries_Read_Byte(const volatile void __iomem *IoAddress)
return 0xff;
}
do {
- ++Pci_Io_Read_Count;
HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, BarOffset, 0);
} while (CheckReturnCode("RDB", DevNode, &retry, ret.rc) != 0);
@@ -737,7 +543,6 @@ u16 iSeries_Read_Word(const volatile void __iomem *IoAddress)
return 0xffff;
}
do {
- ++Pci_Io_Read_Count;
HvCall3Ret16(HvCallPciBarLoad16, &ret, dsa,
BarOffset, 0);
} while (CheckReturnCode("RDW", DevNode, &retry, ret.rc) != 0);
@@ -768,7 +573,6 @@ u32 iSeries_Read_Long(const volatile void __iomem *IoAddress)
return 0xffffffff;
}
do {
- ++Pci_Io_Read_Count;
HvCall3Ret16(HvCallPciBarLoad32, &ret, dsa,
BarOffset, 0);
} while (CheckReturnCode("RDL", DevNode, &retry, ret.rc) != 0);
@@ -806,7 +610,6 @@ void iSeries_Write_Byte(u8 data, volatile void __iomem *IoAddress)
return;
}
do {
- ++Pci_Io_Write_Count;
rc = HvCall4(HvCallPciBarStore8, dsa, BarOffset, data, 0);
} while (CheckReturnCode("WWB", DevNode, &retry, rc) != 0);
}
@@ -834,7 +637,6 @@ void iSeries_Write_Word(u16 data, volatile void __iomem *IoAddress)
return;
}
do {
- ++Pci_Io_Write_Count;
rc = HvCall4(HvCallPciBarStore16, dsa, BarOffset, swab16(data), 0);
} while (CheckReturnCode("WWW", DevNode, &retry, rc) != 0);
}
@@ -862,7 +664,6 @@ void iSeries_Write_Long(u32 data, volatile void __iomem *IoAddress)
return;
}
do {
- ++Pci_Io_Write_Count;
rc = HvCall4(HvCallPciBarStore32, dsa, BarOffset, swab32(data), 0);
} while (CheckReturnCode("WWL", DevNode, &retry, rc) != 0);
}
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index a6fd9be..617c724 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -50,7 +50,6 @@
#include <asm/iseries/hv_call_xm.h>
#include <asm/iseries/it_lp_queue.h>
#include <asm/iseries/mf.h>
-#include <asm/iseries/it_exp_vpd_panel.h>
#include <asm/iseries/hv_lp_event.h>
#include <asm/iseries/lpar_map.h>
#include <asm/udbg.h>
@@ -81,9 +80,6 @@ extern void iSeries_pci_final_fixup(void);
static void iSeries_pci_final_fixup(void) { }
#endif
-/* Global Variables */
-int piranha_simulator;
-
extern int rd_size; /* Defined in drivers/block/rd.c */
extern unsigned long embedded_sysmap_start;
extern unsigned long embedded_sysmap_end;
@@ -91,8 +87,6 @@ extern unsigned long embedded_sysmap_end;
extern unsigned long iSeries_recal_tb;
extern unsigned long iSeries_recal_titan;
-static unsigned long cmd_mem_limit;
-
struct MemoryBlock {
unsigned long absStart;
unsigned long absEnd;
@@ -340,8 +334,6 @@ static void __init iSeries_init_early(void)
#ifdef CONFIG_SMP
smp_init_iSeries();
#endif
- if (itLpNaca.xPirEnvironMode == 0)
- piranha_simulator = 1;
/* Associate Lp Event Queue 0 with processor 0 */
HvCallEvent_setLpEventQueueInterruptProc(0, 0);
@@ -536,10 +528,10 @@ static void __init iSeries_setup_arch(void)
{
if (get_lppaca()->shared_proc) {
ppc_md.idle_loop = iseries_shared_idle;
- printk(KERN_INFO "Using shared processor idle loop\n");
+ printk(KERN_DEBUG "Using shared processor idle loop\n");
} else {
ppc_md.idle_loop = iseries_dedicated_idle;
- printk(KERN_INFO "Using dedicated idle loop\n");
+ printk(KERN_DEBUG "Using dedicated idle loop\n");
}
/* Setup the Lp Event Queue */
@@ -714,243 +706,6 @@ define_machine(iseries) {
/* XXX Implement enable_pmcs for iSeries */
};
-struct blob {
- unsigned char data[PAGE_SIZE];
- unsigned long next;
-};
-
-struct iseries_flat_dt {
- struct boot_param_header header;
- u64 reserve_map[2];
- struct blob dt;
- struct blob strings;
-};
-
-struct iseries_flat_dt iseries_dt;
-
-void dt_init(struct iseries_flat_dt *dt)
-{
- dt->header.off_mem_rsvmap =
- offsetof(struct iseries_flat_dt, reserve_map);
- dt->header.off_dt_struct = offsetof(struct iseries_flat_dt, dt);
- dt->header.off_dt_strings = offsetof(struct iseries_flat_dt, strings);
- dt->header.totalsize = sizeof(struct iseries_flat_dt);
- dt->header.dt_strings_size = sizeof(struct blob);
-
- /* There is no notion of hardware cpu id on iSeries */
- dt->header.boot_cpuid_phys = smp_processor_id();
-
- dt->dt.next = (unsigned long)&dt->dt.data;
- dt->strings.next = (unsigned long)&dt->strings.data;
-
- dt->header.magic = OF_DT_HEADER;
- dt->header.version = 0x10;
- dt->header.last_comp_version = 0x10;
-
- dt->reserve_map[0] = 0;
- dt->reserve_map[1] = 0;
-}
-
-void dt_check_blob(struct blob *b)
-{
- if (b->next >= (unsigned long)&b->next) {
- DBG("Ran out of space in flat device tree blob!\n");
- BUG();
- }
-}
-
-void dt_push_u32(struct iseries_flat_dt *dt, u32 value)
-{
- *((u32*)dt->dt.next) = value;
- dt->dt.next += sizeof(u32);
-
- dt_check_blob(&dt->dt);
-}
-
-void dt_push_u64(struct iseries_flat_dt *dt, u64 value)
-{
- *((u64*)dt->dt.next) = value;
- dt->dt.next += sizeof(u64);
-
- dt_check_blob(&dt->dt);
-}
-
-unsigned long dt_push_bytes(struct blob *blob, char *data, int len)
-{
- unsigned long start = blob->next - (unsigned long)blob->data;
-
- memcpy((char *)blob->next, data, len);
- blob->next = _ALIGN(blob->next + len, 4);
-
- dt_check_blob(blob);
-
- return start;
-}
-
-void dt_start_node(struct iseries_flat_dt *dt, char *name)
-{
- dt_push_u32(dt, OF_DT_BEGIN_NODE);
- dt_push_bytes(&dt->dt, name, strlen(name) + 1);
-}
-
-#define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE)
-
-void dt_prop(struct iseries_flat_dt *dt, char *name, char *data, int len)
-{
- unsigned long offset;
-
- dt_push_u32(dt, OF_DT_PROP);
-
- /* Length of the data */
- dt_push_u32(dt, len);
-
- /* Put the property name in the string blob. */
- offset = dt_push_bytes(&dt->strings, name, strlen(name) + 1);
-
- /* The offset of the properties name in the string blob. */
- dt_push_u32(dt, (u32)offset);
-
- /* The actual data. */
- dt_push_bytes(&dt->dt, data, len);
-}
-
-void dt_prop_str(struct iseries_flat_dt *dt, char *name, char *data)
-{
- dt_prop(dt, name, data, strlen(data) + 1); /* + 1 for NULL */
-}
-
-void dt_prop_u32(struct iseries_flat_dt *dt, char *name, u32 data)
-{
- dt_prop(dt, name, (char *)&data, sizeof(u32));
-}
-
-void dt_prop_u64(struct iseries_flat_dt *dt, char *name, u64 data)
-{
- dt_prop(dt, name, (char *)&data, sizeof(u64));
-}
-
-void dt_prop_u64_list(struct iseries_flat_dt *dt, char *name, u64 *data, int n)
-{
- dt_prop(dt, name, (char *)data, sizeof(u64) * n);
-}
-
-void dt_prop_u32_list(struct iseries_flat_dt *dt, char *name, u32 *data, int n)
-{
- dt_prop(dt, name, (char *)data, sizeof(u32) * n);
-}
-
-void dt_prop_empty(struct iseries_flat_dt *dt, char *name)
-{
- dt_prop(dt, name, NULL, 0);
-}
-
-void dt_cpus(struct iseries_flat_dt *dt)
-{
- unsigned char buf[32];
- unsigned char *p;
- unsigned int i, index;
- struct IoHriProcessorVpd *d;
- u32 pft_size[2];
-
- /* yuck */
- snprintf(buf, 32, "PowerPC,%s", cur_cpu_spec->cpu_name);
- p = strchr(buf, ' ');
- if (!p) p = buf + strlen(buf);
-
- dt_start_node(dt, "cpus");
- dt_prop_u32(dt, "#address-cells", 1);
- dt_prop_u32(dt, "#size-cells", 0);
-
- pft_size[0] = 0; /* NUMA CEC cookie, 0 for non NUMA */
- pft_size[1] = __ilog2(HvCallHpt_getHptPages() * HW_PAGE_SIZE);
-
- for (i = 0; i < NR_CPUS; i++) {
- if (lppaca[i].dyn_proc_status >= 2)
- continue;
-
- snprintf(p, 32 - (p - buf), "@%d", i);
- dt_start_node(dt, buf);
-
- dt_prop_str(dt, "device_type", "cpu");
-
- index = lppaca[i].dyn_hv_phys_proc_index;
- d = &xIoHriProcessorVpd[index];
-
- dt_prop_u32(dt, "i-cache-size", d->xInstCacheSize * 1024);
- dt_prop_u32(dt, "i-cache-line-size", d->xInstCacheOperandSize);
-
- dt_prop_u32(dt, "d-cache-size", d->xDataL1CacheSizeKB * 1024);
- dt_prop_u32(dt, "d-cache-line-size", d->xDataCacheOperandSize);
-
- /* magic conversions to Hz copied from old code */
- dt_prop_u32(dt, "clock-frequency",
- ((1UL << 34) * 1000000) / d->xProcFreq);
- dt_prop_u32(dt, "timebase-frequency",
- ((1UL << 32) * 1000000) / d->xTimeBaseFreq);
-
- dt_prop_u32(dt, "reg", i);
-
- dt_prop_u32_list(dt, "ibm,pft-size", pft_size, 2);
-
- dt_end_node(dt);
- }
-
- dt_end_node(dt);
-}
-
-void dt_model(struct iseries_flat_dt *dt)
-{
- char buf[16] = "IBM,";
-
- /* "IBM," + mfgId[2:3] + systemSerial[1:5] */
- strne2a(buf + 4, xItExtVpdPanel.mfgID + 2, 2);
- strne2a(buf + 6, xItExtVpdPanel.systemSerial + 1, 5);
- buf[11] = '\0';
- dt_prop_str(dt, "system-id", buf);
-
- /* "IBM," + machineType[0:4] */
- strne2a(buf + 4, xItExtVpdPanel.machineType, 4);
- buf[8] = '\0';
- dt_prop_str(dt, "model", buf);
-
- dt_prop_str(dt, "compatible", "IBM,iSeries");
-}
-
-void build_flat_dt(struct iseries_flat_dt *dt, unsigned long phys_mem_size)
-{
- u64 tmp[2];
-
- dt_init(dt);
-
- dt_start_node(dt, "");
-
- dt_prop_u32(dt, "#address-cells", 2);
- dt_prop_u32(dt, "#size-cells", 2);
- dt_model(dt);
-
- /* /memory */
- dt_start_node(dt, "memory@0");
- dt_prop_str(dt, "name", "memory");
- dt_prop_str(dt, "device_type", "memory");
- tmp[0] = 0;
- tmp[1] = phys_mem_size;
- dt_prop_u64_list(dt, "reg", tmp, 2);
- dt_end_node(dt);
-
- /* /chosen */
- dt_start_node(dt, "chosen");
- dt_prop_str(dt, "bootargs", cmd_line);
- if (cmd_mem_limit)
- dt_prop_u64(dt, "linux,memory-limit", cmd_mem_limit);
- dt_end_node(dt);
-
- dt_cpus(dt);
-
- dt_end_node(dt);
-
- dt_push_u32(dt, OF_DT_END);
-}
-
void * __init iSeries_early_setup(void)
{
unsigned long phys_mem_size;
@@ -965,28 +720,8 @@ void * __init iSeries_early_setup(void)
iSeries_get_cmdline();
- /* Save unparsed command line copy for /proc/cmdline */
- strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE);
-
- /* Parse early parameters, in particular mem=x */
- parse_early_param();
-
- build_flat_dt(&iseries_dt, phys_mem_size);
-
- return (void *) __pa(&iseries_dt);
-}
-
-/*
- * On iSeries we just parse the mem=X option from the command line.
- * On pSeries it's a bit more complicated, see prom_init_mem()
- */
-static int __init early_parsemem(char *p)
-{
- if (p)
- cmd_mem_limit = ALIGN(memparse(p, &p), PAGE_SIZE);
- return 0;
+ return (void *) __pa(build_flat_dt(phys_mem_size));
}
-early_param("mem", early_parsemem);
static void hvputc(char c)
{
diff --git a/arch/powerpc/platforms/iseries/setup.h b/arch/powerpc/platforms/iseries/setup.h
index 5213044..0a47ac5 100644
--- a/arch/powerpc/platforms/iseries/setup.h
+++ b/arch/powerpc/platforms/iseries/setup.h
@@ -21,4 +21,6 @@ extern unsigned long iSeries_get_boot_time(void);
extern int iSeries_set_rtc_time(struct rtc_time *tm);
extern void iSeries_get_rtc_time(struct rtc_time *tm);
+extern void *build_flat_dt(unsigned long phys_mem_size);
+
#endif /* __ISERIES_SETUP_H__ */
diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c
deleted file mode 100644
index ad36ab0..0000000
--- a/arch/powerpc/platforms/iseries/vio.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * IBM PowerPC iSeries Virtual I/O Infrastructure Support.
- *
- * Copyright (c) 2005 Stephen Rothwell, IBM Corp.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/types.h>
-#include <linux/device.h>
-#include <linux/init.h>
-
-#include <asm/vio.h>
-#include <asm/iommu.h>
-#include <asm/tce.h>
-#include <asm/abs_addr.h>
-#include <asm/page.h>
-#include <asm/iseries/vio.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/hv_call_xm.h>
-
-#include "iommu.h"
-
-struct device *iSeries_vio_dev = &vio_bus_device.dev;
-EXPORT_SYMBOL(iSeries_vio_dev);
-
-static struct iommu_table veth_iommu_table;
-static struct iommu_table vio_iommu_table;
-
-static void __init iommu_vio_init(void)
-{
- iommu_table_getparms_iSeries(255, 0, 0xff, &veth_iommu_table);
- veth_iommu_table.it_size /= 2;
- vio_iommu_table = veth_iommu_table;
- vio_iommu_table.it_offset += veth_iommu_table.it_size;
-
- if (!iommu_init_table(&veth_iommu_table))
- printk("Virtual Bus VETH TCE table failed.\n");
- if (!iommu_init_table(&vio_iommu_table))
- printk("Virtual Bus VIO TCE table failed.\n");
-}
-
-/**
- * vio_register_device_iseries: - Register a new iSeries vio device.
- * @voidev: The device to register.
- */
-static struct vio_dev *__init vio_register_device_iseries(char *type,
- uint32_t unit_num)
-{
- struct vio_dev *viodev;
-
- /* allocate a vio_dev for this device */
- viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);
- if (!viodev)
- return NULL;
- memset(viodev, 0, sizeof(struct vio_dev));
-
- snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%s%d", type, unit_num);
-
- viodev->name = viodev->dev.bus_id;
- viodev->type = type;
- viodev->unit_address = unit_num;
- viodev->iommu_table = &vio_iommu_table;
- if (vio_register_device(viodev) == NULL) {
- kfree(viodev);
- return NULL;
- }
- return viodev;
-}
-
-void __init probe_bus_iseries(void)
-{
- HvLpIndexMap vlan_map;
- struct vio_dev *viodev;
- int i;
-
- /* there is only one of each of these */
- vio_register_device_iseries("viocons", 0);
- vio_register_device_iseries("vscsi", 0);
-
- vlan_map = HvLpConfig_getVirtualLanIndexMap();
- for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
- if ((vlan_map & (0x8000 >> i)) == 0)
- continue;
- viodev = vio_register_device_iseries("vlan", i);
- /* veth is special and has it own iommu_table */
- viodev->iommu_table = &veth_iommu_table;
- }
- for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++)
- vio_register_device_iseries("viodasd", i);
- for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++)
- vio_register_device_iseries("viocd", i);
- for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++)
- vio_register_device_iseries("viotape", i);
-}
-
-/**
- * vio_match_device_iseries: - Tell if a iSeries VIO device matches a
- * vio_device_id
- */
-static int vio_match_device_iseries(const struct vio_device_id *id,
- const struct vio_dev *dev)
-{
- return strncmp(dev->type, id->type, strlen(id->type)) == 0;
-}
-
-static struct vio_bus_ops vio_bus_ops_iseries = {
- .match = vio_match_device_iseries,
-};
-
-/**
- * vio_bus_init_iseries: - Initialize the iSeries virtual IO bus
- */
-static int __init vio_bus_init_iseries(void)
-{
- int err;
-
- err = vio_bus_init(&vio_bus_ops_iseries);
- if (err == 0) {
- iommu_vio_init();
- vio_bus_device.iommu_table = &vio_iommu_table;
- iSeries_vio_dev = &vio_bus_device.dev;
- probe_bus_iseries();
- }
- return err;
-}
-
-__initcall(vio_bus_init_iseries);
diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c
index 85d6c93..9a4efc0 100644
--- a/arch/powerpc/platforms/maple/pci.c
+++ b/arch/powerpc/platforms/maple/pci.c
@@ -437,9 +437,6 @@ void __init maple_pci_init(void)
/* Tell pci.c to not change any resource allocations. */
pci_probe_only = 1;
-
- /* Allow all IO */
- io_page_mask = -1;
}
int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel)
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c
index 24c0aef4..a0505ea 100644
--- a/arch/powerpc/platforms/maple/setup.c
+++ b/arch/powerpc/platforms/maple/setup.c
@@ -189,7 +189,7 @@ void __init maple_setup_arch(void)
conswitchp = &dummy_con;
#endif
- printk(KERN_INFO "Using native/NAP idle loop\n");
+ printk(KERN_DEBUG "Using native/NAP idle loop\n");
}
/*
diff --git a/arch/powerpc/platforms/powermac/backlight.c b/arch/powerpc/platforms/powermac/backlight.c
index 8be2f7d..498b042 100644
--- a/arch/powerpc/platforms/powermac/backlight.c
+++ b/arch/powerpc/platforms/powermac/backlight.c
@@ -3,200 +3,148 @@
* Contains support for the backlight.
*
* Copyright (C) 2000 Benjamin Herrenschmidt
+ * Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/stddef.h>
-#include <linux/reboot.h>
-#include <linux/nvram.h>
-#include <linux/console.h>
-#include <asm/sections.h>
-#include <asm/ptrace.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/nvram.h>
#include <asm/backlight.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
+#define OLD_BACKLIGHT_MAX 15
-static struct backlight_controller *backlighter;
-static void* backlighter_data;
-static int backlight_autosave;
-static int backlight_level = BACKLIGHT_MAX;
-static int backlight_enabled = 1;
-static int backlight_req_level = -1;
-static int backlight_req_enable = -1;
+/* Protect the pmac_backlight variable */
+DEFINE_MUTEX(pmac_backlight_mutex);
-static void backlight_callback(void *);
-static DECLARE_WORK(backlight_work, backlight_callback, NULL);
+/* Main backlight storage
+ *
+ * Backlight drivers in this variable are required to have the "props"
+ * attribute set and to have an update_status function.
+ *
+ * We can only store one backlight here, but since Apple laptops have only one
+ * internal display, it doesn't matter. Other backlight drivers can be used
+ * independently.
+ *
+ * Lock ordering:
+ * pmac_backlight_mutex (global, main backlight)
+ * pmac_backlight->sem (backlight class)
+ */
+struct backlight_device *pmac_backlight;
-void register_backlight_controller(struct backlight_controller *ctrler,
- void *data, char *type)
+int pmac_has_backlight_type(const char *type)
{
- struct device_node* bk_node;
- char *prop;
- int valid = 0;
-
- /* There's already a matching controller, bail out */
- if (backlighter != NULL)
- return;
-
- bk_node = find_devices("backlight");
-
-#ifdef CONFIG_ADB_PMU
- /* Special case for the old PowerBook since I can't test on it */
- backlight_autosave = machine_is_compatible("AAPL,3400/2400")
- || machine_is_compatible("AAPL,3500");
- if ((backlight_autosave
- || machine_is_compatible("AAPL,PowerBook1998")
- || machine_is_compatible("PowerBook1,1"))
- && !strcmp(type, "pmu"))
- valid = 1;
-#endif
+ struct device_node* bk_node = find_devices("backlight");
+
if (bk_node) {
- prop = get_property(bk_node, "backlight-control", NULL);
- if (prop && !strncmp(prop, type, strlen(type)))
- valid = 1;
- }
- if (!valid)
- return;
- backlighter = ctrler;
- backlighter_data = data;
-
- if (bk_node && !backlight_autosave)
- prop = get_property(bk_node, "bklt", NULL);
- else
- prop = NULL;
- if (prop) {
- backlight_level = ((*prop)+1) >> 1;
- if (backlight_level > BACKLIGHT_MAX)
- backlight_level = BACKLIGHT_MAX;
+ char *prop = get_property(bk_node, "backlight-control", NULL);
+ if (prop && strncmp(prop, type, strlen(type)) == 0)
+ return 1;
}
-#ifdef CONFIG_ADB_PMU
- if (backlight_autosave) {
- struct adb_request req;
- pmu_request(&req, NULL, 2, 0xd9, 0);
- while (!req.complete)
- pmu_poll();
- backlight_level = req.reply[0] >> 4;
- }
-#endif
- acquire_console_sem();
- if (!backlighter->set_enable(1, backlight_level, data))
- backlight_enabled = 1;
- release_console_sem();
-
- printk(KERN_INFO "Registered \"%s\" backlight controller,"
- "level: %d/15\n", type, backlight_level);
+ return 0;
}
-EXPORT_SYMBOL(register_backlight_controller);
-void unregister_backlight_controller(struct backlight_controller
- *ctrler, void *data)
+int pmac_backlight_curve_lookup(struct fb_info *info, int value)
{
- /* We keep the current backlight level (for now) */
- if (ctrler == backlighter && data == backlighter_data)
- backlighter = NULL;
+ int level = (FB_BACKLIGHT_LEVELS - 1);
+
+ if (info && info->bl_dev) {
+ int i, max = 0;
+
+ /* Look for biggest value */
+ for (i = 0; i < FB_BACKLIGHT_LEVELS; i++)
+ max = max((int)info->bl_curve[i], max);
+
+ /* Look for nearest value */
+ for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) {
+ int diff = abs(info->bl_curve[i] - value);
+ if (diff < max) {
+ max = diff;
+ level = i;
+ }
+ }
+
+ }
+
+ return level;
}
-EXPORT_SYMBOL(unregister_backlight_controller);
-static int __set_backlight_enable(int enable)
+static void pmac_backlight_key(int direction)
{
- int rc;
-
- if (!backlighter)
- return -ENODEV;
- acquire_console_sem();
- rc = backlighter->set_enable(enable, backlight_level,
- backlighter_data);
- if (!rc)
- backlight_enabled = enable;
- release_console_sem();
- return rc;
+ mutex_lock(&pmac_backlight_mutex);
+ if (pmac_backlight) {
+ struct backlight_properties *props;
+ int brightness;
+
+ down(&pmac_backlight->sem);
+ props = pmac_backlight->props;
+
+ brightness = props->brightness +
+ ((direction?-1:1) * (props->max_brightness / 15));
+
+ if (brightness < 0)
+ brightness = 0;
+ else if (brightness > props->max_brightness)
+ brightness = props->max_brightness;
+
+ props->brightness = brightness;
+ props->update_status(pmac_backlight);
+
+ up(&pmac_backlight->sem);
+ }
+ mutex_unlock(&pmac_backlight_mutex);
}
-int set_backlight_enable(int enable)
+
+void pmac_backlight_key_up()
{
- if (!backlighter)
- return -ENODEV;
- backlight_req_enable = enable;
- schedule_work(&backlight_work);
- return 0;
+ pmac_backlight_key(0);
}
-EXPORT_SYMBOL(set_backlight_enable);
-
-int get_backlight_enable(void)
+void pmac_backlight_key_down()
{
- if (!backlighter)
- return -ENODEV;
- return backlight_enabled;
+ pmac_backlight_key(1);
}
-EXPORT_SYMBOL(get_backlight_enable);
-static int __set_backlight_level(int level)
+int pmac_backlight_set_legacy_brightness(int brightness)
{
- int rc = 0;
-
- if (!backlighter)
- return -ENODEV;
- if (level < BACKLIGHT_MIN)
- level = BACKLIGHT_OFF;
- if (level > BACKLIGHT_MAX)
- level = BACKLIGHT_MAX;
- acquire_console_sem();
- if (backlight_enabled)
- rc = backlighter->set_level(level, backlighter_data);
- if (!rc)
- backlight_level = level;
- release_console_sem();
- if (!rc && !backlight_autosave) {
- level <<=1;
- if (level & 0x10)
- level |= 0x01;
- // -- todo: save to property "bklt"
+ int error = -ENXIO;
+
+ mutex_lock(&pmac_backlight_mutex);
+ if (pmac_backlight) {
+ struct backlight_properties *props;
+
+ down(&pmac_backlight->sem);
+ props = pmac_backlight->props;
+ props->brightness = brightness *
+ props->max_brightness / OLD_BACKLIGHT_MAX;
+ props->update_status(pmac_backlight);
+ up(&pmac_backlight->sem);
+
+ error = 0;
}
- return rc;
+ mutex_unlock(&pmac_backlight_mutex);
+
+ return error;
}
-int set_backlight_level(int level)
+
+int pmac_backlight_get_legacy_brightness()
{
- if (!backlighter)
- return -ENODEV;
- backlight_req_level = level;
- schedule_work(&backlight_work);
- return 0;
-}
+ int result = -ENXIO;
-EXPORT_SYMBOL(set_backlight_level);
+ mutex_lock(&pmac_backlight_mutex);
+ if (pmac_backlight) {
+ struct backlight_properties *props;
-int get_backlight_level(void)
-{
- if (!backlighter)
- return -ENODEV;
- return backlight_level;
-}
-EXPORT_SYMBOL(get_backlight_level);
+ down(&pmac_backlight->sem);
+ props = pmac_backlight->props;
+ result = props->brightness *
+ OLD_BACKLIGHT_MAX / props->max_brightness;
+ up(&pmac_backlight->sem);
+ }
+ mutex_unlock(&pmac_backlight_mutex);
-static void backlight_callback(void *dummy)
-{
- int level, enable;
-
- do {
- level = backlight_req_level;
- enable = backlight_req_enable;
- mb();
-
- if (level >= 0)
- __set_backlight_level(level);
- if (enable >= 0)
- __set_backlight_enable(enable);
- } while(cmpxchg(&backlight_req_level, level, -1) != level ||
- cmpxchg(&backlight_req_enable, enable, -1) != enable);
+ return result;
}
diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c
index cfd6527..af2a8f9 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_32.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_32.c
@@ -314,7 +314,7 @@ static int pmu_set_cpu_speed(int low_speed)
_set_L3CR(save_l3cr);
/* Restore userland MMU context */
- set_context(current->active_mm->context, current->active_mm->pgd);
+ set_context(current->active_mm->context.id, current->active_mm->pgd);
#ifdef DEBUG_FREQ
printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1));
diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c
index a5063cd..85e00cb 100644
--- a/arch/powerpc/platforms/powermac/feature.c
+++ b/arch/powerpc/platforms/powermac/feature.c
@@ -2510,7 +2510,7 @@ found:
if (get_property(np, "flush-on-lock", NULL))
break;
powersave_nap = 1;
- printk(KERN_INFO "Processor NAP mode on idle enabled.\n");
+ printk(KERN_DEBUG "Processor NAP mode on idle enabled.\n");
break;
}
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index ea179af..8003585 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -1068,9 +1068,6 @@ void __init pmac_pci_init(void)
/* Tell pci.c to not use the common resource allocation mechanism */
pci_probe_only = 1;
- /* Allow all IO */
- io_page_mask = -1;
-
#else /* CONFIG_PPC64 */
init_p2pbridge();
fixup_nec_usb2();
diff --git a/arch/powerpc/platforms/powermac/pfunc_core.c b/arch/powerpc/platforms/powermac/pfunc_core.c
index f08173b..047f954 100644
--- a/arch/powerpc/platforms/powermac/pfunc_core.c
+++ b/arch/powerpc/platforms/powermac/pfunc_core.c
@@ -871,10 +871,17 @@ int pmf_register_irq_client(struct device_node *target,
spin_unlock_irqrestore(&pmf_lock, flags);
if (func == NULL)
return -ENODEV;
+
+ /* guard against manipulations of list */
mutex_lock(&pmf_irq_mutex);
if (list_empty(&func->irq_clients))
func->dev->handlers->irq_enable(func);
+
+ /* guard against pmf_do_irq while changing list */
+ spin_lock_irqsave(&pmf_lock, flags);
list_add(&client->link, &func->irq_clients);
+ spin_unlock_irqrestore(&pmf_lock, flags);
+
client->func = func;
mutex_unlock(&pmf_irq_mutex);
@@ -885,12 +892,19 @@ EXPORT_SYMBOL_GPL(pmf_register_irq_client);
void pmf_unregister_irq_client(struct pmf_irq_client *client)
{
struct pmf_function *func = client->func;
+ unsigned long flags;
BUG_ON(func == NULL);
+ /* guard against manipulations of list */
mutex_lock(&pmf_irq_mutex);
client->func = NULL;
+
+ /* guard against pmf_do_irq while changing list */
+ spin_lock_irqsave(&pmf_lock, flags);
list_del(&client->link);
+ spin_unlock_irqrestore(&pmf_lock, flags);
+
if (list_empty(&func->irq_clients))
func->dev->handlers->irq_disable(func);
mutex_unlock(&pmf_irq_mutex);
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index b9200fb..9cc7db7 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -458,7 +458,7 @@ static int pmac_pm_finish(suspend_state_t state)
printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
/* Restore userland MMU context */
- set_context(current->active_mm->context, current->active_mm->pgd);
+ set_context(current->active_mm->context.id, current->active_mm->pgd);
return 0;
}
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 9308986..e5e0ff4 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -1,8 +1,11 @@
+ifeq ($(CONFIG_PPC64),y)
+EXTRA_CFLAGS += -mno-minimal-toc
+endif
+
obj-y := pci.o lpar.o hvCall.o nvram.o reconfig.o \
setup.o iommu.o ras.o rtasd.o pci_dlpar.o \
firmware.o
obj-$(CONFIG_SMP) += smp.o
-obj-$(CONFIG_IBMVIO) += vio.o
obj-$(CONFIG_XICS) += xics.o
obj-$(CONFIG_SCANLOG) += scanlog.o
obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o
diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c
index d4a402c..98c23ae 100644
--- a/arch/powerpc/platforms/pseries/eeh_cache.c
+++ b/arch/powerpc/platforms/pseries/eeh_cache.c
@@ -304,6 +304,8 @@ void __init pci_addr_cache_build(void)
pci_addr_cache_insert_device(dev);
dn = pci_device_to_OF_node(dev);
+ if (!dn)
+ continue;
pci_dev_get (dev); /* matching put is in eeh_remove_device() */
PCI_DN(dn)->pcidev = dev;
}
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index 1fba695..0ec9a54 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -23,9 +23,8 @@
*
*/
#include <linux/delay.h>
-#include <linux/irq.h>
#include <linux/interrupt.h>
-#include <linux/notifier.h>
+#include <linux/irq.h>
#include <linux/pci.h>
#include <asm/eeh.h>
#include <asm/eeh_event.h>
@@ -202,7 +201,11 @@ static void eeh_report_failure(struct pci_dev *dev, void *userdata)
static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)
{
- int rc;
+ int cnt, rc;
+
+ /* pcibios will clear the counter; save the value */
+ cnt = pe_dn->eeh_freeze_count;
+
if (bus)
pcibios_remove_pci_devices(bus);
@@ -241,6 +244,7 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)
ssleep (5);
pcibios_add_pci_devices(bus);
}
+ pe_dn->eeh_freeze_count = cnt;
return 0;
}
@@ -250,23 +254,29 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)
*/
#define MAX_WAIT_FOR_RECOVERY 15
-void handle_eeh_events (struct eeh_event *event)
+struct pci_dn * handle_eeh_events (struct eeh_event *event)
{
struct device_node *frozen_dn;
struct pci_dn *frozen_pdn;
struct pci_bus *frozen_bus;
int rc = 0;
enum pci_ers_result result = PCI_ERS_RESULT_NONE;
- const char *pci_str, *drv_str;
+ const char *location, *pci_str, *drv_str;
frozen_dn = find_device_pe(event->dn);
frozen_bus = pcibios_find_pci_bus(frozen_dn);
if (!frozen_dn) {
- printk(KERN_ERR "EEH: Error: Cannot find partition endpoint for %s\n",
- pci_name(event->dev));
- return;
+
+ location = (char *) get_property(event->dn, "ibm,loc-code", NULL);
+ location = location ? location : "unknown";
+ printk(KERN_ERR "EEH: Error: Cannot find partition endpoint "
+ "for location=%s pci addr=%s\n",
+ location, pci_name(event->dev));
+ return NULL;
}
+ location = (char *) get_property(frozen_dn, "ibm,loc-code", NULL);
+ location = location ? location : "unknown";
/* There are two different styles for coming up with the PE.
* In the old style, it was the highest EEH-capable device
@@ -278,9 +288,10 @@ void handle_eeh_events (struct eeh_event *event)
frozen_bus = pcibios_find_pci_bus (frozen_dn->parent);
if (!frozen_bus) {
- printk(KERN_ERR "EEH: Cannot find PCI bus for %s\n",
- frozen_dn->full_name);
- return;
+ printk(KERN_ERR "EEH: Cannot find PCI bus "
+ "for location=%s dn=%s\n",
+ location, frozen_dn->full_name);
+ return NULL;
}
#if 0
@@ -314,8 +325,9 @@ void handle_eeh_events (struct eeh_event *event)
eeh_slot_error_detail(frozen_pdn, 1 /* Temporary Error */);
printk(KERN_WARNING
- "EEH: This PCI device has failed %d times since last reboot: %s - %s\n",
- frozen_pdn->eeh_freeze_count, drv_str, pci_str);
+ "EEH: This PCI device has failed %d times since last reboot: "
+ "location=%s driver=%s pci addr=%s\n",
+ frozen_pdn->eeh_freeze_count, location, drv_str, pci_str);
/* Walk the various device drivers attached to this slot through
* a reset sequence, giving each an opportunity to do what it needs
@@ -355,7 +367,7 @@ void handle_eeh_events (struct eeh_event *event)
/* Tell all device drivers that they can resume operations */
pci_walk_bus(frozen_bus, eeh_report_resume, NULL);
- return;
+ return frozen_pdn;
excess_failures:
/*
@@ -364,17 +376,18 @@ excess_failures:
* due to actual, failed cards.
*/
printk(KERN_ERR
- "EEH: PCI device %s - %s has failed %d times \n"
- "and has been permanently disabled. Please try reseating\n"
- "this device or replacing it.\n",
- drv_str, pci_str, frozen_pdn->eeh_freeze_count);
+ "EEH: PCI device at location=%s driver=%s pci addr=%s \n"
+ "has failed %d times and has been permanently disabled. \n"
+ "Please try reseating this device or replacing it.\n",
+ location, drv_str, pci_str, frozen_pdn->eeh_freeze_count);
goto perm_error;
hard_fail:
printk(KERN_ERR
- "EEH: Unable to recover from failure of PCI device %s - %s\n"
+ "EEH: Unable to recover from failure of PCI device "
+ "at location=%s driver=%s pci addr=%s \n"
"Please try reseating this device or replacing it.\n",
- drv_str, pci_str);
+ location, drv_str, pci_str);
perm_error:
eeh_slot_error_detail(frozen_pdn, 2 /* Permanent Error */);
@@ -384,6 +397,8 @@ perm_error:
/* Shut down the device drivers for good. */
pcibios_remove_pci_devices(frozen_bus);
+
+ return NULL;
}
/* ---------- end of file ---------- */
diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c
index 40020c6..8f2d129 100644
--- a/arch/powerpc/platforms/pseries/eeh_event.c
+++ b/arch/powerpc/platforms/pseries/eeh_event.c
@@ -18,6 +18,7 @@
* Copyright (c) 2005 Linas Vepstas <linas@linas.org>
*/
+#include <linux/delay.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/pci.h>
@@ -56,38 +57,43 @@ static int eeh_event_handler(void * dummy)
{
unsigned long flags;
struct eeh_event *event;
+ struct pci_dn *pdn;
daemonize ("eehd");
+ set_current_state(TASK_INTERRUPTIBLE);
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irqsave(&eeh_eventlist_lock, flags);
+ event = NULL;
- spin_lock_irqsave(&eeh_eventlist_lock, flags);
- event = NULL;
+ /* Unqueue the event, get ready to process. */
+ if (!list_empty(&eeh_eventlist)) {
+ event = list_entry(eeh_eventlist.next, struct eeh_event, list);
+ list_del(&event->list);
+ }
+ spin_unlock_irqrestore(&eeh_eventlist_lock, flags);
- /* Unqueue the event, get ready to process. */
- if (!list_empty(&eeh_eventlist)) {
- event = list_entry(eeh_eventlist.next, struct eeh_event, list);
- list_del(&event->list);
- }
- spin_unlock_irqrestore(&eeh_eventlist_lock, flags);
+ if (event == NULL)
+ return 0;
- if (event == NULL)
- break;
+ /* Serialize processing of EEH events */
+ mutex_lock(&eeh_event_mutex);
+ eeh_mark_slot(event->dn, EEH_MODE_RECOVERING);
- /* Serialize processing of EEH events */
- mutex_lock(&eeh_event_mutex);
- eeh_mark_slot(event->dn, EEH_MODE_RECOVERING);
+ printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n",
+ pci_name(event->dev));
- printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n",
- pci_name(event->dev));
+ pdn = handle_eeh_events(event);
- handle_eeh_events(event);
+ eeh_clear_slot(event->dn, EEH_MODE_RECOVERING);
+ pci_dev_put(event->dev);
+ kfree(event);
+ mutex_unlock(&eeh_event_mutex);
- eeh_clear_slot(event->dn, EEH_MODE_RECOVERING);
- pci_dev_put(event->dev);
- kfree(event);
- mutex_unlock(&eeh_event_mutex);
+ /* If there are no new errors after an hour, clear the counter. */
+ if (pdn && pdn->eeh_freeze_count>0) {
+ msleep_interruptible (3600*1000);
+ if (pdn->eeh_freeze_count>0)
+ pdn->eeh_freeze_count--;
}
return 0;
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index 2643078..d03a8b0 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -1,23 +1,24 @@
/*
* Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation
*
- * Rewrite, cleanup:
+ * Rewrite, cleanup:
*
* Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation
+ * Copyright (C) 2006 Olof Johansson <olof@lixom.net>
*
* Dynamic DMA mapping support, pSeries-specific parts, both SMP and LPAR.
*
- *
+ *
* 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
@@ -49,52 +50,46 @@
#define DBG(fmt...)
-static void tce_build_pSeries(struct iommu_table *tbl, long index,
- long npages, unsigned long uaddr,
+static void tce_build_pSeries(struct iommu_table *tbl, long index,
+ long npages, unsigned long uaddr,
enum dma_data_direction direction)
{
- union tce_entry t;
- union tce_entry *tp;
+ u64 proto_tce;
+ u64 *tcep;
+ u64 rpn;
index <<= TCE_PAGE_FACTOR;
npages <<= TCE_PAGE_FACTOR;
- t.te_word = 0;
- t.te_rdwr = 1; // Read allowed
+ proto_tce = TCE_PCI_READ; // Read allowed
if (direction != DMA_TO_DEVICE)
- t.te_pciwr = 1;
+ proto_tce |= TCE_PCI_WRITE;
- tp = ((union tce_entry *)tbl->it_base) + index;
+ tcep = ((u64 *)tbl->it_base) + index;
while (npages--) {
/* can't move this out since we might cross LMB boundary */
- t.te_rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT;
-
- tp->te_word = t.te_word;
+ rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT;
+ *tcep = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT;
uaddr += TCE_PAGE_SIZE;
- tp++;
+ tcep++;
}
}
static void tce_free_pSeries(struct iommu_table *tbl, long index, long npages)
{
- union tce_entry t;
- union tce_entry *tp;
+ u64 *tcep;
npages <<= TCE_PAGE_FACTOR;
index <<= TCE_PAGE_FACTOR;
- t.te_word = 0;
- tp = ((union tce_entry *)tbl->it_base) + index;
-
- while (npages--) {
- tp->te_word = t.te_word;
-
- tp++;
- }
+ tcep = ((u64 *)tbl->it_base) + index;
+
+ while (npages--)
+ *(tcep++) = 0;
}
@@ -103,43 +98,44 @@ static void tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum,
enum dma_data_direction direction)
{
u64 rc;
- union tce_entry tce;
+ u64 proto_tce, tce;
+ u64 rpn;
tcenum <<= TCE_PAGE_FACTOR;
npages <<= TCE_PAGE_FACTOR;
- tce.te_word = 0;
- tce.te_rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT;
- tce.te_rdwr = 1;
+ rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT;
+ proto_tce = TCE_PCI_READ;
if (direction != DMA_TO_DEVICE)
- tce.te_pciwr = 1;
+ proto_tce |= TCE_PCI_WRITE;
while (npages--) {
- rc = plpar_tce_put((u64)tbl->it_index,
- (u64)tcenum << 12,
- tce.te_word );
-
+ tce = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT;
+ rc = plpar_tce_put((u64)tbl->it_index, (u64)tcenum << 12, tce);
+
if (rc && printk_ratelimit()) {
printk("tce_build_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc);
printk("\tindex = 0x%lx\n", (u64)tbl->it_index);
printk("\ttcenum = 0x%lx\n", (u64)tcenum);
- printk("\ttce val = 0x%lx\n", tce.te_word );
+ printk("\ttce val = 0x%lx\n", tce );
show_stack(current, (unsigned long *)__get_SP());
}
-
+
tcenum++;
- tce.te_rpn++;
+ rpn++;
}
}
-static DEFINE_PER_CPU(void *, tce_page) = NULL;
+static DEFINE_PER_CPU(u64 *, tce_page) = NULL;
static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
long npages, unsigned long uaddr,
enum dma_data_direction direction)
{
u64 rc;
- union tce_entry tce, *tcep;
+ u64 proto_tce;
+ u64 *tcep;
+ u64 rpn;
long l, limit;
if (TCE_PAGE_FACTOR == 0 && npages == 1)
@@ -152,7 +148,7 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
* from iommu_alloc{,_sg}()
*/
if (!tcep) {
- tcep = (void *)__get_free_page(GFP_ATOMIC);
+ tcep = (u64 *)__get_free_page(GFP_ATOMIC);
/* If allocation fails, fall back to the loop implementation */
if (!tcep)
return tce_build_pSeriesLP(tbl, tcenum, npages,
@@ -163,11 +159,10 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
tcenum <<= TCE_PAGE_FACTOR;
npages <<= TCE_PAGE_FACTOR;
- tce.te_word = 0;
- tce.te_rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT;
- tce.te_rdwr = 1;
+ rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT;
+ proto_tce = TCE_PCI_READ;
if (direction != DMA_TO_DEVICE)
- tce.te_pciwr = 1;
+ proto_tce |= TCE_PCI_WRITE;
/* We can map max one pageful of TCEs at a time */
do {
@@ -175,11 +170,11 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
* Set up the page with TCE data, looping through and setting
* the values.
*/
- limit = min_t(long, npages, 4096/sizeof(union tce_entry));
+ limit = min_t(long, npages, 4096/TCE_ENTRY_SIZE);
for (l = 0; l < limit; l++) {
- tcep[l] = tce;
- tce.te_rpn++;
+ tcep[l] = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT;
+ rpn++;
}
rc = plpar_tce_put_indirect((u64)tbl->it_index,
@@ -195,7 +190,7 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
printk("tce_buildmulti_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc);
printk("\tindex = 0x%lx\n", (u64)tbl->it_index);
printk("\tnpages = 0x%lx\n", (u64)npages);
- printk("\ttce[0] val = 0x%lx\n", tcep[0].te_word);
+ printk("\ttce[0] val = 0x%lx\n", tcep[0]);
show_stack(current, (unsigned long *)__get_SP());
}
}
@@ -203,23 +198,17 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages)
{
u64 rc;
- union tce_entry tce;
tcenum <<= TCE_PAGE_FACTOR;
npages <<= TCE_PAGE_FACTOR;
- tce.te_word = 0;
-
while (npages--) {
- rc = plpar_tce_put((u64)tbl->it_index,
- (u64)tcenum << 12,
- tce.te_word);
+ rc = plpar_tce_put((u64)tbl->it_index, (u64)tcenum << 12, 0);
if (rc && printk_ratelimit()) {
printk("tce_free_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc);
printk("\tindex = 0x%lx\n", (u64)tbl->it_index);
printk("\ttcenum = 0x%lx\n", (u64)tcenum);
- printk("\ttce val = 0x%lx\n", tce.te_word );
show_stack(current, (unsigned long *)__get_SP());
}
@@ -231,31 +220,24 @@ static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages
static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages)
{
u64 rc;
- union tce_entry tce;
tcenum <<= TCE_PAGE_FACTOR;
npages <<= TCE_PAGE_FACTOR;
- tce.te_word = 0;
-
- rc = plpar_tce_stuff((u64)tbl->it_index,
- (u64)tcenum << 12,
- tce.te_word,
- npages);
+ rc = plpar_tce_stuff((u64)tbl->it_index, (u64)tcenum << 12, 0, npages);
if (rc && printk_ratelimit()) {
printk("tce_freemulti_pSeriesLP: plpar_tce_stuff failed\n");
printk("\trc = %ld\n", rc);
printk("\tindex = 0x%lx\n", (u64)tbl->it_index);
printk("\tnpages = 0x%lx\n", (u64)npages);
- printk("\ttce val = 0x%lx\n", tce.te_word );
show_stack(current, (unsigned long *)__get_SP());
}
}
static void iommu_table_setparms(struct pci_controller *phb,
struct device_node *dn,
- struct iommu_table *tbl)
+ struct iommu_table *tbl)
{
struct device_node *node;
unsigned long *basep;
@@ -275,16 +257,16 @@ static void iommu_table_setparms(struct pci_controller *phb,
memset((void *)tbl->it_base, 0, *sizep);
tbl->it_busno = phb->bus->number;
-
+
/* Units of tce entries */
tbl->it_offset = phb->dma_window_base_cur >> PAGE_SHIFT;
-
+
/* Test if we are going over 2GB of DMA space */
if (phb->dma_window_base_cur + phb->dma_window_size > 0x80000000ul) {
udbg_printf("PCI_DMA: Unexpected number of IOAs under this PHB.\n");
- panic("PCI_DMA: Unexpected number of IOAs under this PHB.\n");
+ panic("PCI_DMA: Unexpected number of IOAs under this PHB.\n");
}
-
+
phb->dma_window_base_cur += phb->dma_window_size;
/* Set the tce table size - measured in entries */
@@ -299,30 +281,22 @@ static void iommu_table_setparms(struct pci_controller *phb,
* iommu_table_setparms_lpar
*
* Function: On pSeries LPAR systems, return TCE table info, given a pci bus.
- *
- * ToDo: properly interpret the ibm,dma-window property. The definition is:
- * logical-bus-number (1 word)
- * phys-address (#address-cells words)
- * size (#cell-size words)
- *
- * Currently we hard code these sizes (more or less).
*/
static void iommu_table_setparms_lpar(struct pci_controller *phb,
struct device_node *dn,
struct iommu_table *tbl,
- unsigned int *dma_window)
+ unsigned char *dma_window)
{
+ unsigned long offset, size;
+
tbl->it_busno = PCI_DN(dn)->bussubno;
+ of_parse_dma_window(dn, dma_window, &tbl->it_index, &offset, &size);
- /* TODO: Parse field size properties properly. */
- tbl->it_size = (((unsigned long)dma_window[4] << 32) |
- (unsigned long)dma_window[5]) >> PAGE_SHIFT;
- tbl->it_offset = (((unsigned long)dma_window[2] << 32) |
- (unsigned long)dma_window[3]) >> PAGE_SHIFT;
tbl->it_base = 0;
- tbl->it_index = dma_window[0];
tbl->it_blocksize = 16;
tbl->it_type = TCE_PCI;
+ tbl->it_offset = offset >> PAGE_SHIFT;
+ tbl->it_size = size >> PAGE_SHIFT;
}
static void iommu_bus_setup_pSeries(struct pci_bus *bus)
@@ -357,13 +331,9 @@ static void iommu_bus_setup_pSeries(struct pci_bus *bus)
if (isa_dn_orig)
of_node_put(isa_dn_orig);
- /* Count number of direct PCI children of the PHB.
- * All PCI device nodes have class-code property, so it's
- * an easy way to find them.
- */
+ /* Count number of direct PCI children of the PHB. */
for (children = 0, tmp = dn->child; tmp; tmp = tmp->sibling)
- if (get_property(tmp, "class-code", NULL))
- children++;
+ children++;
DBG("Children: %d\n", children);
@@ -394,10 +364,11 @@ static void iommu_bus_setup_pSeries(struct pci_bus *bus)
pci->phb->dma_window_size = 0x8000000ul;
pci->phb->dma_window_base_cur = 0x8000000ul;
- tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
+ tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
+ pci->phb->node);
iommu_table_setparms(pci->phb, dn, tbl);
- pci->iommu_table = iommu_init_table(tbl);
+ pci->iommu_table = iommu_init_table(tbl, pci->phb->node);
/* Divide the rest (1.75GB) among the children */
pci->phb->dma_window_size = 0x80000000ul;
@@ -414,7 +385,7 @@ static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus)
struct iommu_table *tbl;
struct device_node *dn, *pdn;
struct pci_dn *ppci;
- unsigned int *dma_window = NULL;
+ unsigned char *dma_window = NULL;
DBG("iommu_bus_setup_pSeriesLP, bus %p, bus->self %p\n", bus, bus->self);
@@ -422,7 +393,7 @@ static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus)
/* Find nearest ibm,dma-window, walking up the device tree */
for (pdn = dn; pdn != NULL; pdn = pdn->parent) {
- dma_window = (unsigned int *)get_property(pdn, "ibm,dma-window", NULL);
+ dma_window = get_property(pdn, "ibm,dma-window", NULL);
if (dma_window != NULL)
break;
}
@@ -440,12 +411,12 @@ static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus)
ppci->bussubno = bus->number;
- tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table),
- GFP_KERNEL);
-
+ tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
+ ppci->phb->node);
+
iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window);
- ppci->iommu_table = iommu_init_table(tbl);
+ ppci->iommu_table = iommu_init_table(tbl, ppci->phb->node);
}
if (pdn != dn)
@@ -468,9 +439,11 @@ static void iommu_dev_setup_pSeries(struct pci_dev *dev)
*/
if (!dev->bus->self) {
DBG(" --> first child, no bridge. Allocating iommu table.\n");
- tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
+ tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
+ PCI_DN(dn)->phb->node);
iommu_table_setparms(PCI_DN(dn)->phb, dn, tbl);
- PCI_DN(mydn)->iommu_table = iommu_init_table(tbl);
+ PCI_DN(dn)->iommu_table = iommu_init_table(tbl,
+ PCI_DN(dn)->phb->node);
return;
}
@@ -516,7 +489,7 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev)
{
struct device_node *pdn, *dn;
struct iommu_table *tbl;
- int *dma_window = NULL;
+ unsigned char *dma_window = NULL;
struct pci_dn *pci;
DBG("iommu_dev_setup_pSeriesLP, dev %p (%s)\n", dev, pci_name(dev));
@@ -531,8 +504,7 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev)
for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table;
pdn = pdn->parent) {
- dma_window = (unsigned int *)
- get_property(pdn, "ibm,dma-window", NULL);
+ dma_window = get_property(pdn, "ibm,dma-window", NULL);
if (dma_window)
break;
}
@@ -553,12 +525,12 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev)
/* iommu_table_setparms_lpar needs bussubno. */
pci->bussubno = pci->phb->bus->number;
- tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table),
- GFP_KERNEL);
+ tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
+ pci->phb->node);
iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window);
- pci->iommu_table = iommu_init_table(tbl);
+ pci->iommu_table = iommu_init_table(tbl, pci->phb->node);
}
if (pdn != dn)
diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c
index e0000ce..2e4e040 100644
--- a/arch/powerpc/platforms/pseries/rtasd.c
+++ b/arch/powerpc/platforms/pseries/rtasd.c
@@ -348,7 +348,7 @@ static int enable_surveillance(int timeout)
return 0;
if (error == -EINVAL) {
- printk(KERN_INFO "rtasd: surveillance not supported\n");
+ printk(KERN_DEBUG "rtasd: surveillance not supported\n");
return 0;
}
@@ -440,7 +440,7 @@ static int rtasd(void *unused)
goto error;
}
- printk(KERN_INFO "RTAS daemon started\n");
+ printk(KERN_DEBUG "RTAS daemon started\n");
DEBUG("will sleep for %d milliseconds\n", (30000/rtas_event_scan_rate));
@@ -487,7 +487,7 @@ static int __init rtas_init(void)
/* No RTAS */
if (rtas_token("event-scan") == RTAS_UNKNOWN_SERVICE) {
- printk(KERN_INFO "rtasd: no event-scan on system\n");
+ printk(KERN_DEBUG "rtasd: no event-scan on system\n");
return -ENODEV;
}
diff --git a/arch/powerpc/platforms/pseries/scanlog.c b/arch/powerpc/platforms/pseries/scanlog.c
index 5064349..77a5bb1 100644
--- a/arch/powerpc/platforms/pseries/scanlog.c
+++ b/arch/powerpc/platforms/pseries/scanlog.c
@@ -107,9 +107,9 @@ static ssize_t scanlog_read(struct file *file, char __user *buf,
/* Break to sleep default time */
break;
default:
- if (status > 9900 && status <= 9905) {
- wait_time = rtas_extended_busy_delay_time(status);
- } else {
+ /* Assume extended busy */
+ wait_time = rtas_busy_delay_time(status);
+ if (!wait_time) {
printk(KERN_ERR "scanlog: unknown error from rtas: %d\n", status);
return -EIO;
}
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 3ba8783..1e28518 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -235,14 +235,14 @@ static void __init pSeries_setup_arch(void)
if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
vpa_init(boot_cpuid);
if (get_lppaca()->shared_proc) {
- printk(KERN_INFO "Using shared processor idle loop\n");
+ printk(KERN_DEBUG "Using shared processor idle loop\n");
ppc_md.power_save = pseries_shared_idle_sleep;
} else {
- printk(KERN_INFO "Using dedicated idle loop\n");
+ printk(KERN_DEBUG "Using dedicated idle loop\n");
ppc_md.power_save = pseries_dedicated_idle_sleep;
}
} else {
- printk(KERN_INFO "Using default idle loop\n");
+ printk(KERN_DEBUG "Using default idle loop\n");
}
if (firmware_has_feature(FW_FEATURE_LPAR))
diff --git a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c
deleted file mode 100644
index 8e53e04..0000000
--- a/arch/powerpc/platforms/pseries/vio.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * IBM PowerPC pSeries Virtual I/O Infrastructure Support.
- *
- * Copyright (c) 2003-2005 IBM Corp.
- * Dave Engebretsen engebret@us.ibm.com
- * Santiago Leon santil@us.ibm.com
- * Hollis Blanchard <hollisb@us.ibm.com>
- * Stephen Rothwell
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/kobject.h>
-#include <asm/iommu.h>
-#include <asm/dma.h>
-#include <asm/prom.h>
-#include <asm/vio.h>
-#include <asm/hvcall.h>
-#include <asm/tce.h>
-
-extern struct subsystem devices_subsys; /* needed for vio_find_name() */
-
-static void probe_bus_pseries(void)
-{
- struct device_node *node_vroot, *of_node;
-
- node_vroot = find_devices("vdevice");
- if ((node_vroot == NULL) || (node_vroot->child == NULL))
- /* this machine doesn't do virtual IO, and that's ok */
- return;
-
- /*
- * Create struct vio_devices for each virtual device in the device tree.
- * Drivers will associate with them later.
- */
- for (of_node = node_vroot->child; of_node != NULL;
- of_node = of_node->sibling) {
- printk(KERN_DEBUG "%s: processing %p\n", __FUNCTION__, of_node);
- vio_register_device_node(of_node);
- }
-}
-
-/**
- * vio_match_device_pseries: - Tell if a pSeries VIO device matches a
- * vio_device_id
- */
-static int vio_match_device_pseries(const struct vio_device_id *id,
- const struct vio_dev *dev)
-{
- return (strncmp(dev->type, id->type, strlen(id->type)) == 0) &&
- device_is_compatible(dev->dev.platform_data, id->compat);
-}
-
-static void vio_release_device_pseries(struct device *dev)
-{
- /* XXX free TCE table */
- of_node_put(dev->platform_data);
-}
-
-static ssize_t viodev_show_devspec(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct device_node *of_node = dev->platform_data;
-
- return sprintf(buf, "%s\n", of_node->full_name);
-}
-DEVICE_ATTR(devspec, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_devspec, NULL);
-
-static void vio_unregister_device_pseries(struct vio_dev *viodev)
-{
- device_remove_file(&viodev->dev, &dev_attr_devspec);
-}
-
-static struct vio_bus_ops vio_bus_ops_pseries = {
- .match = vio_match_device_pseries,
- .unregister_device = vio_unregister_device_pseries,
- .release_device = vio_release_device_pseries,
-};
-
-/**
- * vio_bus_init_pseries: - Initialize the pSeries virtual IO bus
- */
-static int __init vio_bus_init_pseries(void)
-{
- int err;
-
- err = vio_bus_init(&vio_bus_ops_pseries);
- if (err == 0)
- probe_bus_pseries();
- return err;
-}
-
-__initcall(vio_bus_init_pseries);
-
-/**
- * vio_build_iommu_table: - gets the dma information from OF and
- * builds the TCE tree.
- * @dev: the virtual device.
- *
- * Returns a pointer to the built tce tree, or NULL if it can't
- * find property.
-*/
-static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
-{
- unsigned int *dma_window;
- struct iommu_table *newTceTable;
- unsigned long offset;
- int dma_window_property_size;
-
- dma_window = (unsigned int *) get_property(dev->dev.platform_data, "ibm,my-dma-window", &dma_window_property_size);
- if(!dma_window) {
- return NULL;
- }
-
- newTceTable = (struct iommu_table *) kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
-
- /* There should be some code to extract the phys-encoded offset
- using prom_n_addr_cells(). However, according to a comment
- on earlier versions, it's always zero, so we don't bother */
- offset = dma_window[1] >> PAGE_SHIFT;
-
- /* TCE table size - measured in tce entries */
- newTceTable->it_size = dma_window[4] >> PAGE_SHIFT;
- /* offset for VIO should always be 0 */
- newTceTable->it_offset = offset;
- newTceTable->it_busno = 0;
- newTceTable->it_index = (unsigned long)dma_window[0];
- newTceTable->it_type = TCE_VB;
-
- return iommu_init_table(newTceTable);
-}
-
-/**
- * vio_register_device_node: - Register a new vio device.
- * @of_node: The OF node for this device.
- *
- * Creates and initializes a vio_dev structure from the data in
- * of_node (dev.platform_data) and adds it to the list of virtual devices.
- * Returns a pointer to the created vio_dev or NULL if node has
- * NULL device_type or compatible fields.
- */
-struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
-{
- struct vio_dev *viodev;
- unsigned int *unit_address;
- unsigned int *irq_p;
-
- /* we need the 'device_type' property, in order to match with drivers */
- if ((NULL == of_node->type)) {
- printk(KERN_WARNING
- "%s: node %s missing 'device_type'\n", __FUNCTION__,
- of_node->name ? of_node->name : "<unknown>");
- return NULL;
- }
-
- unit_address = (unsigned int *)get_property(of_node, "reg", NULL);
- if (!unit_address) {
- printk(KERN_WARNING "%s: node %s missing 'reg'\n", __FUNCTION__,
- of_node->name ? of_node->name : "<unknown>");
- return NULL;
- }
-
- /* allocate a vio_dev for this node */
- viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);
- if (!viodev) {
- return NULL;
- }
- memset(viodev, 0, sizeof(struct vio_dev));
-
- viodev->dev.platform_data = of_node_get(of_node);
-
- viodev->irq = NO_IRQ;
- irq_p = (unsigned int *)get_property(of_node, "interrupts", NULL);
- if (irq_p) {
- int virq = virt_irq_create_mapping(*irq_p);
- if (virq == NO_IRQ) {
- printk(KERN_ERR "Unable to allocate interrupt "
- "number for %s\n", of_node->full_name);
- } else
- viodev->irq = irq_offset_up(virq);
- }
-
- snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address);
- viodev->name = of_node->name;
- viodev->type = of_node->type;
- viodev->unit_address = *unit_address;
- viodev->iommu_table = vio_build_iommu_table(viodev);
-
- /* register with generic device framework */
- if (vio_register_device(viodev) == NULL) {
- /* XXX free TCE table */
- kfree(viodev);
- return NULL;
- }
- device_create_file(&viodev->dev, &dev_attr_devspec);
-
- return viodev;
-}
-EXPORT_SYMBOL(vio_register_device_node);
-
-/**
- * vio_get_attribute: - get attribute for virtual device
- * @vdev: The vio device to get property.
- * @which: The property/attribute to be extracted.
- * @length: Pointer to length of returned data size (unused if NULL).
- *
- * Calls prom.c's get_property() to return the value of the
- * attribute specified by the preprocessor constant @which
-*/
-const void * vio_get_attribute(struct vio_dev *vdev, void* which, int* length)
-{
- return get_property(vdev->dev.platform_data, (char*)which, length);
-}
-EXPORT_SYMBOL(vio_get_attribute);
-
-/* vio_find_name() - internal because only vio.c knows how we formatted the
- * kobject name
- * XXX once vio_bus_type.devices is actually used as a kset in
- * drivers/base/bus.c, this function should be removed in favor of
- * "device_find(kobj_name, &vio_bus_type)"
- */
-static struct vio_dev *vio_find_name(const char *kobj_name)
-{
- struct kobject *found;
-
- found = kset_find_obj(&devices_subsys.kset, kobj_name);
- if (!found)
- return NULL;
-
- return to_vio_dev(container_of(found, struct device, kobj));
-}
-
-/**
- * vio_find_node - find an already-registered vio_dev
- * @vnode: device_node of the virtual device we're looking for
- */
-struct vio_dev *vio_find_node(struct device_node *vnode)
-{
- uint32_t *unit_address;
- char kobj_name[BUS_ID_SIZE];
-
- /* construct the kobject name from the device node */
- unit_address = (uint32_t *)get_property(vnode, "reg", NULL);
- if (!unit_address)
- return NULL;
- snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address);
-
- return vio_find_name(kobj_name);
-}
-EXPORT_SYMBOL(vio_find_node);
-
-int vio_enable_interrupts(struct vio_dev *dev)
-{
- int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE);
- if (rc != H_SUCCESS)
- printk(KERN_ERR "vio: Error 0x%x enabling interrupts\n", rc);
- return rc;
-}
-EXPORT_SYMBOL(vio_enable_interrupts);
-
-int vio_disable_interrupts(struct vio_dev *dev)
-{
- int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE);
- if (rc != H_SUCCESS)
- printk(KERN_ERR "vio: Error 0x%x disabling interrupts\n", rc);
- return rc;
-}
-EXPORT_SYMBOL(vio_disable_interrupts);
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index 2d60ea3..b14f9b5 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -522,7 +522,7 @@ nextnode:
np = of_find_node_by_type(NULL, "interrupt-controller");
if (!np) {
- printk(KERN_WARNING "xics: no ISA interrupt controller\n");
+ printk(KERN_DEBUG "xics: no ISA interrupt controller\n");
xics_irq_8259_cascade_real = -1;
xics_irq_8259_cascade = -1;
} else {
@@ -641,23 +641,26 @@ void xics_teardown_cpu(int secondary)
ops->cppr_info(cpu, 0x00);
iosync();
+ /* Clear IPI */
+ ops->qirr_info(cpu, 0xff);
+
+ /*
+ * we need to EOI the IPI if we got here from kexec down IPI
+ *
+ * probably need to check all the other interrupts too
+ * should we be flagging idle loop instead?
+ * or creating some task to be scheduled?
+ */
+ ops->xirr_info_set(cpu, XICS_IPI);
+
/*
* Some machines need to have at least one cpu in the GIQ,
* so leave the master cpu in the group.
*/
- if (secondary) {
- /*
- * we need to EOI the IPI if we got here from kexec down IPI
- *
- * probably need to check all the other interrupts too
- * should we be flagging idle loop instead?
- * or creating some task to be scheduled?
- */
- ops->xirr_info_set(cpu, XICS_IPI);
+ if (secondary)
rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE,
(1UL << interrupt_server_size) - 1 -
default_distrib_server, 0);
- }
}
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 4c2b356..cef95b0 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -1,3 +1,7 @@
+ifeq ($(CONFIG_PPC64),y)
+EXTRA_CFLAGS += -mno-minimal-toc
+endif
+
obj-$(CONFIG_MPIC) += mpic.o
obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o
obj-$(CONFIG_PPC_I8259) += i8259.o
diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c
index 38087bd..6232091 100644
--- a/arch/powerpc/sysdev/dart_iommu.c
+++ b/arch/powerpc/sysdev/dart_iommu.c
@@ -246,7 +246,7 @@ static void iommu_table_dart_setup(void)
iommu_table_dart.it_base = (unsigned long)dart_vbase;
iommu_table_dart.it_index = 0;
iommu_table_dart.it_blocksize = 1;
- iommu_init_table(&iommu_table_dart);
+ iommu_init_table(&iommu_table_dart, -1);
/* Reserve the last page of the DART to avoid possible prefetch
* past the DART mapped area
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 7dcdfcb..bffe50d 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -829,7 +829,27 @@ void __init mpic_init(struct mpic *mpic)
mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0);
}
+void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio)
+{
+ u32 v;
+
+ v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1);
+ v &= ~MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO_MASK;
+ v |= MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO(clock_ratio);
+ mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v);
+}
+void __init mpic_set_serial_int(struct mpic *mpic, int enable)
+{
+ u32 v;
+
+ v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1);
+ if (enable)
+ v |= MPIC_GREG_GLOBAL_CONF_1_SIE;
+ else
+ v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE;
+ mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v);
+}
void mpic_irq_set_priority(unsigned int irq, unsigned int pri)
{
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 4735b41..0741df8 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -26,9 +26,6 @@
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/xmon.h>
-#ifdef CONFIG_PMAC_BACKLIGHT
-#include <asm/backlight.h>
-#endif
#include <asm/processor.h>
#include <asm/pgtable.h>
#include <asm/mmu.h>
diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
index e9a8f5d..b55de4f 100644
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -40,6 +40,10 @@ config GENERIC_NVRAM
bool
default y
+config GENERIC_FIND_NEXT_BIT
+ bool
+ default y
+
config SCHED_NO_NO_OMIT_FRAME_POINTER
bool
default y
diff --git a/arch/ppc/boot/lib/Makefile b/arch/ppc/boot/lib/Makefile
index 80c84d5..2f995f7 100644
--- a/arch/ppc/boot/lib/Makefile
+++ b/arch/ppc/boot/lib/Makefile
@@ -5,7 +5,7 @@
CFLAGS_kbd.o := -Idrivers/char
CFLAGS_vreset.o := -Iarch/ppc/boot/include
-zlib := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c
+zlib := inffast.c inflate.c inftrees.c
lib-y += $(zlib:.c=.o) div64.o
lib-$(CONFIG_VGA_CONSOLE) += vreset.o kbd.o
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 809673a..d20accf 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -1032,7 +1032,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
return -EINVAL;
vma->vm_pgoff = offset >> PAGE_SHIFT;
- vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
vma->vm_page_prot,
mmap_state, write_combine);
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
index 386e000..c9bd184 100644
--- a/arch/ppc/mm/init.c
+++ b/arch/ppc/mm/init.c
@@ -583,7 +583,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
mm = (address < TASK_SIZE)? vma->vm_mm: &init_mm;
pmd = pmd_offset(pgd_offset(mm, address), address);
if (!pmd_none(*pmd))
- add_hash_page(mm->context, address, pmd_val(*pmd));
+ add_hash_page(mm->context.id, address, pmd_val(*pmd));
}
#endif
}
diff --git a/arch/ppc/mm/mmu_context.c b/arch/ppc/mm/mmu_context.c
index b4a4b3f..8784f37 100644
--- a/arch/ppc/mm/mmu_context.c
+++ b/arch/ppc/mm/mmu_context.c
@@ -30,7 +30,7 @@
#include <asm/mmu_context.h>
#include <asm/tlbflush.h>
-mm_context_t next_mmu_context;
+unsigned long next_mmu_context;
unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1];
#ifdef FEW_CONTEXTS
atomic_t nr_free_contexts;
diff --git a/arch/ppc/mm/tlb.c b/arch/ppc/mm/tlb.c
index 6c3dc3c..606b023 100644
--- a/arch/ppc/mm/tlb.c
+++ b/arch/ppc/mm/tlb.c
@@ -42,7 +42,7 @@ void flush_hash_entry(struct mm_struct *mm, pte_t *ptep, unsigned long addr)
if (Hash != 0) {
ptephys = __pa(ptep) & PAGE_MASK;
- flush_hash_pages(mm->context, addr, ptephys, 1);
+ flush_hash_pages(mm->context.id, addr, ptephys, 1);
}
}
@@ -102,7 +102,7 @@ static void flush_range(struct mm_struct *mm, unsigned long start,
pmd_t *pmd;
unsigned long pmd_end;
int count;
- unsigned int ctx = mm->context;
+ unsigned int ctx = mm->context.id;
if (Hash == 0) {
_tlbia();
@@ -166,7 +166,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
mm = (vmaddr < TASK_SIZE)? vma->vm_mm: &init_mm;
pmd = pmd_offset(pgd_offset(mm, vmaddr), vmaddr);
if (!pmd_none(*pmd))
- flush_hash_pages(mm->context, vmaddr, pmd_val(*pmd), 1);
+ flush_hash_pages(mm->context.id, vmaddr, pmd_val(*pmd), 1);
FINISH_FLUSH;
}
diff --git a/arch/ppc/platforms/4xx/Kconfig b/arch/ppc/platforms/4xx/Kconfig
index 174ddbc..293bd48 100644
--- a/arch/ppc/platforms/4xx/Kconfig
+++ b/arch/ppc/platforms/4xx/Kconfig
@@ -183,7 +183,7 @@ config IBM_EMAC4
config BIOS_FIXUP
bool
- depends on BUBINGA || EP405 || SYCAMORE || WALNUT
+ depends on BUBINGA || EP405 || SYCAMORE || WALNUT || CPCI405
default y
# OAK doesn't exist but wanted to keep this around for any future 403GCX boards
diff --git a/arch/ppc/platforms/4xx/cpci405.c b/arch/ppc/platforms/4xx/cpci405.c
index 6571e39..970b698 100644
--- a/arch/ppc/platforms/4xx/cpci405.c
+++ b/arch/ppc/platforms/4xx/cpci405.c
@@ -1,10 +1,12 @@
/*
* Board setup routines for the esd CPCI-405 cPCI Board.
*
- * Author: Stefan Roese
- * stefan.roese@esd-electronics.com
+ * Copyright 2001-2006 esd electronic system design - hannover germany
*
- * Copyright 2001 esd electronic system design - hannover germany
+ * Authors: Matthias Fuchs
+ * matthias.fuchs@esd-electronics.com
+ * Stefan Roese
+ * stefan.roese@esd-electronics.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
@@ -20,9 +22,17 @@
#include <asm/pci-bridge.h>
#include <asm/machdep.h>
#include <asm/todc.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
#include <asm/ocp.h>
+#include <asm/ibm_ocp_pci.h>
+#include <platforms/4xx/ibm405gp.h>
+#ifdef CONFIG_GEN_RTC
void *cpci405_nvram;
+#endif
+
+extern bd_t __res;
/*
* Some IRQs unique to CPCI-405.
@@ -36,18 +46,69 @@ ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
* A B C D
*/
{
- {28, 28, 28, 28}, /* IDSEL 15 - cPCI slot 8 */
- {29, 29, 29, 29}, /* IDSEL 16 - cPCI slot 7 */
- {30, 30, 30, 30}, /* IDSEL 17 - cPCI slot 6 */
- {27, 27, 27, 27}, /* IDSEL 18 - cPCI slot 5 */
- {28, 28, 28, 28}, /* IDSEL 19 - cPCI slot 4 */
- {29, 29, 29, 29}, /* IDSEL 20 - cPCI slot 3 */
- {30, 30, 30, 30}, /* IDSEL 21 - cPCI slot 2 */
+ {28, 29, 30, 27}, /* IDSEL 15 - cPCI slot 8 */
+ {29, 30, 27, 28}, /* IDSEL 16 - cPCI slot 7 */
+ {30, 27, 28, 29}, /* IDSEL 17 - cPCI slot 6 */
+ {27, 28, 29, 30}, /* IDSEL 18 - cPCI slot 5 */
+ {28, 29, 30, 27}, /* IDSEL 19 - cPCI slot 4 */
+ {29, 30, 27, 28}, /* IDSEL 20 - cPCI slot 3 */
+ {30, 27, 28, 29}, /* IDSEL 21 - cPCI slot 2 */
};
const long min_idsel = 15, max_idsel = 21, irqs_per_slot = 4;
return PCI_IRQ_TABLE_LOOKUP;
};
+/* The serial clock for the chip is an internal clock determined by
+ * different clock speeds/dividers.
+ * Calculate the proper input baud rate and setup the serial driver.
+ */
+static void __init
+cpci405_early_serial_map(void)
+{
+ u32 uart_div;
+ int uart_clock;
+ struct uart_port port;
+
+ /* Calculate the serial clock input frequency
+ *
+ * The uart clock is the cpu frequency (provided in the board info
+ * structure) divided by the external UART Divisor.
+ */
+ uart_div = ((mfdcr(DCRN_CHCR_BASE) & CHR0_UDIV) >> 1) + 1;
+ uart_clock = __res.bi_procfreq / uart_div;
+
+ /* Setup serial port access */
+ memset(&port, 0, sizeof(port));
+#if defined(CONFIG_UART0_TTYS0)
+ port.membase = (void*)UART0_IO_BASE;
+ port.irq = UART0_INT;
+#else
+ port.membase = (void*)UART1_IO_BASE;
+ port.irq = UART1_INT;
+#endif
+ port.uartclk = uart_clock;
+ port.regshift = 0;
+ port.iotype = UPIO_MEM;
+ port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
+ port.line = 0;
+
+ if (early_serial_setup(&port) != 0) {
+ printk("Early serial init of port 0 failed\n");
+ }
+#if defined(CONFIG_UART0_TTYS0)
+ port.membase = (void*)UART1_IO_BASE;
+ port.irq = UART1_INT;
+#else
+ port.membase = (void*)UART0_IO_BASE;
+ port.irq = UART0_INT;
+#endif
+ port.line = 1;
+
+ if (early_serial_setup(&port) != 0) {
+ printk("Early serial init of port 1 failed\n");
+ }
+}
+
void __init
cpci405_setup_arch(void)
{
@@ -55,14 +116,68 @@ cpci405_setup_arch(void)
ibm_ocp_set_emac(0, 0);
- TODC_INIT(TODC_TYPE_MK48T35, cpci405_nvram, cpci405_nvram, cpci405_nvram, 8);
+ cpci405_early_serial_map();
+
+#ifdef CONFIG_GEN_RTC
+ TODC_INIT(TODC_TYPE_MK48T35,
+ cpci405_nvram, cpci405_nvram, cpci405_nvram, 8);
+#endif
+}
+
+void __init
+bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip)
+{
+ unsigned int bar_response, bar;
+
+ /* Disable region first */
+ out_le32((void *) &(pcip->pmm[0].ma), 0x00000000);
+ /* PLB starting addr, PCI: 0x80000000 */
+ out_le32((void *) &(pcip->pmm[0].la), 0x80000000);
+ /* PCI start addr, 0x80000000 */
+ out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE);
+ /* 512MB range of PLB to PCI */
+ out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000);
+ /* Enable no pre-fetch, enable region */
+ out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff -
+ (PPC405_PCI_UPPER_MEM -
+ PPC405_PCI_MEM_BASE)) | 0x01));
+
+ /* Disable region one */
+ out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].la), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+ out_le32((void *) &(pcip->ptm1ms), 0x00000001);
+
+ /* Disable region two */
+ out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].la), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+ out_le32((void *) &(pcip->ptm2ms), 0x00000000);
+ out_le32((void *) &(pcip->ptm2la), 0x00000000);
+
+ /* Zero config bars */
+ for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
+ early_write_config_dword(hose, hose->first_busno,
+ PCI_FUNC(hose->first_busno), bar,
+ 0x00000000);
+ early_read_config_dword(hose, hose->first_busno,
+ PCI_FUNC(hose->first_busno), bar,
+ &bar_response);
+ }
}
void __init
cpci405_map_io(void)
{
ppc4xx_map_io();
+
+#ifdef CONFIG_GEN_RTC
cpci405_nvram = ioremap(CPCI405_NVRAM_PADDR, CPCI405_NVRAM_SIZE);
+#endif
}
void __init
@@ -74,9 +189,11 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.setup_arch = cpci405_setup_arch;
ppc_md.setup_io_mappings = cpci405_map_io;
+#ifdef CONFIG_GEN_RTC
ppc_md.time_init = todc_time_init;
ppc_md.set_rtc_time = todc_set_rtc_time;
ppc_md.get_rtc_time = todc_get_rtc_time;
ppc_md.nvram_read_val = todc_direct_read_val;
ppc_md.nvram_write_val = todc_direct_write_val;
+#endif
}
diff --git a/arch/ppc/platforms/4xx/cpci405.h b/arch/ppc/platforms/4xx/cpci405.h
index e27f7cb..f5a5c0c 100644
--- a/arch/ppc/platforms/4xx/cpci405.h
+++ b/arch/ppc/platforms/4xx/cpci405.h
@@ -1,37 +1,29 @@
/*
* CPCI-405 board specific definitions
*
- * Copyright (c) 2001 Stefan Roese (stefan.roese@esd-electronics.com)
+ * Copyright 2001-2006 esd electronic system design - hannover germany
+ *
+ * Authors: Matthias Fuchs
+ * matthias.fuchs@esd-electronics.com
+ * Stefan Roese
+ * stefan.roese@esd-electronics.com
*/
#ifdef __KERNEL__
-#ifndef __ASM_CPCI405_H__
-#define __ASM_CPCI405_H__
+#ifndef __CPCI405_H__
+#define __CPCI405_H__
#include <linux/config.h>
-
-/* We have a 405GP core */
#include <platforms/4xx/ibm405gp.h>
-
#include <asm/ppcboot.h>
-#ifndef __ASSEMBLY__
-/* Some 4xx parts use a different timebase frequency from the internal clock.
-*/
-#define bi_tbfreq bi_intfreq
-
/* Map for the NVRAM space */
#define CPCI405_NVRAM_PADDR ((uint)0xf0200000)
#define CPCI405_NVRAM_SIZE ((uint)32*1024)
-#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK
-#define BASE_BAUD 201600
-#else
-#define BASE_BAUD 691200
-#endif
+#define BASE_BAUD 0
-#define PPC4xx_MACHINE_NAME "esd CPCI-405"
+#define PPC4xx_MACHINE_NAME "esd CPCI-405"
-#endif /* !__ASSEMBLY__ */
-#endif /* __ASM_CPCI405_H__ */
+#endif /* __CPCI405_H__ */
#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
index c9e0aee..4368dc3 100644
--- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
+++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
@@ -379,13 +379,12 @@ mpc85xx_cds_pcibios_fixup(void)
PCI_DEVICE_ID_VIA_82C586_2, NULL))) {
dev->irq = 10;
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 10);
- pci_dev_put(dev);
- }
- if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
+ if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
PCI_DEVICE_ID_VIA_82C586_2, dev))) {
- dev->irq = 11;
- pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
+ dev->irq = 11;
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
+ }
pci_dev_put(dev);
}
}
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 01c5c08..821a141 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -446,6 +446,14 @@ config NO_IDLE_HZ_INIT
The HZ timer is switched off in idle by default. That means the
HZ timer is already disabled at boot time.
+config S390_HYPFS_FS
+ bool "s390 hypervisor file system support"
+ select SYS_HYPERVISOR
+ default y
+ help
+ This is a virtual file system intended to provide accounting
+ information in an s390 hypervisor environment.
+
config KEXEC
bool "kexec system call (EXPERIMENTAL)"
depends on EXPERIMENTAL
diff --git a/arch/s390/Makefile b/arch/s390/Makefile
index 7bb16fb..b3791fb 100644
--- a/arch/s390/Makefile
+++ b/arch/s390/Makefile
@@ -76,7 +76,7 @@ LDFLAGS_vmlinux := -e start
head-y := arch/$(ARCH)/kernel/head.o arch/$(ARCH)/kernel/init_task.o
core-y += arch/$(ARCH)/mm/ arch/$(ARCH)/kernel/ arch/$(ARCH)/crypto/ \
- arch/$(ARCH)/appldata/
+ arch/$(ARCH)/appldata/ arch/$(ARCH)/hypfs/
libs-y += arch/$(ARCH)/lib/
drivers-y += drivers/s390/
drivers-$(CONFIG_MATHEMU) += arch/$(ARCH)/math-emu/
diff --git a/arch/s390/hypfs/Makefile b/arch/s390/hypfs/Makefile
new file mode 100644
index 0000000..f4b00cd
--- /dev/null
+++ b/arch/s390/hypfs/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the linux hypfs filesystem routines.
+#
+
+obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o
+
+s390_hypfs-objs := inode.o hypfs_diag.o
diff --git a/arch/s390/hypfs/hypfs.h b/arch/s390/hypfs/hypfs.h
new file mode 100644
index 0000000..ea5567b
--- /dev/null
+++ b/arch/s390/hypfs/hypfs.h
@@ -0,0 +1,30 @@
+/*
+ * fs/hypfs/hypfs.h
+ * Hypervisor filesystem for Linux on s390.
+ *
+ * Copyright (C) IBM Corp. 2006
+ * Author(s): Michael Holzheu <holzheu@de.ibm.com>
+ */
+
+#ifndef _HYPFS_H_
+#define _HYPFS_H_
+
+#include <linux/fs.h>
+#include <linux/types.h>
+
+#define REG_FILE_MODE 0440
+#define UPDATE_FILE_MODE 0220
+#define DIR_MODE 0550
+
+extern struct dentry *hypfs_mkdir(struct super_block *sb, struct dentry *parent,
+ const char *name);
+
+extern struct dentry *hypfs_create_u64(struct super_block *sb,
+ struct dentry *dir, const char *name,
+ __u64 value);
+
+extern struct dentry *hypfs_create_str(struct super_block *sb,
+ struct dentry *dir, const char *name,
+ char *string);
+
+#endif /* _HYPFS_H_ */
diff --git a/arch/s390/hypfs/hypfs_diag.c b/arch/s390/hypfs/hypfs_diag.c
new file mode 100644
index 0000000..efa74af
--- /dev/null
+++ b/arch/s390/hypfs/hypfs_diag.c
@@ -0,0 +1,696 @@
+/*
+ * fs/hypfs/hypfs_diag.c
+ * Hypervisor filesystem for Linux on s390. Diag 204 and 224
+ * implementation.
+ *
+ * Copyright (C) IBM Corp. 2006
+ * Author(s): Michael Holzheu <holzheu@de.ibm.com>
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <asm/ebcdic.h>
+#include "hypfs.h"
+
+#define LPAR_NAME_LEN 8 /* lpar name len in diag 204 data */
+#define CPU_NAME_LEN 16 /* type name len of cpus in diag224 name table */
+#define TMP_SIZE 64 /* size of temporary buffers */
+
+/* diag 204 subcodes */
+enum diag204_sc {
+ SUBC_STIB4 = 4,
+ SUBC_RSI = 5,
+ SUBC_STIB6 = 6,
+ SUBC_STIB7 = 7
+};
+
+/* The two available diag 204 data formats */
+enum diag204_format {
+ INFO_SIMPLE = 0,
+ INFO_EXT = 0x00010000
+};
+
+/* bit is set in flags, when physical cpu info is included in diag 204 data */
+#define LPAR_PHYS_FLG 0x80
+
+static char *diag224_cpu_names; /* diag 224 name table */
+static enum diag204_sc diag204_store_sc; /* used subcode for store */
+static enum diag204_format diag204_info_type; /* used diag 204 data format */
+
+static void *diag204_buf; /* 4K aligned buffer for diag204 data */
+static void *diag204_buf_vmalloc; /* vmalloc pointer for diag204 data */
+static int diag204_buf_pages; /* number of pages for diag204 data */
+
+/*
+ * DIAG 204 data structures and member access functions.
+ *
+ * Since we have two different diag 204 data formats for old and new s390
+ * machines, we do not access the structs directly, but use getter functions for
+ * each struct member instead. This should make the code more readable.
+ */
+
+/* Time information block */
+
+struct info_blk_hdr {
+ __u8 npar;
+ __u8 flags;
+ __u16 tslice;
+ __u16 phys_cpus;
+ __u16 this_part;
+ __u64 curtod;
+} __attribute__ ((packed));
+
+struct x_info_blk_hdr {
+ __u8 npar;
+ __u8 flags;
+ __u16 tslice;
+ __u16 phys_cpus;
+ __u16 this_part;
+ __u64 curtod1;
+ __u64 curtod2;
+ char reserved[40];
+} __attribute__ ((packed));
+
+static inline int info_blk_hdr__size(enum diag204_format type)
+{
+ if (type == INFO_SIMPLE)
+ return sizeof(struct info_blk_hdr);
+ else /* INFO_EXT */
+ return sizeof(struct x_info_blk_hdr);
+}
+
+static inline __u8 info_blk_hdr__npar(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct info_blk_hdr *)hdr)->npar;
+ else /* INFO_EXT */
+ return ((struct x_info_blk_hdr *)hdr)->npar;
+}
+
+static inline __u8 info_blk_hdr__flags(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct info_blk_hdr *)hdr)->flags;
+ else /* INFO_EXT */
+ return ((struct x_info_blk_hdr *)hdr)->flags;
+}
+
+static inline __u16 info_blk_hdr__pcpus(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct info_blk_hdr *)hdr)->phys_cpus;
+ else /* INFO_EXT */
+ return ((struct x_info_blk_hdr *)hdr)->phys_cpus;
+}
+
+/* Partition header */
+
+struct part_hdr {
+ __u8 pn;
+ __u8 cpus;
+ char reserved[6];
+ char part_name[LPAR_NAME_LEN];
+} __attribute__ ((packed));
+
+struct x_part_hdr {
+ __u8 pn;
+ __u8 cpus;
+ __u8 rcpus;
+ __u8 pflag;
+ __u32 mlu;
+ char part_name[LPAR_NAME_LEN];
+ char lpc_name[8];
+ char os_name[8];
+ __u64 online_cs;
+ __u64 online_es;
+ __u8 upid;
+ char reserved1[3];
+ __u32 group_mlu;
+ char group_name[8];
+ char reserved2[32];
+} __attribute__ ((packed));
+
+static inline int part_hdr__size(enum diag204_format type)
+{
+ if (type == INFO_SIMPLE)
+ return sizeof(struct part_hdr);
+ else /* INFO_EXT */
+ return sizeof(struct x_part_hdr);
+}
+
+static inline __u8 part_hdr__rcpus(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct part_hdr *)hdr)->cpus;
+ else /* INFO_EXT */
+ return ((struct x_part_hdr *)hdr)->rcpus;
+}
+
+static inline void part_hdr__part_name(enum diag204_format type, void *hdr,
+ char *name)
+{
+ if (type == INFO_SIMPLE)
+ memcpy(name, ((struct part_hdr *)hdr)->part_name,
+ LPAR_NAME_LEN);
+ else /* INFO_EXT */
+ memcpy(name, ((struct x_part_hdr *)hdr)->part_name,
+ LPAR_NAME_LEN);
+ EBCASC(name, LPAR_NAME_LEN);
+ name[LPAR_NAME_LEN] = 0;
+ strstrip(name);
+}
+
+struct cpu_info {
+ __u16 cpu_addr;
+ char reserved1[2];
+ __u8 ctidx;
+ __u8 cflag;
+ __u16 weight;
+ __u64 acc_time;
+ __u64 lp_time;
+} __attribute__ ((packed));
+
+struct x_cpu_info {
+ __u16 cpu_addr;
+ char reserved1[2];
+ __u8 ctidx;
+ __u8 cflag;
+ __u16 weight;
+ __u64 acc_time;
+ __u64 lp_time;
+ __u16 min_weight;
+ __u16 cur_weight;
+ __u16 max_weight;
+ char reseved2[2];
+ __u64 online_time;
+ __u64 wait_time;
+ __u32 pma_weight;
+ __u32 polar_weight;
+ char reserved3[40];
+} __attribute__ ((packed));
+
+/* CPU info block */
+
+static inline int cpu_info__size(enum diag204_format type)
+{
+ if (type == INFO_SIMPLE)
+ return sizeof(struct cpu_info);
+ else /* INFO_EXT */
+ return sizeof(struct x_cpu_info);
+}
+
+static inline __u8 cpu_info__ctidx(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct cpu_info *)hdr)->ctidx;
+ else /* INFO_EXT */
+ return ((struct x_cpu_info *)hdr)->ctidx;
+}
+
+static inline __u16 cpu_info__cpu_addr(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct cpu_info *)hdr)->cpu_addr;
+ else /* INFO_EXT */
+ return ((struct x_cpu_info *)hdr)->cpu_addr;
+}
+
+static inline __u64 cpu_info__acc_time(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct cpu_info *)hdr)->acc_time;
+ else /* INFO_EXT */
+ return ((struct x_cpu_info *)hdr)->acc_time;
+}
+
+static inline __u64 cpu_info__lp_time(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct cpu_info *)hdr)->lp_time;
+ else /* INFO_EXT */
+ return ((struct x_cpu_info *)hdr)->lp_time;
+}
+
+static inline __u64 cpu_info__online_time(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return 0; /* online_time not available in simple info */
+ else /* INFO_EXT */
+ return ((struct x_cpu_info *)hdr)->online_time;
+}
+
+/* Physical header */
+
+struct phys_hdr {
+ char reserved1[1];
+ __u8 cpus;
+ char reserved2[6];
+ char mgm_name[8];
+} __attribute__ ((packed));
+
+struct x_phys_hdr {
+ char reserved1[1];
+ __u8 cpus;
+ char reserved2[6];
+ char mgm_name[8];
+ char reserved3[80];
+} __attribute__ ((packed));
+
+static inline int phys_hdr__size(enum diag204_format type)
+{
+ if (type == INFO_SIMPLE)
+ return sizeof(struct phys_hdr);
+ else /* INFO_EXT */
+ return sizeof(struct x_phys_hdr);
+}
+
+static inline __u8 phys_hdr__cpus(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct phys_hdr *)hdr)->cpus;
+ else /* INFO_EXT */
+ return ((struct x_phys_hdr *)hdr)->cpus;
+}
+
+/* Physical CPU info block */
+
+struct phys_cpu {
+ __u16 cpu_addr;
+ char reserved1[2];
+ __u8 ctidx;
+ char reserved2[3];
+ __u64 mgm_time;
+ char reserved3[8];
+} __attribute__ ((packed));
+
+struct x_phys_cpu {
+ __u16 cpu_addr;
+ char reserved1[2];
+ __u8 ctidx;
+ char reserved2[3];
+ __u64 mgm_time;
+ char reserved3[80];
+} __attribute__ ((packed));
+
+static inline int phys_cpu__size(enum diag204_format type)
+{
+ if (type == INFO_SIMPLE)
+ return sizeof(struct phys_cpu);
+ else /* INFO_EXT */
+ return sizeof(struct x_phys_cpu);
+}
+
+static inline __u16 phys_cpu__cpu_addr(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct phys_cpu *)hdr)->cpu_addr;
+ else /* INFO_EXT */
+ return ((struct x_phys_cpu *)hdr)->cpu_addr;
+}
+
+static inline __u64 phys_cpu__mgm_time(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct phys_cpu *)hdr)->mgm_time;
+ else /* INFO_EXT */
+ return ((struct x_phys_cpu *)hdr)->mgm_time;
+}
+
+static inline __u64 phys_cpu__ctidx(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct phys_cpu *)hdr)->ctidx;
+ else /* INFO_EXT */
+ return ((struct x_phys_cpu *)hdr)->ctidx;
+}
+
+/* Diagnose 204 functions */
+
+static int diag204(unsigned long subcode, unsigned long size, void *addr)
+{
+ register unsigned long _subcode asm("0") = subcode;
+ register unsigned long _size asm("1") = size;
+
+ asm volatile (" diag %2,%0,0x204\n"
+ "0: \n" ".section __ex_table,\"a\"\n"
+#ifndef __s390x__
+ " .align 4\n"
+ " .long 0b,0b\n"
+#else
+ " .align 8\n"
+ " .quad 0b,0b\n"
+#endif
+ ".previous":"+d" (_subcode), "+d"(_size)
+ :"d"(addr)
+ :"memory");
+ if (_subcode)
+ return -1;
+ else
+ return _size;
+}
+
+/*
+ * For the old diag subcode 4 with simple data format we have to use real
+ * memory. If we use subcode 6 or 7 with extended data format, we can (and
+ * should) use vmalloc, since we need a lot of memory in that case. Currently
+ * up to 93 pages!
+ */
+
+static void diag204_free_buffer(void)
+{
+ if (!diag204_buf)
+ return;
+ if (diag204_buf_vmalloc) {
+ vfree(diag204_buf_vmalloc);
+ diag204_buf_vmalloc = NULL;
+ } else {
+ free_pages((unsigned long) diag204_buf, 0);
+ }
+ diag204_buf_pages = 0;
+ diag204_buf = NULL;
+}
+
+static void *diag204_alloc_vbuf(int pages)
+{
+ /* The buffer has to be page aligned! */
+ diag204_buf_vmalloc = vmalloc(PAGE_SIZE * (pages + 1));
+ if (!diag204_buf_vmalloc)
+ return ERR_PTR(-ENOMEM);
+ diag204_buf = (void*)((unsigned long)diag204_buf_vmalloc
+ & ~0xfffUL) + 0x1000;
+ diag204_buf_pages = pages;
+ return diag204_buf;
+}
+
+static void *diag204_alloc_rbuf(void)
+{
+ diag204_buf = (void*)__get_free_pages(GFP_KERNEL,0);
+ if (diag204_buf)
+ return ERR_PTR(-ENOMEM);
+ diag204_buf_pages = 1;
+ return diag204_buf;
+}
+
+static void *diag204_get_buffer(enum diag204_format fmt, int *pages)
+{
+ if (diag204_buf) {
+ *pages = diag204_buf_pages;
+ return diag204_buf;
+ }
+ if (fmt == INFO_SIMPLE) {
+ *pages = 1;
+ return diag204_alloc_rbuf();
+ } else {/* INFO_EXT */
+ *pages = diag204(SUBC_RSI | INFO_EXT, 0, 0);
+ if (*pages <= 0)
+ return ERR_PTR(-ENOSYS);
+ else
+ return diag204_alloc_vbuf(*pages);
+ }
+}
+
+/*
+ * diag204_probe() has to find out, which type of diagnose 204 implementation
+ * we have on our machine. Currently there are three possible scanarios:
+ * - subcode 4 + simple data format (only one page)
+ * - subcode 4-6 + extended data format
+ * - subcode 4-7 + extended data format
+ *
+ * Subcode 5 is used to retrieve the size of the data, provided by subcodes
+ * 6 and 7. Subcode 7 basically has the same function as subcode 6. In addition
+ * to subcode 6 it provides also information about secondary cpus.
+ * In order to get as much information as possible, we first try
+ * subcode 7, then 6 and if both fail, we use subcode 4.
+ */
+
+static int diag204_probe(void)
+{
+ void *buf;
+ int pages, rc;
+
+ buf = diag204_get_buffer(INFO_EXT, &pages);
+ if (!IS_ERR(buf)) {
+ if (diag204(SUBC_STIB7 | INFO_EXT, pages, buf) >= 0) {
+ diag204_store_sc = SUBC_STIB7;
+ diag204_info_type = INFO_EXT;
+ goto out;
+ }
+ if (diag204(SUBC_STIB6 | INFO_EXT, pages, buf) >= 0) {
+ diag204_store_sc = SUBC_STIB7;
+ diag204_info_type = INFO_EXT;
+ goto out;
+ }
+ diag204_free_buffer();
+ }
+
+ /* subcodes 6 and 7 failed, now try subcode 4 */
+
+ buf = diag204_get_buffer(INFO_SIMPLE, &pages);
+ if (IS_ERR(buf)) {
+ rc = PTR_ERR(buf);
+ goto fail_alloc;
+ }
+ if (diag204(SUBC_STIB4 | INFO_SIMPLE, pages, buf) >= 0) {
+ diag204_store_sc = SUBC_STIB4;
+ diag204_info_type = INFO_SIMPLE;
+ goto out;
+ } else {
+ rc = -ENOSYS;
+ goto fail_store;
+ }
+out:
+ rc = 0;
+fail_store:
+ diag204_free_buffer();
+fail_alloc:
+ return rc;
+}
+
+static void *diag204_store(void)
+{
+ void *buf;
+ int pages;
+
+ buf = diag204_get_buffer(diag204_info_type, &pages);
+ if (IS_ERR(buf))
+ goto out;
+ if (diag204(diag204_store_sc | diag204_info_type, pages, buf) < 0)
+ return ERR_PTR(-ENOSYS);
+out:
+ return buf;
+}
+
+/* Diagnose 224 functions */
+
+static void diag224(void *ptr)
+{
+ asm volatile(" diag %0,%1,0x224\n"
+ : :"d" (0), "d"(ptr) : "memory");
+}
+
+static int diag224_get_name_table(void)
+{
+ /* memory must be below 2GB */
+ diag224_cpu_names = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
+ if (!diag224_cpu_names)
+ return -ENOMEM;
+ diag224(diag224_cpu_names);
+ EBCASC(diag224_cpu_names + 16, (*diag224_cpu_names + 1) * 16);
+ return 0;
+}
+
+static void diag224_delete_name_table(void)
+{
+ kfree(diag224_cpu_names);
+}
+
+static int diag224_idx2name(int index, char *name)
+{
+ memcpy(name, diag224_cpu_names + ((index + 1) * CPU_NAME_LEN),
+ CPU_NAME_LEN);
+ name[CPU_NAME_LEN] = 0;
+ strstrip(name);
+ return 0;
+}
+
+__init int hypfs_diag_init(void)
+{
+ int rc;
+
+ if (diag204_probe()) {
+ printk(KERN_ERR "hypfs: diag 204 not working.");
+ return -ENODATA;
+ }
+ rc = diag224_get_name_table();
+ if (rc) {
+ diag224_delete_name_table();
+ printk(KERN_ERR "hypfs: could not get name table.\n");
+ }
+ return rc;
+}
+
+__exit void hypfs_diag_exit(void)
+{
+ diag224_delete_name_table();
+ diag204_free_buffer();
+}
+
+/*
+ * Functions to create the directory structure
+ * *******************************************
+ */
+
+static int hypfs_create_cpu_files(struct super_block *sb,
+ struct dentry *cpus_dir, void *cpu_info)
+{
+ struct dentry *cpu_dir;
+ char buffer[TMP_SIZE];
+ void *rc;
+
+ snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_info_type,
+ cpu_info));
+ cpu_dir = hypfs_mkdir(sb, cpus_dir, buffer);
+ rc = hypfs_create_u64(sb, cpu_dir, "mgmtime",
+ cpu_info__acc_time(diag204_info_type, cpu_info) -
+ cpu_info__lp_time(diag204_info_type, cpu_info));
+ if (IS_ERR(rc))
+ return PTR_ERR(rc);
+ rc = hypfs_create_u64(sb, cpu_dir, "cputime",
+ cpu_info__lp_time(diag204_info_type, cpu_info));
+ if (IS_ERR(rc))
+ return PTR_ERR(rc);
+ if (diag204_info_type == INFO_EXT) {
+ rc = hypfs_create_u64(sb, cpu_dir, "onlinetime",
+ cpu_info__online_time(diag204_info_type,
+ cpu_info));
+ if (IS_ERR(rc))
+ return PTR_ERR(rc);
+ }
+ diag224_idx2name(cpu_info__ctidx(diag204_info_type, cpu_info), buffer);
+ rc = hypfs_create_str(sb, cpu_dir, "type", buffer);
+ if (IS_ERR(rc))
+ return PTR_ERR(rc);
+ return 0;
+}
+
+static void *hypfs_create_lpar_files(struct super_block *sb,
+ struct dentry *systems_dir, void *part_hdr)
+{
+ struct dentry *cpus_dir;
+ struct dentry *lpar_dir;
+ char lpar_name[LPAR_NAME_LEN + 1];
+ void *cpu_info;
+ int i;
+
+ part_hdr__part_name(diag204_info_type, part_hdr, lpar_name);
+ lpar_name[LPAR_NAME_LEN] = 0;
+ lpar_dir = hypfs_mkdir(sb, systems_dir, lpar_name);
+ if (IS_ERR(lpar_dir))
+ return lpar_dir;
+ cpus_dir = hypfs_mkdir(sb, lpar_dir, "cpus");
+ if (IS_ERR(cpus_dir))
+ return cpus_dir;
+ cpu_info = part_hdr + part_hdr__size(diag204_info_type);
+ for (i = 0; i < part_hdr__rcpus(diag204_info_type, part_hdr); i++) {
+ int rc;
+ rc = hypfs_create_cpu_files(sb, cpus_dir, cpu_info);
+ if (rc)
+ return ERR_PTR(rc);
+ cpu_info += cpu_info__size(diag204_info_type);
+ }
+ return cpu_info;
+}
+
+static int hypfs_create_phys_cpu_files(struct super_block *sb,
+ struct dentry *cpus_dir, void *cpu_info)
+{
+ struct dentry *cpu_dir;
+ char buffer[TMP_SIZE];
+ void *rc;
+
+ snprintf(buffer, TMP_SIZE, "%i", phys_cpu__cpu_addr(diag204_info_type,
+ cpu_info));
+ cpu_dir = hypfs_mkdir(sb, cpus_dir, buffer);
+ if (IS_ERR(cpu_dir))
+ return PTR_ERR(cpu_dir);
+ rc = hypfs_create_u64(sb, cpu_dir, "mgmtime",
+ phys_cpu__mgm_time(diag204_info_type, cpu_info));
+ if (IS_ERR(rc))
+ return PTR_ERR(rc);
+ diag224_idx2name(phys_cpu__ctidx(diag204_info_type, cpu_info), buffer);
+ rc = hypfs_create_str(sb, cpu_dir, "type", buffer);
+ if (IS_ERR(rc))
+ return PTR_ERR(rc);
+ return 0;
+}
+
+static void *hypfs_create_phys_files(struct super_block *sb,
+ struct dentry *parent_dir, void *phys_hdr)
+{
+ int i;
+ void *cpu_info;
+ struct dentry *cpus_dir;
+
+ cpus_dir = hypfs_mkdir(sb, parent_dir, "cpus");
+ if (IS_ERR(cpus_dir))
+ return cpus_dir;
+ cpu_info = phys_hdr + phys_hdr__size(diag204_info_type);
+ for (i = 0; i < phys_hdr__cpus(diag204_info_type, phys_hdr); i++) {
+ int rc;
+ rc = hypfs_create_phys_cpu_files(sb, cpus_dir, cpu_info);
+ if (rc)
+ return ERR_PTR(rc);
+ cpu_info += phys_cpu__size(diag204_info_type);
+ }
+ return cpu_info;
+}
+
+int hypfs_diag_create_files(struct super_block *sb, struct dentry *root)
+{
+ struct dentry *systems_dir, *hyp_dir;
+ void *time_hdr, *part_hdr;
+ int i, rc;
+ void *buffer, *ptr;
+
+ buffer = diag204_store();
+ if (IS_ERR(buffer))
+ return PTR_ERR(buffer);
+
+ systems_dir = hypfs_mkdir(sb, root, "systems");
+ if (IS_ERR(systems_dir)) {
+ rc = PTR_ERR(systems_dir);
+ goto err_out;
+ }
+ time_hdr = (struct x_info_blk_hdr *)buffer;
+ part_hdr = time_hdr + info_blk_hdr__size(diag204_info_type);
+ for (i = 0; i < info_blk_hdr__npar(diag204_info_type, time_hdr); i++) {
+ part_hdr = hypfs_create_lpar_files(sb, systems_dir, part_hdr);
+ if (IS_ERR(part_hdr)) {
+ rc = PTR_ERR(part_hdr);
+ goto err_out;
+ }
+ }
+ if (info_blk_hdr__flags(diag204_info_type, time_hdr) & LPAR_PHYS_FLG) {
+ ptr = hypfs_create_phys_files(sb, root, part_hdr);
+ if (IS_ERR(ptr)) {
+ rc = PTR_ERR(ptr);
+ goto err_out;
+ }
+ }
+ hyp_dir = hypfs_mkdir(sb, root, "hyp");
+ if (IS_ERR(hyp_dir)) {
+ rc = PTR_ERR(hyp_dir);
+ goto err_out;
+ }
+ ptr = hypfs_create_str(sb, hyp_dir, "type", "LPAR Hypervisor");
+ if (IS_ERR(ptr)) {
+ rc = PTR_ERR(ptr);
+ goto err_out;
+ }
+ rc = 0;
+
+err_out:
+ return rc;
+}
diff --git a/arch/s390/hypfs/hypfs_diag.h b/arch/s390/hypfs/hypfs_diag.h
new file mode 100644
index 0000000..793dea6
--- /dev/null
+++ b/arch/s390/hypfs/hypfs_diag.h
@@ -0,0 +1,16 @@
+/*
+ * fs/hypfs/hypfs_diag.h
+ * Hypervisor filesystem for Linux on s390.
+ *
+ * Copyright (C) IBM Corp. 2006
+ * Author(s): Michael Holzheu <holzheu@de.ibm.com>
+ */
+
+#ifndef _HYPFS_DIAG_H_
+#define _HYPFS_DIAG_H_
+
+extern int hypfs_diag_init(void);
+extern void hypfs_diag_exit(void);
+extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root);
+
+#endif /* _HYPFS_DIAG_H_ */
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
new file mode 100644
index 0000000..18c0919
--- /dev/null
+++ b/arch/s390/hypfs/inode.c
@@ -0,0 +1,491 @@
+/*
+ * fs/hypfs/inode.c
+ * Hypervisor filesystem for Linux on s390.
+ *
+ * Copyright (C) IBM Corp. 2006
+ * Author(s): Michael Holzheu <holzheu@de.ibm.com>
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/vfs.h>
+#include <linux/pagemap.h>
+#include <linux/gfp.h>
+#include <linux/time.h>
+#include <linux/parser.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <asm/ebcdic.h>
+#include "hypfs.h"
+#include "hypfs_diag.h"
+
+#define HYPFS_MAGIC 0x687970 /* ASCII 'hyp' */
+#define TMP_SIZE 64 /* size of temporary buffers */
+
+static struct dentry *hypfs_create_update_file(struct super_block *sb,
+ struct dentry *dir);
+
+struct hypfs_sb_info {
+ uid_t uid; /* uid used for files and dirs */
+ gid_t gid; /* gid used for files and dirs */
+ struct dentry *update_file; /* file to trigger update */
+ time_t last_update; /* last update time in secs since 1970 */
+ struct mutex lock; /* lock to protect update process */
+};
+
+static struct file_operations hypfs_file_ops;
+static struct file_system_type hypfs_type;
+static struct super_operations hypfs_s_ops;
+
+/* start of list of all dentries, which have to be deleted on update */
+static struct dentry *hypfs_last_dentry;
+
+static void hypfs_update_update(struct super_block *sb)
+{
+ struct hypfs_sb_info *sb_info = sb->s_fs_info;
+ struct inode *inode = sb_info->update_file->d_inode;
+
+ sb_info->last_update = get_seconds();
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+}
+
+/* directory tree removal functions */
+
+static void hypfs_add_dentry(struct dentry *dentry)
+{
+ dentry->d_fsdata = hypfs_last_dentry;
+ hypfs_last_dentry = dentry;
+}
+
+static void hypfs_remove(struct dentry *dentry)
+{
+ struct dentry *parent;
+
+ parent = dentry->d_parent;
+ if (S_ISDIR(dentry->d_inode->i_mode))
+ simple_rmdir(parent->d_inode, dentry);
+ else
+ simple_unlink(parent->d_inode, dentry);
+ d_delete(dentry);
+ dput(dentry);
+}
+
+static void hypfs_delete_tree(struct dentry *root)
+{
+ while (hypfs_last_dentry) {
+ struct dentry *next_dentry;
+ next_dentry = hypfs_last_dentry->d_fsdata;
+ hypfs_remove(hypfs_last_dentry);
+ hypfs_last_dentry = next_dentry;
+ }
+}
+
+static struct inode *hypfs_make_inode(struct super_block *sb, int mode)
+{
+ struct inode *ret = new_inode(sb);
+
+ if (ret) {
+ struct hypfs_sb_info *hypfs_info = sb->s_fs_info;
+ ret->i_mode = mode;
+ ret->i_uid = hypfs_info->uid;
+ ret->i_gid = hypfs_info->gid;
+ ret->i_blksize = PAGE_CACHE_SIZE;
+ ret->i_blocks = 0;
+ ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
+ if (mode & S_IFDIR)
+ ret->i_nlink = 2;
+ else
+ ret->i_nlink = 1;
+ }
+ return ret;
+}
+
+static void hypfs_drop_inode(struct inode *inode)
+{
+ kfree(inode->u.generic_ip);
+ generic_delete_inode(inode);
+}
+
+static int hypfs_open(struct inode *inode, struct file *filp)
+{
+ char *data = filp->f_dentry->d_inode->u.generic_ip;
+ struct hypfs_sb_info *fs_info;
+
+ if (filp->f_mode & FMODE_WRITE) {
+ if (!(inode->i_mode & S_IWUGO))
+ return -EACCES;
+ }
+ if (filp->f_mode & FMODE_READ) {
+ if (!(inode->i_mode & S_IRUGO))
+ return -EACCES;
+ }
+
+ fs_info = inode->i_sb->s_fs_info;
+ if(data) {
+ mutex_lock(&fs_info->lock);
+ filp->private_data = kstrdup(data, GFP_KERNEL);
+ if (!filp->private_data) {
+ mutex_unlock(&fs_info->lock);
+ return -ENOMEM;
+ }
+ mutex_unlock(&fs_info->lock);
+ }
+ return 0;
+}
+
+static ssize_t hypfs_aio_read(struct kiocb *iocb, __user char *buf,
+ size_t count, loff_t offset)
+{
+ char *data;
+ size_t len;
+ struct file *filp = iocb->ki_filp;
+
+ data = filp->private_data;
+ len = strlen(data);
+ if (offset > len) {
+ count = 0;
+ goto out;
+ }
+ if (count > len - offset)
+ count = len - offset;
+ if (copy_to_user(buf, data + offset, count)) {
+ count = -EFAULT;
+ goto out;
+ }
+ iocb->ki_pos += count;
+ file_accessed(filp);
+out:
+ return count;
+}
+static ssize_t hypfs_aio_write(struct kiocb *iocb, const char __user *buf,
+ size_t count, loff_t pos)
+{
+ int rc;
+ struct super_block *sb;
+ struct hypfs_sb_info *fs_info;
+
+ sb = iocb->ki_filp->f_dentry->d_inode->i_sb;
+ fs_info = sb->s_fs_info;
+ /*
+ * Currently we only allow one update per second for two reasons:
+ * 1. diag 204 is VERY expensive
+ * 2. If several processes do updates in parallel and then read the
+ * hypfs data, the likelihood of collisions is reduced, if we restrict
+ * the minimum update interval. A collision occurs, if during the
+ * data gathering of one process another process triggers an update
+ * If the first process wants to ensure consistent data, it has
+ * to restart data collection in this case.
+ */
+ mutex_lock(&fs_info->lock);
+ if (fs_info->last_update == get_seconds()) {
+ rc = -EBUSY;
+ goto out;
+ }
+ hypfs_delete_tree(sb->s_root);
+ rc = hypfs_diag_create_files(sb, sb->s_root);
+ if (rc) {
+ printk(KERN_ERR "hypfs: Update failed\n");
+ hypfs_delete_tree(sb->s_root);
+ goto out;
+ }
+ hypfs_update_update(sb);
+ rc = count;
+out:
+ mutex_unlock(&fs_info->lock);
+ return rc;
+}
+
+static int hypfs_release(struct inode *inode, struct file *filp)
+{
+ kfree(filp->private_data);
+ return 0;
+}
+
+enum { opt_uid, opt_gid, opt_err };
+
+static match_table_t hypfs_tokens = {
+ {opt_uid, "uid=%u"},
+ {opt_gid, "gid=%u"},
+ {opt_err, NULL}
+};
+
+static int hypfs_parse_options(char *options, struct super_block *sb)
+{
+ char *str;
+ substring_t args[MAX_OPT_ARGS];
+
+ if (!options)
+ return 0;
+ while ((str = strsep(&options, ",")) != NULL) {
+ int token, option;
+ struct hypfs_sb_info *hypfs_info = sb->s_fs_info;
+
+ if (!*str)
+ continue;
+ token = match_token(str, hypfs_tokens, args);
+ switch (token) {
+ case opt_uid:
+ if (match_int(&args[0], &option))
+ return -EINVAL;
+ hypfs_info->uid = option;
+ break;
+ case opt_gid:
+ if (match_int(&args[0], &option))
+ return -EINVAL;
+ hypfs_info->gid = option;
+ break;
+ case opt_err:
+ default:
+ printk(KERN_ERR "hypfs: Unrecognized mount option "
+ "\"%s\" or missing value\n", str);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int hypfs_fill_super(struct super_block *sb, void *data, int silent)
+{
+ struct inode *root_inode;
+ struct dentry *root_dentry;
+ int rc = 0;
+ struct hypfs_sb_info *sbi;
+
+ sbi = kzalloc(sizeof(struct hypfs_sb_info), GFP_KERNEL);
+ if (!sbi)
+ return -ENOMEM;
+ mutex_init(&sbi->lock);
+ sbi->uid = current->uid;
+ sbi->gid = current->gid;
+ sb->s_fs_info = sbi;
+ sb->s_blocksize = PAGE_CACHE_SIZE;
+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+ sb->s_magic = HYPFS_MAGIC;
+ sb->s_op = &hypfs_s_ops;
+ if (hypfs_parse_options(data, sb)) {
+ rc = -EINVAL;
+ goto err_alloc;
+ }
+ root_inode = hypfs_make_inode(sb, S_IFDIR | 0755);
+ if (!root_inode) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ root_inode->i_op = &simple_dir_inode_operations;
+ root_inode->i_fop = &simple_dir_operations;
+ root_dentry = d_alloc_root(root_inode);
+ if (!root_dentry) {
+ iput(root_inode);
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ rc = hypfs_diag_create_files(sb, root_dentry);
+ if (rc)
+ goto err_tree;
+ sbi->update_file = hypfs_create_update_file(sb, root_dentry);
+ if (IS_ERR(sbi->update_file)) {
+ rc = PTR_ERR(sbi->update_file);
+ goto err_tree;
+ }
+ hypfs_update_update(sb);
+ sb->s_root = root_dentry;
+ return 0;
+
+err_tree:
+ hypfs_delete_tree(root_dentry);
+ d_genocide(root_dentry);
+ dput(root_dentry);
+err_alloc:
+ kfree(sbi);
+ return rc;
+}
+
+static int hypfs_get_super(struct file_system_type *fst, int flags,
+ const char *devname, void *data, struct vfsmount *mnt)
+{
+ return get_sb_single(fst, flags, data, hypfs_fill_super, mnt);
+}
+
+static void hypfs_kill_super(struct super_block *sb)
+{
+ struct hypfs_sb_info *sb_info = sb->s_fs_info;
+
+ hypfs_delete_tree(sb->s_root);
+ hypfs_remove(sb_info->update_file);
+ kfree(sb->s_fs_info);
+ sb->s_fs_info = NULL;
+ kill_litter_super(sb);
+}
+
+static struct dentry *hypfs_create_file(struct super_block *sb,
+ struct dentry *parent, const char *name,
+ char *data, mode_t mode)
+{
+ struct dentry *dentry;
+ struct inode *inode;
+ struct qstr qname;
+
+ qname.name = name;
+ qname.len = strlen(name);
+ qname.hash = full_name_hash(name, qname.len);
+ dentry = lookup_one_len(name, parent, strlen(name));
+ if (IS_ERR(dentry))
+ return ERR_PTR(-ENOMEM);
+ inode = hypfs_make_inode(sb, mode);
+ if (!inode) {
+ dput(dentry);
+ return ERR_PTR(-ENOMEM);
+ }
+ if (mode & S_IFREG) {
+ inode->i_fop = &hypfs_file_ops;
+ if (data)
+ inode->i_size = strlen(data);
+ else
+ inode->i_size = 0;
+ } else if (mode & S_IFDIR) {
+ inode->i_op = &simple_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+ parent->d_inode->i_nlink++;
+ } else
+ BUG();
+ inode->u.generic_ip = data;
+ d_instantiate(dentry, inode);
+ dget(dentry);
+ return dentry;
+}
+
+struct dentry *hypfs_mkdir(struct super_block *sb, struct dentry *parent,
+ const char *name)
+{
+ struct dentry *dentry;
+
+ dentry = hypfs_create_file(sb, parent, name, NULL, S_IFDIR | DIR_MODE);
+ if (IS_ERR(dentry))
+ return dentry;
+ hypfs_add_dentry(dentry);
+ parent->d_inode->i_nlink++;
+ return dentry;
+}
+
+static struct dentry *hypfs_create_update_file(struct super_block *sb,
+ struct dentry *dir)
+{
+ struct dentry *dentry;
+
+ dentry = hypfs_create_file(sb, dir, "update", NULL,
+ S_IFREG | UPDATE_FILE_MODE);
+ /*
+ * We do not put the update file on the 'delete' list with
+ * hypfs_add_dentry(), since it should not be removed when the tree
+ * is updated.
+ */
+ return dentry;
+}
+
+struct dentry *hypfs_create_u64(struct super_block *sb, struct dentry *dir,
+ const char *name, __u64 value)
+{
+ char *buffer;
+ char tmp[TMP_SIZE];
+ struct dentry *dentry;
+
+ snprintf(tmp, TMP_SIZE, "%lld\n", (unsigned long long int)value);
+ buffer = kstrdup(tmp, GFP_KERNEL);
+ if (!buffer)
+ return ERR_PTR(-ENOMEM);
+ dentry =
+ hypfs_create_file(sb, dir, name, buffer, S_IFREG | REG_FILE_MODE);
+ if (IS_ERR(dentry)) {
+ kfree(buffer);
+ return ERR_PTR(-ENOMEM);
+ }
+ hypfs_add_dentry(dentry);
+ return dentry;
+}
+
+struct dentry *hypfs_create_str(struct super_block *sb, struct dentry *dir,
+ const char *name, char *string)
+{
+ char *buffer;
+ struct dentry *dentry;
+
+ buffer = kmalloc(strlen(string) + 2, GFP_KERNEL);
+ if (!buffer)
+ return ERR_PTR(-ENOMEM);
+ sprintf(buffer, "%s\n", string);
+ dentry =
+ hypfs_create_file(sb, dir, name, buffer, S_IFREG | REG_FILE_MODE);
+ if (IS_ERR(dentry)) {
+ kfree(buffer);
+ return ERR_PTR(-ENOMEM);
+ }
+ hypfs_add_dentry(dentry);
+ return dentry;
+}
+
+static struct file_operations hypfs_file_ops = {
+ .open = hypfs_open,
+ .release = hypfs_release,
+ .read = do_sync_read,
+ .write = do_sync_write,
+ .aio_read = hypfs_aio_read,
+ .aio_write = hypfs_aio_write,
+};
+
+static struct file_system_type hypfs_type = {
+ .owner = THIS_MODULE,
+ .name = "s390_hypfs",
+ .get_sb = hypfs_get_super,
+ .kill_sb = hypfs_kill_super
+};
+
+static struct super_operations hypfs_s_ops = {
+ .statfs = simple_statfs,
+ .drop_inode = hypfs_drop_inode,
+};
+
+static decl_subsys(s390, NULL, NULL);
+
+static int __init hypfs_init(void)
+{
+ int rc;
+
+ if (MACHINE_IS_VM)
+ return -ENODATA;
+ if (hypfs_diag_init()) {
+ rc = -ENODATA;
+ goto fail_diag;
+ }
+ kset_set_kset_s(&s390_subsys, hypervisor_subsys);
+ rc = subsystem_register(&s390_subsys);
+ if (rc)
+ goto fail_sysfs;
+ rc = register_filesystem(&hypfs_type);
+ if (rc)
+ goto fail_filesystem;
+ return 0;
+
+fail_filesystem:
+ subsystem_unregister(&s390_subsys);
+fail_sysfs:
+ hypfs_diag_exit();
+fail_diag:
+ printk(KERN_ERR "hypfs: Initialization failed with rc = %i.\n", rc);
+ return rc;
+}
+
+static void __exit hypfs_exit(void)
+{
+ hypfs_diag_exit();
+ unregister_filesystem(&hypfs_type);
+ subsystem_unregister(&s390_subsys);
+}
+
+module_init(hypfs_init)
+module_exit(hypfs_exit)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Holzheu <holzheu@de.ibm.com>");
+MODULE_DESCRIPTION("s390 Hypervisor Filesystem");
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 0a04e4a..b282034 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -47,6 +47,7 @@
#include <asm/irq.h>
#include <asm/page.h>
#include <asm/ptrace.h>
+#include <asm/sections.h>
/*
* Machine setup..
@@ -66,11 +67,6 @@ unsigned long __initdata zholes_size[MAX_NR_ZONES];
static unsigned long __initdata memory_end;
/*
- * Setup options
- */
-extern int _text,_etext, _edata, _end;
-
-/*
* This is set up by the setup-routine at boot-time
* for S390 need to find out, what we have to setup
* using address 0x10400 ...
@@ -80,15 +76,11 @@ extern int _text,_etext, _edata, _end;
static struct resource code_resource = {
.name = "Kernel code",
- .start = (unsigned long) &_text,
- .end = (unsigned long) &_etext - 1,
.flags = IORESOURCE_BUSY | IORESOURCE_MEM,
};
static struct resource data_resource = {
.name = "Kernel data",
- .start = (unsigned long) &_etext,
- .end = (unsigned long) &_edata - 1,
.flags = IORESOURCE_BUSY | IORESOURCE_MEM,
};
@@ -422,6 +414,11 @@ setup_resources(void)
struct resource *res;
int i;
+ code_resource.start = (unsigned long) &_text;
+ code_resource.end = (unsigned long) &_etext - 1;
+ data_resource.start = (unsigned long) &_etext;
+ data_resource.end = (unsigned long) &_edata - 1;
+
for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
res = alloc_bootmem_low(sizeof(struct resource));
res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
diff --git a/arch/sh64/kernel/signal.c b/arch/sh64/kernel/signal.c
index 3ea8929e..9e2ffc4 100644
--- a/arch/sh64/kernel/signal.c
+++ b/arch/sh64/kernel/signal.c
@@ -407,7 +407,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
static inline void __user *
get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
{
- if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp))
+ if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp))
sp = current->sas_ss_sp + current->sas_ss_size;
return (void __user *)((sp - frame_size) & -8ul);
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index 1b83e21..6616ee0 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -12,7 +12,7 @@ obj-y := entry.o wof.o wuf.o etrap.o rtrap.o traps.o $(IRQ_OBJS) \
sys_sparc.o sunos_asm.o systbls.o \
time.o windows.o cpu.o devices.o sclow.o \
tadpole.o tick14.o ptrace.o sys_solaris.o \
- unaligned.o muldiv.o semaphore.o
+ unaligned.o muldiv.o semaphore.o prom.o of_device.o
obj-$(CONFIG_PCI) += pcic.o
obj-$(CONFIG_SUN4) += sun4setup.o
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
index 5c3529c..a7a4892 100644
--- a/arch/sparc/kernel/ebus.c
+++ b/arch/sparc/kernel/ebus.c
@@ -20,6 +20,7 @@
#include <asm/ebus.h>
#include <asm/io.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
#include <asm/bpp.h>
struct linux_ebus *ebus_chain = NULL;
@@ -83,79 +84,81 @@ int __init ebus_blacklist_irq(char *name)
return 0;
}
-void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
- struct linux_ebus_child *dev)
+void __init fill_ebus_child(struct device_node *dp,
+ struct linux_ebus_child *dev)
{
- int regs[PROMREG_MAX];
- int irqs[PROMREG_MAX];
- char lbuf[128];
+ int *regs;
+ int *irqs;
int i, len;
- dev->prom_node = node;
- prom_getstring(node, "name", lbuf, sizeof(lbuf));
- strcpy(dev->prom_name, lbuf);
-
- len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
- if (len == -1) len = 0;
+ dev->prom_node = dp;
+ regs = of_get_property(dp, "reg", &len);
+ if (!regs)
+ len = 0;
dev->num_addrs = len / sizeof(regs[0]);
for (i = 0; i < dev->num_addrs; i++) {
if (regs[i] >= dev->parent->num_addrs) {
prom_printf("UGH: property for %s was %d, need < %d\n",
- dev->prom_name, len, dev->parent->num_addrs);
+ dev->prom_node->name, len,
+ dev->parent->num_addrs);
panic(__FUNCTION__);
}
- dev->resource[i].start = dev->parent->resource[regs[i]].start; /* XXX resource */
+
+ /* XXX resource */
+ dev->resource[i].start =
+ dev->parent->resource[regs[i]].start;
}
for (i = 0; i < PROMINTR_MAX; i++)
dev->irqs[i] = PCI_IRQ_NONE;
- if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_name)) != 0) {
+ if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
dev->num_irqs = 1;
- } else if ((len = prom_getproperty(node, "interrupts",
- (char *)&irqs, sizeof(irqs))) == -1 || len == 0) {
- dev->num_irqs = 0;
- dev->irqs[0] = 0;
- if (dev->parent->num_irqs != 0) {
- dev->num_irqs = 1;
- dev->irqs[0] = dev->parent->irqs[0];
-/* P3 */ /* printk("EBUS: dev %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */
- }
} else {
- dev->num_irqs = len / sizeof(irqs[0]);
- if (irqs[0] == 0 || irqs[0] >= 8) {
- /*
- * XXX Zero is a valid pin number...
- * This works as long as Ebus is not wired to INTA#.
- */
- printk("EBUS: %s got bad irq %d from PROM\n",
- dev->prom_name, irqs[0]);
+ irqs = of_get_property(dp, "interrupts", &len);
+ if (!irqs) {
dev->num_irqs = 0;
dev->irqs[0] = 0;
+ if (dev->parent->num_irqs != 0) {
+ dev->num_irqs = 1;
+ dev->irqs[0] = dev->parent->irqs[0];
+ }
} else {
- dev->irqs[0] = pcic_pin_to_irq(irqs[0], dev->prom_name);
+ dev->num_irqs = len / sizeof(irqs[0]);
+ if (irqs[0] == 0 || irqs[0] >= 8) {
+ /*
+ * XXX Zero is a valid pin number...
+ * This works as long as Ebus is not wired
+ * to INTA#.
+ */
+ printk("EBUS: %s got bad irq %d from PROM\n",
+ dev->prom_node->name, irqs[0]);
+ dev->num_irqs = 0;
+ dev->irqs[0] = 0;
+ } else {
+ dev->irqs[0] =
+ pcic_pin_to_irq(irqs[0],
+ dev->prom_node->name);
+ }
}
}
}
-void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
+void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
{
- struct linux_prom_registers regs[PROMREG_MAX];
+ struct linux_prom_registers *regs;
struct linux_ebus_child *child;
- int irqs[PROMINTR_MAX];
- char lbuf[128];
+ int *irqs;
int i, n, len;
unsigned long baseaddr;
- dev->prom_node = node;
- prom_getstring(node, "name", lbuf, sizeof(lbuf));
- strcpy(dev->prom_name, lbuf);
+ dev->prom_node = dp;
- len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
+ regs = of_get_property(dp, "reg", &len);
if (len % sizeof(struct linux_prom_registers)) {
prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
- dev->prom_name, len,
+ dev->prom_node->name, len,
(int)sizeof(struct linux_prom_registers));
panic(__FUNCTION__);
}
@@ -197,7 +200,7 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
if ((baseaddr = (unsigned long) ioremap(baseaddr,
regs[i].reg_size)) == 0) {
panic("ebus: unable to remap dev %s",
- dev->prom_name);
+ dev->prom_node->name);
}
}
dev->resource[i].start = baseaddr; /* XXX Unaligned */
@@ -206,29 +209,43 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
for (i = 0; i < PROMINTR_MAX; i++)
dev->irqs[i] = PCI_IRQ_NONE;
- if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_name)) != 0) {
+ if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
dev->num_irqs = 1;
- } else if ((len = prom_getproperty(node, "interrupts",
- (char *)&irqs, sizeof(irqs))) == -1 || len == 0) {
- dev->num_irqs = 0;
- if ((dev->irqs[0] = dev->bus->self->irq) != 0) {
- dev->num_irqs = 1;
-/* P3 */ /* printk("EBUS: child %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */
- }
} else {
- dev->num_irqs = 1; /* dev->num_irqs = len / sizeof(irqs[0]); */
- if (irqs[0] == 0 || irqs[0] >= 8) {
- /* See above for the parent. XXX */
- printk("EBUS: %s got bad irq %d from PROM\n",
- dev->prom_name, irqs[0]);
+ irqs = of_get_property(dp, "interrupts", &len);
+ if (!irqs) {
dev->num_irqs = 0;
- dev->irqs[0] = 0;
+ if ((dev->irqs[0] = dev->bus->self->irq) != 0) {
+ dev->num_irqs = 1;
+/* P3 */ /* printk("EBUS: child %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */
+ }
} else {
- dev->irqs[0] = pcic_pin_to_irq(irqs[0], dev->prom_name);
+ dev->num_irqs = 1; /* dev->num_irqs = len / sizeof(irqs[0]); */
+ if (irqs[0] == 0 || irqs[0] >= 8) {
+ /* See above for the parent. XXX */
+ printk("EBUS: %s got bad irq %d from PROM\n",
+ dev->prom_node->name, irqs[0]);
+ dev->num_irqs = 0;
+ dev->irqs[0] = 0;
+ } else {
+ dev->irqs[0] =
+ pcic_pin_to_irq(irqs[0],
+ dev->prom_node->name);
+ }
}
}
- if ((node = prom_getchild(node))) {
+ dev->ofdev.node = dp;
+ dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
+ dev->ofdev.dev.bus = &ebus_bus_type;
+ strcpy(dev->ofdev.dev.bus_id, dp->path_component_name);
+
+ /* Register with core */
+ if (of_device_register(&dev->ofdev) != 0)
+ printk(KERN_DEBUG "ebus: device registration error for %s!\n",
+ dev->ofdev.dev.bus_id);
+
+ if ((dp = dp->child) != NULL) {
dev->children = (struct linux_ebus_child *)
ebus_alloc(sizeof(struct linux_ebus_child));
@@ -236,9 +253,9 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
child->next = NULL;
child->parent = dev;
child->bus = dev->bus;
- fill_ebus_child(node, &regs[0], child);
+ fill_ebus_child(dp, child);
- while ((node = prom_getsibling(node)) != 0) {
+ while ((dp = dp->sibling) != NULL) {
child->next = (struct linux_ebus_child *)
ebus_alloc(sizeof(struct linux_ebus_child));
@@ -246,51 +263,49 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
child->next = NULL;
child->parent = dev;
child->bus = dev->bus;
- fill_ebus_child(node, &regs[0], child);
+ fill_ebus_child(dp, child);
}
}
}
void __init ebus_init(void)
{
- struct linux_prom_pci_registers regs[PROMREG_MAX];
+ struct linux_prom_pci_registers *regs;
struct linux_pbm_info *pbm;
struct linux_ebus_device *dev;
struct linux_ebus *ebus;
struct ebus_system_entry *sp;
struct pci_dev *pdev;
struct pcidev_cookie *cookie;
- char lbuf[128];
+ struct device_node *dp;
unsigned long addr, *base;
unsigned short pci_command;
- int nd, len, ebusnd;
- int reg, nreg;
+ int len, reg, nreg;
int num_ebus = 0;
- prom_getstring(prom_root_node, "name", lbuf, sizeof(lbuf));
+ dp = of_find_node_by_path("/");
for (sp = ebus_blacklist; sp->esname != NULL; sp++) {
- if (strcmp(lbuf, sp->esname) == 0) {
+ if (strcmp(dp->name, sp->esname) == 0) {
ebus_blackp = sp->ipt;
break;
}
}
pdev = pci_get_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, NULL);
- if (!pdev) {
+ if (!pdev)
return;
- }
+
cookie = pdev->sysdata;
- ebusnd = cookie->prom_node;
+ dp = cookie->prom_node;
ebus_chain = ebus = (struct linux_ebus *)
ebus_alloc(sizeof(struct linux_ebus));
ebus->next = NULL;
- while (ebusnd) {
+ while (dp) {
+ struct device_node *nd;
- prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf));
- ebus->prom_node = ebusnd;
- strcpy(ebus->prom_name, lbuf);
+ ebus->prom_node = dp;
ebus->self = pdev;
ebus->parent = pbm = cookie->pbm;
@@ -299,9 +314,8 @@ void __init ebus_init(void)
pci_command |= PCI_COMMAND_MASTER;
pci_write_config_word(pdev, PCI_COMMAND, pci_command);
- len = prom_getproperty(ebusnd, "reg", (void *)regs,
- sizeof(regs));
- if (len == 0 || len == -1) {
+ regs = of_get_property(dp, "reg", &len);
+ if (!regs) {
prom_printf("%s: can't find reg property\n",
__FUNCTION__);
prom_halt();
@@ -317,7 +331,18 @@ void __init ebus_init(void)
*base++ = addr;
}
- nd = prom_getchild(ebusnd);
+ ebus->ofdev.node = dp;
+ ebus->ofdev.dev.parent = &pdev->dev;
+ ebus->ofdev.dev.bus = &ebus_bus_type;
+ strcpy(ebus->ofdev.dev.bus_id, dp->path_component_name);
+
+ /* Register with core */
+ if (of_device_register(&ebus->ofdev) != 0)
+ printk(KERN_DEBUG "ebus: device registration error for %s!\n",
+ ebus->ofdev.dev.bus_id);
+
+
+ nd = dp->child;
if (!nd)
goto next_ebus;
@@ -330,7 +355,7 @@ void __init ebus_init(void)
dev->bus = ebus;
fill_ebus_device(nd, dev);
- while ((nd = prom_getsibling(nd)) != 0) {
+ while ((nd = nd->sibling) != NULL) {
dev->next = (struct linux_ebus_device *)
ebus_alloc(sizeof(struct linux_ebus_device));
@@ -348,7 +373,7 @@ void __init ebus_init(void)
break;
cookie = pdev->sysdata;
- ebusnd = cookie->prom_node;
+ dp = cookie->prom_node;
ebus->next = (struct linux_ebus *)
ebus_alloc(sizeof(struct linux_ebus));
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index f9ff297..ae4c667 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -39,6 +39,8 @@
#include <asm/io.h>
#include <asm/vaddrs.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/sbus.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/dma.h>
@@ -224,10 +226,54 @@ static void _sparc_free_io(struct resource *res)
#ifdef CONFIG_SBUS
-void sbus_set_sbus64(struct sbus_dev *sdev, int x) {
+void sbus_set_sbus64(struct sbus_dev *sdev, int x)
+{
printk("sbus_set_sbus64: unsupported\n");
}
+extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq);
+void __init sbus_fill_device_irq(struct sbus_dev *sdev)
+{
+ struct linux_prom_irqs irqs[PROMINTR_MAX];
+ int len;
+
+ len = prom_getproperty(sdev->prom_node, "intr",
+ (char *)irqs, sizeof(irqs));
+ if (len != -1) {
+ sdev->num_irqs = len / 8;
+ if (sdev->num_irqs == 0) {
+ sdev->irqs[0] = 0;
+ } else if (sparc_cpu_model == sun4d) {
+ for (len = 0; len < sdev->num_irqs; len++)
+ sdev->irqs[len] =
+ sun4d_build_irq(sdev, irqs[len].pri);
+ } else {
+ for (len = 0; len < sdev->num_irqs; len++)
+ sdev->irqs[len] = irqs[len].pri;
+ }
+ } else {
+ int interrupts[PROMINTR_MAX];
+
+ /* No "intr" node found-- check for "interrupts" node.
+ * This node contains SBus interrupt levels, not IPLs
+ * as in "intr", and no vector values. We convert
+ * SBus interrupt levels to PILs (platform specific).
+ */
+ len = prom_getproperty(sdev->prom_node, "interrupts",
+ (char *)interrupts, sizeof(interrupts));
+ if (len == -1) {
+ sdev->irqs[0] = 0;
+ sdev->num_irqs = 0;
+ } else {
+ sdev->num_irqs = len / sizeof(int);
+ for (len = 0; len < sdev->num_irqs; len++) {
+ sdev->irqs[len] =
+ sbint_to_irq(sdev, interrupts[len]);
+ }
+ }
+ }
+}
+
/*
* Allocate a chunk of memory suitable for DMA.
* Typically devices use them for control blocks.
@@ -414,6 +460,89 @@ void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg,
{
printk("sbus_dma_sync_sg_for_device: not implemented yet\n");
}
+
+/* Support code for sbus_init(). */
+/*
+ * XXX This functions appears to be a distorted version of
+ * prom_sbus_ranges_init(), with all sun4d stuff cut away.
+ * Ask DaveM what is going on here, how is sun4d supposed to work... XXX
+ */
+/* added back sun4d patch from Thomas Bogendoerfer - should be OK (crn) */
+void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus)
+{
+ int parent_node = pn->node;
+
+ if (sparc_cpu_model == sun4d) {
+ struct linux_prom_ranges iounit_ranges[PROMREG_MAX];
+ int num_iounit_ranges, len;
+
+ len = prom_getproperty(parent_node, "ranges",
+ (char *) iounit_ranges,
+ sizeof (iounit_ranges));
+ if (len != -1) {
+ num_iounit_ranges =
+ (len / sizeof(struct linux_prom_ranges));
+ prom_adjust_ranges(sbus->sbus_ranges,
+ sbus->num_sbus_ranges,
+ iounit_ranges, num_iounit_ranges);
+ }
+ }
+}
+
+void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp)
+{
+ struct device_node *parent = dp->parent;
+
+ if (sparc_cpu_model != sun4d &&
+ parent != NULL &&
+ !strcmp(parent->name, "iommu")) {
+ extern void iommu_init(int iommu_node, struct sbus_bus *sbus);
+
+ iommu_init(parent->node, sbus);
+ }
+
+ if (sparc_cpu_model == sun4d) {
+ extern void iounit_init(int sbi_node, int iounit_node,
+ struct sbus_bus *sbus);
+
+ iounit_init(dp->node, parent->node, sbus);
+ }
+}
+
+void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp)
+{
+ if (sparc_cpu_model == sun4d) {
+ struct device_node *parent = dp->parent;
+
+ sbus->devid = of_getintprop_default(parent, "device-id", 0);
+ sbus->board = of_getintprop_default(parent, "board#", 0);
+ }
+}
+
+int __init sbus_arch_preinit(void)
+{
+ extern void register_proc_sparc_ioport(void);
+
+ register_proc_sparc_ioport();
+
+#ifdef CONFIG_SUN4
+ {
+ extern void sun4_dvma_init(void);
+ sun4_dvma_init();
+ }
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+void __init sbus_arch_postinit(void)
+{
+ if (sparc_cpu_model == sun4d) {
+ extern void sun4d_init_sbi_irq(void);
+ sun4d_init_sbi_irq();
+ }
+}
#endif /* CONFIG_SBUS */
#ifdef CONFIG_PCI
diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c
new file mode 100644
index 0000000..001b867
--- /dev/null
+++ b/arch/sparc/kernel/of_device.c
@@ -0,0 +1,268 @@
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/slab.h>
+
+#include <asm/errno.h>
+#include <asm/of_device.h>
+
+/**
+ * of_match_device - Tell if an of_device structure has a matching
+ * of_match structure
+ * @ids: array of of device match structures to search in
+ * @dev: the of device structure to match against
+ *
+ * Used by a driver to check whether an of_device present in the
+ * system is in its list of supported devices.
+ */
+const struct of_device_id *of_match_device(const struct of_device_id *matches,
+ const struct of_device *dev)
+{
+ if (!dev->node)
+ return NULL;
+ while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
+ int match = 1;
+ if (matches->name[0])
+ match &= dev->node->name
+ && !strcmp(matches->name, dev->node->name);
+ if (matches->type[0])
+ match &= dev->node->type
+ && !strcmp(matches->type, dev->node->type);
+ if (matches->compatible[0])
+ match &= of_device_is_compatible(dev->node,
+ matches->compatible);
+ if (match)
+ return matches;
+ matches++;
+ }
+ return NULL;
+}
+
+static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct of_device * of_dev = to_of_device(dev);
+ struct of_platform_driver * of_drv = to_of_platform_driver(drv);
+ const struct of_device_id * matches = of_drv->match_table;
+
+ if (!matches)
+ return 0;
+
+ return of_match_device(matches, of_dev) != NULL;
+}
+
+struct of_device *of_dev_get(struct of_device *dev)
+{
+ struct device *tmp;
+
+ if (!dev)
+ return NULL;
+ tmp = get_device(&dev->dev);
+ if (tmp)
+ return to_of_device(tmp);
+ else
+ return NULL;
+}
+
+void of_dev_put(struct of_device *dev)
+{
+ if (dev)
+ put_device(&dev->dev);
+}
+
+
+static int of_device_probe(struct device *dev)
+{
+ int error = -ENODEV;
+ struct of_platform_driver *drv;
+ struct of_device *of_dev;
+ const struct of_device_id *match;
+
+ drv = to_of_platform_driver(dev->driver);
+ of_dev = to_of_device(dev);
+
+ if (!drv->probe)
+ return error;
+
+ of_dev_get(of_dev);
+
+ match = of_match_device(drv->match_table, of_dev);
+ if (match)
+ error = drv->probe(of_dev, match);
+ if (error)
+ of_dev_put(of_dev);
+
+ return error;
+}
+
+static int of_device_remove(struct device *dev)
+{
+ struct of_device * of_dev = to_of_device(dev);
+ struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
+
+ if (dev->driver && drv->remove)
+ drv->remove(of_dev);
+ return 0;
+}
+
+static int of_device_suspend(struct device *dev, pm_message_t state)
+{
+ struct of_device * of_dev = to_of_device(dev);
+ struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
+ int error = 0;
+
+ if (dev->driver && drv->suspend)
+ error = drv->suspend(of_dev, state);
+ return error;
+}
+
+static int of_device_resume(struct device * dev)
+{
+ struct of_device * of_dev = to_of_device(dev);
+ struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
+ int error = 0;
+
+ if (dev->driver && drv->resume)
+ error = drv->resume(of_dev);
+ return error;
+}
+
+#ifdef CONFIG_PCI
+struct bus_type ebus_bus_type = {
+ .name = "ebus",
+ .match = of_platform_bus_match,
+ .probe = of_device_probe,
+ .remove = of_device_remove,
+ .suspend = of_device_suspend,
+ .resume = of_device_resume,
+};
+#endif
+
+#ifdef CONFIG_SBUS
+struct bus_type sbus_bus_type = {
+ .name = "sbus",
+ .match = of_platform_bus_match,
+ .probe = of_device_probe,
+ .remove = of_device_remove,
+ .suspend = of_device_suspend,
+ .resume = of_device_resume,
+};
+#endif
+
+static int __init of_bus_driver_init(void)
+{
+ int err = 0;
+
+#ifdef CONFIG_PCI
+ if (!err)
+ err = bus_register(&ebus_bus_type);
+#endif
+#ifdef CONFIG_SBUS
+ if (!err)
+ err = bus_register(&sbus_bus_type);
+#endif
+ return 0;
+}
+
+postcore_initcall(of_bus_driver_init);
+
+int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
+{
+ /* initialize common driver fields */
+ drv->driver.name = drv->name;
+ drv->driver.bus = bus;
+
+ /* register with core */
+ return driver_register(&drv->driver);
+}
+
+void of_unregister_driver(struct of_platform_driver *drv)
+{
+ driver_unregister(&drv->driver);
+}
+
+
+static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct of_device *ofdev;
+
+ ofdev = to_of_device(dev);
+ return sprintf(buf, "%s", ofdev->node->full_name);
+}
+
+static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
+
+/**
+ * of_release_dev - free an of device structure when all users of it are finished.
+ * @dev: device that's been disconnected
+ *
+ * Will be called only by the device core when all users of this of device are
+ * done.
+ */
+void of_release_dev(struct device *dev)
+{
+ struct of_device *ofdev;
+
+ ofdev = to_of_device(dev);
+
+ kfree(ofdev);
+}
+
+int of_device_register(struct of_device *ofdev)
+{
+ int rc;
+
+ BUG_ON(ofdev->node == NULL);
+
+ rc = device_register(&ofdev->dev);
+ if (rc)
+ return rc;
+
+ device_create_file(&ofdev->dev, &dev_attr_devspec);
+
+ return 0;
+}
+
+void of_device_unregister(struct of_device *ofdev)
+{
+ device_remove_file(&ofdev->dev, &dev_attr_devspec);
+ device_unregister(&ofdev->dev);
+}
+
+struct of_device* of_platform_device_create(struct device_node *np,
+ const char *bus_id,
+ struct device *parent,
+ struct bus_type *bus)
+{
+ struct of_device *dev;
+
+ dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+ memset(dev, 0, sizeof(*dev));
+
+ dev->dev.parent = parent;
+ dev->dev.bus = bus;
+ dev->dev.release = of_release_dev;
+
+ strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
+
+ if (of_device_register(dev) != 0) {
+ kfree(dev);
+ return NULL;
+ }
+
+ return dev;
+}
+
+EXPORT_SYMBOL(of_match_device);
+EXPORT_SYMBOL(of_register_driver);
+EXPORT_SYMBOL(of_unregister_driver);
+EXPORT_SYMBOL(of_device_register);
+EXPORT_SYMBOL(of_device_unregister);
+EXPORT_SYMBOL(of_dev_get);
+EXPORT_SYMBOL(of_dev_put);
+EXPORT_SYMBOL(of_platform_device_create);
+EXPORT_SYMBOL(of_release_dev);
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index bcdf5ad..bcfdddd 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -31,6 +31,7 @@
#include <asm/irq.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
#include <asm/pcic.h>
#include <asm/timer.h>
#include <asm/uaccess.h>
@@ -665,7 +666,7 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
/* cookies */
pcp = pci_devcookie_alloc();
pcp->pbm = &pcic->pbm;
- pcp->prom_node = node;
+ pcp->prom_node = of_find_node_by_phandle(node);
dev->sysdata = pcp;
/* fixing I/O to look like memory */
diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c
new file mode 100644
index 0000000..63b2b9b
--- /dev/null
+++ b/arch/sparc/kernel/prom.c
@@ -0,0 +1,474 @@
+/*
+ * Procedures for creating, accessing and interpreting the device tree.
+ *
+ * Paul Mackerras August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ * {engebret|bergner}@us.ibm.com
+ *
+ * Adapted for sparc32 by David S. Miller davem@davemloft.net
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/module.h>
+
+#include <asm/prom.h>
+#include <asm/oplib.h>
+
+static struct device_node *allnodes;
+
+int of_device_is_compatible(struct device_node *device, const char *compat)
+{
+ const char* cp;
+ int cplen, l;
+
+ cp = (char *) of_get_property(device, "compatible", &cplen);
+ if (cp == NULL)
+ return 0;
+ while (cplen > 0) {
+ if (strncmp(cp, compat, strlen(compat)) == 0)
+ return 1;
+ l = strlen(cp) + 1;
+ cp += l;
+ cplen -= l;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(of_device_is_compatible);
+
+struct device_node *of_get_parent(const struct device_node *node)
+{
+ struct device_node *np;
+
+ if (!node)
+ return NULL;
+
+ np = node->parent;
+
+ return np;
+}
+EXPORT_SYMBOL(of_get_parent);
+
+struct device_node *of_get_next_child(const struct device_node *node,
+ struct device_node *prev)
+{
+ struct device_node *next;
+
+ next = prev ? prev->sibling : node->child;
+ for (; next != 0; next = next->sibling) {
+ break;
+ }
+
+ return next;
+}
+EXPORT_SYMBOL(of_get_next_child);
+
+struct device_node *of_find_node_by_path(const char *path)
+{
+ struct device_node *np = allnodes;
+
+ for (; np != 0; np = np->allnext) {
+ if (np->full_name != 0 && strcmp(np->full_name, path) == 0)
+ break;
+ }
+
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_path);
+
+struct device_node *of_find_node_by_phandle(phandle handle)
+{
+ struct device_node *np;
+
+ for (np = allnodes; np != 0; np = np->allnext)
+ if (np->node == handle)
+ break;
+
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_phandle);
+
+struct device_node *of_find_node_by_name(struct device_node *from,
+ const char *name)
+{
+ struct device_node *np;
+
+ np = from ? from->allnext : allnodes;
+ for (; np != NULL; np = np->allnext)
+ if (np->name != NULL && strcmp(np->name, name) == 0)
+ break;
+
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_name);
+
+struct device_node *of_find_node_by_type(struct device_node *from,
+ const char *type)
+{
+ struct device_node *np;
+
+ np = from ? from->allnext : allnodes;
+ for (; np != 0; np = np->allnext)
+ if (np->type != 0 && strcmp(np->type, type) == 0)
+ break;
+
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_type);
+
+struct device_node *of_find_compatible_node(struct device_node *from,
+ const char *type, const char *compatible)
+{
+ struct device_node *np;
+
+ np = from ? from->allnext : allnodes;
+ for (; np != 0; np = np->allnext) {
+ if (type != NULL
+ && !(np->type != 0 && strcmp(np->type, type) == 0))
+ continue;
+ if (of_device_is_compatible(np, compatible))
+ break;
+ }
+
+ return np;
+}
+EXPORT_SYMBOL(of_find_compatible_node);
+
+struct property *of_find_property(struct device_node *np, const char *name,
+ int *lenp)
+{
+ struct property *pp;
+
+ for (pp = np->properties; pp != 0; pp = pp->next) {
+ if (strcmp(pp->name, name) == 0) {
+ if (lenp != 0)
+ *lenp = pp->length;
+ break;
+ }
+ }
+ return pp;
+}
+EXPORT_SYMBOL(of_find_property);
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+void *of_get_property(struct device_node *np, const char *name, int *lenp)
+{
+ struct property *pp = of_find_property(np,name,lenp);
+ return pp ? pp->value : NULL;
+}
+EXPORT_SYMBOL(of_get_property);
+
+int of_getintprop_default(struct device_node *np, const char *name, int def)
+{
+ struct property *prop;
+ int len;
+
+ prop = of_find_property(np, name, &len);
+ if (!prop || len != 4)
+ return def;
+
+ return *(int *) prop->value;
+}
+EXPORT_SYMBOL(of_getintprop_default);
+
+static unsigned int prom_early_allocated;
+
+static void * __init prom_early_alloc(unsigned long size)
+{
+ void *ret;
+
+ ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
+ if (ret != NULL)
+ memset(ret, 0, size);
+
+ prom_early_allocated += size;
+
+ return ret;
+}
+
+static int is_root_node(const struct device_node *dp)
+{
+ if (!dp)
+ return 0;
+
+ return (dp->parent == NULL);
+}
+
+/* The following routines deal with the black magic of fully naming a
+ * node.
+ *
+ * Certain well known named nodes are just the simple name string.
+ *
+ * Actual devices have an address specifier appended to the base name
+ * string, like this "foo@addr". The "addr" can be in any number of
+ * formats, and the platform plus the type of the node determine the
+ * format and how it is constructed.
+ *
+ * For children of the ROOT node, the naming convention is fixed and
+ * determined by whether this is a sun4u or sun4v system.
+ *
+ * For children of other nodes, it is bus type specific. So
+ * we walk up the tree until we discover a "device_type" property
+ * we recognize and we go from there.
+ */
+static void __init sparc32_path_component(struct device_node *dp, char *tmp_buf)
+{
+ struct linux_prom_registers *regs;
+ struct property *rprop;
+
+ rprop = of_find_property(dp, "reg", NULL);
+ if (!rprop)
+ return;
+
+ regs = rprop->value;
+ sprintf(tmp_buf, "%s@%x,%x",
+ dp->name,
+ regs->which_io, regs->phys_addr);
+}
+
+/* "name@slot,offset" */
+static void __init sbus_path_component(struct device_node *dp, char *tmp_buf)
+{
+ struct linux_prom_registers *regs;
+ struct property *prop;
+
+ prop = of_find_property(dp, "reg", NULL);
+ if (!prop)
+ return;
+
+ regs = prop->value;
+ sprintf(tmp_buf, "%s@%x,%x",
+ dp->name,
+ regs->which_io,
+ regs->phys_addr);
+}
+
+/* "name@devnum[,func]" */
+static void __init pci_path_component(struct device_node *dp, char *tmp_buf)
+{
+ struct linux_prom_pci_registers *regs;
+ struct property *prop;
+ unsigned int devfn;
+
+ prop = of_find_property(dp, "reg", NULL);
+ if (!prop)
+ return;
+
+ regs = prop->value;
+ devfn = (regs->phys_hi >> 8) & 0xff;
+ if (devfn & 0x07) {
+ sprintf(tmp_buf, "%s@%x,%x",
+ dp->name,
+ devfn >> 3,
+ devfn & 0x07);
+ } else {
+ sprintf(tmp_buf, "%s@%x",
+ dp->name,
+ devfn >> 3);
+ }
+}
+
+/* "name@addrhi,addrlo" */
+static void __init ebus_path_component(struct device_node *dp, char *tmp_buf)
+{
+ struct linux_prom_registers *regs;
+ struct property *prop;
+
+ prop = of_find_property(dp, "reg", NULL);
+ if (!prop)
+ return;
+
+ regs = prop->value;
+
+ sprintf(tmp_buf, "%s@%x,%x",
+ dp->name,
+ regs->which_io, regs->phys_addr);
+}
+
+static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
+{
+ struct device_node *parent = dp->parent;
+
+ if (parent != NULL) {
+ if (!strcmp(parent->type, "pci") ||
+ !strcmp(parent->type, "pciex"))
+ return pci_path_component(dp, tmp_buf);
+ if (!strcmp(parent->type, "sbus"))
+ return sbus_path_component(dp, tmp_buf);
+ if (!strcmp(parent->type, "ebus"))
+ return ebus_path_component(dp, tmp_buf);
+
+ /* "isa" is handled with platform naming */
+ }
+
+ /* Use platform naming convention. */
+ return sparc32_path_component(dp, tmp_buf);
+}
+
+static char * __init build_path_component(struct device_node *dp)
+{
+ char tmp_buf[64], *n;
+
+ tmp_buf[0] = '\0';
+ __build_path_component(dp, tmp_buf);
+ if (tmp_buf[0] == '\0')
+ strcpy(tmp_buf, dp->name);
+
+ n = prom_early_alloc(strlen(tmp_buf) + 1);
+ strcpy(n, tmp_buf);
+
+ return n;
+}
+
+static char * __init build_full_name(struct device_node *dp)
+{
+ int len, ourlen, plen;
+ char *n;
+
+ plen = strlen(dp->parent->full_name);
+ ourlen = strlen(dp->path_component_name);
+ len = ourlen + plen + 2;
+
+ n = prom_early_alloc(len);
+ strcpy(n, dp->parent->full_name);
+ if (!is_root_node(dp->parent)) {
+ strcpy(n + plen, "/");
+ plen++;
+ }
+ strcpy(n + plen, dp->path_component_name);
+
+ return n;
+}
+
+static struct property * __init build_one_prop(phandle node, char *prev)
+{
+ static struct property *tmp = NULL;
+ struct property *p;
+ int len;
+
+ if (tmp) {
+ p = tmp;
+ memset(p, 0, sizeof(*p) + 32);
+ tmp = NULL;
+ } else
+ p = prom_early_alloc(sizeof(struct property) + 32);
+
+ p->name = (char *) (p + 1);
+ if (prev == NULL) {
+ prom_firstprop(node, p->name);
+ } else {
+ prom_nextprop(node, prev, p->name);
+ }
+ if (strlen(p->name) == 0) {
+ tmp = p;
+ return NULL;
+ }
+ p->length = prom_getproplen(node, p->name);
+ if (p->length <= 0) {
+ p->length = 0;
+ } else {
+ p->value = prom_early_alloc(p->length);
+ len = prom_getproperty(node, p->name, p->value, p->length);
+ }
+ return p;
+}
+
+static struct property * __init build_prop_list(phandle node)
+{
+ struct property *head, *tail;
+
+ head = tail = build_one_prop(node, NULL);
+ while(tail) {
+ tail->next = build_one_prop(node, tail->name);
+ tail = tail->next;
+ }
+
+ return head;
+}
+
+static char * __init get_one_property(phandle node, char *name)
+{
+ char *buf = "<NULL>";
+ int len;
+
+ len = prom_getproplen(node, name);
+ if (len > 0) {
+ buf = prom_early_alloc(len);
+ len = prom_getproperty(node, name, buf, len);
+ }
+
+ return buf;
+}
+
+static struct device_node * __init create_node(phandle node)
+{
+ struct device_node *dp;
+
+ if (!node)
+ return NULL;
+
+ dp = prom_early_alloc(sizeof(*dp));
+
+ kref_init(&dp->kref);
+
+ dp->name = get_one_property(node, "name");
+ dp->type = get_one_property(node, "device_type");
+ dp->node = node;
+
+ /* Build interrupts later... */
+
+ dp->properties = build_prop_list(node);
+
+ return dp;
+}
+
+static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp)
+{
+ struct device_node *dp;
+
+ dp = create_node(node);
+ if (dp) {
+ *(*nextp) = dp;
+ *nextp = &dp->allnext;
+
+ dp->parent = parent;
+ dp->path_component_name = build_path_component(dp);
+ dp->full_name = build_full_name(dp);
+
+ dp->child = build_tree(dp, prom_getchild(node), nextp);
+
+ dp->sibling = build_tree(parent, prom_getsibling(node), nextp);
+ }
+
+ return dp;
+}
+
+void __init prom_build_devicetree(void)
+{
+ struct device_node **nextp;
+
+ allnodes = create_node(prom_root_node);
+ allnodes->path_component_name = "";
+ allnodes->full_name = "/";
+
+ nextp = &allnodes->allnext;
+ allnodes->child = build_tree(allnodes,
+ prom_getchild(allnodes->node),
+ &nextp);
+ printk("PROM: Built device tree with %u bytes of memory.\n",
+ prom_early_allocated);
+}
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 2cbf282..a893a9c 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -332,7 +332,7 @@ void __init setup_arch(char **cmdline_p)
if (!root_flags)
root_mountflags &= ~MS_RDONLY;
ROOT_DEV = old_decode_dev(root_dev);
-#ifdef CONFIG_BLK_DEV_INITRD
+#ifdef CONFIG_BLK_DEV_RAM
rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0);
rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);
diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
index 8986697..cfa7d34 100644
--- a/arch/sparc/mm/init.c
+++ b/arch/sparc/mm/init.c
@@ -31,6 +31,7 @@
#include <asm/vaddrs.h>
#include <asm/pgalloc.h> /* bug in asm-generic/tlb.h: check_pgt_cache */
#include <asm/tlb.h>
+#include <asm/prom.h>
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
@@ -349,6 +350,7 @@ void __init paging_init(void)
protection_map[14] = PAGE_SHARED;
protection_map[15] = PAGE_SHARED;
btfixup();
+ prom_build_devicetree();
device_scan();
}
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 9da75f8..b2f4114 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.17
-# Tue Jun 20 01:26:43 2006
+# Fri Jun 23 23:17:09 2006
#
CONFIG_SPARC=y
CONFIG_SPARC64=y
@@ -286,6 +286,7 @@ CONFIG_STANDALONE=y
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
CONFIG_FW_LOADER=y
# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_SYS_HYPERVISOR is not set
#
# Connector - unified userspace <-> kernelspace linker
@@ -434,6 +435,7 @@ CONFIG_ISCSI_TCP=m
# CONFIG_MEGARAID_LEGACY is not set
# CONFIG_MEGARAID_SAS is not set
# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_IPS is not set
@@ -733,6 +735,7 @@ CONFIG_I2C_ALGOBIT=y
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PROSAVAGE is not set
# CONFIG_I2C_SAVAGE4 is not set
@@ -776,6 +779,7 @@ CONFIG_I2C_ALGOBIT=y
#
CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
# CONFIG_SENSORS_ADM1021 is not set
# CONFIG_SENSORS_ADM1025 is not set
# CONFIG_SENSORS_ADM1026 is not set
@@ -804,10 +808,12 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_PC87360 is not set
# CONFIG_SENSORS_SIS5595 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT8231 is not set
# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
# CONFIG_SENSORS_W83792D is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
@@ -1018,6 +1024,7 @@ CONFIG_USB_DEVICEFS=y
CONFIG_USB_EHCI_HCD=m
# CONFIG_USB_EHCI_SPLIT_ISO is not set
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
# CONFIG_USB_ISP116X_HCD is not set
CONFIG_USB_OHCI_HCD=y
# CONFIG_USB_OHCI_BIG_ENDIAN is not set
@@ -1097,10 +1104,12 @@ CONFIG_USB_HIDDEV=y
# CONFIG_USB_LEGOTOWER is not set
# CONFIG_USB_LCD is not set
# CONFIG_USB_LED is not set
+# CONFIG_USB_CY7C63 is not set
# CONFIG_USB_CYTHERM is not set
# CONFIG_USB_PHIDGETKIT is not set
# CONFIG_USB_PHIDGETSERVO is not set
# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_APPLEDISPLAY is not set
# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
# CONFIG_USB_TEST is not set
@@ -1198,6 +1207,7 @@ CONFIG_FS_POSIX_ACL=y
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index 6f68164..86c9fe3 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -12,7 +12,7 @@ obj-y := process.o setup.o cpu.o idprom.o \
irq.o ptrace.o time.o sys_sparc.o signal.o \
unaligned.o central.o pci.o starfire.o semaphore.o \
power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \
- visemul.o
+ visemul.o prom.o of_device.o
obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \
pci_psycho.o pci_sabre.o pci_schizo.o \
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
index 8852c20..2c42894 100644
--- a/arch/sparc64/kernel/auxio.c
+++ b/arch/sparc64/kernel/auxio.c
@@ -110,43 +110,82 @@ void auxio_set_lte(int on)
}
}
-void __init auxio_probe(void)
+static void __devinit auxio_report_dev(struct device_node *dp)
{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev = NULL;
-
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- if(!strcmp(sdev->prom_name, "auxio"))
- goto found_sdev;
- }
- }
-
-found_sdev:
- if (sdev) {
- auxio_devtype = AUXIO_TYPE_SBUS;
- auxio_register = sbus_ioremap(&sdev->resource[0], 0,
- sdev->reg_addrs[0].reg_size,
- "auxiliaryIO");
- }
+ printk(KERN_INFO "AUXIO: Found device at %s\n",
+ dp->full_name);
+}
+
+static struct of_device_id auxio_match[] = {
+ {
+ .name = "auxio",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, auxio_match);
+
+#ifdef CONFIG_SBUS
+static int __devinit auxio_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+{
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+
+ auxio_devtype = AUXIO_TYPE_SBUS;
+ auxio_register = sbus_ioremap(&sdev->resource[0], 0,
+ sdev->reg_addrs[0].reg_size,
+ "auxiliaryIO");
+ if (!auxio_register)
+ return -ENODEV;
+
+ auxio_report_dev(dev->node);
+ return 0;
+}
+
+static struct of_platform_driver auxio_sbus_driver = {
+ .name = "auxio",
+ .match_table = auxio_match,
+ .probe = auxio_sbus_probe,
+};
+#endif
+
#ifdef CONFIG_PCI
- else {
- struct linux_ebus *ebus;
- struct linux_ebus_device *edev = NULL;
-
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "auxio"))
- goto ebus_done;
- }
- }
- ebus_done:
- if (edev) {
- auxio_devtype = AUXIO_TYPE_EBUS;
- auxio_register =
- ioremap(edev->resource[0].start, sizeof(u32));
- }
- }
+static int __devinit auxio_ebus_probe(struct of_device *dev, const struct of_device_id *match)
+{
+ struct linux_ebus_device *edev = to_ebus_device(&dev->dev);
+
+ auxio_devtype = AUXIO_TYPE_EBUS;
+ auxio_register = ioremap(edev->resource[0].start, sizeof(u32));
+ if (!auxio_register)
+ return -ENODEV;
+
+ auxio_report_dev(dev->node);
+
auxio_set_led(AUXIO_LED_ON);
+
+ return 0;
+}
+
+static struct of_platform_driver auxio_ebus_driver = {
+ .name = "auxio",
+ .match_table = auxio_match,
+ .probe = auxio_ebus_probe,
+};
#endif
+
+static int __init auxio_probe(void)
+{
+#ifdef CONFIG_SBUS
+ of_register_driver(&auxio_sbus_driver, &sbus_bus_type);
+#endif
+#ifdef CONFIG_PCI
+ of_register_driver(&auxio_ebus_driver, &ebus_bus_type);
+#endif
+
+ return 0;
}
+
+/* Must be after subsys_initcall() so that busses are probed. Must
+ * be before device_initcall() because things like the floppy driver
+ * need to use the AUXIO register.
+ */
+fs_initcall(auxio_probe);
diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c
index 3d184a7..b66336d 100644
--- a/arch/sparc64/kernel/central.c
+++ b/arch/sparc64/kernel/central.c
@@ -29,28 +29,34 @@ static void central_probe_failure(int line)
prom_halt();
}
-static void central_ranges_init(int cnode, struct linux_central *central)
+static void central_ranges_init(struct linux_central *central)
{
- int success;
+ struct device_node *dp = central->prom_node;
+ void *pval;
+ int len;
central->num_central_ranges = 0;
- success = prom_getproperty(central->prom_node, "ranges",
- (char *) central->central_ranges,
- sizeof (central->central_ranges));
- if (success != -1)
- central->num_central_ranges = (success/sizeof(struct linux_prom_ranges));
+ pval = of_get_property(dp, "ranges", &len);
+ if (pval) {
+ memcpy(central->central_ranges, pval, len);
+ central->num_central_ranges =
+ (len / sizeof(struct linux_prom_ranges));
+ }
}
-static void fhc_ranges_init(int fnode, struct linux_fhc *fhc)
+static void fhc_ranges_init(struct linux_fhc *fhc)
{
- int success;
+ struct device_node *dp = fhc->prom_node;
+ void *pval;
+ int len;
fhc->num_fhc_ranges = 0;
- success = prom_getproperty(fhc->prom_node, "ranges",
- (char *) fhc->fhc_ranges,
- sizeof (fhc->fhc_ranges));
- if (success != -1)
- fhc->num_fhc_ranges = (success/sizeof(struct linux_prom_ranges));
+ pval = of_get_property(dp, "ranges", &len);
+ if (pval) {
+ memcpy(fhc->fhc_ranges, pval, len);
+ fhc->num_fhc_ranges =
+ (len / sizeof(struct linux_prom_ranges));
+ }
}
/* Range application routines are exported to various drivers,
@@ -112,15 +118,10 @@ static unsigned long prom_reg_to_paddr(struct linux_prom_registers *r)
static void probe_other_fhcs(void)
{
- struct linux_prom64_registers fpregs[6];
- char namebuf[128];
- int node;
+ struct device_node *dp;
+ struct linux_prom64_registers *fpregs;
- node = prom_getchild(prom_root_node);
- node = prom_searchsiblings(node, "fhc");
- if (node == 0)
- central_probe_failure(__LINE__);
- while (node) {
+ for_each_node_by_name(dp, "fhc") {
struct linux_fhc *fhc;
int board;
u32 tmp;
@@ -137,14 +138,12 @@ static void probe_other_fhcs(void)
/* Toplevel FHCs have no parent. */
fhc->parent = NULL;
- fhc->prom_node = node;
- prom_getstring(node, "name", namebuf, sizeof(namebuf));
- strcpy(fhc->prom_name, namebuf);
- fhc_ranges_init(node, fhc);
+ fhc->prom_node = dp;
+ fhc_ranges_init(fhc);
/* Non-central FHC's have 64-bit OBP format registers. */
- if (prom_getproperty(node, "reg",
- (char *)&fpregs[0], sizeof(fpregs)) == -1)
+ fpregs = of_get_property(dp, "reg", NULL);
+ if (!fpregs)
central_probe_failure(__LINE__);
/* Only central FHC needs special ranges applied. */
@@ -155,7 +154,7 @@ static void probe_other_fhcs(void)
fhc->fhc_regs.uregs = fpregs[4].phys_addr;
fhc->fhc_regs.tregs = fpregs[5].phys_addr;
- board = prom_getintdefault(node, "board#", -1);
+ board = of_getintprop_default(dp, "board#", -1);
fhc->board = board;
tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_JCTRL);
@@ -179,33 +178,33 @@ static void probe_other_fhcs(void)
tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
tmp |= FHC_CONTROL_IXIST;
upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
-
- /* Look for the next FHC. */
- node = prom_getsibling(node);
- if (node == 0)
- break;
- node = prom_searchsiblings(node, "fhc");
- if (node == 0)
- break;
}
}
static void probe_clock_board(struct linux_central *central,
struct linux_fhc *fhc,
- int cnode, int fnode)
+ struct device_node *fp)
{
- struct linux_prom_registers cregs[3];
- int clknode, nslots, tmp, nregs;
+ struct device_node *dp;
+ struct linux_prom_registers cregs[3], *pr;
+ int nslots, tmp, nregs;
- clknode = prom_searchsiblings(prom_getchild(fnode), "clock-board");
- if (clknode == 0 || clknode == -1)
+ dp = fp->child;
+ while (dp) {
+ if (!strcmp(dp->name, "clock-board"))
+ break;
+ dp = dp->sibling;
+ }
+ if (!dp)
central_probe_failure(__LINE__);
- nregs = prom_getproperty(clknode, "reg", (char *)&cregs[0], sizeof(cregs));
- if (nregs == -1)
+ pr = of_get_property(dp, "reg", &nregs);
+ if (!pr)
central_probe_failure(__LINE__);
+ memcpy(cregs, pr, nregs);
nregs /= sizeof(struct linux_prom_registers);
+
apply_fhc_ranges(fhc, &cregs[0], nregs);
apply_central_ranges(central, &cregs[0], nregs);
central->cfreg = prom_reg_to_paddr(&cregs[0]);
@@ -296,13 +295,13 @@ static void init_all_fhc_hw(void)
void central_probe(void)
{
- struct linux_prom_registers fpregs[6];
+ struct linux_prom_registers fpregs[6], *pr;
struct linux_fhc *fhc;
- char namebuf[128];
- int cnode, fnode, err;
+ struct device_node *dp, *fp;
+ int err;
- cnode = prom_finddevice("/central");
- if (cnode == 0 || cnode == -1) {
+ dp = of_find_node_by_name(NULL, "central");
+ if (!dp) {
if (this_is_starfire)
starfire_cpu_setup();
return;
@@ -321,31 +320,31 @@ void central_probe(void)
/* First init central. */
central_bus->child = fhc;
- central_bus->prom_node = cnode;
-
- prom_getstring(cnode, "name", namebuf, sizeof(namebuf));
- strcpy(central_bus->prom_name, namebuf);
-
- central_ranges_init(cnode, central_bus);
+ central_bus->prom_node = dp;
+ central_ranges_init(central_bus);
/* And then central's FHC. */
fhc->next = fhc_list;
fhc_list = fhc;
fhc->parent = central_bus;
- fnode = prom_searchsiblings(prom_getchild(cnode), "fhc");
- if (fnode == 0 || fnode == -1)
+ fp = dp->child;
+ while (fp) {
+ if (!strcmp(fp->name, "fhc"))
+ break;
+ fp = fp->sibling;
+ }
+ if (!fp)
central_probe_failure(__LINE__);
- fhc->prom_node = fnode;
- prom_getstring(fnode, "name", namebuf, sizeof(namebuf));
- strcpy(fhc->prom_name, namebuf);
-
- fhc_ranges_init(fnode, fhc);
+ fhc->prom_node = fp;
+ fhc_ranges_init(fhc);
/* Now, map in FHC register set. */
- if (prom_getproperty(fnode, "reg", (char *)&fpregs[0], sizeof(fpregs)) == -1)
+ pr = of_get_property(fp, "reg", NULL);
+ if (!pr)
central_probe_failure(__LINE__);
+ memcpy(fpregs, pr, sizeof(fpregs));
apply_central_ranges(central_bus, &fpregs[0], 6);
@@ -366,7 +365,7 @@ void central_probe(void)
fhc->jtag_master = 0;
/* Attach the clock board registers for CENTRAL. */
- probe_clock_board(central_bus, fhc, cnode, fnode);
+ probe_clock_board(central_bus, fhc, fp);
err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID);
printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] (CENTRAL)\n",
diff --git a/arch/sparc64/kernel/chmc.c b/arch/sparc64/kernel/chmc.c
index 97cf912..259f37e 100644
--- a/arch/sparc64/kernel/chmc.c
+++ b/arch/sparc64/kernel/chmc.c
@@ -17,6 +17,7 @@
#include <asm/spitfire.h>
#include <asm/chmctrl.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
#include <asm/io.h>
#define CHMCTRL_NDGRPS 2
@@ -67,7 +68,6 @@ struct bank_info {
struct mctrl_info {
struct list_head list;
int portid;
- int index;
struct obp_mem_layout layout_prop;
int layout_size;
@@ -339,12 +339,13 @@ static void fetch_decode_regs(struct mctrl_info *mp)
read_mcreg(mp, CHMCTRL_DECODE4));
}
-static int init_one_mctrl(int node, int index)
+static int init_one_mctrl(struct device_node *dp)
{
struct mctrl_info *mp = kmalloc(sizeof(*mp), GFP_KERNEL);
- int portid = prom_getintdefault(node, "portid", -1);
- struct linux_prom64_registers p_reg_prop;
- int t;
+ int portid = of_getintprop_default(dp, "portid", -1);
+ struct linux_prom64_registers *regs;
+ void *pval;
+ int len;
if (!mp)
return -1;
@@ -353,24 +354,21 @@ static int init_one_mctrl(int node, int index)
goto fail;
mp->portid = portid;
- mp->layout_size = prom_getproplen(node, "memory-layout");
- if (mp->layout_size < 0)
+ pval = of_get_property(dp, "memory-layout", &len);
+ mp->layout_size = len;
+ if (!pval)
mp->layout_size = 0;
- if (mp->layout_size > sizeof(mp->layout_prop))
- goto fail;
-
- if (mp->layout_size > 0)
- prom_getproperty(node, "memory-layout",
- (char *) &mp->layout_prop,
- mp->layout_size);
+ else {
+ if (mp->layout_size > sizeof(mp->layout_prop))
+ goto fail;
+ memcpy(&mp->layout_prop, pval, len);
+ }
- t = prom_getproperty(node, "reg",
- (char *) &p_reg_prop,
- sizeof(p_reg_prop));
- if (t < 0 || p_reg_prop.reg_size != 0x48)
+ regs = of_get_property(dp, "reg", NULL);
+ if (!regs || regs->reg_size != 0x48)
goto fail;
- mp->regs = ioremap(p_reg_prop.phys_addr, p_reg_prop.reg_size);
+ mp->regs = ioremap(regs->phys_addr, regs->reg_size);
if (mp->regs == NULL)
goto fail;
@@ -384,13 +382,11 @@ static int init_one_mctrl(int node, int index)
fetch_decode_regs(mp);
- mp->index = index;
-
list_add(&mp->list, &mctrl_list);
/* Report the device. */
- printk(KERN_INFO "chmc%d: US3 memory controller at %p [%s]\n",
- mp->index,
+ printk(KERN_INFO "%s: US3 memory controller at %p [%s]\n",
+ dp->full_name,
mp->regs, (mp->layout_size ? "ACTIVE" : "INACTIVE"));
return 0;
@@ -404,34 +400,19 @@ fail:
return -1;
}
-static int __init probe_for_string(char *name, int index)
-{
- int node = prom_getchild(prom_root_node);
-
- while ((node = prom_searchsiblings(node, name)) != 0) {
- int ret = init_one_mctrl(node, index);
-
- if (!ret)
- index++;
-
- node = prom_getsibling(node);
- if (!node)
- break;
- }
-
- return index;
-}
-
static int __init chmc_init(void)
{
- int index;
+ struct device_node *dp;
/* This driver is only for cheetah platforms. */
if (tlb_type != cheetah && tlb_type != cheetah_plus)
return -ENODEV;
- index = probe_for_string("memory-controller", 0);
- index = probe_for_string("mc-us3", index);
+ for_each_node_by_name(dp, "memory-controller")
+ init_one_mctrl(dp);
+
+ for_each_node_by_name(dp, "mc-us3")
+ init_one_mctrl(dp);
return 0;
}
diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c
index 0dd95ae..389301c 100644
--- a/arch/sparc64/kernel/devices.c
+++ b/arch/sparc64/kernel/devices.c
@@ -33,7 +33,7 @@ extern void cpu_probe(void);
extern void central_probe(void);
u32 sun4v_vdev_devhandle;
-int sun4v_vdev_root;
+struct device_node *sun4v_vdev_root;
struct vdev_intmap {
unsigned int phys;
@@ -50,102 +50,68 @@ struct vdev_intmask {
static struct vdev_intmap *vdev_intmap;
static int vdev_num_intmap;
-static struct vdev_intmask vdev_intmask;
+static struct vdev_intmask *vdev_intmask;
static void __init sun4v_virtual_device_probe(void)
{
- struct linux_prom64_registers regs;
- struct vdev_intmap *ip;
- int node, sz, err;
+ struct linux_prom64_registers *regs;
+ struct property *prop;
+ struct device_node *dp;
+ int sz;
if (tlb_type != hypervisor)
return;
- node = prom_getchild(prom_root_node);
- node = prom_searchsiblings(node, "virtual-devices");
- if (!node) {
+ dp = of_find_node_by_name(NULL, "virtual-devices");
+ if (!dp) {
prom_printf("SUN4V: Fatal error, no virtual-devices node.\n");
prom_halt();
}
- sun4v_vdev_root = node;
+ sun4v_vdev_root = dp;
- prom_getproperty(node, "reg", (char *)&regs, sizeof(regs));
- sun4v_vdev_devhandle = (regs.phys_addr >> 32UL) & 0x0fffffff;
+ prop = of_find_property(dp, "reg", NULL);
+ regs = prop->value;
+ sun4v_vdev_devhandle = (regs[0].phys_addr >> 32UL) & 0x0fffffff;
- sz = prom_getproplen(node, "interrupt-map");
- if (sz <= 0) {
- prom_printf("SUN4V: Error, no vdev interrupt-map.\n");
- prom_halt();
- }
-
- if ((sz % sizeof(*ip)) != 0) {
- prom_printf("SUN4V: Bogus interrupt-map property size %d\n",
- sz);
- prom_halt();
- }
-
- vdev_intmap = ip = alloc_bootmem_low_pages(sz);
- if (!vdev_intmap) {
- prom_printf("SUN4V: Error, cannot allocate vdev_intmap.\n");
- prom_halt();
- }
-
- err = prom_getproperty(node, "interrupt-map", (char *) ip, sz);
- if (err == -1) {
- prom_printf("SUN4V: Fatal error, no vdev interrupt-map.\n");
- prom_halt();
- }
- if (err != sz) {
- prom_printf("SUN4V: Inconsistent interrupt-map size, "
- "proplen(%d) vs getprop(%d).\n", sz,err);
- prom_halt();
- }
-
- vdev_num_intmap = err / sizeof(*ip);
+ prop = of_find_property(dp, "interrupt-map", &sz);
+ vdev_intmap = prop->value;
+ vdev_num_intmap = sz / sizeof(struct vdev_intmap);
- err = prom_getproperty(node, "interrupt-map-mask",
- (char *) &vdev_intmask,
- sizeof(vdev_intmask));
- if (err <= 0) {
- prom_printf("SUN4V: Fatal error, no vdev "
- "interrupt-map-mask.\n");
- prom_halt();
- }
- if (err % sizeof(vdev_intmask)) {
- prom_printf("SUN4V: Bogus interrupt-map-mask "
- "property size %d\n", err);
- prom_halt();
- }
+ prop = of_find_property(dp, "interrupt-map-mask", NULL);
+ vdev_intmask = prop->value;
- printk("SUN4V: virtual-devices devhandle[%x]\n",
- sun4v_vdev_devhandle);
+ printk("%s: Virtual Device Bus devhandle[%x]\n",
+ dp->full_name, sun4v_vdev_devhandle);
}
-unsigned int sun4v_vdev_device_interrupt(unsigned int dev_node)
+unsigned int sun4v_vdev_device_interrupt(struct device_node *dev_node)
{
+ struct property *prop;
unsigned int irq, reg;
- int err, i;
+ int i;
- err = prom_getproperty(dev_node, "interrupts",
- (char *) &irq, sizeof(irq));
- if (err <= 0) {
+ prop = of_find_property(dev_node, "interrupts", NULL);
+ if (!prop) {
printk("VDEV: Cannot get \"interrupts\" "
- "property for OBP node %x\n", dev_node);
+ "property for OBP node %s\n",
+ dev_node->full_name);
return 0;
}
+ irq = *(unsigned int *) prop->value;
- err = prom_getproperty(dev_node, "reg",
- (char *) &reg, sizeof(reg));
- if (err <= 0) {
+ prop = of_find_property(dev_node, "reg", NULL);
+ if (!prop) {
printk("VDEV: Cannot get \"reg\" "
- "property for OBP node %x\n", dev_node);
+ "property for OBP node %s\n",
+ dev_node->full_name);
return 0;
}
+ reg = *(unsigned int *) prop->value;
for (i = 0; i < vdev_num_intmap; i++) {
- if (vdev_intmap[i].phys == (reg & vdev_intmask.phys) &&
- vdev_intmap[i].irq == (irq & vdev_intmask.interrupt)) {
+ if (vdev_intmap[i].phys == (reg & vdev_intmask->phys) &&
+ vdev_intmap[i].irq == (irq & vdev_intmask->interrupt)) {
irq = vdev_intmap[i].cinterrupt;
break;
}
@@ -153,7 +119,7 @@ unsigned int sun4v_vdev_device_interrupt(unsigned int dev_node)
if (i == vdev_num_intmap) {
printk("VDEV: No matching interrupt map entry "
- "for OBP node %x\n", dev_node);
+ "for OBP node %s\n", dev_node->full_name);
return 0;
}
@@ -167,38 +133,44 @@ static const char *cpu_mid_prop(void)
return "portid";
}
-static int get_cpu_mid(int prom_node)
+static int get_cpu_mid(struct device_node *dp)
{
+ struct property *prop;
+
if (tlb_type == hypervisor) {
- struct linux_prom64_registers reg;
+ struct linux_prom64_registers *reg;
+ int len;
- if (prom_getproplen(prom_node, "cpuid") == 4)
- return prom_getintdefault(prom_node, "cpuid", 0);
+ prop = of_find_property(dp, "cpuid", &len);
+ if (prop && len == 4)
+ return *(int *) prop->value;
- prom_getproperty(prom_node, "reg", (char *) &reg, sizeof(reg));
- return (reg.phys_addr >> 32) & 0x0fffffffUL;
+ prop = of_find_property(dp, "reg", NULL);
+ reg = prop->value;
+ return (reg[0].phys_addr >> 32) & 0x0fffffffUL;
} else {
const char *prop_name = cpu_mid_prop();
- return prom_getintdefault(prom_node, prop_name, 0);
+ prop = of_find_property(dp, prop_name, NULL);
+ if (prop)
+ return *(int *) prop->value;
+ return 0;
}
}
-static int check_cpu_node(int nd, int *cur_inst,
- int (*compare)(int, int, void *), void *compare_arg,
- int *prom_node, int *mid)
+static int check_cpu_node(struct device_node *dp, int *cur_inst,
+ int (*compare)(struct device_node *, int, void *),
+ void *compare_arg,
+ struct device_node **dev_node, int *mid)
{
- char node_str[128];
-
- prom_getstring(nd, "device_type", node_str, sizeof(node_str));
- if (strcmp(node_str, "cpu"))
+ if (strcmp(dp->type, "cpu"))
return -ENODEV;
- if (!compare(nd, *cur_inst, compare_arg)) {
- if (prom_node)
- *prom_node = nd;
+ if (!compare(dp, *cur_inst, compare_arg)) {
+ if (dev_node)
+ *dev_node = dp;
if (mid)
- *mid = get_cpu_mid(nd);
+ *mid = get_cpu_mid(dp);
return 0;
}
@@ -207,25 +179,18 @@ static int check_cpu_node(int nd, int *cur_inst,
return -ENODEV;
}
-static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg,
- int *prom_node, int *mid)
+static int __cpu_find_by(int (*compare)(struct device_node *, int, void *),
+ void *compare_arg,
+ struct device_node **dev_node, int *mid)
{
- int nd, cur_inst, err;
+ struct device_node *dp;
+ int cur_inst;
- nd = prom_root_node;
cur_inst = 0;
-
- err = check_cpu_node(nd, &cur_inst,
- compare, compare_arg,
- prom_node, mid);
- if (err == 0)
- return 0;
-
- nd = prom_getchild(nd);
- while ((nd = prom_getsibling(nd)) != 0) {
- err = check_cpu_node(nd, &cur_inst,
- compare, compare_arg,
- prom_node, mid);
+ for_each_node_by_type(dp, "cpu") {
+ int err = check_cpu_node(dp, &cur_inst,
+ compare, compare_arg,
+ dev_node, mid);
if (err == 0)
return 0;
}
@@ -233,7 +198,7 @@ static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg,
return -ENODEV;
}
-static int cpu_instance_compare(int nd, int instance, void *_arg)
+static int cpu_instance_compare(struct device_node *dp, int instance, void *_arg)
{
int desired_instance = (int) (long) _arg;
@@ -242,27 +207,27 @@ static int cpu_instance_compare(int nd, int instance, void *_arg)
return -ENODEV;
}
-int cpu_find_by_instance(int instance, int *prom_node, int *mid)
+int cpu_find_by_instance(int instance, struct device_node **dev_node, int *mid)
{
return __cpu_find_by(cpu_instance_compare, (void *)(long)instance,
- prom_node, mid);
+ dev_node, mid);
}
-static int cpu_mid_compare(int nd, int instance, void *_arg)
+static int cpu_mid_compare(struct device_node *dp, int instance, void *_arg)
{
int desired_mid = (int) (long) _arg;
int this_mid;
- this_mid = get_cpu_mid(nd);
+ this_mid = get_cpu_mid(dp);
if (this_mid == desired_mid)
return 0;
return -ENODEV;
}
-int cpu_find_by_mid(int mid, int *prom_node)
+int cpu_find_by_mid(int mid, struct device_node **dev_node)
{
return __cpu_find_by(cpu_mid_compare, (void *)(long)mid,
- prom_node, NULL);
+ dev_node, NULL);
}
void __init device_scan(void)
@@ -274,50 +239,47 @@ void __init device_scan(void)
#ifndef CONFIG_SMP
{
- int err, cpu_node, def;
+ struct device_node *dp;
+ int err, def;
- err = cpu_find_by_instance(0, &cpu_node, NULL);
+ err = cpu_find_by_instance(0, &dp, NULL);
if (err) {
prom_printf("No cpu nodes, cannot continue\n");
prom_halt();
}
- cpu_data(0).clock_tick = prom_getintdefault(cpu_node,
- "clock-frequency",
- 0);
+ cpu_data(0).clock_tick =
+ of_getintprop_default(dp, "clock-frequency", 0);
def = ((tlb_type == hypervisor) ?
(8 * 1024) :
(16 * 1024));
- cpu_data(0).dcache_size = prom_getintdefault(cpu_node,
- "dcache-size",
- def);
+ cpu_data(0).dcache_size = of_getintprop_default(dp,
+ "dcache-size",
+ def);
def = 32;
cpu_data(0).dcache_line_size =
- prom_getintdefault(cpu_node, "dcache-line-size",
- def);
+ of_getintprop_default(dp, "dcache-line-size", def);
def = 16 * 1024;
- cpu_data(0).icache_size = prom_getintdefault(cpu_node,
- "icache-size",
- def);
+ cpu_data(0).icache_size = of_getintprop_default(dp,
+ "icache-size",
+ def);
def = 32;
cpu_data(0).icache_line_size =
- prom_getintdefault(cpu_node, "icache-line-size",
- def);
+ of_getintprop_default(dp, "icache-line-size", def);
def = ((tlb_type == hypervisor) ?
(3 * 1024 * 1024) :
(4 * 1024 * 1024));
- cpu_data(0).ecache_size = prom_getintdefault(cpu_node,
- "ecache-size",
- def);
+ cpu_data(0).ecache_size = of_getintprop_default(dp,
+ "ecache-size",
+ def);
def = 64;
cpu_data(0).ecache_line_size =
- prom_getintdefault(cpu_node, "ecache-line-size",
- def);
+ of_getintprop_default(dp, "ecache-line-size", def);
printk("CPU[0]: Caches "
"D[sz(%d):line_sz(%d)] "
"I[sz(%d):line_sz(%d)] "
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index c69504a..98e0a8c 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -269,10 +269,6 @@ EXPORT_SYMBOL(ebus_dma_enable);
struct linux_ebus *ebus_chain = NULL;
-#ifdef CONFIG_SUN_AUXIO
-extern void auxio_probe(void);
-#endif
-
static inline void *ebus_alloc(size_t size)
{
void *mem;
@@ -283,77 +279,55 @@ static inline void *ebus_alloc(size_t size)
return mem;
}
-static void __init ebus_ranges_init(struct linux_ebus *ebus)
-{
- int success;
-
- ebus->num_ebus_ranges = 0;
- success = prom_getproperty(ebus->prom_node, "ranges",
- (char *)ebus->ebus_ranges,
- sizeof(ebus->ebus_ranges));
- if (success != -1)
- ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges));
-}
-
-static void __init ebus_intmap_init(struct linux_ebus *ebus)
-{
- int success;
-
- ebus->num_ebus_intmap = 0;
- success = prom_getproperty(ebus->prom_node, "interrupt-map",
- (char *)ebus->ebus_intmap,
- sizeof(ebus->ebus_intmap));
- if (success == -1)
- return;
-
- ebus->num_ebus_intmap = (success/sizeof(struct linux_prom_ebus_intmap));
-
- success = prom_getproperty(ebus->prom_node, "interrupt-map-mask",
- (char *)&ebus->ebus_intmask,
- sizeof(ebus->ebus_intmask));
- if (success == -1) {
- prom_printf("%s: can't get interrupt-map-mask\n", __FUNCTION__);
- prom_halt();
- }
-}
-
int __init ebus_intmap_match(struct linux_ebus *ebus,
struct linux_prom_registers *reg,
int *interrupt)
{
+ struct linux_prom_ebus_intmap *imap;
+ struct linux_prom_ebus_intmask *imask;
unsigned int hi, lo, irq;
- int i;
+ int i, len, n_imap;
+
+ imap = of_get_property(ebus->prom_node, "interrupt-map", &len);
+ if (!imap)
+ return 0;
+ n_imap = len / sizeof(imap[0]);
- if (!ebus->num_ebus_intmap)
+ imask = of_get_property(ebus->prom_node, "interrupt-map-mask", NULL);
+ if (!imask)
return 0;
- hi = reg->which_io & ebus->ebus_intmask.phys_hi;
- lo = reg->phys_addr & ebus->ebus_intmask.phys_lo;
- irq = *interrupt & ebus->ebus_intmask.interrupt;
- for (i = 0; i < ebus->num_ebus_intmap; i++) {
- if ((ebus->ebus_intmap[i].phys_hi == hi) &&
- (ebus->ebus_intmap[i].phys_lo == lo) &&
- (ebus->ebus_intmap[i].interrupt == irq)) {
- *interrupt = ebus->ebus_intmap[i].cinterrupt;
+ hi = reg->which_io & imask->phys_hi;
+ lo = reg->phys_addr & imask->phys_lo;
+ irq = *interrupt & imask->interrupt;
+ for (i = 0; i < n_imap; i++) {
+ if ((imap[i].phys_hi == hi) &&
+ (imap[i].phys_lo == lo) &&
+ (imap[i].interrupt == irq)) {
+ *interrupt = imap[i].cinterrupt;
return 0;
}
}
return -1;
}
-void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
- struct linux_ebus_child *dev, int non_standard_regs)
+void __init fill_ebus_child(struct device_node *dp,
+ struct linux_prom_registers *preg,
+ struct linux_ebus_child *dev,
+ int non_standard_regs)
{
- int regs[PROMREG_MAX];
- int irqs[PROMREG_MAX];
+ int *regs;
+ int *irqs;
int i, len;
- dev->prom_node = node;
- prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name));
- printk(" (%s)", dev->prom_name);
+ dev->prom_node = dp;
+ printk(" (%s)", dp->name);
- len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
- dev->num_addrs = len / sizeof(regs[0]);
+ regs = of_get_property(dp, "reg", &len);
+ if (!regs)
+ dev->num_addrs = 0;
+ else
+ dev->num_addrs = len / sizeof(regs[0]);
if (non_standard_regs) {
/* This is to handle reg properties which are not
@@ -370,21 +344,21 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
int rnum = regs[i];
if (rnum >= dev->parent->num_addrs) {
prom_printf("UGH: property for %s was %d, need < %d\n",
- dev->prom_name, len, dev->parent->num_addrs);
- panic(__FUNCTION__);
+ dp->name, len, dev->parent->num_addrs);
+ prom_halt();
}
dev->resource[i].start = dev->parent->resource[i].start;
dev->resource[i].end = dev->parent->resource[i].end;
dev->resource[i].flags = IORESOURCE_MEM;
- dev->resource[i].name = dev->prom_name;
+ dev->resource[i].name = dp->name;
}
}
for (i = 0; i < PROMINTR_MAX; i++)
dev->irqs[i] = PCI_IRQ_NONE;
- len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
- if ((len == -1) || (len == 0)) {
+ irqs = of_get_property(dp, "interrupts", &len);
+ if (!irqs) {
dev->num_irqs = 0;
/*
* Oh, well, some PROMs don't export interrupts
@@ -392,8 +366,8 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
*
* Be smart about PS/2 keyboard and mouse.
*/
- if (!strcmp(dev->parent->prom_name, "8042")) {
- if (!strcmp(dev->prom_name, "kb_ps2")) {
+ if (!strcmp(dev->parent->prom_node->name, "8042")) {
+ if (!strcmp(dev->prom_node->name, "kb_ps2")) {
dev->num_irqs = 1;
dev->irqs[0] = dev->parent->irqs[0];
} else {
@@ -423,32 +397,32 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
static int __init child_regs_nonstandard(struct linux_ebus_device *dev)
{
- if (!strcmp(dev->prom_name, "i2c") ||
- !strcmp(dev->prom_name, "SUNW,lombus"))
+ if (!strcmp(dev->prom_node->name, "i2c") ||
+ !strcmp(dev->prom_node->name, "SUNW,lombus"))
return 1;
return 0;
}
-void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
+void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
{
- struct linux_prom_registers regs[PROMREG_MAX];
+ struct linux_prom_registers *regs;
struct linux_ebus_child *child;
- int irqs[PROMINTR_MAX];
+ int *irqs;
int i, n, len;
- dev->prom_node = node;
- prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name));
- printk(" [%s", dev->prom_name);
+ dev->prom_node = dp;
+
+ printk(" [%s", dp->name);
- len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
- if (len == -1) {
+ regs = of_get_property(dp, "reg", &len);
+ if (!regs) {
dev->num_addrs = 0;
goto probe_interrupts;
}
if (len % sizeof(struct linux_prom_registers)) {
prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
- dev->prom_name, len,
+ dev->prom_node->name, len,
(int)sizeof(struct linux_prom_registers));
prom_halt();
}
@@ -466,7 +440,7 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
dev->resource[i].end =
(dev->resource[i].start + (unsigned long)regs[i].reg_size - 1UL);
dev->resource[i].flags = IORESOURCE_MEM;
- dev->resource[i].name = dev->prom_name;
+ dev->resource[i].name = dev->prom_node->name;
request_resource(&dev->bus->self->resource[n],
&dev->resource[i]);
}
@@ -475,8 +449,8 @@ probe_interrupts:
for (i = 0; i < PROMINTR_MAX; i++)
dev->irqs[i] = PCI_IRQ_NONE;
- len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
- if ((len == -1) || (len == 0)) {
+ irqs = of_get_property(dp, "interrupts", &len);
+ if (!irqs) {
dev->num_irqs = 0;
} else {
dev->num_irqs = len / sizeof(irqs[0]);
@@ -497,7 +471,18 @@ probe_interrupts:
}
}
- if ((node = prom_getchild(node))) {
+ dev->ofdev.node = dp;
+ dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
+ dev->ofdev.dev.bus = &ebus_bus_type;
+ strcpy(dev->ofdev.dev.bus_id, dp->path_component_name);
+
+ /* Register with core */
+ if (of_device_register(&dev->ofdev) != 0)
+ printk(KERN_DEBUG "ebus: device registration error for %s!\n",
+ dev->ofdev.dev.bus_id);
+
+ dp = dp->child;
+ if (dp) {
printk(" ->");
dev->children = ebus_alloc(sizeof(struct linux_ebus_child));
@@ -505,18 +490,18 @@ probe_interrupts:
child->next = NULL;
child->parent = dev;
child->bus = dev->bus;
- fill_ebus_child(node, &regs[0],
- child, child_regs_nonstandard(dev));
+ fill_ebus_child(dp, regs, child,
+ child_regs_nonstandard(dev));
- while ((node = prom_getsibling(node)) != 0) {
+ while ((dp = dp->sibling) != NULL) {
child->next = ebus_alloc(sizeof(struct linux_ebus_child));
child = child->next;
child->next = NULL;
child->parent = dev;
child->bus = dev->bus;
- fill_ebus_child(node, &regs[0],
- child, child_regs_nonstandard(dev));
+ fill_ebus_child(dp, regs, child,
+ child_regs_nonstandard(dev));
}
}
printk("]");
@@ -543,7 +528,8 @@ void __init ebus_init(void)
struct linux_ebus *ebus;
struct pci_dev *pdev;
struct pcidev_cookie *cookie;
- int nd, ebusnd, is_rio;
+ struct device_node *dp;
+ int is_rio;
int num_ebus = 0;
pdev = find_next_ebus(NULL, &is_rio);
@@ -553,20 +539,22 @@ void __init ebus_init(void)
}
cookie = pdev->sysdata;
- ebusnd = cookie->prom_node;
+ dp = cookie->prom_node;
ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus));
ebus->next = NULL;
ebus->is_rio = is_rio;
- while (ebusnd) {
+ while (dp) {
+ struct device_node *child;
+
/* SUNW,pci-qfe uses four empty ebuses on it.
I think we should not consider them here,
as they have half of the properties this
code expects and once we do PCI hot-plug,
we'd have to tweak with the ebus_chain
in the runtime after initialization. -jj */
- if (!prom_getchild (ebusnd)) {
+ if (!dp->child) {
pdev = find_next_ebus(pdev, &is_rio);
if (!pdev) {
if (ebus == ebus_chain) {
@@ -578,22 +566,29 @@ void __init ebus_init(void)
}
ebus->is_rio = is_rio;
cookie = pdev->sysdata;
- ebusnd = cookie->prom_node;
+ dp = cookie->prom_node;
continue;
}
printk("ebus%d:", num_ebus);
- prom_getstring(ebusnd, "name", ebus->prom_name, sizeof(ebus->prom_name));
ebus->index = num_ebus;
- ebus->prom_node = ebusnd;
+ ebus->prom_node = dp;
ebus->self = pdev;
ebus->parent = pbm = cookie->pbm;
- ebus_ranges_init(ebus);
- ebus_intmap_init(ebus);
+ ebus->ofdev.node = dp;
+ ebus->ofdev.dev.parent = &pdev->dev;
+ ebus->ofdev.dev.bus = &ebus_bus_type;
+ strcpy(ebus->ofdev.dev.bus_id, dp->path_component_name);
- nd = prom_getchild(ebusnd);
- if (!nd)
+ /* Register with core */
+ if (of_device_register(&ebus->ofdev) != 0)
+ printk(KERN_DEBUG "ebus: device registration error for %s!\n",
+ ebus->ofdev.dev.bus_id);
+
+
+ child = dp->child;
+ if (!child)
goto next_ebus;
ebus->devices = ebus_alloc(sizeof(struct linux_ebus_device));
@@ -602,16 +597,16 @@ void __init ebus_init(void)
dev->next = NULL;
dev->children = NULL;
dev->bus = ebus;
- fill_ebus_device(nd, dev);
+ fill_ebus_device(child, dev);
- while ((nd = prom_getsibling(nd)) != 0) {
+ while ((child = child->sibling) != NULL) {
dev->next = ebus_alloc(sizeof(struct linux_ebus_device));
dev = dev->next;
dev->next = NULL;
dev->children = NULL;
dev->bus = ebus;
- fill_ebus_device(nd, dev);
+ fill_ebus_device(child, dev);
}
next_ebus:
@@ -622,7 +617,7 @@ void __init ebus_init(void)
break;
cookie = pdev->sysdata;
- ebusnd = cookie->prom_node;
+ dp = cookie->prom_node;
ebus->next = ebus_alloc(sizeof(struct linux_ebus));
ebus = ebus->next;
@@ -631,8 +626,4 @@ void __init ebus_init(void)
++num_ebus;
}
pci_dev_put(pdev); /* XXX for the case, when ebusnd is 0, is it OK? */
-
-#ifdef CONFIG_SUN_AUXIO
- auxio_probe();
-#endif
}
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index a8c9dc8..31e0fbb 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -34,6 +34,7 @@
#include <asm/iommu.h>
#include <asm/upa.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
#include <asm/timer.h>
#include <asm/smp.h>
#include <asm/starfire.h>
@@ -635,23 +636,29 @@ static u64 prom_limit0, prom_limit1;
static void map_prom_timers(void)
{
- unsigned int addr[3];
- int tnode, err;
+ struct device_node *dp;
+ unsigned int *addr;
/* PROM timer node hangs out in the top level of device siblings... */
- tnode = prom_finddevice("/counter-timer");
+ dp = of_find_node_by_path("/");
+ dp = dp->child;
+ while (dp) {
+ if (!strcmp(dp->name, "counter-timer"))
+ break;
+ dp = dp->sibling;
+ }
/* Assume if node is not present, PROM uses different tick mechanism
* which we should not care about.
*/
- if (tnode == 0 || tnode == -1) {
+ if (!dp) {
prom_timers = (struct sun5_timer *) 0;
return;
}
/* If PROM is really using this, it must be mapped by him. */
- err = prom_getproperty(tnode, "address", (char *)addr, sizeof(addr));
- if (err == -1) {
+ addr = of_get_property(dp, "address", NULL);
+ if (!addr) {
prom_printf("PROM does not have timer mapped, trying to continue.\n");
prom_timers = (struct sun5_timer *) 0;
return;
diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c
index 30862ab..6f16dee 100644
--- a/arch/sparc64/kernel/isa.c
+++ b/arch/sparc64/kernel/isa.c
@@ -15,23 +15,19 @@ static void __init fatal_err(const char *reason)
static void __init report_dev(struct sparc_isa_device *isa_dev, int child)
{
if (child)
- printk(" (%s)", isa_dev->prom_name);
+ printk(" (%s)", isa_dev->prom_node->name);
else
- printk(" [%s", isa_dev->prom_name);
+ printk(" [%s", isa_dev->prom_node->name);
}
-static void __init isa_dev_get_resource(struct sparc_isa_device *isa_dev,
- struct linux_prom_registers *pregs,
- int pregs_size)
+static struct linux_prom_registers * __init
+isa_dev_get_resource(struct sparc_isa_device *isa_dev)
{
+ struct linux_prom_registers *pregs;
unsigned long base, len;
int prop_len;
- prop_len = prom_getproperty(isa_dev->prom_node, "reg",
- (char *) pregs, pregs_size);
-
- if (prop_len <= 0)
- return;
+ pregs = of_get_property(isa_dev->prom_node, "reg", &prop_len);
/* Only the first one is interesting. */
len = pregs[0].reg_size;
@@ -42,10 +38,12 @@ static void __init isa_dev_get_resource(struct sparc_isa_device *isa_dev,
isa_dev->resource.start = base;
isa_dev->resource.end = (base + len - 1UL);
isa_dev->resource.flags = IORESOURCE_IO;
- isa_dev->resource.name = isa_dev->prom_name;
+ isa_dev->resource.name = isa_dev->prom_node->name;
request_resource(&isa_dev->bus->parent->io_space,
&isa_dev->resource);
+
+ return pregs;
}
/* I can't believe they didn't put a real INO in the isa device
@@ -74,19 +72,30 @@ static struct {
static int __init isa_dev_get_irq_using_imap(struct sparc_isa_device *isa_dev,
struct sparc_isa_bridge *isa_br,
int *interrupt,
- struct linux_prom_registers *pregs)
+ struct linux_prom_registers *reg)
{
+ struct linux_prom_ebus_intmap *imap;
+ struct linux_prom_ebus_intmap *imask;
unsigned int hi, lo, irq;
- int i;
-
- hi = pregs->which_io & isa_br->isa_intmask.phys_hi;
- lo = pregs->phys_addr & isa_br->isa_intmask.phys_lo;
- irq = *interrupt & isa_br->isa_intmask.interrupt;
- for (i = 0; i < isa_br->num_isa_intmap; i++) {
- if ((isa_br->isa_intmap[i].phys_hi == hi) &&
- (isa_br->isa_intmap[i].phys_lo == lo) &&
- (isa_br->isa_intmap[i].interrupt == irq)) {
- *interrupt = isa_br->isa_intmap[i].cinterrupt;
+ int i, len, n_imap;
+
+ imap = of_get_property(isa_br->prom_node, "interrupt-map", &len);
+ if (!imap)
+ return 0;
+ n_imap = len / sizeof(imap[0]);
+
+ imask = of_get_property(isa_br->prom_node, "interrupt-map-mask", NULL);
+ if (!imask)
+ return 0;
+
+ hi = reg->which_io & imask->phys_hi;
+ lo = reg->phys_addr & imask->phys_lo;
+ irq = *interrupt & imask->interrupt;
+ for (i = 0; i < n_imap; i++) {
+ if ((imap[i].phys_hi == hi) &&
+ (imap[i].phys_lo == lo) &&
+ (imap[i].interrupt == irq)) {
+ *interrupt = imap[i].cinterrupt;
return 0;
}
}
@@ -98,8 +107,8 @@ static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev,
{
int irq_prop;
- irq_prop = prom_getintdefault(isa_dev->prom_node,
- "interrupts", -1);
+ irq_prop = of_getintprop_default(isa_dev->prom_node,
+ "interrupts", -1);
if (irq_prop <= 0) {
goto no_irq;
} else {
@@ -107,7 +116,8 @@ static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev,
struct pci_pbm_info *pbm;
int i;
- if (isa_dev->bus->num_isa_intmap) {
+ if (of_find_property(isa_dev->bus->prom_node,
+ "interrupt-map", NULL)) {
if (!isa_dev_get_irq_using_imap(isa_dev,
isa_dev->bus,
&irq_prop,
@@ -141,16 +151,15 @@ no_irq:
static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev)
{
- int node = prom_getchild(parent_isa_dev->prom_node);
+ struct device_node *dp = parent_isa_dev->prom_node->child;
- if (node == 0)
+ if (!dp)
return;
printk(" ->");
- while (node != 0) {
- struct linux_prom_registers regs[PROMREG_MAX];
+ while (dp) {
+ struct linux_prom_registers *regs;
struct sparc_isa_device *isa_dev;
- int prop_len;
isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL);
if (!isa_dev) {
@@ -165,49 +174,46 @@ static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev)
parent_isa_dev->child = isa_dev;
isa_dev->bus = parent_isa_dev->bus;
- isa_dev->prom_node = node;
- prop_len = prom_getproperty(node, "name",
- (char *) isa_dev->prom_name,
- sizeof(isa_dev->prom_name));
- if (prop_len <= 0) {
- fatal_err("cannot get child isa_dev OBP node name");
- prom_halt();
- }
+ isa_dev->prom_node = dp;
- prop_len = prom_getproperty(node, "compatible",
- (char *) isa_dev->compatible,
- sizeof(isa_dev->compatible));
-
- /* Not having this is OK. */
- if (prop_len <= 0)
- isa_dev->compatible[0] = '\0';
-
- isa_dev_get_resource(isa_dev, regs, sizeof(regs));
+ regs = isa_dev_get_resource(isa_dev);
isa_dev_get_irq(isa_dev, regs);
report_dev(isa_dev, 1);
- node = prom_getsibling(node);
+ dp = dp->sibling;
}
}
static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
{
- int node = prom_getchild(isa_br->prom_node);
+ struct device_node *dp = isa_br->prom_node->child;
- while (node != 0) {
- struct linux_prom_registers regs[PROMREG_MAX];
+ while (dp) {
+ struct linux_prom_registers *regs;
struct sparc_isa_device *isa_dev;
- int prop_len;
isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL);
if (!isa_dev) {
- fatal_err("cannot allocate isa_dev");
- prom_halt();
+ printk(KERN_DEBUG "ISA: cannot allocate isa_dev");
+ return;
}
memset(isa_dev, 0, sizeof(*isa_dev));
+ isa_dev->ofdev.node = dp;
+ isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev;
+ isa_dev->ofdev.dev.bus = &isa_bus_type;
+ strcpy(isa_dev->ofdev.dev.bus_id, dp->path_component_name);
+
+ /* Register with core */
+ if (of_device_register(&isa_dev->ofdev) != 0) {
+ printk(KERN_DEBUG "isa: device registration error for %s!\n",
+ isa_dev->ofdev.dev.bus_id);
+ kfree(isa_dev);
+ goto next_sibling;
+ }
+
/* Link it in. */
isa_dev->next = NULL;
if (isa_br->devices == NULL) {
@@ -222,24 +228,9 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
}
isa_dev->bus = isa_br;
- isa_dev->prom_node = node;
- prop_len = prom_getproperty(node, "name",
- (char *) isa_dev->prom_name,
- sizeof(isa_dev->prom_name));
- if (prop_len <= 0) {
- fatal_err("cannot get isa_dev OBP node name");
- prom_halt();
- }
-
- prop_len = prom_getproperty(node, "compatible",
- (char *) isa_dev->compatible,
- sizeof(isa_dev->compatible));
+ isa_dev->prom_node = dp;
- /* Not having this is OK. */
- if (prop_len <= 0)
- isa_dev->compatible[0] = '\0';
-
- isa_dev_get_resource(isa_dev, regs, sizeof(regs));
+ regs = isa_dev_get_resource(isa_dev);
isa_dev_get_irq(isa_dev, regs);
report_dev(isa_dev, 0);
@@ -248,7 +239,8 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
printk("]");
- node = prom_getsibling(node);
+ next_sibling:
+ dp = dp->sibling;
}
}
@@ -266,7 +258,7 @@ void __init isa_init(void)
struct pcidev_cookie *pdev_cookie;
struct pci_pbm_info *pbm;
struct sparc_isa_bridge *isa_br;
- int prop_len;
+ struct device_node *dp;
pdev_cookie = pdev->sysdata;
if (!pdev_cookie) {
@@ -275,15 +267,29 @@ void __init isa_init(void)
continue;
}
pbm = pdev_cookie->pbm;
+ dp = pdev_cookie->prom_node;
isa_br = kmalloc(sizeof(*isa_br), GFP_KERNEL);
if (!isa_br) {
- fatal_err("cannot allocate sparc_isa_bridge");
- prom_halt();
+ printk(KERN_DEBUG "isa: cannot allocate sparc_isa_bridge");
+ return;
}
memset(isa_br, 0, sizeof(*isa_br));
+ isa_br->ofdev.node = dp;
+ isa_br->ofdev.dev.parent = &pdev->dev;
+ isa_br->ofdev.dev.bus = &isa_bus_type;
+ strcpy(isa_br->ofdev.dev.bus_id, dp->path_component_name);
+
+ /* Register with core */
+ if (of_device_register(&isa_br->ofdev) != 0) {
+ printk(KERN_DEBUG "isa: device registration error for %s!\n",
+ isa_br->ofdev.dev.bus_id);
+ kfree(isa_br);
+ return;
+ }
+
/* Link it in. */
isa_br->next = isa_chain;
isa_chain = isa_br;
@@ -292,33 +298,6 @@ void __init isa_init(void)
isa_br->self = pdev;
isa_br->index = index++;
isa_br->prom_node = pdev_cookie->prom_node;
- strncpy(isa_br->prom_name, pdev_cookie->prom_name,
- sizeof(isa_br->prom_name));
-
- prop_len = prom_getproperty(isa_br->prom_node,
- "ranges",
- (char *) isa_br->isa_ranges,
- sizeof(isa_br->isa_ranges));
- if (prop_len <= 0)
- isa_br->num_isa_ranges = 0;
- else
- isa_br->num_isa_ranges =
- (prop_len / sizeof(struct linux_prom_isa_ranges));
-
- prop_len = prom_getproperty(isa_br->prom_node,
- "interrupt-map",
- (char *) isa_br->isa_intmap,
- sizeof(isa_br->isa_intmap));
- if (prop_len <= 0)
- isa_br->num_isa_intmap = 0;
- else
- isa_br->num_isa_intmap =
- (prop_len / sizeof(struct linux_prom_isa_intmap));
-
- prop_len = prom_getproperty(isa_br->prom_node,
- "interrupt-map-mask",
- (char *) &(isa_br->isa_intmask),
- sizeof(isa_br->isa_intmask));
printk("isa%d:", isa_br->index);
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
new file mode 100644
index 0000000..566aa34
--- /dev/null
+++ b/arch/sparc64/kernel/of_device.c
@@ -0,0 +1,279 @@
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/slab.h>
+
+#include <asm/errno.h>
+#include <asm/of_device.h>
+
+/**
+ * of_match_device - Tell if an of_device structure has a matching
+ * of_match structure
+ * @ids: array of of device match structures to search in
+ * @dev: the of device structure to match against
+ *
+ * Used by a driver to check whether an of_device present in the
+ * system is in its list of supported devices.
+ */
+const struct of_device_id *of_match_device(const struct of_device_id *matches,
+ const struct of_device *dev)
+{
+ if (!dev->node)
+ return NULL;
+ while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
+ int match = 1;
+ if (matches->name[0])
+ match &= dev->node->name
+ && !strcmp(matches->name, dev->node->name);
+ if (matches->type[0])
+ match &= dev->node->type
+ && !strcmp(matches->type, dev->node->type);
+ if (matches->compatible[0])
+ match &= of_device_is_compatible(dev->node,
+ matches->compatible);
+ if (match)
+ return matches;
+ matches++;
+ }
+ return NULL;
+}
+
+static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct of_device * of_dev = to_of_device(dev);
+ struct of_platform_driver * of_drv = to_of_platform_driver(drv);
+ const struct of_device_id * matches = of_drv->match_table;
+
+ if (!matches)
+ return 0;
+
+ return of_match_device(matches, of_dev) != NULL;
+}
+
+struct of_device *of_dev_get(struct of_device *dev)
+{
+ struct device *tmp;
+
+ if (!dev)
+ return NULL;
+ tmp = get_device(&dev->dev);
+ if (tmp)
+ return to_of_device(tmp);
+ else
+ return NULL;
+}
+
+void of_dev_put(struct of_device *dev)
+{
+ if (dev)
+ put_device(&dev->dev);
+}
+
+
+static int of_device_probe(struct device *dev)
+{
+ int error = -ENODEV;
+ struct of_platform_driver *drv;
+ struct of_device *of_dev;
+ const struct of_device_id *match;
+
+ drv = to_of_platform_driver(dev->driver);
+ of_dev = to_of_device(dev);
+
+ if (!drv->probe)
+ return error;
+
+ of_dev_get(of_dev);
+
+ match = of_match_device(drv->match_table, of_dev);
+ if (match)
+ error = drv->probe(of_dev, match);
+ if (error)
+ of_dev_put(of_dev);
+
+ return error;
+}
+
+static int of_device_remove(struct device *dev)
+{
+ struct of_device * of_dev = to_of_device(dev);
+ struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
+
+ if (dev->driver && drv->remove)
+ drv->remove(of_dev);
+ return 0;
+}
+
+static int of_device_suspend(struct device *dev, pm_message_t state)
+{
+ struct of_device * of_dev = to_of_device(dev);
+ struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
+ int error = 0;
+
+ if (dev->driver && drv->suspend)
+ error = drv->suspend(of_dev, state);
+ return error;
+}
+
+static int of_device_resume(struct device * dev)
+{
+ struct of_device * of_dev = to_of_device(dev);
+ struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
+ int error = 0;
+
+ if (dev->driver && drv->resume)
+ error = drv->resume(of_dev);
+ return error;
+}
+
+#ifdef CONFIG_PCI
+struct bus_type isa_bus_type = {
+ .name = "isa",
+ .match = of_platform_bus_match,
+ .probe = of_device_probe,
+ .remove = of_device_remove,
+ .suspend = of_device_suspend,
+ .resume = of_device_resume,
+};
+
+struct bus_type ebus_bus_type = {
+ .name = "ebus",
+ .match = of_platform_bus_match,
+ .probe = of_device_probe,
+ .remove = of_device_remove,
+ .suspend = of_device_suspend,
+ .resume = of_device_resume,
+};
+#endif
+
+#ifdef CONFIG_SBUS
+struct bus_type sbus_bus_type = {
+ .name = "sbus",
+ .match = of_platform_bus_match,
+ .probe = of_device_probe,
+ .remove = of_device_remove,
+ .suspend = of_device_suspend,
+ .resume = of_device_resume,
+};
+#endif
+
+static int __init of_bus_driver_init(void)
+{
+ int err = 0;
+
+#ifdef CONFIG_PCI
+ if (!err)
+ err = bus_register(&isa_bus_type);
+ if (!err)
+ err = bus_register(&ebus_bus_type);
+#endif
+#ifdef CONFIG_SBUS
+ if (!err)
+ err = bus_register(&sbus_bus_type);
+#endif
+ return 0;
+}
+
+postcore_initcall(of_bus_driver_init);
+
+int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
+{
+ /* initialize common driver fields */
+ drv->driver.name = drv->name;
+ drv->driver.bus = bus;
+
+ /* register with core */
+ return driver_register(&drv->driver);
+}
+
+void of_unregister_driver(struct of_platform_driver *drv)
+{
+ driver_unregister(&drv->driver);
+}
+
+
+static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct of_device *ofdev;
+
+ ofdev = to_of_device(dev);
+ return sprintf(buf, "%s", ofdev->node->full_name);
+}
+
+static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
+
+/**
+ * of_release_dev - free an of device structure when all users of it are finished.
+ * @dev: device that's been disconnected
+ *
+ * Will be called only by the device core when all users of this of device are
+ * done.
+ */
+void of_release_dev(struct device *dev)
+{
+ struct of_device *ofdev;
+
+ ofdev = to_of_device(dev);
+
+ kfree(ofdev);
+}
+
+int of_device_register(struct of_device *ofdev)
+{
+ int rc;
+
+ BUG_ON(ofdev->node == NULL);
+
+ rc = device_register(&ofdev->dev);
+ if (rc)
+ return rc;
+
+ device_create_file(&ofdev->dev, &dev_attr_devspec);
+
+ return 0;
+}
+
+void of_device_unregister(struct of_device *ofdev)
+{
+ device_remove_file(&ofdev->dev, &dev_attr_devspec);
+ device_unregister(&ofdev->dev);
+}
+
+struct of_device* of_platform_device_create(struct device_node *np,
+ const char *bus_id,
+ struct device *parent,
+ struct bus_type *bus)
+{
+ struct of_device *dev;
+
+ dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+ memset(dev, 0, sizeof(*dev));
+
+ dev->dev.parent = parent;
+ dev->dev.bus = bus;
+ dev->dev.release = of_release_dev;
+
+ strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
+
+ if (of_device_register(dev) != 0) {
+ kfree(dev);
+ return NULL;
+ }
+
+ return dev;
+}
+
+EXPORT_SYMBOL(of_match_device);
+EXPORT_SYMBOL(of_register_driver);
+EXPORT_SYMBOL(of_unregister_driver);
+EXPORT_SYMBOL(of_device_register);
+EXPORT_SYMBOL(of_device_unregister);
+EXPORT_SYMBOL(of_dev_get);
+EXPORT_SYMBOL(of_dev_put);
+EXPORT_SYMBOL(of_platform_device_create);
+EXPORT_SYMBOL(of_release_dev);
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index 9472580..6c9e3e9 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -22,6 +22,7 @@
#include <asm/irq.h>
#include <asm/ebus.h>
#include <asm/isa.h>
+#include <asm/prom.h>
unsigned long pci_memspace_mask = 0xffffffffUL;
@@ -177,16 +178,16 @@ void pci_config_write32(u32 *addr, u32 val)
}
/* Probe for all PCI controllers in the system. */
-extern void sabre_init(int, char *);
-extern void psycho_init(int, char *);
-extern void schizo_init(int, char *);
-extern void schizo_plus_init(int, char *);
-extern void tomatillo_init(int, char *);
-extern void sun4v_pci_init(int, char *);
+extern void sabre_init(struct device_node *, const char *);
+extern void psycho_init(struct device_node *, const char *);
+extern void schizo_init(struct device_node *, const char *);
+extern void schizo_plus_init(struct device_node *, const char *);
+extern void tomatillo_init(struct device_node *, const char *);
+extern void sun4v_pci_init(struct device_node *, const char *);
static struct {
char *model_name;
- void (*init)(int, char *);
+ void (*init)(struct device_node *, const char *);
} pci_controller_table[] __initdata = {
{ "SUNW,sabre", sabre_init },
{ "pci108e,a000", sabre_init },
@@ -204,7 +205,7 @@ static struct {
#define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \
sizeof(pci_controller_table[0]))
-static int __init pci_controller_init(char *model_name, int namelen, int node)
+static int __init pci_controller_init(const char *model_name, int namelen, struct device_node *dp)
{
int i;
@@ -212,18 +213,15 @@ static int __init pci_controller_init(char *model_name, int namelen, int node)
if (!strncmp(model_name,
pci_controller_table[i].model_name,
namelen)) {
- pci_controller_table[i].init(node, model_name);
+ pci_controller_table[i].init(dp, model_name);
return 1;
}
}
- printk("PCI: Warning unknown controller, model name [%s]\n",
- model_name);
- printk("PCI: Ignoring controller...\n");
return 0;
}
-static int __init pci_is_controller(char *model_name, int namelen, int node)
+static int __init pci_is_controller(const char *model_name, int namelen, struct device_node *dp)
{
int i;
@@ -237,36 +235,35 @@ static int __init pci_is_controller(char *model_name, int namelen, int node)
return 0;
}
-static int __init pci_controller_scan(int (*handler)(char *, int, int))
+static int __init pci_controller_scan(int (*handler)(const char *, int, struct device_node *))
{
- char namebuf[64];
- int node;
+ struct device_node *dp;
int count = 0;
- node = prom_getchild(prom_root_node);
- while ((node = prom_searchsiblings(node, "pci")) != 0) {
+ for_each_node_by_name(dp, "pci") {
+ struct property *prop;
int len;
- if ((len = prom_getproperty(node, "model", namebuf, sizeof(namebuf))) > 0 ||
- (len = prom_getproperty(node, "compatible", namebuf, sizeof(namebuf))) > 0) {
+ prop = of_find_property(dp, "model", &len);
+ if (!prop)
+ prop = of_find_property(dp, "compatible", &len);
+
+ if (prop) {
+ const char *model = prop->value;
int item_len = 0;
/* Our value may be a multi-valued string in the
* case of some compatible properties. For sanity,
- * only try the first one. */
-
- while (namebuf[item_len] && len) {
+ * only try the first one.
+ */
+ while (model[item_len] && len) {
len--;
item_len++;
}
- if (handler(namebuf, item_len, node))
+ if (handler(model, item_len, dp))
count++;
}
-
- node = prom_getsibling(node);
- if (!node)
- break;
}
return count;
@@ -409,8 +406,14 @@ void pcibios_bus_to_resource(struct pci_dev *pdev, struct resource *res,
}
EXPORT_SYMBOL(pcibios_bus_to_resource);
+extern int pci_irq_verbose;
+
char * __init pcibios_setup(char *str)
{
+ if (!strcmp(str, "irq_verbose")) {
+ pci_irq_verbose = 1;
+ return NULL;
+ }
return str;
}
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
index 33dedb1..b06a295 100644
--- a/arch/sparc64/kernel/pci_common.c
+++ b/arch/sparc64/kernel/pci_common.c
@@ -9,6 +9,12 @@
#include <linux/init.h>
#include <asm/pbm.h>
+#include <asm/prom.h>
+
+#include "pci_impl.h"
+
+/* Pass "pci=irq_verbose" on the kernel command line to enable this. */
+int pci_irq_verbose;
/* Fix self device of BUS and hook it into BUS->self.
* The pci_scan_bus does not do this for the host bridge.
@@ -28,16 +34,14 @@ void __init pci_fixup_host_bridge_self(struct pci_bus *pbus)
prom_halt();
}
-/* Find the OBP PROM device tree node for a PCI device.
- * Return zero if not found.
- */
-static int __init find_device_prom_node(struct pci_pbm_info *pbm,
- struct pci_dev *pdev,
- int bus_prom_node,
- struct linux_prom_pci_registers *pregs,
- int *nregs)
+/* Find the OBP PROM device tree node for a PCI device. */
+static struct device_node * __init
+find_device_prom_node(struct pci_pbm_info *pbm, struct pci_dev *pdev,
+ struct device_node *bus_node,
+ struct linux_prom_pci_registers **pregs,
+ int *nregs)
{
- int node;
+ struct device_node *dp;
*nregs = 0;
@@ -54,24 +58,30 @@ static int __init find_device_prom_node(struct pci_pbm_info *pbm,
pdev->device == PCI_DEVICE_ID_SUN_TOMATILLO ||
pdev->device == PCI_DEVICE_ID_SUN_SABRE ||
pdev->device == PCI_DEVICE_ID_SUN_HUMMINGBIRD))
- return bus_prom_node;
-
- node = prom_getchild(bus_prom_node);
- while (node != 0) {
- int err = prom_getproperty(node, "reg",
- (char *)pregs,
- sizeof(*pregs) * PROMREG_MAX);
- if (err == 0 || err == -1)
+ return bus_node;
+
+ dp = bus_node->child;
+ while (dp) {
+ struct linux_prom_pci_registers *regs;
+ struct property *prop;
+ int len;
+
+ prop = of_find_property(dp, "reg", &len);
+ if (!prop)
goto do_next_sibling;
- if (((pregs[0].phys_hi >> 8) & 0xff) == pdev->devfn) {
- *nregs = err / sizeof(*pregs);
- return node;
+
+ regs = prop->value;
+ if (((regs[0].phys_hi >> 8) & 0xff) == pdev->devfn) {
+ *pregs = regs;
+ *nregs = len / sizeof(struct linux_prom_pci_registers);
+ return dp;
}
do_next_sibling:
- node = prom_getsibling(node);
+ dp = dp->sibling;
}
- return 0;
+
+ return NULL;
}
/* Older versions of OBP on PCI systems encode 64-bit MEM
@@ -128,15 +138,17 @@ static void __init fixup_obp_assignments(struct pci_dev *pdev,
*/
static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm,
struct pci_dev *pdev,
- int bus_prom_node)
+ struct device_node *bus_node)
{
- struct linux_prom_pci_registers pregs[PROMREG_MAX];
+ struct linux_prom_pci_registers *pregs = NULL;
struct pcidev_cookie *pcp;
- int device_prom_node, nregs, err;
+ struct device_node *dp;
+ struct property *prop;
+ int nregs, len;
- device_prom_node = find_device_prom_node(pbm, pdev, bus_prom_node,
- pregs, &nregs);
- if (device_prom_node == 0) {
+ dp = find_device_prom_node(pbm, pdev, bus_node,
+ &pregs, &nregs);
+ if (!dp) {
/* If it is not in the OBP device tree then
* there must be a damn good reason for it.
*
@@ -150,45 +162,43 @@ static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm,
return;
}
- pcp = kmalloc(sizeof(*pcp), GFP_ATOMIC);
+ pcp = kzalloc(sizeof(*pcp), GFP_ATOMIC);
if (pcp == NULL) {
prom_printf("PCI_COOKIE: Fatal malloc error, aborting...\n");
prom_halt();
}
pcp->pbm = pbm;
- pcp->prom_node = device_prom_node;
- memcpy(pcp->prom_regs, pregs, sizeof(pcp->prom_regs));
+ pcp->prom_node = dp;
+ memcpy(pcp->prom_regs, pregs,
+ nregs * sizeof(struct linux_prom_pci_registers));
pcp->num_prom_regs = nregs;
- err = prom_getproperty(device_prom_node, "name",
- pcp->prom_name, sizeof(pcp->prom_name));
- if (err > 0)
- pcp->prom_name[err] = 0;
- else
- pcp->prom_name[0] = 0;
-
- err = prom_getproperty(device_prom_node,
- "assigned-addresses",
- (char *)pcp->prom_assignments,
- sizeof(pcp->prom_assignments));
- if (err == 0 || err == -1)
+
+ /* We can't have the pcidev_cookie assignments be just
+ * direct pointers into the property value, since they
+ * are potentially modified by the probing process.
+ */
+ prop = of_find_property(dp, "assigned-addresses", &len);
+ if (!prop) {
pcp->num_prom_assignments = 0;
- else
+ } else {
+ memcpy(pcp->prom_assignments, prop->value, len);
pcp->num_prom_assignments =
- (err / sizeof(pcp->prom_assignments[0]));
+ (len / sizeof(pcp->prom_assignments[0]));
+ }
- if (strcmp(pcp->prom_name, "ebus") == 0) {
- struct linux_prom_ebus_ranges erng[PROM_PCIRNG_MAX];
+ if (strcmp(dp->name, "ebus") == 0) {
+ struct linux_prom_ebus_ranges *erng;
int iter;
/* EBUS is special... */
- err = prom_getproperty(device_prom_node, "ranges",
- (char *)&erng[0], sizeof(erng));
- if (err == 0 || err == -1) {
+ prop = of_find_property(dp, "ranges", &len);
+ if (!prop) {
prom_printf("EBUS: Fatal error, no range property\n");
prom_halt();
}
- err = (err / sizeof(erng[0]));
- for(iter = 0; iter < err; iter++) {
+ erng = prop->value;
+ len = (len / sizeof(erng[0]));
+ for (iter = 0; iter < len; iter++) {
struct linux_prom_ebus_ranges *ep = &erng[iter];
struct linux_prom_pci_registers *ap;
@@ -200,7 +210,7 @@ static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm,
ap->size_hi = 0;
ap->size_lo = ep->size;
}
- pcp->num_prom_assignments = err;
+ pcp->num_prom_assignments = len;
}
fixup_obp_assignments(pdev, pcp);
@@ -210,7 +220,7 @@ static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm,
void __init pci_fill_in_pbm_cookies(struct pci_bus *pbus,
struct pci_pbm_info *pbm,
- int prom_node)
+ struct device_node *dp)
{
struct pci_dev *pdev, *pdev_next;
struct pci_bus *this_pbus, *pbus_next;
@@ -218,7 +228,7 @@ void __init pci_fill_in_pbm_cookies(struct pci_bus *pbus,
/* This must be _safe because the cookie fillin
routine can delete devices from the tree. */
list_for_each_entry_safe(pdev, pdev_next, &pbus->devices, bus_list)
- pdev_cookie_fillin(pbm, pdev, prom_node);
+ pdev_cookie_fillin(pbm, pdev, dp);
list_for_each_entry_safe(this_pbus, pbus_next, &pbus->children, node) {
struct pcidev_cookie *pcp = this_pbus->self->sysdata;
@@ -241,7 +251,6 @@ static void __init bad_assignment(struct pci_dev *pdev,
if (res)
prom_printf("PCI: RES[%016lx-->%016lx:(%lx)]\n",
res->start, res->end, res->flags);
- prom_printf("Please email this information to davem@redhat.com\n");
if (do_prom_halt)
prom_halt();
}
@@ -273,8 +282,7 @@ __init get_root_resource(struct linux_prom_pci_registers *ap,
return &pbm->mem_space;
default:
- printk("PCI: What is resource space %x? "
- "Tell davem@redhat.com about it!\n", space);
+ printk("PCI: What is resource space %x?\n", space);
return NULL;
};
}
@@ -556,9 +564,10 @@ static inline unsigned int pci_slot_swivel(struct pci_pbm_info *pbm,
ret = ((interrupt - 1 + (PCI_SLOT(pdev->devfn) & 3)) & 3) + 1;
- printk("%s: %s IRQ Swivel %s [%x:%x] -> [%x]\n",
- pbm->name, pci_name(toplevel_pdev), pci_name(pdev),
- interrupt, PCI_SLOT(pdev->devfn), ret);
+ if (pci_irq_verbose)
+ printk("%s: %s IRQ Swivel %s [%x:%x] -> [%x]\n",
+ pbm->name, pci_name(toplevel_pdev), pci_name(pdev),
+ interrupt, PCI_SLOT(pdev->devfn), ret);
return ret;
}
@@ -568,58 +577,60 @@ static inline unsigned int pci_apply_intmap(struct pci_pbm_info *pbm,
struct pci_dev *pbus,
struct pci_dev *pdev,
unsigned int interrupt,
- unsigned int *cnode)
+ struct device_node **cnode)
{
- struct linux_prom_pci_intmap imap[PROM_PCIIMAP_MAX];
- struct linux_prom_pci_intmask imask;
+ struct linux_prom_pci_intmap *imap;
+ struct linux_prom_pci_intmask *imask;
struct pcidev_cookie *pbus_pcp = pbus->sysdata;
struct pcidev_cookie *pdev_pcp = pdev->sysdata;
struct linux_prom_pci_registers *pregs = pdev_pcp->prom_regs;
+ struct property *prop;
int plen, num_imap, i;
unsigned int hi, mid, lo, irq, orig_interrupt;
*cnode = pbus_pcp->prom_node;
- plen = prom_getproperty(pbus_pcp->prom_node, "interrupt-map",
- (char *) &imap[0], sizeof(imap));
- if (plen <= 0 ||
+ prop = of_find_property(pbus_pcp->prom_node, "interrupt-map", &plen);
+ if (!prop ||
(plen % sizeof(struct linux_prom_pci_intmap)) != 0) {
printk("%s: Device %s interrupt-map has bad len %d\n",
pbm->name, pci_name(pbus), plen);
goto no_intmap;
}
+ imap = prop->value;
num_imap = plen / sizeof(struct linux_prom_pci_intmap);
- plen = prom_getproperty(pbus_pcp->prom_node, "interrupt-map-mask",
- (char *) &imask, sizeof(imask));
- if (plen <= 0 ||
+ prop = of_find_property(pbus_pcp->prom_node, "interrupt-map-mask", &plen);
+ if (!prop ||
(plen % sizeof(struct linux_prom_pci_intmask)) != 0) {
printk("%s: Device %s interrupt-map-mask has bad len %d\n",
pbm->name, pci_name(pbus), plen);
goto no_intmap;
}
+ imask = prop->value;
orig_interrupt = interrupt;
- hi = pregs->phys_hi & imask.phys_hi;
- mid = pregs->phys_mid & imask.phys_mid;
- lo = pregs->phys_lo & imask.phys_lo;
- irq = interrupt & imask.interrupt;
+ hi = pregs->phys_hi & imask->phys_hi;
+ mid = pregs->phys_mid & imask->phys_mid;
+ lo = pregs->phys_lo & imask->phys_lo;
+ irq = interrupt & imask->interrupt;
for (i = 0; i < num_imap; i++) {
if (imap[i].phys_hi == hi &&
imap[i].phys_mid == mid &&
imap[i].phys_lo == lo &&
imap[i].interrupt == irq) {
- *cnode = imap[i].cnode;
+ *cnode = of_find_node_by_phandle(imap[i].cnode);
interrupt = imap[i].cinterrupt;
}
}
- printk("%s: %s MAP BUS %s DEV %s [%x] -> [%x]\n",
- pbm->name, pci_name(toplevel_pdev),
- pci_name(pbus), pci_name(pdev),
- orig_interrupt, interrupt);
+ if (pci_irq_verbose)
+ printk("%s: %s MAP BUS %s DEV %s [%x] -> [%x]\n",
+ pbm->name, pci_name(toplevel_pdev),
+ pci_name(pbus), pci_name(pdev),
+ orig_interrupt, interrupt);
no_intmap:
return interrupt;
@@ -633,21 +644,22 @@ no_intmap:
* all interrupt translations are complete, else we should use that node's
* "reg" property to apply the PBM's "interrupt-{map,mask}" to the interrupt.
*/
-static unsigned int __init pci_intmap_match_to_root(struct pci_pbm_info *pbm,
- struct pci_dev *pdev,
- unsigned int *interrupt)
+static struct device_node * __init
+pci_intmap_match_to_root(struct pci_pbm_info *pbm,
+ struct pci_dev *pdev,
+ unsigned int *interrupt)
{
struct pci_dev *toplevel_pdev = pdev;
struct pcidev_cookie *toplevel_pcp = toplevel_pdev->sysdata;
- unsigned int cnode = toplevel_pcp->prom_node;
+ struct device_node *cnode = toplevel_pcp->prom_node;
while (pdev->bus->number != pbm->pci_first_busno) {
struct pci_dev *pbus = pdev->bus->self;
struct pcidev_cookie *pcp = pbus->sysdata;
- int plen;
+ struct property *prop;
- plen = prom_getproplen(pcp->prom_node, "interrupt-map");
- if (plen <= 0) {
+ prop = of_find_property(pcp->prom_node, "interrupt-map", NULL);
+ if (!prop) {
*interrupt = pci_slot_swivel(pbm, toplevel_pdev,
pdev, *interrupt);
cnode = pcp->prom_node;
@@ -675,26 +687,29 @@ static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt
{
struct pcidev_cookie *dev_pcp = pdev->sysdata;
struct pci_pbm_info *pbm = dev_pcp->pbm;
- struct linux_prom_pci_registers reg[PROMREG_MAX];
+ struct linux_prom_pci_registers *reg;
+ struct device_node *cnode;
+ struct property *prop;
unsigned int hi, mid, lo, irq;
- int i, cnode, plen;
+ int i, plen;
cnode = pci_intmap_match_to_root(pbm, pdev, interrupt);
if (cnode == pbm->prom_node)
goto success;
- plen = prom_getproperty(cnode, "reg", (char *) reg, sizeof(reg));
- if (plen <= 0 ||
+ prop = of_find_property(cnode, "reg", &plen);
+ if (!prop ||
(plen % sizeof(struct linux_prom_pci_registers)) != 0) {
- printk("%s: OBP node %x reg property has bad len %d\n",
- pbm->name, cnode, plen);
+ printk("%s: OBP node %s reg property has bad len %d\n",
+ pbm->name, cnode->full_name, plen);
goto fail;
}
+ reg = prop->value;
- hi = reg[0].phys_hi & pbm->pbm_intmask.phys_hi;
- mid = reg[0].phys_mid & pbm->pbm_intmask.phys_mid;
- lo = reg[0].phys_lo & pbm->pbm_intmask.phys_lo;
- irq = *interrupt & pbm->pbm_intmask.interrupt;
+ hi = reg[0].phys_hi & pbm->pbm_intmask->phys_hi;
+ mid = reg[0].phys_mid & pbm->pbm_intmask->phys_mid;
+ lo = reg[0].phys_lo & pbm->pbm_intmask->phys_lo;
+ irq = *interrupt & pbm->pbm_intmask->interrupt;
for (i = 0; i < pbm->num_pbm_intmap; i++) {
struct linux_prom_pci_intmap *intmap;
@@ -714,9 +729,11 @@ fail:
return 0;
success:
- printk("PCI-IRQ: Routing bus[%2x] slot[%2x] to INO[%02x]\n",
- pdev->bus->number, PCI_SLOT(pdev->devfn),
- *interrupt);
+ if (pci_irq_verbose)
+ printk("%s: Routing bus[%2x] slot[%2x] to INO[%02x]\n",
+ pbm->name,
+ pdev->bus->number, PCI_SLOT(pdev->devfn),
+ *interrupt);
return 1;
}
@@ -727,8 +744,8 @@ static void __init pdev_fixup_irq(struct pci_dev *pdev)
struct pci_controller_info *p = pbm->parent;
unsigned int portid = pbm->portid;
unsigned int prom_irq;
- int prom_node = pcp->prom_node;
- int err;
+ struct device_node *dp = pcp->prom_node;
+ struct property *prop;
/* If this is an empty EBUS device, sometimes OBP fails to
* give it a valid fully specified interrupts property.
@@ -739,17 +756,17 @@ static void __init pdev_fixup_irq(struct pci_dev *pdev)
*/
if (pdev->vendor == PCI_VENDOR_ID_SUN &&
pdev->device == PCI_DEVICE_ID_SUN_EBUS &&
- !prom_getchild(prom_node)) {
+ !dp->child) {
pdev->irq = 0;
return;
}
- err = prom_getproperty(prom_node, "interrupts",
- (char *)&prom_irq, sizeof(prom_irq));
- if (err == 0 || err == -1) {
+ prop = of_find_property(dp, "interrupts", NULL);
+ if (!prop) {
pdev->irq = 0;
return;
}
+ prom_irq = *(unsigned int *) prop->value;
if (tlb_type != hypervisor) {
/* Fully specified already? */
diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h
index 6c32059..971e2be 100644
--- a/arch/sparc64/kernel/pci_impl.h
+++ b/arch/sparc64/kernel/pci_impl.h
@@ -10,6 +10,7 @@
#include <linux/types.h>
#include <linux/spinlock.h>
#include <asm/io.h>
+#include <asm/prom.h>
extern struct pci_controller_info *pci_controller_root;
@@ -19,7 +20,7 @@ extern int pci_num_controllers;
extern void pci_fixup_host_bridge_self(struct pci_bus *pbus);
extern void pci_fill_in_pbm_cookies(struct pci_bus *pbus,
struct pci_pbm_info *pbm,
- int prom_node);
+ struct device_node *prom_node);
extern void pci_record_assignments(struct pci_pbm_info *pbm,
struct pci_bus *pbus);
extern void pci_assign_unassigned(struct pci_pbm_info *pbm,
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index 24db22a..5b2261e 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -17,6 +17,7 @@
#include <asm/iommu.h>
#include <asm/irq.h>
#include <asm/starfire.h>
+#include <asm/prom.h>
#include "pci_impl.h"
#include "iommu_common.h"
@@ -1291,11 +1292,12 @@ static void psycho_pbm_strbuf_init(struct pci_controller_info *p,
#define PSYCHO_MEMSPACE_SIZE 0x07fffffffUL
static void psycho_pbm_init(struct pci_controller_info *p,
- int prom_node, int is_pbm_a)
+ struct device_node *dp, int is_pbm_a)
{
- unsigned int busrange[2];
+ unsigned int *busrange;
+ struct property *prop;
struct pci_pbm_info *pbm;
- int err;
+ int len;
if (is_pbm_a) {
pbm = &p->pbm_A;
@@ -1310,10 +1312,14 @@ static void psycho_pbm_init(struct pci_controller_info *p,
}
pbm->chip_type = PBM_CHIP_TYPE_PSYCHO;
- pbm->chip_version =
- prom_getintdefault(prom_node, "version#", 0);
- pbm->chip_revision =
- prom_getintdefault(prom_node, "module-revision#", 0);
+ pbm->chip_version = 0;
+ prop = of_find_property(dp, "version#", NULL);
+ if (prop)
+ pbm->chip_version = *(int *) prop->value;
+ pbm->chip_revision = 0;
+ prop = of_find_property(dp, "module-revision#", NULL);
+ if (prop)
+ pbm->chip_revision = *(int *) prop->value;
pbm->io_space.end = pbm->io_space.start + PSYCHO_IOSPACE_SIZE;
pbm->io_space.flags = IORESOURCE_IO;
@@ -1322,45 +1328,36 @@ static void psycho_pbm_init(struct pci_controller_info *p,
pbm_register_toplevel_resources(p, pbm);
pbm->parent = p;
- pbm->prom_node = prom_node;
- prom_getstring(prom_node, "name",
- pbm->prom_name,
- sizeof(pbm->prom_name));
-
- err = prom_getproperty(prom_node, "ranges",
- (char *)pbm->pbm_ranges,
- sizeof(pbm->pbm_ranges));
- if (err != -1)
+ pbm->prom_node = dp;
+ pbm->name = dp->full_name;
+
+ printk("%s: PSYCHO PCI Bus Module ver[%x:%x]\n",
+ pbm->name,
+ pbm->chip_version, pbm->chip_revision);
+
+ prop = of_find_property(dp, "ranges", &len);
+ if (prop) {
+ pbm->pbm_ranges = prop->value;
pbm->num_pbm_ranges =
- (err / sizeof(struct linux_prom_pci_ranges));
- else
+ (len / sizeof(struct linux_prom_pci_ranges));
+ } else {
pbm->num_pbm_ranges = 0;
+ }
- err = prom_getproperty(prom_node, "interrupt-map",
- (char *)pbm->pbm_intmap,
- sizeof(pbm->pbm_intmap));
- if (err != -1) {
- pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap));
- err = prom_getproperty(prom_node, "interrupt-map-mask",
- (char *)&pbm->pbm_intmask,
- sizeof(pbm->pbm_intmask));
- if (err == -1) {
- prom_printf("PSYCHO-PBM: Fatal error, no "
- "interrupt-map-mask.\n");
- prom_halt();
- }
+ prop = of_find_property(dp, "interrupt-map", &len);
+ if (prop) {
+ pbm->pbm_intmap = prop->value;
+ pbm->num_pbm_intmap =
+ (len / sizeof(struct linux_prom_pci_intmap));
+
+ prop = of_find_property(dp, "interrupt-map-mask", NULL);
+ pbm->pbm_intmask = prop->value;
} else {
pbm->num_pbm_intmap = 0;
- memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask));
}
- err = prom_getproperty(prom_node, "bus-range",
- (char *)&busrange[0],
- sizeof(busrange));
- if (err == 0 || err == -1) {
- prom_printf("PSYCHO-PBM: Fatal error, no bus-range.\n");
- prom_halt();
- }
+ prop = of_find_property(dp, "bus-range", NULL);
+ busrange = prop->value;
pbm->pci_first_busno = busrange[0];
pbm->pci_last_busno = busrange[1];
@@ -1369,20 +1366,24 @@ static void psycho_pbm_init(struct pci_controller_info *p,
#define PSYCHO_CONFIGSPACE 0x001000000UL
-void psycho_init(int node, char *model_name)
+void psycho_init(struct device_node *dp, char *model_name)
{
- struct linux_prom64_registers pr_regs[3];
+ struct linux_prom64_registers *pr_regs;
struct pci_controller_info *p;
struct pci_iommu *iommu;
+ struct property *prop;
u32 upa_portid;
- int is_pbm_a, err;
+ int is_pbm_a;
- upa_portid = prom_getintdefault(node, "upa-portid", 0xff);
+ upa_portid = 0xff;
+ prop = of_find_property(dp, "upa-portid", NULL);
+ if (prop)
+ upa_portid = *(u32 *) prop->value;
for(p = pci_controller_root; p; p = p->next) {
if (p->pbm_A.portid == upa_portid) {
- is_pbm_a = (p->pbm_A.prom_node == 0);
- psycho_pbm_init(p, node, is_pbm_a);
+ is_pbm_a = (p->pbm_A.prom_node == NULL);
+ psycho_pbm_init(p, dp, is_pbm_a);
return;
}
}
@@ -1412,23 +1413,14 @@ void psycho_init(int node, char *model_name)
p->resource_adjust = psycho_resource_adjust;
p->pci_ops = &psycho_ops;
- err = prom_getproperty(node, "reg",
- (char *)&pr_regs[0],
- sizeof(pr_regs));
- if (err == 0 || err == -1) {
- prom_printf("PSYCHO: Fatal error, no reg property.\n");
- prom_halt();
- }
+ prop = of_find_property(dp, "reg", NULL);
+ pr_regs = prop->value;
p->pbm_A.controller_regs = pr_regs[2].phys_addr;
p->pbm_B.controller_regs = pr_regs[2].phys_addr;
- printk("PCI: Found PSYCHO, control regs at %016lx\n",
- p->pbm_A.controller_regs);
p->pbm_A.config_space = p->pbm_B.config_space =
(pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
- printk("PSYCHO: Shared PCI config space at %016lx\n",
- p->pbm_A.config_space);
/*
* Psycho's PCI MEM space is mapped to a 2GB aligned area, so
@@ -1441,5 +1433,5 @@ void psycho_init(int node, char *model_name)
psycho_iommu_init(p);
is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
- psycho_pbm_init(p, node, is_pbm_a);
+ psycho_pbm_init(p, dp, is_pbm_a);
}
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index b7d997b..26f194c 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -19,6 +19,7 @@
#include <asm/irq.h>
#include <asm/smp.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
#include "pci_impl.h"
#include "iommu_common.h"
@@ -1306,34 +1307,36 @@ static void pbm_register_toplevel_resources(struct pci_controller_info *p,
&pbm->mem_space);
}
-static void sabre_pbm_init(struct pci_controller_info *p, int sabre_node, u32 dma_begin)
+static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_begin)
{
struct pci_pbm_info *pbm;
- char namebuf[128];
- u32 busrange[2];
- int node, simbas_found;
+ struct device_node *node;
+ struct property *prop;
+ u32 *busrange;
+ int len, simbas_found;
simbas_found = 0;
- node = prom_getchild(sabre_node);
- while ((node = prom_searchsiblings(node, "pci")) != 0) {
- int err;
-
- err = prom_getproperty(node, "model", namebuf, sizeof(namebuf));
- if ((err <= 0) || strncmp(namebuf, "SUNW,simba", err))
+ node = dp->child;
+ while (node != NULL) {
+ if (strcmp(node->name, "pci"))
goto next_pci;
- err = prom_getproperty(node, "bus-range",
- (char *)&busrange[0], sizeof(busrange));
- if (err == 0 || err == -1) {
- prom_printf("APB: Error, cannot get PCI bus-range.\n");
- prom_halt();
- }
+ prop = of_find_property(node, "model", NULL);
+ if (!prop || strncmp(prop->value, "SUNW,simba", prop->length))
+ goto next_pci;
simbas_found++;
+
+ prop = of_find_property(node, "bus-range", NULL);
+ busrange = prop->value;
if (busrange[0] == 1)
pbm = &p->pbm_B;
else
pbm = &p->pbm_A;
+
+ pbm->name = node->full_name;
+ printk("%s: SABRE PCI Bus Module\n", pbm->name);
+
pbm->chip_type = PBM_CHIP_TYPE_SABRE;
pbm->parent = p;
pbm->prom_node = node;
@@ -1341,83 +1344,68 @@ static void sabre_pbm_init(struct pci_controller_info *p, int sabre_node, u32 dm
pbm->pci_first_busno = busrange[0];
pbm->pci_last_busno = busrange[1];
- prom_getstring(node, "name", pbm->prom_name, sizeof(pbm->prom_name));
- err = prom_getproperty(node, "ranges",
- (char *)pbm->pbm_ranges,
- sizeof(pbm->pbm_ranges));
- if (err != -1)
+ prop = of_find_property(node, "ranges", &len);
+ if (prop) {
+ pbm->pbm_ranges = prop->value;
pbm->num_pbm_ranges =
- (err / sizeof(struct linux_prom_pci_ranges));
- else
+ (len / sizeof(struct linux_prom_pci_ranges));
+ } else {
pbm->num_pbm_ranges = 0;
+ }
- err = prom_getproperty(node, "interrupt-map",
- (char *)pbm->pbm_intmap,
- sizeof(pbm->pbm_intmap));
- if (err != -1) {
- pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap));
- err = prom_getproperty(node, "interrupt-map-mask",
- (char *)&pbm->pbm_intmask,
- sizeof(pbm->pbm_intmask));
- if (err == -1) {
- prom_printf("APB: Fatal error, no interrupt-map-mask.\n");
- prom_halt();
- }
+ prop = of_find_property(node, "interrupt-map", &len);
+ if (prop) {
+ pbm->pbm_intmap = prop->value;
+ pbm->num_pbm_intmap =
+ (len / sizeof(struct linux_prom_pci_intmap));
+
+ prop = of_find_property(node, "interrupt-map-mask",
+ NULL);
+ pbm->pbm_intmask = prop->value;
} else {
pbm->num_pbm_intmap = 0;
- memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask));
}
pbm_register_toplevel_resources(p, pbm);
next_pci:
- node = prom_getsibling(node);
- if (!node)
- break;
+ node = node->sibling;
}
if (simbas_found == 0) {
- int err;
-
/* No APBs underneath, probably this is a hummingbird
* system.
*/
pbm = &p->pbm_A;
pbm->parent = p;
- pbm->prom_node = sabre_node;
+ pbm->prom_node = dp;
pbm->pci_first_busno = p->pci_first_busno;
pbm->pci_last_busno = p->pci_last_busno;
- prom_getstring(sabre_node, "name", pbm->prom_name, sizeof(pbm->prom_name));
- err = prom_getproperty(sabre_node, "ranges",
- (char *) pbm->pbm_ranges,
- sizeof(pbm->pbm_ranges));
- if (err != -1)
+ prop = of_find_property(dp, "ranges", &len);
+ if (prop) {
+ pbm->pbm_ranges = prop->value;
pbm->num_pbm_ranges =
- (err / sizeof(struct linux_prom_pci_ranges));
- else
+ (len / sizeof(struct linux_prom_pci_ranges));
+ } else {
pbm->num_pbm_ranges = 0;
+ }
- err = prom_getproperty(sabre_node, "interrupt-map",
- (char *) pbm->pbm_intmap,
- sizeof(pbm->pbm_intmap));
-
- if (err != -1) {
- pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap));
- err = prom_getproperty(sabre_node, "interrupt-map-mask",
- (char *)&pbm->pbm_intmask,
- sizeof(pbm->pbm_intmask));
- if (err == -1) {
- prom_printf("Hummingbird: Fatal error, no interrupt-map-mask.\n");
- prom_halt();
- }
+ prop = of_find_property(dp, "interrupt-map", &len);
+ if (prop) {
+ pbm->pbm_intmap = prop->value;
+ pbm->num_pbm_intmap =
+ (len / sizeof(struct linux_prom_pci_intmap));
+
+ prop = of_find_property(dp, "interrupt-map-mask",
+ NULL);
+ pbm->pbm_intmask = prop->value;
} else {
pbm->num_pbm_intmap = 0;
- memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask));
}
+ pbm->name = dp->full_name;
+ printk("%s: SABRE PCI Bus Module\n", pbm->name);
- sprintf(pbm->name, "SABRE%d PBM%c", p->index,
- (pbm == &p->pbm_A ? 'A' : 'B'));
pbm->io_space.name = pbm->mem_space.name = pbm->name;
/* Hack up top-level resources. */
@@ -1443,14 +1431,15 @@ static void sabre_pbm_init(struct pci_controller_info *p, int sabre_node, u32 dm
}
}
-void sabre_init(int pnode, char *model_name)
+void sabre_init(struct device_node *dp, char *model_name)
{
- struct linux_prom64_registers pr_regs[2];
+ struct linux_prom64_registers *pr_regs;
struct pci_controller_info *p;
struct pci_iommu *iommu;
- int tsbsize, err;
- u32 busrange[2];
- u32 vdma[2];
+ struct property *prop;
+ int tsbsize;
+ u32 *busrange;
+ u32 *vdma;
u32 upa_portid, dma_mask;
u64 clear_irq;
@@ -1458,22 +1447,21 @@ void sabre_init(int pnode, char *model_name)
if (!strcmp(model_name, "pci108e,a001"))
hummingbird_p = 1;
else if (!strcmp(model_name, "SUNW,sabre")) {
- char compat[64];
+ prop = of_find_property(dp, "compatible", NULL);
+ if (prop) {
+ const char *compat = prop->value;
- if (prom_getproperty(pnode, "compatible",
- compat, sizeof(compat)) > 0 &&
- !strcmp(compat, "pci108e,a001")) {
- hummingbird_p = 1;
- } else {
- int cpu_node;
+ if (!strcmp(compat, "pci108e,a001"))
+ hummingbird_p = 1;
+ }
+ if (!hummingbird_p) {
+ struct device_node *dp;
/* Of course, Sun has to encode things a thousand
* different ways, inconsistently.
*/
- cpu_find_by_instance(0, &cpu_node, NULL);
- if (prom_getproperty(cpu_node, "name",
- compat, sizeof(compat)) > 0 &&
- !strcmp(compat, "SUNW,UltraSPARC-IIe"))
+ cpu_find_by_instance(0, &dp, NULL);
+ if (!strcmp(dp->name, "SUNW,UltraSPARC-IIe"))
hummingbird_p = 1;
}
}
@@ -1491,7 +1479,10 @@ void sabre_init(int pnode, char *model_name)
}
p->pbm_A.iommu = p->pbm_B.iommu = iommu;
- upa_portid = prom_getintdefault(pnode, "upa-portid", 0xff);
+ upa_portid = 0xff;
+ prop = of_find_property(dp, "upa-portid", NULL);
+ if (prop)
+ upa_portid = *(u32 *) prop->value;
p->next = pci_controller_root;
pci_controller_root = p;
@@ -1509,13 +1500,9 @@ void sabre_init(int pnode, char *model_name)
/*
* Map in SABRE register set and report the presence of this SABRE.
*/
- err = prom_getproperty(pnode, "reg",
- (char *)&pr_regs[0], sizeof(pr_regs));
- if(err == 0 || err == -1) {
- prom_printf("SABRE: Error, cannot get U2P registers "
- "from PROM.\n");
- prom_halt();
- }
+
+ prop = of_find_property(dp, "reg", NULL);
+ pr_regs = prop->value;
/*
* First REG in property is base of entire SABRE register space.
@@ -1523,9 +1510,6 @@ void sabre_init(int pnode, char *model_name)
p->pbm_A.controller_regs = pr_regs[0].phys_addr;
p->pbm_B.controller_regs = pr_regs[0].phys_addr;
- printk("PCI: Found SABRE, main regs at %016lx\n",
- p->pbm_A.controller_regs);
-
/* Clear interrupts */
/* PCI first */
@@ -1544,16 +1528,9 @@ void sabre_init(int pnode, char *model_name)
/* Now map in PCI config space for entire SABRE. */
p->pbm_A.config_space = p->pbm_B.config_space =
(p->pbm_A.controller_regs + SABRE_CONFIGSPACE);
- printk("SABRE: Shared PCI config space at %016lx\n",
- p->pbm_A.config_space);
-
- err = prom_getproperty(pnode, "virtual-dma",
- (char *)&vdma[0], sizeof(vdma));
- if(err == 0 || err == -1) {
- prom_printf("SABRE: Error, cannot get virtual-dma property "
- "from PROM.\n");
- prom_halt();
- }
+
+ prop = of_find_property(dp, "virtual-dma", NULL);
+ vdma = prop->value;
dma_mask = vdma[0];
switch(vdma[1]) {
@@ -1577,21 +1554,13 @@ void sabre_init(int pnode, char *model_name)
sabre_iommu_init(p, tsbsize, vdma[0], dma_mask);
- printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]);
-
- err = prom_getproperty(pnode, "bus-range",
- (char *)&busrange[0], sizeof(busrange));
- if(err == 0 || err == -1) {
- prom_printf("SABRE: Error, cannot get PCI bus-range "
- " from PROM.\n");
- prom_halt();
- }
-
+ prop = of_find_property(dp, "bus-range", NULL);
+ busrange = prop->value;
p->pci_first_busno = busrange[0];
p->pci_last_busno = busrange[1];
/*
* Look for APB underneath.
*/
- sabre_pbm_init(p, pnode, vdma[0]);
+ sabre_pbm_init(p, dp, vdma[0]);
}
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
index cc662e9..f16449c 100644
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/arch/sparc64/kernel/pci_schizo.c
@@ -16,6 +16,7 @@
#include <asm/irq.h>
#include <asm/upa.h>
#include <asm/pstate.h>
+#include <asm/prom.h>
#include "pci_impl.h"
#include "iommu_common.h"
@@ -1456,10 +1457,12 @@ static void __schizo_scan_bus(struct pci_controller_info *p,
pbm_config_busmastering(&p->pbm_B);
p->pbm_B.is_66mhz_capable =
- prom_getbool(p->pbm_B.prom_node, "66mhz-capable");
+ (of_find_property(p->pbm_B.prom_node, "66mhz-capable", NULL)
+ != NULL);
pbm_config_busmastering(&p->pbm_A);
p->pbm_A.is_66mhz_capable =
- prom_getbool(p->pbm_A.prom_node, "66mhz-capable");
+ (of_find_property(p->pbm_A.prom_node, "66mhz-capable", NULL)
+ != NULL);
pbm_scan_bus(p, &p->pbm_B);
pbm_scan_bus(p, &p->pbm_A);
@@ -1661,13 +1664,18 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
{
struct pci_iommu *iommu = pbm->iommu;
unsigned long i, tagbase, database;
+ struct property *prop;
u32 vdma[2], dma_mask;
u64 control;
- int err, tsbsize;
+ int tsbsize;
- err = prom_getproperty(pbm->prom_node, "virtual-dma",
- (char *)&vdma[0], sizeof(vdma));
- if (err == 0 || err == -1) {
+ prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
+ if (prop) {
+ u32 *val = prop->value;
+
+ vdma[0] = val[0];
+ vdma[1] = val[1];
+ } else {
/* No property, use default values. */
vdma[0] = 0xc0000000;
vdma[1] = 0x40000000;
@@ -1778,6 +1786,7 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
{
+ struct property *prop;
u64 tmp;
schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY, 5);
@@ -1791,7 +1800,8 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
pbm->chip_version >= 0x2)
tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT;
- if (!prom_getbool(pbm->prom_node, "no-bus-parking"))
+ prop = of_find_property(pbm->prom_node, "no-bus-parking", NULL);
+ if (!prop)
tmp |= SCHIZO_PCICTRL_PARK;
else
tmp &= ~SCHIZO_PCICTRL_PARK;
@@ -1831,16 +1841,17 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
}
static void schizo_pbm_init(struct pci_controller_info *p,
- int prom_node, u32 portid,
+ struct device_node *dp, u32 portid,
int chip_type)
{
- struct linux_prom64_registers pr_regs[4];
- unsigned int busrange[2];
+ struct linux_prom64_registers *regs;
+ struct property *prop;
+ unsigned int *busrange;
struct pci_pbm_info *pbm;
const char *chipset_name;
- u32 ino_bitmap[2];
+ u32 *ino_bitmap;
int is_pbm_a;
- int err;
+ int len;
switch (chip_type) {
case PBM_CHIP_TYPE_TOMATILLO:
@@ -1868,16 +1879,10 @@ static void schizo_pbm_init(struct pci_controller_info *p,
* 3) PBM PCI config space
* 4) Ichip regs
*/
- err = prom_getproperty(prom_node, "reg",
- (char *)&pr_regs[0],
- sizeof(pr_regs));
- if (err == 0 || err == -1) {
- prom_printf("%s: Fatal error, no reg property.\n",
- chipset_name);
- prom_halt();
- }
+ prop = of_find_property(dp, "reg", NULL);
+ regs = prop->value;
- is_pbm_a = ((pr_regs[0].phys_addr & 0x00700000) == 0x00600000);
+ is_pbm_a = ((regs[0].phys_addr & 0x00700000) == 0x00600000);
if (is_pbm_a)
pbm = &p->pbm_A;
@@ -1886,92 +1891,62 @@ static void schizo_pbm_init(struct pci_controller_info *p,
pbm->portid = portid;
pbm->parent = p;
- pbm->prom_node = prom_node;
+ pbm->prom_node = dp;
pbm->pci_first_slot = 1;
pbm->chip_type = chip_type;
- pbm->chip_version =
- prom_getintdefault(prom_node, "version#", 0);
- pbm->chip_revision =
- prom_getintdefault(prom_node, "module-revision#", 0);
-
- pbm->pbm_regs = pr_regs[0].phys_addr;
- pbm->controller_regs = pr_regs[1].phys_addr - 0x10000UL;
+ pbm->chip_version = 0;
+ prop = of_find_property(dp, "version#", NULL);
+ if (prop)
+ pbm->chip_version = *(int *) prop->value;
+ pbm->chip_revision = 0;
+ prop = of_find_property(dp, "module-revision#", NULL);
+ if (prop)
+ pbm->chip_revision = *(int *) prop->value;
+
+ pbm->pbm_regs = regs[0].phys_addr;
+ pbm->controller_regs = regs[1].phys_addr - 0x10000UL;
if (chip_type == PBM_CHIP_TYPE_TOMATILLO)
- pbm->sync_reg = pr_regs[3].phys_addr + 0x1a18UL;
+ pbm->sync_reg = regs[3].phys_addr + 0x1a18UL;
- sprintf(pbm->name,
- (chip_type == PBM_CHIP_TYPE_TOMATILLO ?
- "TOMATILLO%d PBM%c" :
- "SCHIZO%d PBM%c"),
- p->index,
- (pbm == &p->pbm_A ? 'A' : 'B'));
+ pbm->name = dp->full_name;
- printk("%s: ver[%x:%x], portid %x, "
- "cregs[%lx] pregs[%lx]\n",
+ printk("%s: %s PCI Bus Module ver[%x:%x]\n",
pbm->name,
- pbm->chip_version, pbm->chip_revision,
- pbm->portid,
- pbm->controller_regs,
- pbm->pbm_regs);
+ (chip_type == PBM_CHIP_TYPE_TOMATILLO ?
+ "TOMATILLO" : "SCHIZO"),
+ pbm->chip_version, pbm->chip_revision);
schizo_pbm_hw_init(pbm);
- prom_getstring(prom_node, "name",
- pbm->prom_name,
- sizeof(pbm->prom_name));
-
- err = prom_getproperty(prom_node, "ranges",
- (char *) pbm->pbm_ranges,
- sizeof(pbm->pbm_ranges));
- if (err == 0 || err == -1) {
- prom_printf("%s: Fatal error, no ranges property.\n",
- pbm->name);
- prom_halt();
- }
-
+ prop = of_find_property(dp, "ranges", &len);
+ pbm->pbm_ranges = prop->value;
pbm->num_pbm_ranges =
- (err / sizeof(struct linux_prom_pci_ranges));
+ (len / sizeof(struct linux_prom_pci_ranges));
schizo_determine_mem_io_space(pbm);
pbm_register_toplevel_resources(p, pbm);
- err = prom_getproperty(prom_node, "interrupt-map",
- (char *)pbm->pbm_intmap,
- sizeof(pbm->pbm_intmap));
- if (err != -1) {
- pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap));
- err = prom_getproperty(prom_node, "interrupt-map-mask",
- (char *)&pbm->pbm_intmask,
- sizeof(pbm->pbm_intmask));
- if (err == -1) {
- prom_printf("%s: Fatal error, no "
- "interrupt-map-mask.\n", pbm->name);
- prom_halt();
- }
+ prop = of_find_property(dp, "interrupt-map", &len);
+ if (prop) {
+ pbm->pbm_intmap = prop->value;
+ pbm->num_pbm_intmap =
+ (len / sizeof(struct linux_prom_pci_intmap));
+
+ prop = of_find_property(dp, "interrupt-map-mask", NULL);
+ pbm->pbm_intmask = prop->value;
} else {
pbm->num_pbm_intmap = 0;
- memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask));
}
- err = prom_getproperty(prom_node, "ino-bitmap",
- (char *) &ino_bitmap[0],
- sizeof(ino_bitmap));
- if (err == 0 || err == -1) {
- prom_printf("%s: Fatal error, no ino-bitmap.\n", pbm->name);
- prom_halt();
- }
+ prop = of_find_property(dp, "ino-bitmap", NULL);
+ ino_bitmap = prop->value;
pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) |
((u64)ino_bitmap[0] << 0UL));
- err = prom_getproperty(prom_node, "bus-range",
- (char *)&busrange[0],
- sizeof(busrange));
- if (err == 0 || err == -1) {
- prom_printf("%s: Fatal error, no bus-range.\n", pbm->name);
- prom_halt();
- }
+ prop = of_find_property(dp, "bus-range", NULL);
+ busrange = prop->value;
pbm->pci_first_busno = busrange[0];
pbm->pci_last_busno = busrange[1];
@@ -1989,16 +1964,20 @@ static inline int portid_compare(u32 x, u32 y, int chip_type)
return (x == y);
}
-static void __schizo_init(int node, char *model_name, int chip_type)
+static void __schizo_init(struct device_node *dp, char *model_name, int chip_type)
{
struct pci_controller_info *p;
struct pci_iommu *iommu;
+ struct property *prop;
int is_pbm_a;
u32 portid;
- portid = prom_getintdefault(node, "portid", 0xff);
+ portid = 0xff;
+ prop = of_find_property(dp, "portid", NULL);
+ if (prop)
+ portid = *(u32 *) prop->value;
- for(p = pci_controller_root; p; p = p->next) {
+ for (p = pci_controller_root; p; p = p->next) {
struct pci_pbm_info *pbm;
if (p->pbm_A.prom_node && p->pbm_B.prom_node)
@@ -2009,8 +1988,8 @@ static void __schizo_init(int node, char *model_name, int chip_type)
&p->pbm_B);
if (portid_compare(pbm->portid, portid, chip_type)) {
- is_pbm_a = (p->pbm_A.prom_node == 0);
- schizo_pbm_init(p, node, portid, chip_type);
+ is_pbm_a = (p->pbm_A.prom_node == NULL);
+ schizo_pbm_init(p, dp, portid, chip_type);
return;
}
}
@@ -2051,20 +2030,20 @@ static void __schizo_init(int node, char *model_name, int chip_type)
/* Like PSYCHO we have a 2GB aligned area for memory space. */
pci_memspace_mask = 0x7fffffffUL;
- schizo_pbm_init(p, node, portid, chip_type);
+ schizo_pbm_init(p, dp, portid, chip_type);
}
-void schizo_init(int node, char *model_name)
+void schizo_init(struct device_node *dp, char *model_name)
{
- __schizo_init(node, model_name, PBM_CHIP_TYPE_SCHIZO);
+ __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO);
}
-void schizo_plus_init(int node, char *model_name)
+void schizo_plus_init(struct device_node *dp, char *model_name)
{
- __schizo_init(node, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS);
+ __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS);
}
-void tomatillo_init(int node, char *model_name)
+void tomatillo_init(struct device_node *dp, char *model_name)
{
- __schizo_init(node, model_name, PBM_CHIP_TYPE_TOMATILLO);
+ __schizo_init(dp, model_name, PBM_CHIP_TYPE_TOMATILLO);
}
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index 5419480..b69e227 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -18,6 +18,7 @@
#include <asm/pstate.h>
#include <asm/oplib.h>
#include <asm/hypervisor.h>
+#include <asm/prom.h>
#include "pci_impl.h"
#include "iommu_common.h"
@@ -646,35 +647,37 @@ static int pdev_htab_add(u32 devhandle, unsigned int bus, unsigned int device, u
/* Recursively descend into the OBP device tree, rooted at toplevel_node,
* looking for a PCI device matching bus and devfn.
*/
-static int obp_find(struct linux_prom_pci_registers *pregs, int toplevel_node, unsigned int bus, unsigned int devfn)
+static int obp_find(struct device_node *toplevel_node, unsigned int bus, unsigned int devfn)
{
- toplevel_node = prom_getchild(toplevel_node);
+ toplevel_node = toplevel_node->child;
- while (toplevel_node != 0) {
- int ret = obp_find(pregs, toplevel_node, bus, devfn);
+ while (toplevel_node != NULL) {
+ struct linux_prom_pci_registers *regs;
+ struct property *prop;
+ int ret;
+ ret = obp_find(toplevel_node, bus, devfn);
if (ret != 0)
return ret;
- ret = prom_getproperty(toplevel_node, "reg", (char *) pregs,
- sizeof(*pregs) * PROMREG_MAX);
- if (ret == 0 || ret == -1)
+ prop = of_find_property(toplevel_node, "reg", NULL);
+ if (!prop)
goto next_sibling;
- if (((pregs[0].phys_hi >> 16) & 0xff) == bus &&
- ((pregs[0].phys_hi >> 8) & 0xff) == devfn)
+ regs = prop->value;
+ if (((regs->phys_hi >> 16) & 0xff) == bus &&
+ ((regs->phys_hi >> 8) & 0xff) == devfn)
break;
next_sibling:
- toplevel_node = prom_getsibling(toplevel_node);
+ toplevel_node = toplevel_node->sibling;
}
- return toplevel_node;
+ return toplevel_node != NULL;
}
static int pdev_htab_populate(struct pci_pbm_info *pbm)
{
- struct linux_prom_pci_registers pr[PROMREG_MAX];
u32 devhandle = pbm->devhandle;
unsigned int bus;
@@ -685,7 +688,7 @@ static int pdev_htab_populate(struct pci_pbm_info *pbm)
unsigned int device = PCI_SLOT(devfn);
unsigned int func = PCI_FUNC(devfn);
- if (obp_find(pr, pbm->prom_node, bus, devfn)) {
+ if (obp_find(pbm->prom_node, bus, devfn)) {
int err = pdev_htab_add(devhandle, bus,
device, func);
if (err)
@@ -811,8 +814,7 @@ static void pbm_scan_bus(struct pci_controller_info *p,
pci_fixup_host_bridge_self(pbm->pci_bus);
pbm->pci_bus->self->sysdata = cookie;
#endif
- pci_fill_in_pbm_cookies(pbm->pci_bus, pbm,
- pbm->prom_node);
+ pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node);
pci_record_assignments(pbm, pbm->pci_bus);
pci_assign_unassigned(pbm, pbm->pci_bus);
pci_fixup_irq(pbm, pbm->pci_bus);
@@ -822,15 +824,18 @@ static void pbm_scan_bus(struct pci_controller_info *p,
static void pci_sun4v_scan_bus(struct pci_controller_info *p)
{
- if (p->pbm_A.prom_node) {
- p->pbm_A.is_66mhz_capable =
- prom_getbool(p->pbm_A.prom_node, "66mhz-capable");
+ struct property *prop;
+ struct device_node *dp;
+
+ if ((dp = p->pbm_A.prom_node) != NULL) {
+ prop = of_find_property(dp, "66mhz-capable", NULL);
+ p->pbm_A.is_66mhz_capable = (prop != NULL);
pbm_scan_bus(p, &p->pbm_A);
}
- if (p->pbm_B.prom_node) {
- p->pbm_B.is_66mhz_capable =
- prom_getbool(p->pbm_B.prom_node, "66mhz-capable");
+ if ((dp = p->pbm_B.prom_node) != NULL) {
+ prop = of_find_property(dp, "66mhz-capable", NULL);
+ p->pbm_B.is_66mhz_capable = (prop != NULL);
pbm_scan_bus(p, &p->pbm_B);
}
@@ -982,8 +987,13 @@ static unsigned long probe_existing_entries(struct pci_pbm_info *pbm,
HV_PCI_TSBID(0, i),
&io_attrs, &ra);
if (ret == HV_EOK) {
- cnt++;
- __set_bit(i, arena->map);
+ if (page_in_phys_avail(ra)) {
+ pci_sun4v_iommu_demap(devhandle,
+ HV_PCI_TSBID(0, i), 1);
+ } else {
+ cnt++;
+ __set_bit(i, arena->map);
+ }
}
}
@@ -993,13 +1003,18 @@ static unsigned long probe_existing_entries(struct pci_pbm_info *pbm,
static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
{
struct pci_iommu *iommu = pbm->iommu;
+ struct property *prop;
unsigned long num_tsb_entries, sz;
u32 vdma[2], dma_mask, dma_offset;
- int err, tsbsize;
+ int tsbsize;
+
+ prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
+ if (prop) {
+ u32 *val = prop->value;
- err = prom_getproperty(pbm->prom_node, "virtual-dma",
- (char *)&vdma[0], sizeof(vdma));
- if (err == 0 || err == -1) {
+ vdma[0] = val[0];
+ vdma[1] = val[1];
+ } else {
/* No property, use default values. */
vdma[0] = 0x80000000;
vdma[1] = 0x80000000;
@@ -1051,34 +1066,30 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
iommu->arena.limit = num_tsb_entries;
sz = probe_existing_entries(pbm, iommu);
-
- printk("%s: TSB entries [%lu], existing mapings [%lu]\n",
- pbm->name, num_tsb_entries, sz);
+ if (sz)
+ printk("%s: Imported %lu TSB entries from OBP\n",
+ pbm->name, sz);
}
static void pci_sun4v_get_bus_range(struct pci_pbm_info *pbm)
{
- unsigned int busrange[2];
- int prom_node = pbm->prom_node;
- int err;
-
- err = prom_getproperty(prom_node, "bus-range",
- (char *)&busrange[0],
- sizeof(busrange));
- if (err == 0 || err == -1) {
- prom_printf("%s: Fatal error, no bus-range.\n", pbm->name);
- prom_halt();
- }
+ struct property *prop;
+ unsigned int *busrange;
+
+ prop = of_find_property(pbm->prom_node, "bus-range", NULL);
+
+ busrange = prop->value;
pbm->pci_first_busno = busrange[0];
pbm->pci_last_busno = busrange[1];
}
-static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32 devhandle)
+static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle)
{
struct pci_pbm_info *pbm;
- int err, i;
+ struct property *prop;
+ int len, i;
if (devhandle & 0x40)
pbm = &p->pbm_B;
@@ -1086,32 +1097,19 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32
pbm = &p->pbm_A;
pbm->parent = p;
- pbm->prom_node = prom_node;
+ pbm->prom_node = dp;
pbm->pci_first_slot = 1;
pbm->devhandle = devhandle;
- sprintf(pbm->name, "SUN4V-PCI%d PBM%c",
- p->index, (pbm == &p->pbm_A ? 'A' : 'B'));
+ pbm->name = dp->full_name;
- printk("%s: devhandle[%x] prom_node[%x:%x]\n",
- pbm->name, pbm->devhandle,
- pbm->prom_node, prom_getchild(pbm->prom_node));
-
- prom_getstring(prom_node, "name",
- pbm->prom_name, sizeof(pbm->prom_name));
-
- err = prom_getproperty(prom_node, "ranges",
- (char *) pbm->pbm_ranges,
- sizeof(pbm->pbm_ranges));
- if (err == 0 || err == -1) {
- prom_printf("%s: Fatal error, no ranges property.\n",
- pbm->name);
- prom_halt();
- }
+ printk("%s: SUN4V PCI Bus Module\n", pbm->name);
+ prop = of_find_property(dp, "ranges", &len);
+ pbm->pbm_ranges = prop->value;
pbm->num_pbm_ranges =
- (err / sizeof(struct linux_prom_pci_ranges));
+ (len / sizeof(struct linux_prom_pci_ranges));
/* Mask out the top 8 bits of the ranges, leaving the real
* physical address.
@@ -1122,24 +1120,13 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32
pci_sun4v_determine_mem_io_space(pbm);
pbm_register_toplevel_resources(p, pbm);
- err = prom_getproperty(prom_node, "interrupt-map",
- (char *)pbm->pbm_intmap,
- sizeof(pbm->pbm_intmap));
- if (err == 0 || err == -1) {
- prom_printf("%s: Fatal error, no interrupt-map property.\n",
- pbm->name);
- prom_halt();
- }
+ prop = of_find_property(dp, "interrupt-map", &len);
+ pbm->pbm_intmap = prop->value;
+ pbm->num_pbm_intmap =
+ (len / sizeof(struct linux_prom_pci_intmap));
- pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap));
- err = prom_getproperty(prom_node, "interrupt-map-mask",
- (char *)&pbm->pbm_intmask,
- sizeof(pbm->pbm_intmask));
- if (err == 0 || err == -1) {
- prom_printf("%s: Fatal error, no interrupt-map-mask.\n",
- pbm->name);
- prom_halt();
- }
+ prop = of_find_property(dp, "interrupt-map-mask", NULL);
+ pbm->pbm_intmask = prop->value;
pci_sun4v_get_bus_range(pbm);
pci_sun4v_iommu_init(pbm);
@@ -1147,16 +1134,19 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32
pdev_htab_populate(pbm);
}
-void sun4v_pci_init(int node, char *model_name)
+void sun4v_pci_init(struct device_node *dp, char *model_name)
{
struct pci_controller_info *p;
struct pci_iommu *iommu;
- struct linux_prom64_registers regs;
+ struct property *prop;
+ struct linux_prom64_registers *regs;
u32 devhandle;
int i;
- prom_getproperty(node, "reg", (char *)&regs, sizeof(regs));
- devhandle = (regs.phys_addr >> 32UL) & 0x0fffffff;
+ prop = of_find_property(dp, "reg", NULL);
+ regs = prop->value;
+
+ devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff;
for (p = pci_controller_root; p; p = p->next) {
struct pci_pbm_info *pbm;
@@ -1169,7 +1159,7 @@ void sun4v_pci_init(int node, char *model_name)
&p->pbm_B);
if (pbm->devhandle == (devhandle ^ 0x40)) {
- pci_sun4v_pbm_init(p, node, devhandle);
+ pci_sun4v_pbm_init(p, dp, devhandle);
return;
}
}
@@ -1220,7 +1210,7 @@ void sun4v_pci_init(int node, char *model_name)
*/
pci_memspace_mask = 0x7fffffffUL;
- pci_sun4v_pbm_init(p, node, devhandle);
+ pci_sun4v_pbm_init(p, dp, devhandle);
return;
fatal_memory_error:
diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
index 30bcaf5..9496c77 100644
--- a/arch/sparc64/kernel/power.c
+++ b/arch/sparc64/kernel/power.c
@@ -105,76 +105,25 @@ again:
return 0;
}
-static int __init has_button_interrupt(unsigned int irq, int prom_node)
+static int __init has_button_interrupt(unsigned int irq, struct device_node *dp)
{
if (irq == PCI_IRQ_NONE)
return 0;
- if (!prom_node_has_property(prom_node, "button"))
+ if (!of_find_property(dp, "button", NULL))
return 0;
return 1;
}
-static int __init power_probe_ebus(struct resource **resp, unsigned int *irq_p, int *prom_node_p)
+static void __devinit power_probe_common(struct of_device *dev, struct resource *res, unsigned int irq)
{
- struct linux_ebus *ebus;
- struct linux_ebus_device *edev;
-
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "power")) {
- *resp = &edev->resource[0];
- *irq_p = edev->irqs[0];
- *prom_node_p = edev->prom_node;
- return 0;
- }
- }
- }
- return -ENODEV;
-}
-
-static int __init power_probe_isa(struct resource **resp, unsigned int *irq_p, int *prom_node_p)
-{
- struct sparc_isa_bridge *isa_bus;
- struct sparc_isa_device *isa_dev;
-
- for_each_isa(isa_bus) {
- for_each_isadev(isa_dev, isa_bus) {
- if (!strcmp(isa_dev->prom_name, "power")) {
- *resp = &isa_dev->resource;
- *irq_p = isa_dev->irq;
- *prom_node_p = isa_dev->prom_node;
- return 0;
- }
- }
- }
- return -ENODEV;
-}
-
-void __init power_init(void)
-{
- struct resource *res = NULL;
- unsigned int irq;
- int prom_node;
- static int invoked;
-
- if (invoked)
- return;
- invoked = 1;
-
- if (!power_probe_ebus(&res, &irq, &prom_node))
- goto found;
-
- if (!power_probe_isa(&res, &irq, &prom_node))
- goto found;
-
- return;
-
-found:
power_reg = ioremap(res->start, 0x4);
+
printk("power: Control reg at %p ... ", power_reg);
+
poweroff_method = machine_halt; /* able to use the standard halt */
- if (has_button_interrupt(irq, prom_node)) {
+
+ if (has_button_interrupt(irq, dev->node)) {
if (kernel_thread(powerd, NULL, CLONE_FS) < 0) {
printk("Failed to start power daemon.\n");
return;
@@ -188,4 +137,52 @@ found:
printk("not using powerd.\n");
}
}
+
+static struct of_device_id power_match[] = {
+ {
+ .name = "power",
+ },
+ {},
+};
+
+static int __devinit ebus_power_probe(struct of_device *dev, const struct of_device_id *match)
+{
+ struct linux_ebus_device *edev = to_ebus_device(&dev->dev);
+ struct resource *res = &edev->resource[0];
+ unsigned int irq = edev->irqs[0];
+
+ power_probe_common(dev, res,irq);
+
+ return 0;
+}
+
+static struct of_platform_driver ebus_power_driver = {
+ .name = "power",
+ .match_table = power_match,
+ .probe = ebus_power_probe,
+};
+
+static int __devinit isa_power_probe(struct of_device *dev, const struct of_device_id *match)
+{
+ struct sparc_isa_device *idev = to_isa_device(&dev->dev);
+ struct resource *res = &idev->resource;
+ unsigned int irq = idev->irq;
+
+ power_probe_common(dev, res,irq);
+
+ return 0;
+}
+
+static struct of_platform_driver isa_power_driver = {
+ .name = "power",
+ .match_table = power_match,
+ .probe = isa_power_probe,
+};
+
+void __init power_init(void)
+{
+ of_register_driver(&ebus_power_driver, &ebus_bus_type);
+ of_register_driver(&isa_power_driver, &isa_bus_type);
+ return;
+}
#endif /* CONFIG_PCI */
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
new file mode 100644
index 0000000..e9d703e
--- /dev/null
+++ b/arch/sparc64/kernel/prom.c
@@ -0,0 +1,650 @@
+/*
+ * Procedures for creating, accessing and interpreting the device tree.
+ *
+ * Paul Mackerras August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ * {engebret|bergner}@us.ibm.com
+ *
+ * Adapted for sparc64 by David S. Miller davem@davemloft.net
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/module.h>
+
+#include <asm/prom.h>
+#include <asm/oplib.h>
+
+static struct device_node *allnodes;
+
+int of_device_is_compatible(struct device_node *device, const char *compat)
+{
+ const char* cp;
+ int cplen, l;
+
+ cp = (char *) of_get_property(device, "compatible", &cplen);
+ if (cp == NULL)
+ return 0;
+ while (cplen > 0) {
+ if (strncmp(cp, compat, strlen(compat)) == 0)
+ return 1;
+ l = strlen(cp) + 1;
+ cp += l;
+ cplen -= l;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(of_device_is_compatible);
+
+struct device_node *of_get_parent(const struct device_node *node)
+{
+ struct device_node *np;
+
+ if (!node)
+ return NULL;
+
+ np = node->parent;
+
+ return np;
+}
+EXPORT_SYMBOL(of_get_parent);
+
+struct device_node *of_get_next_child(const struct device_node *node,
+ struct device_node *prev)
+{
+ struct device_node *next;
+
+ next = prev ? prev->sibling : node->child;
+ for (; next != 0; next = next->sibling) {
+ break;
+ }
+
+ return next;
+}
+EXPORT_SYMBOL(of_get_next_child);
+
+struct device_node *of_find_node_by_path(const char *path)
+{
+ struct device_node *np = allnodes;
+
+ for (; np != 0; np = np->allnext) {
+ if (np->full_name != 0 && strcmp(np->full_name, path) == 0)
+ break;
+ }
+
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_path);
+
+struct device_node *of_find_node_by_phandle(phandle handle)
+{
+ struct device_node *np;
+
+ for (np = allnodes; np != 0; np = np->allnext)
+ if (np->node == handle)
+ break;
+
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_phandle);
+
+struct device_node *of_find_node_by_name(struct device_node *from,
+ const char *name)
+{
+ struct device_node *np;
+
+ np = from ? from->allnext : allnodes;
+ for (; np != NULL; np = np->allnext)
+ if (np->name != NULL && strcmp(np->name, name) == 0)
+ break;
+
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_name);
+
+struct device_node *of_find_node_by_type(struct device_node *from,
+ const char *type)
+{
+ struct device_node *np;
+
+ np = from ? from->allnext : allnodes;
+ for (; np != 0; np = np->allnext)
+ if (np->type != 0 && strcmp(np->type, type) == 0)
+ break;
+
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_type);
+
+struct device_node *of_find_compatible_node(struct device_node *from,
+ const char *type, const char *compatible)
+{
+ struct device_node *np;
+
+ np = from ? from->allnext : allnodes;
+ for (; np != 0; np = np->allnext) {
+ if (type != NULL
+ && !(np->type != 0 && strcmp(np->type, type) == 0))
+ continue;
+ if (of_device_is_compatible(np, compatible))
+ break;
+ }
+
+ return np;
+}
+EXPORT_SYMBOL(of_find_compatible_node);
+
+struct property *of_find_property(struct device_node *np, const char *name,
+ int *lenp)
+{
+ struct property *pp;
+
+ for (pp = np->properties; pp != 0; pp = pp->next) {
+ if (strcmp(pp->name, name) == 0) {
+ if (lenp != 0)
+ *lenp = pp->length;
+ break;
+ }
+ }
+ return pp;
+}
+EXPORT_SYMBOL(of_find_property);
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+void *of_get_property(struct device_node *np, const char *name, int *lenp)
+{
+ struct property *pp = of_find_property(np,name,lenp);
+ return pp ? pp->value : NULL;
+}
+EXPORT_SYMBOL(of_get_property);
+
+int of_getintprop_default(struct device_node *np, const char *name, int def)
+{
+ struct property *prop;
+ int len;
+
+ prop = of_find_property(np, name, &len);
+ if (!prop || len != 4)
+ return def;
+
+ return *(int *) prop->value;
+}
+EXPORT_SYMBOL(of_getintprop_default);
+
+static unsigned int prom_early_allocated;
+
+static void * __init prom_early_alloc(unsigned long size)
+{
+ void *ret;
+
+ ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
+ if (ret != NULL)
+ memset(ret, 0, size);
+
+ prom_early_allocated += size;
+
+ return ret;
+}
+
+static int is_root_node(const struct device_node *dp)
+{
+ if (!dp)
+ return 0;
+
+ return (dp->parent == NULL);
+}
+
+/* The following routines deal with the black magic of fully naming a
+ * node.
+ *
+ * Certain well known named nodes are just the simple name string.
+ *
+ * Actual devices have an address specifier appended to the base name
+ * string, like this "foo@addr". The "addr" can be in any number of
+ * formats, and the platform plus the type of the node determine the
+ * format and how it is constructed.
+ *
+ * For children of the ROOT node, the naming convention is fixed and
+ * determined by whether this is a sun4u or sun4v system.
+ *
+ * For children of other nodes, it is bus type specific. So
+ * we walk up the tree until we discover a "device_type" property
+ * we recognize and we go from there.
+ *
+ * As an example, the boot device on my workstation has a full path:
+ *
+ * /pci@1e,600000/ide@d/disk@0,0:c
+ */
+static void __init sun4v_path_component(struct device_node *dp, char *tmp_buf)
+{
+ struct linux_prom64_registers *regs;
+ struct property *rprop;
+ u32 high_bits, low_bits, type;
+
+ rprop = of_find_property(dp, "reg", NULL);
+ if (!rprop)
+ return;
+
+ regs = rprop->value;
+ if (!is_root_node(dp->parent)) {
+ sprintf(tmp_buf, "%s@%x,%x",
+ dp->name,
+ (unsigned int) (regs->phys_addr >> 32UL),
+ (unsigned int) (regs->phys_addr & 0xffffffffUL));
+ return;
+ }
+
+ type = regs->phys_addr >> 60UL;
+ high_bits = (regs->phys_addr >> 32UL) & 0x0fffffffUL;
+ low_bits = (regs->phys_addr & 0xffffffffUL);
+
+ if (type == 0 || type == 8) {
+ const char *prefix = (type == 0) ? "m" : "i";
+
+ if (low_bits)
+ sprintf(tmp_buf, "%s@%s%x,%x",
+ dp->name, prefix,
+ high_bits, low_bits);
+ else
+ sprintf(tmp_buf, "%s@%s%x",
+ dp->name,
+ prefix,
+ high_bits);
+ } else if (type == 12) {
+ sprintf(tmp_buf, "%s@%x",
+ dp->name, high_bits);
+ }
+}
+
+static void __init sun4u_path_component(struct device_node *dp, char *tmp_buf)
+{
+ struct linux_prom64_registers *regs;
+ struct property *prop;
+
+ prop = of_find_property(dp, "reg", NULL);
+ if (!prop)
+ return;
+
+ regs = prop->value;
+ if (!is_root_node(dp->parent)) {
+ sprintf(tmp_buf, "%s@%x,%x",
+ dp->name,
+ (unsigned int) (regs->phys_addr >> 32UL),
+ (unsigned int) (regs->phys_addr & 0xffffffffUL));
+ return;
+ }
+
+ prop = of_find_property(dp, "upa-portid", NULL);
+ if (!prop)
+ prop = of_find_property(dp, "portid", NULL);
+ if (prop) {
+ unsigned long mask = 0xffffffffUL;
+
+ if (tlb_type >= cheetah)
+ mask = 0x7fffff;
+
+ sprintf(tmp_buf, "%s@%x,%x",
+ dp->name,
+ *(u32 *)prop->value,
+ (unsigned int) (regs->phys_addr & mask));
+ }
+}
+
+/* "name@slot,offset" */
+static void __init sbus_path_component(struct device_node *dp, char *tmp_buf)
+{
+ struct linux_prom_registers *regs;
+ struct property *prop;
+
+ prop = of_find_property(dp, "reg", NULL);
+ if (!prop)
+ return;
+
+ regs = prop->value;
+ sprintf(tmp_buf, "%s@%x,%x",
+ dp->name,
+ regs->which_io,
+ regs->phys_addr);
+}
+
+/* "name@devnum[,func]" */
+static void __init pci_path_component(struct device_node *dp, char *tmp_buf)
+{
+ struct linux_prom_pci_registers *regs;
+ struct property *prop;
+ unsigned int devfn;
+
+ prop = of_find_property(dp, "reg", NULL);
+ if (!prop)
+ return;
+
+ regs = prop->value;
+ devfn = (regs->phys_hi >> 8) & 0xff;
+ if (devfn & 0x07) {
+ sprintf(tmp_buf, "%s@%x,%x",
+ dp->name,
+ devfn >> 3,
+ devfn & 0x07);
+ } else {
+ sprintf(tmp_buf, "%s@%x",
+ dp->name,
+ devfn >> 3);
+ }
+}
+
+/* "name@UPA_PORTID,offset" */
+static void __init upa_path_component(struct device_node *dp, char *tmp_buf)
+{
+ struct linux_prom64_registers *regs;
+ struct property *prop;
+
+ prop = of_find_property(dp, "reg", NULL);
+ if (!prop)
+ return;
+
+ regs = prop->value;
+
+ prop = of_find_property(dp, "upa-portid", NULL);
+ if (!prop)
+ return;
+
+ sprintf(tmp_buf, "%s@%x,%x",
+ dp->name,
+ *(u32 *) prop->value,
+ (unsigned int) (regs->phys_addr & 0xffffffffUL));
+}
+
+/* "name@reg" */
+static void __init vdev_path_component(struct device_node *dp, char *tmp_buf)
+{
+ struct property *prop;
+ u32 *regs;
+
+ prop = of_find_property(dp, "reg", NULL);
+ if (!prop)
+ return;
+
+ regs = prop->value;
+
+ sprintf(tmp_buf, "%s@%x", dp->name, *regs);
+}
+
+/* "name@addrhi,addrlo" */
+static void __init ebus_path_component(struct device_node *dp, char *tmp_buf)
+{
+ struct linux_prom64_registers *regs;
+ struct property *prop;
+
+ prop = of_find_property(dp, "reg", NULL);
+ if (!prop)
+ return;
+
+ regs = prop->value;
+
+ sprintf(tmp_buf, "%s@%x,%x",
+ dp->name,
+ (unsigned int) (regs->phys_addr >> 32UL),
+ (unsigned int) (regs->phys_addr & 0xffffffffUL));
+}
+
+/* "name@bus,addr" */
+static void __init i2c_path_component(struct device_node *dp, char *tmp_buf)
+{
+ struct property *prop;
+ u32 *regs;
+
+ prop = of_find_property(dp, "reg", NULL);
+ if (!prop)
+ return;
+
+ regs = prop->value;
+
+ /* This actually isn't right... should look at the #address-cells
+ * property of the i2c bus node etc. etc.
+ */
+ sprintf(tmp_buf, "%s@%x,%x",
+ dp->name, regs[0], regs[1]);
+}
+
+/* "name@reg0[,reg1]" */
+static void __init usb_path_component(struct device_node *dp, char *tmp_buf)
+{
+ struct property *prop;
+ u32 *regs;
+
+ prop = of_find_property(dp, "reg", NULL);
+ if (!prop)
+ return;
+
+ regs = prop->value;
+
+ if (prop->length == sizeof(u32) || regs[1] == 1) {
+ sprintf(tmp_buf, "%s@%x",
+ dp->name, regs[0]);
+ } else {
+ sprintf(tmp_buf, "%s@%x,%x",
+ dp->name, regs[0], regs[1]);
+ }
+}
+
+/* "name@reg0reg1[,reg2reg3]" */
+static void __init ieee1394_path_component(struct device_node *dp, char *tmp_buf)
+{
+ struct property *prop;
+ u32 *regs;
+
+ prop = of_find_property(dp, "reg", NULL);
+ if (!prop)
+ return;
+
+ regs = prop->value;
+
+ if (regs[2] || regs[3]) {
+ sprintf(tmp_buf, "%s@%08x%08x,%04x%08x",
+ dp->name, regs[0], regs[1], regs[2], regs[3]);
+ } else {
+ sprintf(tmp_buf, "%s@%08x%08x",
+ dp->name, regs[0], regs[1]);
+ }
+}
+
+static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
+{
+ struct device_node *parent = dp->parent;
+
+ if (parent != NULL) {
+ if (!strcmp(parent->type, "pci") ||
+ !strcmp(parent->type, "pciex"))
+ return pci_path_component(dp, tmp_buf);
+ if (!strcmp(parent->type, "sbus"))
+ return sbus_path_component(dp, tmp_buf);
+ if (!strcmp(parent->type, "upa"))
+ return upa_path_component(dp, tmp_buf);
+ if (!strcmp(parent->type, "ebus"))
+ return ebus_path_component(dp, tmp_buf);
+ if (!strcmp(parent->name, "usb") ||
+ !strcmp(parent->name, "hub"))
+ return usb_path_component(dp, tmp_buf);
+ if (!strcmp(parent->type, "i2c"))
+ return i2c_path_component(dp, tmp_buf);
+ if (!strcmp(parent->type, "firewire"))
+ return ieee1394_path_component(dp, tmp_buf);
+ if (!strcmp(parent->type, "virtual-devices"))
+ return vdev_path_component(dp, tmp_buf);
+
+ /* "isa" is handled with platform naming */
+ }
+
+ /* Use platform naming convention. */
+ if (tlb_type == hypervisor)
+ return sun4v_path_component(dp, tmp_buf);
+ else
+ return sun4u_path_component(dp, tmp_buf);
+}
+
+static char * __init build_path_component(struct device_node *dp)
+{
+ char tmp_buf[64], *n;
+
+ tmp_buf[0] = '\0';
+ __build_path_component(dp, tmp_buf);
+ if (tmp_buf[0] == '\0')
+ strcpy(tmp_buf, dp->name);
+
+ n = prom_early_alloc(strlen(tmp_buf) + 1);
+ strcpy(n, tmp_buf);
+
+ return n;
+}
+
+static char * __init build_full_name(struct device_node *dp)
+{
+ int len, ourlen, plen;
+ char *n;
+
+ plen = strlen(dp->parent->full_name);
+ ourlen = strlen(dp->path_component_name);
+ len = ourlen + plen + 2;
+
+ n = prom_early_alloc(len);
+ strcpy(n, dp->parent->full_name);
+ if (!is_root_node(dp->parent)) {
+ strcpy(n + plen, "/");
+ plen++;
+ }
+ strcpy(n + plen, dp->path_component_name);
+
+ return n;
+}
+
+static struct property * __init build_one_prop(phandle node, char *prev)
+{
+ static struct property *tmp = NULL;
+ struct property *p;
+
+ if (tmp) {
+ p = tmp;
+ memset(p, 0, sizeof(*p) + 32);
+ tmp = NULL;
+ } else
+ p = prom_early_alloc(sizeof(struct property) + 32);
+
+ p->name = (char *) (p + 1);
+ if (prev == NULL) {
+ prom_firstprop(node, p->name);
+ } else {
+ prom_nextprop(node, prev, p->name);
+ }
+ if (strlen(p->name) == 0) {
+ tmp = p;
+ return NULL;
+ }
+ p->length = prom_getproplen(node, p->name);
+ if (p->length <= 0) {
+ p->length = 0;
+ } else {
+ p->value = prom_early_alloc(p->length);
+ prom_getproperty(node, p->name, p->value, p->length);
+ }
+ return p;
+}
+
+static struct property * __init build_prop_list(phandle node)
+{
+ struct property *head, *tail;
+
+ head = tail = build_one_prop(node, NULL);
+ while(tail) {
+ tail->next = build_one_prop(node, tail->name);
+ tail = tail->next;
+ }
+
+ return head;
+}
+
+static char * __init get_one_property(phandle node, const char *name)
+{
+ char *buf = "<NULL>";
+ int len;
+
+ len = prom_getproplen(node, name);
+ if (len > 0) {
+ buf = prom_early_alloc(len);
+ prom_getproperty(node, name, buf, len);
+ }
+
+ return buf;
+}
+
+static struct device_node * __init create_node(phandle node)
+{
+ struct device_node *dp;
+
+ if (!node)
+ return NULL;
+
+ dp = prom_early_alloc(sizeof(*dp));
+
+ kref_init(&dp->kref);
+
+ dp->name = get_one_property(node, "name");
+ dp->type = get_one_property(node, "device_type");
+ dp->node = node;
+
+ /* Build interrupts later... */
+
+ dp->properties = build_prop_list(node);
+
+ return dp;
+}
+
+static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp)
+{
+ struct device_node *dp;
+
+ dp = create_node(node);
+ if (dp) {
+ *(*nextp) = dp;
+ *nextp = &dp->allnext;
+
+ dp->parent = parent;
+ dp->path_component_name = build_path_component(dp);
+ dp->full_name = build_full_name(dp);
+
+ dp->child = build_tree(dp, prom_getchild(node), nextp);
+
+ dp->sibling = build_tree(parent, prom_getsibling(node), nextp);
+ }
+
+ return dp;
+}
+
+void __init prom_build_devicetree(void)
+{
+ struct device_node **nextp;
+
+ allnodes = create_node(prom_root_node);
+ allnodes->path_component_name = "";
+ allnodes->full_name = "/";
+
+ nextp = &allnodes->allnext;
+ allnodes->child = build_tree(allnodes,
+ prom_getchild(allnodes->node),
+ &nextp);
+ printk("PROM: Built device tree with %u bytes of memory.\n",
+ prom_early_allocated);
+}
diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
index 8812417..ac05e0f 100644
--- a/arch/sparc64/kernel/sbus.c
+++ b/arch/sparc64/kernel/sbus.c
@@ -19,6 +19,7 @@
#include <asm/cache.h>
#include <asm/dma.h>
#include <asm/irq.h>
+#include <asm/prom.h>
#include <asm/starfire.h>
#include "iommu_common.h"
@@ -1098,24 +1099,25 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
}
/* Boot time initialization. */
-void __init sbus_iommu_init(int prom_node, struct sbus_bus *sbus)
+static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
{
- struct linux_prom64_registers rprop;
+ struct linux_prom64_registers *pr;
+ struct device_node *dp;
struct sbus_iommu *iommu;
unsigned long regs, tsb_base;
u64 control;
- int err, i;
+ int i;
+
+ dp = of_find_node_by_phandle(__node);
- sbus->portid = prom_getintdefault(sbus->prom_node,
- "upa-portid", -1);
+ sbus->portid = of_getintprop_default(dp, "upa-portid", -1);
- err = prom_getproperty(prom_node, "reg",
- (char *)&rprop, sizeof(rprop));
- if (err < 0) {
+ pr = of_get_property(dp, "reg", NULL);
+ if (!pr) {
prom_printf("sbus_iommu_init: Cannot map SYSIO control registers.\n");
prom_halt();
}
- regs = rprop.phys_addr;
+ regs = pr->phys_addr;
iommu = kmalloc(sizeof(*iommu) + SMP_CACHE_BYTES, GFP_ATOMIC);
if (iommu == NULL) {
@@ -1225,3 +1227,50 @@ void __init sbus_iommu_init(int prom_node, struct sbus_bus *sbus)
sysio_register_error_handlers(sbus);
}
+
+void sbus_fill_device_irq(struct sbus_dev *sdev)
+{
+ struct device_node *dp = of_find_node_by_phandle(sdev->prom_node);
+ struct linux_prom_irqs *irqs;
+
+ irqs = of_get_property(dp, "interrupts", NULL);
+ if (!irqs) {
+ sdev->irqs[0] = 0;
+ sdev->num_irqs = 0;
+ } else {
+ unsigned int pri = irqs[0].pri;
+
+ sdev->num_irqs = 1;
+ if (pri < 0x20)
+ pri += sdev->slot * 8;
+
+ sdev->irqs[0] = sbus_build_irq(sdev->bus, pri);
+ }
+}
+
+void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus)
+{
+}
+
+void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp)
+{
+ sbus_iommu_init(dp->node, sbus);
+}
+
+void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp)
+{
+}
+
+int __init sbus_arch_preinit(void)
+{
+ return 0;
+}
+
+void __init sbus_arch_postinit(void)
+{
+ extern void firetruck_init(void);
+ extern void clock_probe(void);
+
+ firetruck_init();
+ clock_probe();
+}
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 9cf1c88..a6a7d81 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -376,12 +376,12 @@ void __init setup_arch(char **cmdline_p)
}
#endif
- smp_setup_cpu_possible_map();
-
/* Get boot processor trap_block[] setup. */
init_cur_cpu_trap(current_thread_info());
paging_init();
+
+ smp_setup_cpu_possible_map();
}
static int __init set_preferred_console(void)
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index f03d52d..f62bf3a 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -39,6 +39,7 @@
#include <asm/starfire.h>
#include <asm/tlb.h>
#include <asm/sections.h>
+#include <asm/prom.h>
extern void calibrate_delay(void);
@@ -76,41 +77,42 @@ void smp_bogo(struct seq_file *m)
void __init smp_store_cpu_info(int id)
{
- int cpu_node, def;
+ struct device_node *dp;
+ int def;
/* multiplier and counter set by
smp_setup_percpu_timer() */
cpu_data(id).udelay_val = loops_per_jiffy;
- cpu_find_by_mid(id, &cpu_node);
- cpu_data(id).clock_tick = prom_getintdefault(cpu_node,
- "clock-frequency", 0);
+ cpu_find_by_mid(id, &dp);
+ cpu_data(id).clock_tick =
+ of_getintprop_default(dp, "clock-frequency", 0);
def = ((tlb_type == hypervisor) ? (8 * 1024) : (16 * 1024));
- cpu_data(id).dcache_size = prom_getintdefault(cpu_node, "dcache-size",
- def);
+ cpu_data(id).dcache_size =
+ of_getintprop_default(dp, "dcache-size", def);
def = 32;
cpu_data(id).dcache_line_size =
- prom_getintdefault(cpu_node, "dcache-line-size", def);
+ of_getintprop_default(dp, "dcache-line-size", def);
def = 16 * 1024;
- cpu_data(id).icache_size = prom_getintdefault(cpu_node, "icache-size",
- def);
+ cpu_data(id).icache_size =
+ of_getintprop_default(dp, "icache-size", def);
def = 32;
cpu_data(id).icache_line_size =
- prom_getintdefault(cpu_node, "icache-line-size", def);
+ of_getintprop_default(dp, "icache-line-size", def);
def = ((tlb_type == hypervisor) ?
(3 * 1024 * 1024) :
(4 * 1024 * 1024));
- cpu_data(id).ecache_size = prom_getintdefault(cpu_node, "ecache-size",
- def);
+ cpu_data(id).ecache_size =
+ of_getintprop_default(dp, "ecache-size", def);
def = 64;
cpu_data(id).ecache_line_size =
- prom_getintdefault(cpu_node, "ecache-line-size", def);
+ of_getintprop_default(dp, "ecache-line-size", def);
printk("CPU[%d]: Caches "
"D[sz(%d):line_sz(%d)] "
@@ -342,10 +344,10 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu)
prom_startcpu_cpuid(cpu, entry, cookie);
} else {
- int cpu_node;
+ struct device_node *dp;
- cpu_find_by_mid(cpu, &cpu_node);
- prom_startcpu(cpu_node, entry, cookie);
+ cpu_find_by_mid(cpu, &dp);
+ prom_startcpu(dp->node, entry, cookie);
}
for (timeout = 0; timeout < 5000000; timeout++) {
@@ -1289,7 +1291,8 @@ int setup_profiling_timer(unsigned int multiplier)
static void __init smp_tune_scheduling(void)
{
- int instance, node;
+ struct device_node *dp;
+ int instance;
unsigned int def, smallest = ~0U;
def = ((tlb_type == hypervisor) ?
@@ -1297,10 +1300,10 @@ static void __init smp_tune_scheduling(void)
(4 * 1024 * 1024));
instance = 0;
- while (!cpu_find_by_instance(instance, &node, NULL)) {
+ while (!cpu_find_by_instance(instance, &dp, NULL)) {
unsigned int val;
- val = prom_getintdefault(node, "ecache-size", def);
+ val = of_getintprop_default(dp, "ecache-size", def);
if (val < smallest)
smallest = val;
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index 0f00a99..348b820 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -48,6 +48,7 @@
#include <asm/sections.h>
#include <asm/cpudata.h>
#include <asm/uaccess.h>
+#include <asm/prom.h>
DEFINE_SPINLOCK(mostek_lock);
DEFINE_SPINLOCK(rtc_lock);
@@ -755,24 +756,200 @@ retry:
return -EOPNOTSUPP;
}
-void __init clock_probe(void)
+static int __init clock_model_matches(char *model)
{
- struct linux_prom_registers clk_reg[2];
- char model[128];
- int node, busnd = -1, err;
- unsigned long flags;
- struct linux_central *cbus;
+ if (strcmp(model, "mk48t02") &&
+ strcmp(model, "mk48t08") &&
+ strcmp(model, "mk48t59") &&
+ strcmp(model, "m5819") &&
+ strcmp(model, "m5819p") &&
+ strcmp(model, "m5823") &&
+ strcmp(model, "ds1287"))
+ return 0;
+
+ return 1;
+}
+
+static void __init __clock_assign_common(void __iomem *addr, char *model)
+{
+ if (model[5] == '0' && model[6] == '2') {
+ mstk48t02_regs = addr;
+ } else if(model[5] == '0' && model[6] == '8') {
+ mstk48t08_regs = addr;
+ mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02;
+ } else {
+ mstk48t59_regs = addr;
+ mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
+ }
+}
+
+static void __init clock_assign_clk_reg(struct linux_prom_registers *clk_reg,
+ char *model)
+{
+ unsigned long addr;
+
+ addr = ((unsigned long) clk_reg[0].phys_addr |
+ (((unsigned long) clk_reg[0].which_io) << 32UL));
+
+ __clock_assign_common((void __iomem *) addr, model);
+}
+
+static int __init clock_probe_central(void)
+{
+ struct linux_prom_registers clk_reg[2], *pr;
+ struct device_node *dp;
+ char *model;
+
+ if (!central_bus)
+ return 0;
+
+ /* Get Central FHC's prom node. */
+ dp = central_bus->child->prom_node;
+
+ /* Then get the first child device below it. */
+ dp = dp->child;
+
+ while (dp) {
+ model = of_get_property(dp, "model", NULL);
+ if (!model || !clock_model_matches(model))
+ goto next_sibling;
+
+ pr = of_get_property(dp, "reg", NULL);
+ memcpy(clk_reg, pr, sizeof(clk_reg));
+
+ apply_fhc_ranges(central_bus->child, clk_reg, 1);
+ apply_central_ranges(central_bus, clk_reg, 1);
+
+ clock_assign_clk_reg(clk_reg, model);
+ return 1;
+
+ next_sibling:
+ dp = dp->sibling;
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_PCI
- struct linux_ebus *ebus = NULL;
- struct sparc_isa_bridge *isa_br = NULL;
+static void __init clock_isa_ebus_assign_regs(struct resource *res, char *model)
+{
+ if (!strcmp(model, "ds1287") ||
+ !strcmp(model, "m5819") ||
+ !strcmp(model, "m5819p") ||
+ !strcmp(model, "m5823")) {
+ ds1287_regs = res->start;
+ } else {
+ mstk48t59_regs = (void __iomem *) res->start;
+ mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
+ }
+}
+
+static int __init clock_probe_one_ebus_dev(struct linux_ebus_device *edev)
+{
+ struct device_node *dp = edev->prom_node;
+ char *model;
+
+ model = of_get_property(dp, "model", NULL);
+ if (!clock_model_matches(model))
+ return 0;
+
+ clock_isa_ebus_assign_regs(&edev->resource[0], model);
+
+ return 1;
+}
+
+static int __init clock_probe_ebus(void)
+{
+ struct linux_ebus *ebus;
+
+ for_each_ebus(ebus) {
+ struct linux_ebus_device *edev;
+
+ for_each_ebusdev(edev, ebus) {
+ if (clock_probe_one_ebus_dev(edev))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int __init clock_probe_one_isa_dev(struct sparc_isa_device *idev)
+{
+ struct device_node *dp = idev->prom_node;
+ char *model;
+
+ model = of_get_property(dp, "model", NULL);
+ if (!clock_model_matches(model))
+ return 0;
+
+ clock_isa_ebus_assign_regs(&idev->resource, model);
+
+ return 1;
+}
+
+static int __init clock_probe_isa(void)
+{
+ struct sparc_isa_bridge *isa_br;
+
+ for_each_isa(isa_br) {
+ struct sparc_isa_device *isa_dev;
+
+ for_each_isadev(isa_dev, isa_br) {
+ if (clock_probe_one_isa_dev(isa_dev))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+#endif /* CONFIG_PCI */
+
+#ifdef CONFIG_SBUS
+static int __init clock_probe_one_sbus_dev(struct sbus_bus *sbus, struct sbus_dev *sdev)
+{
+ struct resource *res;
+ char model[64];
+ void __iomem *addr;
+
+ prom_getstring(sdev->prom_node, "model", model, sizeof(model));
+ if (!clock_model_matches(model))
+ return 0;
+
+ res = &sdev->resource[0];
+ addr = sbus_ioremap(res, 0, 0x800UL, "eeprom");
+
+ __clock_assign_common(addr, model);
+
+ return 1;
+}
+
+static int __init clock_probe_sbus(void)
+{
+ struct sbus_bus *sbus;
+
+ for_each_sbus(sbus) {
+ struct sbus_dev *sdev;
+
+ for_each_sbusdev(sdev, sbus) {
+ if (clock_probe_one_sbus_dev(sbus, sdev))
+ return 1;
+ }
+ }
+
+ return 0;
+}
#endif
+
+void __init clock_probe(void)
+{
static int invoked;
+ unsigned long flags;
if (invoked)
return;
invoked = 1;
-
if (this_is_starfire) {
xtime.tv_sec = starfire_get_time();
xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
@@ -788,183 +965,27 @@ void __init clock_probe(void)
return;
}
- local_irq_save(flags);
-
- cbus = central_bus;
- if (cbus != NULL)
- busnd = central_bus->child->prom_node;
-
/* Check FHC Central then EBUSs then ISA bridges then SBUSs.
* That way we handle the presence of multiple properly.
*
* As a special case, machines with Central must provide the
* timer chip there.
*/
+ if (!clock_probe_central() &&
#ifdef CONFIG_PCI
- if (ebus_chain != NULL) {
- ebus = ebus_chain;
- if (busnd == -1)
- busnd = ebus->prom_node;
- }
- if (isa_chain != NULL) {
- isa_br = isa_chain;
- if (busnd == -1)
- busnd = isa_br->prom_node;
- }
-#endif
- if (sbus_root != NULL && busnd == -1)
- busnd = sbus_root->prom_node;
-
- if (busnd == -1) {
- prom_printf("clock_probe: problem, cannot find bus to search.\n");
- prom_halt();
- }
-
- node = prom_getchild(busnd);
-
- while (1) {
- if (!node)
- model[0] = 0;
- else
- prom_getstring(node, "model", model, sizeof(model));
- if (strcmp(model, "mk48t02") &&
- strcmp(model, "mk48t08") &&
- strcmp(model, "mk48t59") &&
- strcmp(model, "m5819") &&
- strcmp(model, "m5819p") &&
- strcmp(model, "m5823") &&
- strcmp(model, "ds1287")) {
- if (cbus != NULL) {
- prom_printf("clock_probe: Central bus lacks timer chip.\n");
- prom_halt();
- }
-
- if (node != 0)
- node = prom_getsibling(node);
-#ifdef CONFIG_PCI
- while ((node == 0) && ebus != NULL) {
- ebus = ebus->next;
- if (ebus != NULL) {
- busnd = ebus->prom_node;
- node = prom_getchild(busnd);
- }
- }
- while ((node == 0) && isa_br != NULL) {
- isa_br = isa_br->next;
- if (isa_br != NULL) {
- busnd = isa_br->prom_node;
- node = prom_getchild(busnd);
- }
- }
+ !clock_probe_ebus() &&
+ !clock_probe_isa() &&
#endif
- if (node == 0) {
- prom_printf("clock_probe: Cannot find timer chip\n");
- prom_halt();
- }
- continue;
- }
-
- err = prom_getproperty(node, "reg", (char *)clk_reg,
- sizeof(clk_reg));
- if(err == -1) {
- prom_printf("clock_probe: Cannot get Mostek reg property\n");
- prom_halt();
- }
-
- if (cbus != NULL) {
- apply_fhc_ranges(central_bus->child, clk_reg, 1);
- apply_central_ranges(central_bus, clk_reg, 1);
- }
-#ifdef CONFIG_PCI
- else if (ebus != NULL) {
- struct linux_ebus_device *edev;
-
- for_each_ebusdev(edev, ebus)
- if (edev->prom_node == node)
- break;
- if (edev == NULL) {
- if (isa_chain != NULL)
- goto try_isa_clock;
- prom_printf("%s: Mostek not probed by EBUS\n",
- __FUNCTION__);
- prom_halt();
- }
-
- if (!strcmp(model, "ds1287") ||
- !strcmp(model, "m5819") ||
- !strcmp(model, "m5819p") ||
- !strcmp(model, "m5823")) {
- ds1287_regs = edev->resource[0].start;
- } else {
- mstk48t59_regs = (void __iomem *)
- edev->resource[0].start;
- mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
- }
- break;
- }
- else if (isa_br != NULL) {
- struct sparc_isa_device *isadev;
-
-try_isa_clock:
- for_each_isadev(isadev, isa_br)
- if (isadev->prom_node == node)
- break;
- if (isadev == NULL) {
- prom_printf("%s: Mostek not probed by ISA\n");
- prom_halt();
- }
- if (!strcmp(model, "ds1287") ||
- !strcmp(model, "m5819") ||
- !strcmp(model, "m5819p") ||
- !strcmp(model, "m5823")) {
- ds1287_regs = isadev->resource.start;
- } else {
- mstk48t59_regs = (void __iomem *)
- isadev->resource.start;
- mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
- }
- break;
- }
+#ifdef CONFIG_SBUS
+ !clock_probe_sbus()
#endif
- else {
- if (sbus_root->num_sbus_ranges) {
- int nranges = sbus_root->num_sbus_ranges;
- int rngc;
-
- for (rngc = 0; rngc < nranges; rngc++)
- if (clk_reg[0].which_io ==
- sbus_root->sbus_ranges[rngc].ot_child_space)
- break;
- if (rngc == nranges) {
- prom_printf("clock_probe: Cannot find ranges for "
- "clock regs.\n");
- prom_halt();
- }
- clk_reg[0].which_io =
- sbus_root->sbus_ranges[rngc].ot_parent_space;
- clk_reg[0].phys_addr +=
- sbus_root->sbus_ranges[rngc].ot_parent_base;
- }
- }
-
- if(model[5] == '0' && model[6] == '2') {
- mstk48t02_regs = (void __iomem *)
- (((u64)clk_reg[0].phys_addr) |
- (((u64)clk_reg[0].which_io)<<32UL));
- } else if(model[5] == '0' && model[6] == '8') {
- mstk48t08_regs = (void __iomem *)
- (((u64)clk_reg[0].phys_addr) |
- (((u64)clk_reg[0].which_io)<<32UL));
- mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02;
- } else {
- mstk48t59_regs = (void __iomem *)
- (((u64)clk_reg[0].phys_addr) |
- (((u64)clk_reg[0].which_io)<<32UL));
- mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
- }
- break;
+ ) {
+ printk(KERN_WARNING "No clock chip found.\n");
+ return;
}
+ local_irq_save(flags);
+
if (mstk48t02_regs != NULL) {
/* Report a low battery voltage condition. */
if (has_low_battery())
@@ -983,12 +1004,14 @@ try_isa_clock:
/* This is gets the master TICK_INT timer going. */
static unsigned long sparc64_init_timers(void)
{
+ struct device_node *dp;
+ struct property *prop;
unsigned long clock;
- int node;
#ifdef CONFIG_SMP
extern void smp_tick_init(void);
#endif
+ dp = of_find_node_by_path("/");
if (tlb_type == spitfire) {
unsigned long ver, manuf, impl;
@@ -999,18 +1022,17 @@ static unsigned long sparc64_init_timers(void)
if (manuf == 0x17 && impl == 0x13) {
/* Hummingbird, aka Ultra-IIe */
tick_ops = &hbtick_operations;
- node = prom_root_node;
- clock = prom_getint(node, "stick-frequency");
+ prop = of_find_property(dp, "stick-frequency", NULL);
} else {
tick_ops = &tick_operations;
- cpu_find_by_instance(0, &node, NULL);
- clock = prom_getint(node, "clock-frequency");
+ cpu_find_by_instance(0, &dp, NULL);
+ prop = of_find_property(dp, "clock-frequency", NULL);
}
} else {
tick_ops = &stick_operations;
- node = prom_root_node;
- clock = prom_getint(node, "stick-frequency");
+ prop = of_find_property(dp, "stick-frequency", NULL);
}
+ clock = *(unsigned int *) prop->value;
timer_tick_offset = clock / HZ;
#ifdef CONFIG_SMP
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 5059cbd..1ff34b0 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -42,6 +42,7 @@
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
+#include <asm/prom.h>
ATOMIC_NOTIFIER_HEAD(sparc64die_chain);
@@ -807,7 +808,8 @@ extern unsigned int cheetah_deferred_trap_vector[], cheetah_deferred_trap_vector
void __init cheetah_ecache_flush_init(void)
{
unsigned long largest_size, smallest_linesize, order, ver;
- int node, i, instance;
+ struct device_node *dp;
+ int i, instance, sz;
/* Scan all cpu device tree nodes, note two values:
* 1) largest E-cache size
@@ -817,14 +819,14 @@ void __init cheetah_ecache_flush_init(void)
smallest_linesize = ~0UL;
instance = 0;
- while (!cpu_find_by_instance(instance, &node, NULL)) {
+ while (!cpu_find_by_instance(instance, &dp, NULL)) {
unsigned long val;
- val = prom_getintdefault(node, "ecache-size",
- (2 * 1024 * 1024));
+ val = of_getintprop_default(dp, "ecache-size",
+ (2 * 1024 * 1024));
if (val > largest_size)
largest_size = val;
- val = prom_getintdefault(node, "ecache-line-size", 64);
+ val = of_getintprop_default(dp, "ecache-line-size", 64);
if (val < smallest_linesize)
smallest_linesize = val;
instance++;
@@ -849,16 +851,16 @@ void __init cheetah_ecache_flush_init(void)
}
/* Now allocate error trap reporting scoreboard. */
- node = NR_CPUS * (2 * sizeof(struct cheetah_err_info));
+ sz = NR_CPUS * (2 * sizeof(struct cheetah_err_info));
for (order = 0; order < MAX_ORDER; order++) {
- if ((PAGE_SIZE << order) >= node)
+ if ((PAGE_SIZE << order) >= sz)
break;
}
cheetah_error_log = (struct cheetah_err_info *)
__get_free_pages(GFP_KERNEL, order);
if (!cheetah_error_log) {
prom_printf("cheetah_ecache_flush_init: Failed to allocate "
- "error logging scoreboard (%d bytes).\n", node);
+ "error logging scoreboard (%d bytes).\n", sz);
prom_halt();
}
memset(cheetah_error_log, 0, PAGE_SIZE << order);
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
index 001e851..bb2d685 100644
--- a/arch/sparc64/kernel/unaligned.c
+++ b/arch/sparc64/kernel/unaligned.c
@@ -279,12 +279,21 @@ static void kernel_mna_trap_fault(void)
asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
{
+ static unsigned long count, last_time;
enum direction dir = decode_direction(insn);
int size = decode_access_size(insn);
current_thread_info()->kern_una_regs = regs;
current_thread_info()->kern_una_insn = insn;
+ if (jiffies - last_time > 5 * HZ)
+ count = 0;
+ if (count < 5) {
+ last_time = jiffies;
+ count++;
+ printk("Kernel unaligned access at TPC[%lx]\n", regs->tpc);
+ }
+
if (!ok_for_kernel(insn) || dir == both) {
printk("Unsupported unaligned load/store trap for kernel "
"at <%016lx>.\n", regs->tpc);
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 1539a83..5139934 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -42,6 +42,7 @@
#include <asm/sections.h>
#include <asm/tsb.h>
#include <asm/hypervisor.h>
+#include <asm/prom.h>
extern void device_scan(void);
@@ -101,8 +102,6 @@ static void __init read_obp_memory(const char *property,
prom_halt();
}
- *num_ents = ents;
-
/* Sanitize what we got from the firmware, by page aligning
* everything.
*/
@@ -124,6 +123,25 @@ static void __init read_obp_memory(const char *property,
regs[i].phys_addr = base;
regs[i].reg_size = size;
}
+
+ for (i = 0; i < ents; i++) {
+ if (regs[i].reg_size == 0UL) {
+ int j;
+
+ for (j = i; j < ents - 1; j++) {
+ regs[j].phys_addr =
+ regs[j+1].phys_addr;
+ regs[j].reg_size =
+ regs[j+1].reg_size;
+ }
+
+ ents--;
+ i--;
+ }
+ }
+
+ *num_ents = ents;
+
sort(regs, ents, sizeof(struct linux_prom64_registers),
cmp_p64, NULL);
}
@@ -1339,6 +1357,8 @@ void __init paging_init(void)
kernel_physical_mapping_init();
+ prom_build_devicetree();
+
{
unsigned long zones_size[MAX_NR_ZONES];
unsigned long zholes_size[MAX_NR_ZONES];
@@ -1376,7 +1396,7 @@ static void __init taint_real_pages(void)
while (old_start < old_end) {
int n;
- for (n = 0; pavail_rescan_ents; n++) {
+ for (n = 0; n < pavail_rescan_ents; n++) {
unsigned long new_start, new_end;
new_start = pavail_rescan[n].phys_addr;
@@ -1398,6 +1418,32 @@ static void __init taint_real_pages(void)
}
}
+int __init page_in_phys_avail(unsigned long paddr)
+{
+ int i;
+
+ paddr &= PAGE_MASK;
+
+ for (i = 0; i < pavail_rescan_ents; i++) {
+ unsigned long start, end;
+
+ start = pavail_rescan[i].phys_addr;
+ end = start + pavail_rescan[i].reg_size;
+
+ if (paddr >= start && paddr < end)
+ return 1;
+ }
+ if (paddr >= kern_base && paddr < (kern_base + kern_size))
+ return 1;
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (paddr >= __pa(initrd_start) &&
+ paddr < __pa(PAGE_ALIGN(initrd_end)))
+ return 1;
+#endif
+
+ return 0;
+}
+
void __init mem_init(void)
{
unsigned long codepages, datapages, initpages;
diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c
index 4885ca6..0f0eb6a 100644
--- a/arch/sparc64/solaris/fs.c
+++ b/arch/sparc64/solaris/fs.c
@@ -356,7 +356,7 @@ static int report_statvfs(struct vfsmount *mnt, struct inode *inode, u32 buf)
int error;
struct sol_statvfs __user *ss = A(buf);
- error = vfs_statfs(mnt->mnt_sb, &s);
+ error = vfs_statfs(mnt->mnt_root, &s);
if (!error) {
const char *p = mnt->mnt_sb->s_type->name;
int i = 0;
@@ -392,7 +392,7 @@ static int report_statvfs64(struct vfsmount *mnt, struct inode *inode, u32 buf)
int error;
struct sol_statvfs64 __user *ss = A(buf);
- error = vfs_statfs(mnt->mnt_sb, &s);
+ error = vfs_statfs(mnt->mnt_root, &s);
if (!error) {
const char *p = mnt->mnt_sb->s_type->name;
int i = 0;
diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c
index 5284996..719c909 100644
--- a/arch/sparc64/solaris/misc.c
+++ b/arch/sparc64/solaris/misc.c
@@ -23,6 +23,7 @@
#include <asm/oplib.h>
#include <asm/idprom.h>
#include <asm/smp.h>
+#include <asm/prom.h>
#include "conv.h"
@@ -194,14 +195,17 @@ static char *machine(void)
}
}
-static char *platform(char *buffer)
+static char *platform(char *buffer, int sz)
{
+ struct device_node *dp = of_find_node_by_path("/");
int len;
*buffer = 0;
- len = prom_getproperty(prom_root_node, "name", buffer, 256);
- if(len > 0)
- buffer[len] = 0;
+ len = strlen(dp->name);
+ if (len > sz)
+ len = sz;
+ memcpy(buffer, dp->name, len);
+ buffer[len] = 0;
if (*buffer) {
char *p;
@@ -213,16 +217,22 @@ static char *platform(char *buffer)
return "sun4u";
}
-static char *serial(char *buffer)
+static char *serial(char *buffer, int sz)
{
- int node = prom_getchild(prom_root_node);
+ struct device_node *dp = of_find_node_by_path("/options");
int len;
- node = prom_searchsiblings(node, "options");
*buffer = 0;
- len = prom_getproperty(node, "system-board-serial#", buffer, 256);
- if(len > 0)
- buffer[len] = 0;
+ if (dp) {
+ char *val = of_get_property(dp, "system-board-serial#", &len);
+
+ if (val && len > 0) {
+ if (len > sz)
+ len = sz;
+ memcpy(buffer, val, len);
+ buffer[len] = 0;
+ }
+ }
if (!*buffer)
return "4512348717234";
else
@@ -305,8 +315,8 @@ asmlinkage int solaris_sysinfo(int cmd, u32 buf, s32 count)
case SI_MACHINE: r = machine(); break;
case SI_ARCHITECTURE: r = "sparc"; break;
case SI_HW_PROVIDER: r = "Sun_Microsystems"; break;
- case SI_HW_SERIAL: r = serial(buffer); break;
- case SI_PLATFORM: r = platform(buffer); break;
+ case SI_HW_SERIAL: r = serial(buffer, sizeof(buffer)); break;
+ case SI_PLATFORM: r = platform(buffer, sizeof(buffer)); break;
case SI_SRPC_DOMAIN: r = ""; break;
case SI_VERSION: r = "Generic"; break;
default: return -EINVAL;
diff --git a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug
index 5681a8b..bab51d6 100644
--- a/arch/um/Kconfig.debug
+++ b/arch/um/Kconfig.debug
@@ -49,7 +49,6 @@ config GCOV
config SYSCALL_DEBUG
bool "Enable system call debugging"
- default N
depends on DEBUG_INFO
help
This adds some system debugging to UML, including keeping a ring buffer
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index 6d7173f..7914931 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -300,8 +300,6 @@ void mconsole_reboot(struct mc_request *req)
machine_restart(NULL);
}
-extern void ctrl_alt_del(void);
-
void mconsole_cad(struct mc_request *req)
{
mconsole_reply(req, "", 0, 0);
diff --git a/arch/um/include/sysdep-x86_64/syscalls.h b/arch/um/include/sysdep-x86_64/syscalls.h
index e06f83e..5e86aa0 100644
--- a/arch/um/include/sysdep-x86_64/syscalls.h
+++ b/arch/um/include/sysdep-x86_64/syscalls.h
@@ -12,8 +12,6 @@
typedef long syscall_handler_t(void);
-extern syscall_handler_t *ia32_sys_call_table[];
-
extern syscall_handler_t *sys_call_table[];
#define EXECUTE_SYSCALL(syscall, regs) \
diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c
index 86f51d0..87cdbc5 100644
--- a/arch/um/kernel/time_kern.c
+++ b/arch/um/kernel/time_kern.c
@@ -87,7 +87,7 @@ void timer_irq(union uml_pt_regs *regs)
void time_init_kern(void)
{
- unsigned long long nsecs;
+ long long nsecs;
nsecs = os_nsecs();
set_normalized_timespec(&wall_to_monotonic, -nsecs / BILLION,
diff --git a/arch/um/sys-ppc/misc.S b/arch/um/sys-ppc/misc.S
index 11b7bd7..f0c971db 100644
--- a/arch/um/sys-ppc/misc.S
+++ b/arch/um/sys-ppc/misc.S
@@ -23,14 +23,10 @@
#define CACHE_LINE_SIZE 16
#define LG_CACHE_LINE_SIZE 4
#define MAX_COPY_PREFETCH 1
-#elif !defined(CONFIG_PPC64BRIDGE)
+#else
#define CACHE_LINE_SIZE 32
#define LG_CACHE_LINE_SIZE 5
#define MAX_COPY_PREFETCH 4
-#else
-#define CACHE_LINE_SIZE 128
-#define LG_CACHE_LINE_SIZE 7
-#define MAX_COPY_PREFETCH 1
#endif /* CONFIG_4xx || CONFIG_8xx */
.text
diff --git a/arch/v850/kernel/signal.c b/arch/v850/kernel/signal.c
index 633e4e1..17c2d43 100644
--- a/arch/v850/kernel/signal.c
+++ b/arch/v850/kernel/signal.c
@@ -274,7 +274,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
/* Default to using normal stack */
unsigned long sp = regs->gpr[GPR_SP];
- if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp))
+ if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp))
sp = current->sas_ss_sp + current->sas_ss_size;
return (void *)((sp - frame_size) & -8UL);
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index 408d44a..af44130 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -299,6 +299,7 @@ config X86_64_ACPI_NUMA
bool "ACPI NUMA detection"
depends on NUMA
select ACPI
+ select PCI
select ACPI_NUMA
default y
help
@@ -389,6 +390,7 @@ config GART_IOMMU
bool "K8 GART IOMMU support"
default y
select SWIOTLB
+ select AGP
depends on PCI
help
Support for hardware IOMMU in AMD's Opteron/Athlon64 Processors
@@ -401,11 +403,9 @@ config GART_IOMMU
northbridge and a software emulation used on other systems without
hardware IOMMU. If unsure, say Y.
-# need this always enabled with GART_IOMMU for the VIA workaround
+# need this always selected by GART_IOMMU for the VIA workaround
config SWIOTLB
bool
- default y
- depends on GART_IOMMU
config X86_MCE
bool "Machine check support" if EMBEDDED
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
index 5a92fed..4ec594a 100644
--- a/arch/x86_64/ia32/ia32entry.S
+++ b/arch/x86_64/ia32/ia32entry.S
@@ -696,4 +696,5 @@ ia32_sys_call_table:
.quad sys_sync_file_range
.quad sys_tee
.quad compat_sys_vmsplice
+ .quad compat_sys_move_pages
ia32_syscall_end:
diff --git a/arch/x86_64/kernel/acpi/Makefile b/arch/x86_64/kernel/acpi/Makefile
index 4fe9707..080b996 100644
--- a/arch/x86_64/kernel/acpi/Makefile
+++ b/arch/x86_64/kernel/acpi/Makefile
@@ -4,5 +4,6 @@ obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o
ifneq ($(CONFIG_ACPI_PROCESSOR),)
obj-y += processor.o
+processor-y := ../../../i386/kernel/acpi/processor.o ../../../i386/kernel/acpi/cstate.o
endif
diff --git a/arch/x86_64/kernel/acpi/processor.c b/arch/x86_64/kernel/acpi/processor.c
deleted file mode 100644
index 3bdc2ba..0000000
--- a/arch/x86_64/kernel/acpi/processor.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * arch/x86_64/kernel/acpi/processor.c
- *
- * Copyright (C) 2005 Intel Corporation
- * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
- * - Added _PDC for platforms with Intel CPUs
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/acpi.h>
-
-#include <acpi/processor.h>
-#include <asm/acpi.h>
-
-static void init_intel_pdc(struct acpi_processor *pr, struct cpuinfo_x86 *c)
-{
- struct acpi_object_list *obj_list;
- union acpi_object *obj;
- u32 *buf;
-
- /* allocate and initialize pdc. It will be used later. */
- obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL);
- if (!obj_list) {
- printk(KERN_ERR "Memory allocation error\n");
- return;
- }
-
- obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL);
- if (!obj) {
- printk(KERN_ERR "Memory allocation error\n");
- kfree(obj_list);
- return;
- }
-
- buf = kmalloc(12, GFP_KERNEL);
- if (!buf) {
- printk(KERN_ERR "Memory allocation error\n");
- kfree(obj);
- kfree(obj_list);
- return;
- }
-
- buf[0] = ACPI_PDC_REVISION_ID;
- buf[1] = 1;
- buf[2] = ACPI_PDC_EST_CAPABILITY_SMP;
-
- obj->type = ACPI_TYPE_BUFFER;
- obj->buffer.length = 12;
- obj->buffer.pointer = (u8 *) buf;
- obj_list->count = 1;
- obj_list->pointer = obj;
- pr->pdc = obj_list;
-
- return;
-}
-
-/* Initialize _PDC data based on the CPU vendor */
-void arch_acpi_processor_init_pdc(struct acpi_processor *pr)
-{
- unsigned int cpu = pr->id;
- struct cpuinfo_x86 *c = cpu_data + cpu;
-
- pr->pdc = NULL;
- if (c->x86_vendor == X86_VENDOR_INTEL && cpu_has(c, X86_FEATURE_EST))
- init_intel_pdc(pr, c);
-
- return;
-}
-
-EXPORT_SYMBOL(arch_acpi_processor_init_pdc);
diff --git a/arch/x86_64/kernel/acpi/sleep.c b/arch/x86_64/kernel/acpi/sleep.c
index 867a0ebe..091bc79 100644
--- a/arch/x86_64/kernel/acpi/sleep.c
+++ b/arch/x86_64/kernel/acpi/sleep.c
@@ -35,6 +35,8 @@
#include <linux/pci.h>
#include <linux/bootmem.h>
#include <linux/acpi.h>
+#include <linux/cpumask.h>
+
#include <asm/mpspec.h>
#include <asm/io.h>
#include <asm/apic.h>
@@ -66,7 +68,8 @@ static void init_low_mapping(void)
pgd_t *slot0 = pgd_offset(current->mm, 0UL);
low_ptr = *slot0;
set_pgd(slot0, *pgd_offset(current->mm, PAGE_OFFSET));
- flush_tlb_all();
+ WARN_ON(num_online_cpus() != 1);
+ local_flush_tlb();
}
/**
@@ -92,7 +95,7 @@ int acpi_save_state_mem(void)
void acpi_restore_state_mem(void)
{
set_pgd(pgd_offset(current->mm, 0UL), low_ptr);
- flush_tlb_all();
+ local_flush_tlb();
}
/**
diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c
index 100a30c..29ef990 100644
--- a/arch/x86_64/kernel/apic.c
+++ b/arch/x86_64/kernel/apic.c
@@ -51,7 +51,7 @@ int disable_apic_timer __initdata;
static cpumask_t timer_interrupt_broadcast_ipi_mask;
/* Using APIC to generate smp_local_timer_interrupt? */
-int using_apic_timer = 0;
+int using_apic_timer __read_mostly = 0;
static void apic_pm_activate(void);
diff --git a/arch/x86_64/kernel/i387.c b/arch/x86_64/kernel/i387.c
index a5d7e16..44ddb1e 100644
--- a/arch/x86_64/kernel/i387.c
+++ b/arch/x86_64/kernel/i387.c
@@ -24,7 +24,7 @@
#include <asm/ptrace.h>
#include <asm/uaccess.h>
-unsigned int mxcsr_feature_mask = 0xffffffff;
+unsigned int mxcsr_feature_mask __read_mostly = 0xffffffff;
void mxcsr_feature_mask_init(void)
{
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index 655b919..fdb8265 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -47,6 +47,7 @@
#include <linux/dmi.h>
#include <linux/dma-mapping.h>
#include <linux/ctype.h>
+#include <linux/suspend.h>
#include <asm/mtrr.h>
#include <asm/uaccess.h>
@@ -595,6 +596,100 @@ static void discover_ebda(void)
ebda_size = 64*1024;
}
+#ifdef CONFIG_SOFTWARE_SUSPEND
+static void __init mark_nosave_page_range(unsigned long start, unsigned long end)
+{
+ struct page *page;
+ while (start <= end) {
+ page = pfn_to_page(start);
+ SetPageNosave(page);
+ start++;
+ }
+}
+
+static void __init e820_nosave_reserved_pages(void)
+{
+ int i;
+ unsigned long r_start = 0, r_end = 0;
+
+ /* Assume e820 map is sorted */
+ for (i = 0; i < e820.nr_map; i++) {
+ struct e820entry *ei = &e820.map[i];
+ unsigned long start, end;
+
+ start = round_down(ei->addr, PAGE_SIZE);
+ end = round_up(ei->addr + ei->size, PAGE_SIZE);
+ if (start >= end)
+ continue;
+ if (ei->type == E820_RESERVED)
+ continue;
+ r_end = start>>PAGE_SHIFT;
+ /* swsusp ignores invalid pfn, ignore these pages here */
+ if (r_end > end_pfn)
+ r_end = end_pfn;
+ if (r_end > r_start)
+ mark_nosave_page_range(r_start, r_end-1);
+ if (r_end >= end_pfn)
+ break;
+ r_start = end>>PAGE_SHIFT;
+ }
+}
+
+static void __init e820_save_acpi_pages(void)
+{
+ int i;
+
+ /* Assume e820 map is sorted */
+ for (i = 0; i < e820.nr_map; i++) {
+ struct e820entry *ei = &e820.map[i];
+ unsigned long start, end;
+
+ start = ei->addr, PAGE_SIZE;
+ end = ei->addr + ei->size;
+ if (start >= end)
+ continue;
+ if (ei->type != E820_ACPI && ei->type != E820_NVS)
+ continue;
+ /*
+ * If the region is below end_pfn, it will be
+ * saved/restored by swsusp follow 'RAM' type.
+ */
+ if (start < (end_pfn << PAGE_SHIFT))
+ start = end_pfn << PAGE_SHIFT;
+ if (end > start)
+ swsusp_add_arch_pages(start, end);
+ }
+}
+
+extern char __start_rodata, __end_rodata;
+/*
+ * BIOS reserved region/hole - no save/restore
+ * ACPI NVS - save/restore
+ * ACPI Data - this is a little tricky, the mem could be used by OS after OS
+ * reads tables from the region, but anyway save/restore the memory hasn't any
+ * side effect and Linux runtime module load/unload might use it.
+ * kernel rodata - no save/restore (kernel rodata isn't changed)
+ */
+static int __init mark_nosave_pages(void)
+{
+ unsigned long pfn_start, pfn_end;
+
+ /* BIOS reserved regions & holes */
+ e820_nosave_reserved_pages();
+
+ /* kernel rodata */
+ pfn_start = round_up(__pa_symbol(&__start_rodata), PAGE_SIZE) >> PAGE_SHIFT;
+ pfn_end = round_down(__pa_symbol(&__end_rodata), PAGE_SIZE) >> PAGE_SHIFT;
+ mark_nosave_page_range(pfn_start, pfn_end-1);
+
+ /* record ACPI Data/NVS as saveable */
+ e820_save_acpi_pages();
+
+ return 0;
+}
+core_initcall(mark_nosave_pages);
+#endif
+
void __init setup_arch(char **cmdline_p)
{
unsigned long kernel_end;
@@ -728,7 +823,7 @@ void __init setup_arch(char **cmdline_p)
#endif
#ifdef CONFIG_KEXEC
if (crashk_res.start != crashk_res.end) {
- reserve_bootmem(crashk_res.start,
+ reserve_bootmem_generic(crashk_res.start,
crashk_res.end - crashk_res.start + 1);
}
#endif
diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c
index 474df22..502fce6 100644
--- a/arch/x86_64/mm/srat.c
+++ b/arch/x86_64/mm/srat.c
@@ -30,7 +30,6 @@
static struct acpi_table_slit *acpi_slit;
static nodemask_t nodes_parsed __initdata;
-static nodemask_t nodes_found __initdata;
static struct bootnode nodes[MAX_NUMNODES] __initdata;
static struct bootnode nodes_add[MAX_NUMNODES] __initdata;
static int found_add_area __initdata;
@@ -38,33 +37,14 @@ int hotadd_percent __initdata = 0;
#ifndef RESERVE_HOTADD
#define hotadd_percent 0 /* Ignore all settings */
#endif
-static u8 pxm2node[256] = { [0 ... 255] = 0xff };
/* Too small nodes confuse the VM badly. Usually they result
from BIOS bugs. */
#define NODE_MIN_SIZE (4*1024*1024)
-static int node_to_pxm(int n);
-
-int pxm_to_node(int pxm)
-{
- if ((unsigned)pxm >= 256)
- return -1;
- /* Extend 0xff to (int)-1 */
- return (signed char)pxm2node[pxm];
-}
-
static __init int setup_node(int pxm)
{
- unsigned node = pxm2node[pxm];
- if (node == 0xff) {
- if (nodes_weight(nodes_found) >= MAX_NUMNODES)
- return -1;
- node = first_unset_node(nodes_found);
- node_set(node, nodes_found);
- pxm2node[pxm] = node;
- }
- return pxm2node[pxm];
+ return acpi_map_pxm_to_node(pxm);
}
static __init int conflicting_nodes(unsigned long start, unsigned long end)
@@ -440,17 +420,6 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
return 0;
}
-static int node_to_pxm(int n)
-{
- int i;
- if (pxm2node[n] == n)
- return n;
- for (i = 0; i < 256; i++)
- if (pxm2node[i] == n)
- return i;
- return 0;
-}
-
void __init srat_reserve_add_area(int nodeid)
{
if (found_add_area && nodes_add[nodeid].end) {
diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c
index a2060e4..3c55c76 100644
--- a/arch/x86_64/pci/mmconfig.c
+++ b/arch/x86_64/pci/mmconfig.c
@@ -13,7 +13,10 @@
#include "pci.h"
-#define MMCONFIG_APER_SIZE (256*1024*1024)
+/* aperture is up to 256MB but BIOS may reserve less */
+#define MMCONFIG_APER_MIN (2 * 1024*1024)
+#define MMCONFIG_APER_MAX (256 * 1024*1024)
+
/* Verify the first 16 busses. We assume that systems with more busses
get MCFG right. */
#define MAX_CHECK_BUS 16
@@ -175,9 +178,10 @@ void __init pci_mmcfg_init(void)
return;
if (!e820_all_mapped(pci_mmcfg_config[0].base_address,
- pci_mmcfg_config[0].base_address + MMCONFIG_APER_SIZE,
+ pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN,
E820_RESERVED)) {
- printk(KERN_ERR "PCI: BIOS Bug: MCFG area is not E820-reserved\n");
+ printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n",
+ pci_mmcfg_config[0].base_address);
printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
return;
}
@@ -190,7 +194,8 @@ void __init pci_mmcfg_init(void)
}
for (i = 0; i < pci_mmcfg_config_num; ++i) {
pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
- pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address, MMCONFIG_APER_SIZE);
+ pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address,
+ MMCONFIG_APER_MAX);
if (!pci_mmcfg_virt[i].virt) {
printk("PCI: Cannot map mmconfig aperture for segment %d\n",
pci_mmcfg_config[i].pci_segment_group_number);
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index dbeb350..848f173 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -34,10 +34,6 @@ config GENERIC_HARDIRQS
bool
default y
-config RWSEM_GENERIC_SPINLOCK
- bool
- default y
-
source "init/Kconfig"
menu "Processor type and features"
diff --git a/arch/xtensa/boot/lib/Makefile b/arch/xtensa/boot/lib/Makefile
index 9e73bb8..d3d2aa2 100644
--- a/arch/xtensa/boot/lib/Makefile
+++ b/arch/xtensa/boot/lib/Makefile
@@ -2,7 +2,7 @@
# Makefile for some libs needed by zImage.
#
-zlib := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c
+zlib := inffast.c inflate.c inftrees.c
lib-y += $(zlib:.c=.o) zmem.o
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index 5c018c5..89e409e 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -1102,7 +1102,7 @@ ENTRY(fast_syscall_sysxtensa)
s32i a7, a2, PT_AREG7
movi a7, 4 # sizeof(unsigned int)
- verify_area a3, a7, a0, a2, .Leac
+ access_ok a0, a3, a7, a2, .Leac
_beqi a6, SYSXTENSA_ATOMIC_SET, .Lset
_beqi a6, SYSXTENSA_ATOMIC_EXG_ADD, .Lexg
diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
index de19501..c6f471b 100644
--- a/arch/xtensa/kernel/pci.c
+++ b/arch/xtensa/kernel/pci.c
@@ -350,17 +350,6 @@ __pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma,
}
/*
- * Set vm_flags of VMA, as appropriate for this architecture, for a pci device
- * mapping.
- */
-static __inline__ void
-__pci_mmap_set_flags(struct pci_dev *dev, struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state)
-{
- vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
-}
-
-/*
* Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
* device mapping.
*/
@@ -399,7 +388,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
if (ret < 0)
return ret;
- __pci_mmap_set_flags(dev, vma, mmap_state);
__pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine);
ret = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c
index e252b61..c494f08 100644
--- a/arch/xtensa/kernel/signal.c
+++ b/arch/xtensa/kernel/signal.c
@@ -104,7 +104,7 @@ sys_sigaction(int sig, const struct old_sigaction *act,
if (act) {
old_sigset_t mask;
- if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+ if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
__get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
return -EFAULT;
@@ -116,7 +116,7 @@ sys_sigaction(int sig, const struct old_sigaction *act,
ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
if (!ret && oact) {
- if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+ if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
__put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
__put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
return -EFAULT;
@@ -236,7 +236,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
err |= __copy_from_user (regs->areg, sc->sc_areg, XCHAL_NUM_AREGS*4);
err |= __get_user(buf, &sc->sc_cpstate);
if (buf) {
- if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
+ if (!access_ok(VERIFY_READ, buf, sizeof(*buf)))
goto badframe;
err |= restore_cpextra(buf);
}
@@ -357,7 +357,7 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs)
if (regs->depc > 64)
panic ("Double exception sys_sigreturn\n");
- if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+ if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
if (__get_user(set.sig[0], &frame->sc.oldmask)
@@ -394,7 +394,7 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
return 0;
}
- if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+ if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
@@ -433,7 +433,7 @@ badframe:
static inline void *
get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
{
- if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp))
+ if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp))
sp = current->sas_ss_sp + current->sas_ss_size;
return (void *)((sp - frame_size) & -16ul);
diff --git a/block/Kconfig.iosched b/block/Kconfig.iosched
index f3b7753..48d090e 100644
--- a/block/Kconfig.iosched
+++ b/block/Kconfig.iosched
@@ -40,7 +40,7 @@ config IOSCHED_CFQ
choice
prompt "Default I/O scheduler"
- default DEFAULT_AS
+ default DEFAULT_CFQ
help
Select the I/O scheduler which will be used by default for all
block devices.
diff --git a/block/as-iosched.c b/block/as-iosched.c
index 0c75039..1ec5df4 100644
--- a/block/as-iosched.c
+++ b/block/as-iosched.c
@@ -96,7 +96,7 @@ struct as_data {
struct as_rq *next_arq[2]; /* next in sort order */
sector_t last_sector[2]; /* last REQ_SYNC & REQ_ASYNC sectors */
- struct list_head *hash; /* request hash */
+ struct hlist_head *hash; /* request hash */
unsigned long exit_prob; /* probability a task will exit while
being waited on */
@@ -165,8 +165,7 @@ struct as_rq {
/*
* request hash, key is the ending offset (for back merge lookup)
*/
- struct list_head hash;
- unsigned int on_hash;
+ struct hlist_node hash;
/*
* expire fifo
@@ -282,17 +281,15 @@ static const int as_hash_shift = 6;
#define AS_HASH_FN(sec) (hash_long(AS_HASH_BLOCK((sec)), as_hash_shift))
#define AS_HASH_ENTRIES (1 << as_hash_shift)
#define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors)
-#define list_entry_hash(ptr) list_entry((ptr), struct as_rq, hash)
static inline void __as_del_arq_hash(struct as_rq *arq)
{
- arq->on_hash = 0;
- list_del_init(&arq->hash);
+ hlist_del_init(&arq->hash);
}
static inline void as_del_arq_hash(struct as_rq *arq)
{
- if (arq->on_hash)
+ if (!hlist_unhashed(&arq->hash))
__as_del_arq_hash(arq);
}
@@ -300,10 +297,9 @@ static void as_add_arq_hash(struct as_data *ad, struct as_rq *arq)
{
struct request *rq = arq->request;
- BUG_ON(arq->on_hash);
+ BUG_ON(!hlist_unhashed(&arq->hash));
- arq->on_hash = 1;
- list_add(&arq->hash, &ad->hash[AS_HASH_FN(rq_hash_key(rq))]);
+ hlist_add_head(&arq->hash, &ad->hash[AS_HASH_FN(rq_hash_key(rq))]);
}
/*
@@ -312,31 +308,29 @@ static void as_add_arq_hash(struct as_data *ad, struct as_rq *arq)
static inline void as_hot_arq_hash(struct as_data *ad, struct as_rq *arq)
{
struct request *rq = arq->request;
- struct list_head *head = &ad->hash[AS_HASH_FN(rq_hash_key(rq))];
+ struct hlist_head *head = &ad->hash[AS_HASH_FN(rq_hash_key(rq))];
- if (!arq->on_hash) {
+ if (hlist_unhashed(&arq->hash)) {
WARN_ON(1);
return;
}
- if (arq->hash.prev != head) {
- list_del(&arq->hash);
- list_add(&arq->hash, head);
+ if (&arq->hash != head->first) {
+ hlist_del(&arq->hash);
+ hlist_add_head(&arq->hash, head);
}
}
static struct request *as_find_arq_hash(struct as_data *ad, sector_t offset)
{
- struct list_head *hash_list = &ad->hash[AS_HASH_FN(offset)];
- struct list_head *entry, *next = hash_list->next;
+ struct hlist_head *hash_list = &ad->hash[AS_HASH_FN(offset)];
+ struct hlist_node *entry, *next;
+ struct as_rq *arq;
- while ((entry = next) != hash_list) {
- struct as_rq *arq = list_entry_hash(entry);
+ hlist_for_each_entry_safe(arq, entry, next, hash_list, hash) {
struct request *__rq = arq->request;
- next = entry->next;
-
- BUG_ON(!arq->on_hash);
+ BUG_ON(hlist_unhashed(&arq->hash));
if (!rq_mergeable(__rq)) {
as_del_arq_hash(arq);
@@ -353,9 +347,6 @@ static struct request *as_find_arq_hash(struct as_data *ad, sector_t offset)
/*
* rb tree support functions
*/
-#define RB_EMPTY(root) ((root)->rb_node == NULL)
-#define ON_RB(node) (rb_parent(node) != node)
-#define RB_CLEAR(node) (rb_set_parent(node, node))
#define rb_entry_arq(node) rb_entry((node), struct as_rq, rb_node)
#define ARQ_RB_ROOT(ad, arq) (&(ad)->sort_list[(arq)->is_sync])
#define rq_rb_key(rq) (rq)->sector
@@ -424,13 +415,13 @@ static void as_add_arq_rb(struct as_data *ad, struct as_rq *arq)
static inline void as_del_arq_rb(struct as_data *ad, struct as_rq *arq)
{
- if (!ON_RB(&arq->rb_node)) {
+ if (!RB_EMPTY_NODE(&arq->rb_node)) {
WARN_ON(1);
return;
}
rb_erase(&arq->rb_node, ARQ_RB_ROOT(ad, arq));
- RB_CLEAR(&arq->rb_node);
+ RB_CLEAR_NODE(&arq->rb_node);
}
static struct request *
@@ -551,7 +542,7 @@ static struct as_rq *as_find_next_arq(struct as_data *ad, struct as_rq *last)
struct rb_node *rbprev = rb_prev(&last->rb_node);
struct as_rq *arq_next, *arq_prev;
- BUG_ON(!ON_RB(&last->rb_node));
+ BUG_ON(!RB_EMPTY_NODE(&last->rb_node));
if (rbprev)
arq_prev = rb_entry_arq(rbprev);
@@ -1128,7 +1119,7 @@ static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq)
struct request *rq = arq->request;
const int data_dir = arq->is_sync;
- BUG_ON(!ON_RB(&arq->rb_node));
+ BUG_ON(!RB_EMPTY_NODE(&arq->rb_node));
as_antic_stop(ad);
ad->antic_status = ANTIC_OFF;
@@ -1253,7 +1244,7 @@ static int as_dispatch_request(request_queue_t *q, int force)
*/
if (reads) {
- BUG_ON(RB_EMPTY(&ad->sort_list[REQ_SYNC]));
+ BUG_ON(RB_EMPTY_ROOT(&ad->sort_list[REQ_SYNC]));
if (writes && ad->batch_data_dir == REQ_SYNC)
/*
@@ -1277,7 +1268,7 @@ static int as_dispatch_request(request_queue_t *q, int force)
if (writes) {
dispatch_writes:
- BUG_ON(RB_EMPTY(&ad->sort_list[REQ_ASYNC]));
+ BUG_ON(RB_EMPTY_ROOT(&ad->sort_list[REQ_ASYNC]));
if (ad->batch_data_dir == REQ_SYNC) {
ad->changed_batch = 1;
@@ -1345,7 +1336,7 @@ static void as_add_request(request_queue_t *q, struct request *rq)
arq->state = AS_RQ_NEW;
if (rq_data_dir(arq->request) == READ
- || current->flags&PF_SYNCWRITE)
+ || (arq->request->flags & REQ_RW_SYNC))
arq->is_sync = 1;
else
arq->is_sync = 0;
@@ -1597,12 +1588,11 @@ static int as_set_request(request_queue_t *q, struct request *rq,
if (arq) {
memset(arq, 0, sizeof(*arq));
- RB_CLEAR(&arq->rb_node);
+ RB_CLEAR_NODE(&arq->rb_node);
arq->request = rq;
arq->state = AS_RQ_PRESCHED;
arq->io_context = NULL;
- INIT_LIST_HEAD(&arq->hash);
- arq->on_hash = 0;
+ INIT_HLIST_NODE(&arq->hash);
INIT_LIST_HEAD(&arq->fifo);
rq->elevator_private = arq;
return 0;
@@ -1662,7 +1652,7 @@ static void *as_init_queue(request_queue_t *q, elevator_t *e)
ad->q = q; /* Identify what queue the data belongs to */
- ad->hash = kmalloc_node(sizeof(struct list_head)*AS_HASH_ENTRIES,
+ ad->hash = kmalloc_node(sizeof(struct hlist_head)*AS_HASH_ENTRIES,
GFP_KERNEL, q->node);
if (!ad->hash) {
kfree(ad);
@@ -1684,7 +1674,7 @@ static void *as_init_queue(request_queue_t *q, elevator_t *e)
INIT_WORK(&ad->antic_work, as_work_handler, q);
for (i = 0; i < AS_HASH_ENTRIES; i++)
- INIT_LIST_HEAD(&ad->hash[i]);
+ INIT_HLIST_HEAD(&ad->hash[i]);
INIT_LIST_HEAD(&ad->fifo_list[REQ_SYNC]);
INIT_LIST_HEAD(&ad->fifo_list[REQ_ASYNC]);
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index e2e6ad0..e25223e 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -26,7 +26,7 @@ static const int cfq_back_penalty = 2; /* penalty of a backwards seek */
static const int cfq_slice_sync = HZ / 10;
static int cfq_slice_async = HZ / 25;
static const int cfq_slice_async_rq = 2;
-static int cfq_slice_idle = HZ / 70;
+static int cfq_slice_idle = HZ / 125;
#define CFQ_IDLE_GRACE (HZ / 10)
#define CFQ_SLICE_SCALE (5)
@@ -60,11 +60,6 @@ static DEFINE_SPINLOCK(cfq_exit_lock);
/*
* rb-tree defines
*/
-#define RB_EMPTY(node) ((node)->rb_node == NULL)
-#define RB_CLEAR(node) do { \
- memset(node, 0, sizeof(*node)); \
-} while (0)
-#define RB_CLEAR_ROOT(root) ((root)->rb_node = NULL)
#define rb_entry_crq(node) rb_entry((node), struct cfq_rq, rb_node)
#define rq_rb_key(rq) (rq)->sector
@@ -123,8 +118,6 @@ struct cfq_data {
*/
struct hlist_head *crq_hash;
- unsigned int max_queued;
-
mempool_t *crq_pool;
int rq_in_driver;
@@ -279,8 +272,6 @@ static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsi
static void cfq_dispatch_insert(request_queue_t *, struct cfq_rq *);
static struct cfq_queue *cfq_get_queue(struct cfq_data *cfqd, unsigned int key, struct task_struct *tsk, gfp_t gfp_mask);
-#define process_sync(tsk) ((tsk)->flags & PF_SYNCWRITE)
-
/*
* lots of deadline iosched dupes, can be abstracted later...
*/
@@ -336,7 +327,7 @@ static int cfq_queue_empty(request_queue_t *q)
static inline pid_t cfq_queue_pid(struct task_struct *task, int rw)
{
- if (rw == READ || process_sync(task))
+ if (rw == READ || rw == WRITE_SYNC)
return task->pid;
return CFQ_KEY_ASYNC;
@@ -563,7 +554,7 @@ static inline void cfq_del_crq_rb(struct cfq_rq *crq)
rb_erase(&crq->rb_node, &cfqq->sort_list);
- if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY(&cfqq->sort_list))
+ if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY_ROOT(&cfqq->sort_list))
cfq_del_cfqq_rr(cfqd, cfqq);
}
@@ -910,13 +901,15 @@ static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd)
return cfqq;
}
+#define CIC_SEEKY(cic) ((cic)->seek_mean > (128 * 1024))
+
static int cfq_arm_slice_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
struct cfq_io_context *cic;
unsigned long sl;
- WARN_ON(!RB_EMPTY(&cfqq->sort_list));
+ WARN_ON(!RB_EMPTY_ROOT(&cfqq->sort_list));
WARN_ON(cfqq != cfqd->active_queue);
/*
@@ -943,7 +936,7 @@ static int cfq_arm_slice_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq)
* fair distribution of slice time for a process doing back-to-back
* seeks. so allow a little bit of time for him to submit a new rq
*/
- if (sample_valid(cic->seek_samples) && cic->seek_mean > 131072)
+ if (sample_valid(cic->seek_samples) && CIC_SEEKY(cic))
sl = 2;
mod_timer(&cfqd->idle_slice_timer, jiffies + sl);
@@ -954,11 +947,15 @@ static void cfq_dispatch_insert(request_queue_t *q, struct cfq_rq *crq)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
struct cfq_queue *cfqq = crq->cfq_queue;
+ struct request *rq;
cfqq->next_crq = cfq_find_next_crq(cfqd, cfqq, crq);
cfq_remove_request(crq->request);
cfqq->on_dispatch[cfq_crq_is_sync(crq)]++;
elv_dispatch_sort(q, crq->request);
+
+ rq = list_entry(q->queue_head.prev, struct request, queuelist);
+ cfqd->last_sector = rq->sector + rq->nr_sectors;
}
/*
@@ -1040,10 +1037,12 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
* if queue has requests, dispatch one. if not, check if
* enough slice is left to wait for one
*/
- if (!RB_EMPTY(&cfqq->sort_list))
+ if (!RB_EMPTY_ROOT(&cfqq->sort_list))
goto keep_queue;
- else if (cfq_cfqq_class_sync(cfqq) &&
- time_before(now, cfqq->slice_end)) {
+ else if (cfq_cfqq_dispatched(cfqq)) {
+ cfqq = NULL;
+ goto keep_queue;
+ } else if (cfq_cfqq_class_sync(cfqq)) {
if (cfq_arm_slice_timer(cfqd, cfqq))
return NULL;
}
@@ -1062,7 +1061,7 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
{
int dispatched = 0;
- BUG_ON(RB_EMPTY(&cfqq->sort_list));
+ BUG_ON(RB_EMPTY_ROOT(&cfqq->sort_list));
do {
struct cfq_rq *crq;
@@ -1086,14 +1085,13 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
cfqd->active_cic = crq->io_context;
}
- if (RB_EMPTY(&cfqq->sort_list))
+ if (RB_EMPTY_ROOT(&cfqq->sort_list))
break;
} while (dispatched < max_dispatch);
/*
- * if slice end isn't set yet, set it. if at least one request was
- * sync, use the sync time slice value
+ * if slice end isn't set yet, set it.
*/
if (!cfqq->slice_end)
cfq_set_prio_slice(cfqd, cfqq);
@@ -1104,7 +1102,8 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
*/
if ((!cfq_cfqq_sync(cfqq) &&
cfqd->dispatch_slice >= cfq_prio_to_maxrq(cfqd, cfqq)) ||
- cfq_class_idle(cfqq))
+ cfq_class_idle(cfqq) ||
+ !cfq_cfqq_idle_window(cfqq))
cfq_slice_expired(cfqd, 0);
return dispatched;
@@ -1113,10 +1112,11 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
static int
cfq_forced_dispatch_cfqqs(struct list_head *list)
{
- int dispatched = 0;
struct cfq_queue *cfqq, *next;
struct cfq_rq *crq;
+ int dispatched;
+ dispatched = 0;
list_for_each_entry_safe(cfqq, next, list, cfq_list) {
while ((crq = cfqq->next_crq)) {
cfq_dispatch_insert(cfqq->cfqd->queue, crq);
@@ -1124,6 +1124,7 @@ cfq_forced_dispatch_cfqqs(struct list_head *list)
}
BUG_ON(!list_empty(&cfqq->fifo));
}
+
return dispatched;
}
@@ -1150,7 +1151,8 @@ static int
cfq_dispatch_requests(request_queue_t *q, int force)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
- struct cfq_queue *cfqq;
+ struct cfq_queue *cfqq, *prev_cfqq;
+ int dispatched;
if (!cfqd->busy_queues)
return 0;
@@ -1158,10 +1160,17 @@ cfq_dispatch_requests(request_queue_t *q, int force)
if (unlikely(force))
return cfq_forced_dispatch(cfqd);
- cfqq = cfq_select_queue(cfqd);
- if (cfqq) {
+ dispatched = 0;
+ prev_cfqq = NULL;
+ while ((cfqq = cfq_select_queue(cfqd)) != NULL) {
int max_dispatch;
+ /*
+ * Don't repeat dispatch from the previous queue.
+ */
+ if (prev_cfqq == cfqq)
+ break;
+
cfq_clear_cfqq_must_dispatch(cfqq);
cfq_clear_cfqq_wait_request(cfqq);
del_timer(&cfqd->idle_slice_timer);
@@ -1170,10 +1179,19 @@ cfq_dispatch_requests(request_queue_t *q, int force)
if (cfq_class_idle(cfqq))
max_dispatch = 1;
- return __cfq_dispatch_requests(cfqd, cfqq, max_dispatch);
+ dispatched += __cfq_dispatch_requests(cfqd, cfqq, max_dispatch);
+
+ /*
+ * If the dispatch cfqq has idling enabled and is still
+ * the active queue, break out.
+ */
+ if (cfq_cfqq_idle_window(cfqq) && cfqd->active_queue)
+ break;
+
+ prev_cfqq = cfqq;
}
- return 0;
+ return dispatched;
}
/*
@@ -1379,25 +1397,28 @@ static inline void changed_ioprio(struct cfq_io_context *cic)
{
struct cfq_data *cfqd = cic->key;
struct cfq_queue *cfqq;
- if (cfqd) {
- spin_lock(cfqd->queue->queue_lock);
- cfqq = cic->cfqq[ASYNC];
- if (cfqq) {
- struct cfq_queue *new_cfqq;
- new_cfqq = cfq_get_queue(cfqd, CFQ_KEY_ASYNC,
- cic->ioc->task, GFP_ATOMIC);
- if (new_cfqq) {
- cic->cfqq[ASYNC] = new_cfqq;
- cfq_put_queue(cfqq);
- }
- }
- cfqq = cic->cfqq[SYNC];
- if (cfqq) {
- cfq_mark_cfqq_prio_changed(cfqq);
- cfq_init_prio_data(cfqq);
+
+ if (unlikely(!cfqd))
+ return;
+
+ spin_lock(cfqd->queue->queue_lock);
+
+ cfqq = cic->cfqq[ASYNC];
+ if (cfqq) {
+ struct cfq_queue *new_cfqq;
+ new_cfqq = cfq_get_queue(cfqd, CFQ_KEY_ASYNC, cic->ioc->task,
+ GFP_ATOMIC);
+ if (new_cfqq) {
+ cic->cfqq[ASYNC] = new_cfqq;
+ cfq_put_queue(cfqq);
}
- spin_unlock(cfqd->queue->queue_lock);
}
+
+ cfqq = cic->cfqq[SYNC];
+ if (cfqq)
+ cfq_mark_cfqq_prio_changed(cfqq);
+
+ spin_unlock(cfqd->queue->queue_lock);
}
/*
@@ -1454,7 +1475,6 @@ retry:
INIT_HLIST_NODE(&cfqq->cfq_hash);
INIT_LIST_HEAD(&cfqq->cfq_list);
- RB_CLEAR_ROOT(&cfqq->sort_list);
INIT_LIST_HEAD(&cfqq->fifo);
cfqq->key = key;
@@ -1466,8 +1486,7 @@ retry:
* set ->slice_left to allow preemption for a new process
*/
cfqq->slice_left = 2 * cfqd->cfq_slice_idle;
- if (!cfqd->hw_tag)
- cfq_mark_cfqq_idle_window(cfqq);
+ cfq_mark_cfqq_idle_window(cfqq);
cfq_mark_cfqq_prio_changed(cfqq);
cfq_init_prio_data(cfqq);
}
@@ -1658,7 +1677,8 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
{
int enable_idle = cfq_cfqq_idle_window(cfqq);
- if (!cic->ioc->task || !cfqd->cfq_slice_idle || cfqd->hw_tag)
+ if (!cic->ioc->task || !cfqd->cfq_slice_idle ||
+ (cfqd->hw_tag && CIC_SEEKY(cic)))
enable_idle = 0;
else if (sample_valid(cic->ttime_samples)) {
if (cic->ttime_mean > cfqd->cfq_slice_idle)
@@ -1688,7 +1708,7 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
return 0;
if (!cfqq)
- return 1;
+ return 0;
if (cfq_class_idle(cfqq))
return 1;
@@ -1720,7 +1740,7 @@ static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
cfqq->slice_left = cfq_prio_to_slice(cfqd, cfqq) / 2;
cfqq->slice_end = cfqq->slice_left + jiffies;
- __cfq_slice_expired(cfqd, cfqq, 1);
+ cfq_slice_expired(cfqd, 1);
__cfq_set_active_queue(cfqd, cfqq);
}
@@ -1745,11 +1765,7 @@ static void
cfq_crq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
struct cfq_rq *crq)
{
- struct cfq_io_context *cic;
-
- cfqq->next_crq = cfq_choose_req(cfqd, cfqq->next_crq, crq);
-
- cic = crq->io_context;
+ struct cfq_io_context *cic = crq->io_context;
/*
* we never wait for an async request and we don't allow preemption
@@ -1839,11 +1855,23 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq)
cfqq->service_last = now;
cfq_resort_rr_list(cfqq, 0);
}
- cfq_schedule_dispatch(cfqd);
}
- if (cfq_crq_is_sync(crq))
+ if (sync)
crq->io_context->last_end_request = now;
+
+ /*
+ * If this is the active queue, check if it needs to be expired,
+ * or if we want to idle in case it has no pending requests.
+ */
+ if (cfqd->active_queue == cfqq) {
+ if (time_after(now, cfqq->slice_end))
+ cfq_slice_expired(cfqd, 0);
+ else if (sync && RB_EMPTY_ROOT(&cfqq->sort_list)) {
+ if (!cfq_arm_slice_timer(cfqd, cfqq))
+ cfq_schedule_dispatch(cfqd);
+ }
+ }
}
static struct request *
@@ -1910,7 +1938,6 @@ static inline int
__cfq_may_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq,
struct task_struct *task, int rw)
{
-#if 1
if ((cfq_cfqq_wait_request(cfqq) || cfq_cfqq_must_alloc(cfqq)) &&
!cfq_cfqq_must_alloc_slice(cfqq)) {
cfq_mark_cfqq_must_alloc_slice(cfqq);
@@ -1918,39 +1945,6 @@ __cfq_may_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq,
}
return ELV_MQUEUE_MAY;
-#else
- if (!cfqq || task->flags & PF_MEMALLOC)
- return ELV_MQUEUE_MAY;
- if (!cfqq->allocated[rw] || cfq_cfqq_must_alloc(cfqq)) {
- if (cfq_cfqq_wait_request(cfqq))
- return ELV_MQUEUE_MUST;
-
- /*
- * only allow 1 ELV_MQUEUE_MUST per slice, otherwise we
- * can quickly flood the queue with writes from a single task
- */
- if (rw == READ || !cfq_cfqq_must_alloc_slice(cfqq)) {
- cfq_mark_cfqq_must_alloc_slice(cfqq);
- return ELV_MQUEUE_MUST;
- }
-
- return ELV_MQUEUE_MAY;
- }
- if (cfq_class_idle(cfqq))
- return ELV_MQUEUE_NO;
- if (cfqq->allocated[rw] >= cfqd->max_queued) {
- struct io_context *ioc = get_io_context(GFP_ATOMIC);
- int ret = ELV_MQUEUE_NO;
-
- if (ioc && ioc->nr_batch_requests)
- ret = ELV_MQUEUE_MAY;
-
- put_io_context(ioc);
- return ret;
- }
-
- return ELV_MQUEUE_MAY;
-#endif
}
static int cfq_may_queue(request_queue_t *q, int rw, struct bio *bio)
@@ -1979,16 +1973,13 @@ static int cfq_may_queue(request_queue_t *q, int rw, struct bio *bio)
static void cfq_check_waiters(request_queue_t *q, struct cfq_queue *cfqq)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
- struct request_list *rl = &q->rq;
- if (cfqq->allocated[READ] <= cfqd->max_queued || cfqd->rq_starved) {
+ if (unlikely(cfqd->rq_starved)) {
+ struct request_list *rl = &q->rq;
+
smp_mb();
if (waitqueue_active(&rl->wait[READ]))
wake_up(&rl->wait[READ]);
- }
-
- if (cfqq->allocated[WRITE] <= cfqd->max_queued || cfqd->rq_starved) {
- smp_mb();
if (waitqueue_active(&rl->wait[WRITE]))
wake_up(&rl->wait[WRITE]);
}
@@ -2062,7 +2053,7 @@ cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
crq = mempool_alloc(cfqd->crq_pool, gfp_mask);
if (crq) {
- RB_CLEAR(&crq->rb_node);
+ RB_CLEAR_NODE(&crq->rb_node);
crq->rb_key = 0;
crq->request = rq;
INIT_HLIST_NODE(&crq->hash);
@@ -2148,16 +2139,13 @@ static void cfq_idle_slice_timer(unsigned long data)
* only expire and reinvoke request handler, if there are
* other queues with pending requests
*/
- if (!cfqd->busy_queues) {
- cfqd->idle_slice_timer.expires = min(now + cfqd->cfq_slice_idle, cfqq->slice_end);
- add_timer(&cfqd->idle_slice_timer);
+ if (!cfqd->busy_queues)
goto out_cont;
- }
/*
* not expired and it has a request pending, let it dispatch
*/
- if (!RB_EMPTY(&cfqq->sort_list)) {
+ if (!RB_EMPTY_ROOT(&cfqq->sort_list)) {
cfq_mark_cfqq_must_dispatch(cfqq);
goto out_kick;
}
@@ -2278,9 +2266,6 @@ static void *cfq_init_queue(request_queue_t *q, elevator_t *e)
cfqd->queue = q;
- cfqd->max_queued = q->nr_requests / 4;
- q->nr_batching = cfq_queued;
-
init_timer(&cfqd->idle_slice_timer);
cfqd->idle_slice_timer.function = cfq_idle_slice_timer;
cfqd->idle_slice_timer.data = (unsigned long) cfqd;
diff --git a/block/deadline-iosched.c b/block/deadline-iosched.c
index c94de8e..4469dd8 100644
--- a/block/deadline-iosched.c
+++ b/block/deadline-iosched.c
@@ -30,8 +30,7 @@ static const int deadline_hash_shift = 5;
#define DL_HASH_FN(sec) (hash_long(DL_HASH_BLOCK((sec)), deadline_hash_shift))
#define DL_HASH_ENTRIES (1 << deadline_hash_shift)
#define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors)
-#define list_entry_hash(ptr) list_entry((ptr), struct deadline_rq, hash)
-#define ON_HASH(drq) (drq)->on_hash
+#define ON_HASH(drq) (!hlist_unhashed(&(drq)->hash))
struct deadline_data {
/*
@@ -48,7 +47,7 @@ struct deadline_data {
* next in sort order. read, write or both are NULL
*/
struct deadline_rq *next_drq[2];
- struct list_head *hash; /* request hash */
+ struct hlist_head *hash; /* request hash */
unsigned int batching; /* number of sequential requests made */
sector_t last_sector; /* head position */
unsigned int starved; /* times reads have starved writes */
@@ -79,8 +78,7 @@ struct deadline_rq {
/*
* request hash, key is the ending offset (for back merge lookup)
*/
- struct list_head hash;
- char on_hash;
+ struct hlist_node hash;
/*
* expire fifo
@@ -100,8 +98,7 @@ static kmem_cache_t *drq_pool;
*/
static inline void __deadline_del_drq_hash(struct deadline_rq *drq)
{
- drq->on_hash = 0;
- list_del_init(&drq->hash);
+ hlist_del_init(&drq->hash);
}
static inline void deadline_del_drq_hash(struct deadline_rq *drq)
@@ -117,8 +114,7 @@ deadline_add_drq_hash(struct deadline_data *dd, struct deadline_rq *drq)
BUG_ON(ON_HASH(drq));
- drq->on_hash = 1;
- list_add(&drq->hash, &dd->hash[DL_HASH_FN(rq_hash_key(rq))]);
+ hlist_add_head(&drq->hash, &dd->hash[DL_HASH_FN(rq_hash_key(rq))]);
}
/*
@@ -128,26 +124,24 @@ static inline void
deadline_hot_drq_hash(struct deadline_data *dd, struct deadline_rq *drq)
{
struct request *rq = drq->request;
- struct list_head *head = &dd->hash[DL_HASH_FN(rq_hash_key(rq))];
+ struct hlist_head *head = &dd->hash[DL_HASH_FN(rq_hash_key(rq))];
- if (ON_HASH(drq) && drq->hash.prev != head) {
- list_del(&drq->hash);
- list_add(&drq->hash, head);
+ if (ON_HASH(drq) && &drq->hash != head->first) {
+ hlist_del(&drq->hash);
+ hlist_add_head(&drq->hash, head);
}
}
static struct request *
deadline_find_drq_hash(struct deadline_data *dd, sector_t offset)
{
- struct list_head *hash_list = &dd->hash[DL_HASH_FN(offset)];
- struct list_head *entry, *next = hash_list->next;
+ struct hlist_head *hash_list = &dd->hash[DL_HASH_FN(offset)];
+ struct hlist_node *entry, *next;
+ struct deadline_rq *drq;
- while ((entry = next) != hash_list) {
- struct deadline_rq *drq = list_entry_hash(entry);
+ hlist_for_each_entry_safe(drq, entry, next, hash_list, hash) {
struct request *__rq = drq->request;
- next = entry->next;
-
BUG_ON(!ON_HASH(drq));
if (!rq_mergeable(__rq)) {
@@ -165,9 +159,6 @@ deadline_find_drq_hash(struct deadline_data *dd, sector_t offset)
/*
* rb tree support functions
*/
-#define RB_EMPTY(root) ((root)->rb_node == NULL)
-#define ON_RB(node) (rb_parent(node) != node)
-#define RB_CLEAR(node) (rb_set_parent(node, node))
#define rb_entry_drq(node) rb_entry((node), struct deadline_rq, rb_node)
#define DRQ_RB_ROOT(dd, drq) (&(dd)->sort_list[rq_data_dir((drq)->request)])
#define rq_rb_key(rq) (rq)->sector
@@ -226,9 +217,9 @@ deadline_del_drq_rb(struct deadline_data *dd, struct deadline_rq *drq)
dd->next_drq[data_dir] = rb_entry_drq(rbnext);
}
- BUG_ON(!ON_RB(&drq->rb_node));
+ BUG_ON(!RB_EMPTY_NODE(&drq->rb_node));
rb_erase(&drq->rb_node, DRQ_RB_ROOT(dd, drq));
- RB_CLEAR(&drq->rb_node);
+ RB_CLEAR_NODE(&drq->rb_node);
}
static struct request *
@@ -502,7 +493,7 @@ static int deadline_dispatch_requests(request_queue_t *q, int force)
*/
if (reads) {
- BUG_ON(RB_EMPTY(&dd->sort_list[READ]));
+ BUG_ON(RB_EMPTY_ROOT(&dd->sort_list[READ]));
if (writes && (dd->starved++ >= dd->writes_starved))
goto dispatch_writes;
@@ -518,7 +509,7 @@ static int deadline_dispatch_requests(request_queue_t *q, int force)
if (writes) {
dispatch_writes:
- BUG_ON(RB_EMPTY(&dd->sort_list[WRITE]));
+ BUG_ON(RB_EMPTY_ROOT(&dd->sort_list[WRITE]));
dd->starved = 0;
@@ -625,7 +616,7 @@ static void *deadline_init_queue(request_queue_t *q, elevator_t *e)
return NULL;
memset(dd, 0, sizeof(*dd));
- dd->hash = kmalloc_node(sizeof(struct list_head)*DL_HASH_ENTRIES,
+ dd->hash = kmalloc_node(sizeof(struct hlist_head)*DL_HASH_ENTRIES,
GFP_KERNEL, q->node);
if (!dd->hash) {
kfree(dd);
@@ -641,7 +632,7 @@ static void *deadline_init_queue(request_queue_t *q, elevator_t *e)
}
for (i = 0; i < DL_HASH_ENTRIES; i++)
- INIT_LIST_HEAD(&dd->hash[i]);
+ INIT_HLIST_HEAD(&dd->hash[i]);
INIT_LIST_HEAD(&dd->fifo_list[READ]);
INIT_LIST_HEAD(&dd->fifo_list[WRITE]);
@@ -674,11 +665,10 @@ deadline_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
drq = mempool_alloc(dd->drq_pool, gfp_mask);
if (drq) {
memset(drq, 0, sizeof(*drq));
- RB_CLEAR(&drq->rb_node);
+ RB_CLEAR_NODE(&drq->rb_node);
drq->request = rq;
- INIT_LIST_HEAD(&drq->hash);
- drq->on_hash = 0;
+ INIT_HLIST_NODE(&drq->hash);
INIT_LIST_HEAD(&drq->fifo);
diff --git a/block/elevator.c b/block/elevator.c
index a0afdd3..d00b283 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -850,12 +850,9 @@ fail_register:
* one again (along with re-adding the sysfs dir)
*/
elevator_exit(e);
- e = NULL;
q->elevator = old_elevator;
elv_register_queue(q);
clear_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags);
- if (e)
- kobject_put(&e->kobj);
return 0;
}
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index 7eb36c5..0603ab2 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -638,7 +638,7 @@ void blk_queue_bounce_limit(request_queue_t *q, u64 dma_addr)
/* Assume anything <= 4GB can be handled by IOMMU.
Actually some IOMMUs can handle everything, but I don't
know of a way to test this here. */
- if (bounce_pfn < (0xffffffff>>PAGE_SHIFT))
+ if (bounce_pfn < (min_t(u64,0xffffffff,BLK_BOUNCE_HIGH) >> PAGE_SHIFT))
dma = 1;
q->bounce_pfn = max_low_pfn;
#else
@@ -1663,6 +1663,8 @@ static void blk_unplug_timeout(unsigned long data)
**/
void blk_start_queue(request_queue_t *q)
{
+ WARN_ON(!irqs_disabled());
+
clear_bit(QUEUE_FLAG_STOPPED, &q->queue_flags);
/*
@@ -1878,7 +1880,8 @@ EXPORT_SYMBOL(blk_alloc_queue_node);
* get dealt with eventually.
*
* The queue spin lock must be held while manipulating the requests on the
- * request queue.
+ * request queue; this lock will be taken also from interrupt context, so irq
+ * disabling is needed for it.
*
* Function returns a pointer to the initialized request queue, or NULL if
* it didn't succeed.
@@ -2824,6 +2827,9 @@ static void init_request_from_bio(struct request *req, struct bio *bio)
if (unlikely(bio_barrier(bio)))
req->flags |= (REQ_HARDBARRIER | REQ_NOMERGE);
+ if (bio_sync(bio))
+ req->flags |= REQ_RW_SYNC;
+
req->errors = 0;
req->hard_sector = req->sector = bio->bi_sector;
req->hard_nr_sectors = req->nr_sectors = bio_sectors(bio);
@@ -3359,12 +3365,11 @@ EXPORT_SYMBOL(end_that_request_chunk);
*/
static void blk_done_softirq(struct softirq_action *h)
{
- struct list_head *cpu_list;
- LIST_HEAD(local_list);
+ struct list_head *cpu_list, local_list;
local_irq_disable();
cpu_list = &__get_cpu_var(blk_cpu_done);
- list_splice_init(cpu_list, &local_list);
+ list_replace_init(cpu_list, &local_list);
local_irq_enable();
while (!list_empty(&local_list)) {
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index c24652d..94b8d82 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -10,9 +10,8 @@ menu "ACPI (Advanced Configuration and Power Interface) Support"
config ACPI
bool "ACPI Support"
depends on IA64 || X86
+ depends on PCI
select PM
- select PCI
-
default y
---help---
Advanced Configuration and Power Interface (ACPI) support for
@@ -162,7 +161,7 @@ config ACPI_THERMAL
config ACPI_NUMA
bool "NUMA support"
depends on NUMA
- depends on (IA64 || X86_64)
+ depends on (X86 || IA64)
default y if IA64_GENERIC || IA64_SGI_SN2
config ACPI_ASUS
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index d882bf8..e0a95ba 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -74,7 +74,7 @@ struct acpi_memory_device {
unsigned short caching; /* memory cache attribute */
unsigned short write_protect; /* memory read/write attribute */
u64 start_addr; /* Memory Range start physical addr */
- u64 end_addr; /* Memory Range end physical addr */
+ u64 length; /* Memory Range length */
};
static int
@@ -97,12 +97,11 @@ acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
if (ACPI_SUCCESS(status)) {
if (address64.resource_type == ACPI_MEMORY_RANGE) {
/* Populate the structure */
- mem_device->caching =
- address64.info.mem.caching;
+ mem_device->caching = address64.info.mem.caching;
mem_device->write_protect =
address64.info.mem.write_protect;
mem_device->start_addr = address64.minimum;
- mem_device->end_addr = address64.maximum;
+ mem_device->length = address64.address_length;
}
}
@@ -199,8 +198,7 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
* Tell the VM there is more memory here...
* Note: Assume that this function returns zero on success
*/
- result = add_memory(mem_device->start_addr,
- (mem_device->end_addr - mem_device->start_addr) + 1);
+ result = add_memory(mem_device->start_addr, mem_device->length);
if (result) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "\nadd_memory failed\n"));
mem_device->state = MEMORY_INVALID_STATE;
@@ -249,7 +247,7 @@ static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)
{
int result;
u64 start = mem_device->start_addr;
- u64 len = mem_device->end_addr - start + 1;
+ u64 len = mem_device->length;
ACPI_FUNCTION_TRACE("acpi_memory_disable_device");
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
index f4c8775..839f423 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/acpi/asus_acpi.c
@@ -817,7 +817,7 @@ typedef int (proc_writefunc) (struct file * file, const char __user * buffer,
unsigned long count, void *data);
static int
-__init asus_proc_add(char *name, proc_writefunc * writefunc,
+asus_proc_add(char *name, proc_writefunc * writefunc,
proc_readfunc * readfunc, mode_t mode,
struct acpi_device *device)
{
@@ -836,7 +836,7 @@ __init asus_proc_add(char *name, proc_writefunc * writefunc,
return 0;
}
-static int __init asus_hotk_add_fs(struct acpi_device *device)
+static int asus_hotk_add_fs(struct acpi_device *device)
{
struct proc_dir_entry *proc;
mode_t mode;
@@ -954,7 +954,7 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
* This function is used to initialize the hotk with right values. In this
* method, we can make all the detection we want, and modify the hotk struct
*/
-static int __init asus_hotk_get_info(void)
+static int asus_hotk_get_info(void)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -970,7 +970,7 @@ static int __init asus_hotk_get_info(void)
* HID), this bit will be moved. A global variable asus_info contains
* the DSDT header.
*/
- status = acpi_get_table(ACPI_TABLE_DSDT, 1, &dsdt);
+ status = acpi_get_table(ACPI_TABLE_ID_DSDT, 1, &dsdt);
if (ACPI_FAILURE(status))
printk(KERN_WARNING " Couldn't get the DSDT table header\n");
else
@@ -1101,7 +1101,7 @@ static int __init asus_hotk_get_info(void)
return AE_OK;
}
-static int __init asus_hotk_check(void)
+static int asus_hotk_check(void)
{
int result = 0;
@@ -1119,7 +1119,9 @@ static int __init asus_hotk_check(void)
return result;
}
-static int __init asus_hotk_add(struct acpi_device *device)
+static int asus_hotk_found;
+
+static int asus_hotk_add(struct acpi_device *device)
{
acpi_status status = AE_OK;
int result;
@@ -1180,6 +1182,8 @@ static int __init asus_hotk_add(struct acpi_device *device)
}
}
+ asus_hotk_found = 1;
+
end:
if (result) {
kfree(hotk);
@@ -1226,12 +1230,24 @@ static int __init asus_acpi_init(void)
asus_proc_dir->owner = THIS_MODULE;
result = acpi_bus_register_driver(&asus_hotk_driver);
- if (result < 1) {
- acpi_bus_unregister_driver(&asus_hotk_driver);
+ if (result < 0) {
remove_proc_entry(PROC_ASUS, acpi_root_dir);
return -ENODEV;
}
+ /*
+ * This is a bit of a kludge. We only want this module loaded
+ * for ASUS systems, but there's currently no way to probe the
+ * ACPI namespace for ASUS HIDs. So we just return failure if
+ * we didn't find one, which will cause the module to be
+ * unloaded.
+ */
+ if (!asus_hotk_found) {
+ acpi_bus_unregister_driver(&asus_hotk_driver);
+ remove_proc_entry(PROC_ASUS, acpi_root_dir);
+ return result;
+ }
+
return 0;
}
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 606f873..dd3983c 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -43,7 +43,7 @@ ACPI_MODULE_NAME("acpi_bus")
extern void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger);
#endif
-FADT_DESCRIPTOR acpi_fadt;
+struct fadt_descriptor acpi_fadt;
EXPORT_SYMBOL(acpi_fadt);
struct acpi_device *acpi_root;
@@ -205,12 +205,14 @@ int acpi_bus_set_power(acpi_handle handle, int state)
* Get device's current power state if it's unknown
* This means device power state isn't initialized or previous setting failed
*/
- if (device->power.state == ACPI_STATE_UNKNOWN)
- acpi_bus_get_power(device->handle, &device->power.state);
- if (state == device->power.state) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
- state));
- return_VALUE(0);
+ if (!device->flags.force_power_state) {
+ if (device->power.state == ACPI_STATE_UNKNOWN)
+ acpi_bus_get_power(device->handle, &device->power.state);
+ if (state == device->power.state) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
+ state));
+ return_VALUE(0);
+ }
}
if (!device->power.states[state].flags.valid) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Device does not support D%d\n",
@@ -596,6 +598,8 @@ void __init acpi_early_init(void)
if (acpi_disabled)
return_VOID;
+ printk(KERN_INFO PREFIX "Core revision %08x\n", ACPI_CA_VERSION);
+
/* enable workarounds, unless strict ACPI spec. compliance */
if (!acpi_strict)
acpi_gbl_enable_interpreter_slack = TRUE;
@@ -617,7 +621,7 @@ void __init acpi_early_init(void)
/*
* Get a separate copy of the FADT for use by other drivers.
*/
- status = acpi_get_table(ACPI_TABLE_FADT, 1, &buffer);
+ status = acpi_get_table(ACPI_TABLE_ID_FADT, 1, &buffer);
if (ACPI_FAILURE(status)) {
printk(KERN_ERR PREFIX "Unable to get the FADT\n");
goto error0;
@@ -743,8 +747,6 @@ static int __init acpi_init(void)
ACPI_FUNCTION_TRACE("acpi_init");
- printk(KERN_INFO PREFIX "Subsystem revision %08x\n", ACPI_CA_VERSION);
-
if (acpi_disabled) {
printk(KERN_INFO PREFIX "Interpreter disabled.\n");
return_VALUE(-ENODEV);
diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c
index 76bc046..a6d77ef 100644
--- a/drivers/acpi/dispatcher/dsfield.c
+++ b/drivers/acpi/dispatcher/dsfield.c
@@ -87,7 +87,7 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op,
union acpi_operand_object *second_desc = NULL;
u32 flags;
- ACPI_FUNCTION_TRACE("ds_create_buffer_field");
+ ACPI_FUNCTION_TRACE(ds_create_buffer_field);
/* Get the name_string argument */
@@ -210,7 +210,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
acpi_status status;
acpi_integer position;
- ACPI_FUNCTION_TRACE_PTR("ds_get_field_names", info);
+ ACPI_FUNCTION_TRACE_PTR(ds_get_field_names, info);
/* First field starts at bit zero */
@@ -342,7 +342,7 @@ acpi_ds_create_field(union acpi_parse_object *op,
union acpi_parse_object *arg;
struct acpi_create_field_info info;
- ACPI_FUNCTION_TRACE_PTR("ds_create_field", op);
+ ACPI_FUNCTION_TRACE_PTR(ds_create_field, op);
/* First arg is the name of the parent op_region (must already exist) */
@@ -399,7 +399,7 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
struct acpi_namespace_node *node;
u8 type = 0;
- ACPI_FUNCTION_TRACE_PTR("ds_init_field_objects", op);
+ ACPI_FUNCTION_TRACE_PTR(ds_init_field_objects, op);
switch (walk_state->opcode) {
case AML_FIELD_OP:
@@ -425,6 +425,7 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
* Walk the list of entries in the field_list
*/
while (arg) {
+
/* Ignore OFFSET and ACCESSAS terms here */
if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
@@ -481,7 +482,7 @@ acpi_ds_create_bank_field(union acpi_parse_object *op,
union acpi_parse_object *arg;
struct acpi_create_field_info info;
- ACPI_FUNCTION_TRACE_PTR("ds_create_bank_field", op);
+ ACPI_FUNCTION_TRACE_PTR(ds_create_bank_field, op);
/* First arg is the name of the parent op_region (must already exist) */
@@ -554,7 +555,7 @@ acpi_ds_create_index_field(union acpi_parse_object *op,
union acpi_parse_object *arg;
struct acpi_create_field_info info;
- ACPI_FUNCTION_TRACE_PTR("ds_create_index_field", op);
+ ACPI_FUNCTION_TRACE_PTR(ds_create_index_field, op);
/* First arg is the name of the Index register (must already exist) */
diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c
index e65a07a..bbdf990 100644
--- a/drivers/acpi/dispatcher/dsinit.c
+++ b/drivers/acpi/dispatcher/dsinit.c
@@ -184,7 +184,7 @@ acpi_ds_init_one_object(acpi_handle obj_handle,
*
* RETURN: Status
*
- * DESCRIPTION: Walk the namespace starting at "start_node" and perform any
+ * DESCRIPTION: Walk the namespace starting at "StartNode" and perform any
* necessary initialization on the objects found therein
*
******************************************************************************/
@@ -196,7 +196,7 @@ acpi_ds_initialize_objects(struct acpi_table_desc * table_desc,
acpi_status status;
struct acpi_init_walk_info info;
- ACPI_FUNCTION_TRACE("ds_initialize_objects");
+ ACPI_FUNCTION_TRACE(ds_initialize_objects);
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"**** Starting initialization of namespace objects ****\n"));
@@ -213,7 +213,7 @@ acpi_ds_initialize_objects(struct acpi_table_desc * table_desc,
status = acpi_walk_namespace(ACPI_TYPE_ANY, start_node, ACPI_UINT32_MAX,
acpi_ds_init_one_object, &info, NULL);
if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "During walk_namespace"));
+ ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace"));
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
index c475546..bc9aca4 100644
--- a/drivers/acpi/dispatcher/dsmethod.c
+++ b/drivers/acpi/dispatcher/dsmethod.c
@@ -81,6 +81,7 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state)
/* Invoke the global exception handler */
if (acpi_gbl_exception_handler) {
+
/* Exit the interpreter, allow handler to execute methods */
acpi_ex_exit_interpreter();
@@ -100,6 +101,7 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state)
}
#ifdef ACPI_DISASSEMBLER
if (ACPI_FAILURE(status)) {
+
/* Display method locals/args if disassembler is present */
acpi_dm_dump_method_info(status, walk_state, walk_state->op);
@@ -132,7 +134,7 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node * method_node,
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE_PTR("ds_begin_method_execution", method_node);
+ ACPI_FUNCTION_TRACE_PTR(ds_begin_method_execution, method_node);
if (!method_node) {
return_ACPI_STATUS(AE_NULL_ENTRY);
@@ -168,11 +170,14 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node * method_node,
/*
* Get a unit from the method semaphore. This releases the
- * interpreter if we block
+ * interpreter if we block (then reacquires it)
*/
status =
acpi_ex_system_wait_semaphore(obj_desc->method.semaphore,
ACPI_WAIT_FOREVER);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
}
/*
@@ -183,7 +188,7 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node * method_node,
if (!obj_desc->method.owner_id) {
status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto cleanup;
}
}
@@ -193,6 +198,14 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node * method_node,
*/
obj_desc->method.thread_count++;
return_ACPI_STATUS(status);
+
+ cleanup:
+ /* On error, must signal the method semaphore if present */
+
+ if (obj_desc->method.semaphore) {
+ (void)acpi_os_signal_semaphore(obj_desc->method.semaphore, 1);
+ }
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
@@ -218,10 +231,10 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
struct acpi_namespace_node *method_node;
struct acpi_walk_state *next_walk_state = NULL;
union acpi_operand_object *obj_desc;
- struct acpi_parameter_info info;
+ struct acpi_evaluate_info *info;
u32 i;
- ACPI_FUNCTION_TRACE_PTR("ds_call_control_method", this_walk_state);
+ ACPI_FUNCTION_TRACE_PTR(ds_call_control_method, this_walk_state);
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"Execute method %p, currentstate=%p\n",
@@ -240,25 +253,31 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
return_ACPI_STATUS(AE_NULL_OBJECT);
}
- /* Init for new method, wait on concurrency semaphore */
+ /* Init for new method, possibly wait on concurrency semaphore */
status = acpi_ds_begin_method_execution(method_node, obj_desc,
this_walk_state->method_node);
if (ACPI_FAILURE(status)) {
- goto cleanup;
+ return_ACPI_STATUS(status);
}
+ /*
+ * 1) Parse the method. All "normal" methods are parsed for each execution.
+ * Internal methods (_OSI, etc.) do not require parsing.
+ */
if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) {
- /* 1) Parse: Create a new walk state for the preempting walk */
+
+ /* Create a new walk state for the parse */
next_walk_state =
acpi_ds_create_walk_state(obj_desc->method.owner_id, op,
obj_desc, NULL);
if (!next_walk_state) {
- return_ACPI_STATUS(AE_NO_MEMORY);
+ status = AE_NO_MEMORY;
+ goto cleanup;
}
- /* Create and init a Root Node */
+ /* Create and init a parse tree root */
op = acpi_ps_create_scope_op();
if (!op) {
@@ -271,17 +290,20 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
obj_desc->method.aml_length,
NULL, 1);
if (ACPI_FAILURE(status)) {
- acpi_ds_delete_walk_state(next_walk_state);
+ acpi_ps_delete_parse_tree(op);
goto cleanup;
}
- /* Begin AML parse */
+ /* Begin AML parse (deletes next_walk_state) */
status = acpi_ps_parse_aml(next_walk_state);
acpi_ps_delete_parse_tree(op);
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
}
- /* 2) Execute: Create a new state for the preempting walk */
+ /* 2) Begin method execution. Create a new walk state */
next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id,
NULL, obj_desc, thread);
@@ -289,6 +311,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
status = AE_NO_MEMORY;
goto cleanup;
}
+
/*
* The resolved arguments were put on the previous walk state's operand
* stack. Operands on the previous walk state stack always
@@ -296,12 +319,24 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
*/
this_walk_state->operands[this_walk_state->num_operands] = NULL;
- info.parameters = &this_walk_state->operands[0];
- info.parameter_type = ACPI_PARAM_ARGS;
+ /*
+ * Allocate and initialize the evaluation information block
+ * TBD: this is somewhat inefficient, should change interface to
+ * ds_init_aml_walk. For now, keeps this struct off the CPU stack
+ */
+ info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
+ if (!info) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ info->parameters = &this_walk_state->operands[0];
+ info->parameter_type = ACPI_PARAM_ARGS;
status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node,
obj_desc->method.aml_start,
- obj_desc->method.aml_length, &info, 3);
+ obj_desc->method.aml_length, info, 3);
+
+ ACPI_FREE(info);
if (ACPI_FAILURE(status)) {
goto cleanup;
}
@@ -323,6 +358,8 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
"Starting nested execution, newstate=%p\n",
next_walk_state));
+ /* Invoke an internal method if necessary */
+
if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) {
status = obj_desc->method.implementation(next_walk_state);
}
@@ -330,16 +367,14 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
return_ACPI_STATUS(status);
cleanup:
- /* Decrement the thread count on the method parse tree */
- if (next_walk_state && (next_walk_state->method_desc)) {
- next_walk_state->method_desc->method.thread_count--;
- }
+ /* On error, we must terminate the method properly */
- /* On error, we must delete the new walk state */
+ acpi_ds_terminate_control_method(obj_desc, next_walk_state);
+ if (next_walk_state) {
+ acpi_ds_delete_walk_state(next_walk_state);
+ }
- acpi_ds_terminate_control_method(next_walk_state);
- acpi_ds_delete_walk_state(next_walk_state);
return_ACPI_STATUS(status);
}
@@ -362,25 +397,33 @@ acpi_ds_restart_control_method(struct acpi_walk_state *walk_state,
union acpi_operand_object *return_desc)
{
acpi_status status;
+ int same_as_implicit_return;
- ACPI_FUNCTION_TRACE_PTR("ds_restart_control_method", walk_state);
+ ACPI_FUNCTION_TRACE_PTR(ds_restart_control_method, walk_state);
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "****Restart [%4.4s] Op %p return_value_from_callee %p\n",
+ "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
(char *)&walk_state->method_node->name,
walk_state->method_call_op, return_desc));
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- " return_from_this_method_used?=%X res_stack %p Walk %p\n",
+ " ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n",
walk_state->return_used,
walk_state->results, walk_state));
/* Did the called method return a value? */
if (return_desc) {
+
+ /* Is the implicit return object the same as the return desc? */
+
+ same_as_implicit_return =
+ (walk_state->implicit_return_obj == return_desc);
+
/* Are we actually going to use the return value? */
if (walk_state->return_used) {
+
/* Save the return value from the previous method */
status = acpi_ds_result_push(return_desc, walk_state);
@@ -397,18 +440,23 @@ acpi_ds_restart_control_method(struct acpi_walk_state *walk_state,
}
/*
- * The following code is the
- * optional support for a so-called "implicit return". Some AML code
- * assumes that the last value of the method is "implicitly" returned
- * to the caller. Just save the last result as the return value.
+ * The following code is the optional support for the so-called
+ * "implicit return". Some AML code assumes that the last value of the
+ * method is "implicitly" returned to the caller, in the absence of an
+ * explicit return value.
+ *
+ * Just save the last result of the method as the return value.
+ *
* NOTE: this is optional because the ASL language does not actually
* support this behavior.
*/
else if (!acpi_ds_do_implicit_return
- (return_desc, walk_state, FALSE)) {
+ (return_desc, walk_state, FALSE)
+ || same_as_implicit_return) {
/*
* Delete the return value if it will not be used by the
- * calling method
+ * calling method or remove one reference if the explicit return
+ * is the same as the implicit return value.
*/
acpi_ut_remove_reference(return_desc);
}
@@ -421,7 +469,8 @@ acpi_ds_restart_control_method(struct acpi_walk_state *walk_state,
*
* FUNCTION: acpi_ds_terminate_control_method
*
- * PARAMETERS: walk_state - State of the method
+ * PARAMETERS: method_desc - Method object
+ * walk_state - State associated with the method
*
* RETURN: None
*
@@ -431,95 +480,100 @@ acpi_ds_restart_control_method(struct acpi_walk_state *walk_state,
*
******************************************************************************/
-void acpi_ds_terminate_control_method(struct acpi_walk_state *walk_state)
+void
+acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
+ struct acpi_walk_state *walk_state)
{
- union acpi_operand_object *obj_desc;
struct acpi_namespace_node *method_node;
acpi_status status;
- ACPI_FUNCTION_TRACE_PTR("ds_terminate_control_method", walk_state);
+ ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state);
- if (!walk_state) {
- return_VOID;
- }
+ /* method_desc is required, walk_state is optional */
- /* The current method object was saved in the walk state */
-
- obj_desc = walk_state->method_desc;
- if (!obj_desc) {
+ if (!method_desc) {
return_VOID;
}
- /* Delete all arguments and locals */
+ if (walk_state) {
- acpi_ds_method_data_delete_all(walk_state);
+ /* Delete all arguments and locals */
+
+ acpi_ds_method_data_delete_all(walk_state);
+ }
/*
* Lock the parser while we terminate this method.
* If this is the last thread executing the method,
* we have additional cleanup to perform
*/
- status = acpi_ut_acquire_mutex(ACPI_MTX_PARSER);
+ status = acpi_ut_acquire_mutex(ACPI_MTX_CONTROL_METHOD);
if (ACPI_FAILURE(status)) {
return_VOID;
}
/* Signal completion of the execution of this method if necessary */
- if (walk_state->method_desc->method.semaphore) {
+ if (method_desc->method.semaphore) {
status =
- acpi_os_signal_semaphore(walk_state->method_desc->method.
- semaphore, 1);
+ acpi_os_signal_semaphore(method_desc->method.semaphore, 1);
if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Could not signal method semaphore"));
- /* Ignore error and continue cleanup */
+ /* Ignore error and continue */
+
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Could not signal method semaphore"));
}
}
- /*
- * There are no more threads executing this method. Perform
- * additional cleanup.
- *
- * The method Node is stored in the walk state
- */
- method_node = walk_state->method_node;
+ if (walk_state) {
+ /*
+ * Delete any objects created by this method during execution.
+ * The method Node is stored in the walk state
+ */
+ method_node = walk_state->method_node;
- /* Lock namespace for possible update */
+ /* Lock namespace for possible update */
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- goto exit;
- }
+ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
- /*
- * Delete any namespace entries created immediately underneath
- * the method
- */
- if (method_node->child) {
- acpi_ns_delete_namespace_subtree(method_node);
+ /*
+ * Delete any namespace entries created immediately underneath
+ * the method
+ */
+ if (method_node && method_node->child) {
+ acpi_ns_delete_namespace_subtree(method_node);
+ }
+
+ /*
+ * Delete any namespace entries created anywhere else within
+ * the namespace by the execution of this method
+ */
+ acpi_ns_delete_namespace_by_owner(method_desc->method.owner_id);
+ status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
}
- /*
- * Delete any namespace entries created anywhere else within
- * the namespace by the execution of this method
- */
- acpi_ns_delete_namespace_by_owner(walk_state->method_desc->method.
- owner_id);
- status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+ /* Decrement the thread count on the method */
+
+ if (method_desc->method.thread_count) {
+ method_desc->method.thread_count--;
+ } else {
+ ACPI_ERROR((AE_INFO, "Invalid zero thread count in method"));
+ }
/* Are there any other threads currently executing this method? */
- if (walk_state->method_desc->method.thread_count) {
+ if (method_desc->method.thread_count) {
/*
* Additional threads. Do not release the owner_id in this case,
* we immediately reuse it for the next thread executing this method
*/
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"*** Completed execution of one thread, %d threads remaining\n",
- walk_state->method_desc->method.
- thread_count));
+ method_desc->method.thread_count));
} else {
/* This is the only executing thread for this method */
@@ -533,22 +587,20 @@ void acpi_ds_terminate_control_method(struct acpi_walk_state *walk_state)
* This code is here because we must wait until the last thread exits
* before creating the synchronization semaphore.
*/
- if ((walk_state->method_desc->method.concurrency == 1) &&
- (!walk_state->method_desc->method.semaphore)) {
+ if ((method_desc->method.concurrency == 1) &&
+ (!method_desc->method.semaphore)) {
status = acpi_os_create_semaphore(1, 1,
- &walk_state->
- method_desc->method.
+ &method_desc->method.
semaphore);
}
/* No more threads, we can free the owner_id */
- acpi_ut_release_owner_id(&walk_state->method_desc->method.
- owner_id);
+ acpi_ut_release_owner_id(&method_desc->method.owner_id);
}
exit:
- (void)acpi_ut_release_mutex(ACPI_MTX_PARSER);
+ (void)acpi_ut_release_mutex(ACPI_MTX_CONTROL_METHOD);
return_VOID;
}
@@ -581,7 +633,7 @@ acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node)
union acpi_parse_object *op;
struct acpi_walk_state *walk_state;
- ACPI_FUNCTION_TRACE_PTR("ds_parse_method", node);
+ ACPI_FUNCTION_TRACE_PTR(ds_parse_method, node);
/* Parameter Validation */
@@ -590,7 +642,7 @@ acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node)
}
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "**** Parsing [%4.4s] **** named_obj=%p\n",
+ "**** Parsing [%4.4s] **** NamedObj=%p\n",
acpi_ut_get_node_name(node), node));
/* Extract the method object from the method Node */
@@ -669,7 +721,7 @@ acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node)
}
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "**** [%4.4s] Parsed **** named_obj=%p Op=%p\n",
+ "**** [%4.4s] Parsed **** NamedObj=%p Op=%p\n",
acpi_ut_get_node_name(node), node, op));
/*
diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c
index c025674..459160f 100644
--- a/drivers/acpi/dispatcher/dsmthdat.c
+++ b/drivers/acpi/dispatcher/dsmthdat.c
@@ -81,7 +81,7 @@ acpi_ds_method_data_get_type(u16 opcode,
* special data types.
*
* NOTES: walk_state fields are initialized to zero by the
- * ACPI_MEM_CALLOCATE().
+ * ACPI_ALLOCATE_ZEROED().
*
* A pseudo-Namespace Node is assigned to each argument and local
* so that ref_of() can return a pointer to the Node.
@@ -92,7 +92,7 @@ void acpi_ds_method_data_init(struct acpi_walk_state *walk_state)
{
u32 i;
- ACPI_FUNCTION_TRACE("ds_method_data_init");
+ ACPI_FUNCTION_TRACE(ds_method_data_init);
/* Init the method arguments */
@@ -100,10 +100,10 @@ void acpi_ds_method_data_init(struct acpi_walk_state *walk_state)
ACPI_MOVE_32_TO_32(&walk_state->arguments[i].name,
NAMEOF_ARG_NTE);
walk_state->arguments[i].name.integer |= (i << 24);
- walk_state->arguments[i].descriptor = ACPI_DESC_TYPE_NAMED;
+ walk_state->arguments[i].descriptor_type = ACPI_DESC_TYPE_NAMED;
walk_state->arguments[i].type = ACPI_TYPE_ANY;
- walk_state->arguments[i].flags = ANOBJ_END_OF_PEER_LIST |
- ANOBJ_METHOD_ARG;
+ walk_state->arguments[i].flags =
+ ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_ARG;
}
/* Init the method locals */
@@ -113,11 +113,11 @@ void acpi_ds_method_data_init(struct acpi_walk_state *walk_state)
NAMEOF_LOCAL_NTE);
walk_state->local_variables[i].name.integer |= (i << 24);
- walk_state->local_variables[i].descriptor =
+ walk_state->local_variables[i].descriptor_type =
ACPI_DESC_TYPE_NAMED;
walk_state->local_variables[i].type = ACPI_TYPE_ANY;
- walk_state->local_variables[i].flags = ANOBJ_END_OF_PEER_LIST |
- ANOBJ_METHOD_LOCAL;
+ walk_state->local_variables[i].flags =
+ ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_LOCAL;
}
return_VOID;
@@ -140,7 +140,7 @@ void acpi_ds_method_data_delete_all(struct acpi_walk_state *walk_state)
{
u32 index;
- ACPI_FUNCTION_TRACE("ds_method_data_delete_all");
+ ACPI_FUNCTION_TRACE(ds_method_data_delete_all);
/* Detach the locals */
@@ -199,7 +199,7 @@ acpi_ds_method_data_init_args(union acpi_operand_object **params,
acpi_status status;
u32 index = 0;
- ACPI_FUNCTION_TRACE_PTR("ds_method_data_init_args", params);
+ ACPI_FUNCTION_TRACE_PTR(ds_method_data_init_args, params);
if (!params) {
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
@@ -251,7 +251,7 @@ acpi_ds_method_data_get_node(u16 opcode,
struct acpi_walk_state *walk_state,
struct acpi_namespace_node **node)
{
- ACPI_FUNCTION_TRACE("ds_method_data_get_node");
+ ACPI_FUNCTION_TRACE(ds_method_data_get_node);
/*
* Method Locals and Arguments are supported
@@ -318,10 +318,10 @@ acpi_ds_method_data_set_value(u16 opcode,
acpi_status status;
struct acpi_namespace_node *node;
- ACPI_FUNCTION_TRACE("ds_method_data_set_value");
+ ACPI_FUNCTION_TRACE(ds_method_data_set_value);
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "new_obj %p Opcode %X, Refs=%d [%s]\n", object,
+ "NewObj %p Opcode %X, Refs=%d [%s]\n", object,
opcode, object->common.reference_count,
acpi_ut_get_type_name(object->common.type)));
@@ -336,7 +336,7 @@ acpi_ds_method_data_set_value(u16 opcode,
* Increment ref count so object can't be deleted while installed.
* NOTE: We do not copy the object in order to preserve the call by
* reference semantics of ACPI Control Method invocation.
- * (See ACPI specification 2.0_c)
+ * (See ACPI Specification 2.0_c)
*/
acpi_ut_add_reference(object);
@@ -351,7 +351,7 @@ acpi_ds_method_data_set_value(u16 opcode,
* FUNCTION: acpi_ds_method_data_get_value
*
* PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
- * Index - which local_var or argument to get
+ * Index - Which local_var or argument to get
* walk_state - Current walk state object
* dest_desc - Where Arg or Local value is returned
*
@@ -372,7 +372,7 @@ acpi_ds_method_data_get_value(u16 opcode,
struct acpi_namespace_node *node;
union acpi_operand_object *object;
- ACPI_FUNCTION_TRACE("ds_method_data_get_value");
+ ACPI_FUNCTION_TRACE(ds_method_data_get_value);
/* Validate the object descriptor */
@@ -459,7 +459,7 @@ acpi_ds_method_data_get_value(u16 opcode,
* FUNCTION: acpi_ds_method_data_delete_value
*
* PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
- * Index - which local_var or argument to delete
+ * Index - Which local_var or argument to delete
* walk_state - Current walk state object
*
* RETURN: None
@@ -477,7 +477,7 @@ acpi_ds_method_data_delete_value(u16 opcode,
struct acpi_namespace_node *node;
union acpi_operand_object *object;
- ACPI_FUNCTION_TRACE("ds_method_data_delete_value");
+ ACPI_FUNCTION_TRACE(ds_method_data_delete_value);
/* Get the namespace node for the arg/local */
@@ -538,7 +538,7 @@ acpi_ds_store_object_to_local(u16 opcode,
union acpi_operand_object *current_obj_desc;
union acpi_operand_object *new_obj_desc;
- ACPI_FUNCTION_TRACE("ds_store_object_to_local");
+ ACPI_FUNCTION_TRACE(ds_store_object_to_local);
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Opcode=%X Index=%d Obj=%p\n",
opcode, index, obj_desc));
@@ -614,7 +614,7 @@ acpi_ds_store_object_to_local(u16 opcode,
&& (current_obj_desc->reference.opcode ==
AML_REF_OF_OP)) {
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Arg (%p) is an obj_ref(Node), storing in node %p\n",
+ "Arg (%p) is an ObjRef(Node), storing in node %p\n",
new_obj_desc,
current_obj_desc));
@@ -688,7 +688,7 @@ acpi_ds_method_data_get_type(u16 opcode,
struct acpi_namespace_node *node;
union acpi_operand_object *object;
- ACPI_FUNCTION_TRACE("ds_method_data_get_type");
+ ACPI_FUNCTION_TRACE(ds_method_data_get_type);
/* Get the namespace node for the arg/local */
@@ -701,6 +701,7 @@ acpi_ds_method_data_get_type(u16 opcode,
object = acpi_ns_get_attached_object(node);
if (!object) {
+
/* Uninitialized local/arg, return TYPE_ANY */
return_VALUE(ACPI_TYPE_ANY);
diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c
index 8b21f0f..72190ab 100644
--- a/drivers/acpi/dispatcher/dsobject.c
+++ b/drivers/acpi/dispatcher/dsobject.c
@@ -81,7 +81,7 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state,
union acpi_operand_object *obj_desc;
acpi_status status;
- ACPI_FUNCTION_TRACE("ds_build_internal_object");
+ ACPI_FUNCTION_TRACE(ds_build_internal_object);
*obj_desc_ptr = NULL;
if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) {
@@ -103,6 +103,7 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state,
common.
node)));
if (ACPI_FAILURE(status)) {
+
/* Check if we are resolving a named reference within a package */
if ((status == AE_NOT_FOUND)
@@ -186,7 +187,7 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state,
union acpi_parse_object *byte_list;
u32 byte_list_length = 0;
- ACPI_FUNCTION_TRACE("ds_build_internal_buffer_obj");
+ ACPI_FUNCTION_TRACE(ds_build_internal_buffer_obj);
/*
* If we are evaluating a Named buffer object "Name (xxxx, Buffer)".
@@ -195,6 +196,7 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state,
*/
obj_desc = *obj_desc_ptr;
if (!obj_desc) {
+
/* Create a new buffer object */
obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_BUFFER);
@@ -243,7 +245,7 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state,
"Buffer defined with zero length in AML, creating\n"));
} else {
obj_desc->buffer.pointer =
- ACPI_MEM_CALLOCATE(obj_desc->buffer.length);
+ ACPI_ALLOCATE_ZEROED(obj_desc->buffer.length);
if (!obj_desc->buffer.pointer) {
acpi_ut_delete_object_desc(obj_desc);
return_ACPI_STATUS(AE_NO_MEMORY);
@@ -291,7 +293,7 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
acpi_status status = AE_OK;
acpi_native_uint i;
- ACPI_FUNCTION_TRACE("ds_build_internal_package_obj");
+ ACPI_FUNCTION_TRACE(ds_build_internal_package_obj);
/* Find the parent of a possibly nested package */
@@ -339,9 +341,10 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
* individual objects). Add an extra pointer slot so
* that the list is always null terminated.
*/
- obj_desc->package.elements = ACPI_MEM_CALLOCATE(((acpi_size) obj_desc->
- package.count +
- 1) * sizeof(void *));
+ obj_desc->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size)
+ obj_desc->package.
+ count +
+ 1) * sizeof(void *));
if (!obj_desc->package.elements) {
acpi_ut_delete_object_desc(obj_desc);
@@ -355,6 +358,7 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
arg = arg->common.next;
for (i = 0; arg; i++) {
if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) {
+
/* Object (package or buffer) is already built */
obj_desc->package.elements[i] =
@@ -396,7 +400,7 @@ acpi_ds_create_node(struct acpi_walk_state *walk_state,
acpi_status status;
union acpi_operand_object *obj_desc;
- ACPI_FUNCTION_TRACE_PTR("ds_create_node", op);
+ ACPI_FUNCTION_TRACE_PTR(ds_create_node, op);
/*
* Because of the execution pass through the non-control-method
@@ -408,6 +412,7 @@ acpi_ds_create_node(struct acpi_walk_state *walk_state,
}
if (!op->common.value.arg) {
+
/* No arguments, there is nothing to do */
return_ACPI_STATUS(AE_OK);
@@ -464,11 +469,12 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
union acpi_operand_object *obj_desc;
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("ds_init_object_from_op");
+ ACPI_FUNCTION_TRACE(ds_init_object_from_op);
obj_desc = *ret_obj_desc;
op_info = acpi_ps_get_opcode_info(opcode);
if (op_info->class == AML_CLASS_UNKNOWN) {
+
/* Unknown opcode */
return_ACPI_STATUS(AE_TYPE);
@@ -626,6 +632,7 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
default: /* Other literals, etc.. */
if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) {
+
/* Node was saved in Op */
obj_desc->reference.node = op->common.node;
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c
index 6229c10..5b974a8 100644
--- a/drivers/acpi/dispatcher/dsopcode.c
+++ b/drivers/acpi/dispatcher/dsopcode.c
@@ -91,7 +91,7 @@ acpi_ds_execute_arguments(struct acpi_namespace_node *node,
union acpi_parse_object *op;
struct acpi_walk_state *walk_state;
- ACPI_FUNCTION_TRACE("ds_execute_arguments");
+ ACPI_FUNCTION_TRACE(ds_execute_arguments);
/*
* Allocate a new parser op to be the root of the parsed tree
@@ -193,7 +193,7 @@ acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc)
struct acpi_namespace_node *node;
acpi_status status;
- ACPI_FUNCTION_TRACE_PTR("ds_get_buffer_field_arguments", obj_desc);
+ ACPI_FUNCTION_TRACE_PTR(ds_get_buffer_field_arguments, obj_desc);
if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
return_ACPI_STATUS(AE_OK);
@@ -206,7 +206,7 @@ acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc)
ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
(ACPI_TYPE_BUFFER_FIELD, node, NULL));
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] buffer_field Arg Init\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] BufferField Arg Init\n",
acpi_ut_get_node_name(node)));
/* Execute the AML code for the term_arg arguments */
@@ -235,7 +235,7 @@ acpi_status acpi_ds_get_buffer_arguments(union acpi_operand_object *obj_desc)
struct acpi_namespace_node *node;
acpi_status status;
- ACPI_FUNCTION_TRACE_PTR("ds_get_buffer_arguments", obj_desc);
+ ACPI_FUNCTION_TRACE_PTR(ds_get_buffer_arguments, obj_desc);
if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
return_ACPI_STATUS(AE_OK);
@@ -279,7 +279,7 @@ acpi_status acpi_ds_get_package_arguments(union acpi_operand_object *obj_desc)
struct acpi_namespace_node *node;
acpi_status status;
- ACPI_FUNCTION_TRACE_PTR("ds_get_package_arguments", obj_desc);
+ ACPI_FUNCTION_TRACE_PTR(ds_get_package_arguments, obj_desc);
if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
return_ACPI_STATUS(AE_OK);
@@ -324,7 +324,7 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc)
acpi_status status;
union acpi_operand_object *extra_desc;
- ACPI_FUNCTION_TRACE_PTR("ds_get_region_arguments", obj_desc);
+ ACPI_FUNCTION_TRACE_PTR(ds_get_region_arguments, obj_desc);
if (obj_desc->region.flags & AOPOBJ_DATA_VALID) {
return_ACPI_STATUS(AE_OK);
@@ -342,8 +342,7 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc)
ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
(ACPI_TYPE_REGION, node, NULL));
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "[%4.4s] op_region Arg Init at AML %p\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] OpRegion Arg Init at AML %p\n",
acpi_ut_get_node_name(node),
extra_desc->extra.aml_start));
@@ -352,6 +351,28 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc)
status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node),
extra_desc->extra.aml_length,
extra_desc->extra.aml_start);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Validate the region address/length via the host OS */
+
+ status = acpi_os_validate_address(obj_desc->region.space_id,
+ obj_desc->region.address,
+ (acpi_size) obj_desc->region.length);
+ if (ACPI_FAILURE(status)) {
+ /*
+ * Invalid address/length. We will emit an error message and mark
+ * the region as invalid, so that it will cause an additional error if
+ * it is ever used. Then return AE_OK.
+ */
+ ACPI_EXCEPTION((AE_INFO, status,
+ "During address validation of OpRegion [%4.4s]",
+ node->name.ascii));
+ obj_desc->common.flags |= AOPOBJ_INVALID;
+ status = AE_OK;
+ }
+
return_ACPI_STATUS(status);
}
@@ -411,7 +432,7 @@ acpi_ds_init_buffer_field(u16 aml_opcode,
u8 field_flags;
acpi_status status;
- ACPI_FUNCTION_TRACE_PTR("ds_init_buffer_field", obj_desc);
+ ACPI_FUNCTION_TRACE_PTR(ds_init_buffer_field, obj_desc);
/* Host object must be a Buffer */
@@ -457,7 +478,7 @@ acpi_ds_init_buffer_field(u16 aml_opcode,
if (bit_count == 0) {
ACPI_ERROR((AE_INFO,
- "Attempt to create_field of length zero"));
+ "Attempt to CreateField of length zero"));
status = AE_AML_OPERAND_VALUE;
goto cleanup;
}
@@ -595,7 +616,7 @@ acpi_ds_eval_buffer_field_operands(struct acpi_walk_state *walk_state,
struct acpi_namespace_node *node;
union acpi_parse_object *next_op;
- ACPI_FUNCTION_TRACE_PTR("ds_eval_buffer_field_operands", op);
+ ACPI_FUNCTION_TRACE_PTR(ds_eval_buffer_field_operands, op);
/*
* This is where we evaluate the address and length fields of the
@@ -627,7 +648,7 @@ acpi_ds_eval_buffer_field_operands(struct acpi_walk_state *walk_state,
ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE,
acpi_ps_get_opcode_name(op->common.aml_opcode),
walk_state->num_operands,
- "after acpi_ex_resolve_operands");
+ "after AcpiExResolveOperands");
if (ACPI_FAILURE(status)) {
ACPI_ERROR((AE_INFO, "(%s) bad operand(s) (%X)",
@@ -640,6 +661,7 @@ acpi_ds_eval_buffer_field_operands(struct acpi_walk_state *walk_state,
/* Initialize the Buffer Field */
if (op->common.aml_opcode == AML_CREATE_FIELD_OP) {
+
/* NOTE: Slightly different operands for this opcode */
status =
@@ -685,7 +707,7 @@ acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state,
struct acpi_namespace_node *node;
union acpi_parse_object *next_op;
- ACPI_FUNCTION_TRACE_PTR("ds_eval_region_operands", op);
+ ACPI_FUNCTION_TRACE_PTR(ds_eval_region_operands, op);
/*
* This is where we evaluate the address and length fields of the
@@ -718,7 +740,7 @@ acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state,
ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE,
acpi_ps_get_opcode_name(op->common.aml_opcode),
- 1, "after acpi_ex_resolve_operands");
+ 1, "after AcpiExResolveOperands");
obj_desc = acpi_ns_get_attached_object(node);
if (!obj_desc) {
@@ -744,7 +766,7 @@ acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state,
operand_desc->integer.value;
acpi_ut_remove_reference(operand_desc);
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "rgn_obj %p Addr %8.8X%8.8X Len %X\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n",
obj_desc,
ACPI_FORMAT_UINT64(obj_desc->region.address),
obj_desc->region.length));
@@ -780,7 +802,7 @@ acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state,
union acpi_operand_object *arg_desc;
u32 length;
- ACPI_FUNCTION_TRACE("ds_eval_data_object_operands");
+ ACPI_FUNCTION_TRACE(ds_eval_data_object_operands);
/* The first operand (for all of these data objects) is the length */
@@ -874,7 +896,7 @@ acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,
acpi_status status = AE_OK;
union acpi_generic_state *control_state;
- ACPI_FUNCTION_NAME("ds_exec_begin_control_op");
+ ACPI_FUNCTION_NAME(ds_exec_begin_control_op);
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p Opcode=%2.2X State=%p\n", op,
op->common.aml_opcode, walk_state));
@@ -952,7 +974,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
acpi_status status = AE_OK;
union acpi_generic_state *control_state;
- ACPI_FUNCTION_NAME("ds_exec_end_control_op");
+ ACPI_FUNCTION_NAME(ds_exec_end_control_op);
switch (op->common.aml_opcode) {
case AML_IF_OP:
@@ -984,6 +1006,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op));
if (walk_state->control_state->common.value) {
+
/* Predicate was true, go back and evaluate it again! */
status = AE_CTRL_PENDING;
@@ -1014,6 +1037,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
* has been bubbled up the tree
*/
if (op->common.value.arg) {
+
/* Since we have a real Return(), delete any implicit return */
acpi_ds_clear_implicit_return(walk_state);
@@ -1047,6 +1071,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
walk_state->return_desc = walk_state->operands[0];
} else if ((walk_state->results) &&
(walk_state->results->results.num_results > 0)) {
+
/* Since we have a real Return(), delete any implicit return */
acpi_ds_clear_implicit_return(walk_state);
@@ -1095,7 +1120,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
}
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "Completed RETURN_OP State=%p, ret_val=%p\n",
+ "Completed RETURN_OP State=%p, RetVal=%p\n",
walk_state, walk_state->return_desc));
/* End the control method execution right now */
diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c
index 53356a5..05230ba 100644
--- a/drivers/acpi/dispatcher/dsutils.c
+++ b/drivers/acpi/dispatcher/dsutils.c
@@ -68,7 +68,7 @@ ACPI_MODULE_NAME("dsutils")
******************************************************************************/
void acpi_ds_clear_implicit_return(struct acpi_walk_state *walk_state)
{
- ACPI_FUNCTION_NAME("ds_clear_implicit_return");
+ ACPI_FUNCTION_NAME(ds_clear_implicit_return);
/*
* Slack must be enabled for this feature
@@ -115,7 +115,7 @@ u8
acpi_ds_do_implicit_return(union acpi_operand_object *return_desc,
struct acpi_walk_state *walk_state, u8 add_reference)
{
- ACPI_FUNCTION_NAME("ds_do_implicit_return");
+ ACPI_FUNCTION_NAME(ds_do_implicit_return);
/*
* Slack must be enabled for this feature, and we must
@@ -171,7 +171,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
{
const struct acpi_opcode_info *parent_info;
- ACPI_FUNCTION_TRACE_PTR("ds_is_result_used", op);
+ ACPI_FUNCTION_TRACE_PTR(ds_is_result_used, op);
/* Must have both an Op and a Result Object */
@@ -202,6 +202,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
*/
if ((!op->common.parent) ||
(op->common.parent->common.aml_opcode == AML_SCOPE_OP)) {
+
/* No parent, the return value cannot possibly be used */
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
@@ -340,7 +341,7 @@ acpi_ds_delete_result_if_not_used(union acpi_parse_object *op,
union acpi_operand_object *obj_desc;
acpi_status status;
- ACPI_FUNCTION_TRACE_PTR("ds_delete_result_if_not_used", result_obj);
+ ACPI_FUNCTION_TRACE_PTR(ds_delete_result_if_not_used, result_obj);
if (!op) {
ACPI_ERROR((AE_INFO, "Null Op"));
@@ -352,6 +353,7 @@ acpi_ds_delete_result_if_not_used(union acpi_parse_object *op,
}
if (!acpi_ds_is_result_used(op, walk_state)) {
+
/* Must pop the result stack (obj_desc should be equal to result_obj) */
status = acpi_ds_result_pop(&obj_desc, walk_state);
@@ -382,7 +384,7 @@ acpi_status acpi_ds_resolve_operands(struct acpi_walk_state *walk_state)
u32 i;
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE_PTR("ds_resolve_operands", walk_state);
+ ACPI_FUNCTION_TRACE_PTR(ds_resolve_operands, walk_state);
/*
* Attempt to resolve each of the valid operands
@@ -417,7 +419,7 @@ void acpi_ds_clear_operands(struct acpi_walk_state *walk_state)
{
u32 i;
- ACPI_FUNCTION_TRACE_PTR("ds_clear_operands", walk_state);
+ ACPI_FUNCTION_TRACE_PTR(ds_clear_operands, walk_state);
/* Remove a reference on each operand on the stack */
@@ -465,7 +467,7 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state,
acpi_interpreter_mode interpreter_mode;
const struct acpi_opcode_info *op_info;
- ACPI_FUNCTION_TRACE_PTR("ds_create_operand", arg);
+ ACPI_FUNCTION_TRACE_PTR(ds_create_operand, arg);
/* A valid name must be looked up in the namespace */
@@ -498,7 +500,9 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state,
*/
if ((walk_state->deferred_node) &&
(walk_state->deferred_node->type == ACPI_TYPE_BUFFER_FIELD)
- && (arg_index != 0)) {
+ && (arg_index ==
+ (u32) ((walk_state->opcode ==
+ AML_CREATE_FIELD_OP) ? 3 : 2))) {
obj_desc =
ACPI_CAST_PTR(union acpi_operand_object,
walk_state->deferred_node);
@@ -521,6 +525,7 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state,
&& (parent_op->common.aml_opcode != AML_REGION_OP)
&& (parent_op->common.aml_opcode !=
AML_INT_NAMEPATH_OP)) {
+
/* Enter name into namespace if not found */
interpreter_mode = ACPI_IMODE_LOAD_PASS2;
@@ -572,7 +577,7 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state,
/* Free the namestring created above */
- ACPI_MEM_FREE(name_string);
+ ACPI_FREE(name_string);
/* Check status from the lookup */
@@ -696,7 +701,7 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state,
union acpi_parse_object *arg;
u32 arg_count = 0;
- ACPI_FUNCTION_TRACE_PTR("ds_create_operands", first_arg);
+ ACPI_FUNCTION_TRACE_PTR(ds_create_operands, first_arg);
/* For all arguments in the list... */
diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c
index f1af655..3acbd91 100644
--- a/drivers/acpi/dispatcher/dswexec.c
+++ b/drivers/acpi/dispatcher/dswexec.c
@@ -49,7 +49,6 @@
#include <acpi/acinterp.h>
#include <acpi/acnamesp.h>
#include <acpi/acdebug.h>
-#include <acpi/acdisasm.h>
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dswexec")
@@ -93,7 +92,7 @@ acpi_ds_get_predicate_value(struct acpi_walk_state *walk_state,
union acpi_operand_object *obj_desc;
union acpi_operand_object *local_obj_desc = NULL;
- ACPI_FUNCTION_TRACE_PTR("ds_get_predicate_value", walk_state);
+ ACPI_FUNCTION_TRACE_PTR(ds_get_predicate_value, walk_state);
walk_state->control_state->common.state = 0;
@@ -123,7 +122,7 @@ acpi_ds_get_predicate_value(struct acpi_walk_state *walk_state,
if (!obj_desc) {
ACPI_ERROR((AE_INFO,
- "No predicate obj_desc=%p State=%p",
+ "No predicate ObjDesc=%p State=%p",
obj_desc, walk_state));
return_ACPI_STATUS(AE_AML_NO_OPERAND);
@@ -140,7 +139,7 @@ acpi_ds_get_predicate_value(struct acpi_walk_state *walk_state,
if (ACPI_GET_OBJECT_TYPE(local_obj_desc) != ACPI_TYPE_INTEGER) {
ACPI_ERROR((AE_INFO,
- "Bad predicate (not an integer) obj_desc=%p State=%p Type=%X",
+ "Bad predicate (not an integer) ObjDesc=%p State=%p Type=%X",
obj_desc, walk_state,
ACPI_GET_OBJECT_TYPE(obj_desc)));
@@ -214,7 +213,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
acpi_status status = AE_OK;
u32 opcode_class;
- ACPI_FUNCTION_TRACE_PTR("ds_exec_begin_op", walk_state);
+ ACPI_FUNCTION_TRACE_PTR(ds_exec_begin_op, walk_state);
op = walk_state->op;
if (!op) {
@@ -296,7 +295,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
case AML_CLASS_NAMED_OBJECT:
- if (walk_state->walk_type == ACPI_WALK_METHOD) {
+ if (walk_state->walk_type & ACPI_WALK_METHOD) {
/*
* Found a named object declaration during method execution;
* we must enter this object into the namespace. The created
@@ -354,7 +353,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
union acpi_parse_object *next_op;
union acpi_parse_object *first_arg;
- ACPI_FUNCTION_TRACE_PTR("ds_exec_end_op", walk_state);
+ ACPI_FUNCTION_TRACE_PTR(ds_exec_end_op, walk_state);
op = walk_state->op;
op_type = walk_state->op_info->type;
@@ -409,6 +408,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
* being the object_type and size_of operators.
*/
if (!(walk_state->op_info->flags & AML_NO_OPERAND_RESOLVE)) {
+
/* Resolve all operands */
status = acpi_ex_resolve_operands(walk_state->opcode,
@@ -423,7 +423,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
acpi_ps_get_opcode_name
(walk_state->opcode),
walk_state->num_operands,
- "after ex_resolve_operands");
+ "after ExResolveOperands");
}
}
@@ -437,7 +437,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
acpi_gbl_op_type_dispatch[op_type] (walk_state);
} else {
/*
- * Treat constructs of the form "Store(local_x,local_x)" as noops when the
+ * Treat constructs of the form "Store(LocalX,LocalX)" as noops when the
* Local is uninitialized.
*/
if ((status == AE_AML_UNINITIALIZED_LOCAL) &&
@@ -548,6 +548,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
*/
status = acpi_ds_resolve_operands(walk_state);
if (ACPI_FAILURE(status)) {
+
/* On error, clear all resolved operands */
acpi_ds_clear_operands(walk_state);
@@ -569,7 +570,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
case AML_TYPE_CREATE_FIELD:
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Executing create_field Buffer/Index Op=%p\n",
+ "Executing CreateField Buffer/Index Op=%p\n",
op));
status = acpi_ds_load2_end_op(walk_state);
@@ -584,7 +585,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
case AML_TYPE_CREATE_OBJECT:
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Executing create_object (Buffer/Package) Op=%p\n",
+ "Executing CreateObject (Buffer/Package) Op=%p\n",
op));
switch (op->common.parent->common.aml_opcode) {
@@ -657,7 +658,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
if (op->common.aml_opcode == AML_REGION_OP) {
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Executing op_region Address/Length Op=%p\n",
+ "Executing OpRegion Address/Length Op=%p\n",
op));
status =
@@ -722,6 +723,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
cleanup:
if (walk_state->result_obj) {
+
/* Break to debugger to display result */
ACPI_DEBUGGER_EXEC(acpi_db_display_result_object
diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c
index d3d24da..3507439 100644
--- a/drivers/acpi/dispatcher/dswload.c
+++ b/drivers/acpi/dispatcher/dswload.c
@@ -127,7 +127,7 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
char *path;
u32 flags;
- ACPI_FUNCTION_TRACE("ds_load1_begin_op");
+ ACPI_FUNCTION_TRACE(ds_load1_begin_op);
op = walk_state->op;
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op,
@@ -178,12 +178,12 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
* Target of Scope() not found. Generate an External for it, and
* insert the name into the namespace.
*/
- acpi_dm_add_to_external_list(path);
+ acpi_dm_add_to_external_list(path, ACPI_TYPE_DEVICE, 0);
status =
acpi_ns_lookup(walk_state->scope_info, path,
object_type, ACPI_IMODE_LOAD_PASS1,
ACPI_NS_SEARCH_PARENT, walk_state,
- &(node));
+ &node);
}
#endif
if (ACPI_FAILURE(status)) {
@@ -261,6 +261,7 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
*/
if (walk_state->deferred_node) {
+
/* This name is already in the namespace, get the node */
node = walk_state->deferred_node;
@@ -300,10 +301,41 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
status =
acpi_ns_lookup(walk_state->scope_info, path, object_type,
ACPI_IMODE_LOAD_PASS1, flags, walk_state,
- &(node));
+ &node);
if (ACPI_FAILURE(status)) {
- ACPI_ERROR_NAMESPACE(path, status);
- return_ACPI_STATUS(status);
+ if (status == AE_ALREADY_EXISTS) {
+
+ /* The name already exists in this scope */
+
+ if (node->flags & ANOBJ_IS_EXTERNAL) {
+ /*
+ * Allow one create on an object or segment that was
+ * previously declared External
+ */
+ node->flags &= ~ANOBJ_IS_EXTERNAL;
+ node->type = (u8) object_type;
+
+ /* Just retyped a node, probably will need to open a scope */
+
+ if (acpi_ns_opens_scope(object_type)) {
+ status =
+ acpi_ds_scope_stack_push
+ (node, object_type,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS
+ (status);
+ }
+ }
+ status = AE_OK;
+ }
+ }
+
+ if (ACPI_FAILURE(status)) {
+
+ ACPI_ERROR_NAMESPACE(path, status);
+ return_ACPI_STATUS(status);
+ }
}
break;
}
@@ -311,6 +343,7 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
/* Common exit */
if (!op) {
+
/* Create a new op */
op = acpi_ps_alloc_op(walk_state->opcode);
@@ -359,7 +392,7 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state)
acpi_object_type object_type;
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("ds_load1_end_op");
+ ACPI_FUNCTION_TRACE(ds_load1_end_op);
op = walk_state->op;
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op,
@@ -413,6 +446,7 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state)
#endif
if (op->common.aml_opcode == AML_NAME_OP) {
+
/* For Name opcode, get the object type from the argument */
if (op->common.value.arg) {
@@ -445,7 +479,7 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state)
* arguments.)
*/
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "LOADING-Method: State=%p Op=%p named_obj=%p\n",
+ "LOADING-Method: State=%p Op=%p NamedObj=%p\n",
walk_state, op, op->named.node));
if (!acpi_ns_get_attached_object(op->named.node)) {
@@ -511,7 +545,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
acpi_object_type object_type;
char *buffer_ptr;
- ACPI_FUNCTION_TRACE("ds_load2_begin_op");
+ ACPI_FUNCTION_TRACE(ds_load2_begin_op);
op = walk_state->op;
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op,
@@ -521,6 +555,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
if ((walk_state->control_state) &&
(walk_state->control_state->common.state ==
ACPI_CONTROL_CONDITIONAL_EXECUTING)) {
+
/* We are executing a while loop outside of a method */
status = acpi_ds_exec_begin_op(walk_state, out_op);
@@ -554,10 +589,12 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
/* Get the name we are going to enter or lookup in the namespace */
if (walk_state->opcode == AML_INT_NAMEPATH_OP) {
+
/* For Namepath op, get the path string */
buffer_ptr = op->common.value.string;
if (!buffer_ptr) {
+
/* No name, just exit */
return_ACPI_STATUS(AE_OK);
@@ -680,6 +717,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
/* All other opcodes */
if (op && op->common.node) {
+
/* This op/node was previously entered into the namespace */
node = op->common.node;
@@ -705,6 +743,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
* Note: Name may already exist if we are executing a deferred opcode.
*/
if (walk_state->deferred_node) {
+
/* This name is already in the namespace, get the node */
node = walk_state->deferred_node;
@@ -727,6 +766,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
}
if (!op) {
+
/* Create a new op */
op = acpi_ps_alloc_op(walk_state->opcode);
@@ -776,7 +816,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
u32 i;
#endif
- ACPI_FUNCTION_TRACE("ds_load2_end_op");
+ ACPI_FUNCTION_TRACE(ds_load2_end_op);
op = walk_state->op;
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Opcode [%s] Op %p State %p\n",
@@ -870,7 +910,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
*/
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "Create-Load [%s] State=%p Op=%p named_obj=%p\n",
+ "Create-Load [%s] State=%p Op=%p NamedObj=%p\n",
acpi_ps_get_opcode_name(op->common.aml_opcode),
walk_state, op, node));
@@ -1045,7 +1085,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
* arguments.)
*/
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "LOADING-Method: State=%p Op=%p named_obj=%p\n",
+ "LOADING-Method: State=%p Op=%p NamedObj=%p\n",
walk_state, op, op->named.node));
if (!acpi_ns_get_attached_object(op->named.node)) {
@@ -1090,7 +1130,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
case AML_CLASS_METHOD_CALL:
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "RESOLVING-method_call: State=%p Op=%p named_obj=%p\n",
+ "RESOLVING-MethodCall: State=%p Op=%p NamedObj=%p\n",
walk_state, op, node));
/*
@@ -1104,7 +1144,6 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
ACPI_NS_DONT_OPEN_SCOPE, walk_state,
&(new_node));
if (ACPI_SUCCESS(status)) {
-
/*
* Make sure that what we found is indeed a method
* We didn't search for a method on purpose, to see if the name
diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c
index ada21ef..c922897 100644
--- a/drivers/acpi/dispatcher/dswscope.c
+++ b/drivers/acpi/dispatcher/dswscope.c
@@ -63,9 +63,10 @@ void acpi_ds_scope_stack_clear(struct acpi_walk_state *walk_state)
{
union acpi_generic_state *scope_info;
- ACPI_FUNCTION_NAME("ds_scope_stack_clear");
+ ACPI_FUNCTION_NAME(ds_scope_stack_clear);
while (walk_state->scope_info) {
+
/* Pop a scope off the stack */
scope_info = walk_state->scope_info;
@@ -102,9 +103,10 @@ acpi_ds_scope_stack_push(struct acpi_namespace_node *node,
union acpi_generic_state *scope_info;
union acpi_generic_state *old_scope_info;
- ACPI_FUNCTION_TRACE("ds_scope_stack_push");
+ ACPI_FUNCTION_TRACE(ds_scope_stack_push);
if (!node) {
+
/* Invalid scope */
ACPI_ERROR((AE_INFO, "Null scope parameter"));
@@ -126,7 +128,7 @@ acpi_ds_scope_stack_push(struct acpi_namespace_node *node,
/* Init new scope object */
- scope_info->common.data_type = ACPI_DESC_TYPE_STATE_WSCOPE;
+ scope_info->common.descriptor_type = ACPI_DESC_TYPE_STATE_WSCOPE;
scope_info->scope.node = node;
scope_info->common.value = (u16) type;
@@ -176,7 +178,7 @@ acpi_status acpi_ds_scope_stack_pop(struct acpi_walk_state *walk_state)
union acpi_generic_state *scope_info;
union acpi_generic_state *new_scope_info;
- ACPI_FUNCTION_TRACE("ds_scope_stack_pop");
+ ACPI_FUNCTION_TRACE(ds_scope_stack_pop);
/*
* Pop scope info object off the stack.
diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c
index fa78cb7..7817e55 100644
--- a/drivers/acpi/dispatcher/dswstate.c
+++ b/drivers/acpi/dispatcher/dswstate.c
@@ -66,7 +66,6 @@ void *acpi_ds_obj_stack_get_value(u32 index,
#endif
#ifdef ACPI_FUTURE_USAGE
-
/*******************************************************************************
*
* FUNCTION: acpi_ds_result_remove
@@ -88,7 +87,7 @@ acpi_ds_result_remove(union acpi_operand_object **object,
{
union acpi_generic_state *state;
- ACPI_FUNCTION_NAME("ds_result_remove");
+ ACPI_FUNCTION_NAME(ds_result_remove);
state = walk_state->results;
if (!state) {
@@ -128,7 +127,6 @@ acpi_ds_result_remove(union acpi_operand_object **object,
return (AE_OK);
}
-
#endif /* ACPI_FUTURE_USAGE */
/*******************************************************************************
@@ -152,7 +150,7 @@ acpi_ds_result_pop(union acpi_operand_object ** object,
acpi_native_uint index;
union acpi_generic_state *state;
- ACPI_FUNCTION_NAME("ds_result_pop");
+ ACPI_FUNCTION_NAME(ds_result_pop);
state = walk_state->results;
if (!state) {
@@ -170,6 +168,7 @@ acpi_ds_result_pop(union acpi_operand_object ** object,
state->results.num_results--;
for (index = ACPI_OBJ_NUM_OPERANDS; index; index--) {
+
/* Check for a valid result object */
if (state->results.obj_desc[index - 1]) {
@@ -213,7 +212,7 @@ acpi_ds_result_pop_from_bottom(union acpi_operand_object ** object,
acpi_native_uint index;
union acpi_generic_state *state;
- ACPI_FUNCTION_NAME("ds_result_pop_from_bottom");
+ ACPI_FUNCTION_NAME(ds_result_pop_from_bottom);
state = walk_state->results;
if (!state) {
@@ -278,7 +277,7 @@ acpi_ds_result_push(union acpi_operand_object * object,
{
union acpi_generic_state *state;
- ACPI_FUNCTION_NAME("ds_result_push");
+ ACPI_FUNCTION_NAME(ds_result_push);
state = walk_state->results;
if (!state) {
@@ -331,14 +330,14 @@ acpi_status acpi_ds_result_stack_push(struct acpi_walk_state * walk_state)
{
union acpi_generic_state *state;
- ACPI_FUNCTION_NAME("ds_result_stack_push");
+ ACPI_FUNCTION_NAME(ds_result_stack_push);
state = acpi_ut_create_generic_state();
if (!state) {
return (AE_NO_MEMORY);
}
- state->common.data_type = ACPI_DESC_TYPE_STATE_RESULT;
+ state->common.descriptor_type = ACPI_DESC_TYPE_STATE_RESULT;
acpi_ut_push_generic_state(&walk_state->results, state);
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Results=%p State=%p\n",
@@ -363,7 +362,7 @@ acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state * walk_state)
{
union acpi_generic_state *state;
- ACPI_FUNCTION_NAME("ds_result_stack_pop");
+ ACPI_FUNCTION_NAME(ds_result_stack_pop);
/* Check for stack underflow */
@@ -376,7 +375,7 @@ acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state * walk_state)
state = acpi_ut_pop_generic_state(&walk_state->results);
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Result=%p remaining_results=%X State=%p\n",
+ "Result=%p RemainingResults=%X State=%p\n",
state, state->results.num_results, walk_state));
acpi_ut_delete_generic_state(state);
@@ -400,7 +399,7 @@ acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state * walk_state)
acpi_status
acpi_ds_obj_stack_push(void *object, struct acpi_walk_state * walk_state)
{
- ACPI_FUNCTION_NAME("ds_obj_stack_push");
+ ACPI_FUNCTION_NAME(ds_obj_stack_push);
/* Check for stack overflow */
@@ -445,9 +444,10 @@ acpi_ds_obj_stack_pop(u32 pop_count, struct acpi_walk_state * walk_state)
{
u32 i;
- ACPI_FUNCTION_NAME("ds_obj_stack_pop");
+ ACPI_FUNCTION_NAME(ds_obj_stack_pop);
for (i = 0; i < pop_count; i++) {
+
/* Check for stack underflow */
if (walk_state->num_operands == 0) {
@@ -491,9 +491,10 @@ acpi_ds_obj_stack_pop_and_delete(u32 pop_count,
u32 i;
union acpi_operand_object *obj_desc;
- ACPI_FUNCTION_NAME("ds_obj_stack_pop_and_delete");
+ ACPI_FUNCTION_NAME(ds_obj_stack_pop_and_delete);
for (i = 0; i < pop_count; i++) {
+
/* Check for stack underflow */
if (walk_state->num_operands == 0) {
@@ -538,13 +539,13 @@ acpi_ds_obj_stack_pop_and_delete(u32 pop_count,
struct acpi_walk_state *acpi_ds_get_current_walk_state(struct acpi_thread_state
*thread)
{
- ACPI_FUNCTION_NAME("ds_get_current_walk_state");
+ ACPI_FUNCTION_NAME(ds_get_current_walk_state);
if (!thread) {
return (NULL);
}
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Current walk_state %p\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Current WalkState %p\n",
thread->walk_state_list));
return (thread->walk_state_list);
@@ -567,7 +568,7 @@ void
acpi_ds_push_walk_state(struct acpi_walk_state *walk_state,
struct acpi_thread_state *thread)
{
- ACPI_FUNCTION_TRACE("ds_push_walk_state");
+ ACPI_FUNCTION_TRACE(ds_push_walk_state);
walk_state->next = thread->walk_state_list;
thread->walk_state_list = walk_state;
@@ -593,11 +594,12 @@ struct acpi_walk_state *acpi_ds_pop_walk_state(struct acpi_thread_state *thread)
{
struct acpi_walk_state *walk_state;
- ACPI_FUNCTION_TRACE("ds_pop_walk_state");
+ ACPI_FUNCTION_TRACE(ds_pop_walk_state);
walk_state = thread->walk_state_list;
if (walk_state) {
+
/* Next walk state becomes the current walk state */
thread->walk_state_list = walk_state->next;
@@ -618,7 +620,7 @@ struct acpi_walk_state *acpi_ds_pop_walk_state(struct acpi_thread_state *thread)
*
* PARAMETERS: owner_id - ID for object creation
* Origin - Starting point for this walk
- * mth_desc - Method object
+ * method_desc - Method object
* Thread - Current thread state
*
* RETURN: Pointer to the new walk state.
@@ -632,24 +634,24 @@ struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id,
union acpi_parse_object
*origin,
union acpi_operand_object
- *mth_desc,
+ *method_desc,
struct acpi_thread_state
*thread)
{
struct acpi_walk_state *walk_state;
acpi_status status;
- ACPI_FUNCTION_TRACE("ds_create_walk_state");
+ ACPI_FUNCTION_TRACE(ds_create_walk_state);
- walk_state = ACPI_MEM_CALLOCATE(sizeof(struct acpi_walk_state));
+ walk_state = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_walk_state));
if (!walk_state) {
return_PTR(NULL);
}
- walk_state->data_type = ACPI_DESC_TYPE_WALK;
+ walk_state->descriptor_type = ACPI_DESC_TYPE_WALK;
+ walk_state->method_desc = method_desc;
walk_state->owner_id = owner_id;
walk_state->origin = origin;
- walk_state->method_desc = mth_desc;
walk_state->thread = thread;
walk_state->parser_state.start_op = origin;
@@ -664,7 +666,7 @@ struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id,
status = acpi_ds_result_stack_push(walk_state);
if (ACPI_FAILURE(status)) {
- ACPI_MEM_FREE(walk_state);
+ ACPI_FREE(walk_state);
return_PTR(NULL);
}
@@ -701,13 +703,13 @@ acpi_ds_init_aml_walk(struct acpi_walk_state *walk_state,
struct acpi_namespace_node *method_node,
u8 * aml_start,
u32 aml_length,
- struct acpi_parameter_info *info, u8 pass_number)
+ struct acpi_evaluate_info *info, u8 pass_number)
{
acpi_status status;
struct acpi_parse_state *parser_state = &walk_state->parser_state;
union acpi_parse_object *extra_op;
- ACPI_FUNCTION_TRACE("ds_init_aml_walk");
+ ACPI_FUNCTION_TRACE(ds_init_aml_walk);
walk_state->parser_state.aml =
walk_state->parser_state.aml_start = aml_start;
@@ -778,6 +780,7 @@ acpi_ds_init_aml_walk(struct acpi_walk_state *walk_state,
}
if (parser_state->start_node) {
+
/* Push start scope on scope stack and make it current */
status =
@@ -810,21 +813,24 @@ void acpi_ds_delete_walk_state(struct acpi_walk_state *walk_state)
{
union acpi_generic_state *state;
- ACPI_FUNCTION_TRACE_PTR("ds_delete_walk_state", walk_state);
+ ACPI_FUNCTION_TRACE_PTR(ds_delete_walk_state, walk_state);
if (!walk_state) {
return;
}
- if (walk_state->data_type != ACPI_DESC_TYPE_WALK) {
+ if (walk_state->descriptor_type != ACPI_DESC_TYPE_WALK) {
ACPI_ERROR((AE_INFO, "%p is not a valid walk state",
walk_state));
return;
}
+ /* There should not be any open scopes */
+
if (walk_state->parser_state.scope) {
ACPI_ERROR((AE_INFO, "%p walk still has a scope list",
walk_state));
+ acpi_ps_cleanup_scope(&walk_state->parser_state);
}
/* Always must free any linked control states */
@@ -854,7 +860,7 @@ void acpi_ds_delete_walk_state(struct acpi_walk_state *walk_state)
acpi_ut_delete_generic_state(state);
}
- ACPI_MEM_FREE(walk_state);
+ ACPI_FREE(walk_state);
return_VOID;
}
@@ -879,7 +885,7 @@ acpi_ds_result_insert(void *object,
{
union acpi_generic_state *state;
- ACPI_FUNCTION_NAME("ds_result_insert");
+ ACPI_FUNCTION_NAME(ds_result_insert);
state = walk_state->results;
if (!state) {
@@ -937,7 +943,7 @@ acpi_status acpi_ds_obj_stack_delete_all(struct acpi_walk_state * walk_state)
{
u32 i;
- ACPI_FUNCTION_TRACE_PTR("ds_obj_stack_delete_all", walk_state);
+ ACPI_FUNCTION_TRACE_PTR(ds_obj_stack_delete_all, walk_state);
/* The stack size is configurable, but fixed */
@@ -969,7 +975,7 @@ acpi_status
acpi_ds_obj_stack_pop_object(union acpi_operand_object **object,
struct acpi_walk_state *walk_state)
{
- ACPI_FUNCTION_NAME("ds_obj_stack_pop_object");
+ ACPI_FUNCTION_NAME(ds_obj_stack_pop_object);
/* Check for stack underflow */
@@ -1025,7 +1031,7 @@ acpi_ds_obj_stack_pop_object(union acpi_operand_object **object,
void *acpi_ds_obj_stack_get_value(u32 index, struct acpi_walk_state *walk_state)
{
- ACPI_FUNCTION_TRACE_PTR("ds_obj_stack_get_value", walk_state);
+ ACPI_FUNCTION_TRACE_PTR(ds_obj_stack_get_value, walk_state);
/* Can't do it if the stack is empty */
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index eee0864..18b3ea9 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -116,7 +116,7 @@ union acpi_ec {
struct acpi_generic_address command_addr;
struct acpi_generic_address data_addr;
unsigned long global_lock;
- spinlock_t lock;
+ struct semaphore sem;
} poll;
};
@@ -323,7 +323,6 @@ static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data)
{
acpi_status status = AE_OK;
int result = 0;
- unsigned long flags = 0;
u32 glk = 0;
ACPI_FUNCTION_TRACE("acpi_ec_read");
@@ -339,8 +338,11 @@ static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data)
return_VALUE(-ENODEV);
}
- spin_lock_irqsave(&ec->poll.lock, flags);
-
+ if (down_interruptible(&ec->poll.sem)) {
+ result = -ERESTARTSYS;
+ goto end_nosem;
+ }
+
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ,
&ec->common.command_addr);
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
@@ -358,8 +360,8 @@ static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data)
*data, address));
end:
- spin_unlock_irqrestore(&ec->poll.lock, flags);
-
+ up(&ec->poll.sem);
+end_nosem:
if (ec->common.global_lock)
acpi_release_global_lock(glk);
@@ -370,7 +372,6 @@ static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data)
{
int result = 0;
acpi_status status = AE_OK;
- unsigned long flags = 0;
u32 glk = 0;
ACPI_FUNCTION_TRACE("acpi_ec_write");
@@ -384,8 +385,11 @@ static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data)
return_VALUE(-ENODEV);
}
- spin_lock_irqsave(&ec->poll.lock, flags);
-
+ if (down_interruptible(&ec->poll.sem)) {
+ result = -ERESTARTSYS;
+ goto end_nosem;
+ }
+
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE,
&ec->common.command_addr);
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
@@ -406,8 +410,8 @@ static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data)
data, address));
end:
- spin_unlock_irqrestore(&ec->poll.lock, flags);
-
+ up(&ec->poll.sem);
+end_nosem:
if (ec->common.global_lock)
acpi_release_global_lock(glk);
@@ -568,7 +572,6 @@ static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data)
{
int result = 0;
acpi_status status = AE_OK;
- unsigned long flags = 0;
u32 glk = 0;
ACPI_FUNCTION_TRACE("acpi_ec_query");
@@ -589,8 +592,11 @@ static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data)
* Note that successful completion of the query causes the ACPI_EC_SCI
* bit to be cleared (and thus clearing the interrupt source).
*/
- spin_lock_irqsave(&ec->poll.lock, flags);
-
+ if (down_interruptible(&ec->poll.sem)) {
+ result = -ERESTARTSYS;
+ goto end_nosem;
+ }
+
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY,
&ec->common.command_addr);
result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
@@ -602,8 +608,8 @@ static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data)
result = -ENODATA;
end:
- spin_unlock_irqrestore(&ec->poll.lock, flags);
-
+ up(&ec->poll.sem);
+end_nosem:
if (ec->common.global_lock)
acpi_release_global_lock(glk);
@@ -680,7 +686,6 @@ static void acpi_ec_gpe_poll_query(void *ec_cxt)
{
union acpi_ec *ec = (union acpi_ec *)ec_cxt;
u32 value = 0;
- unsigned long flags = 0;
static char object_name[5] = { '_', 'Q', '0', '0', '\0' };
const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
@@ -691,9 +696,11 @@ static void acpi_ec_gpe_poll_query(void *ec_cxt)
if (!ec_cxt)
goto end;
- spin_lock_irqsave(&ec->poll.lock, flags);
+ if (down_interruptible (&ec->poll.sem)) {
+ return_VOID;
+ }
acpi_hw_low_level_read(8, &value, &ec->common.command_addr);
- spin_unlock_irqrestore(&ec->poll.lock, flags);
+ up(&ec->poll.sem);
/* TBD: Implement asynch events!
* NOTE: All we care about are EC-SCI's. Other EC events are
@@ -763,8 +770,7 @@ static u32 acpi_ec_gpe_poll_handler(void *data)
acpi_disable_gpe(NULL, ec->common.gpe_bit, ACPI_ISR);
- status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE,
- acpi_ec_gpe_query, ec);
+ status = acpi_os_execute(OSL_EC_POLL_HANDLER, acpi_ec_gpe_query, ec);
if (status == AE_OK)
return ACPI_INTERRUPT_HANDLED;
@@ -799,7 +805,7 @@ static u32 acpi_ec_gpe_intr_handler(void *data)
if (value & ACPI_EC_FLAG_SCI) {
atomic_add(1, &ec->intr.pending_gpe);
- status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE,
+ status = acpi_os_execute(OSL_EC_BURST_HANDLER,
acpi_ec_gpe_query, ec);
return status == AE_OK ?
ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
@@ -991,7 +997,6 @@ static int acpi_ec_poll_add(struct acpi_device *device)
int result = 0;
acpi_status status = AE_OK;
union acpi_ec *ec = NULL;
- unsigned long uid;
ACPI_FUNCTION_TRACE("acpi_ec_add");
@@ -1005,7 +1010,7 @@ static int acpi_ec_poll_add(struct acpi_device *device)
ec->common.handle = device->handle;
ec->common.uid = -1;
- spin_lock_init(&ec->poll.lock);
+ init_MUTEX(&ec->poll.sem);
strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_EC_CLASS);
acpi_driver_data(device) = ec;
@@ -1014,10 +1019,9 @@ static int acpi_ec_poll_add(struct acpi_device *device)
acpi_evaluate_integer(ec->common.handle, "_GLK", NULL,
&ec->common.global_lock);
- /* If our UID matches the UID for the ECDT-enumerated EC,
- we now have the *real* EC info, so kill the makeshift one. */
- acpi_evaluate_integer(ec->common.handle, "_UID", NULL, &uid);
- if (ec_ecdt && ec_ecdt->common.uid == uid) {
+ /* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
+ http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
+ if (ec_ecdt) {
acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
ACPI_ADR_SPACE_EC,
&acpi_ec_space_handler);
@@ -1062,7 +1066,6 @@ static int acpi_ec_intr_add(struct acpi_device *device)
int result = 0;
acpi_status status = AE_OK;
union acpi_ec *ec = NULL;
- unsigned long uid;
ACPI_FUNCTION_TRACE("acpi_ec_add");
@@ -1088,10 +1091,9 @@ static int acpi_ec_intr_add(struct acpi_device *device)
acpi_evaluate_integer(ec->common.handle, "_GLK", NULL,
&ec->common.global_lock);
- /* If our UID matches the UID for the ECDT-enumerated EC,
- we now have the *real* EC info, so kill the makeshift one. */
- acpi_evaluate_integer(ec->common.handle, "_UID", NULL, &uid);
- if (ec_ecdt && ec_ecdt->common.uid == uid) {
+ /* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
+ http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
+ if (ec_ecdt) {
acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
ACPI_ADR_SPACE_EC,
&acpi_ec_space_handler);
@@ -1300,7 +1302,7 @@ acpi_fake_ecdt_poll_callback(acpi_handle handle,
&ec_ecdt->common.gpe_bit);
if (ACPI_FAILURE(status))
return status;
- spin_lock_init(&ec_ecdt->poll.lock);
+ init_MUTEX(&ec_ecdt->poll.sem);
ec_ecdt->common.global_lock = TRUE;
ec_ecdt->common.handle = handle;
@@ -1416,7 +1418,7 @@ static int __init acpi_ec_poll_get_real_ecdt(void)
ec_ecdt->common.status_addr = ecdt_ptr->ec_control;
ec_ecdt->common.data_addr = ecdt_ptr->ec_data;
ec_ecdt->common.gpe_bit = ecdt_ptr->gpe_bit;
- spin_lock_init(&ec_ecdt->poll.lock);
+ init_MUTEX(&ec_ecdt->poll.sem);
/* use the GL just to be safe */
ec_ecdt->common.global_lock = TRUE;
ec_ecdt->common.uid = ecdt_ptr->uid;
diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c
index c9ac05c..919037d 100644
--- a/drivers/acpi/events/evevent.c
+++ b/drivers/acpi/events/evevent.c
@@ -68,7 +68,7 @@ acpi_status acpi_ev_initialize_events(void)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ev_initialize_events");
+ ACPI_FUNCTION_TRACE(ev_initialize_events);
/* Make sure we have ACPI tables */
@@ -118,7 +118,7 @@ acpi_status acpi_ev_install_fadt_gpes(void)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ev_install_fadt_gpes");
+ ACPI_FUNCTION_TRACE(ev_install_fadt_gpes);
/* Namespace must be locked */
@@ -157,7 +157,7 @@ acpi_status acpi_ev_install_xrupt_handlers(void)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ev_install_xrupt_handlers");
+ ACPI_FUNCTION_TRACE(ev_install_xrupt_handlers);
/* Install the SCI handler */
@@ -241,7 +241,7 @@ u32 acpi_ev_fixed_event_detect(void)
u32 fixed_enable;
acpi_native_uint i;
- ACPI_FUNCTION_NAME("ev_fixed_event_detect");
+ ACPI_FUNCTION_NAME(ev_fixed_event_detect);
/*
* Read the fixed feature status and enable registers, as all the cases
@@ -260,12 +260,14 @@ u32 acpi_ev_fixed_event_detect(void)
* Check for all possible Fixed Events and dispatch those that are active
*/
for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
+
/* Both the status and enable bits must be on for this event */
if ((fixed_status & acpi_gbl_fixed_event_info[i].
status_bit_mask)
&& (fixed_enable & acpi_gbl_fixed_event_info[i].
enable_bit_mask)) {
+
/* Found an active (signalled) event */
int_status |= acpi_ev_fixed_event_dispatch((u32) i);
diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c
index f64f977..f01d339 100644
--- a/drivers/acpi/events/evgpe.c
+++ b/drivers/acpi/events/evgpe.c
@@ -69,7 +69,7 @@ acpi_ev_set_gpe_type(struct acpi_gpe_event_info *gpe_event_info, u8 type)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ev_set_gpe_type");
+ ACPI_FUNCTION_TRACE(ev_set_gpe_type);
/* Validate type and update register enable masks */
@@ -115,7 +115,7 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info,
struct acpi_gpe_register_info *gpe_register_info;
u8 register_bit;
- ACPI_FUNCTION_TRACE("ev_update_gpe_enable_masks");
+ ACPI_FUNCTION_TRACE(ev_update_gpe_enable_masks);
gpe_register_info = gpe_event_info->register_info;
if (!gpe_register_info) {
@@ -178,7 +178,7 @@ acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info,
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ev_enable_gpe");
+ ACPI_FUNCTION_TRACE(ev_enable_gpe);
/* Make sure HW enable masks are updated */
@@ -207,6 +207,7 @@ acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info,
ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);
if (write_to_hardware) {
+
/* Clear the GPE (of stale events), then enable it */
status = acpi_hw_clear_gpe(gpe_event_info);
@@ -243,7 +244,7 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ev_disable_gpe");
+ ACPI_FUNCTION_TRACE(ev_disable_gpe);
if (!(gpe_event_info->flags & ACPI_GPE_ENABLE_MASK)) {
return_ACPI_STATUS(AE_OK);
@@ -313,6 +314,7 @@ struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device,
/* A NULL gpe_block means use the FADT-defined GPE block(s) */
if (!gpe_device) {
+
/* Examine GPE Block 0 and 1 (These blocks are permanent) */
for (i = 0; i < ACPI_MAX_GPE_BLOCKS; i++) {
@@ -380,10 +382,11 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
u32 status_reg;
u32 enable_reg;
acpi_cpu_flags flags;
+ acpi_cpu_flags hw_flags;
acpi_native_uint i;
acpi_native_uint j;
- ACPI_FUNCTION_NAME("ev_gpe_detect");
+ ACPI_FUNCTION_NAME(ev_gpe_detect);
/* Check for the case where there are no GPEs */
@@ -391,9 +394,12 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
return (int_status);
}
- /* Examine all GPE blocks attached to this interrupt level */
+ /* We need to hold the GPE lock now, hardware lock in the loop */
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+ /* Examine all GPE blocks attached to this interrupt level */
+
gpe_block = gpe_xrupt_list->gpe_block_list_head;
while (gpe_block) {
/*
@@ -402,10 +408,13 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
* Find all currently active GP events.
*/
for (i = 0; i < gpe_block->register_count; i++) {
+
/* Get the next status/enable pair */
gpe_register_info = &gpe_block->register_info[i];
+ hw_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
+
/* Read the Status Register */
status =
@@ -414,6 +423,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
&gpe_register_info->
status_address);
if (ACPI_FAILURE(status)) {
+ acpi_os_release_lock(acpi_gbl_hardware_lock,
+ hw_flags);
goto unlock_and_exit;
}
@@ -424,6 +435,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
&enable_reg,
&gpe_register_info->
enable_address);
+ acpi_os_release_lock(acpi_gbl_hardware_lock, hw_flags);
+
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
@@ -437,6 +450,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
enabled_status_byte = (u8) (status_reg & enable_reg);
if (!enabled_status_byte) {
+
/* No active GPEs in this register, move on */
continue;
@@ -445,6 +459,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
/* Now look at the individual GPEs in this byte register */
for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
+
/* Examine one GPE bit */
if (enabled_status_byte &
@@ -483,9 +498,9 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
*
* RETURN: None
*
- * DESCRIPTION: Perform the actual execution of a GPE control method. This
- * function is called from an invocation of acpi_os_queue_for_execution
- * (and therefore does NOT execute at interrupt level) so that
+ * DESCRIPTION: Perform the actual execution of a GPE control method. This
+ * function is called from an invocation of acpi_os_execute and
+ * therefore does NOT execute at interrupt level - so that
* the control method itself is not executed in the context of
* an interrupt handler.
*
@@ -494,12 +509,11 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
{
struct acpi_gpe_event_info *gpe_event_info = (void *)context;
- u32 gpe_number = 0;
acpi_status status;
struct acpi_gpe_event_info local_gpe_event_info;
- struct acpi_parameter_info info;
+ struct acpi_evaluate_info *info;
- ACPI_FUNCTION_TRACE("ev_asynch_execute_gpe_method");
+ ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method);
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
if (ACPI_FAILURE(status)) {
@@ -535,22 +549,35 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
*/
if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) ==
ACPI_GPE_DISPATCH_METHOD) {
- /*
- * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx
- * control method that corresponds to this GPE
- */
- info.node = local_gpe_event_info.dispatch.method_node;
- info.parameters =
- ACPI_CAST_PTR(union acpi_operand_object *, gpe_event_info);
- info.parameter_type = ACPI_PARAM_GPE;
- status = acpi_ns_evaluate_by_handle(&info);
+ /* Allocate the evaluation information block */
+
+ info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
+ if (!info) {
+ status = AE_NO_MEMORY;
+ } else {
+ /*
+ * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx
+ * control method that corresponds to this GPE
+ */
+ info->prefix_node =
+ local_gpe_event_info.dispatch.method_node;
+ info->parameters =
+ ACPI_CAST_PTR(union acpi_operand_object *,
+ gpe_event_info);
+ info->parameter_type = ACPI_PARAM_GPE;
+ info->flags = ACPI_IGNORE_RETURN_VALUE;
+
+ status = acpi_ns_evaluate(info);
+ ACPI_FREE(info);
+ }
+
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
- "While evaluating method [%4.4s] for GPE[%2X]",
+ "While evaluating GPE method [%4.4s]",
acpi_ut_get_node_name
(local_gpe_event_info.dispatch.
- method_node), gpe_number));
+ method_node)));
}
}
@@ -593,7 +620,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ev_gpe_dispatch");
+ ACPI_FUNCTION_TRACE(ev_gpe_dispatch);
/*
* If edge-triggered, clear the GPE status bit now. Note that
@@ -669,9 +696,9 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
* Execute the method associated with the GPE
* NOTE: Level-triggered GPEs are cleared after the method completes.
*/
- status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE,
- acpi_ev_asynch_execute_gpe_method,
- gpe_event_info);
+ status = acpi_os_execute(OSL_GPE_HANDLER,
+ acpi_ev_asynch_execute_gpe_method,
+ gpe_event_info);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Unable to queue handler for GPE[%2X] - event disabled",
@@ -716,7 +743,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
*
* DESCRIPTION: Determine if a a GPE is "wake-only".
*
- * Called from Notify() code in interpreter when a "device_wake"
+ * Called from Notify() code in interpreter when a "DeviceWake"
* Notify comes in.
*
******************************************************************************/
@@ -726,7 +753,7 @@ acpi_ev_check_for_wake_only_gpe(struct acpi_gpe_event_info *gpe_event_info)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ev_check_for_wake_only_gpe");
+ ACPI_FUNCTION_TRACE(ev_check_for_wake_only_gpe);
if ((gpe_event_info) && /* Only >0 for _Lxx/_Exx */
((gpe_event_info->flags & ACPI_GPE_SYSTEM_MASK) == ACPI_GPE_SYSTEM_RUNNING)) { /* System state at GPE time */
diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c
index 0fd00b5..95ddeb4 100644
--- a/drivers/acpi/events/evgpeblk.c
+++ b/drivers/acpi/events/evgpeblk.c
@@ -131,14 +131,14 @@ u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info)
*
******************************************************************************/
-acpi_status acpi_ev_walk_gpe_list(ACPI_GPE_CALLBACK gpe_walk_callback)
+acpi_status acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback)
{
struct acpi_gpe_block_info *gpe_block;
struct acpi_gpe_xrupt_info *gpe_xrupt_info;
acpi_status status = AE_OK;
acpi_cpu_flags flags;
- ACPI_FUNCTION_TRACE("ev_walk_gpe_list");
+ ACPI_FUNCTION_TRACE(ev_walk_gpe_list);
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
@@ -146,10 +146,12 @@ acpi_status acpi_ev_walk_gpe_list(ACPI_GPE_CALLBACK gpe_walk_callback)
gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
while (gpe_xrupt_info) {
+
/* Walk all Gpe Blocks attached to this interrupt level */
gpe_block = gpe_xrupt_info->gpe_block_list_head;
while (gpe_block) {
+
/* One callback per GPE block */
status = gpe_walk_callback(gpe_xrupt_info, gpe_block);
@@ -190,11 +192,12 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
acpi_native_uint i;
acpi_native_uint j;
- ACPI_FUNCTION_TRACE("ev_delete_gpe_handlers");
+ ACPI_FUNCTION_TRACE(ev_delete_gpe_handlers);
/* Examine each GPE Register within the block */
for (i = 0; i < gpe_block->register_count; i++) {
+
/* Now look at the individual GPEs in this byte register */
for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
@@ -204,7 +207,7 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
ACPI_GPE_DISPATCH_HANDLER) {
- ACPI_MEM_FREE(gpe_event_info->dispatch.handler);
+ ACPI_FREE(gpe_event_info->dispatch.handler);
gpe_event_info->dispatch.handler = NULL;
gpe_event_info->flags &=
~ACPI_GPE_DISPATCH_MASK;
@@ -248,7 +251,7 @@ acpi_ev_save_method_info(acpi_handle obj_handle,
u8 type;
acpi_status status;
- ACPI_FUNCTION_TRACE("ev_save_method_info");
+ ACPI_FUNCTION_TRACE(ev_save_method_info);
/*
* _Lxx and _Exx GPE method support
@@ -279,9 +282,9 @@ acpi_ev_save_method_info(acpi_handle obj_handle,
default:
/* Unknown method type, just ignore it! */
- ACPI_ERROR((AE_INFO,
- "Unknown GPE method type: %s (name not of form _Lxx or _Exx)",
- name));
+ ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
+ "Ignoring unknown GPE method type: %s (name not of form _Lxx or _Exx)",
+ name));
return_ACPI_STATUS(AE_OK);
}
@@ -289,11 +292,12 @@ acpi_ev_save_method_info(acpi_handle obj_handle,
gpe_number = ACPI_STRTOUL(&name[2], NULL, 16);
if (gpe_number == ACPI_UINT32_MAX) {
+
/* Conversion failed; invalid method, just ignore it */
- ACPI_ERROR((AE_INFO,
- "Could not extract GPE number from name: %s (name is not of form _Lxx or _Exx)",
- name));
+ ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
+ "Could not extract GPE number from name: %s (name is not of form _Lxx or _Exx)",
+ name));
return_ACPI_STATUS(AE_OK);
}
@@ -364,13 +368,14 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle,
u32 gpe_number;
acpi_status status;
- ACPI_FUNCTION_TRACE("ev_match_prw_and_gpe");
+ ACPI_FUNCTION_TRACE(ev_match_prw_and_gpe);
/* Check for a _PRW method under this device */
status = acpi_ut_evaluate_object(obj_handle, METHOD_NAME__PRW,
ACPI_BTYPE_PACKAGE, &pkg_desc);
if (ACPI_FAILURE(status)) {
+
/* Ignore all errors from _PRW, we don't want to abort the subsystem */
return_ACPI_STATUS(AE_OK);
@@ -394,6 +399,7 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle,
obj_desc = pkg_desc->package.elements[0];
if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) {
+
/* Use FADT-defined GPE device (from definition of _PRW) */
target_gpe_device = acpi_gbl_fadt_gpe_device;
@@ -402,6 +408,7 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle,
gpe_number = (u32) obj_desc->integer.value;
} else if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_PACKAGE) {
+
/* Package contains a GPE reference and GPE number within a GPE block */
if ((obj_desc->package.count < 2) ||
@@ -482,7 +489,7 @@ static struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32
acpi_status status;
acpi_cpu_flags flags;
- ACPI_FUNCTION_TRACE("ev_get_gpe_xrupt_block");
+ ACPI_FUNCTION_TRACE(ev_get_gpe_xrupt_block);
/* No need for lock since we are not changing any list elements here */
@@ -497,7 +504,7 @@ static struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32
/* Not found, must allocate a new xrupt descriptor */
- gpe_xrupt = ACPI_MEM_CALLOCATE(sizeof(struct acpi_gpe_xrupt_info));
+ gpe_xrupt = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_xrupt_info));
if (!gpe_xrupt) {
return_PTR(NULL);
}
@@ -556,7 +563,7 @@ acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt)
acpi_status status;
acpi_cpu_flags flags;
- ACPI_FUNCTION_TRACE("ev_delete_gpe_xrupt");
+ ACPI_FUNCTION_TRACE(ev_delete_gpe_xrupt);
/* We never want to remove the SCI interrupt handler */
@@ -588,7 +595,7 @@ acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt)
/* Free the block */
- ACPI_MEM_FREE(gpe_xrupt);
+ ACPI_FREE(gpe_xrupt);
return_ACPI_STATUS(AE_OK);
}
@@ -614,7 +621,7 @@ acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block,
acpi_status status;
acpi_cpu_flags flags;
- ACPI_FUNCTION_TRACE("ev_install_gpe_block");
+ ACPI_FUNCTION_TRACE(ev_install_gpe_block);
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
if (ACPI_FAILURE(status)) {
@@ -667,7 +674,7 @@ acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block)
acpi_status status;
acpi_cpu_flags flags;
- ACPI_FUNCTION_TRACE("ev_install_gpe_block");
+ ACPI_FUNCTION_TRACE(ev_install_gpe_block);
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
if (ACPI_FAILURE(status)) {
@@ -679,6 +686,7 @@ acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block)
status = acpi_hw_disable_gpe_block(gpe_block->xrupt_block, gpe_block);
if (!gpe_block->previous && !gpe_block->next) {
+
/* This is the last gpe_block on this interrupt */
status = acpi_ev_delete_gpe_xrupt(gpe_block->xrupt_block);
@@ -704,9 +712,9 @@ acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block)
/* Free the gpe_block */
- ACPI_MEM_FREE(gpe_block->register_info);
- ACPI_MEM_FREE(gpe_block->event_info);
- ACPI_MEM_FREE(gpe_block);
+ ACPI_FREE(gpe_block->register_info);
+ ACPI_FREE(gpe_block->event_info);
+ ACPI_FREE(gpe_block);
unlock_and_exit:
status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
@@ -736,17 +744,17 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
acpi_native_uint j;
acpi_status status;
- ACPI_FUNCTION_TRACE("ev_create_gpe_info_blocks");
+ ACPI_FUNCTION_TRACE(ev_create_gpe_info_blocks);
/* Allocate the GPE register information block */
- gpe_register_info = ACPI_MEM_CALLOCATE((acpi_size) gpe_block->
- register_count *
- sizeof(struct
- acpi_gpe_register_info));
+ gpe_register_info = ACPI_ALLOCATE_ZEROED((acpi_size) gpe_block->
+ register_count *
+ sizeof(struct
+ acpi_gpe_register_info));
if (!gpe_register_info) {
ACPI_ERROR((AE_INFO,
- "Could not allocate the gpe_register_info table"));
+ "Could not allocate the GpeRegisterInfo table"));
return_ACPI_STATUS(AE_NO_MEMORY);
}
@@ -754,13 +762,14 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
* Allocate the GPE event_info block. There are eight distinct GPEs
* per register. Initialization to zeros is sufficient.
*/
- gpe_event_info = ACPI_MEM_CALLOCATE(((acpi_size) gpe_block->
- register_count *
- ACPI_GPE_REGISTER_WIDTH) *
- sizeof(struct acpi_gpe_event_info));
+ gpe_event_info = ACPI_ALLOCATE_ZEROED(((acpi_size) gpe_block->
+ register_count *
+ ACPI_GPE_REGISTER_WIDTH) *
+ sizeof(struct
+ acpi_gpe_event_info));
if (!gpe_event_info) {
ACPI_ERROR((AE_INFO,
- "Could not allocate the gpe_event_info table"));
+ "Could not allocate the GpeEventInfo table"));
status = AE_NO_MEMORY;
goto error_exit;
}
@@ -780,6 +789,7 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
this_event = gpe_event_info;
for (i = 0; i < gpe_block->register_count; i++) {
+
/* Init the register_info for this GPE register (8 GPEs) */
this_register->base_gpe_number =
@@ -839,10 +849,10 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
error_exit:
if (gpe_register_info) {
- ACPI_MEM_FREE(gpe_register_info);
+ ACPI_FREE(gpe_register_info);
}
if (gpe_event_info) {
- ACPI_MEM_FREE(gpe_event_info);
+ ACPI_FREE(gpe_event_info);
}
return_ACPI_STATUS(status);
@@ -878,7 +888,7 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
acpi_status status;
struct acpi_gpe_block_info *gpe_block;
- ACPI_FUNCTION_TRACE("ev_create_gpe_block");
+ ACPI_FUNCTION_TRACE(ev_create_gpe_block);
if (!register_count) {
return_ACPI_STATUS(AE_OK);
@@ -886,7 +896,7 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
/* Allocate a new GPE block */
- gpe_block = ACPI_MEM_CALLOCATE(sizeof(struct acpi_gpe_block_info));
+ gpe_block = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_block_info));
if (!gpe_block) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
@@ -906,7 +916,7 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
*/
status = acpi_ev_create_gpe_info_blocks(gpe_block);
if (ACPI_FAILURE(status)) {
- ACPI_MEM_FREE(gpe_block);
+ ACPI_FREE(gpe_block);
return_ACPI_STATUS(status);
}
@@ -914,7 +924,7 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
status = acpi_ev_install_gpe_block(gpe_block, interrupt_number);
if (ACPI_FAILURE(status)) {
- ACPI_MEM_FREE(gpe_block);
+ ACPI_FREE(gpe_block);
return_ACPI_STATUS(status);
}
@@ -971,7 +981,7 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
acpi_native_uint i;
acpi_native_uint j;
- ACPI_FUNCTION_TRACE("ev_initialize_gpe_block");
+ ACPI_FUNCTION_TRACE(ev_initialize_gpe_block);
/* Ignore a null GPE block (e.g., if no GPE block 1 exists) */
@@ -1013,6 +1023,7 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
for (i = 0; i < gpe_block->register_count; i++) {
for (j = 0; j < 8; j++) {
+
/* Get the info block for this particular GPE */
gpe_event_info =
@@ -1040,7 +1051,7 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
status = acpi_hw_enable_runtime_gpe_block(NULL, gpe_block);
if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO, "Could not enable GPEs in gpe_block %p",
+ ACPI_ERROR((AE_INFO, "Could not enable GPEs in GpeBlock %p",
gpe_block));
}
@@ -1066,7 +1077,7 @@ acpi_status acpi_ev_gpe_initialize(void)
u32 gpe_number_max = 0;
acpi_status status;
- ACPI_FUNCTION_TRACE("ev_gpe_initialize");
+ ACPI_FUNCTION_TRACE(ev_gpe_initialize);
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
@@ -1099,6 +1110,7 @@ acpi_status acpi_ev_gpe_initialize(void)
* particular block is not supported.
*/
if (acpi_gbl_FADT->gpe0_blk_len && acpi_gbl_FADT->xgpe0_blk.address) {
+
/* GPE block 0 exists (has both length and address > 0) */
register_count0 = (u16) (acpi_gbl_FADT->gpe0_blk_len / 2);
@@ -1121,6 +1133,7 @@ acpi_status acpi_ev_gpe_initialize(void)
}
if (acpi_gbl_FADT->gpe1_blk_len && acpi_gbl_FADT->xgpe1_blk.address) {
+
/* GPE block 1 exists (has both length and address > 0) */
register_count1 = (u16) (acpi_gbl_FADT->gpe1_blk_len / 2);
@@ -1168,6 +1181,7 @@ acpi_status acpi_ev_gpe_initialize(void)
/* Exit if there are no GPE registers */
if ((register_count0 + register_count1) == 0) {
+
/* GPEs are not required by ACPI, this is OK */
ACPI_DEBUG_PRINT((ACPI_DB_INIT,
diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c
index 0909ba6..6eef4ef 100644
--- a/drivers/acpi/events/evmisc.c
+++ b/drivers/acpi/events/evmisc.c
@@ -49,12 +49,13 @@
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evmisc")
+/* Names for Notify() values, used for debug output */
#ifdef ACPI_DEBUG_OUTPUT
static const char *acpi_notify_value_names[] = {
"Bus Check",
"Device Check",
"Device Wake",
- "Eject request",
+ "Eject Request",
"Device Check Light",
"Frequency Mismatch",
"Bus Mode Mismatch",
@@ -124,7 +125,7 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
union acpi_generic_state *notify_info;
acpi_status status = AE_OK;
- ACPI_FUNCTION_NAME("ev_queue_notify_request");
+ ACPI_FUNCTION_NAME(ev_queue_notify_request);
/*
* For value 3 (Ejection Request), some device method may need to be run.
@@ -150,6 +151,7 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
obj_desc = acpi_ns_get_attached_object(node);
if (obj_desc) {
+
/* We have the notify object, Get the right handler */
switch (node->type) {
@@ -184,14 +186,15 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
return (AE_NO_MEMORY);
}
- notify_info->common.data_type = ACPI_DESC_TYPE_STATE_NOTIFY;
+ notify_info->common.descriptor_type =
+ ACPI_DESC_TYPE_STATE_NOTIFY;
notify_info->notify.node = node;
notify_info->notify.value = (u16) notify_value;
notify_info->notify.handler_obj = handler_obj;
- status = acpi_os_queue_for_execution(OSD_PRIORITY_HIGH,
- acpi_ev_notify_dispatch,
- notify_info);
+ status =
+ acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch,
+ notify_info);
if (ACPI_FAILURE(status)) {
acpi_ut_delete_generic_state(notify_info);
}
@@ -240,6 +243,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
* to the device.
*/
if (notify_info->notify.value <= ACPI_MAX_SYS_NOTIFY) {
+
/* Global system notification handler */
if (acpi_gbl_system_notify.handler) {
@@ -297,6 +301,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread(void *context)
/* Signal threads that are waiting for the lock */
if (acpi_gbl_global_lock_thread_count) {
+
/* Send sufficient units to the semaphore */
status =
@@ -335,15 +340,16 @@ static u32 acpi_ev_global_lock_handler(void *context)
*/
ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired);
if (acquired) {
+
/* Got the lock, now wake all threads waiting for it */
acpi_gbl_global_lock_acquired = TRUE;
/* Run the Global Lock thread which will signal all waiting threads */
- status = acpi_os_queue_for_execution(OSD_PRIORITY_HIGH,
- acpi_ev_global_lock_thread,
- context);
+ status =
+ acpi_os_execute(OSL_GLOBAL_LOCK_HANDLER,
+ acpi_ev_global_lock_thread, context);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Could not queue Global Lock thread"));
@@ -371,7 +377,7 @@ acpi_status acpi_ev_init_global_lock_handler(void)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ev_init_global_lock_handler");
+ ACPI_FUNCTION_TRACE(ev_init_global_lock_handler);
acpi_gbl_global_lock_present = TRUE;
status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL,
@@ -413,7 +419,7 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
acpi_status status = AE_OK;
u8 acquired = FALSE;
- ACPI_FUNCTION_TRACE("ev_acquire_global_lock");
+ ACPI_FUNCTION_TRACE(ev_acquire_global_lock);
#ifndef ACPI_APPLICATION
/* Make sure that we actually have a global lock */
@@ -439,6 +445,7 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired);
if (acquired) {
+
/* We got the lock */
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
@@ -458,8 +465,9 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
* Acquire the global lock semaphore first.
* Since this wait will block, we must release the interpreter
*/
- status = acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore,
- timeout);
+ status =
+ acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore,
+ timeout);
return_ACPI_STATUS(status);
}
@@ -480,7 +488,7 @@ acpi_status acpi_ev_release_global_lock(void)
u8 pending = FALSE;
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("ev_release_global_lock");
+ ACPI_FUNCTION_TRACE(ev_release_global_lock);
if (!acpi_gbl_global_lock_thread_count) {
ACPI_WARNING((AE_INFO,
@@ -492,6 +500,7 @@ acpi_status acpi_ev_release_global_lock(void)
acpi_gbl_global_lock_thread_count--;
if (acpi_gbl_global_lock_thread_count) {
+
/* There are still some threads holding the lock, cannot release */
return_ACPI_STATUS(AE_OK);
@@ -533,7 +542,7 @@ void acpi_ev_terminate(void)
acpi_native_uint i;
acpi_status status;
- ACPI_FUNCTION_TRACE("ev_terminate");
+ ACPI_FUNCTION_TRACE(ev_terminate);
if (acpi_gbl_events_initialized) {
/*
@@ -573,7 +582,7 @@ void acpi_ev_terminate(void)
if (acpi_gbl_original_mode == ACPI_SYS_MODE_LEGACY) {
status = acpi_disable();
if (ACPI_FAILURE(status)) {
- ACPI_WARNING((AE_INFO, "acpi_disable failed"));
+ ACPI_WARNING((AE_INFO, "AcpiDisable failed"));
}
}
return_VOID;
diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c
index 6da58e7..094a17e 100644
--- a/drivers/acpi/events/evregion.c
+++ b/drivers/acpi/events/evregion.c
@@ -83,7 +83,7 @@ acpi_status acpi_ev_install_region_handlers(void)
acpi_status status;
acpi_native_uint i;
- ACPI_FUNCTION_TRACE("ev_install_region_handlers");
+ ACPI_FUNCTION_TRACE(ev_install_region_handlers);
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
@@ -153,7 +153,7 @@ acpi_status acpi_ev_initialize_op_regions(void)
acpi_status status;
acpi_native_uint i;
- ACPI_FUNCTION_TRACE("ev_initialize_op_regions");
+ ACPI_FUNCTION_TRACE(ev_initialize_op_regions);
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
@@ -164,6 +164,7 @@ acpi_status acpi_ev_initialize_op_regions(void)
* Run the _REG methods for op_regions in each default address space
*/
for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) {
+
/* TBD: Make sure handler is the DEFAULT handler, otherwise
* _REG will have already been run.
*/
@@ -192,12 +193,12 @@ acpi_status acpi_ev_initialize_op_regions(void)
acpi_status
acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
{
- struct acpi_parameter_info info;
- union acpi_operand_object *params[3];
+ struct acpi_evaluate_info *info;
+ union acpi_operand_object *args[3];
union acpi_operand_object *region_obj2;
acpi_status status;
- ACPI_FUNCTION_TRACE("ev_execute_reg_method");
+ ACPI_FUNCTION_TRACE(ev_execute_reg_method);
region_obj2 = acpi_ns_get_secondary_object(region_obj);
if (!region_obj2) {
@@ -208,48 +209,60 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
return_ACPI_STATUS(AE_OK);
}
+ /* Allocate and initialize the evaluation information block */
+
+ info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
+ if (!info) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ info->prefix_node = region_obj2->extra.method_REG;
+ info->pathname = NULL;
+ info->parameters = args;
+ info->parameter_type = ACPI_PARAM_ARGS;
+ info->flags = ACPI_IGNORE_RETURN_VALUE;
+
/*
* The _REG method has two arguments:
*
- * Arg0, Integer: Operation region space ID
- * Same value as region_obj->Region.space_id
- * Arg1, Integer: connection status
- * 1 for connecting the handler,
- * 0 for disconnecting the handler
- * Passed as a parameter
+ * Arg0 - Integer:
+ * Operation region space ID Same value as region_obj->Region.space_id
+ *
+ * Arg1 - Integer:
+ * connection status 1 for connecting the handler, 0 for disconnecting
+ * the handler (Passed as a parameter)
*/
- params[0] = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
- if (!params[0]) {
- return_ACPI_STATUS(AE_NO_MEMORY);
+ args[0] = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
+ if (!args[0]) {
+ status = AE_NO_MEMORY;
+ goto cleanup1;
}
- params[1] = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
- if (!params[1]) {
+ args[1] = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
+ if (!args[1]) {
status = AE_NO_MEMORY;
- goto cleanup;
+ goto cleanup2;
}
/* Setup the parameter objects */
- params[0]->integer.value = region_obj->region.space_id;
- params[1]->integer.value = function;
- params[2] = NULL;
-
- info.node = region_obj2->extra.method_REG;
- info.parameters = params;
- info.parameter_type = ACPI_PARAM_ARGS;
+ args[0]->integer.value = region_obj->region.space_id;
+ args[1]->integer.value = function;
+ args[2] = NULL;
/* Execute the method, no return value */
ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
- (ACPI_TYPE_METHOD, info.node, NULL));
- status = acpi_ns_evaluate_by_handle(&info);
+ (ACPI_TYPE_METHOD, info->prefix_node, NULL));
- acpi_ut_remove_reference(params[1]);
+ status = acpi_ns_evaluate(info);
+ acpi_ut_remove_reference(args[1]);
- cleanup:
- acpi_ut_remove_reference(params[0]);
+ cleanup2:
+ acpi_ut_remove_reference(args[0]);
+ cleanup1:
+ ACPI_FREE(info);
return_ACPI_STATUS(status);
}
@@ -261,7 +274,8 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
* Function - Read or Write operation
* Address - Where in the space to read or write
* bit_width - Field width in bits (8, 16, 32, or 64)
- * Value - Pointer to in or out value
+ * Value - Pointer to in or out value, must be
+ * full 64-bit acpi_integer
*
* RETURN: Status
*
@@ -274,7 +288,7 @@ acpi_status
acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
u32 function,
acpi_physical_address address,
- u32 bit_width, void *value)
+ u32 bit_width, acpi_integer * value)
{
acpi_status status;
acpi_status status2;
@@ -284,7 +298,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
union acpi_operand_object *region_obj2;
void *region_context = NULL;
- ACPI_FUNCTION_TRACE("ev_address_space_dispatch");
+ ACPI_FUNCTION_TRACE(ev_address_space_dispatch);
region_obj2 = acpi_ns_get_secondary_object(region_obj);
if (!region_obj2) {
@@ -315,6 +329,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
*/
region_setup = handler_desc->address_space.setup;
if (!region_setup) {
+
/* No initialization routine, exit with error */
ACPI_ERROR((AE_INFO,
@@ -361,9 +376,10 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
region_obj->region.flags |= AOPOBJ_SETUP_COMPLETE;
if (region_obj2->extra.region_context) {
+
/* The handler for this region was already installed */
- ACPI_MEM_FREE(region_context);
+ ACPI_FREE(region_context);
} else {
/*
* Save the returned context for use in all accesses to
@@ -386,9 +402,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
acpi_ut_get_region_name(region_obj->region.
space_id)));
- if (!
- (handler_desc->address_space.
- hflags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
+ if (!(handler_desc->address_space.handler_flags &
+ ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
/*
* For handlers other than the default (supplied) handlers, we must
* exit the interpreter because the handler *might* block -- we don't
@@ -409,9 +424,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
space_id)));
}
- if (!
- (handler_desc->address_space.
- hflags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
+ if (!(handler_desc->address_space.handler_flags &
+ ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
/*
* We just returned from a non-default handler, we must re-enter the
* interpreter
@@ -451,7 +465,7 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
union acpi_operand_object *region_obj2;
acpi_status status;
- ACPI_FUNCTION_TRACE("ev_detach_region");
+ ACPI_FUNCTION_TRACE(ev_detach_region);
region_obj2 = acpi_ns_get_secondary_object(region_obj);
if (!region_obj2) {
@@ -463,6 +477,7 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
handler_obj = region_obj->region.handler;
if (!handler_obj) {
+
/* This region has no handler, all done */
return_VOID;
@@ -474,6 +489,7 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
last_obj_ptr = &handler_obj->address_space.region_list;
while (obj_desc) {
+
/* Is this the correct Region? */
if (obj_desc == region_obj) {
@@ -583,7 +599,7 @@ acpi_ev_attach_region(union acpi_operand_object *handler_obj,
u8 acpi_ns_is_locked)
{
- ACPI_FUNCTION_TRACE("ev_attach_region");
+ ACPI_FUNCTION_TRACE(ev_attach_region);
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
"Adding Region [%4.4s] %p to address handler %p [%s]\n",
@@ -636,7 +652,7 @@ acpi_ev_install_handler(acpi_handle obj_handle,
struct acpi_namespace_node *node;
acpi_status status;
- ACPI_FUNCTION_NAME("ev_install_handler");
+ ACPI_FUNCTION_NAME(ev_install_handler);
handler_obj = (union acpi_operand_object *)context;
@@ -666,6 +682,7 @@ acpi_ev_install_handler(acpi_handle obj_handle,
obj_desc = acpi_ns_get_attached_object(node);
if (!obj_desc) {
+
/* No object, just exit */
return (AE_OK);
@@ -674,10 +691,12 @@ acpi_ev_install_handler(acpi_handle obj_handle,
/* Devices are handled different than regions */
if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_DEVICE) {
+
/* Check if this Device already has a handler for this address space */
next_handler_obj = obj_desc->device.handler;
while (next_handler_obj) {
+
/* Found a handler, is it for the same address space? */
if (next_handler_obj->address_space.space_id ==
@@ -764,9 +783,9 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node,
union acpi_operand_object *handler_obj;
acpi_status status;
acpi_object_type type;
- u16 flags = 0;
+ u8 flags = 0;
- ACPI_FUNCTION_TRACE("ev_install_space_handler");
+ ACPI_FUNCTION_TRACE(ev_install_space_handler);
/*
* This registration is valid for only the types below
@@ -839,6 +858,7 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node,
/* Walk the handler list for this device */
while (handler_obj) {
+
/* Same space_id indicates a handler already installed */
if (handler_obj->address_space.space_id == space_id) {
@@ -921,7 +941,7 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node,
/* Init handler obj */
handler_obj->address_space.space_id = (u8) space_id;
- handler_obj->address_space.hflags = flags;
+ handler_obj->address_space.handler_flags = flags;
handler_obj->address_space.region_list = NULL;
handler_obj->address_space.node = node;
handler_obj->address_space.handler = handler;
@@ -979,7 +999,7 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node,
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ev_execute_reg_methods");
+ ACPI_FUNCTION_TRACE(ev_execute_reg_methods);
/*
* Run all _REG methods for all Operation Regions for this
@@ -1001,7 +1021,7 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node,
*
* PARAMETERS: walk_namespace callback
*
- * DESCRIPTION: Run _REg method for region objects of the requested space_iD
+ * DESCRIPTION: Run _REG method for region objects of the requested space_iD
*
******************************************************************************/
@@ -1035,6 +1055,7 @@ acpi_ev_reg_run(acpi_handle obj_handle,
obj_desc = acpi_ns_get_attached_object(node);
if (!obj_desc) {
+
/* No object, just exit */
return (AE_OK);
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
index baed8c1..5b3c7a8 100644
--- a/drivers/acpi/events/evrgnini.c
+++ b/drivers/acpi/events/evrgnini.c
@@ -71,11 +71,22 @@ acpi_ev_system_memory_region_setup(acpi_handle handle,
(union acpi_operand_object *)handle;
struct acpi_mem_space_context *local_region_context;
- ACPI_FUNCTION_TRACE("ev_system_memory_region_setup");
+ ACPI_FUNCTION_TRACE(ev_system_memory_region_setup);
if (function == ACPI_REGION_DEACTIVATE) {
if (*region_context) {
- ACPI_MEM_FREE(*region_context);
+ local_region_context =
+ (struct acpi_mem_space_context *)*region_context;
+
+ /* Delete a cached mapping if present */
+
+ if (local_region_context->mapped_length) {
+ acpi_os_unmap_memory(local_region_context->
+ mapped_logical_address,
+ local_region_context->
+ mapped_length);
+ }
+ ACPI_FREE(local_region_context);
*region_context = NULL;
}
return_ACPI_STATUS(AE_OK);
@@ -84,7 +95,7 @@ acpi_ev_system_memory_region_setup(acpi_handle handle,
/* Create a new context */
local_region_context =
- ACPI_MEM_CALLOCATE(sizeof(struct acpi_mem_space_context));
+ ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_mem_space_context));
if (!(local_region_context)) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
@@ -118,7 +129,7 @@ acpi_ev_io_space_region_setup(acpi_handle handle,
u32 function,
void *handler_context, void **region_context)
{
- ACPI_FUNCTION_TRACE("ev_io_space_region_setup");
+ ACPI_FUNCTION_TRACE(ev_io_space_region_setup);
if (function == ACPI_REGION_DEACTIVATE) {
*region_context = NULL;
@@ -161,7 +172,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
(union acpi_operand_object *)handle;
struct acpi_device_id object_hID;
- ACPI_FUNCTION_TRACE("ev_pci_config_region_setup");
+ ACPI_FUNCTION_TRACE(ev_pci_config_region_setup);
handler_obj = region_obj->region.handler;
if (!handler_obj) {
@@ -178,7 +189,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
*region_context = NULL;
if (function == ACPI_REGION_DEACTIVATE) {
if (pci_id) {
- ACPI_MEM_FREE(pci_id);
+ ACPI_FREE(pci_id);
}
return_ACPI_STATUS(status);
}
@@ -199,6 +210,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
* handlers with that device.
*/
if (handler_obj->address_space.node == acpi_gbl_root_node) {
+
/* Start search from the parent object */
pci_root_node = parent_node;
@@ -220,6 +232,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
PCI_EXPRESS_ROOT_HID_STRING,
sizeof(PCI_EXPRESS_ROOT_HID_STRING)))))
{
+
/* Install a handler for this PCI root bridge */
status =
@@ -235,7 +248,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
} else {
ACPI_EXCEPTION((AE_INFO,
status,
- "Could not install pci_config handler for Root Bridge %4.4s",
+ "Could not install PciConfig handler for Root Bridge %4.4s",
acpi_ut_get_node_name
(pci_root_node)));
}
@@ -262,7 +275,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
/* Region is still not initialized. Create a new context */
- pci_id = ACPI_MEM_CALLOCATE(sizeof(struct acpi_pci_id));
+ pci_id = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pci_id));
if (!pci_id) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
@@ -337,7 +350,7 @@ acpi_ev_pci_bar_region_setup(acpi_handle handle,
u32 function,
void *handler_context, void **region_context)
{
- ACPI_FUNCTION_TRACE("ev_pci_bar_region_setup");
+ ACPI_FUNCTION_TRACE(ev_pci_bar_region_setup);
return_ACPI_STATUS(AE_OK);
}
@@ -364,7 +377,7 @@ acpi_ev_cmos_region_setup(acpi_handle handle,
u32 function,
void *handler_context, void **region_context)
{
- ACPI_FUNCTION_TRACE("ev_cmos_region_setup");
+ ACPI_FUNCTION_TRACE(ev_cmos_region_setup);
return_ACPI_STATUS(AE_OK);
}
@@ -389,7 +402,7 @@ acpi_ev_default_region_setup(acpi_handle handle,
u32 function,
void *handler_context, void **region_context)
{
- ACPI_FUNCTION_TRACE("ev_default_region_setup");
+ ACPI_FUNCTION_TRACE(ev_default_region_setup);
if (function == ACPI_REGION_DEACTIVATE) {
*region_context = NULL;
@@ -435,7 +448,7 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj,
acpi_name *reg_name_ptr = (acpi_name *) METHOD_NAME__REG;
union acpi_operand_object *region_obj2;
- ACPI_FUNCTION_TRACE_U32("ev_initialize_region", acpi_ns_locked);
+ ACPI_FUNCTION_TRACE_U32(ev_initialize_region, acpi_ns_locked);
if (!region_obj) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -462,8 +475,9 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj,
/* Find any "_REG" method associated with this region definition */
- status = acpi_ns_search_node(*reg_name_ptr, node,
- ACPI_TYPE_METHOD, &method_node);
+ status =
+ acpi_ns_search_one_scope(*reg_name_ptr, node, ACPI_TYPE_METHOD,
+ &method_node);
if (ACPI_SUCCESS(status)) {
/*
* The _REG method is optional and there can be only one per region
@@ -478,11 +492,13 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj,
* ie: acpi_gbl_root_node->parent_entry being set to NULL
*/
while (node) {
+
/* Check to see if a handler exists */
handler_obj = NULL;
obj_desc = acpi_ns_get_attached_object(node);
if (obj_desc) {
+
/* Can only be a handler if the object exists */
switch (node->type) {
@@ -507,10 +523,12 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj,
}
while (handler_obj) {
+
/* Is this handler of the correct type? */
if (handler_obj->address_space.space_id ==
space_id) {
+
/* Found correct handler */
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
@@ -571,7 +589,7 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj,
/* If we get here, there is no handler for this region */
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
- "No handler for region_type %s(%X) (region_obj %p)\n",
+ "No handler for RegionType %s(%X) (RegionObj %p)\n",
acpi_ut_get_region_name(space_id), space_id,
region_obj));
diff --git a/drivers/acpi/events/evsci.c b/drivers/acpi/events/evsci.c
index 9a62216..8106215 100644
--- a/drivers/acpi/events/evsci.c
+++ b/drivers/acpi/events/evsci.c
@@ -69,7 +69,7 @@ static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context)
struct acpi_gpe_xrupt_info *gpe_xrupt_list = context;
u32 interrupt_handled = ACPI_INTERRUPT_NOT_HANDLED;
- ACPI_FUNCTION_TRACE("ev_sci_xrupt_handler");
+ ACPI_FUNCTION_TRACE(ev_sci_xrupt_handler);
/*
* We are guaranteed by the ACPI CA initialization/shutdown code that
@@ -108,7 +108,7 @@ u32 ACPI_SYSTEM_XFACE acpi_ev_gpe_xrupt_handler(void *context)
struct acpi_gpe_xrupt_info *gpe_xrupt_list = context;
u32 interrupt_handled = ACPI_INTERRUPT_NOT_HANDLED;
- ACPI_FUNCTION_TRACE("ev_gpe_xrupt_handler");
+ ACPI_FUNCTION_TRACE(ev_gpe_xrupt_handler);
/*
* We are guaranteed by the ACPI CA initialization/shutdown code that
@@ -140,7 +140,7 @@ u32 acpi_ev_install_sci_handler(void)
{
u32 status = AE_OK;
- ACPI_FUNCTION_TRACE("ev_install_sci_handler");
+ ACPI_FUNCTION_TRACE(ev_install_sci_handler);
status = acpi_os_install_interrupt_handler((u32) acpi_gbl_FADT->sci_int,
acpi_ev_sci_xrupt_handler,
@@ -171,7 +171,7 @@ acpi_status acpi_ev_remove_sci_handler(void)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ev_remove_sci_handler");
+ ACPI_FUNCTION_TRACE(ev_remove_sci_handler);
/* Just let the OS remove the handler and disable the level */
diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c
index b38b39d..76c34a6 100644
--- a/drivers/acpi/events/evxface.c
+++ b/drivers/acpi/events/evxface.c
@@ -41,8 +41,6 @@
* POSSIBILITY OF SUCH DAMAGES.
*/
-#include <linux/module.h>
-
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
#include <acpi/acevents.h>
@@ -68,7 +66,7 @@ acpi_status acpi_install_exception_handler(acpi_exception_handler handler)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_install_exception_handler");
+ ACPI_FUNCTION_TRACE(acpi_install_exception_handler);
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
if (ACPI_FAILURE(status)) {
@@ -90,6 +88,8 @@ acpi_status acpi_install_exception_handler(acpi_exception_handler handler)
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
return_ACPI_STATUS(status);
}
+
+ACPI_EXPORT_SYMBOL(acpi_install_exception_handler)
#endif /* ACPI_FUTURE_USAGE */
/*******************************************************************************
@@ -107,14 +107,13 @@ acpi_status acpi_install_exception_handler(acpi_exception_handler handler)
* event.
*
******************************************************************************/
-
acpi_status
acpi_install_fixed_event_handler(u32 event,
acpi_event_handler handler, void *context)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_install_fixed_event_handler");
+ ACPI_FUNCTION_TRACE(acpi_install_fixed_event_handler);
/* Parameter validation */
@@ -161,7 +160,7 @@ acpi_install_fixed_event_handler(u32 event,
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_install_fixed_event_handler);
+ACPI_EXPORT_SYMBOL(acpi_install_fixed_event_handler)
/*******************************************************************************
*
@@ -175,13 +174,12 @@ EXPORT_SYMBOL(acpi_install_fixed_event_handler);
* DESCRIPTION: Disables the event and unregisters the event handler.
*
******************************************************************************/
-
acpi_status
acpi_remove_fixed_event_handler(u32 event, acpi_event_handler handler)
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("acpi_remove_fixed_event_handler");
+ ACPI_FUNCTION_TRACE(acpi_remove_fixed_event_handler);
/* Parameter validation */
@@ -216,7 +214,7 @@ acpi_remove_fixed_event_handler(u32 event, acpi_event_handler handler)
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_remove_fixed_event_handler);
+ACPI_EXPORT_SYMBOL(acpi_remove_fixed_event_handler)
/*******************************************************************************
*
@@ -235,7 +233,6 @@ EXPORT_SYMBOL(acpi_remove_fixed_event_handler);
* DESCRIPTION: Install a handler for notifies on an ACPI device
*
******************************************************************************/
-
acpi_status
acpi_install_notify_handler(acpi_handle device,
u32 handler_type,
@@ -246,7 +243,7 @@ acpi_install_notify_handler(acpi_handle device,
struct acpi_namespace_node *node;
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_install_notify_handler");
+ ACPI_FUNCTION_TRACE(acpi_install_notify_handler);
/* Parameter validation */
@@ -275,6 +272,7 @@ acpi_install_notify_handler(acpi_handle device,
* only one <external> global handler can be regsitered (per notify type).
*/
if (device == ACPI_ROOT_OBJECT) {
+
/* Make sure the handler is not already installed */
if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
@@ -317,6 +315,7 @@ acpi_install_notify_handler(acpi_handle device,
obj_desc = acpi_ns_get_attached_object(node);
if (obj_desc) {
+
/* Object exists - make sure there's no handler */
if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
@@ -370,6 +369,7 @@ acpi_install_notify_handler(acpi_handle device,
}
if (handler_type == ACPI_ALL_NOTIFY) {
+
/* Extra ref if installed in both */
acpi_ut_add_reference(notify_obj);
@@ -381,7 +381,7 @@ acpi_install_notify_handler(acpi_handle device,
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_install_notify_handler);
+ACPI_EXPORT_SYMBOL(acpi_install_notify_handler)
/*******************************************************************************
*
@@ -399,7 +399,6 @@ EXPORT_SYMBOL(acpi_install_notify_handler);
* DESCRIPTION: Remove a handler for notifies on an ACPI device
*
******************************************************************************/
-
acpi_status
acpi_remove_notify_handler(acpi_handle device,
u32 handler_type, acpi_notify_handler handler)
@@ -409,7 +408,7 @@ acpi_remove_notify_handler(acpi_handle device,
struct acpi_namespace_node *node;
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_remove_notify_handler");
+ ACPI_FUNCTION_TRACE(acpi_remove_notify_handler);
/* Parameter validation */
@@ -535,7 +534,7 @@ acpi_remove_notify_handler(acpi_handle device,
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_remove_notify_handler);
+ACPI_EXPORT_SYMBOL(acpi_remove_notify_handler)
/*******************************************************************************
*
@@ -554,7 +553,6 @@ EXPORT_SYMBOL(acpi_remove_notify_handler);
* DESCRIPTION: Install a handler for a General Purpose Event.
*
******************************************************************************/
-
acpi_status
acpi_install_gpe_handler(acpi_handle gpe_device,
u32 gpe_number,
@@ -565,7 +563,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
acpi_status status;
acpi_cpu_flags flags;
- ACPI_FUNCTION_TRACE("acpi_install_gpe_handler");
+ ACPI_FUNCTION_TRACE(acpi_install_gpe_handler);
/* Parameter validation */
@@ -596,7 +594,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
/* Allocate and init handler object */
- handler = ACPI_MEM_CALLOCATE(sizeof(struct acpi_handler_info));
+ handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_handler_info));
if (!handler) {
status = AE_NO_MEMORY;
goto unlock_and_exit;
@@ -630,7 +628,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_install_gpe_handler);
+ACPI_EXPORT_SYMBOL(acpi_install_gpe_handler)
/*******************************************************************************
*
@@ -646,7 +644,6 @@ EXPORT_SYMBOL(acpi_install_gpe_handler);
* DESCRIPTION: Remove a handler for a General Purpose acpi_event.
*
******************************************************************************/
-
acpi_status
acpi_remove_gpe_handler(acpi_handle gpe_device,
u32 gpe_number, acpi_event_handler address)
@@ -656,7 +653,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
acpi_status status;
acpi_cpu_flags flags;
- ACPI_FUNCTION_TRACE("acpi_remove_gpe_handler");
+ ACPI_FUNCTION_TRACE(acpi_remove_gpe_handler);
/* Parameter validation */
@@ -724,14 +721,14 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
/* Now we can free the handler object */
- ACPI_MEM_FREE(handler);
+ ACPI_FREE(handler);
unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_remove_gpe_handler);
+ACPI_EXPORT_SYMBOL(acpi_remove_gpe_handler)
/*******************************************************************************
*
@@ -746,7 +743,6 @@ EXPORT_SYMBOL(acpi_remove_gpe_handler);
* DESCRIPTION: Acquire the ACPI Global Lock
*
******************************************************************************/
-
acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle)
{
acpi_status status;
@@ -771,7 +767,7 @@ acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle)
return (status);
}
-EXPORT_SYMBOL(acpi_acquire_global_lock);
+ACPI_EXPORT_SYMBOL(acpi_acquire_global_lock)
/*******************************************************************************
*
@@ -784,7 +780,6 @@ EXPORT_SYMBOL(acpi_acquire_global_lock);
* DESCRIPTION: Release the ACPI Global Lock. The handle must be valid.
*
******************************************************************************/
-
acpi_status acpi_release_global_lock(u32 handle)
{
acpi_status status;
@@ -797,4 +792,4 @@ acpi_status acpi_release_global_lock(u32 handle)
return (status);
}
-EXPORT_SYMBOL(acpi_release_global_lock);
+ACPI_EXPORT_SYMBOL(acpi_release_global_lock)
diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c
index ec9ce84..7ebc2ef 100644
--- a/drivers/acpi/events/evxfevnt.c
+++ b/drivers/acpi/events/evxfevnt.c
@@ -41,8 +41,6 @@
* POSSIBILITY OF SUCH DAMAGES.
*/
-#include <linux/module.h>
-
#include <acpi/acpi.h>
#include <acpi/acevents.h>
#include <acpi/acnamesp.h>
@@ -65,7 +63,7 @@ acpi_status acpi_enable(void)
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("acpi_enable");
+ ACPI_FUNCTION_TRACE(acpi_enable);
/* Make sure we have the FADT */
@@ -94,6 +92,8 @@ acpi_status acpi_enable(void)
return_ACPI_STATUS(status);
}
+ACPI_EXPORT_SYMBOL(acpi_enable)
+
/*******************************************************************************
*
* FUNCTION: acpi_disable
@@ -105,12 +105,11 @@ acpi_status acpi_enable(void)
* DESCRIPTION: Transfers the system into LEGACY (non-ACPI) mode.
*
******************************************************************************/
-
acpi_status acpi_disable(void)
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("acpi_disable");
+ ACPI_FUNCTION_TRACE(acpi_disable);
if (!acpi_gbl_FADT) {
ACPI_WARNING((AE_INFO, "No FADT information present!"));
@@ -137,6 +136,8 @@ acpi_status acpi_disable(void)
return_ACPI_STATUS(status);
}
+ACPI_EXPORT_SYMBOL(acpi_disable)
+
/*******************************************************************************
*
* FUNCTION: acpi_enable_event
@@ -149,13 +150,12 @@ acpi_status acpi_disable(void)
* DESCRIPTION: Enable an ACPI event (fixed)
*
******************************************************************************/
-
acpi_status acpi_enable_event(u32 event, u32 flags)
{
acpi_status status = AE_OK;
u32 value;
- ACPI_FUNCTION_TRACE("acpi_enable_event");
+ ACPI_FUNCTION_TRACE(acpi_enable_event);
/* Decode the Fixed Event */
@@ -193,7 +193,7 @@ acpi_status acpi_enable_event(u32 event, u32 flags)
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_enable_event);
+ACPI_EXPORT_SYMBOL(acpi_enable_event)
/*******************************************************************************
*
@@ -208,13 +208,12 @@ EXPORT_SYMBOL(acpi_enable_event);
* DESCRIPTION: Set the type of an individual GPE
*
******************************************************************************/
-
acpi_status acpi_set_gpe_type(acpi_handle gpe_device, u32 gpe_number, u8 type)
{
acpi_status status = AE_OK;
struct acpi_gpe_event_info *gpe_event_info;
- ACPI_FUNCTION_TRACE("acpi_set_gpe_type");
+ ACPI_FUNCTION_TRACE(acpi_set_gpe_type);
/* Ensure that we have a valid GPE number */
@@ -236,7 +235,7 @@ acpi_status acpi_set_gpe_type(acpi_handle gpe_device, u32 gpe_number, u8 type)
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_set_gpe_type);
+ACPI_EXPORT_SYMBOL(acpi_set_gpe_type)
/*******************************************************************************
*
@@ -252,13 +251,12 @@ EXPORT_SYMBOL(acpi_set_gpe_type);
* DESCRIPTION: Enable an ACPI event (general purpose)
*
******************************************************************************/
-
acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags)
{
acpi_status status = AE_OK;
struct acpi_gpe_event_info *gpe_event_info;
- ACPI_FUNCTION_TRACE("acpi_enable_gpe");
+ ACPI_FUNCTION_TRACE(acpi_enable_gpe);
/* Use semaphore lock if not executing at interrupt level */
@@ -288,7 +286,7 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags)
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_enable_gpe);
+ACPI_EXPORT_SYMBOL(acpi_enable_gpe)
/*******************************************************************************
*
@@ -304,13 +302,12 @@ EXPORT_SYMBOL(acpi_enable_gpe);
* DESCRIPTION: Disable an ACPI event (general purpose)
*
******************************************************************************/
-
acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags)
{
acpi_status status = AE_OK;
struct acpi_gpe_event_info *gpe_event_info;
- ACPI_FUNCTION_TRACE("acpi_disable_gpe");
+ ACPI_FUNCTION_TRACE(acpi_disable_gpe);
/* Use semaphore lock if not executing at interrupt level */
@@ -338,6 +335,8 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags)
return_ACPI_STATUS(status);
}
+ACPI_EXPORT_SYMBOL(acpi_disable_gpe)
+
/*******************************************************************************
*
* FUNCTION: acpi_disable_event
@@ -350,13 +349,12 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags)
* DESCRIPTION: Disable an ACPI event (fixed)
*
******************************************************************************/
-
acpi_status acpi_disable_event(u32 event, u32 flags)
{
acpi_status status = AE_OK;
u32 value;
- ACPI_FUNCTION_TRACE("acpi_disable_event");
+ ACPI_FUNCTION_TRACE(acpi_disable_event);
/* Decode the Fixed Event */
@@ -392,7 +390,7 @@ acpi_status acpi_disable_event(u32 event, u32 flags)
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_disable_event);
+ACPI_EXPORT_SYMBOL(acpi_disable_event)
/*******************************************************************************
*
@@ -405,12 +403,11 @@ EXPORT_SYMBOL(acpi_disable_event);
* DESCRIPTION: Clear an ACPI event (fixed)
*
******************************************************************************/
-
acpi_status acpi_clear_event(u32 event)
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("acpi_clear_event");
+ ACPI_FUNCTION_TRACE(acpi_clear_event);
/* Decode the Fixed Event */
@@ -429,7 +426,7 @@ acpi_status acpi_clear_event(u32 event)
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_clear_event);
+ACPI_EXPORT_SYMBOL(acpi_clear_event)
/*******************************************************************************
*
@@ -444,13 +441,12 @@ EXPORT_SYMBOL(acpi_clear_event);
* DESCRIPTION: Clear an ACPI event (general purpose)
*
******************************************************************************/
-
acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags)
{
acpi_status status = AE_OK;
struct acpi_gpe_event_info *gpe_event_info;
- ACPI_FUNCTION_TRACE("acpi_clear_gpe");
+ ACPI_FUNCTION_TRACE(acpi_clear_gpe);
/* Use semaphore lock if not executing at interrupt level */
@@ -478,6 +474,8 @@ acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags)
return_ACPI_STATUS(status);
}
+ACPI_EXPORT_SYMBOL(acpi_clear_gpe)
+
#ifdef ACPI_FUTURE_USAGE
/*******************************************************************************
*
@@ -492,12 +490,11 @@ acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags)
* DESCRIPTION: Obtains and returns the current status of the event
*
******************************************************************************/
-
acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status)
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("acpi_get_event_status");
+ ACPI_FUNCTION_TRACE(acpi_get_event_status);
if (!event_status) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -518,6 +515,8 @@ acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status)
return_ACPI_STATUS(status);
}
+ACPI_EXPORT_SYMBOL(acpi_get_event_status)
+
/*******************************************************************************
*
* FUNCTION: acpi_get_gpe_status
@@ -533,7 +532,6 @@ acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status)
* DESCRIPTION: Get status of an event (general purpose)
*
******************************************************************************/
-
acpi_status
acpi_get_gpe_status(acpi_handle gpe_device,
u32 gpe_number, u32 flags, acpi_event_status * event_status)
@@ -541,7 +539,7 @@ acpi_get_gpe_status(acpi_handle gpe_device,
acpi_status status = AE_OK;
struct acpi_gpe_event_info *gpe_event_info;
- ACPI_FUNCTION_TRACE("acpi_get_gpe_status");
+ ACPI_FUNCTION_TRACE(acpi_get_gpe_status);
/* Use semaphore lock if not executing at interrupt level */
@@ -570,6 +568,8 @@ acpi_get_gpe_status(acpi_handle gpe_device,
}
return_ACPI_STATUS(status);
}
+
+ACPI_EXPORT_SYMBOL(acpi_get_gpe_status)
#endif /* ACPI_FUTURE_USAGE */
/*******************************************************************************
@@ -586,7 +586,6 @@ acpi_get_gpe_status(acpi_handle gpe_device,
* DESCRIPTION: Create and Install a block of GPE registers
*
******************************************************************************/
-
acpi_status
acpi_install_gpe_block(acpi_handle gpe_device,
struct acpi_generic_address *gpe_block_address,
@@ -597,7 +596,7 @@ acpi_install_gpe_block(acpi_handle gpe_device,
struct acpi_namespace_node *node;
struct acpi_gpe_block_info *gpe_block;
- ACPI_FUNCTION_TRACE("acpi_install_gpe_block");
+ ACPI_FUNCTION_TRACE(acpi_install_gpe_block);
if ((!gpe_device) || (!gpe_block_address) || (!register_count)) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -636,6 +635,7 @@ acpi_install_gpe_block(acpi_handle gpe_device,
obj_desc = acpi_ns_get_attached_object(node);
if (!obj_desc) {
+
/* No object, create a new one */
obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_DEVICE);
@@ -665,7 +665,7 @@ acpi_install_gpe_block(acpi_handle gpe_device,
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_install_gpe_block);
+ACPI_EXPORT_SYMBOL(acpi_install_gpe_block)
/*******************************************************************************
*
@@ -678,14 +678,13 @@ EXPORT_SYMBOL(acpi_install_gpe_block);
* DESCRIPTION: Remove a previously installed block of GPE registers
*
******************************************************************************/
-
acpi_status acpi_remove_gpe_block(acpi_handle gpe_device)
{
union acpi_operand_object *obj_desc;
acpi_status status;
struct acpi_namespace_node *node;
- ACPI_FUNCTION_TRACE("acpi_remove_gpe_block");
+ ACPI_FUNCTION_TRACE(acpi_remove_gpe_block);
if (!gpe_device) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -721,4 +720,4 @@ acpi_status acpi_remove_gpe_block(acpi_handle gpe_device)
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_remove_gpe_block);
+ACPI_EXPORT_SYMBOL(acpi_remove_gpe_block)
diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c
index abf5cac..e8b86a0 100644
--- a/drivers/acpi/events/evxfregn.c
+++ b/drivers/acpi/events/evxfregn.c
@@ -42,8 +42,6 @@
* POSSIBILITY OF SUCH DAMAGES.
*/
-#include <linux/module.h>
-
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
#include <acpi/acevents.h>
@@ -75,7 +73,7 @@ acpi_install_address_space_handler(acpi_handle device,
struct acpi_namespace_node *node;
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_install_address_space_handler");
+ ACPI_FUNCTION_TRACE(acpi_install_address_space_handler);
/* Parameter validation */
@@ -114,7 +112,7 @@ acpi_install_address_space_handler(acpi_handle device,
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_install_address_space_handler);
+ACPI_EXPORT_SYMBOL(acpi_install_address_space_handler)
/*******************************************************************************
*
@@ -129,7 +127,6 @@ EXPORT_SYMBOL(acpi_install_address_space_handler);
* DESCRIPTION: Remove a previously installed handler.
*
******************************************************************************/
-
acpi_status
acpi_remove_address_space_handler(acpi_handle device,
acpi_adr_space_type space_id,
@@ -142,7 +139,7 @@ acpi_remove_address_space_handler(acpi_handle device,
struct acpi_namespace_node *node;
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_remove_address_space_handler");
+ ACPI_FUNCTION_TRACE(acpi_remove_address_space_handler);
/* Parameter validation */
@@ -176,9 +173,11 @@ acpi_remove_address_space_handler(acpi_handle device,
handler_obj = obj_desc->device.handler;
last_obj_ptr = &obj_desc->device.handler;
while (handler_obj) {
+
/* We have a handler, see if user requested this one */
if (handler_obj->address_space.space_id == space_id) {
+
/* Matched space_id, first dereference this in the Regions */
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
@@ -229,7 +228,7 @@ acpi_remove_address_space_handler(acpi_handle device,
/* The handler does not exist */
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
- "Unable to remove address handler %p for %s(%X), dev_node %p, obj %p\n",
+ "Unable to remove address handler %p for %s(%X), DevNode %p, obj %p\n",
handler, acpi_ut_get_region_name(space_id), space_id,
node, obj_desc));
@@ -240,4 +239,4 @@ acpi_remove_address_space_handler(acpi_handle device,
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_remove_address_space_handler);
+ACPI_EXPORT_SYMBOL(acpi_remove_address_space_handler)
diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c
index a29782f..8233524 100644
--- a/drivers/acpi/executer/exconfig.c
+++ b/drivers/acpi/executer/exconfig.c
@@ -82,7 +82,7 @@ acpi_ex_add_table(struct acpi_table_header *table,
struct acpi_table_desc table_info;
union acpi_operand_object *obj_desc;
- ACPI_FUNCTION_TRACE("ex_add_table");
+ ACPI_FUNCTION_TRACE(ex_add_table);
/* Create an object to be the table handle */
@@ -100,7 +100,7 @@ acpi_ex_add_table(struct acpi_table_header *table,
ACPI_MEMSET(&table_info, 0, sizeof(struct acpi_table_desc));
- table_info.type = ACPI_TABLE_SSDT;
+ table_info.type = ACPI_TABLE_ID_SSDT;
table_info.pointer = table;
table_info.length = (acpi_size) table->length;
table_info.allocation = ACPI_MEM_ALLOCATED;
@@ -110,6 +110,7 @@ acpi_ex_add_table(struct acpi_table_header *table,
if (ACPI_FAILURE(status)) {
if (status == AE_ALREADY_EXISTS) {
+
/* Table already exists, just return the handle */
return_ACPI_STATUS(AE_OK);
@@ -121,6 +122,7 @@ acpi_ex_add_table(struct acpi_table_header *table,
status = acpi_ns_load_table(table_info.installed_desc, parent_node);
if (ACPI_FAILURE(status)) {
+
/* Uninstall table on error */
(void)acpi_tb_uninstall_table(table_info.installed_desc);
@@ -160,7 +162,7 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
struct acpi_namespace_node *parameter_node = NULL;
union acpi_operand_object *ddb_handle;
- ACPI_FUNCTION_TRACE("ex_load_table_op");
+ ACPI_FUNCTION_TRACE(ex_load_table_op);
#if 0
/*
@@ -169,6 +171,7 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
*/
status = acpi_tb_match_signature(operand[0]->string.pointer, NULL);
if (status == AE_OK) {
+
/* Signature matched -- don't allow override */
return_ACPI_STATUS(AE_ALREADY_EXISTS);
@@ -211,9 +214,8 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
* location within the namespace where the table will be loaded.
*/
status =
- acpi_ns_get_node_by_path(operand[3]->string.pointer,
- start_node, ACPI_NS_SEARCH_PARENT,
- &parent_node);
+ acpi_ns_get_node(start_node, operand[3]->string.pointer,
+ ACPI_NS_SEARCH_PARENT, &parent_node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -234,9 +236,8 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
/* Find the node referenced by the parameter_path_string */
status =
- acpi_ns_get_node_by_path(operand[4]->string.pointer,
- start_node, ACPI_NS_SEARCH_PARENT,
- &parameter_node);
+ acpi_ns_get_node(start_node, operand[4]->string.pointer,
+ ACPI_NS_SEARCH_PARENT, &parameter_node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -252,6 +253,7 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
/* Parameter Data (optional) */
if (parameter_node) {
+
/* Store the parameter data into the optional parameter object */
status = acpi_ex_store(operand[5],
@@ -294,9 +296,10 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
struct acpi_table_header *table_ptr = NULL;
acpi_physical_address address;
struct acpi_table_header table_header;
+ acpi_integer temp;
u32 i;
- ACPI_FUNCTION_TRACE("ex_load_op");
+ ACPI_FUNCTION_TRACE(ex_load_op);
/* Object can be either an op_region or a Field */
@@ -322,7 +325,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
address = obj_desc->region.address;
- /* Get the table length from the table header */
+ /* Get part of the table header to get the table length */
table_header.length = 0;
for (i = 0; i < 8; i++) {
@@ -330,11 +333,14 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
acpi_ev_address_space_dispatch(obj_desc, ACPI_READ,
(acpi_physical_address)
(i + address), 8,
- ((u8 *) &
- table_header) + i);
+ &temp);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
+
+ /* Get the one valid byte of the returned 64-bit value */
+
+ ACPI_CAST_PTR(u8, &table_header)[i] = (u8) temp;
}
/* Sanity check the table length */
@@ -345,7 +351,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
/* Allocate a buffer for the entire table */
- table_ptr = ACPI_MEM_ALLOCATE(table_header.length);
+ table_ptr = ACPI_ALLOCATE(table_header.length);
if (!table_ptr) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
@@ -357,11 +363,14 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
acpi_ev_address_space_dispatch(obj_desc, ACPI_READ,
(acpi_physical_address)
(i + address), 8,
- ((u8 *) table_ptr +
- i));
+ &temp);
if (ACPI_FAILURE(status)) {
goto cleanup;
}
+
+ /* Get the one valid byte of the returned 64-bit value */
+
+ ACPI_CAST_PTR(u8, table_ptr)[i] = (u8) temp;
}
break;
@@ -407,12 +416,8 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
/* The table must be either an SSDT or a PSDT */
- if ((!ACPI_STRNCMP(table_ptr->signature,
- acpi_gbl_table_data[ACPI_TABLE_PSDT].signature,
- acpi_gbl_table_data[ACPI_TABLE_PSDT].sig_length)) &&
- (!ACPI_STRNCMP(table_ptr->signature,
- acpi_gbl_table_data[ACPI_TABLE_SSDT].signature,
- acpi_gbl_table_data[ACPI_TABLE_SSDT].sig_length))) {
+ if ((!ACPI_COMPARE_NAME(table_ptr->signature, PSDT_SIG)) &&
+ (!ACPI_COMPARE_NAME(table_ptr->signature, SSDT_SIG))) {
ACPI_ERROR((AE_INFO,
"Table has invalid signature [%4.4s], must be SSDT or PSDT",
table_ptr->signature));
@@ -424,6 +429,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
status = acpi_ex_add_table(table_ptr, acpi_gbl_root_node, &ddb_handle);
if (ACPI_FAILURE(status)) {
+
/* On error, table_ptr was deallocated above */
return_ACPI_STATUS(status);
@@ -442,7 +448,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
cleanup:
if (ACPI_FAILURE(status)) {
- ACPI_MEM_FREE(table_ptr);
+ ACPI_FREE(table_ptr);
}
return_ACPI_STATUS(status);
}
@@ -465,7 +471,7 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
union acpi_operand_object *table_desc = ddb_handle;
struct acpi_table_desc *table_info;
- ACPI_FUNCTION_TRACE("ex_unload_table");
+ ACPI_FUNCTION_TRACE(ex_unload_table);
/*
* Validate the handle
diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c
index e6d52e1..b732e39 100644
--- a/drivers/acpi/executer/exconvrt.c
+++ b/drivers/acpi/executer/exconvrt.c
@@ -79,7 +79,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
u32 count;
acpi_status status;
- ACPI_FUNCTION_TRACE_PTR("ex_convert_to_integer", obj_desc);
+ ACPI_FUNCTION_TRACE_PTR(ex_convert_to_integer, obj_desc);
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
case ACPI_TYPE_INTEGER:
@@ -199,7 +199,7 @@ acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc,
union acpi_operand_object *return_desc;
u8 *new_buf;
- ACPI_FUNCTION_TRACE_PTR("ex_convert_to_buffer", obj_desc);
+ ACPI_FUNCTION_TRACE_PTR(ex_convert_to_buffer, obj_desc);
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
case ACPI_TYPE_BUFFER:
@@ -319,6 +319,7 @@ acpi_ex_convert_to_ascii(acpi_integer integer,
remainder = 0;
for (i = decimal_length; i > 0; i--) {
+
/* Divide by nth factor of 10 */
digit = integer;
@@ -346,6 +347,7 @@ acpi_ex_convert_to_ascii(acpi_integer integer,
hex_length = (acpi_native_uint) ACPI_MUL_2(data_width);
for (i = 0, j = (hex_length - 1); i < hex_length; i++, j--) {
+
/* Get one hex digit, most significant digits first */
string[k] =
@@ -400,7 +402,7 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
u16 base = 16;
u8 separator = ',';
- ACPI_FUNCTION_TRACE_PTR("ex_convert_to_string", obj_desc);
+ ACPI_FUNCTION_TRACE_PTR(ex_convert_to_string, obj_desc);
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
case ACPI_TYPE_STRING:
@@ -567,7 +569,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("ex_convert_to_target_type");
+ ACPI_FUNCTION_TRACE(ex_convert_to_target_type);
/* Default behavior */
@@ -657,7 +659,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
default:
ACPI_ERROR((AE_INFO,
- "Unknown Target type ID 0x%X aml_opcode %X dest_type %s",
+ "Unknown Target type ID 0x%X AmlOpcode %X DestType %s",
GET_CURRENT_ARG_TYPE(walk_state->op_info->
runtime_args),
walk_state->opcode,
diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c
index 6805754..106dc72 100644
--- a/drivers/acpi/executer/excreate.c
+++ b/drivers/acpi/executer/excreate.c
@@ -69,7 +69,7 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state)
struct acpi_namespace_node *alias_node;
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("ex_create_alias");
+ ACPI_FUNCTION_TRACE(ex_create_alias);
/* Get the source/alias operands (both namespace nodes) */
@@ -164,7 +164,7 @@ acpi_status acpi_ex_create_event(struct acpi_walk_state *walk_state)
acpi_status status;
union acpi_operand_object *obj_desc;
- ACPI_FUNCTION_TRACE("ex_create_event");
+ ACPI_FUNCTION_TRACE(ex_create_event);
obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_EVENT);
if (!obj_desc) {
@@ -216,7 +216,7 @@ acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state)
acpi_status status = AE_OK;
union acpi_operand_object *obj_desc;
- ACPI_FUNCTION_TRACE_PTR("ex_create_mutex", ACPI_WALK_OPERANDS);
+ ACPI_FUNCTION_TRACE_PTR(ex_create_mutex, ACPI_WALK_OPERANDS);
/* Create the new mutex object */
@@ -243,8 +243,9 @@ acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state)
obj_desc->mutex.node =
(struct acpi_namespace_node *)walk_state->operands[0];
- status = acpi_ns_attach_object(obj_desc->mutex.node,
- obj_desc, ACPI_TYPE_MUTEX);
+ status =
+ acpi_ns_attach_object(obj_desc->mutex.node, obj_desc,
+ ACPI_TYPE_MUTEX);
cleanup:
/*
@@ -280,7 +281,7 @@ acpi_ex_create_region(u8 * aml_start,
struct acpi_namespace_node *node;
union acpi_operand_object *region_obj2;
- ACPI_FUNCTION_TRACE("ex_create_region");
+ ACPI_FUNCTION_TRACE(ex_create_region);
/* Get the Namespace Node */
@@ -300,7 +301,7 @@ acpi_ex_create_region(u8 * aml_start,
*/
if ((region_space >= ACPI_NUM_PREDEFINED_REGIONS) &&
(region_space < ACPI_USER_REGION_BEGIN)) {
- ACPI_ERROR((AE_INFO, "Invalid address_space type %X",
+ ACPI_ERROR((AE_INFO, "Invalid AddressSpace type %X",
region_space));
return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID);
}
@@ -364,7 +365,7 @@ acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state)
struct acpi_table_header *table;
union acpi_operand_object *region_obj2;
- ACPI_FUNCTION_TRACE("ex_create_table_region");
+ ACPI_FUNCTION_TRACE(ex_create_table_region);
/* Get the Node from the object stack */
@@ -452,7 +453,7 @@ acpi_status acpi_ex_create_processor(struct acpi_walk_state *walk_state)
union acpi_operand_object *obj_desc;
acpi_status status;
- ACPI_FUNCTION_TRACE_PTR("ex_create_processor", walk_state);
+ ACPI_FUNCTION_TRACE_PTR(ex_create_processor, walk_state);
/* Create the processor object */
@@ -464,9 +465,9 @@ acpi_status acpi_ex_create_processor(struct acpi_walk_state *walk_state)
/* Initialize the processor object from the operands */
obj_desc->processor.proc_id = (u8) operand[1]->integer.value;
+ obj_desc->processor.length = (u8) operand[3]->integer.value;
obj_desc->processor.address =
(acpi_io_address) operand[2]->integer.value;
- obj_desc->processor.length = (u8) operand[3]->integer.value;
/* Install the processor object in the parent Node */
@@ -499,7 +500,7 @@ acpi_status acpi_ex_create_power_resource(struct acpi_walk_state *walk_state)
acpi_status status;
union acpi_operand_object *obj_desc;
- ACPI_FUNCTION_TRACE_PTR("ex_create_power_resource", walk_state);
+ ACPI_FUNCTION_TRACE_PTR(ex_create_power_resource, walk_state);
/* Create the power resource object */
@@ -549,7 +550,7 @@ acpi_ex_create_method(u8 * aml_start,
acpi_status status;
u8 method_flags;
- ACPI_FUNCTION_TRACE_PTR("ex_create_method", walk_state);
+ ACPI_FUNCTION_TRACE_PTR(ex_create_method, walk_state);
/* Create a new method object */
diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c
index a7cca8d..7b9718e 100644
--- a/drivers/acpi/executer/exdump.c
+++ b/drivers/acpi/executer/exdump.c
@@ -61,6 +61,10 @@ static void acpi_ex_out_pointer(char *title, void *value);
static void acpi_ex_out_address(char *title, acpi_physical_address value);
+static void
+acpi_ex_dump_object(union acpi_operand_object *obj_desc,
+ struct acpi_exdump_info *info);
+
static void acpi_ex_dump_reference_obj(union acpi_operand_object *obj_desc);
static void
@@ -119,7 +123,7 @@ static struct acpi_exdump_info acpi_ex_dump_event[2] = {
static struct acpi_exdump_info acpi_ex_dump_method[8] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_method), NULL},
- {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count), "param_count"},
+ {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count), "ParamCount"},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.concurrency), "Concurrency"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.semaphore), "Semaphore"},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.owner_id), "Owner Id"},
@@ -263,12 +267,10 @@ static struct acpi_exdump_info acpi_ex_dump_field_common[7] = {
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(common_field.node), "Parent Node"}
};
-static struct acpi_exdump_info acpi_ex_dump_node[6] = {
+static struct acpi_exdump_info acpi_ex_dump_node[5] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_node), NULL},
{ACPI_EXD_UINT8, ACPI_EXD_NSOFFSET(flags), "Flags"},
{ACPI_EXD_UINT8, ACPI_EXD_NSOFFSET(owner_id), "Owner Id"},
- {ACPI_EXD_UINT16, ACPI_EXD_NSOFFSET(reference_count),
- "Reference Count"},
{ACPI_EXD_POINTER, ACPI_EXD_NSOFFSET(child), "Child List"},
{ACPI_EXD_POINTER, ACPI_EXD_NSOFFSET(peer), "Next Peer"}
};
@@ -330,7 +332,7 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
if (!info) {
acpi_os_printf
- ("ex_dump_object: Display not implemented for object type %s\n",
+ ("ExDumpObject: Display not implemented for object type %s\n",
acpi_ut_get_object_type_name(obj_desc));
return;
}
@@ -454,7 +456,7 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
u32 length;
u32 index;
- ACPI_FUNCTION_NAME("ex_dump_operand")
+ ACPI_FUNCTION_NAME(ex_dump_operand)
if (!
((ACPI_LV_EXEC & acpi_dbg_level)
@@ -463,6 +465,7 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
}
if (!obj_desc) {
+
/* This could be a null element of a package */
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Null Object Descriptor\n"));
@@ -522,7 +525,7 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
case AML_REF_OF_OP:
- acpi_os_printf("Reference: (ref_of) %p\n",
+ acpi_os_printf("Reference: (RefOf) %p\n",
obj_desc->reference.object);
break;
@@ -532,6 +535,7 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
obj_desc->reference.offset);
if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) {
+
/* Value is an Integer */
acpi_os_printf(" value is [%8.8X%8.8x]",
@@ -610,7 +614,7 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
case ACPI_TYPE_PACKAGE:
- acpi_os_printf("Package [Len %X] element_array %p\n",
+ acpi_os_printf("Package [Len %X] ElementArray %p\n",
obj_desc->package.count,
obj_desc->package.elements);
@@ -662,13 +666,13 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
case ACPI_TYPE_LOCAL_BANK_FIELD:
- acpi_os_printf("bank_field\n");
+ acpi_os_printf("BankField\n");
break;
case ACPI_TYPE_LOCAL_REGION_FIELD:
acpi_os_printf
- ("region_field: Bits=%X acc_width=%X Lock=%X Update=%X at byte=%X bit=%X of below:\n",
+ ("RegionField: Bits=%X AccWidth=%X Lock=%X Update=%X at byte=%X bit=%X of below:\n",
obj_desc->field.bit_length,
obj_desc->field.access_byte_width,
obj_desc->field.field_flags & AML_FIELD_LOCK_RULE_MASK,
@@ -681,12 +685,12 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
case ACPI_TYPE_LOCAL_INDEX_FIELD:
- acpi_os_printf("index_field\n");
+ acpi_os_printf("IndexField\n");
break;
case ACPI_TYPE_BUFFER_FIELD:
- acpi_os_printf("buffer_field: %X bits at byte %X bit %X of\n",
+ acpi_os_printf("BufferField: %X bits at byte %X bit %X of\n",
obj_desc->buffer_field.bit_length,
obj_desc->buffer_field.base_byte_offset,
obj_desc->buffer_field.start_field_bit_offset);
@@ -777,7 +781,7 @@ acpi_ex_dump_operands(union acpi_operand_object **operands,
{
acpi_native_uint i;
- ACPI_FUNCTION_NAME("ex_dump_operands");
+ ACPI_FUNCTION_NAME(ex_dump_operands);
if (!ident) {
ident = "?";
@@ -901,7 +905,7 @@ static void acpi_ex_dump_reference_obj(union acpi_operand_object *obj_desc)
acpi_os_printf("Could not convert name to pathname\n");
} else {
acpi_os_printf("%s\n", (char *)ret_buf.pointer);
- ACPI_MEM_FREE(ret_buf.pointer);
+ ACPI_FREE(ret_buf.pointer);
}
} else if (obj_desc->reference.object) {
acpi_os_printf("\nReferenced Object: %p\n",
@@ -1017,7 +1021,7 @@ acpi_ex_dump_package_obj(union acpi_operand_object *obj_desc,
void
acpi_ex_dump_object_descriptor(union acpi_operand_object *obj_desc, u32 flags)
{
- ACPI_FUNCTION_TRACE("ex_dump_object_descriptor");
+ ACPI_FUNCTION_TRACE(ex_dump_object_descriptor);
if (!obj_desc) {
return_VOID;
@@ -1046,7 +1050,7 @@ acpi_ex_dump_object_descriptor(union acpi_operand_object *obj_desc, u32 flags)
if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) {
acpi_os_printf
- ("ex_dump_object_descriptor: %p is not an ACPI operand object: [%s]\n",
+ ("ExDumpObjectDescriptor: %p is not an ACPI operand object: [%s]\n",
obj_desc, acpi_ut_get_descriptor_name(obj_desc));
return_VOID;
}
diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/executer/exfield.c
index e259201..9ea9c3a6 100644
--- a/drivers/acpi/executer/exfield.c
+++ b/drivers/acpi/executer/exfield.c
@@ -73,7 +73,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
void *buffer;
u8 locked;
- ACPI_FUNCTION_TRACE_PTR("ex_read_data_from_field", obj_desc);
+ ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc);
/* Parameter validation */
@@ -142,6 +142,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
length =
(acpi_size) ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length);
if (length > acpi_gbl_integer_byte_width) {
+
/* Field is too large for an Integer, create a Buffer instead */
buffer_desc = acpi_ut_create_buffer_object(length);
@@ -163,11 +164,11 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
}
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "field_read [TO]: Obj %p, Type %X, Buf %p, byte_len %X\n",
+ "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n",
obj_desc, ACPI_GET_OBJECT_TYPE(obj_desc), buffer,
(u32) length));
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "field_read [FROM]: bit_len %X, bit_off %X, byte_off %X\n",
+ "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
obj_desc->common_field.bit_length,
obj_desc->common_field.start_field_bit_offset,
obj_desc->common_field.base_byte_offset));
@@ -219,7 +220,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
u8 locked;
union acpi_operand_object *buffer_desc;
- ACPI_FUNCTION_TRACE_PTR("ex_write_data_to_field", obj_desc);
+ ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc);
/* Parameter validation */
@@ -329,9 +330,10 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length);
if (length < required_length) {
+
/* We need to create a new buffer */
- new_buffer = ACPI_MEM_CALLOCATE(required_length);
+ new_buffer = ACPI_ALLOCATE_ZEROED(required_length);
if (!new_buffer) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
@@ -347,14 +349,14 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
}
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "field_write [FROM]: Obj %p (%s:%X), Buf %p, byte_len %X\n",
+ "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
source_desc,
acpi_ut_get_type_name(ACPI_GET_OBJECT_TYPE
(source_desc)),
ACPI_GET_OBJECT_TYPE(source_desc), buffer, length));
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "field_write [TO]: Obj %p (%s:%X), bit_len %X, bit_off %X, byte_off %X\n",
+ "FieldWrite [TO]: Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
obj_desc,
acpi_ut_get_type_name(ACPI_GET_OBJECT_TYPE(obj_desc)),
ACPI_GET_OBJECT_TYPE(obj_desc),
@@ -375,7 +377,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
/* Free temporary buffer if we used one */
if (new_buffer) {
- ACPI_MEM_FREE(new_buffer);
+ ACPI_FREE(new_buffer);
}
return_ACPI_STATUS(status);
diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c
index bd1af35..051053f 100644
--- a/drivers/acpi/executer/exfldio.c
+++ b/drivers/acpi/executer/exfldio.c
@@ -87,7 +87,7 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc,
acpi_status status = AE_OK;
union acpi_operand_object *rgn_desc;
- ACPI_FUNCTION_TRACE_U32("ex_setup_region", field_datum_byte_offset);
+ ACPI_FUNCTION_TRACE_U32(ex_setup_region, field_datum_byte_offset);
rgn_desc = obj_desc->common_field.region_obj;
@@ -112,7 +112,18 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc,
}
}
+ /* Exit if Address/Length have been disallowed by the host OS */
+
+ if (rgn_desc->common.flags & AOPOBJ_INVALID) {
+ return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS);
+ }
+
+ /*
+ * Exit now for SMBus address space, it has a non-linear address space
+ * and the request cannot be directly validated
+ */
if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS) {
+
/* SMBus has a non-linear address space */
return_ACPI_STATUS(AE_OK);
@@ -134,10 +145,10 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc,
* length of one field datum (access width) must fit within the region.
* (Region length is specified in bytes)
*/
- if (rgn_desc->region.length < (obj_desc->common_field.base_byte_offset +
- field_datum_byte_offset +
- obj_desc->common_field.
- access_byte_width)) {
+ if (rgn_desc->region.length <
+ (obj_desc->common_field.base_byte_offset +
+ field_datum_byte_offset +
+ obj_desc->common_field.access_byte_width)) {
if (acpi_gbl_enable_interpreter_slack) {
/*
* Slack mode only: We will go ahead and allow access to this
@@ -217,7 +228,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc,
union acpi_operand_object *rgn_desc;
acpi_physical_address address;
- ACPI_FUNCTION_TRACE("ex_access_region");
+ ACPI_FUNCTION_TRACE(ex_access_region);
/*
* Ensure that the region operands are fully evaluated and verify
@@ -246,7 +257,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc,
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_BFIELD,
- " Region [%s:%X], Width %X, byte_base %X, Offset %X at %8.8X%8.8X\n",
+ " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n",
acpi_ut_get_region_name(rgn_desc->region.
space_id),
rgn_desc->region.space_id,
@@ -352,7 +363,7 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
acpi_status status;
acpi_integer local_value;
- ACPI_FUNCTION_TRACE_U32("ex_field_datum_io", field_datum_byte_offset);
+ ACPI_FUNCTION_TRACE_U32(ex_field_datum_io, field_datum_byte_offset);
if (read_write == ACPI_READ) {
if (!value) {
@@ -487,10 +498,11 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
}
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "I/O to Data Register: value_ptr %p\n",
+ "I/O to Data Register: ValuePtr %p\n",
value));
if (read_write == ACPI_READ) {
+
/* Read the datum from the data_register */
status =
@@ -559,7 +571,7 @@ acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc,
acpi_integer merged_value;
acpi_integer current_value;
- ACPI_FUNCTION_TRACE_U32("ex_write_with_update_rule", mask);
+ ACPI_FUNCTION_TRACE_U32(ex_write_with_update_rule, mask);
/* Start with the new bits */
@@ -568,6 +580,7 @@ acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc,
/* If the mask is all ones, we don't need to worry about the update rule */
if (mask != ACPI_INTEGER_MAX) {
+
/* Decode the update rule */
switch (obj_desc->common_field.
@@ -614,7 +627,7 @@ acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc,
default:
ACPI_ERROR((AE_INFO,
- "Unknown update_rule value: %X",
+ "Unknown UpdateRule value: %X",
(obj_desc->common_field.
field_flags &
AML_FIELD_UPDATE_RULE_MASK)));
@@ -623,7 +636,7 @@ acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc,
}
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "Mask %8.8X%8.8X, datum_offset %X, Width %X, Value %8.8X%8.8X, merged_value %8.8X%8.8X\n",
+ "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
ACPI_FORMAT_UINT64(mask),
field_datum_byte_offset,
obj_desc->common_field.access_byte_width,
@@ -666,7 +679,7 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,
u32 field_datum_count;
u32 i;
- ACPI_FUNCTION_TRACE("ex_extract_from_field");
+ ACPI_FUNCTION_TRACE(ex_extract_from_field);
/* Validate target buffer and clear it */
@@ -704,6 +717,7 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,
/* Read the rest of the field */
for (i = 1; i < field_datum_count; i++) {
+
/* Get next input datum from the field */
field_offset += obj_desc->common_field.access_byte_width;
@@ -771,6 +785,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
{
acpi_status status;
acpi_integer mask;
+ acpi_integer width_mask;
acpi_integer merged_datum;
acpi_integer raw_datum = 0;
u32 field_offset = 0;
@@ -780,7 +795,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
u32 field_datum_count;
u32 i;
- ACPI_FUNCTION_TRACE("ex_insert_into_field");
+ ACPI_FUNCTION_TRACE(ex_insert_into_field);
/* Validate input buffer */
@@ -795,15 +810,20 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
/* Compute the number of datums (access width data items) */
+ width_mask =
+ ACPI_MASK_BITS_ABOVE(obj_desc->common_field.access_bit_width);
mask =
- ACPI_MASK_BITS_BELOW(obj_desc->common_field.start_field_bit_offset);
- datum_count =
- ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
- obj_desc->common_field.access_bit_width);
- field_datum_count =
- ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
- obj_desc->common_field.start_field_bit_offset,
- obj_desc->common_field.access_bit_width);
+ width_mask & ACPI_MASK_BITS_BELOW(obj_desc->common_field.
+ start_field_bit_offset);
+
+ datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
+ obj_desc->common_field.access_bit_width);
+
+ field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
+ obj_desc->common_field.
+ start_field_bit_offset,
+ obj_desc->common_field.
+ access_bit_width);
/* Get initial Datum from the input buffer */
@@ -817,6 +837,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
/* Write the entire field */
for (i = 1; i < field_datum_count; i++) {
+
/* Write merged datum to the target field */
merged_datum &= mask;
@@ -833,7 +854,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
merged_datum = raw_datum >>
(obj_desc->common_field.access_bit_width -
obj_desc->common_field.start_field_bit_offset);
- mask = ACPI_INTEGER_MAX;
+ mask = width_mask;
if (i == datum_count) {
break;
diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c
index 48c18d2..bd98aab 100644
--- a/drivers/acpi/executer/exmisc.c
+++ b/drivers/acpi/executer/exmisc.c
@@ -72,7 +72,7 @@ acpi_ex_get_object_reference(union acpi_operand_object *obj_desc,
union acpi_operand_object *reference_obj;
union acpi_operand_object *referenced_obj;
- ACPI_FUNCTION_TRACE_PTR("ex_get_object_reference", obj_desc);
+ ACPI_FUNCTION_TRACE_PTR(ex_get_object_reference, obj_desc);
*return_desc = NULL;
@@ -168,7 +168,7 @@ acpi_ex_concat_template(union acpi_operand_object *operand0,
acpi_size length1;
acpi_size new_length;
- ACPI_FUNCTION_TRACE("ex_concat_template");
+ ACPI_FUNCTION_TRACE(ex_concat_template);
/*
* Find the end_tag descriptor in each resource template.
@@ -250,7 +250,7 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0,
char *new_buf;
acpi_status status;
- ACPI_FUNCTION_TRACE("ex_do_concatenate");
+ ACPI_FUNCTION_TRACE(ex_do_concatenate);
/*
* Convert the second operand if necessary. The first operand
@@ -445,10 +445,24 @@ acpi_ex_do_math_op(u16 opcode, acpi_integer integer0, acpi_integer integer1)
case AML_SHIFT_LEFT_OP: /* shift_left (Operand, shift_count, Result) */
+ /*
+ * We need to check if the shiftcount is larger than the integer bit
+ * width since the behavior of this is not well-defined in the C language.
+ */
+ if (integer1 >= acpi_gbl_integer_bit_width) {
+ return (0);
+ }
return (integer0 << integer1);
case AML_SHIFT_RIGHT_OP: /* shift_right (Operand, shift_count, Result) */
+ /*
+ * We need to check if the shiftcount is larger than the integer bit
+ * width since the behavior of this is not well-defined in the C language.
+ */
+ if (integer1 >= acpi_gbl_integer_bit_width) {
+ return (0);
+ }
return (integer0 >> integer1);
case AML_SUBTRACT_OP: /* Subtract (Integer0, Integer1, Result) */
@@ -489,7 +503,7 @@ acpi_ex_do_logical_numeric_op(u16 opcode,
acpi_status status = AE_OK;
u8 local_result = FALSE;
- ACPI_FUNCTION_TRACE("ex_do_logical_numeric_op");
+ ACPI_FUNCTION_TRACE(ex_do_logical_numeric_op);
switch (opcode) {
case AML_LAND_OP: /* LAnd (Integer0, Integer1) */
@@ -557,7 +571,7 @@ acpi_ex_do_logical_op(u16 opcode,
u8 local_result = FALSE;
int compare;
- ACPI_FUNCTION_TRACE("ex_do_logical_op");
+ ACPI_FUNCTION_TRACE(ex_do_logical_op);
/*
* Convert the second operand if necessary. The first operand
@@ -649,6 +663,7 @@ acpi_ex_do_logical_op(u16 opcode,
/* Length and all bytes must be equal */
if ((length0 == length1) && (compare == 0)) {
+
/* Length and all bytes match ==> TRUE */
local_result = TRUE;
diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c
index f843b22..93098d6 100644
--- a/drivers/acpi/executer/exmutex.c
+++ b/drivers/acpi/executer/exmutex.c
@@ -61,7 +61,7 @@ acpi_ex_link_mutex(union acpi_operand_object *obj_desc,
*
* RETURN: None
*
- * DESCRIPTION: Remove a mutex from the "acquired_mutex" list
+ * DESCRIPTION: Remove a mutex from the "AcquiredMutex" list
*
******************************************************************************/
@@ -95,7 +95,7 @@ void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc)
*
* RETURN: None
*
- * DESCRIPTION: Add a mutex to the "acquired_mutex" list for this walk
+ * DESCRIPTION: Add a mutex to the "AcquiredMutex" list for this walk
*
******************************************************************************/
@@ -144,7 +144,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
{
acpi_status status;
- ACPI_FUNCTION_TRACE_PTR("ex_acquire_mutex", obj_desc);
+ ACPI_FUNCTION_TRACE_PTR(ex_acquire_mutex, obj_desc);
if (!obj_desc) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -165,7 +165,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
*/
if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) {
ACPI_ERROR((AE_INFO,
- "Cannot acquire Mutex [%4.4s], incorrect sync_level",
+ "Cannot acquire Mutex [%4.4s], incorrect SyncLevel",
acpi_ut_get_node_name(obj_desc->mutex.node)));
return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
}
@@ -173,6 +173,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
/* Support for multiple acquires by the owning thread */
if (obj_desc->mutex.owner_thread) {
+
/* Special case for Global Lock, allow all threads */
if ((obj_desc->mutex.owner_thread->thread_id ==
@@ -192,6 +193,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
status = acpi_ex_system_acquire_mutex(time_desc, obj_desc);
if (ACPI_FAILURE(status)) {
+
/* Includes failure from a timeout on time_desc */
return_ACPI_STATUS(status);
@@ -232,7 +234,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ex_release_mutex");
+ ACPI_FUNCTION_TRACE(ex_release_mutex);
if (!obj_desc) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -277,7 +279,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
*/
if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) {
ACPI_ERROR((AE_INFO,
- "Cannot release Mutex [%4.4s], incorrect sync_level",
+ "Cannot release Mutex [%4.4s], incorrect SyncLevel",
acpi_ut_get_node_name(obj_desc->mutex.node)));
return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
}
@@ -286,6 +288,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
obj_desc->mutex.acquisition_depth--;
if (obj_desc->mutex.acquisition_depth != 0) {
+
/* Just decrement the depth and return */
return_ACPI_STATUS(AE_OK);
diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c
index 054fe5e..d3d7036 100644
--- a/drivers/acpi/executer/exnames.c
+++ b/drivers/acpi/executer/exnames.c
@@ -77,7 +77,7 @@ static char *acpi_ex_allocate_name_string(u32 prefix_count, u32 num_name_segs)
char *name_string;
u32 size_needed;
- ACPI_FUNCTION_TRACE("ex_allocate_name_string");
+ ACPI_FUNCTION_TRACE(ex_allocate_name_string);
/*
* Allow room for all \ and ^ prefixes, all segments and a multi_name_prefix.
@@ -85,6 +85,7 @@ static char *acpi_ex_allocate_name_string(u32 prefix_count, u32 num_name_segs)
* This may actually be somewhat longer than needed.
*/
if (prefix_count == ACPI_UINT32_MAX) {
+
/* Special case for root */
size_needed = 1 + (ACPI_NAME_SIZE * num_name_segs) + 2 + 1;
@@ -97,7 +98,7 @@ static char *acpi_ex_allocate_name_string(u32 prefix_count, u32 num_name_segs)
* Allocate a buffer for the name.
* This buffer must be deleted by the caller!
*/
- name_string = ACPI_MEM_ALLOCATE(size_needed);
+ name_string = ACPI_ALLOCATE(size_needed);
if (!name_string) {
ACPI_ERROR((AE_INFO,
"Could not allocate size %d", size_needed));
@@ -119,11 +120,13 @@ static char *acpi_ex_allocate_name_string(u32 prefix_count, u32 num_name_segs)
/* Set up Dual or Multi prefixes if needed */
if (num_name_segs > 2) {
+
/* Set up multi prefixes */
*temp_ptr++ = AML_MULTI_NAME_PREFIX_OP;
*temp_ptr++ = (char)num_name_segs;
} else if (2 == num_name_segs) {
+
/* Set up dual prefixes */
*temp_ptr++ = AML_DUAL_NAME_PREFIX;
@@ -159,7 +162,7 @@ static acpi_status acpi_ex_name_segment(u8 ** in_aml_address, char *name_string)
u32 index;
char char_buf[5];
- ACPI_FUNCTION_TRACE("ex_name_segment");
+ ACPI_FUNCTION_TRACE(ex_name_segment);
/*
* If first character is a digit, then we know that we aren't looking at a
@@ -176,7 +179,7 @@ static acpi_status acpi_ex_name_segment(u8 ** in_aml_address, char *name_string)
for (index = 0;
(index < ACPI_NAME_SIZE)
- && (acpi_ut_valid_acpi_character(*aml_address)); index++) {
+ && (acpi_ut_valid_acpi_char(*aml_address, 0)); index++) {
char_buf[index] = *aml_address++;
ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "%c\n", char_buf[index]));
}
@@ -184,6 +187,7 @@ static acpi_status acpi_ex_name_segment(u8 ** in_aml_address, char *name_string)
/* Valid name segment */
if (index == 4) {
+
/* Found 4 valid characters */
char_buf[4] = '\0';
@@ -249,11 +253,12 @@ acpi_ex_get_name_string(acpi_object_type data_type,
u32 prefix_count = 0;
u8 has_prefix = FALSE;
- ACPI_FUNCTION_TRACE_PTR("ex_get_name_string", aml_address);
+ ACPI_FUNCTION_TRACE_PTR(ex_get_name_string, aml_address);
if (ACPI_TYPE_LOCAL_REGION_FIELD == data_type ||
ACPI_TYPE_LOCAL_BANK_FIELD == data_type ||
ACPI_TYPE_LOCAL_INDEX_FIELD == data_type) {
+
/* Disallow prefixes for types associated with field_unit names */
name_string = acpi_ex_allocate_name_string(0, 1);
@@ -272,7 +277,7 @@ acpi_ex_get_name_string(acpi_object_type data_type,
case AML_ROOT_PREFIX:
ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
- "root_prefix(\\) at %p\n",
+ "RootPrefix(\\) at %p\n",
aml_address));
/*
@@ -290,7 +295,7 @@ acpi_ex_get_name_string(acpi_object_type data_type,
do {
ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
- "parent_prefix (^) at %p\n",
+ "ParentPrefix (^) at %p\n",
aml_address));
aml_address++;
@@ -314,7 +319,7 @@ acpi_ex_get_name_string(acpi_object_type data_type,
case AML_DUAL_NAME_PREFIX:
ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
- "dual_name_prefix at %p\n",
+ "DualNamePrefix at %p\n",
aml_address));
aml_address++;
@@ -341,7 +346,7 @@ acpi_ex_get_name_string(acpi_object_type data_type,
case AML_MULTI_NAME_PREFIX_OP:
ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
- "multi_name_prefix at %p\n",
+ "MultiNamePrefix at %p\n",
aml_address));
/* Fetch count of segments remaining in name path */
@@ -377,7 +382,7 @@ acpi_ex_get_name_string(acpi_object_type data_type,
if (prefix_count == ACPI_UINT32_MAX) {
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "name_seg is \"\\\" followed by NULL\n"));
+ "NameSeg is \"\\\" followed by NULL\n"));
}
/* Consume the NULL byte */
@@ -410,6 +415,7 @@ acpi_ex_get_name_string(acpi_object_type data_type,
}
if (AE_CTRL_PENDING == status && has_prefix) {
+
/* Ran out of segments after processing a prefix */
ACPI_ERROR((AE_INFO, "Malformed Name at %p", name_string));
@@ -418,7 +424,7 @@ acpi_ex_get_name_string(acpi_object_type data_type,
if (ACPI_FAILURE(status)) {
if (name_string) {
- ACPI_MEM_FREE(name_string);
+ ACPI_FREE(name_string);
}
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c
index 23d0823..6374d8b 100644
--- a/drivers/acpi/executer/exoparg1.c
+++ b/drivers/acpi/executer/exoparg1.c
@@ -89,7 +89,7 @@ acpi_status acpi_ex_opcode_0A_0T_1R(struct acpi_walk_state *walk_state)
acpi_status status = AE_OK;
union acpi_operand_object *return_desc = NULL;
- ACPI_FUNCTION_TRACE_STR("ex_opcode_0A_0T_1R",
+ ACPI_FUNCTION_TRACE_STR(ex_opcode_0A_0T_1R,
acpi_ps_get_opcode_name(walk_state->opcode));
/* Examine the AML opcode */
@@ -150,7 +150,7 @@ acpi_status acpi_ex_opcode_1A_0T_0R(struct acpi_walk_state *walk_state)
union acpi_operand_object **operand = &walk_state->operands[0];
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE_STR("ex_opcode_1A_0T_0R",
+ ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_0T_0R,
acpi_ps_get_opcode_name(walk_state->opcode));
/* Examine the AML opcode */
@@ -216,7 +216,7 @@ acpi_status acpi_ex_opcode_1A_1T_0R(struct acpi_walk_state *walk_state)
acpi_status status = AE_OK;
union acpi_operand_object **operand = &walk_state->operands[0];
- ACPI_FUNCTION_TRACE_STR("ex_opcode_1A_1T_0R",
+ ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_1T_0R,
acpi_ps_get_opcode_name(walk_state->opcode));
/* Examine the AML opcode */
@@ -264,7 +264,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
acpi_integer power_of_ten;
acpi_integer digit;
- ACPI_FUNCTION_TRACE_STR("ex_opcode_1A_1T_1R",
+ ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_1T_1R,
acpi_ps_get_opcode_name(walk_state->opcode));
/* Examine the AML opcode */
@@ -322,8 +322,9 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
/* Since the bit position is one-based, subtract from 33 (65) */
- return_desc->integer.value = temp32 == 0 ? 0 :
- (ACPI_INTEGER_BIT_SIZE + 1) - temp32;
+ return_desc->integer.value =
+ temp32 ==
+ 0 ? 0 : (ACPI_INTEGER_BIT_SIZE + 1) - temp32;
break;
case AML_FROM_BCD_OP: /* from_bcd (BCDValue, Result) */
@@ -342,6 +343,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
for (i = 0;
(i < acpi_gbl_integer_nybble_width) && (digit > 0);
i++) {
+
/* Get the least significant 4-bit BCD digit */
temp32 = ((u32) digit) & 0xF;
@@ -487,6 +489,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
status = acpi_ex_convert_to_string(operand[0], &return_desc,
ACPI_EXPLICIT_CONVERT_DECIMAL);
if (return_desc == operand[0]) {
+
/* No conversion performed, add ref to handle return value */
acpi_ut_add_reference(return_desc);
}
@@ -497,6 +500,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
status = acpi_ex_convert_to_string(operand[0], &return_desc,
ACPI_EXPLICIT_CONVERT_HEX);
if (return_desc == operand[0]) {
+
/* No conversion performed, add ref to handle return value */
acpi_ut_add_reference(return_desc);
}
@@ -506,6 +510,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
status = acpi_ex_convert_to_buffer(operand[0], &return_desc);
if (return_desc == operand[0]) {
+
/* No conversion performed, add ref to handle return value */
acpi_ut_add_reference(return_desc);
}
@@ -516,6 +521,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
status = acpi_ex_convert_to_integer(operand[0], &return_desc,
ACPI_ANY_BASE);
if (return_desc == operand[0]) {
+
/* No conversion performed, add ref to handle return value */
acpi_ut_add_reference(return_desc);
}
@@ -541,6 +547,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
}
if (ACPI_SUCCESS(status)) {
+
/* Store the return value computed above into the target object */
status = acpi_ex_store(return_desc, operand[1], walk_state);
@@ -548,16 +555,18 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
cleanup:
- if (!walk_state->result_obj) {
- walk_state->result_obj = return_desc;
- }
-
/* Delete return object on error */
if (ACPI_FAILURE(status)) {
acpi_ut_remove_reference(return_desc);
}
+ /* Save return object on success */
+
+ else if (!walk_state->result_obj) {
+ walk_state->result_obj = return_desc;
+ }
+
return_ACPI_STATUS(status);
}
@@ -582,7 +591,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
u32 type;
acpi_integer value;
- ACPI_FUNCTION_TRACE_STR("ex_opcode_1A_0T_1R",
+ ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_0T_1R,
acpi_ps_get_opcode_name(walk_state->opcode));
/* Examine the AML opcode */
@@ -625,6 +634,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
temp_desc = operand[0];
if (ACPI_GET_DESCRIPTOR_TYPE(temp_desc) ==
ACPI_DESC_TYPE_OPERAND) {
+
/* Internal reference object - prevent deletion */
acpi_ut_add_reference(temp_desc);
@@ -689,6 +699,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
if (ACPI_FAILURE(status)) {
goto cleanup;
}
+
/* Allocate a descriptor to hold the type. */
return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
@@ -777,8 +788,25 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
/* Check for a method local or argument, or standalone String */
- if (ACPI_GET_DESCRIPTOR_TYPE(operand[0]) !=
+ if (ACPI_GET_DESCRIPTOR_TYPE(operand[0]) ==
ACPI_DESC_TYPE_NAMED) {
+ temp_desc =
+ acpi_ns_get_attached_object((struct
+ acpi_namespace_node *)
+ operand[0]);
+ if (temp_desc
+ &&
+ ((ACPI_GET_OBJECT_TYPE(temp_desc) ==
+ ACPI_TYPE_STRING)
+ || (ACPI_GET_OBJECT_TYPE(temp_desc) ==
+ ACPI_TYPE_LOCAL_REFERENCE))) {
+ operand[0] = temp_desc;
+ acpi_ut_add_reference(temp_desc);
+ } else {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+ } else {
switch (ACPI_GET_OBJECT_TYPE(operand[0])) {
case ACPI_TYPE_LOCAL_REFERENCE:
/*
@@ -827,26 +855,35 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
break;
case ACPI_TYPE_STRING:
+ break;
+ default:
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+ }
+
+ if (ACPI_GET_DESCRIPTOR_TYPE(operand[0]) !=
+ ACPI_DESC_TYPE_NAMED) {
+ if (ACPI_GET_OBJECT_TYPE(operand[0]) ==
+ ACPI_TYPE_STRING) {
/*
* This is a deref_of (String). The string is a reference
* to a named ACPI object.
*
* 1) Find the owning Node
- * 2) Dereference the node to an actual object. Could be a
+ * 2) Dereference the node to an actual object. Could be a
* Field, so we need to resolve the node to a value.
*/
status =
- acpi_ns_get_node_by_path(operand[0]->string.
- pointer,
- walk_state->
- scope_info->scope.
- node,
- ACPI_NS_SEARCH_PARENT,
- ACPI_CAST_INDIRECT_PTR
- (struct
- acpi_namespace_node,
- &return_desc));
+ acpi_ns_get_node(walk_state->scope_info->
+ scope.node,
+ operand[0]->string.pointer,
+ ACPI_NS_SEARCH_PARENT,
+ ACPI_CAST_INDIRECT_PTR
+ (struct
+ acpi_namespace_node,
+ &return_desc));
if (ACPI_FAILURE(status)) {
goto cleanup;
}
@@ -857,11 +894,6 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
(struct acpi_namespace_node, &return_desc),
walk_state);
goto cleanup;
-
- default:
-
- status = AE_AML_OPERAND_TYPE;
- goto cleanup;
}
}
@@ -937,13 +969,12 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
acpi_ut_add_reference
(return_desc);
}
-
break;
default:
ACPI_ERROR((AE_INFO,
- "Unknown Index target_type %X in obj %p",
+ "Unknown Index TargetType %X in obj %p",
operand[0]->reference.
target_type, operand[0]));
status = AE_AML_OPERAND_TYPE;
@@ -957,7 +988,6 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
if (ACPI_GET_DESCRIPTOR_TYPE(return_desc) ==
ACPI_DESC_TYPE_NAMED) {
-
return_desc =
acpi_ns_get_attached_object((struct
acpi_namespace_node
@@ -972,7 +1002,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
default:
ACPI_ERROR((AE_INFO,
- "Unknown opcode in ref(%p) - %X",
+ "Unknown opcode in reference(%p) - %X",
operand[0],
operand[0]->reference.opcode));
@@ -998,6 +1028,11 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
acpi_ut_remove_reference(return_desc);
}
- walk_state->result_obj = return_desc;
+ /* Save return object on success */
+
+ else {
+ walk_state->result_obj = return_desc;
+ }
+
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c
index e263a5d..7d2cbc1 100644
--- a/drivers/acpi/executer/exoparg2.c
+++ b/drivers/acpi/executer/exoparg2.c
@@ -92,7 +92,7 @@ acpi_status acpi_ex_opcode_2A_0T_0R(struct acpi_walk_state *walk_state)
u32 value;
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE_STR("ex_opcode_2A_0T_0R",
+ ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_0T_0R,
acpi_ps_get_opcode_name(walk_state->opcode));
/* Examine the opcode */
@@ -121,7 +121,7 @@ acpi_status acpi_ex_opcode_2A_0T_0R(struct acpi_walk_state *walk_state)
#ifdef ACPI_GPE_NOTIFY_CHECK
/*
* GPE method wake/notify check. Here, we want to ensure that we
- * don't receive any "device_wake" Notifies from a GPE _Lxx or _Exx
+ * don't receive any "DeviceWake" Notifies from a GPE _Lxx or _Exx
* GPE method during system runtime. If we do, the GPE is marked
* as "wake-only" and disabled.
*
@@ -138,6 +138,7 @@ acpi_status acpi_ex_opcode_2A_0T_0R(struct acpi_walk_state *walk_state)
acpi_ev_check_for_wake_only_gpe(walk_state->
gpe_event_info);
if (ACPI_FAILURE(status)) {
+
/* AE_WAKE_ONLY_GPE only error, means ignore this notify */
return_ACPI_STATUS(AE_OK)
@@ -185,7 +186,7 @@ acpi_status acpi_ex_opcode_2A_2T_1R(struct acpi_walk_state *walk_state)
union acpi_operand_object *return_desc2 = NULL;
acpi_status status;
- ACPI_FUNCTION_TRACE_STR("ex_opcode_2A_2T_1R",
+ ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_2T_1R,
acpi_ps_get_opcode_name(walk_state->opcode));
/* Execute the opcode */
@@ -252,6 +253,7 @@ acpi_status acpi_ex_opcode_2A_2T_1R(struct acpi_walk_state *walk_state)
acpi_ut_remove_reference(return_desc2);
if (ACPI_FAILURE(status)) {
+
/* Delete the return object */
acpi_ut_remove_reference(return_desc1);
@@ -281,12 +283,13 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
acpi_status status = AE_OK;
acpi_size length;
- ACPI_FUNCTION_TRACE_STR("ex_opcode_2A_1T_1R",
+ ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_1T_1R,
acpi_ps_get_opcode_name(walk_state->opcode));
/* Execute the opcode */
if (walk_state->op_info->flags & AML_MATH) {
+
/* All simple math opcodes (add, etc.) */
return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
@@ -383,54 +386,70 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
goto cleanup;
}
+ /* Initialize the Index reference object */
+
index = operand[1]->integer.value;
+ return_desc->reference.offset = (u32) index;
+ return_desc->reference.opcode = AML_INDEX_OP;
- /* At this point, the Source operand is a Package, Buffer, or String */
+ /*
+ * At this point, the Source operand is a String, Buffer, or Package.
+ * Verify that the index is within range.
+ */
+ switch (ACPI_GET_OBJECT_TYPE(operand[0])) {
+ case ACPI_TYPE_STRING:
- if (ACPI_GET_OBJECT_TYPE(operand[0]) == ACPI_TYPE_PACKAGE) {
- /* Object to be indexed is a Package */
+ if (index >= operand[0]->string.length) {
+ status = AE_AML_STRING_LIMIT;
+ }
+
+ return_desc->reference.target_type =
+ ACPI_TYPE_BUFFER_FIELD;
+ break;
+
+ case ACPI_TYPE_BUFFER:
+
+ if (index >= operand[0]->buffer.length) {
+ status = AE_AML_BUFFER_LIMIT;
+ }
+
+ return_desc->reference.target_type =
+ ACPI_TYPE_BUFFER_FIELD;
+ break;
+
+ case ACPI_TYPE_PACKAGE:
if (index >= operand[0]->package.count) {
- ACPI_ERROR((AE_INFO,
- "Index value (%X%8.8X) beyond package end (%X)",
- ACPI_FORMAT_UINT64(index),
- operand[0]->package.count));
status = AE_AML_PACKAGE_LIMIT;
- goto cleanup;
}
return_desc->reference.target_type = ACPI_TYPE_PACKAGE;
- return_desc->reference.object = operand[0];
return_desc->reference.where =
&operand[0]->package.elements[index];
- } else {
- /* Object to be indexed is a Buffer/String */
+ break;
- if (index >= operand[0]->buffer.length) {
- ACPI_ERROR((AE_INFO,
- "Index value (%X%8.8X) beyond end of buffer (%X)",
- ACPI_FORMAT_UINT64(index),
- operand[0]->buffer.length));
- status = AE_AML_BUFFER_LIMIT;
- goto cleanup;
- }
+ default:
- return_desc->reference.target_type =
- ACPI_TYPE_BUFFER_FIELD;
- return_desc->reference.object = operand[0];
+ status = AE_AML_INTERNAL;
+ goto cleanup;
+ }
+
+ /* Failure means that the Index was beyond the end of the object */
+
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Index (%X%8.8X) is beyond end of object",
+ ACPI_FORMAT_UINT64(index)));
+ goto cleanup;
}
/*
- * Add a reference to the target package/buffer/string for the life
- * of the index.
+ * Save the target object and add a reference to it for the life
+ * of the index
*/
+ return_desc->reference.object = operand[0];
acpi_ut_add_reference(operand[0]);
- /* Complete the Index reference object */
-
- return_desc->reference.opcode = AML_INDEX_OP;
- return_desc->reference.offset = (u32) index;
-
/* Store the reference to the Target */
status = acpi_ex_store(return_desc, operand[2], walk_state);
@@ -495,7 +514,7 @@ acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state)
acpi_status status = AE_OK;
u8 logical_result = FALSE;
- ACPI_FUNCTION_TRACE_STR("ex_opcode_2A_0T_1R",
+ ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_0T_1R,
acpi_ps_get_opcode_name(walk_state->opcode));
/* Create the internal return object */
@@ -509,6 +528,7 @@ acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state)
/* Execute the Opcode */
if (walk_state->op_info->flags & AML_LOGICAL_NUMERIC) {
+
/* logical_op (Operand0, Operand1) */
status = acpi_ex_do_logical_numeric_op(walk_state->opcode,
@@ -518,6 +538,7 @@ acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state)
value, &logical_result);
goto store_logical_result;
} else if (walk_state->op_info->flags & AML_LOGICAL) {
+
/* logical_op (Operand0, Operand1) */
status = acpi_ex_do_logical_op(walk_state->opcode, operand[0],
diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/executer/exoparg3.c
index 6a3a883..e2d945d 100644
--- a/drivers/acpi/executer/exoparg3.c
+++ b/drivers/acpi/executer/exoparg3.c
@@ -88,20 +88,19 @@ acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state)
struct acpi_signal_fatal_info *fatal;
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE_STR("ex_opcode_3A_0T_0R",
+ ACPI_FUNCTION_TRACE_STR(ex_opcode_3A_0T_0R,
acpi_ps_get_opcode_name(walk_state->opcode));
switch (walk_state->opcode) {
case AML_FATAL_OP: /* Fatal (fatal_type fatal_code fatal_arg) */
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "fatal_op: Type %X Code %X Arg %X <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n",
+ "FatalOp: Type %X Code %X Arg %X <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n",
(u32) operand[0]->integer.value,
(u32) operand[1]->integer.value,
(u32) operand[2]->integer.value));
- fatal =
- ACPI_MEM_ALLOCATE(sizeof(struct acpi_signal_fatal_info));
+ fatal = ACPI_ALLOCATE(sizeof(struct acpi_signal_fatal_info));
if (fatal) {
fatal->type = (u32) operand[0]->integer.value;
fatal->code = (u32) operand[1]->integer.value;
@@ -114,7 +113,7 @@ acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state)
/* Might return while OS is shutting down, just continue */
- ACPI_MEM_FREE(fatal);
+ ACPI_FREE(fatal);
break;
default:
@@ -151,7 +150,7 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state)
acpi_integer index;
acpi_size length;
- ACPI_FUNCTION_TRACE_STR("ex_opcode_3A_1T_1R",
+ ACPI_FUNCTION_TRACE_STR(ex_opcode_3A_1T_1R,
acpi_ps_get_opcode_name(walk_state->opcode));
switch (walk_state->opcode) {
@@ -196,7 +195,7 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state)
/* Always allocate a new buffer for the String */
- buffer = ACPI_MEM_CALLOCATE((acpi_size) length + 1);
+ buffer = ACPI_ALLOCATE_ZEROED((acpi_size) length + 1);
if (!buffer) {
status = AE_NO_MEMORY;
goto cleanup;
@@ -208,9 +207,10 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state)
/* If the requested length is zero, don't allocate a buffer */
if (length > 0) {
+
/* Allocate a new buffer for the Buffer */
- buffer = ACPI_MEM_CALLOCATE(length);
+ buffer = ACPI_ALLOCATE_ZEROED(length);
if (!buffer) {
status = AE_NO_MEMORY;
goto cleanup;
@@ -225,6 +225,7 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state)
}
if (buffer) {
+
/* We have a buffer, copy the portion requested */
ACPI_MEMCPY(buffer, operand[0]->string.pointer + index,
diff --git a/drivers/acpi/executer/exoparg6.c b/drivers/acpi/executer/exoparg6.c
index e043d92..f0c0ba6 100644
--- a/drivers/acpi/executer/exoparg6.c
+++ b/drivers/acpi/executer/exoparg6.c
@@ -220,7 +220,7 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state)
acpi_integer index;
union acpi_operand_object *this_element;
- ACPI_FUNCTION_TRACE_STR("ex_opcode_6A_0T_1R",
+ ACPI_FUNCTION_TRACE_STR(ex_opcode_6A_0T_1R,
acpi_ps_get_opcode_name(walk_state->opcode));
switch (walk_state->opcode) {
@@ -276,6 +276,7 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state)
* match was found.
*/
for (; index < operand[0]->package.count; index++) {
+
/* Get the current package element */
this_element = operand[0]->package.elements[index];
diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c
index 7719ae5..44d064f 100644
--- a/drivers/acpi/executer/exprep.c
+++ b/drivers/acpi/executer/exprep.c
@@ -97,7 +97,7 @@ acpi_ex_generate_access(u32 field_bit_offset,
u32 minimum_accesses = 0xFFFFFFFF;
u32 accesses;
- ACPI_FUNCTION_TRACE("ex_generate_access");
+ ACPI_FUNCTION_TRACE(ex_generate_access);
/* Round Field start offset and length to "minimal" byte boundaries */
@@ -146,7 +146,7 @@ acpi_ex_generate_access(u32 field_bit_offset,
accesses = field_end_offset - field_start_offset;
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "access_width %d end is within region\n",
+ "AccessWidth %d end is within region\n",
access_byte_width));
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
@@ -173,7 +173,7 @@ acpi_ex_generate_access(u32 field_bit_offset,
}
} else {
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "access_width %d end is NOT within region\n",
+ "AccessWidth %d end is NOT within region\n",
access_byte_width));
if (access_byte_width == 1) {
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
@@ -228,7 +228,7 @@ acpi_ex_decode_field_access(union acpi_operand_object *obj_desc,
u32 byte_alignment;
u32 bit_length;
- ACPI_FUNCTION_TRACE("ex_decode_field_access");
+ ACPI_FUNCTION_TRACE(ex_decode_field_access);
access = (field_flags & AML_FIELD_ACCESS_TYPE_MASK);
@@ -322,7 +322,7 @@ acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc,
u32 byte_alignment;
u32 nearest_byte_address;
- ACPI_FUNCTION_TRACE("ex_prep_common_field_object");
+ ACPI_FUNCTION_TRACE(ex_prep_common_field_object);
/*
* Note: the structure being initialized is the
@@ -415,13 +415,13 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
u32 type;
acpi_status status;
- ACPI_FUNCTION_TRACE("ex_prep_field_value");
+ ACPI_FUNCTION_TRACE(ex_prep_field_value);
/* Parameter validation */
if (info->field_type != ACPI_TYPE_LOCAL_INDEX_FIELD) {
if (!info->region_node) {
- ACPI_ERROR((AE_INFO, "Null region_node"));
+ ACPI_ERROR((AE_INFO, "Null RegionNode"));
return_ACPI_STATUS(AE_AML_NO_OPERAND);
}
@@ -467,7 +467,7 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
acpi_ut_add_reference(obj_desc->field.region_obj);
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "region_field: bit_off %X, Off %X, Gran %X, Region %p\n",
+ "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n",
obj_desc->field.start_field_bit_offset,
obj_desc->field.base_byte_offset,
obj_desc->field.access_byte_width,
@@ -488,7 +488,7 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
acpi_ut_add_reference(obj_desc->bank_field.bank_obj);
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "Bank Field: bit_off %X, Off %X, Gran %X, Region %p, bank_reg %p\n",
+ "Bank Field: BitOff %X, Off %X, Gran %X, Region %p, BankReg %p\n",
obj_desc->bank_field.start_field_bit_offset,
obj_desc->bank_field.base_byte_offset,
obj_desc->field.access_byte_width,
@@ -519,16 +519,29 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
acpi_ut_add_reference(obj_desc->index_field.index_obj);
/*
+ * April 2006: Changed to match MS behavior
+ *
* The value written to the Index register is the byte offset of the
- * target field
- * Note: may change code to: ACPI_DIV_8 (Info->field_bit_position)
+ * target field in units of the granularity of the index_field
+ *
+ * Previously, the value was calculated as an index in terms of the
+ * width of the Data register, as below:
+ *
+ * obj_desc->index_field.Value = (u32)
+ * (Info->field_bit_position / ACPI_MUL_8 (
+ * obj_desc->Field.access_byte_width));
+ *
+ * February 2006: Tried value as a byte offset:
+ * obj_desc->index_field.Value = (u32)
+ * ACPI_DIV_8 (Info->field_bit_position);
*/
- obj_desc->index_field.value = (u32)
- (info->field_bit_position /
- ACPI_MUL_8(obj_desc->field.access_byte_width));
+ obj_desc->index_field.value =
+ (u32) ACPI_ROUND_DOWN(ACPI_DIV_8(info->field_bit_position),
+ obj_desc->index_field.
+ access_byte_width);
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "index_field: bit_off %X, Off %X, Value %X, Gran %X, Index %p, Data %p\n",
+ "IndexField: BitOff %X, Off %X, Value %X, Gran %X, Index %p, Data %p\n",
obj_desc->index_field.start_field_bit_offset,
obj_desc->index_field.base_byte_offset,
obj_desc->index_field.value,
@@ -550,7 +563,7 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
acpi_ns_get_type(info->field_node));
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "Set named_obj %p [%4.4s], obj_desc %p\n",
+ "Set NamedObj %p [%4.4s], ObjDesc %p\n",
info->field_node,
acpi_ut_get_node_name(info->field_node), obj_desc));
diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c
index 6a4cfdf..3cc97ba 100644
--- a/drivers/acpi/executer/exregion.c
+++ b/drivers/acpi/executer/exregion.c
@@ -81,7 +81,7 @@ acpi_ex_system_memory_space_handler(u32 function,
u32 remainder;
#endif
- ACPI_FUNCTION_TRACE("ex_system_memory_space_handler");
+ ACPI_FUNCTION_TRACE(ex_system_memory_space_handler);
/* Validate and translate the bit width */
@@ -103,7 +103,7 @@ acpi_ex_system_memory_space_handler(u32 function,
break;
default:
- ACPI_ERROR((AE_INFO, "Invalid system_memory width %d",
+ ACPI_ERROR((AE_INFO, "Invalid SystemMemory width %d",
bit_width));
return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
}
@@ -135,6 +135,7 @@ acpi_ex_system_memory_space_handler(u32 function,
* Delete the existing mapping and create a new one.
*/
if (mem_info->mapped_length) {
+
/* Valid mapping, delete it */
acpi_os_unmap_memory(mem_info->mapped_logical_address,
@@ -181,8 +182,8 @@ acpi_ex_system_memory_space_handler(u32 function,
(acpi_integer) mem_info->mapped_physical_address);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "system_memory %d (%d width) Address=%8.8X%8.8X\n",
- function, bit_width, ACPI_FORMAT_UINT64(address)));
+ "System-Memory (width %d) R/W %d Address=%8.8X%8.8X\n",
+ bit_width, function, ACPI_FORMAT_UINT64(address)));
/*
* Perform the memory read or write
@@ -283,11 +284,11 @@ acpi_ex_system_io_space_handler(u32 function,
acpi_status status = AE_OK;
u32 value32;
- ACPI_FUNCTION_TRACE("ex_system_io_space_handler");
+ ACPI_FUNCTION_TRACE(ex_system_io_space_handler);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "system_iO %d (%d width) Address=%8.8X%8.8X\n",
- function, bit_width, ACPI_FORMAT_UINT64(address)));
+ "System-IO (width %d) R/W %d Address=%8.8X%8.8X\n",
+ bit_width, function, ACPI_FORMAT_UINT64(address)));
/* Decode the function parameter */
@@ -342,7 +343,7 @@ acpi_ex_pci_config_space_handler(u32 function,
struct acpi_pci_id *pci_id;
u16 pci_register;
- ACPI_FUNCTION_TRACE("ex_pci_config_space_handler");
+ ACPI_FUNCTION_TRACE(ex_pci_config_space_handler);
/*
* The arguments to acpi_os(Read|Write)pci_configuration are:
@@ -360,7 +361,7 @@ acpi_ex_pci_config_space_handler(u32 function,
pci_register = (u16) (u32) address;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "pci_config %d (%d) Seg(%04x) Bus(%04x) Dev(%04x) Func(%04x) Reg(%04x)\n",
+ "Pci-Config %d (%d) Seg(%04x) Bus(%04x) Dev(%04x) Func(%04x) Reg(%04x)\n",
function, bit_width, pci_id->segment, pci_id->bus,
pci_id->device, pci_id->function, pci_register));
@@ -414,7 +415,7 @@ acpi_ex_cmos_space_handler(u32 function,
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("ex_cmos_space_handler");
+ ACPI_FUNCTION_TRACE(ex_cmos_space_handler);
return_ACPI_STATUS(status);
}
@@ -446,7 +447,7 @@ acpi_ex_pci_bar_space_handler(u32 function,
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("ex_pci_bar_space_handler");
+ ACPI_FUNCTION_TRACE(ex_pci_bar_space_handler);
return_ACPI_STATUS(status);
}
@@ -476,23 +477,16 @@ acpi_ex_data_table_space_handler(u32 function,
acpi_integer * value,
void *handler_context, void *region_context)
{
- acpi_status status = AE_OK;
- u32 byte_width = ACPI_DIV_8(bit_width);
- u32 i;
- char *logical_addr_ptr;
-
- ACPI_FUNCTION_TRACE("ex_data_table_space_handler");
-
- logical_addr_ptr = ACPI_PHYSADDR_TO_PTR(address);
+ ACPI_FUNCTION_TRACE(ex_data_table_space_handler);
/* Perform the memory read or write */
switch (function) {
case ACPI_READ:
- for (i = 0; i < byte_width; i++) {
- ((char *)value)[i] = logical_addr_ptr[i];
- }
+ ACPI_MEMCPY(ACPI_CAST_PTR(char, value),
+ ACPI_PHYSADDR_TO_PTR(address),
+ ACPI_DIV_8(bit_width));
break;
case ACPI_WRITE:
@@ -501,5 +495,5 @@ acpi_ex_data_table_space_handler(u32 function,
return_ACPI_STATUS(AE_SUPPORT);
}
- return_ACPI_STATUS(status);
+ return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c
index 01b26c8..3089b05 100644
--- a/drivers/acpi/executer/exresnte.c
+++ b/drivers/acpi/executer/exresnte.c
@@ -87,7 +87,7 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr,
struct acpi_namespace_node *node;
acpi_object_type entry_type;
- ACPI_FUNCTION_TRACE("ex_resolve_node_to_value");
+ ACPI_FUNCTION_TRACE(ex_resolve_node_to_value);
/*
* The stack pointer points to a struct acpi_namespace_node (Node). Get the
@@ -97,12 +97,13 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr,
source_desc = acpi_ns_get_attached_object(node);
entry_type = acpi_ns_get_type((acpi_handle) node);
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Entry=%p source_desc=%p [%s]\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Entry=%p SourceDesc=%p [%s]\n",
node, source_desc,
acpi_ut_get_type_name(entry_type)));
if ((entry_type == ACPI_TYPE_LOCAL_ALIAS) ||
(entry_type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) {
+
/* There is always exactly one level of indirection */
node = ACPI_CAST_PTR(struct acpi_namespace_node, node->object);
@@ -113,10 +114,11 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr,
/*
* Several object types require no further processing:
- * 1) Devices rarely have an attached object, return the Node
+ * 1) Device/Thermal objects don't have a "real" subobject, return the Node
* 2) Method locals and arguments have a pseudo-Node
*/
- if (entry_type == ACPI_TYPE_DEVICE ||
+ if ((entry_type == ACPI_TYPE_DEVICE) ||
+ (entry_type == ACPI_TYPE_THERMAL) ||
(node->flags & (ANOBJ_METHOD_ARG | ANOBJ_METHOD_LOCAL))) {
return_ACPI_STATUS(AE_OK);
}
@@ -141,6 +143,7 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr,
status = acpi_ds_get_package_arguments(source_desc);
if (ACPI_SUCCESS(status)) {
+
/* Return an additional reference to the object */
obj_desc = source_desc;
@@ -158,6 +161,7 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr,
status = acpi_ds_get_buffer_arguments(source_desc);
if (ACPI_SUCCESS(status)) {
+
/* Return an additional reference to the object */
obj_desc = source_desc;
@@ -199,7 +203,7 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr,
case ACPI_TYPE_LOCAL_INDEX_FIELD:
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "field_read Node=%p source_desc=%p Type=%X\n",
+ "FieldRead Node=%p SourceDesc=%p Type=%X\n",
node, source_desc, entry_type));
status =
@@ -213,7 +217,6 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr,
case ACPI_TYPE_METHOD:
case ACPI_TYPE_POWER:
case ACPI_TYPE_PROCESSOR:
- case ACPI_TYPE_THERMAL:
case ACPI_TYPE_EVENT:
case ACPI_TYPE_REGION:
@@ -240,6 +243,8 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr,
/* This is a ddb_handle */
/* Return an additional reference to the object */
+ case AML_REF_OF_OP:
+
obj_desc = source_desc;
acpi_ut_add_reference(obj_desc);
break;
diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c
index 1deed49..6499de8 100644
--- a/drivers/acpi/executer/exresolv.c
+++ b/drivers/acpi/executer/exresolv.c
@@ -78,7 +78,7 @@ acpi_ex_resolve_to_value(union acpi_operand_object **stack_ptr,
{
acpi_status status;
- ACPI_FUNCTION_TRACE_PTR("ex_resolve_to_value", stack_ptr);
+ ACPI_FUNCTION_TRACE_PTR(ex_resolve_to_value, stack_ptr);
if (!stack_ptr || !*stack_ptr) {
ACPI_ERROR((AE_INFO, "Internal - null pointer"));
@@ -144,7 +144,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
union acpi_operand_object *obj_desc;
u16 opcode;
- ACPI_FUNCTION_TRACE("ex_resolve_object_to_value");
+ ACPI_FUNCTION_TRACE(ex_resolve_object_to_value);
stack_desc = *stack_ptr;
@@ -190,7 +190,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
}
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "[Arg/Local %X] value_obj is %p\n",
+ "[Arg/Local %X] ValueObj is %p\n",
stack_desc->reference.offset,
obj_desc));
@@ -239,7 +239,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
/* Invalid reference object */
ACPI_ERROR((AE_INFO,
- "Unknown target_type %X in Index/Reference obj %p",
+ "Unknown TargetType %X in Index/Reference obj %p",
stack_desc->reference.target_type,
stack_desc));
status = AE_AML_INTERNAL;
@@ -257,10 +257,24 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
case AML_INT_NAMEPATH_OP: /* Reference to a named object */
- /* Get the object pointed to by the namespace node */
+ /* Dereference the name */
+
+ if ((stack_desc->reference.node->type ==
+ ACPI_TYPE_DEVICE)
+ || (stack_desc->reference.node->type ==
+ ACPI_TYPE_THERMAL)) {
+
+ /* These node types do not have 'real' subobjects */
+
+ *stack_ptr = (void *)stack_desc->reference.node;
+ } else {
+ /* Get the object pointed to by the namespace node */
+
+ *stack_ptr =
+ (stack_desc->reference.node)->object;
+ acpi_ut_add_reference(*stack_ptr);
+ }
- *stack_ptr = (stack_desc->reference.node)->object;
- acpi_ut_add_reference(*stack_ptr);
acpi_ut_remove_reference(stack_desc);
break;
@@ -293,7 +307,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
case ACPI_TYPE_LOCAL_INDEX_FIELD:
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "field_read source_desc=%p Type=%X\n",
+ "FieldRead SourceDesc=%p Type=%X\n",
stack_desc,
ACPI_GET_OBJECT_TYPE(stack_desc)));
@@ -337,7 +351,7 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
acpi_object_type type;
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_ex_resolve_multiple");
+ ACPI_FUNCTION_TRACE(acpi_ex_resolve_multiple);
/* Operand can be either a namespace node or an operand descriptor */
@@ -382,10 +396,16 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
while (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_REFERENCE) {
switch (obj_desc->reference.opcode) {
case AML_REF_OF_OP:
+ case AML_INT_NAMEPATH_OP:
/* Dereference the reference pointer */
- node = obj_desc->reference.object;
+ if (obj_desc->reference.opcode == AML_REF_OF_OP) {
+ node = obj_desc->reference.object;
+ } else { /* AML_INT_NAMEPATH_OP */
+
+ node = obj_desc->reference.node;
+ }
/* All "References" point to a NS node */
@@ -401,6 +421,7 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
obj_desc = acpi_ns_get_attached_object(node);
if (!obj_desc) {
+
/* No object, use the NS node type */
type = acpi_ns_get_type(node);
@@ -432,6 +453,7 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
*/
obj_desc = *(obj_desc->reference.where);
if (!obj_desc) {
+
/* NULL package elements are allowed */
type = 0; /* Uninitialized */
@@ -439,39 +461,6 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
}
break;
- case AML_INT_NAMEPATH_OP:
-
- /* Dereference the reference pointer */
-
- node = obj_desc->reference.node;
-
- /* All "References" point to a NS node */
-
- if (ACPI_GET_DESCRIPTOR_TYPE(node) !=
- ACPI_DESC_TYPE_NAMED) {
- ACPI_ERROR((AE_INFO, "Not a NS node %p [%s]",
- node,
- acpi_ut_get_descriptor_name(node)));
- return_ACPI_STATUS(AE_AML_INTERNAL);
- }
-
- /* Get the attached object */
-
- obj_desc = acpi_ns_get_attached_object(node);
- if (!obj_desc) {
- /* No object, use the NS node type */
-
- type = acpi_ns_get_type(node);
- goto exit;
- }
-
- /* Check for circular references */
-
- if (obj_desc == operand) {
- return_ACPI_STATUS(AE_AML_CIRCULAR_REFERENCE);
- }
- break;
-
case AML_LOCAL_OP:
case AML_ARG_OP:
@@ -513,7 +502,7 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
case AML_DEBUG_OP:
- /* The Debug Object is of type "debug_object" */
+ /* The Debug Object is of type "DebugObject" */
type = ACPI_TYPE_DEBUG_OBJECT;
goto exit;
diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c
index a1c000f..4c93d09 100644
--- a/drivers/acpi/executer/exresop.c
+++ b/drivers/acpi/executer/exresop.c
@@ -77,6 +77,7 @@ acpi_ex_check_object_type(acpi_object_type type_needed,
ACPI_FUNCTION_ENTRY();
if (type_needed == ACPI_TYPE_ANY) {
+
/* All types OK, so we don't perform any typechecks */
return (AE_OK);
@@ -143,7 +144,7 @@ acpi_ex_resolve_operands(u16 opcode,
acpi_object_type type_needed;
u16 target_op = 0;
- ACPI_FUNCTION_TRACE_U32("ex_resolve_operands", opcode);
+ ACPI_FUNCTION_TRACE_U32(ex_resolve_operands, opcode);
op_info = acpi_ps_get_opcode_info(opcode);
if (op_info->class == AML_CLASS_UNKNOWN) {
@@ -158,7 +159,7 @@ acpi_ex_resolve_operands(u16 opcode,
}
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Opcode %X [%s] required_operand_types=%8.8X\n",
+ "Opcode %X [%s] RequiredOperandTypes=%8.8X\n",
opcode, op_info->name, arg_types));
/*
@@ -224,6 +225,7 @@ acpi_ex_resolve_operands(u16 opcode,
}
if (object_type == (u8) ACPI_TYPE_LOCAL_REFERENCE) {
+
/* Decode the Reference */
op_info = acpi_ps_get_opcode_info(opcode);
@@ -247,7 +249,7 @@ acpi_ex_resolve_operands(u16 opcode,
ACPI_DEBUG_ONLY_MEMBERS(ACPI_DEBUG_PRINT
((ACPI_DB_EXEC,
- "Operand is a Reference, ref_opcode [%s]\n",
+ "Operand is a Reference, RefOpcode [%s]\n",
(acpi_ps_get_opcode_info
(obj_desc->
reference.
@@ -332,6 +334,7 @@ acpi_ex_resolve_operands(u16 opcode,
}
if (obj_desc->reference.opcode == AML_NAME_OP) {
+
/* Convert a named reference to the actual named object */
temp_node = obj_desc->reference.object;
@@ -623,7 +626,7 @@ acpi_ex_resolve_operands(u16 opcode,
default:
ACPI_ERROR((AE_INFO,
- "Needed [Region/region_field], found [%s] %p",
+ "Needed [Region/RegionField], found [%s] %p",
acpi_ut_get_object_type_name
(obj_desc), obj_desc));
@@ -662,6 +665,7 @@ acpi_ex_resolve_operands(u16 opcode,
}
if (target_op == AML_DEBUG_OP) {
+
/* Allow store of any object to the Debug object */
break;
diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c
index 3f020c0..0456405 100644
--- a/drivers/acpi/executer/exstore.c
+++ b/drivers/acpi/executer/exstore.c
@@ -82,7 +82,7 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
{
u32 i;
- ACPI_FUNCTION_TRACE_PTR("ex_do_debug_object", source_desc);
+ ACPI_FUNCTION_TRACE_PTR(ex_do_debug_object, source_desc);
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %*s",
level, " "));
@@ -245,7 +245,7 @@ acpi_ex_store(union acpi_operand_object *source_desc,
acpi_status status = AE_OK;
union acpi_operand_object *ref_desc = dest_desc;
- ACPI_FUNCTION_TRACE_PTR("ex_store", dest_desc);
+ ACPI_FUNCTION_TRACE_PTR(ex_store, dest_desc);
/* Validate parameters */
@@ -297,7 +297,7 @@ acpi_ex_store(union acpi_operand_object *source_desc,
ACPI_DUMP_STACK_ENTRY(source_desc);
ACPI_DUMP_STACK_ENTRY(dest_desc);
- ACPI_DUMP_OPERANDS(&dest_desc, ACPI_IMODE_EXECUTE, "ex_store",
+ ACPI_DUMP_OPERANDS(&dest_desc, ACPI_IMODE_EXECUTE, "ExStore",
2,
"Target is not a Reference or Constant object");
@@ -396,7 +396,7 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
u8 value = 0;
u32 i;
- ACPI_FUNCTION_TRACE("ex_store_object_to_index");
+ ACPI_FUNCTION_TRACE(ex_store_object_to_index);
/*
* Destination must be a reference pointer, and
@@ -423,6 +423,7 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
}
if (obj_desc) {
+
/* Decrement reference count by the ref count of the parent package */
for (i = 0; i < ((union acpi_operand_object *)
@@ -502,8 +503,7 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
break;
default:
- ACPI_ERROR((AE_INFO,
- "Target is not a Package or buffer_field"));
+ ACPI_ERROR((AE_INFO, "Target is not a Package or BufferField"));
status = AE_AML_OPERAND_TYPE;
break;
}
@@ -548,7 +548,7 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
union acpi_operand_object *new_desc;
acpi_object_type target_type;
- ACPI_FUNCTION_TRACE_PTR("ex_store_object_to_node", source_desc);
+ ACPI_FUNCTION_TRACE_PTR(ex_store_object_to_node, source_desc);
/* Get current type of the node, and object attached to Node */
@@ -572,6 +572,7 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
/* If no implicit conversion, drop into the default case below */
if ((!implicit_conversion) || (walk_state->opcode == AML_COPY_OP)) {
+
/* Force execution of default (no implicit conversion) */
target_type = ACPI_TYPE_ANY;
diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c
index 42967ba..591aaf0 100644
--- a/drivers/acpi/executer/exstoren.c
+++ b/drivers/acpi/executer/exstoren.c
@@ -72,7 +72,7 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr,
union acpi_operand_object *source_desc = *source_desc_ptr;
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("ex_resolve_object");
+ ACPI_FUNCTION_TRACE(ex_resolve_object);
/* Ensure we have a Target that can be stored to */
@@ -97,6 +97,7 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr,
*/
if (ACPI_GET_OBJECT_TYPE(source_desc) ==
ACPI_TYPE_LOCAL_REFERENCE) {
+
/* Resolve a reference object first */
status =
@@ -121,6 +122,7 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr,
!((ACPI_GET_OBJECT_TYPE(source_desc) ==
ACPI_TYPE_LOCAL_REFERENCE)
&& (source_desc->reference.opcode == AML_LOAD_OP))) {
+
/* Conversion successful but still not a valid type */
ACPI_ERROR((AE_INFO,
@@ -199,7 +201,7 @@ acpi_ex_store_object_to_object(union acpi_operand_object *source_desc,
union acpi_operand_object *actual_src_desc;
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE_PTR("ex_store_object_to_object", source_desc);
+ ACPI_FUNCTION_TRACE_PTR(ex_store_object_to_object, source_desc);
actual_src_desc = source_desc;
if (!dest_desc) {
@@ -289,6 +291,7 @@ acpi_ex_store_object_to_object(union acpi_operand_object *source_desc,
}
if (actual_src_desc != source_desc) {
+
/* Delete the intermediate (temporary) source object */
acpi_ut_remove_reference(actual_src_desc);
diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/executer/exstorob.c
index 6ab7070..99ebe5a 100644
--- a/drivers/acpi/executer/exstorob.c
+++ b/drivers/acpi/executer/exstorob.c
@@ -67,7 +67,7 @@ acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc,
u32 length;
u8 *buffer;
- ACPI_FUNCTION_TRACE_PTR("ex_store_buffer_to_buffer", source_desc);
+ ACPI_FUNCTION_TRACE_PTR(ex_store_buffer_to_buffer, source_desc);
/* We know that source_desc is a buffer by now */
@@ -80,7 +80,7 @@ acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc,
*/
if ((target_desc->buffer.length == 0) ||
(target_desc->common.flags & AOPOBJ_STATIC_POINTER)) {
- target_desc->buffer.pointer = ACPI_MEM_ALLOCATE(length);
+ target_desc->buffer.pointer = ACPI_ALLOCATE(length);
if (!target_desc->buffer.pointer) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
@@ -91,6 +91,7 @@ acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc,
/* Copy source buffer to target buffer */
if (length <= target_desc->buffer.length) {
+
/* Clear existing buffer and copy in the new one */
ACPI_MEMSET(target_desc->buffer.pointer, 0,
@@ -102,7 +103,7 @@ acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc,
* NOTE: ACPI versions up to 3.0 specified that the buffer must be
* truncated if the string is smaller than the buffer. However, "other"
* implementations of ACPI never did this and thus became the defacto
- * standard. ACPi 3.0_a changes this behavior such that the buffer
+ * standard. ACPI 3.0_a changes this behavior such that the buffer
* is no longer truncated.
*/
@@ -113,6 +114,7 @@ acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc,
* copy must not truncate the original buffer.
*/
if (original_src_type == ACPI_TYPE_STRING) {
+
/* Set the new length of the target */
target_desc->buffer.length = length;
@@ -156,7 +158,7 @@ acpi_ex_store_string_to_string(union acpi_operand_object *source_desc,
u32 length;
u8 *buffer;
- ACPI_FUNCTION_TRACE_PTR("ex_store_string_to_string", source_desc);
+ ACPI_FUNCTION_TRACE_PTR(ex_store_string_to_string, source_desc);
/* We know that source_desc is a string by now */
@@ -183,13 +185,14 @@ acpi_ex_store_string_to_string(union acpi_operand_object *source_desc,
*/
if (target_desc->string.pointer &&
(!(target_desc->common.flags & AOPOBJ_STATIC_POINTER))) {
+
/* Only free if not a pointer into the DSDT */
- ACPI_MEM_FREE(target_desc->string.pointer);
+ ACPI_FREE(target_desc->string.pointer);
}
- target_desc->string.pointer = ACPI_MEM_CALLOCATE((acpi_size)
- length + 1);
+ target_desc->string.pointer = ACPI_ALLOCATE_ZEROED((acpi_size)
+ length + 1);
if (!target_desc->string.pointer) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c
index ea9144f..52beee3 100644
--- a/drivers/acpi/executer/exsystem.c
+++ b/drivers/acpi/executer/exsystem.c
@@ -68,7 +68,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_handle semaphore, u16 timeout)
acpi_status status;
acpi_status status2;
- ACPI_FUNCTION_TRACE("ex_system_wait_semaphore");
+ ACPI_FUNCTION_TRACE(ex_system_wait_semaphore);
status = acpi_os_wait_semaphore(semaphore, 1, 0);
if (ACPI_SUCCESS(status)) {
@@ -76,6 +76,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_handle semaphore, u16 timeout)
}
if (status == AE_TIME) {
+
/* We must wait, so unlock the interpreter */
acpi_ex_exit_interpreter();
@@ -90,6 +91,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_handle semaphore, u16 timeout)
status2 = acpi_ex_enter_interpreter();
if (ACPI_FAILURE(status2)) {
+
/* Report fatal error, could not acquire interpreter */
return_ACPI_STATUS(status2);
@@ -191,7 +193,7 @@ acpi_ex_system_acquire_mutex(union acpi_operand_object * time_desc,
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE_PTR("ex_system_acquire_mutex", obj_desc);
+ ACPI_FUNCTION_TRACE_PTR(ex_system_acquire_mutex, obj_desc);
if (!obj_desc) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -229,7 +231,7 @@ acpi_status acpi_ex_system_release_mutex(union acpi_operand_object *obj_desc)
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("ex_system_release_mutex");
+ ACPI_FUNCTION_TRACE(ex_system_release_mutex);
if (!obj_desc) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -263,7 +265,7 @@ acpi_status acpi_ex_system_signal_event(union acpi_operand_object *obj_desc)
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("ex_system_signal_event");
+ ACPI_FUNCTION_TRACE(ex_system_signal_event);
if (obj_desc) {
status = acpi_os_signal_semaphore(obj_desc->event.semaphore, 1);
@@ -293,7 +295,7 @@ acpi_ex_system_wait_event(union acpi_operand_object *time_desc,
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("ex_system_wait_event");
+ ACPI_FUNCTION_TRACE(ex_system_wait_event);
if (obj_desc) {
status =
diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c
index f73a61a..982c8b6 100644
--- a/drivers/acpi/executer/exutils.c
+++ b/drivers/acpi/executer/exutils.c
@@ -87,9 +87,9 @@ acpi_status acpi_ex_enter_interpreter(void)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ex_enter_interpreter");
+ ACPI_FUNCTION_TRACE(ex_enter_interpreter);
- status = acpi_ut_acquire_mutex(ACPI_MTX_EXECUTE);
+ status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER);
if (ACPI_FAILURE(status)) {
ACPI_ERROR((AE_INFO, "Could not acquire interpreter mutex"));
}
@@ -123,9 +123,9 @@ void acpi_ex_exit_interpreter(void)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ex_exit_interpreter");
+ ACPI_FUNCTION_TRACE(ex_exit_interpreter);
- status = acpi_ut_release_mutex(ACPI_MTX_EXECUTE);
+ status = acpi_ut_release_mutex(ACPI_MTX_INTERPRETER);
if (ACPI_FAILURE(status)) {
ACPI_ERROR((AE_INFO, "Could not release interpreter mutex"));
}
@@ -189,11 +189,12 @@ u8 acpi_ex_acquire_global_lock(u32 field_flags)
u8 locked = FALSE;
acpi_status status;
- ACPI_FUNCTION_TRACE("ex_acquire_global_lock");
+ ACPI_FUNCTION_TRACE(ex_acquire_global_lock);
/* Only attempt lock if the always_lock bit is set */
if (field_flags & AML_FIELD_LOCK_RULE_MASK) {
+
/* We should attempt to get the lock, wait forever */
status = acpi_ev_acquire_global_lock(ACPI_WAIT_FOREVER);
@@ -225,15 +226,17 @@ void acpi_ex_release_global_lock(u8 locked_by_me)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ex_release_global_lock");
+ ACPI_FUNCTION_TRACE(ex_release_global_lock);
/* Only attempt unlock if the caller locked it */
if (locked_by_me) {
+
/* OK, now release the lock */
status = acpi_ev_release_global_lock();
if (ACPI_FAILURE(status)) {
+
/* Report the error, but there isn't much else we can do */
ACPI_EXCEPTION((AE_INFO, status,
@@ -263,7 +266,7 @@ static u32 acpi_ex_digits_needed(acpi_integer value, u32 base)
u32 num_digits;
acpi_integer current_value;
- ACPI_FUNCTION_TRACE("ex_digits_needed");
+ ACPI_FUNCTION_TRACE(ex_digits_needed);
/* acpi_integer is unsigned, so we don't worry about a '-' prefix */
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index e8165c4..1cd2578 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -48,6 +48,8 @@ MODULE_LICENSE("GPL");
static int acpi_fan_add(struct acpi_device *device);
static int acpi_fan_remove(struct acpi_device *device, int type);
+static int acpi_fan_suspend(struct acpi_device *device, int state);
+static int acpi_fan_resume(struct acpi_device *device, int state);
static struct acpi_driver acpi_fan_driver = {
.name = ACPI_FAN_DRIVER_NAME,
@@ -56,6 +58,8 @@ static struct acpi_driver acpi_fan_driver = {
.ops = {
.add = acpi_fan_add,
.remove = acpi_fan_remove,
+ .suspend = acpi_fan_suspend,
+ .resume = acpi_fan_resume,
},
};
@@ -206,6 +210,10 @@ static int acpi_fan_add(struct acpi_device *device)
goto end;
}
+ device->flags.force_power_state = 1;
+ acpi_bus_set_power(device->handle, state);
+ device->flags.force_power_state = 0;
+
result = acpi_fan_add_fs(device);
if (result)
goto end;
@@ -239,6 +247,38 @@ static int acpi_fan_remove(struct acpi_device *device, int type)
return_VALUE(0);
}
+static int acpi_fan_suspend(struct acpi_device *device, int state)
+{
+ if (!device)
+ return -EINVAL;
+
+ acpi_bus_set_power(device->handle, ACPI_STATE_D0);
+
+ return AE_OK;
+}
+
+static int acpi_fan_resume(struct acpi_device *device, int state)
+{
+ int result = 0;
+ int power_state = 0;
+
+ if (!device)
+ return -EINVAL;
+
+ result = acpi_bus_get_power(device->handle, &power_state);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error reading fan power state\n"));
+ return result;
+ }
+
+ device->flags.force_power_state = 1;
+ acpi_bus_set_power(device->handle, power_state);
+ device->flags.force_power_state = 0;
+
+ return result;
+}
+
static int __init acpi_fan_init(void)
{
int result = 0;
diff --git a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/hardware/hwacpi.c
index ea2f132..de50fab 100644
--- a/drivers/acpi/hardware/hwacpi.c
+++ b/drivers/acpi/hardware/hwacpi.c
@@ -63,7 +63,7 @@ acpi_status acpi_hw_initialize(void)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("hw_initialize");
+ ACPI_FUNCTION_TRACE(hw_initialize);
/* We must have the ACPI tables by the time we get here */
@@ -100,7 +100,7 @@ acpi_status acpi_hw_set_mode(u32 mode)
acpi_status status;
u32 retry;
- ACPI_FUNCTION_TRACE("hw_set_mode");
+ ACPI_FUNCTION_TRACE(hw_set_mode);
/*
* ACPI 2.0 clarified that if SMI_CMD in FADT is zero,
@@ -198,7 +198,7 @@ u32 acpi_hw_get_mode(void)
acpi_status status;
u32 value;
- ACPI_FUNCTION_TRACE("hw_get_mode");
+ ACPI_FUNCTION_TRACE(hw_get_mode);
/*
* ACPI 2.0 clarified that if SMI_CMD in FADT is zero,
diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c
index d84942d..608a3a6 100644
--- a/drivers/acpi/hardware/hwgpe.c
+++ b/drivers/acpi/hardware/hwgpe.c
@@ -214,6 +214,7 @@ acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info,
/* Examine each GPE Register within the block */
for (i = 0; i < gpe_block->register_count; i++) {
+
/* Disable all GPEs in this register */
status = acpi_hw_low_level_write(8, 0x00,
@@ -250,6 +251,7 @@ acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info,
/* Examine each GPE Register within the block */
for (i = 0; i < gpe_block->register_count; i++) {
+
/* Clear status on all GPEs in this register */
status = acpi_hw_low_level_write(8, 0xFF,
@@ -368,7 +370,7 @@ acpi_status acpi_hw_disable_all_gpes(void)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("hw_disable_all_gpes");
+ ACPI_FUNCTION_TRACE(hw_disable_all_gpes);
status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block);
status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block);
@@ -391,7 +393,7 @@ acpi_status acpi_hw_enable_all_runtime_gpes(void)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("hw_enable_all_runtime_gpes");
+ ACPI_FUNCTION_TRACE(hw_enable_all_runtime_gpes);
status = acpi_ev_walk_gpe_list(acpi_hw_enable_runtime_gpe_block);
return_ACPI_STATUS(status);
@@ -413,7 +415,7 @@ acpi_status acpi_hw_enable_all_wakeup_gpes(void)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("hw_enable_all_wakeup_gpes");
+ ACPI_FUNCTION_TRACE(hw_enable_all_wakeup_gpes);
status = acpi_ev_walk_gpe_list(acpi_hw_enable_wakeup_gpe_block);
return_ACPI_STATUS(status);
diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c
index e1fe754..ae142de 100644
--- a/drivers/acpi/hardware/hwregs.c
+++ b/drivers/acpi/hardware/hwregs.c
@@ -43,8 +43,6 @@
* POSSIBILITY OF SUCH DAMAGES.
*/
-#include <linux/module.h>
-
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
#include <acpi/acevents.h>
@@ -63,23 +61,21 @@ ACPI_MODULE_NAME("hwregs")
* DESCRIPTION: Clears all fixed and general purpose status bits
* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
*
+ * NOTE: TBD: Flags parameter is obsolete, to be removed
+ *
******************************************************************************/
acpi_status acpi_hw_clear_acpi_status(u32 flags)
{
acpi_status status;
+ acpi_cpu_flags lock_flags = 0;
- ACPI_FUNCTION_TRACE("hw_clear_acpi_status");
+ ACPI_FUNCTION_TRACE(hw_clear_acpi_status);
ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %04X\n",
ACPI_BITMASK_ALL_FIXED_STATUS,
(u16) acpi_gbl_FADT->xpm1a_evt_blk.address));
- if (flags & ACPI_MTX_LOCK) {
- status = acpi_ut_acquire_mutex(ACPI_MTX_HARDWARE);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- }
+ lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
ACPI_REGISTER_PM1_STATUS,
@@ -104,9 +100,7 @@ acpi_status acpi_hw_clear_acpi_status(u32 flags)
status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block);
unlock_and_exit:
- if (flags & ACPI_MTX_LOCK) {
- (void)acpi_ut_release_mutex(ACPI_MTX_HARDWARE);
- }
+ acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags);
return_ACPI_STATUS(status);
}
@@ -129,10 +123,9 @@ acpi_status
acpi_get_sleep_type_data(u8 sleep_state, u8 * sleep_type_a, u8 * sleep_type_b)
{
acpi_status status = AE_OK;
- struct acpi_parameter_info info;
- char *sleep_state_name;
+ struct acpi_evaluate_info *info;
- ACPI_FUNCTION_TRACE("acpi_get_sleep_type_data");
+ ACPI_FUNCTION_TRACE(acpi_get_sleep_type_data);
/* Validate parameters */
@@ -140,34 +133,39 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 * sleep_type_a, u8 * sleep_type_b)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Evaluate the namespace object containing the values for this state */
+ /* Allocate the evaluation information block */
+
+ info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
+ if (!info) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
- info.parameters = NULL;
- info.return_object = NULL;
- sleep_state_name =
+ info->pathname =
ACPI_CAST_PTR(char, acpi_gbl_sleep_state_names[sleep_state]);
- status = acpi_ns_evaluate_by_name(sleep_state_name, &info);
+ /* Evaluate the namespace object containing the values for this state */
+
+ status = acpi_ns_evaluate(info);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "%s while evaluating sleep_state [%s]\n",
+ "%s while evaluating SleepState [%s]\n",
acpi_format_exception(status),
- sleep_state_name));
+ info->pathname));
- return_ACPI_STATUS(status);
+ goto cleanup;
}
/* Must have a return object */
- if (!info.return_object) {
+ if (!info->return_object) {
ACPI_ERROR((AE_INFO, "No Sleep State object returned from [%s]",
- sleep_state_name));
+ info->pathname));
status = AE_NOT_EXIST;
}
/* It must be of type Package */
- else if (ACPI_GET_OBJECT_TYPE(info.return_object) != ACPI_TYPE_PACKAGE) {
+ else if (ACPI_GET_OBJECT_TYPE(info->return_object) != ACPI_TYPE_PACKAGE) {
ACPI_ERROR((AE_INFO,
"Sleep State return object is not a Package"));
status = AE_AML_OPERAND_TYPE;
@@ -180,7 +178,7 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 * sleep_type_a, u8 * sleep_type_b)
* by BIOS vendors seems to be to have 2 or more elements, at least
* one per sleep type (A/B).
*/
- else if (info.return_object->package.count < 2) {
+ else if (info->return_object->package.count < 2) {
ACPI_ERROR((AE_INFO,
"Sleep State return package does not have at least two elements"));
status = AE_AML_NO_OPERAND;
@@ -188,39 +186,42 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 * sleep_type_a, u8 * sleep_type_b)
/* The first two elements must both be of type Integer */
- else if ((ACPI_GET_OBJECT_TYPE(info.return_object->package.elements[0])
+ else if ((ACPI_GET_OBJECT_TYPE(info->return_object->package.elements[0])
!= ACPI_TYPE_INTEGER) ||
- (ACPI_GET_OBJECT_TYPE(info.return_object->package.elements[1])
+ (ACPI_GET_OBJECT_TYPE(info->return_object->package.elements[1])
!= ACPI_TYPE_INTEGER)) {
ACPI_ERROR((AE_INFO,
"Sleep State return package elements are not both Integers (%s, %s)",
- acpi_ut_get_object_type_name(info.return_object->
+ acpi_ut_get_object_type_name(info->return_object->
package.elements[0]),
- acpi_ut_get_object_type_name(info.return_object->
+ acpi_ut_get_object_type_name(info->return_object->
package.elements[1])));
status = AE_AML_OPERAND_TYPE;
} else {
/* Valid _Sx_ package size, type, and value */
*sleep_type_a = (u8)
- (info.return_object->package.elements[0])->integer.value;
+ (info->return_object->package.elements[0])->integer.value;
*sleep_type_b = (u8)
- (info.return_object->package.elements[1])->integer.value;
+ (info->return_object->package.elements[1])->integer.value;
}
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
- "While evaluating sleep_state [%s], bad Sleep object %p type %s",
- sleep_state_name, info.return_object,
- acpi_ut_get_object_type_name(info.
+ "While evaluating SleepState [%s], bad Sleep object %p type %s",
+ info->pathname, info->return_object,
+ acpi_ut_get_object_type_name(info->
return_object)));
}
- acpi_ut_remove_reference(info.return_object);
+ acpi_ut_remove_reference(info->return_object);
+
+ cleanup:
+ ACPI_FREE(info);
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_get_sleep_type_data);
+ACPI_EXPORT_SYMBOL(acpi_get_sleep_type_data)
/*******************************************************************************
*
@@ -233,13 +234,12 @@ EXPORT_SYMBOL(acpi_get_sleep_type_data);
* DESCRIPTION: Map register_id into a register bitmask.
*
******************************************************************************/
-
struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id)
{
ACPI_FUNCTION_ENTRY();
if (register_id > ACPI_BITREG_MAX) {
- ACPI_ERROR((AE_INFO, "Invalid bit_register ID: %X",
+ ACPI_ERROR((AE_INFO, "Invalid BitRegister ID: %X",
register_id));
return (NULL);
}
@@ -260,6 +260,8 @@ struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id)
*
* DESCRIPTION: ACPI bit_register read function.
*
+ * NOTE: TBD: Flags parameter is obsolete, to be removed
+ *
******************************************************************************/
acpi_status acpi_get_register(u32 register_id, u32 * return_value, u32 flags)
@@ -268,7 +270,7 @@ acpi_status acpi_get_register(u32 register_id, u32 * return_value, u32 flags)
struct acpi_bit_register_info *bit_reg_info;
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_get_register");
+ ACPI_FUNCTION_TRACE(acpi_get_register);
/* Get the info structure corresponding to the requested ACPI Register */
@@ -277,24 +279,14 @@ acpi_status acpi_get_register(u32 register_id, u32 * return_value, u32 flags)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- if (flags & ACPI_MTX_LOCK) {
- status = acpi_ut_acquire_mutex(ACPI_MTX_HARDWARE);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- }
-
/* Read from the register */
- status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
+ status = acpi_hw_register_read(ACPI_MTX_LOCK,
bit_reg_info->parent_register,
&register_value);
- if (flags & ACPI_MTX_LOCK) {
- (void)acpi_ut_release_mutex(ACPI_MTX_HARDWARE);
- }
-
if (ACPI_SUCCESS(status)) {
+
/* Normalize the value that was read */
register_value =
@@ -311,7 +303,7 @@ acpi_status acpi_get_register(u32 register_id, u32 * return_value, u32 flags)
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_get_register);
+ACPI_EXPORT_SYMBOL(acpi_get_register)
/*******************************************************************************
*
@@ -326,31 +318,28 @@ EXPORT_SYMBOL(acpi_get_register);
*
* DESCRIPTION: ACPI Bit Register write function.
*
+ * NOTE: TBD: Flags parameter is obsolete, to be removed
+ *
******************************************************************************/
-
acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags)
{
u32 register_value = 0;
struct acpi_bit_register_info *bit_reg_info;
acpi_status status;
+ acpi_cpu_flags lock_flags;
- ACPI_FUNCTION_TRACE_U32("acpi_set_register", register_id);
+ ACPI_FUNCTION_TRACE_U32(acpi_set_register, register_id);
/* Get the info structure corresponding to the requested ACPI Register */
bit_reg_info = acpi_hw_get_bit_register_info(register_id);
if (!bit_reg_info) {
- ACPI_ERROR((AE_INFO, "Bad ACPI HW register_id: %X",
+ ACPI_ERROR((AE_INFO, "Bad ACPI HW RegisterId: %X",
register_id));
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- if (flags & ACPI_MTX_LOCK) {
- status = acpi_ut_acquire_mutex(ACPI_MTX_HARDWARE);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- }
+ lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
/* Always do a register read first so we can insert the new bits */
@@ -458,9 +447,7 @@ acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags)
unlock_and_exit:
- if (flags & ACPI_MTX_LOCK) {
- (void)acpi_ut_release_mutex(ACPI_MTX_HARDWARE);
- }
+ acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags);
/* Normalize the value that was read */
@@ -474,7 +461,7 @@ acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags)
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_set_register);
+ACPI_EXPORT_SYMBOL(acpi_set_register)
/******************************************************************************
*
@@ -490,21 +477,18 @@ EXPORT_SYMBOL(acpi_set_register);
* given offset.
*
******************************************************************************/
-
acpi_status
acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
{
u32 value1 = 0;
u32 value2 = 0;
acpi_status status;
+ acpi_cpu_flags lock_flags = 0;
- ACPI_FUNCTION_TRACE("hw_register_read");
+ ACPI_FUNCTION_TRACE(hw_register_read);
if (ACPI_MTX_LOCK == use_lock) {
- status = acpi_ut_acquire_mutex(ACPI_MTX_HARDWARE);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
+ lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
}
switch (register_id) {
@@ -582,7 +566,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
unlock_and_exit:
if (ACPI_MTX_LOCK == use_lock) {
- (void)acpi_ut_release_mutex(ACPI_MTX_HARDWARE);
+ acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags);
}
if (ACPI_SUCCESS(status)) {
@@ -610,14 +594,12 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
{
acpi_status status;
+ acpi_cpu_flags lock_flags = 0;
- ACPI_FUNCTION_TRACE("hw_register_write");
+ ACPI_FUNCTION_TRACE(hw_register_write);
if (ACPI_MTX_LOCK == use_lock) {
- status = acpi_ut_acquire_mutex(ACPI_MTX_HARDWARE);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
+ lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
}
switch (register_id) {
@@ -707,7 +689,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
unlock_and_exit:
if (ACPI_MTX_LOCK == use_lock) {
- (void)acpi_ut_release_mutex(ACPI_MTX_HARDWARE);
+ acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags);
}
return_ACPI_STATUS(status);
@@ -733,7 +715,7 @@ acpi_hw_low_level_read(u32 width, u32 * value, struct acpi_generic_address *reg)
u64 address;
acpi_status status;
- ACPI_FUNCTION_NAME("hw_low_level_read");
+ ACPI_FUNCTION_NAME(hw_low_level_read);
/*
* Must have a valid pointer to a GAS structure, and
@@ -805,7 +787,7 @@ acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address * reg)
u64 address;
acpi_status status;
- ACPI_FUNCTION_NAME("hw_low_level_write");
+ ACPI_FUNCTION_NAME(hw_low_level_write);
/*
* Must have a valid pointer to a GAS structure, and
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
index 8926927..8bb43ca 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -42,7 +42,6 @@
* POSSIBILITY OF SUCH DAMAGES.
*/
-#include <linux/module.h>
#include <acpi/acpi.h>
#define _COMPONENT ACPI_HARDWARE
@@ -64,7 +63,7 @@ acpi_status
acpi_set_firmware_waking_vector(acpi_physical_address physical_address)
{
- ACPI_FUNCTION_TRACE("acpi_set_firmware_waking_vector");
+ ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector);
/* Set the vector */
@@ -79,6 +78,8 @@ acpi_set_firmware_waking_vector(acpi_physical_address physical_address)
return_ACPI_STATUS(AE_OK);
}
+ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector)
+
/*******************************************************************************
*
* FUNCTION: acpi_get_firmware_waking_vector
@@ -92,13 +93,12 @@ acpi_set_firmware_waking_vector(acpi_physical_address physical_address)
* DESCRIPTION: Access function for the firmware_waking_vector field in FACS
*
******************************************************************************/
-
#ifdef ACPI_FUTURE_USAGE
acpi_status
acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
{
- ACPI_FUNCTION_TRACE("acpi_get_firmware_waking_vector");
+ ACPI_FUNCTION_TRACE(acpi_get_firmware_waking_vector);
if (!physical_address) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -118,6 +118,8 @@ acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
return_ACPI_STATUS(AE_OK);
}
+
+ACPI_EXPORT_SYMBOL(acpi_get_firmware_waking_vector)
#endif
/*******************************************************************************
@@ -134,14 +136,13 @@ acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
* various OS-specific tasks between the two steps.
*
******************************************************************************/
-
acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
{
acpi_status status;
struct acpi_object_list arg_list;
union acpi_object arg;
- ACPI_FUNCTION_TRACE("acpi_enter_sleep_state_prep");
+ ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_prep);
/*
* _PSW methods could be run here to enable wake-on keyboard, LAN, etc.
@@ -206,6 +207,8 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
return_ACPI_STATUS(AE_OK);
}
+ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep)
+
/*******************************************************************************
*
* FUNCTION: acpi_enter_sleep_state
@@ -218,7 +221,6 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
*
******************************************************************************/
-
acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
{
u32 PM1Acontrol;
@@ -228,7 +230,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
u32 in_value;
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_enter_sleep_state");
+ ACPI_FUNCTION_TRACE(acpi_enter_sleep_state);
if ((acpi_gbl_sleep_type_a > ACPI_SLEEP_TYPE_MAX) ||
(acpi_gbl_sleep_type_b > ACPI_SLEEP_TYPE_MAX)) {
@@ -378,7 +380,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
return_ACPI_STATUS(AE_OK);
}
-EXPORT_SYMBOL(acpi_enter_sleep_state);
+ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state)
/*******************************************************************************
*
@@ -392,13 +394,12 @@ EXPORT_SYMBOL(acpi_enter_sleep_state);
* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
*
******************************************************************************/
-
acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void)
{
u32 in_value;
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_enter_sleep_state_s4bios");
+ ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios);
status =
acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
@@ -443,7 +444,7 @@ acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void)
return_ACPI_STATUS(AE_OK);
}
-EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios);
+ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios)
/*******************************************************************************
*
@@ -457,7 +458,6 @@ EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios);
* Called with interrupts ENABLED.
*
******************************************************************************/
-
acpi_status acpi_leave_sleep_state(u8 sleep_state)
{
struct acpi_object_list arg_list;
@@ -468,7 +468,7 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
u32 PM1Acontrol;
u32 PM1Bcontrol;
- ACPI_FUNCTION_TRACE("acpi_leave_sleep_state");
+ ACPI_FUNCTION_TRACE(acpi_leave_sleep_state);
/*
* Set SLP_TYPE and SLP_EN to state S0.
@@ -490,6 +490,7 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
ACPI_REGISTER_PM1_CONTROL,
&PM1Acontrol);
if (ACPI_SUCCESS(status)) {
+
/* Clear SLP_EN and SLP_TYP fields */
PM1Acontrol &= ~(sleep_type_reg_info->access_bit_mask |
@@ -583,3 +584,5 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
return_ACPI_STATUS(status);
}
+
+ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state)
diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c
index fc10b7c..c4ec47c 100644
--- a/drivers/acpi/hardware/hwtimer.c
+++ b/drivers/acpi/hardware/hwtimer.c
@@ -42,7 +42,6 @@
* POSSIBILITY OF SUCH DAMAGES.
*/
-#include <linux/module.h>
#include <acpi/acpi.h>
#define _COMPONENT ACPI_HARDWARE
@@ -61,13 +60,13 @@ ACPI_MODULE_NAME("hwtimer")
******************************************************************************/
acpi_status acpi_get_timer_resolution(u32 * resolution)
{
- ACPI_FUNCTION_TRACE("acpi_get_timer_resolution");
+ ACPI_FUNCTION_TRACE(acpi_get_timer_resolution);
if (!resolution) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- if (0 == acpi_gbl_FADT->tmr_val_ext) {
+ if (acpi_gbl_FADT->tmr_val_ext == 0) {
*resolution = 24;
} else {
*resolution = 32;
@@ -76,6 +75,8 @@ acpi_status acpi_get_timer_resolution(u32 * resolution)
return_ACPI_STATUS(AE_OK);
}
+ACPI_EXPORT_SYMBOL(acpi_get_timer_resolution)
+
/******************************************************************************
*
* FUNCTION: acpi_get_timer
@@ -87,12 +88,11 @@ acpi_status acpi_get_timer_resolution(u32 * resolution)
* DESCRIPTION: Obtains current value of ACPI PM Timer (in ticks).
*
******************************************************************************/
-
acpi_status acpi_get_timer(u32 * ticks)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_get_timer");
+ ACPI_FUNCTION_TRACE(acpi_get_timer);
if (!ticks) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -103,7 +103,7 @@ acpi_status acpi_get_timer(u32 * ticks)
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_get_timer);
+ACPI_EXPORT_SYMBOL(acpi_get_timer)
/******************************************************************************
*
@@ -133,7 +133,6 @@ EXPORT_SYMBOL(acpi_get_timer);
* 2**32 Ticks / 3,600,000 Ticks/Sec = 1193 sec or 19.88 minutes
*
******************************************************************************/
-
acpi_status
acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed)
{
@@ -141,7 +140,7 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed)
u32 delta_ticks;
acpi_integer quotient;
- ACPI_FUNCTION_TRACE("acpi_get_timer_duration");
+ ACPI_FUNCTION_TRACE(acpi_get_timer_duration);
if (!time_elapsed) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -154,7 +153,8 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed)
if (start_ticks < end_ticks) {
delta_ticks = end_ticks - start_ticks;
} else if (start_ticks > end_ticks) {
- if (0 == acpi_gbl_FADT->tmr_val_ext) {
+ if (acpi_gbl_FADT->tmr_val_ext == 0) {
+
/* 24-bit Timer */
delta_ticks =
@@ -183,4 +183,4 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed)
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_get_timer_duration);
+ACPI_EXPORT_SYMBOL(acpi_get_timer_duration)
diff --git a/drivers/acpi/hotkey.c b/drivers/acpi/hotkey.c
index 2e2e4051..c25b2b9 100644
--- a/drivers/acpi/hotkey.c
+++ b/drivers/acpi/hotkey.c
@@ -723,6 +723,8 @@ get_parms(char *config_record,
goto do_fail;
count = tmp1 - tmp;
*action_handle = (char *)kmalloc(count + 1, GFP_KERNEL);
+ if (!*action_handle)
+ goto do_fail;
strncpy(*action_handle, tmp, count);
*(*action_handle + count) = 0;
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
index 262b1f4..15fc124 100644
--- a/drivers/acpi/ibm_acpi.c
+++ b/drivers/acpi/ibm_acpi.c
@@ -567,6 +567,69 @@ static int bluetooth_write(char *buf)
return 0;
}
+static int wan_supported;
+
+static int wan_init(void)
+{
+ wan_supported = hkey_handle &&
+ acpi_evalf(hkey_handle, NULL, "GWAN", "qv");
+
+ return 0;
+}
+
+static int wan_status(void)
+{
+ int status;
+
+ if (!wan_supported ||
+ !acpi_evalf(hkey_handle, &status, "GWAN", "d"))
+ status = 0;
+
+ return status;
+}
+
+static int wan_read(char *p)
+{
+ int len = 0;
+ int status = wan_status();
+
+ if (!wan_supported)
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ else if (!(status & 1))
+ len += sprintf(p + len, "status:\t\tnot installed\n");
+ else {
+ len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 1));
+ len += sprintf(p + len, "commands:\tenable, disable\n");
+ }
+
+ return len;
+}
+
+static int wan_write(char *buf)
+{
+ int status = wan_status();
+ char *cmd;
+ int do_cmd = 0;
+
+ if (!wan_supported)
+ return -ENODEV;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (strlencmp(cmd, "enable") == 0) {
+ status |= 2;
+ } else if (strlencmp(cmd, "disable") == 0) {
+ status &= ~2;
+ } else
+ return -EINVAL;
+ do_cmd = 1;
+ }
+
+ if (do_cmd && !acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
+ return -EIO;
+
+ return 0;
+}
+
static int video_supported;
static int video_orig_autosw;
@@ -1563,6 +1626,13 @@ static struct ibm_struct ibms[] = {
.write = bluetooth_write,
},
{
+ .name = "wan",
+ .init = wan_init,
+ .read = wan_read,
+ .write = wan_write,
+ .experimental = 1,
+ },
+ {
.name = "video",
.init = video_init,
.read = video_read,
diff --git a/drivers/acpi/motherboard.c b/drivers/acpi/motherboard.c
index 4682441..d51d68f 100644
--- a/drivers/acpi/motherboard.c
+++ b/drivers/acpi/motherboard.c
@@ -37,7 +37,7 @@ ACPI_MODULE_NAME("acpi_motherboard")
#define ACPI_MB_HID2 "PNP0C02"
/**
* Doesn't care about legacy IO ports, only IO ports beyond 0x1000 are reserved
- * Doesn't care about the failure of 'request_region', since other may reserve
+ * Doesn't care about the failure of 'request_region', since other may reserve
* the io ports as well
*/
#define IS_RESERVED_ADDR(base, len) \
@@ -46,7 +46,7 @@ ACPI_MODULE_NAME("acpi_motherboard")
/*
* Clearing the flag (IORESOURCE_BUSY) allows drivers to use
* the io ports if they really know they can use it, while
- * still preventing hotplug PCI devices from using it.
+ * still preventing hotplug PCI devices from using it.
*/
static acpi_status acpi_reserve_io_ranges(struct acpi_resource *res, void *data)
{
@@ -123,49 +123,54 @@ static struct acpi_driver acpi_motherboard_driver2 = {
},
};
+static void __init acpi_request_region (struct acpi_generic_address *addr,
+ unsigned int length, char *desc)
+{
+ if (!addr->address || !length)
+ return;
+
+ if (addr->address_space_id == ACPI_ADR_SPACE_SYSTEM_IO)
+ request_region(addr->address, length, desc);
+ else if (addr->address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
+ request_mem_region(addr->address, length, desc);
+}
+
static void __init acpi_reserve_resources(void)
{
- if (acpi_gbl_FADT->xpm1a_evt_blk.address && acpi_gbl_FADT->pm1_evt_len)
- request_region(acpi_gbl_FADT->xpm1a_evt_blk.address,
- acpi_gbl_FADT->pm1_evt_len, "PM1a_EVT_BLK");
+ acpi_request_region(&acpi_gbl_FADT->xpm1a_evt_blk,
+ acpi_gbl_FADT->pm1_evt_len, "ACPI PM1a_EVT_BLK");
- if (acpi_gbl_FADT->xpm1b_evt_blk.address && acpi_gbl_FADT->pm1_evt_len)
- request_region(acpi_gbl_FADT->xpm1b_evt_blk.address,
- acpi_gbl_FADT->pm1_evt_len, "PM1b_EVT_BLK");
+ acpi_request_region(&acpi_gbl_FADT->xpm1b_evt_blk,
+ acpi_gbl_FADT->pm1_evt_len, "ACPI PM1b_EVT_BLK");
- if (acpi_gbl_FADT->xpm1a_cnt_blk.address && acpi_gbl_FADT->pm1_cnt_len)
- request_region(acpi_gbl_FADT->xpm1a_cnt_blk.address,
- acpi_gbl_FADT->pm1_cnt_len, "PM1a_CNT_BLK");
+ acpi_request_region(&acpi_gbl_FADT->xpm1a_cnt_blk,
+ acpi_gbl_FADT->pm1_cnt_len, "ACPI PM1a_CNT_BLK");
- if (acpi_gbl_FADT->xpm1b_cnt_blk.address && acpi_gbl_FADT->pm1_cnt_len)
- request_region(acpi_gbl_FADT->xpm1b_cnt_blk.address,
- acpi_gbl_FADT->pm1_cnt_len, "PM1b_CNT_BLK");
+ acpi_request_region(&acpi_gbl_FADT->xpm1b_cnt_blk,
+ acpi_gbl_FADT->pm1_cnt_len, "ACPI PM1b_CNT_BLK");
- if (acpi_gbl_FADT->xpm_tmr_blk.address && acpi_gbl_FADT->pm_tm_len == 4)
- request_region(acpi_gbl_FADT->xpm_tmr_blk.address, 4, "PM_TMR");
+ if (acpi_gbl_FADT->pm_tm_len == 4)
+ acpi_request_region(&acpi_gbl_FADT->xpm_tmr_blk, 4, "ACPI PM_TMR");
- if (acpi_gbl_FADT->xpm2_cnt_blk.address && acpi_gbl_FADT->pm2_cnt_len)
- request_region(acpi_gbl_FADT->xpm2_cnt_blk.address,
- acpi_gbl_FADT->pm2_cnt_len, "PM2_CNT_BLK");
+ acpi_request_region(&acpi_gbl_FADT->xpm2_cnt_blk,
+ acpi_gbl_FADT->pm2_cnt_len, "ACPI PM2_CNT_BLK");
/* Length of GPE blocks must be a non-negative multiple of 2 */
- if (acpi_gbl_FADT->xgpe0_blk.address && acpi_gbl_FADT->gpe0_blk_len &&
- !(acpi_gbl_FADT->gpe0_blk_len & 0x1))
- request_region(acpi_gbl_FADT->xgpe0_blk.address,
- acpi_gbl_FADT->gpe0_blk_len, "GPE0_BLK");
+ if (!(acpi_gbl_FADT->gpe0_blk_len & 0x1))
+ acpi_request_region(&acpi_gbl_FADT->xgpe0_blk,
+ acpi_gbl_FADT->gpe0_blk_len, "ACPI GPE0_BLK");
- if (acpi_gbl_FADT->xgpe1_blk.address && acpi_gbl_FADT->gpe1_blk_len &&
- !(acpi_gbl_FADT->gpe1_blk_len & 0x1))
- request_region(acpi_gbl_FADT->xgpe1_blk.address,
- acpi_gbl_FADT->gpe1_blk_len, "GPE1_BLK");
+ if (!(acpi_gbl_FADT->gpe1_blk_len & 0x1))
+ acpi_request_region(&acpi_gbl_FADT->xgpe1_blk,
+ acpi_gbl_FADT->gpe1_blk_len, "ACPI GPE1_BLK");
}
static int __init acpi_motherboard_init(void)
{
acpi_bus_register_driver(&acpi_motherboard_driver1);
acpi_bus_register_driver(&acpi_motherboard_driver2);
- /*
+ /*
* Guarantee motherboard IO reservation first
* This module must run after scan.c
*/
diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c
index 1149bc1..48fadad 100644
--- a/drivers/acpi/namespace/nsaccess.c
+++ b/drivers/acpi/namespace/nsaccess.c
@@ -70,7 +70,7 @@ acpi_status acpi_ns_root_initialize(void)
union acpi_operand_object *obj_desc;
acpi_string val = NULL;
- ACPI_FUNCTION_TRACE("ns_root_initialize");
+ ACPI_FUNCTION_TRACE(ns_root_initialize);
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
@@ -98,6 +98,7 @@ acpi_status acpi_ns_root_initialize(void)
"Entering predefined entries into namespace\n"));
for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) {
+
/* _OSI is optional for now, will be permanent later */
if (!ACPI_STRCMP(init_val->name, "_OSI")
@@ -156,7 +157,7 @@ acpi_status acpi_ns_root_initialize(void)
#if defined (ACPI_ASL_COMPILER)
- /* save the parameter count for the i_aSL compiler */
+ /* Save the parameter count for the i_aSL compiler */
new_node->value = obj_desc->method.param_count;
#else
@@ -258,10 +259,8 @@ acpi_status acpi_ns_root_initialize(void)
/* Save a handle to "_GPE", it is always present */
if (ACPI_SUCCESS(status)) {
- status =
- acpi_ns_get_node_by_path("\\_GPE", NULL,
- ACPI_NS_NO_UPSEARCH,
- &acpi_gbl_fadt_gpe_device);
+ status = acpi_ns_get_node(NULL, "\\_GPE", ACPI_NS_NO_UPSEARCH,
+ &acpi_gbl_fadt_gpe_device);
}
return_ACPI_STATUS(status);
@@ -310,17 +309,17 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
acpi_object_type type_to_check_for;
acpi_object_type this_search_type;
u32 search_parent_flag = ACPI_NS_SEARCH_PARENT;
- u32 local_flags = flags & ~(ACPI_NS_ERROR_IF_FOUND |
- ACPI_NS_SEARCH_PARENT);
+ u32 local_flags;
- ACPI_FUNCTION_TRACE("ns_lookup");
+ ACPI_FUNCTION_TRACE(ns_lookup);
if (!return_node) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- acpi_gbl_ns_lookup_count++;
+ local_flags = flags & ~(ACPI_NS_ERROR_IF_FOUND | ACPI_NS_SEARCH_PARENT);
*return_node = ACPI_ENTRY_NOT_FOUND;
+ acpi_gbl_ns_lookup_count++;
if (!acpi_gbl_root_node) {
return_ACPI_STATUS(AE_NO_NAMESPACE);
@@ -346,14 +345,17 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
return_ACPI_STATUS(AE_AML_INTERNAL);
}
- /*
- * This node might not be a actual "scope" node (such as a
- * Device/Method, etc.) It could be a Package or other object node.
- * Backup up the tree to find the containing scope node.
- */
- while (!acpi_ns_opens_scope(prefix_node->type) &&
- prefix_node->type != ACPI_TYPE_ANY) {
- prefix_node = acpi_ns_get_parent_node(prefix_node);
+ if (!(flags & ACPI_NS_PREFIX_IS_SCOPE)) {
+ /*
+ * This node might not be a actual "scope" node (such as a
+ * Device/Method, etc.) It could be a Package or other object node.
+ * Backup up the tree to find the containing scope node.
+ */
+ while (!acpi_ns_opens_scope(prefix_node->type) &&
+ prefix_node->type != ACPI_TYPE_ANY) {
+ prefix_node =
+ acpi_ns_get_parent_node(prefix_node);
+ }
}
}
@@ -365,6 +367,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
* Begin examination of the actual pathname
*/
if (!pathname) {
+
/* A Null name_path is allowed and refers to the root */
num_segments = 0;
@@ -389,6 +392,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
* to the current scope).
*/
if (*path == (u8) AML_ROOT_PREFIX) {
+
/* Pathname is fully qualified, start from the root */
this_node = acpi_gbl_root_node;
@@ -416,6 +420,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
this_node = prefix_node;
num_carats = 0;
while (*path == (u8) AML_PARENT_PREFIX) {
+
/* Name is fully qualified, no search rules apply */
search_parent_flag = ACPI_NS_NO_UPSEARCH;
@@ -430,6 +435,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
num_carats++;
this_node = acpi_ns_get_parent_node(this_node);
if (!this_node) {
+
/* Current scope has no parent scope */
ACPI_ERROR((AE_INFO,
@@ -569,6 +575,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
&this_node);
if (ACPI_FAILURE(status)) {
if (status == AE_NOT_FOUND) {
+
/* Name not found in ACPI namespace */
ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
@@ -602,10 +609,11 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
(type_to_check_for != ACPI_TYPE_LOCAL_SCOPE) &&
(this_node->type != ACPI_TYPE_ANY) &&
(this_node->type != type_to_check_for)) {
+
/* Complain about a type mismatch */
ACPI_WARNING((AE_INFO,
- "ns_lookup: Type mismatch on %4.4s (%s), searching for (%s)",
+ "NsLookup: Type mismatch on %4.4s (%s), searching for (%s)",
ACPI_CAST_PTR(char, &simple_name),
acpi_ut_get_type_name(this_node->type),
acpi_ut_get_type_name
diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c
index 9b871f3..dc3f073 100644
--- a/drivers/acpi/namespace/nsalloc.c
+++ b/drivers/acpi/namespace/nsalloc.c
@@ -47,9 +47,6 @@
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsalloc")
-/* Local prototypes */
-static void acpi_ns_remove_reference(struct acpi_namespace_node *node);
-
/*******************************************************************************
*
* FUNCTION: acpi_ns_create_node
@@ -61,14 +58,13 @@ static void acpi_ns_remove_reference(struct acpi_namespace_node *node);
* DESCRIPTION: Create a namespace node
*
******************************************************************************/
-
struct acpi_namespace_node *acpi_ns_create_node(u32 name)
{
struct acpi_namespace_node *node;
- ACPI_FUNCTION_TRACE("ns_create_node");
+ ACPI_FUNCTION_TRACE(ns_create_node);
- node = ACPI_MEM_CALLOCATE(sizeof(struct acpi_namespace_node));
+ node = acpi_os_acquire_object(acpi_gbl_namespace_cache);
if (!node) {
return_PTR(NULL);
}
@@ -76,9 +72,7 @@ struct acpi_namespace_node *acpi_ns_create_node(u32 name)
ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_allocated++);
node->name.integer = name;
- node->reference_count = 1;
ACPI_SET_DESCRIPTOR_TYPE(node, ACPI_DESC_TYPE_NAMED);
-
return_PTR(node);
}
@@ -100,7 +94,7 @@ void acpi_ns_delete_node(struct acpi_namespace_node *node)
struct acpi_namespace_node *prev_node;
struct acpi_namespace_node *next_node;
- ACPI_FUNCTION_TRACE_PTR("ns_delete_node", node);
+ ACPI_FUNCTION_TRACE_PTR(ns_delete_node, node);
parent_node = acpi_ns_get_parent_node(node);
@@ -115,6 +109,7 @@ void acpi_ns_delete_node(struct acpi_namespace_node *node)
}
if (prev_node) {
+
/* Node is not first child, unlink it */
prev_node->peer = next_node->peer;
@@ -125,6 +120,7 @@ void acpi_ns_delete_node(struct acpi_namespace_node *node)
/* Node is first child (has no previous peer) */
if (next_node->flags & ANOBJ_END_OF_PEER_LIST) {
+
/* No peers at all */
parent_node->child = NULL;
@@ -137,10 +133,10 @@ void acpi_ns_delete_node(struct acpi_namespace_node *node)
ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++);
/*
- * Detach an object if there is one then delete the node
+ * Detach an object if there is one, then delete the node
*/
acpi_ns_detach_object(node);
- ACPI_MEM_FREE(node);
+ (void)acpi_os_release_object(acpi_gbl_namespace_cache, node);
return_VOID;
}
@@ -171,7 +167,7 @@ void acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namesp
acpi_owner_id owner_id = 0;
struct acpi_namespace_node *child_node;
- ACPI_FUNCTION_TRACE("ns_install_node");
+ ACPI_FUNCTION_TRACE(ns_install_node);
/*
* Get the owner ID from the Walk state
@@ -216,14 +212,6 @@ void acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namesp
acpi_ut_get_type_name(parent_node->type),
parent_node));
- /*
- * Increment the reference count(s) of all parents up to
- * the root!
- */
- while ((node = acpi_ns_get_parent_node(node)) != NULL) {
- node->reference_count++;
- }
-
return_VOID;
}
@@ -244,10 +232,9 @@ void acpi_ns_delete_children(struct acpi_namespace_node *parent_node)
{
struct acpi_namespace_node *child_node;
struct acpi_namespace_node *next_node;
- struct acpi_namespace_node *node;
u8 flags;
- ACPI_FUNCTION_TRACE_PTR("ns_delete_children", parent_node);
+ ACPI_FUNCTION_TRACE_PTR(ns_delete_children, parent_node);
if (!parent_node) {
return_VOID;
@@ -264,6 +251,7 @@ void acpi_ns_delete_children(struct acpi_namespace_node *parent_node)
* Deallocate all children at this level
*/
do {
+
/* Get the things we need */
next_node = child_node->peer;
@@ -289,26 +277,10 @@ void acpi_ns_delete_children(struct acpi_namespace_node *parent_node)
*/
acpi_ns_detach_object(child_node);
- /*
- * Decrement the reference count(s) of all parents up to
- * the root! (counts were incremented when the node was created)
- */
- node = child_node;
- while ((node = acpi_ns_get_parent_node(node)) != NULL) {
- node->reference_count--;
- }
-
- /* There should be only one reference remaining on this node */
-
- if (child_node->reference_count != 1) {
- ACPI_WARNING((AE_INFO,
- "Existing references (%d) on node being deleted (%p)",
- child_node->reference_count, child_node));
- }
-
/* Now we can delete the node */
- ACPI_MEM_FREE(child_node);
+ (void)acpi_os_release_object(acpi_gbl_namespace_cache,
+ child_node);
/* And move on to the next child in the list */
@@ -341,7 +313,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node)
struct acpi_namespace_node *child_node = NULL;
u32 level = 1;
- ACPI_FUNCTION_TRACE("ns_delete_namespace_subtree");
+ ACPI_FUNCTION_TRACE(ns_delete_namespace_subtree);
if (!parent_node) {
return_VOID;
@@ -352,11 +324,14 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node)
* to where we started.
*/
while (level > 0) {
+
/* Get the next node in this scope (NULL if none) */
- child_node = acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node,
- child_node);
+ child_node =
+ acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node,
+ child_node);
if (child_node) {
+
/* Found a child node - detach any attached object */
acpi_ns_detach_object(child_node);
@@ -401,55 +376,6 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node)
/*******************************************************************************
*
- * FUNCTION: acpi_ns_remove_reference
- *
- * PARAMETERS: Node - Named node whose reference count is to be
- * decremented
- *
- * RETURN: None.
- *
- * DESCRIPTION: Remove a Node reference. Decrements the reference count
- * of all parent Nodes up to the root. Any node along
- * the way that reaches zero references is freed.
- *
- ******************************************************************************/
-
-static void acpi_ns_remove_reference(struct acpi_namespace_node *node)
-{
- struct acpi_namespace_node *parent_node;
- struct acpi_namespace_node *this_node;
-
- ACPI_FUNCTION_ENTRY();
-
- /*
- * Decrement the reference count(s) of this node and all
- * nodes up to the root, Delete anything with zero remaining references.
- */
- this_node = node;
- while (this_node) {
- /* Prepare to move up to parent */
-
- parent_node = acpi_ns_get_parent_node(this_node);
-
- /* Decrement the reference count on this node */
-
- this_node->reference_count--;
-
- /* Delete the node if no more references */
-
- if (!this_node->reference_count) {
- /* Delete all children and delete the node */
-
- acpi_ns_delete_children(this_node);
- acpi_ns_delete_node(this_node);
- }
-
- this_node = parent_node;
- }
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ns_delete_namespace_by_owner
*
* PARAMETERS: owner_id - All nodes with this owner will be deleted
@@ -469,15 +395,15 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id)
u32 level;
struct acpi_namespace_node *parent_node;
- ACPI_FUNCTION_TRACE_U32("ns_delete_namespace_by_owner", owner_id);
+ ACPI_FUNCTION_TRACE_U32(ns_delete_namespace_by_owner, owner_id);
if (owner_id == 0) {
return_VOID;
}
+ deletion_node = NULL;
parent_node = acpi_gbl_root_node;
child_node = NULL;
- deletion_node = NULL;
level = 1;
/*
@@ -494,12 +420,14 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id)
child_node);
if (deletion_node) {
- acpi_ns_remove_reference(deletion_node);
+ acpi_ns_delete_children(deletion_node);
+ acpi_ns_delete_node(deletion_node);
deletion_node = NULL;
}
if (child_node) {
if (child_node->owner_id == owner_id) {
+
/* Found a matching child node - detach any attached object */
acpi_ns_detach_object(child_node);
diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c
index a280731..d72df66 100644
--- a/drivers/acpi/namespace/nsdump.c
+++ b/drivers/acpi/namespace/nsdump.c
@@ -75,7 +75,7 @@ void acpi_ns_print_pathname(u32 num_segments, char *pathname)
{
acpi_native_uint i;
- ACPI_FUNCTION_NAME("ns_print_pathname");
+ ACPI_FUNCTION_NAME(ns_print_pathname);
if (!(acpi_dbg_level & ACPI_LV_NAMES)
|| !(acpi_dbg_layer & ACPI_NAMESPACE)) {
@@ -123,7 +123,7 @@ void
acpi_ns_dump_pathname(acpi_handle handle, char *msg, u32 level, u32 component)
{
- ACPI_FUNCTION_TRACE("ns_dump_pathname");
+ ACPI_FUNCTION_TRACE(ns_dump_pathname);
/* Do this only if the requested debug level and component are enabled */
@@ -167,7 +167,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
u32 dbg_level;
u32 i;
- ACPI_FUNCTION_NAME("ns_dump_one_object");
+ ACPI_FUNCTION_NAME(ns_dump_one_object);
/* Is output enabled? */
@@ -191,6 +191,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
}
if (!(info->display_type & ACPI_DISPLAY_SHORT)) {
+
/* Indent the object according to the level */
acpi_os_printf("%2d%*s", (u32) level - 1, (int)level * 2, " ");
@@ -203,6 +204,9 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
}
if (!acpi_ut_valid_acpi_name(this_node->name.integer)) {
+ this_node->name.integer =
+ acpi_ut_repair_name(this_node->name.integer);
+
ACPI_WARNING((AE_INFO, "Invalid ACPI Name %08X",
this_node->name.integer));
}
@@ -226,6 +230,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
case ACPI_DISPLAY_SUMMARY:
if (!obj_desc) {
+
/* No attached object, we are done */
acpi_os_printf("\n");
@@ -419,6 +424,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
acpi_os_printf("O:%p", obj_desc);
if (!obj_desc) {
+
/* No attached object, we are done */
acpi_os_printf("\n");
@@ -669,7 +675,7 @@ void acpi_ns_dump_tables(acpi_handle search_base, u32 max_depth)
{
acpi_handle search_handle = search_base;
- ACPI_FUNCTION_TRACE("ns_dump_tables");
+ ACPI_FUNCTION_TRACE(ns_dump_tables);
if (!acpi_gbl_root_node) {
/*
@@ -682,6 +688,7 @@ void acpi_ns_dump_tables(acpi_handle search_base, u32 max_depth)
}
if (ACPI_NS_ALL == search_base) {
+
/* Entire namespace */
search_handle = acpi_gbl_root_node;
diff --git a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c
index aff899a..c6bf5d3 100644
--- a/drivers/acpi/namespace/nsdumpdv.c
+++ b/drivers/acpi/namespace/nsdumpdv.c
@@ -74,7 +74,7 @@ acpi_ns_dump_one_device(acpi_handle obj_handle,
acpi_status status;
u32 i;
- ACPI_FUNCTION_NAME("ns_dump_one_device");
+ ACPI_FUNCTION_NAME(ns_dump_one_device);
status =
acpi_ns_dump_one_object(obj_handle, level, context, return_value);
@@ -92,7 +92,7 @@ acpi_ns_dump_one_device(acpi_handle obj_handle,
info->hardware_id.value,
ACPI_FORMAT_UINT64(info->address),
info->current_status));
- ACPI_MEM_FREE(info);
+ ACPI_FREE(info);
}
return (status);
@@ -115,7 +115,7 @@ void acpi_ns_dump_root_devices(void)
acpi_handle sys_bus_handle;
acpi_status status;
- ACPI_FUNCTION_NAME("ns_dump_root_devices");
+ ACPI_FUNCTION_NAME(ns_dump_root_devices);
/* Only dump the table if tracing is enabled */
diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c
index 19d7b94..4b0a4a8 100644
--- a/drivers/acpi/namespace/nseval.c
+++ b/drivers/acpi/namespace/nseval.c
@@ -1,7 +1,6 @@
/*******************************************************************************
*
- * Module Name: nseval - Object evaluation interfaces -- includes control
- * method lookup and execution.
+ * Module Name: nseval - Object evaluation, includes control method execution
*
******************************************************************************/
@@ -50,196 +49,14 @@
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nseval")
-/* Local prototypes */
-static acpi_status
-acpi_ns_execute_control_method(struct acpi_parameter_info *info);
-
-static acpi_status acpi_ns_get_object_value(struct acpi_parameter_info *info);
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_evaluate_relative
- *
- * PARAMETERS: Pathname - Name of method to execute, If NULL, the
- * handle is the object to execute
- * Info - Method info block, contains:
- * return_object - Where to put method's return value (if
- * any). If NULL, no value is returned.
- * Params - List of parameters to pass to the method,
- * terminated by NULL. Params itself may be
- * NULL if no parameters are being passed.
- *
- * RETURN: Status
- *
- * DESCRIPTION: Evaluate the object or find and execute the requested method
- *
- * MUTEX: Locks Namespace
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ns_evaluate_relative(char *pathname, struct acpi_parameter_info *info)
-{
- acpi_status status;
- struct acpi_namespace_node *node = NULL;
- union acpi_generic_state *scope_info;
- char *internal_path = NULL;
-
- ACPI_FUNCTION_TRACE("ns_evaluate_relative");
-
- /*
- * Must have a valid object handle
- */
- if (!info || !info->node) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Build an internal name string for the method */
-
- status = acpi_ns_internalize_name(pathname, &internal_path);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- scope_info = acpi_ut_create_generic_state();
- if (!scope_info) {
- goto cleanup1;
- }
-
- /* Get the prefix handle and Node */
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
- info->node = acpi_ns_map_handle_to_node(info->node);
- if (!info->node) {
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- status = AE_BAD_PARAMETER;
- goto cleanup;
- }
-
- /* Lookup the name in the namespace */
-
- scope_info->scope.node = info->node;
- status = acpi_ns_lookup(scope_info, internal_path, ACPI_TYPE_ANY,
- ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL,
- &node);
-
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
-
- if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Object [%s] not found [%s]\n",
- pathname, acpi_format_exception(status)));
- goto cleanup;
- }
-
- /*
- * Now that we have a handle to the object, we can attempt to evaluate it.
- */
- ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "%s [%p] Value %p\n",
- pathname, node, acpi_ns_get_attached_object(node)));
-
- info->node = node;
- status = acpi_ns_evaluate_by_handle(info);
-
- ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
- "*** Completed eval of object %s ***\n", pathname));
-
- cleanup:
- acpi_ut_delete_generic_state(scope_info);
-
- cleanup1:
- ACPI_MEM_FREE(internal_path);
- return_ACPI_STATUS(status);
-}
-
/*******************************************************************************
*
- * FUNCTION: acpi_ns_evaluate_by_name
+ * FUNCTION: acpi_ns_evaluate
*
- * PARAMETERS: Pathname - Fully qualified pathname to the object
- * Info - Method info block, contains:
- * return_object - Where to put method's return value (if
- * any). If NULL, no value is returned.
- * Params - List of parameters to pass to the method,
- * terminated by NULL. Params itself may be
- * NULL if no parameters are being passed.
- *
- * RETURN: Status
- *
- * DESCRIPTION: Evaluate the object or rind and execute the requested method
- * passing the given parameters
- *
- * MUTEX: Locks Namespace
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ns_evaluate_by_name(char *pathname, struct acpi_parameter_info *info)
-{
- acpi_status status;
- char *internal_path = NULL;
-
- ACPI_FUNCTION_TRACE("ns_evaluate_by_name");
-
- /* Build an internal name string for the method */
-
- status = acpi_ns_internalize_name(pathname, &internal_path);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
- /* Lookup the name in the namespace */
-
- status = acpi_ns_lookup(NULL, internal_path, ACPI_TYPE_ANY,
- ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL,
- &info->node);
-
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
-
- if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
- "Object at [%s] was not found, status=%.4X\n",
- pathname, status));
- goto cleanup;
- }
-
- /*
- * Now that we have a handle to the object, we can attempt to evaluate it.
- */
- ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "%s [%p] Value %p\n",
- pathname, info->node,
- acpi_ns_get_attached_object(info->node)));
-
- status = acpi_ns_evaluate_by_handle(info);
-
- ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
- "*** Completed eval of object %s ***\n", pathname));
-
- cleanup:
-
- /* Cleanup */
-
- if (internal_path) {
- ACPI_MEM_FREE(internal_path);
- }
-
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_evaluate_by_handle
- *
- * PARAMETERS: Info - Method info block, contains:
- * Node - Method/Object Node to execute
+ * PARAMETERS: Info - Evaluation info block, contains:
+ * prefix_node - Prefix or Method/Object Node to execute
+ * Pathname - Name of method to execute, If NULL, the
+ * Node is the object to execute
* Parameters - List of parameters to pass to the method,
* terminated by NULL. Params itself may be
* NULL if no parameters are being passed.
@@ -248,29 +65,21 @@ acpi_ns_evaluate_by_name(char *pathname, struct acpi_parameter_info *info)
* parameter_type - Type of Parameter list
* return_object - Where to put method's return value (if
* any). If NULL, no value is returned.
+ * Flags - ACPI_IGNORE_RETURN_VALUE to delete return
*
* RETURN: Status
*
- * DESCRIPTION: Evaluate object or execute the requested method passing the
- * given parameters
+ * DESCRIPTION: Execute a control method or return the current value of an
+ * ACPI namespace object.
*
- * MUTEX: Locks Namespace
+ * MUTEX: Locks interpreter
*
******************************************************************************/
-
-acpi_status acpi_ns_evaluate_by_handle(struct acpi_parameter_info *info)
+acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ns_evaluate_by_handle");
-
- /* Check if namespace has been initialized */
-
- if (!acpi_gbl_root_node) {
- return_ACPI_STATUS(AE_NO_NAMESPACE);
- }
-
- /* Parameter Validation */
+ ACPI_FUNCTION_TRACE(ns_evaluate);
if (!info) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -280,202 +89,120 @@ acpi_status acpi_ns_evaluate_by_handle(struct acpi_parameter_info *info)
info->return_object = NULL;
- /* Get the prefix handle and Node */
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ /*
+ * Get the actual namespace node for the target object. Handles these cases:
+ *
+ * 1) Null node, Pathname (absolute path)
+ * 2) Node, Pathname (path relative to Node)
+ * 3) Node, Null Pathname
+ */
+ status = acpi_ns_get_node(info->prefix_node, info->pathname,
+ ACPI_NS_NO_UPSEARCH, &info->resolved_node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
- info->node = acpi_ns_map_handle_to_node(info->node);
- if (!info->node) {
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
/*
* For a method alias, we must grab the actual method node so that proper
* scoping context will be established before execution.
*/
- if (acpi_ns_get_type(info->node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) {
- info->node =
+ if (acpi_ns_get_type(info->resolved_node) ==
+ ACPI_TYPE_LOCAL_METHOD_ALIAS) {
+ info->resolved_node =
ACPI_CAST_PTR(struct acpi_namespace_node,
- info->node->object);
+ info->resolved_node->object);
}
+ ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "%s [%p] Value %p\n", info->pathname,
+ info->resolved_node,
+ acpi_ns_get_attached_object(info->resolved_node)));
+
/*
* Two major cases here:
- * 1) The object is an actual control method -- execute it.
- * 2) The object is not a method -- just return it's current value
*
- * In both cases, the namespace is unlocked by the acpi_ns* procedure
+ * 1) The object is a control method -- execute it
+ * 2) The object is not a method -- just return it's current value
*/
- if (acpi_ns_get_type(info->node) == ACPI_TYPE_METHOD) {
- /*
- * Case 1) We have an actual control method to execute
- */
- status = acpi_ns_execute_control_method(info);
- } else {
+ if (acpi_ns_get_type(info->resolved_node) == ACPI_TYPE_METHOD) {
/*
- * Case 2) Object is NOT a method, just return its current value
+ * 1) Object is a control method - execute it
*/
- status = acpi_ns_get_object_value(info);
- }
-
- /*
- * Check if there is a return value on the stack that must be dealt with
- */
- if (status == AE_CTRL_RETURN_VALUE) {
- /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */
-
- status = AE_OK;
- }
-
- /*
- * Namespace was unlocked by the handling acpi_ns* function, so we
- * just return
- */
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_execute_control_method
- *
- * PARAMETERS: Info - Method info block, contains:
- * Node - Method Node to execute
- * obj_desc - Method object
- * Parameters - List of parameters to pass to the method,
- * terminated by NULL. Params itself may be
- * NULL if no parameters are being passed.
- * return_object - Where to put method's return value (if
- * any). If NULL, no value is returned.
- * parameter_type - Type of Parameter list
- * return_object - Where to put method's return value (if
- * any). If NULL, no value is returned.
- *
- * RETURN: Status
- *
- * DESCRIPTION: Execute the requested method passing the given parameters
- *
- * MUTEX: Assumes namespace is locked
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ns_execute_control_method(struct acpi_parameter_info *info)
-{
- acpi_status status;
-
- ACPI_FUNCTION_TRACE("ns_execute_control_method");
-
- /* Verify that there is a method associated with this object */
-
- info->obj_desc = acpi_ns_get_attached_object(info->node);
- if (!info->obj_desc) {
- ACPI_ERROR((AE_INFO, "No attached method object"));
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- return_ACPI_STATUS(AE_NULL_OBJECT);
- }
-
- ACPI_DUMP_PATHNAME(info->node, "Execute Method:",
- ACPI_LV_INFO, _COMPONENT);
-
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Method at AML address %p Length %X\n",
- info->obj_desc->method.aml_start + 1,
- info->obj_desc->method.aml_length - 1));
-
- /*
- * Unlock the namespace before execution. This allows namespace access
- * via the external Acpi* interfaces while a method is being executed.
- * However, any namespace deletion must acquire both the namespace and
- * interpreter locks to ensure that no thread is using the portion of the
- * namespace that is being deleted.
- */
- status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
+ /* Verify that there is a method object associated with this node */
- /*
- * Execute the method via the interpreter. The interpreter is locked
- * here before calling into the AML parser
- */
- status = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
+ info->obj_desc =
+ acpi_ns_get_attached_object(info->resolved_node);
+ if (!info->obj_desc) {
+ ACPI_ERROR((AE_INFO,
+ "Control method has no attached sub-object"));
+ return_ACPI_STATUS(AE_NULL_OBJECT);
+ }
- status = acpi_ps_execute_method(info);
- acpi_ex_exit_interpreter();
+ ACPI_DUMP_PATHNAME(info->resolved_node, "Execute Method:",
+ ACPI_LV_INFO, _COMPONENT);
- return_ACPI_STATUS(status);
-}
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Method at AML address %p Length %X\n",
+ info->obj_desc->method.aml_start + 1,
+ info->obj_desc->method.aml_length - 1));
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_get_object_value
- *
- * PARAMETERS: Info - Method info block, contains:
- * Node - Object's NS node
- * return_object - Where to put object value (if
- * any). If NULL, no value is returned.
- *
- * RETURN: Status
- *
- * DESCRIPTION: Return the current value of the object
- *
- * MUTEX: Assumes namespace is locked, leaves namespace unlocked
- *
- ******************************************************************************/
+ /*
+ * Any namespace deletion must acquire both the namespace and
+ * interpreter locks to ensure that no thread is using the portion of
+ * the namespace that is being deleted.
+ *
+ * Execute the method via the interpreter. The interpreter is locked
+ * here before calling into the AML parser
+ */
+ status = acpi_ex_enter_interpreter();
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
-static acpi_status acpi_ns_get_object_value(struct acpi_parameter_info *info)
-{
- acpi_status status = AE_OK;
- struct acpi_namespace_node *resolved_node = info->node;
+ status = acpi_ps_execute_method(info);
+ acpi_ex_exit_interpreter();
+ } else {
+ /*
+ * 2) Object is not a method, return its current value
+ */
- ACPI_FUNCTION_TRACE("ns_get_object_value");
+ /*
+ * Objects require additional resolution steps (e.g., the Node may be
+ * a field that must be read, etc.) -- we can't just grab the object
+ * out of the node.
+ *
+ * Use resolve_node_to_value() to get the associated value.
+ *
+ * NOTE: we can get away with passing in NULL for a walk state because
+ * resolved_node is guaranteed to not be a reference to either a method
+ * local or a method argument (because this interface is never called
+ * from a running method.)
+ *
+ * Even though we do not directly invoke the interpreter for object
+ * resolution, we must lock it because we could access an opregion.
+ * The opregion access code assumes that the interpreter is locked.
+ */
+ status = acpi_ex_enter_interpreter();
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
- /*
- * Objects require additional resolution steps (e.g., the Node may be a
- * field that must be read, etc.) -- we can't just grab the object out of
- * the node.
- */
+ /* Function has a strange interface */
- /*
- * Use resolve_node_to_value() to get the associated value. This call always
- * deletes obj_desc (allocated above).
- *
- * NOTE: we can get away with passing in NULL for a walk state because
- * obj_desc is guaranteed to not be a reference to either a method local or
- * a method argument (because this interface can only be called from the
- * acpi_evaluate external interface, never called from a running method.)
- *
- * Even though we do not directly invoke the interpreter for this, we must
- * enter it because we could access an opregion. The opregion access code
- * assumes that the interpreter is locked.
- *
- * We must release the namespace lock before entering the intepreter.
- */
- status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
+ status =
+ acpi_ex_resolve_node_to_value(&info->resolved_node, NULL);
+ acpi_ex_exit_interpreter();
- status = acpi_ex_enter_interpreter();
- if (ACPI_SUCCESS(status)) {
- status = acpi_ex_resolve_node_to_value(&resolved_node, NULL);
/*
* If acpi_ex_resolve_node_to_value() succeeded, the return value was placed
* in resolved_node.
*/
- acpi_ex_exit_interpreter();
-
if (ACPI_SUCCESS(status)) {
status = AE_CTRL_RETURN_VALUE;
- info->return_object = ACPI_CAST_PTR
- (union acpi_operand_object, resolved_node);
+ info->return_object =
+ ACPI_CAST_PTR(union acpi_operand_object,
+ info->resolved_node);
+
ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
"Returning object %p [%s]\n",
info->return_object,
@@ -484,7 +211,30 @@ static acpi_status acpi_ns_get_object_value(struct acpi_parameter_info *info)
}
}
- /* Namespace is unlocked */
+ /*
+ * Check if there is a return value that must be dealt with
+ */
+ if (status == AE_CTRL_RETURN_VALUE) {
+
+ /* If caller does not want the return value, delete it */
+ if (info->flags & ACPI_IGNORE_RETURN_VALUE) {
+ acpi_ut_remove_reference(info->return_object);
+ info->return_object = NULL;
+ }
+
+ /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */
+
+ status = AE_OK;
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
+ "*** Completed evaluation of object %s ***\n",
+ info->pathname));
+
+ /*
+ * Namespace was unlocked by the handling acpi_ns* function, so we
+ * just return
+ */
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c
index 9f929e4..aec8488 100644
--- a/drivers/acpi/namespace/nsinit.c
+++ b/drivers/acpi/namespace/nsinit.c
@@ -58,6 +58,10 @@ static acpi_status
acpi_ns_init_one_device(acpi_handle obj_handle,
u32 nesting_level, void *context, void **return_value);
+static acpi_status
+acpi_ns_find_ini_methods(acpi_handle obj_handle,
+ u32 nesting_level, void *context, void **return_value);
+
/*******************************************************************************
*
* FUNCTION: acpi_ns_initialize_objects
@@ -76,7 +80,7 @@ acpi_status acpi_ns_initialize_objects(void)
acpi_status status;
struct acpi_init_walk_info info;
- ACPI_FUNCTION_TRACE("ns_initialize_objects");
+ ACPI_FUNCTION_TRACE(ns_initialize_objects);
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"**** Starting initialization of namespace objects ****\n"));
@@ -93,7 +97,7 @@ acpi_status acpi_ns_initialize_objects(void)
ACPI_UINT32_MAX, acpi_ns_init_one_object,
&info, NULL);
if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "During walk_namespace"));
+ ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace"));
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
@@ -133,7 +137,7 @@ acpi_status acpi_ns_initialize_devices(void)
acpi_status status;
struct acpi_device_walk_info info;
- ACPI_FUNCTION_TRACE("ns_initialize_devices");
+ ACPI_FUNCTION_TRACE(ns_initialize_devices);
/* Init counters */
@@ -142,30 +146,46 @@ acpi_status acpi_ns_initialize_devices(void)
info.num_INI = 0;
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
- "Executing all Device _STA and_INI methods:"));
+ "Initializing Device/Processor/Thermal objects by executing _INI methods:"));
+
+ /* Tree analysis: find all subtrees that contain _INI methods */
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, FALSE,
+ acpi_ns_find_ini_methods, &info, NULL);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto error_exit;
}
- /* Walk namespace for all objects */
+ /* Allocate the evaluation information block */
+
+ info.evaluate_info =
+ ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
+ if (!info.evaluate_info) {
+ status = AE_NO_MEMORY;
+ goto error_exit;
+ }
+
+ /* Walk namespace to execute all _INIs on present devices */
status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX, TRUE,
+ ACPI_UINT32_MAX, FALSE,
acpi_ns_init_one_device, &info, NULL);
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
-
+ ACPI_FREE(info.evaluate_info);
if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "During walk_namespace"));
+ goto error_exit;
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
- "\n%hd Devices found - executed %hd _STA, %hd _INI methods\n",
- info.device_count, info.num_STA, info.num_INI));
+ "\nExecuted %hd _INI methods requiring %hd _STA executions (examined %hd objects)\n",
+ info.num_INI, info.num_STA, info.device_count));
return_ACPI_STATUS(status);
+
+ error_exit:
+ ACPI_EXCEPTION((AE_INFO, status, "During device initialization"));
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
@@ -200,7 +220,7 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
(struct acpi_namespace_node *)obj_handle;
union acpi_operand_object *obj_desc;
- ACPI_FUNCTION_NAME("ns_init_one_object");
+ ACPI_FUNCTION_NAME(ns_init_one_object);
info->object_count++;
@@ -311,6 +331,72 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
/*******************************************************************************
*
+ * FUNCTION: acpi_ns_find_ini_methods
+ *
+ * PARAMETERS: acpi_walk_callback
+ *
+ * RETURN: acpi_status
+ *
+ * DESCRIPTION: Called during namespace walk. Finds objects named _INI under
+ * device/processor/thermal objects, and marks the entire subtree
+ * with a SUBTREE_HAS_INI flag. This flag is used during the
+ * subsequent device initialization walk to avoid entire subtrees
+ * that do not contain an _INI.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ns_find_ini_methods(acpi_handle obj_handle,
+ u32 nesting_level, void *context, void **return_value)
+{
+ struct acpi_device_walk_info *info =
+ ACPI_CAST_PTR(struct acpi_device_walk_info, context);
+ struct acpi_namespace_node *node;
+ struct acpi_namespace_node *parent_node;
+
+ /* Keep count of device/processor/thermal objects */
+
+ node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle);
+ if ((node->type == ACPI_TYPE_DEVICE) ||
+ (node->type == ACPI_TYPE_PROCESSOR) ||
+ (node->type == ACPI_TYPE_THERMAL)) {
+ info->device_count++;
+ return (AE_OK);
+ }
+
+ /* We are only looking for methods named _INI */
+
+ if (!ACPI_COMPARE_NAME(node->name.ascii, METHOD_NAME__INI)) {
+ return (AE_OK);
+ }
+
+ /*
+ * The only _INI methods that we care about are those that are
+ * present under Device, Processor, and Thermal objects.
+ */
+ parent_node = acpi_ns_get_parent_node(node);
+ switch (parent_node->type) {
+ case ACPI_TYPE_DEVICE:
+ case ACPI_TYPE_PROCESSOR:
+ case ACPI_TYPE_THERMAL:
+
+ /* Mark parent and bubble up the INI present flag to the root */
+
+ while (parent_node) {
+ parent_node->flags |= ANOBJ_SUBTREE_HAS_INI;
+ parent_node = acpi_ns_get_parent_node(parent_node);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ns_init_one_device
*
* PARAMETERS: acpi_walk_callback
@@ -327,119 +413,165 @@ static acpi_status
acpi_ns_init_one_device(acpi_handle obj_handle,
u32 nesting_level, void *context, void **return_value)
{
- struct acpi_device_walk_info *info =
- (struct acpi_device_walk_info *)context;
- struct acpi_parameter_info pinfo;
+ struct acpi_device_walk_info *walk_info =
+ ACPI_CAST_PTR(struct acpi_device_walk_info, context);
+ struct acpi_evaluate_info *info = walk_info->evaluate_info;
u32 flags;
acpi_status status;
- struct acpi_namespace_node *ini_node;
struct acpi_namespace_node *device_node;
- ACPI_FUNCTION_TRACE("ns_init_one_device");
+ ACPI_FUNCTION_TRACE(ns_init_one_device);
- device_node = acpi_ns_map_handle_to_node(obj_handle);
- if (!device_node) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
+ /* We are interested in Devices, Processors and thermal_zones only */
- /*
- * We will run _STA/_INI on Devices, Processors and thermal_zones only
- */
+ device_node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle);
if ((device_node->type != ACPI_TYPE_DEVICE) &&
(device_node->type != ACPI_TYPE_PROCESSOR) &&
(device_node->type != ACPI_TYPE_THERMAL)) {
return_ACPI_STATUS(AE_OK);
}
- if ((acpi_dbg_level <= ACPI_LV_ALL_EXCEPTIONS) &&
- (!(acpi_dbg_level & ACPI_LV_INFO))) {
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "."));
- }
-
- info->device_count++;
-
/*
- * Check if the _INI method exists for this device -
- * if _INI does not exist, there is no need to run _STA
- * No _INI means device requires no initialization
+ * Because of an earlier namespace analysis, all subtrees that contain an
+ * _INI method are tagged.
+ *
+ * If this device subtree does not contain any _INI methods, we
+ * can exit now and stop traversing this entire subtree.
*/
- status = acpi_ns_search_node(*ACPI_CAST_PTR(u32, METHOD_NAME__INI),
- device_node, ACPI_TYPE_METHOD, &ini_node);
- if (ACPI_FAILURE(status)) {
- /* No _INI method found - move on to next device */
-
- return_ACPI_STATUS(AE_OK);
+ if (!(device_node->flags & ANOBJ_SUBTREE_HAS_INI)) {
+ return_ACPI_STATUS(AE_CTRL_DEPTH);
}
/*
- * Run _STA to determine if we can run _INI on the device -
- * the device must be present before _INI can be run.
- * However, _STA is not required - assume device present if no _STA
+ * Run _STA to determine if this device is present and functioning. We
+ * must know this information for two important reasons (from ACPI spec):
+ *
+ * 1) We can only run _INI if the device is present.
+ * 2) We must abort the device tree walk on this subtree if the device is
+ * not present and is not functional (we will not examine the children)
+ *
+ * The _STA method is not required to be present under the device, we
+ * assume the device is present if _STA does not exist.
*/
- ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname(ACPI_TYPE_METHOD,
- device_node,
- METHOD_NAME__STA));
-
- pinfo.node = device_node;
- pinfo.parameters = NULL;
- pinfo.parameter_type = ACPI_PARAM_ARGS;
+ ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
+ (ACPI_TYPE_METHOD, device_node, METHOD_NAME__STA));
- status = acpi_ut_execute_STA(pinfo.node, &flags);
+ status = acpi_ut_execute_STA(device_node, &flags);
if (ACPI_FAILURE(status)) {
+
/* Ignore error and move on to next device */
return_ACPI_STATUS(AE_OK);
}
+ /*
+ * Flags == -1 means that _STA was not found. In this case, we assume that
+ * the device is both present and functional.
+ *
+ * From the ACPI spec, description of _STA:
+ *
+ * "If a device object (including the processor object) does not have an
+ * _STA object, then OSPM assumes that all of the above bits are set (in
+ * other words, the device is present, ..., and functioning)"
+ */
if (flags != ACPI_UINT32_MAX) {
- info->num_STA++;
+ walk_info->num_STA++;
}
+ /*
+ * Examine the PRESENT and FUNCTIONING status bits
+ *
+ * Note: ACPI spec does not seem to specify behavior for the present but
+ * not functioning case, so we assume functioning if present.
+ */
if (!(flags & ACPI_STA_DEVICE_PRESENT)) {
- /* Don't look at children of a not present device */
- return_ACPI_STATUS(AE_CTRL_DEPTH);
+ /* Device is not present, we must examine the Functioning bit */
+
+ if (flags & ACPI_STA_DEVICE_FUNCTIONING) {
+ /*
+ * Device is not present but is "functioning". In this case,
+ * we will not run _INI, but we continue to examine the children
+ * of this device.
+ *
+ * From the ACPI spec, description of _STA: (Note - no mention
+ * of whether to run _INI or not on the device in question)
+ *
+ * "_STA may return bit 0 clear (not present) with bit 3 set
+ * (device is functional). This case is used to indicate a valid
+ * device for which no device driver should be loaded (for example,
+ * a bridge device.) Children of this device may be present and
+ * valid. OSPM should continue enumeration below a device whose
+ * _STA returns this bit combination"
+ */
+ return_ACPI_STATUS(AE_OK);
+ } else {
+ /*
+ * Device is not present and is not functioning. We must abort the
+ * walk of this subtree immediately -- don't look at the children
+ * of such a device.
+ *
+ * From the ACPI spec, description of _INI:
+ *
+ * "If the _STA method indicates that the device is not present,
+ * OSPM will not run the _INI and will not examine the children
+ * of the device for _INI methods"
+ */
+ return_ACPI_STATUS(AE_CTRL_DEPTH);
+ }
}
/*
- * The device is present and _INI exists. Run the _INI method.
- * (We already have the _INI node from above)
+ * The device is present or is assumed present if no _STA exists.
+ * Run the _INI if it exists (not required to exist)
+ *
+ * Note: We know there is an _INI within this subtree, but it may not be
+ * under this particular device, it may be lower in the branch.
*/
- ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname(ACPI_TYPE_METHOD,
- pinfo.node,
- METHOD_NAME__INI));
+ ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
+ (ACPI_TYPE_METHOD, device_node, METHOD_NAME__INI));
+
+ info->prefix_node = device_node;
+ info->pathname = METHOD_NAME__INI;
+ info->parameters = NULL;
+ info->parameter_type = ACPI_PARAM_ARGS;
+ info->flags = ACPI_IGNORE_RETURN_VALUE;
+
+ status = acpi_ns_evaluate(info);
+ if (ACPI_SUCCESS(status)) {
+ walk_info->num_INI++;
+
+ if ((acpi_dbg_level <= ACPI_LV_ALL_EXCEPTIONS) &&
+ (!(acpi_dbg_level & ACPI_LV_INFO))) {
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "."));
+ }
+ }
+#ifdef ACPI_DEBUG_OUTPUT
+ else if (status != AE_NOT_FOUND) {
- pinfo.node = ini_node;
- status = acpi_ns_evaluate_by_handle(&pinfo);
- if (ACPI_FAILURE(status)) {
/* Ignore error and move on to next device */
-#ifdef ACPI_DEBUG_OUTPUT
- char *scope_name = acpi_ns_get_external_pathname(ini_node);
-
- ACPI_WARNING((AE_INFO, "%s._INI failed: %s",
- scope_name, acpi_format_exception(status)));
+ char *scope_name =
+ acpi_ns_get_external_pathname(info->resolved_node);
- ACPI_MEM_FREE(scope_name);
+ ACPI_EXCEPTION((AE_INFO, status, "during %s._INI execution",
+ scope_name));
+ ACPI_FREE(scope_name);
+ }
#endif
- } else {
- /* Delete any return object (especially if implicit_return is enabled) */
- if (pinfo.return_object) {
- acpi_ut_remove_reference(pinfo.return_object);
- }
+ /* Ignore errors from above */
- /* Count of successful INIs */
-
- info->num_INI++;
- }
+ status = AE_OK;
+ /*
+ * The _INI method has been run if present; call the Global Initialization
+ * Handler for this device.
+ */
if (acpi_gbl_init_handler) {
- /* External initialization handler is present, call it */
-
status =
- acpi_gbl_init_handler(pinfo.node, ACPI_INIT_DEVICE_INI);
+ acpi_gbl_init_handler(device_node, ACPI_INIT_DEVICE_INI);
}
- return_ACPI_STATUS(AE_OK);
+ return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c
index 4e0b052..fe75d88 100644
--- a/drivers/acpi/namespace/nsload.c
+++ b/drivers/acpi/namespace/nsload.c
@@ -77,13 +77,14 @@ acpi_ns_load_table(struct acpi_table_desc *table_desc,
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ns_load_table");
+ ACPI_FUNCTION_TRACE(ns_load_table);
/* Check if table contains valid AML (must be DSDT, PSDT, SSDT, etc.) */
if (!
(acpi_gbl_table_data[table_desc->type].
flags & ACPI_TABLE_EXECUTABLE)) {
+
/* Just ignore this table */
return_ACPI_STATUS(AE_OK);
@@ -168,7 +169,7 @@ static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type)
acpi_status status;
struct acpi_table_desc *table_desc;
- ACPI_FUNCTION_TRACE("ns_load_table_by_type");
+ ACPI_FUNCTION_TRACE(ns_load_table_by_type);
status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
if (ACPI_FAILURE(status)) {
@@ -180,11 +181,11 @@ static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type)
* DSDT (one), SSDT/PSDT (multiple)
*/
switch (table_type) {
- case ACPI_TABLE_DSDT:
+ case ACPI_TABLE_ID_DSDT:
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace load: DSDT\n"));
- table_desc = acpi_gbl_table_lists[ACPI_TABLE_DSDT].next;
+ table_desc = acpi_gbl_table_lists[ACPI_TABLE_ID_DSDT].next;
/* If table already loaded into namespace, just return */
@@ -200,8 +201,8 @@ static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type)
}
break;
- case ACPI_TABLE_SSDT:
- case ACPI_TABLE_PSDT:
+ case ACPI_TABLE_ID_SSDT:
+ case ACPI_TABLE_ID_PSDT:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Namespace load: %d SSDT or PSDTs\n",
@@ -258,7 +259,7 @@ acpi_status acpi_ns_load_namespace(void)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_load_name_space");
+ ACPI_FUNCTION_TRACE(acpi_load_name_space);
/* There must be at least a DSDT installed */
@@ -271,15 +272,15 @@ acpi_status acpi_ns_load_namespace(void)
* Load the namespace. The DSDT is required,
* but the SSDT and PSDT tables are optional.
*/
- status = acpi_ns_load_table_by_type(ACPI_TABLE_DSDT);
+ status = acpi_ns_load_table_by_type(ACPI_TABLE_ID_DSDT);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
/* Ignore exceptions from these */
- (void)acpi_ns_load_table_by_type(ACPI_TABLE_SSDT);
- (void)acpi_ns_load_table_by_type(ACPI_TABLE_PSDT);
+ (void)acpi_ns_load_table_by_type(ACPI_TABLE_ID_SSDT);
+ (void)acpi_ns_load_table_by_type(ACPI_TABLE_ID_PSDT);
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
"ACPI Namespace successfully loaded at root %p\n",
@@ -314,7 +315,7 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle)
acpi_handle dummy;
u32 level;
- ACPI_FUNCTION_TRACE("ns_delete_subtree");
+ ACPI_FUNCTION_TRACE(ns_delete_subtree);
parent_handle = start_handle;
child_handle = NULL;
@@ -325,6 +326,7 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle)
* to where we started.
*/
while (level > 0) {
+
/* Attempt to get the next object in this scope */
status = acpi_get_next_object(ACPI_TYPE_ANY, parent_handle,
@@ -335,6 +337,7 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle)
/* Did we get a new object? */
if (ACPI_SUCCESS(status)) {
+
/* Check if this object has any children */
if (ACPI_SUCCESS
@@ -392,7 +395,7 @@ acpi_status acpi_ns_unload_namespace(acpi_handle handle)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ns_unload_name_space");
+ ACPI_FUNCTION_TRACE(ns_unload_name_space);
/* Parameter validation */
diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c
index 639f653..97b8332 100644
--- a/drivers/acpi/namespace/nsnames.c
+++ b/drivers/acpi/namespace/nsnames.c
@@ -48,11 +48,6 @@
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsnames")
-/* Local prototypes */
-static void
-acpi_ns_build_external_path(struct acpi_namespace_node *node,
- acpi_size size, char *name_buffer);
-
/*******************************************************************************
*
* FUNCTION: acpi_ns_build_external_path
@@ -67,8 +62,7 @@ acpi_ns_build_external_path(struct acpi_namespace_node *node,
* DESCRIPTION: Generate a full pathaname
*
******************************************************************************/
-
-static void
+void
acpi_ns_build_external_path(struct acpi_namespace_node *node,
acpi_size size, char *name_buffer)
{
@@ -138,7 +132,7 @@ char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node)
char *name_buffer;
acpi_size size;
- ACPI_FUNCTION_TRACE_PTR("ns_get_external_pathname", node);
+ ACPI_FUNCTION_TRACE_PTR(ns_get_external_pathname, node);
/* Calculate required buffer size based on depth below root */
@@ -146,7 +140,7 @@ char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node)
/* Allocate a buffer to be returned to caller */
- name_buffer = ACPI_MEM_CALLOCATE(size);
+ name_buffer = ACPI_ALLOCATE_ZEROED(size);
if (!name_buffer) {
ACPI_ERROR((AE_INFO, "Allocation failure"));
return_PTR(NULL);
@@ -219,7 +213,7 @@ acpi_ns_handle_to_pathname(acpi_handle target_handle,
struct acpi_namespace_node *node;
acpi_size required_size;
- ACPI_FUNCTION_TRACE_PTR("ns_handle_to_pathname", target_handle);
+ ACPI_FUNCTION_TRACE_PTR(ns_handle_to_pathname, target_handle);
node = acpi_ns_map_handle_to_node(target_handle);
if (!node) {
diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/namespace/nsobject.c
index 10ae629..aabe879 100644
--- a/drivers/acpi/namespace/nsobject.c
+++ b/drivers/acpi/namespace/nsobject.c
@@ -76,19 +76,21 @@ acpi_ns_attach_object(struct acpi_namespace_node *node,
union acpi_operand_object *last_obj_desc;
acpi_object_type object_type = ACPI_TYPE_ANY;
- ACPI_FUNCTION_TRACE("ns_attach_object");
+ ACPI_FUNCTION_TRACE(ns_attach_object);
/*
* Parameter validation
*/
if (!node) {
+
/* Invalid handle */
- ACPI_ERROR((AE_INFO, "Null named_obj handle"));
+ ACPI_ERROR((AE_INFO, "Null NamedObj handle"));
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
if (!object && (ACPI_TYPE_ANY != type)) {
+
/* Null object */
ACPI_ERROR((AE_INFO,
@@ -97,6 +99,7 @@ acpi_ns_attach_object(struct acpi_namespace_node *node,
}
if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) {
+
/* Not a name handle */
ACPI_ERROR((AE_INFO, "Invalid handle %p [%s]",
@@ -108,7 +111,7 @@ acpi_ns_attach_object(struct acpi_namespace_node *node,
if (node->object == object) {
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Obj %p already installed in name_obj %p\n",
+ "Obj %p already installed in NameObj %p\n",
object, node));
return_ACPI_STATUS(AE_OK);
@@ -201,7 +204,7 @@ void acpi_ns_detach_object(struct acpi_namespace_node *node)
{
union acpi_operand_object *obj_desc;
- ACPI_FUNCTION_TRACE("ns_detach_object");
+ ACPI_FUNCTION_TRACE(ns_detach_object);
obj_desc = node->object;
@@ -252,7 +255,7 @@ union acpi_operand_object *acpi_ns_get_attached_object(struct
acpi_namespace_node
*node)
{
- ACPI_FUNCTION_TRACE_PTR("ns_get_attached_object", node);
+ ACPI_FUNCTION_TRACE_PTR(ns_get_attached_object, node);
if (!node) {
ACPI_WARNING((AE_INFO, "Null Node ptr"));
@@ -287,7 +290,7 @@ union acpi_operand_object *acpi_ns_get_secondary_object(union
acpi_operand_object
*obj_desc)
{
- ACPI_FUNCTION_TRACE_PTR("ns_get_secondary_object", obj_desc);
+ ACPI_FUNCTION_TRACE_PTR(ns_get_secondary_object, obj_desc);
if ((!obj_desc) ||
(ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_DATA) ||
diff --git a/drivers/acpi/namespace/nsparse.c b/drivers/acpi/namespace/nsparse.c
index 232be43..155505a 100644
--- a/drivers/acpi/namespace/nsparse.c
+++ b/drivers/acpi/namespace/nsparse.c
@@ -62,13 +62,13 @@ ACPI_MODULE_NAME("nsparse")
*
******************************************************************************/
acpi_status
-acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc * table_desc)
+acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc)
{
union acpi_parse_object *parse_root;
acpi_status status;
struct acpi_walk_state *walk_state;
- ACPI_FUNCTION_TRACE("ns_one_complete_parse");
+ ACPI_FUNCTION_TRACE(ns_one_complete_parse);
/* Create and init a Root Node */
@@ -124,7 +124,7 @@ acpi_ns_parse_table(struct acpi_table_desc *table_desc,
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ns_parse_table");
+ ACPI_FUNCTION_TRACE(ns_parse_table);
/*
* AML Parse, pass 1
diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c
index d64b789..500e2bb 100644
--- a/drivers/acpi/namespace/nssearch.c
+++ b/drivers/acpi/namespace/nssearch.c
@@ -56,16 +56,16 @@ acpi_ns_search_parent_tree(u32 target_name,
/*******************************************************************************
*
- * FUNCTION: acpi_ns_search_node
+ * FUNCTION: acpi_ns_search_one_scope
*
* PARAMETERS: target_name - Ascii ACPI name to search for
- * Node - Starting node where search will begin
+ * parent_node - Starting node where search will begin
* Type - Object type to match
* return_node - Where the matched Named obj is returned
*
* RETURN: Status
*
- * DESCRIPTION: Search a single level of the namespace. Performs a
+ * DESCRIPTION: Search a single level of the namespace. Performs a
* simple search of the specified level, and does not add
* entries or search parents.
*
@@ -75,35 +75,40 @@ acpi_ns_search_parent_tree(u32 target_name,
*
* All namespace searching is linear in this implementation, but
* could be easily modified to support any improved search
- * algorithm. However, the linear search was chosen for simplicity
+ * algorithm. However, the linear search was chosen for simplicity
* and because the trees are small and the other interpreter
* execution overhead is relatively high.
*
+ * Note: CPU execution analysis has shown that the AML interpreter spends
+ * a very small percentage of its time searching the namespace. Therefore,
+ * the linear search seems to be sufficient, as there would seem to be
+ * little value in improving the search.
+ *
******************************************************************************/
acpi_status
-acpi_ns_search_node(u32 target_name,
- struct acpi_namespace_node *node,
- acpi_object_type type,
- struct acpi_namespace_node **return_node)
+acpi_ns_search_one_scope(u32 target_name,
+ struct acpi_namespace_node *parent_node,
+ acpi_object_type type,
+ struct acpi_namespace_node **return_node)
{
- struct acpi_namespace_node *next_node;
+ struct acpi_namespace_node *node;
- ACPI_FUNCTION_TRACE("ns_search_node");
+ ACPI_FUNCTION_TRACE(ns_search_one_scope);
#ifdef ACPI_DEBUG_OUTPUT
if (ACPI_LV_NAMES & acpi_dbg_level) {
char *scope_name;
- scope_name = acpi_ns_get_external_pathname(node);
+ scope_name = acpi_ns_get_external_pathname(parent_node);
if (scope_name) {
ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
"Searching %s (%p) For [%4.4s] (%s)\n",
- scope_name, node, ACPI_CAST_PTR(char,
- &target_name),
+ scope_name, parent_node,
+ ACPI_CAST_PTR(char, &target_name),
acpi_ut_get_type_name(type)));
- ACPI_MEM_FREE(scope_name);
+ ACPI_FREE(scope_name);
}
}
#endif
@@ -112,32 +117,33 @@ acpi_ns_search_node(u32 target_name,
* Search for name at this namespace level, which is to say that we
* must search for the name among the children of this object
*/
- next_node = node->child;
- while (next_node) {
+ node = parent_node->child;
+ while (node) {
+
/* Check for match against the name */
- if (next_node->name.integer == target_name) {
+ if (node->name.integer == target_name) {
+
/* Resolve a control method alias if any */
- if (acpi_ns_get_type(next_node) ==
+ if (acpi_ns_get_type(node) ==
ACPI_TYPE_LOCAL_METHOD_ALIAS) {
- next_node =
+ node =
ACPI_CAST_PTR(struct acpi_namespace_node,
- next_node->object);
+ node->object);
}
- /*
- * Found matching entry.
- */
+ /* Found matching entry */
+
ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
"Name [%4.4s] (%s) %p found in scope [%4.4s] %p\n",
ACPI_CAST_PTR(char, &target_name),
- acpi_ut_get_type_name(next_node->
- type),
- next_node,
- acpi_ut_get_node_name(node), node));
+ acpi_ut_get_type_name(node->type),
+ node,
+ acpi_ut_get_node_name(parent_node),
+ parent_node));
- *return_node = next_node;
+ *return_node = node;
return_ACPI_STATUS(AE_OK);
}
@@ -145,7 +151,8 @@ acpi_ns_search_node(u32 target_name,
* The last entry in the list points back to the parent,
* so a flag is used to indicate the end-of-list
*/
- if (next_node->flags & ANOBJ_END_OF_PEER_LIST) {
+ if (node->flags & ANOBJ_END_OF_PEER_LIST) {
+
/* Searched entire list, we are done */
break;
@@ -153,7 +160,7 @@ acpi_ns_search_node(u32 target_name,
/* Didn't match name, move on to the next peer object */
- next_node = next_node->peer;
+ node = node->peer;
}
/* Searched entire namespace level, not found */
@@ -162,7 +169,8 @@ acpi_ns_search_node(u32 target_name,
"Name [%4.4s] (%s) not found in search in scope [%4.4s] %p first child %p\n",
ACPI_CAST_PTR(char, &target_name),
acpi_ut_get_type_name(type),
- acpi_ut_get_node_name(node), node, node->child));
+ acpi_ut_get_node_name(parent_node), parent_node,
+ parent_node->child));
return_ACPI_STATUS(AE_NOT_FOUND);
}
@@ -179,14 +187,14 @@ acpi_ns_search_node(u32 target_name,
* RETURN: Status
*
* DESCRIPTION: Called when a name has not been found in the current namespace
- * level. Before adding it or giving up, ACPI scope rules require
+ * level. Before adding it or giving up, ACPI scope rules require
* searching enclosing scopes in cases identified by acpi_ns_local().
*
* "A name is located by finding the matching name in the current
* name space, and then in the parent name space. If the parent
* name space does not contain the name, the search continues
* recursively until either the name is found or the name space
- * does not have a parent (the root of the name space). This
+ * does not have a parent (the root of the name space). This
* indicates that the name is not found" (From ACPI Specification,
* section 5.3)
*
@@ -201,7 +209,7 @@ acpi_ns_search_parent_tree(u32 target_name,
acpi_status status;
struct acpi_namespace_node *parent_node;
- ACPI_FUNCTION_TRACE("ns_search_parent_tree");
+ ACPI_FUNCTION_TRACE(ns_search_parent_tree);
parent_node = acpi_ns_get_parent_node(node);
@@ -235,20 +243,19 @@ acpi_ns_search_parent_tree(u32 target_name,
*/
while (parent_node) {
/*
- * Search parent scope. Use TYPE_ANY because we don't care about the
+ * Search parent scope. Use TYPE_ANY because we don't care about the
* object type at this point, we only care about the existence of
- * the actual name we are searching for. Typechecking comes later.
+ * the actual name we are searching for. Typechecking comes later.
*/
- status = acpi_ns_search_node(target_name, parent_node,
+ status =
+ acpi_ns_search_one_scope(target_name, parent_node,
ACPI_TYPE_ANY, return_node);
if (ACPI_SUCCESS(status)) {
return_ACPI_STATUS(status);
}
- /*
- * Not found here, go up another level
- * (until we reach the root)
- */
+ /* Not found here, go up another level (until we reach the root) */
+
parent_node = acpi_ns_get_parent_node(parent_node);
}
@@ -273,7 +280,7 @@ acpi_ns_search_parent_tree(u32 target_name,
* RETURN: Status
*
* DESCRIPTION: Search for a name segment in a single namespace level,
- * optionally adding it if it is not found. If the passed
+ * optionally adding it if it is not found. If the passed
* Type is not Any and the type previously stored in the
* entry was Any (i.e. unknown), update the stored type.
*
@@ -293,29 +300,46 @@ acpi_ns_search_and_enter(u32 target_name,
acpi_status status;
struct acpi_namespace_node *new_node;
- ACPI_FUNCTION_TRACE("ns_search_and_enter");
+ ACPI_FUNCTION_TRACE(ns_search_and_enter);
/* Parameter validation */
if (!node || !target_name || !return_node) {
ACPI_ERROR((AE_INFO,
- "Null param: Node %p Name %X return_node %p",
+ "Null parameter: Node %p Name %X ReturnNode %p",
node, target_name, return_node));
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Name must consist of printable characters */
-
+ /*
+ * Name must consist of valid ACPI characters. We will repair the name if
+ * necessary because we don't want to abort because of this, but we want
+ * all namespace names to be printable. A warning message is appropriate.
+ *
+ * This issue came up because there are in fact machines that exhibit
+ * this problem, and we want to be able to enable ACPI support for them,
+ * even though there are a few bad names.
+ */
if (!acpi_ut_valid_acpi_name(target_name)) {
- ACPI_ERROR((AE_INFO, "Bad character in ACPI Name: %X",
- target_name));
- return_ACPI_STATUS(AE_BAD_CHARACTER);
+ target_name = acpi_ut_repair_name(target_name);
+
+ /* Report warning only if in strict mode or debug mode */
+
+ if (!acpi_gbl_enable_interpreter_slack) {
+ ACPI_WARNING((AE_INFO,
+ "Found bad character(s) in name, repaired: [%4.4s]\n",
+ ACPI_CAST_PTR(char, &target_name)));
+ } else {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+ "Found bad character(s) in name, repaired: [%4.4s]\n",
+ ACPI_CAST_PTR(char, &target_name)));
+ }
}
/* Try to find the name in the namespace level specified by the caller */
*return_node = ACPI_ENTRY_NOT_FOUND;
- status = acpi_ns_search_node(target_name, node, type, return_node);
+ status = acpi_ns_search_one_scope(target_name, node, type, return_node);
if (status != AE_NOT_FOUND) {
/*
* If we found it AND the request specifies that a find is an error,
@@ -325,18 +349,16 @@ acpi_ns_search_and_enter(u32 target_name,
status = AE_ALREADY_EXISTS;
}
- /*
- * Either found it or there was an error
- * -- finished either way
- */
+ /* Either found it or there was an error: finished either way */
+
return_ACPI_STATUS(status);
}
/*
- * The name was not found. If we are NOT performing the first pass
+ * The name was not found. If we are NOT performing the first pass
* (name entry) of loading the namespace, search the parent tree (all the
* way to the root if necessary.) We don't want to perform the parent
- * search when the namespace is actually being loaded. We want to perform
+ * search when the namespace is actually being loaded. We want to perform
* the search when namespace references are being resolved (load pass 2)
* and during the execution phase.
*/
@@ -354,9 +376,8 @@ acpi_ns_search_and_enter(u32 target_name,
}
}
- /*
- * In execute mode, just search, never add names. Exit now.
- */
+ /* In execute mode, just search, never add names. Exit now */
+
if (interpreter_mode == ACPI_IMODE_EXECUTE) {
ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
"%4.4s Not found in %p [Not adding]\n",
@@ -371,11 +392,18 @@ acpi_ns_search_and_enter(u32 target_name,
if (!new_node) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
+#ifdef ACPI_ASL_COMPILER
+ /*
+ * Node is an object defined by an External() statement
+ */
+ if (flags & ACPI_NS_EXTERNAL) {
+ new_node->flags |= ANOBJ_IS_EXTERNAL;
+ }
+#endif
/* Install the new object into the parent's list of children */
acpi_ns_install_node(walk_state, node, new_node, type);
*return_node = new_node;
-
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c
index 3e7cad5..aa4e799 100644
--- a/drivers/acpi/namespace/nsutils.c
+++ b/drivers/acpi/namespace/nsutils.c
@@ -78,15 +78,17 @@ acpi_ns_report_error(char *module_name,
char *internal_name, acpi_status lookup_status)
{
acpi_status status;
+ u32 bad_name;
char *name = NULL;
- acpi_ut_report_error(module_name, line_number);
+ acpi_os_printf("ACPI Error (%s-%04d): ", module_name, line_number);
if (lookup_status == AE_BAD_CHARACTER) {
+
/* There is a non-ascii character in the name */
- acpi_os_printf("[0x%4.4X] (NON-ASCII)",
- *(ACPI_CAST_PTR(u32, internal_name)));
+ ACPI_MOVE_32_TO_32(&bad_name, internal_name);
+ acpi_os_printf("[0x%4.4X] (NON-ASCII)", bad_name);
} else {
/* Convert path to external format */
@@ -102,7 +104,7 @@ acpi_ns_report_error(char *module_name,
}
if (name) {
- ACPI_MEM_FREE(name);
+ ACPI_FREE(name);
}
}
@@ -137,11 +139,12 @@ acpi_ns_report_method_error(char *module_name,
acpi_status status;
struct acpi_namespace_node *node = prefix_node;
- acpi_ut_report_error(module_name, line_number);
+ acpi_os_printf("ACPI Error (%s-%04d): ", module_name, line_number);
if (path) {
- status = acpi_ns_get_node_by_path(path, prefix_node,
- ACPI_NS_NO_UPSEARCH, &node);
+ status =
+ acpi_ns_get_node(prefix_node, path, ACPI_NS_NO_UPSEARCH,
+ &node);
if (ACPI_FAILURE(status)) {
acpi_os_printf("[Could not get node by pathname]");
}
@@ -185,7 +188,7 @@ acpi_ns_print_node_pathname(struct acpi_namespace_node *node, char *message)
}
acpi_os_printf("[%s] (Node %p)", (char *)buffer.pointer, node);
- ACPI_MEM_FREE(buffer.pointer);
+ ACPI_FREE(buffer.pointer);
}
}
@@ -239,7 +242,7 @@ static u8 acpi_ns_valid_path_separator(char sep)
acpi_object_type acpi_ns_get_type(struct acpi_namespace_node * node)
{
- ACPI_FUNCTION_TRACE("ns_get_type");
+ ACPI_FUNCTION_TRACE(ns_get_type);
if (!node) {
ACPI_WARNING((AE_INFO, "Null Node parameter"));
@@ -264,9 +267,10 @@ acpi_object_type acpi_ns_get_type(struct acpi_namespace_node * node)
u32 acpi_ns_local(acpi_object_type type)
{
- ACPI_FUNCTION_TRACE("ns_local");
+ ACPI_FUNCTION_TRACE(ns_local);
if (!acpi_ut_valid_object_type(type)) {
+
/* Type code out of range */
ACPI_WARNING((AE_INFO, "Invalid Object Type %X", type));
@@ -363,7 +367,7 @@ acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info)
char *result = NULL;
acpi_native_uint i;
- ACPI_FUNCTION_TRACE("ns_build_internal_name");
+ ACPI_FUNCTION_TRACE(ns_build_internal_name);
/* Setup the correct prefixes, counts, and pointers */
@@ -411,6 +415,7 @@ acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info)
for (i = 0; i < ACPI_NAME_SIZE; i++) {
if (acpi_ns_valid_path_separator(*external_name) ||
(*external_name == 0)) {
+
/* Pad the segment with underscore(s) if segment is short */
result[i] = '_';
@@ -473,7 +478,7 @@ acpi_status acpi_ns_internalize_name(char *external_name, char **converted_name)
struct acpi_namestring_info info;
acpi_status status;
- ACPI_FUNCTION_TRACE("ns_internalize_name");
+ ACPI_FUNCTION_TRACE(ns_internalize_name);
if ((!external_name) || (*external_name == 0) || (!converted_name)) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -486,7 +491,7 @@ acpi_status acpi_ns_internalize_name(char *external_name, char **converted_name)
/* We need a segment to store the internal name */
- internal_name = ACPI_MEM_CALLOCATE(info.length);
+ internal_name = ACPI_ALLOCATE_ZEROED(info.length);
if (!internal_name) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
@@ -496,7 +501,7 @@ acpi_status acpi_ns_internalize_name(char *external_name, char **converted_name)
info.internal_name = internal_name;
status = acpi_ns_build_internal_name(&info);
if (ACPI_FAILURE(status)) {
- ACPI_MEM_FREE(internal_name);
+ ACPI_FREE(internal_name);
return_ACPI_STATUS(status);
}
@@ -533,7 +538,7 @@ acpi_ns_externalize_name(u32 internal_name_length,
acpi_native_uint i = 0;
acpi_native_uint j = 0;
- ACPI_FUNCTION_TRACE("ns_externalize_name");
+ ACPI_FUNCTION_TRACE(ns_externalize_name);
if (!internal_name_length || !internal_name || !converted_name) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -628,7 +633,7 @@ acpi_ns_externalize_name(u32 internal_name_length,
/*
* Build converted_name
*/
- *converted_name = ACPI_MEM_CALLOCATE(required_length);
+ *converted_name = ACPI_ALLOCATE_ZEROED(required_length);
if (!(*converted_name)) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
@@ -681,13 +686,9 @@ struct acpi_namespace_node *acpi_ns_map_handle_to_node(acpi_handle handle)
ACPI_FUNCTION_ENTRY();
/*
- * Simple implementation.
+ * Simple implementation
*/
- if (!handle) {
- return (NULL);
- }
-
- if (handle == ACPI_ROOT_OBJECT) {
+ if ((!handle) || (handle == ACPI_ROOT_OBJECT)) {
return (acpi_gbl_root_node);
}
@@ -697,7 +698,7 @@ struct acpi_namespace_node *acpi_ns_map_handle_to_node(acpi_handle handle)
return (NULL);
}
- return ((struct acpi_namespace_node *)handle);
+ return (ACPI_CAST_PTR(struct acpi_namespace_node, handle));
}
/*******************************************************************************
@@ -752,7 +753,7 @@ void acpi_ns_terminate(void)
{
union acpi_operand_object *obj_desc;
- ACPI_FUNCTION_TRACE("ns_terminate");
+ ACPI_FUNCTION_TRACE(ns_terminate);
/*
* 1) Free the entire namespace -- all nodes and objects
@@ -792,9 +793,10 @@ void acpi_ns_terminate(void)
u32 acpi_ns_opens_scope(acpi_object_type type)
{
- ACPI_FUNCTION_TRACE_STR("ns_opens_scope", acpi_ut_get_type_name(type));
+ ACPI_FUNCTION_TRACE_STR(ns_opens_scope, acpi_ut_get_type_name(type));
if (!acpi_ut_valid_object_type(type)) {
+
/* type code out of range */
ACPI_WARNING((AE_INFO, "Invalid Object Type %X", type));
@@ -806,12 +808,12 @@ u32 acpi_ns_opens_scope(acpi_object_type type)
/*******************************************************************************
*
- * FUNCTION: acpi_ns_get_node_by_path
+ * FUNCTION: acpi_ns_get_node
*
* PARAMETERS: *Pathname - Name to be found, in external (ASL) format. The
* \ (backslash) and ^ (carat) prefixes, and the
* . (period) to separate segments are supported.
- * start_node - Root of subtree to be searched, or NS_ALL for the
+ * prefix_node - Root of subtree to be searched, or NS_ALL for the
* root of the name space. If Name is fully
* qualified (first s8 is '\'), the passed value
* of Scope will not be accessed.
@@ -827,23 +829,29 @@ u32 acpi_ns_opens_scope(acpi_object_type type)
******************************************************************************/
acpi_status
-acpi_ns_get_node_by_path(char *pathname,
- struct acpi_namespace_node *start_node,
- u32 flags, struct acpi_namespace_node **return_node)
+acpi_ns_get_node(struct acpi_namespace_node *prefix_node,
+ char *pathname,
+ u32 flags, struct acpi_namespace_node **return_node)
{
union acpi_generic_state scope_info;
acpi_status status;
- char *internal_path = NULL;
-
- ACPI_FUNCTION_TRACE_PTR("ns_get_node_by_path", pathname);
+ char *internal_path;
- if (pathname) {
- /* Convert path to internal representation */
+ ACPI_FUNCTION_TRACE_PTR(ns_get_node, pathname);
- status = acpi_ns_internalize_name(pathname, &internal_path);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ if (!pathname) {
+ *return_node = prefix_node;
+ if (!prefix_node) {
+ *return_node = acpi_gbl_root_node;
}
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ /* Convert path to internal representation */
+
+ status = acpi_ns_internalize_name(pathname, &internal_path);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
}
/* Must lock namespace during lookup */
@@ -855,26 +863,23 @@ acpi_ns_get_node_by_path(char *pathname,
/* Setup lookup scope (search starting point) */
- scope_info.scope.node = start_node;
+ scope_info.scope.node = prefix_node;
/* Lookup the name in the namespace */
- status = acpi_ns_lookup(&scope_info, internal_path,
- ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
- (flags | ACPI_NS_DONT_OPEN_SCOPE),
- NULL, return_node);
+ status = acpi_ns_lookup(&scope_info, internal_path, ACPI_TYPE_ANY,
+ ACPI_IMODE_EXECUTE,
+ (flags | ACPI_NS_DONT_OPEN_SCOPE), NULL,
+ return_node);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s, %s\n",
- internal_path,
- acpi_format_exception(status)));
+ pathname, acpi_format_exception(status)));
}
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
cleanup:
- if (internal_path) {
- ACPI_MEM_FREE(internal_path);
- }
+ ACPI_FREE(internal_path);
return_ACPI_STATUS(status);
}
@@ -960,9 +965,10 @@ acpi_name acpi_ns_find_parent_name(struct acpi_namespace_node * child_node)
{
struct acpi_namespace_node *parent_node;
- ACPI_FUNCTION_TRACE("ns_find_parent_name");
+ ACPI_FUNCTION_TRACE(ns_find_parent_name);
if (child_node) {
+
/* Valid entry. Get the parent Node */
parent_node = acpi_ns_get_parent_node(child_node);
diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c
index fcab1e7..c8f6bef 100644
--- a/drivers/acpi/namespace/nswalk.c
+++ b/drivers/acpi/namespace/nswalk.c
@@ -76,6 +76,7 @@ struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type,
ACPI_FUNCTION_ENTRY();
if (!child_node) {
+
/* It's really the parent's _scope_ that we want */
if (parent_node->child) {
@@ -92,6 +93,7 @@ struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type,
/* If any type is OK, we are done */
if (type == ACPI_TYPE_ANY) {
+
/* next_node is NULL if we are at the end-of-list */
return (next_node);
@@ -100,6 +102,7 @@ struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type,
/* Must search for the node -- but within this scope only */
while (next_node) {
+
/* If type matches, we are done */
if (next_node->type == type) {
@@ -161,7 +164,7 @@ acpi_ns_walk_namespace(acpi_object_type type,
acpi_object_type child_type;
u32 level;
- ACPI_FUNCTION_TRACE("ns_walk_namespace");
+ ACPI_FUNCTION_TRACE(ns_walk_namespace);
/* Special case for the namespace Root Node */
@@ -182,6 +185,7 @@ acpi_ns_walk_namespace(acpi_object_type type,
* bubbled up to (and passed) the original parent handle (start_entry)
*/
while (level > 0) {
+
/* Get the next node in this scope. Null if not found */
status = AE_OK;
diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
index a95f636..6d9bd45a 100644
--- a/drivers/acpi/namespace/nsxfeval.c
+++ b/drivers/acpi/namespace/nsxfeval.c
@@ -42,8 +42,6 @@
* POSSIBILITY OF SUCH DAMAGES.
*/
-#include <linux/module.h>
-
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
#include <acpi/acinterp.h>
@@ -51,6 +49,7 @@
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsxfeval")
+#ifdef ACPI_FUTURE_USAGE
/*******************************************************************************
*
* FUNCTION: acpi_evaluate_object_typed
@@ -71,18 +70,17 @@ ACPI_MODULE_NAME("nsxfeval")
* be valid (non-null)
*
******************************************************************************/
-#ifdef ACPI_FUTURE_USAGE
acpi_status
acpi_evaluate_object_typed(acpi_handle handle,
acpi_string pathname,
- struct acpi_object_list *external_params,
- struct acpi_buffer *return_buffer,
+ struct acpi_object_list * external_params,
+ struct acpi_buffer * return_buffer,
acpi_object_type return_type)
{
acpi_status status;
u8 must_free = FALSE;
- ACPI_FUNCTION_TRACE("acpi_evaluate_object_typed");
+ ACPI_FUNCTION_TRACE(acpi_evaluate_object_typed);
/* Return buffer must be valid */
@@ -110,6 +108,7 @@ acpi_evaluate_object_typed(acpi_handle handle,
}
if (return_buffer->length == 0) {
+
/* Error because caller specifically asked for a return value */
ACPI_ERROR((AE_INFO, "No return value"));
@@ -131,6 +130,7 @@ acpi_evaluate_object_typed(acpi_handle handle,
acpi_ut_get_type_name(return_type)));
if (must_free) {
+
/* Caller used ACPI_ALLOCATE_BUFFER, free the return buffer */
acpi_os_free(return_buffer->pointer);
@@ -140,6 +140,8 @@ acpi_evaluate_object_typed(acpi_handle handle,
return_buffer->length = 0;
return_ACPI_STATUS(AE_TYPE);
}
+
+ACPI_EXPORT_SYMBOL(acpi_evaluate_object_typed)
#endif /* ACPI_FUTURE_USAGE */
/*******************************************************************************
@@ -161,7 +163,6 @@ acpi_evaluate_object_typed(acpi_handle handle,
* be valid (non-null)
*
******************************************************************************/
-
acpi_status
acpi_evaluate_object(acpi_handle handle,
acpi_string pathname,
@@ -170,51 +171,61 @@ acpi_evaluate_object(acpi_handle handle,
{
acpi_status status;
acpi_status status2;
- struct acpi_parameter_info info;
+ struct acpi_evaluate_info *info;
acpi_size buffer_space_needed;
u32 i;
- ACPI_FUNCTION_TRACE("acpi_evaluate_object");
+ ACPI_FUNCTION_TRACE(acpi_evaluate_object);
- info.node = handle;
- info.parameters = NULL;
- info.return_object = NULL;
- info.parameter_type = ACPI_PARAM_ARGS;
+ /* Allocate and initialize the evaluation information block */
+
+ info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
+ if (!info) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ info->pathname = pathname;
+ info->parameter_type = ACPI_PARAM_ARGS;
+
+ /* Convert and validate the device handle */
+
+ info->prefix_node = acpi_ns_map_handle_to_node(handle);
+ if (!info->prefix_node) {
+ status = AE_BAD_PARAMETER;
+ goto cleanup;
+ }
/*
- * If there are parameters to be passed to the object
- * (which must be a control method), the external objects
- * must be converted to internal objects
+ * If there are parameters to be passed to a control method, the external
+ * objects must all be converted to internal objects
*/
if (external_params && external_params->count) {
/*
* Allocate a new parameter block for the internal objects
* Add 1 to count to allow for null terminated internal list
*/
- info.parameters = ACPI_MEM_CALLOCATE(((acpi_size)
- external_params->count +
- 1) * sizeof(void *));
- if (!info.parameters) {
- return_ACPI_STATUS(AE_NO_MEMORY);
+ info->parameters = ACPI_ALLOCATE_ZEROED(((acpi_size)
+ external_params->
+ count +
+ 1) * sizeof(void *));
+ if (!info->parameters) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
}
- /*
- * Convert each external object in the list to an
- * internal object
- */
+ /* Convert each external object in the list to an internal object */
+
for (i = 0; i < external_params->count; i++) {
status =
acpi_ut_copy_eobject_to_iobject(&external_params->
pointer[i],
- &info.
+ &info->
parameters[i]);
if (ACPI_FAILURE(status)) {
- acpi_ut_delete_internal_object_list(info.
- parameters);
- return_ACPI_STATUS(status);
+ goto cleanup;
}
}
- info.parameters[external_params->count] = NULL;
+ info->parameters[external_params->count] = NULL;
}
/*
@@ -224,43 +235,31 @@ acpi_evaluate_object(acpi_handle handle,
* 3) Valid handle
*/
if ((pathname) && (acpi_ns_valid_root_prefix(pathname[0]))) {
- /*
- * The path is fully qualified, just evaluate by name
- */
- status = acpi_ns_evaluate_by_name(pathname, &info);
+
+ /* The path is fully qualified, just evaluate by name */
+
+ info->prefix_node = NULL;
+ status = acpi_ns_evaluate(info);
} else if (!handle) {
/*
- * A handle is optional iff a fully qualified pathname
- * is specified. Since we've already handled fully
- * qualified names above, this is an error
+ * A handle is optional iff a fully qualified pathname is specified.
+ * Since we've already handled fully qualified names above, this is
+ * an error
*/
if (!pathname) {
- ACPI_ERROR((AE_INFO,
- "Both Handle and Pathname are NULL"));
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Both Handle and Pathname are NULL"));
} else {
- ACPI_ERROR((AE_INFO,
- "Handle is NULL and Pathname is relative"));
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Null Handle with relative pathname [%s]",
+ pathname));
}
status = AE_BAD_PARAMETER;
} else {
- /*
- * We get here if we have a handle -- and if we have a
- * pathname it is relative. The handle will be validated
- * in the lower procedures
- */
- if (!pathname) {
- /*
- * The null pathname case means the handle is for
- * the actual object to be evaluated
- */
- status = acpi_ns_evaluate_by_handle(&info);
- } else {
- /*
- * Both a Handle and a relative Pathname
- */
- status = acpi_ns_evaluate_relative(pathname, &info);
- }
+ /* We have a namespace a node and a possible relative path */
+
+ status = acpi_ns_evaluate(info);
}
/*
@@ -268,10 +267,10 @@ acpi_evaluate_object(acpi_handle handle,
* copy the return value to an external object.
*/
if (return_buffer) {
- if (!info.return_object) {
+ if (!info->return_object) {
return_buffer->length = 0;
} else {
- if (ACPI_GET_DESCRIPTOR_TYPE(info.return_object) ==
+ if (ACPI_GET_DESCRIPTOR_TYPE(info->return_object) ==
ACPI_DESC_TYPE_NAMED) {
/*
* If we received a NS Node as a return object, this means that
@@ -282,19 +281,19 @@ acpi_evaluate_object(acpi_handle handle,
* support for various types at a later date if necessary.
*/
status = AE_TYPE;
- info.return_object = NULL; /* No need to delete a NS Node */
+ info->return_object = NULL; /* No need to delete a NS Node */
return_buffer->length = 0;
}
if (ACPI_SUCCESS(status)) {
- /*
- * Find out how large a buffer is needed
- * to contain the returned object
- */
+
+ /* Get the size of the returned object */
+
status =
- acpi_ut_get_object_size(info.return_object,
+ acpi_ut_get_object_size(info->return_object,
&buffer_space_needed);
if (ACPI_SUCCESS(status)) {
+
/* Validate/Allocate/Clear caller buffer */
status =
@@ -303,7 +302,8 @@ acpi_evaluate_object(acpi_handle handle,
buffer_space_needed);
if (ACPI_FAILURE(status)) {
/*
- * Caller's buffer is too small or a new one can't be allocated
+ * Caller's buffer is too small or a new one can't
+ * be allocated
*/
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Needed buffer size %X, %s\n",
@@ -312,12 +312,11 @@ acpi_evaluate_object(acpi_handle handle,
acpi_format_exception
(status)));
} else {
- /*
- * We have enough space for the object, build it
- */
+ /* We have enough space for the object, build it */
+
status =
acpi_ut_copy_iobject_to_eobject
- (info.return_object,
+ (info->return_object,
return_buffer);
}
}
@@ -325,35 +324,37 @@ acpi_evaluate_object(acpi_handle handle,
}
}
- if (info.return_object) {
+ if (info->return_object) {
/*
- * Delete the internal return object. NOTE: Interpreter
- * must be locked to avoid race condition.
+ * Delete the internal return object. NOTE: Interpreter must be
+ * locked to avoid race condition.
*/
status2 = acpi_ex_enter_interpreter();
if (ACPI_SUCCESS(status2)) {
- /*
- * Delete the internal return object. (Or at least
- * decrement the reference count by one)
- */
- acpi_ut_remove_reference(info.return_object);
+
+ /* Remove one reference on the return object (should delete it) */
+
+ acpi_ut_remove_reference(info->return_object);
acpi_ex_exit_interpreter();
}
}
- /*
- * Free the input parameter list (if we created one),
- */
- if (info.parameters) {
+ cleanup:
+
+ /* Free the input parameter list (if we created one) */
+
+ if (info->parameters) {
+
/* Free the allocated parameter block */
- acpi_ut_delete_internal_object_list(info.parameters);
+ acpi_ut_delete_internal_object_list(info->parameters);
}
+ ACPI_FREE(info);
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_evaluate_object);
+ACPI_EXPORT_SYMBOL(acpi_evaluate_object)
/*******************************************************************************
*
@@ -384,7 +385,6 @@ EXPORT_SYMBOL(acpi_evaluate_object);
* function, etc.
*
******************************************************************************/
-
acpi_status
acpi_walk_namespace(acpi_object_type type,
acpi_handle start_object,
@@ -394,7 +394,7 @@ acpi_walk_namespace(acpi_object_type type,
{
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_walk_namespace");
+ ACPI_FUNCTION_TRACE(acpi_walk_namespace);
/* Parameter validation */
@@ -421,7 +421,7 @@ acpi_walk_namespace(acpi_object_type type,
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_walk_namespace);
+ACPI_EXPORT_SYMBOL(acpi_walk_namespace)
/*******************************************************************************
*
@@ -436,7 +436,6 @@ EXPORT_SYMBOL(acpi_walk_namespace);
* on that.
*
******************************************************************************/
-
static acpi_status
acpi_ns_get_device_callback(acpi_handle obj_handle,
u32 nesting_level,
@@ -473,6 +472,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
}
if (!(flags & ACPI_STA_DEVICE_PRESENT)) {
+
/* Don't examine children of the device if not present */
return (AE_CTRL_DEPTH);
@@ -489,6 +489,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
}
if (ACPI_STRNCMP(hid.value, info->hid, sizeof(hid.value)) != 0) {
+
/* Get the list of Compatible IDs */
status = acpi_ut_execute_CID(node, &cid);
@@ -505,11 +506,11 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
sizeof(struct
acpi_compatible_id)) !=
0) {
- ACPI_MEM_FREE(cid);
+ ACPI_FREE(cid);
return (AE_OK);
}
}
- ACPI_MEM_FREE(cid);
+ ACPI_FREE(cid);
}
}
@@ -551,7 +552,7 @@ acpi_get_devices(char *HID,
acpi_status status;
struct acpi_get_devices_info info;
- ACPI_FUNCTION_TRACE("acpi_get_devices");
+ ACPI_FUNCTION_TRACE(acpi_get_devices);
/* Parameter validation */
@@ -563,9 +564,9 @@ acpi_get_devices(char *HID,
* We're going to call their callback from OUR callback, so we need
* to know what it is, and their context parameter.
*/
+ info.hid = HID;
info.context = context;
info.user_function = user_function;
- info.hid = HID;
/*
* Lock the namespace around the walk.
@@ -578,9 +579,8 @@ acpi_get_devices(char *HID,
return_ACPI_STATUS(status);
}
- status = acpi_ns_walk_namespace(ACPI_TYPE_DEVICE,
- ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
- ACPI_NS_WALK_UNLOCK,
+ status = acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK,
acpi_ns_get_device_callback, &info,
return_value);
@@ -588,7 +588,7 @@ acpi_get_devices(char *HID,
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_get_devices);
+ACPI_EXPORT_SYMBOL(acpi_get_devices)
/*******************************************************************************
*
@@ -603,7 +603,6 @@ EXPORT_SYMBOL(acpi_get_devices);
* DESCRIPTION: Attach arbitrary data and handler to a namespace node.
*
******************************************************************************/
-
acpi_status
acpi_attach_data(acpi_handle obj_handle,
acpi_object_handler handler, void *data)
@@ -637,6 +636,8 @@ acpi_attach_data(acpi_handle obj_handle,
return (status);
}
+ACPI_EXPORT_SYMBOL(acpi_attach_data)
+
/*******************************************************************************
*
* FUNCTION: acpi_detach_data
@@ -649,7 +650,6 @@ acpi_attach_data(acpi_handle obj_handle,
* DESCRIPTION: Remove data that was previously attached to a node.
*
******************************************************************************/
-
acpi_status
acpi_detach_data(acpi_handle obj_handle, acpi_object_handler handler)
{
@@ -682,6 +682,8 @@ acpi_detach_data(acpi_handle obj_handle, acpi_object_handler handler)
return (status);
}
+ACPI_EXPORT_SYMBOL(acpi_detach_data)
+
/*******************************************************************************
*
* FUNCTION: acpi_get_data
@@ -695,7 +697,6 @@ acpi_detach_data(acpi_handle obj_handle, acpi_object_handler handler)
* DESCRIPTION: Retrieve data that was previously attached to a namespace node.
*
******************************************************************************/
-
acpi_status
acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data)
{
@@ -727,3 +728,5 @@ acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data)
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
return (status);
}
+
+ACPI_EXPORT_SYMBOL(acpi_get_data)
diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c
index 8cd8675..978213a 100644
--- a/drivers/acpi/namespace/nsxfname.c
+++ b/drivers/acpi/namespace/nsxfname.c
@@ -42,8 +42,6 @@
* POSSIBILITY OF SUCH DAMAGES.
*/
-#include <linux/module.h>
-
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
@@ -114,9 +112,8 @@ acpi_get_handle(acpi_handle parent,
/*
* Find the Node and convert to a handle
*/
- status =
- acpi_ns_get_node_by_path(pathname, prefix_node, ACPI_NS_NO_UPSEARCH,
- &node);
+ status = acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH,
+ &node);
*ret_handle = NULL;
if (ACPI_SUCCESS(status)) {
@@ -126,7 +123,7 @@ acpi_get_handle(acpi_handle parent,
return (status);
}
-EXPORT_SYMBOL(acpi_get_handle);
+ACPI_EXPORT_SYMBOL(acpi_get_handle)
/******************************************************************************
*
@@ -143,7 +140,6 @@ EXPORT_SYMBOL(acpi_get_handle);
* complementary functions.
*
******************************************************************************/
-
acpi_status
acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer)
{
@@ -162,6 +158,7 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer)
}
if (name_type == ACPI_FULL_PATHNAME) {
+
/* Get the full pathname (From the namespace root) */
status = acpi_ns_handle_to_pathname(handle, buffer);
@@ -203,7 +200,7 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer)
return (status);
}
-EXPORT_SYMBOL(acpi_get_name);
+ACPI_EXPORT_SYMBOL(acpi_get_name)
/******************************************************************************
*
@@ -219,7 +216,6 @@ EXPORT_SYMBOL(acpi_get_name);
* control methods (Such as in the case of a device.)
*
******************************************************************************/
-
acpi_status
acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer)
{
@@ -241,7 +237,7 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer)
return (status);
}
- info = ACPI_MEM_CALLOCATE(sizeof(struct acpi_device_info));
+ info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_device_info));
if (!info) {
return (AE_NO_MEMORY);
}
@@ -345,11 +341,11 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer)
}
cleanup:
- ACPI_MEM_FREE(info);
+ ACPI_FREE(info);
if (cid_list) {
- ACPI_MEM_FREE(cid_list);
+ ACPI_FREE(cid_list);
}
return (status);
}
-EXPORT_SYMBOL(acpi_get_object_info);
+ACPI_EXPORT_SYMBOL(acpi_get_object_info)
diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c
index a033259..a163e1d 100644
--- a/drivers/acpi/namespace/nsxfobj.c
+++ b/drivers/acpi/namespace/nsxfobj.c
@@ -42,8 +42,6 @@
* POSSIBILITY OF SUCH DAMAGES.
*/
-#include <linux/module.h>
-
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
@@ -101,7 +99,7 @@ acpi_status acpi_get_type(acpi_handle handle, acpi_object_type * ret_type)
return (status);
}
-EXPORT_SYMBOL(acpi_get_type);
+ACPI_EXPORT_SYMBOL(acpi_get_type)
/*******************************************************************************
*
@@ -116,7 +114,6 @@ EXPORT_SYMBOL(acpi_get_type);
* Handle.
*
******************************************************************************/
-
acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle)
{
struct acpi_namespace_node *node;
@@ -162,7 +159,7 @@ acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle)
return (status);
}
-EXPORT_SYMBOL(acpi_get_parent);
+ACPI_EXPORT_SYMBOL(acpi_get_parent)
/*******************************************************************************
*
@@ -181,7 +178,6 @@ EXPORT_SYMBOL(acpi_get_parent);
* Scope is returned.
*
******************************************************************************/
-
acpi_status
acpi_get_next_object(acpi_object_type type,
acpi_handle parent,
@@ -206,6 +202,7 @@ acpi_get_next_object(acpi_object_type type,
/* If null handle, use the parent */
if (!child) {
+
/* Start search at the beginning of the specified scope */
parent_node = acpi_ns_map_handle_to_node(parent);
@@ -242,4 +239,4 @@ acpi_get_next_object(acpi_object_type type,
return (status);
}
-EXPORT_SYMBOL(acpi_get_next_object);
+ACPI_EXPORT_SYMBOL(acpi_get_next_object)
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 64b98e8..e2c1a16 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -36,12 +36,60 @@
#define _COMPONENT ACPI_NUMA
ACPI_MODULE_NAME("numa")
+static nodemask_t nodes_found_map = NODE_MASK_NONE;
+#define PXM_INVAL -1
+#define NID_INVAL -1
+
+/* maps to convert between proximity domain and logical node ID */
+int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS]
+ = { [0 ... MAX_PXM_DOMAINS - 1] = NID_INVAL };
+int __cpuinitdata node_to_pxm_map[MAX_NUMNODES]
+ = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
+
extern int __init acpi_table_parse_madt_family(enum acpi_table_id id,
unsigned long madt_size,
int entry_id,
acpi_madt_entry_handler handler,
unsigned int max_entries);
+int __cpuinit pxm_to_node(int pxm)
+{
+ if (pxm < 0)
+ return NID_INVAL;
+ return pxm_to_node_map[pxm];
+}
+
+int __cpuinit node_to_pxm(int node)
+{
+ if (node < 0)
+ return PXM_INVAL;
+ return node_to_pxm_map[node];
+}
+
+int __cpuinit acpi_map_pxm_to_node(int pxm)
+{
+ int node = pxm_to_node_map[pxm];
+
+ if (node < 0){
+ if (nodes_weight(nodes_found_map) >= MAX_NUMNODES)
+ return NID_INVAL;
+ node = first_unset_node(nodes_found_map);
+ pxm_to_node_map[pxm] = node;
+ node_to_pxm_map[node] = pxm;
+ node_set(node, nodes_found_map);
+ }
+
+ return node;
+}
+
+void __cpuinit acpi_unmap_pxm_to_node(int node)
+{
+ int pxm = node_to_pxm_map[node];
+ pxm_to_node_map[pxm] = NID_INVAL;
+ node_to_pxm_map[node] = PXM_INVAL;
+ node_clear(node, nodes_found_map);
+}
+
void __init acpi_table_print_srat_entry(acpi_table_entry_header * header)
{
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 13b5fd5..1bb558a 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -37,6 +37,7 @@
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/nmi.h>
+#include <linux/kthread.h>
#include <acpi/acpi.h>
#include <asm/io.h>
#include <acpi/acpi_bus.h>
@@ -600,23 +601,41 @@ static void acpi_os_execute_deferred(void *context)
return_VOID;
}
-acpi_status
-acpi_os_queue_for_execution(u32 priority,
+static int acpi_os_execute_thread(void *context)
+{
+ struct acpi_os_dpc *dpc = (struct acpi_os_dpc *)context;
+ if (dpc) {
+ dpc->function(dpc->context);
+ kfree(dpc);
+ }
+ do_exit(0);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_os_execute
+ *
+ * PARAMETERS: Type - Type of the callback
+ * Function - Function to be executed
+ * Context - Function parameters
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Depending on type, either queues function for deferred execution or
+ * immediately executes function on a separate thread.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_os_execute(acpi_execute_type type,
acpi_osd_exec_callback function, void *context)
{
acpi_status status = AE_OK;
struct acpi_os_dpc *dpc;
struct work_struct *task;
-
- ACPI_FUNCTION_TRACE("os_queue_for_execution");
-
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Scheduling function [%p(%p)] for deferred execution.\n",
- function, context));
+ struct task_struct *p;
if (!function)
- return_ACPI_STATUS(AE_BAD_PARAMETER);
-
+ return AE_BAD_PARAMETER;
/*
* Allocate/initialize DPC structure. Note that this memory will be
* freed by the callee. The kernel handles the tq_struct list in a
@@ -627,30 +646,37 @@ acpi_os_queue_for_execution(u32 priority,
* We can save time and code by allocating the DPC and tq_structs
* from the same memory.
*/
-
- dpc =
- kmalloc(sizeof(struct acpi_os_dpc) + sizeof(struct work_struct),
- GFP_ATOMIC);
+ if (type == OSL_NOTIFY_HANDLER) {
+ dpc = kmalloc(sizeof(struct acpi_os_dpc), GFP_KERNEL);
+ } else {
+ dpc = kmalloc(sizeof(struct acpi_os_dpc) +
+ sizeof(struct work_struct), GFP_ATOMIC);
+ }
if (!dpc)
- return_ACPI_STATUS(AE_NO_MEMORY);
-
+ return AE_NO_MEMORY;
dpc->function = function;
dpc->context = context;
- task = (void *)(dpc + 1);
- INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc);
-
- if (!queue_work(kacpid_wq, task)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Call to queue_work() failed.\n"));
- kfree(dpc);
- status = AE_ERROR;
+ if (type == OSL_NOTIFY_HANDLER) {
+ p = kthread_create(acpi_os_execute_thread, dpc, "kacpid_notify");
+ if (!IS_ERR(p)) {
+ wake_up_process(p);
+ } else {
+ status = AE_NO_MEMORY;
+ kfree(dpc);
+ }
+ } else {
+ task = (void *)(dpc + 1);
+ INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc);
+ if (!queue_work(kacpid_wq, task)) {
+ status = AE_ERROR;
+ kfree(dpc);
+ }
}
-
- return_ACPI_STATUS(status);
+ return status;
}
-EXPORT_SYMBOL(acpi_os_queue_for_execution);
+EXPORT_SYMBOL(acpi_os_execute);
void acpi_os_wait_events_complete(void *context)
{
@@ -769,9 +795,6 @@ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout)
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n",
handle, units, timeout));
- if (in_atomic())
- timeout = 0;
-
switch (timeout) {
/*
* No Wait:
@@ -896,14 +919,6 @@ u8 acpi_os_writable(void *ptr, acpi_size len)
}
#endif
-u32 acpi_os_get_thread_id(void)
-{
- if (!in_atomic())
- return current->pid;
-
- return 0;
-}
-
acpi_status acpi_os_signal(u32 function, void *info)
{
switch (function) {
@@ -1050,12 +1065,12 @@ void acpi_os_release_lock(acpi_handle handle, acpi_cpu_flags flags)
*
* FUNCTION: acpi_os_create_cache
*
- * PARAMETERS: CacheName - Ascii name for the cache
- * ObjectSize - Size of each cached object
- * MaxDepth - Maximum depth of the cache (in objects)
- * ReturnCache - Where the new cache object is returned
+ * PARAMETERS: name - Ascii name for the cache
+ * size - Size of each cached object
+ * depth - Maximum depth of the cache (in objects) <ignored>
+ * cache - Where the new cache object is returned
*
- * RETURN: Status
+ * RETURN: status
*
* DESCRIPTION: Create a cache object
*
@@ -1065,7 +1080,10 @@ acpi_status
acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache)
{
*cache = kmem_cache_create(name, size, 0, 0, NULL, NULL);
- return AE_OK;
+ if (cache == NULL)
+ return AE_ERROR;
+ else
+ return AE_OK;
}
/*******************************************************************************
@@ -1134,16 +1152,63 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
*
* RETURN: Status
*
- * DESCRIPTION: Get an object from the specified cache. If cache is empty,
- * the object is allocated.
+ * DESCRIPTION: Return a zero-filled object.
*
******************************************************************************/
void *acpi_os_acquire_object(acpi_cache_t * cache)
{
- void *object = kmem_cache_alloc(cache, GFP_KERNEL);
+ void *object = kmem_cache_zalloc(cache, GFP_KERNEL);
WARN_ON(!object);
return object;
}
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_validate_interface
+ *
+ * PARAMETERS: interface - Requested interface to be validated
+ *
+ * RETURN: AE_OK if interface is supported, AE_SUPPORT otherwise
+ *
+ * DESCRIPTION: Match an interface string to the interfaces supported by the
+ * host. Strings originate from an AML call to the _OSI method.
+ *
+ *****************************************************************************/
+
+acpi_status
+acpi_os_validate_interface (char *interface)
+{
+
+ return AE_SUPPORT;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_os_validate_address
+ *
+ * PARAMETERS: space_id - ACPI space ID
+ * address - Physical address
+ * length - Address length
+ *
+ * RETURN: AE_OK if address/length is valid for the space_id. Otherwise,
+ * should return AE_AML_ILLEGAL_ADDRESS.
+ *
+ * DESCRIPTION: Validate a system address via the host OS. Used to validate
+ * the addresses accessed by AML operation regions.
+ *
+ *****************************************************************************/
+
+acpi_status
+acpi_os_validate_address (
+ u8 space_id,
+ acpi_physical_address address,
+ acpi_size length)
+{
+
+ return AE_OK;
+}
+
+
#endif
diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c
index de573be..bf88e07 100644
--- a/drivers/acpi/parser/psargs.c
+++ b/drivers/acpi/parser/psargs.c
@@ -79,7 +79,7 @@ acpi_ps_get_next_package_length(struct acpi_parse_state *parser_state)
acpi_native_uint byte_count;
u8 byte_zero_mask = 0x3F; /* Default [0:5] */
- ACPI_FUNCTION_TRACE("ps_get_next_package_length");
+ ACPI_FUNCTION_TRACE(ps_get_next_package_length);
/*
* Byte 0 bits [6:7] contain the number of additional bytes
@@ -128,7 +128,7 @@ u8 *acpi_ps_get_next_package_end(struct acpi_parse_state *parser_state)
u8 *start = parser_state->aml;
u32 package_length;
- ACPI_FUNCTION_TRACE("ps_get_next_package_end");
+ ACPI_FUNCTION_TRACE(ps_get_next_package_end);
/* Function below updates parser_state->Aml */
@@ -157,7 +157,7 @@ char *acpi_ps_get_next_namestring(struct acpi_parse_state *parser_state)
u8 *start = parser_state->aml;
u8 *end = parser_state->aml;
- ACPI_FUNCTION_TRACE("ps_get_next_namestring");
+ ACPI_FUNCTION_TRACE(ps_get_next_namestring);
/* Point past any namestring prefix characters (backslash or carat) */
@@ -237,7 +237,7 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state,
struct acpi_namespace_node *node;
union acpi_generic_state scope_info;
- ACPI_FUNCTION_TRACE("ps_get_next_namepath");
+ ACPI_FUNCTION_TRACE(ps_get_next_namepath);
path = acpi_ps_get_next_namestring(parser_state);
acpi_ps_init_op(arg, AML_INT_NAMEPATH_OP);
@@ -275,6 +275,7 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state,
*/
if (ACPI_SUCCESS(status) &&
possible_method_call && (node->type == ACPI_TYPE_METHOD)) {
+
/* This name is actually a control method invocation */
method_desc = acpi_ns_get_attached_object(node);
@@ -319,6 +320,7 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state,
* some not_found cases are allowed
*/
if (status == AE_NOT_FOUND) {
+
/* 1) not_found is ok during load pass 1/2 (allow forward references) */
if ((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) !=
@@ -354,6 +356,7 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state,
if ((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) ==
ACPI_PARSE_EXECUTE) {
+
/* Report a control method execution error */
status = acpi_ds_method_error(status, walk_state);
@@ -388,7 +391,7 @@ acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state,
u16 opcode;
u8 *aml = parser_state->aml;
- ACPI_FUNCTION_TRACE_U32("ps_get_next_simple_arg", arg_type);
+ ACPI_FUNCTION_TRACE_U32(ps_get_next_simple_arg, arg_type);
switch (arg_type) {
case ARGP_BYTEDATA:
@@ -453,7 +456,7 @@ acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state,
default:
- ACPI_ERROR((AE_INFO, "Invalid arg_type %X", arg_type));
+ ACPI_ERROR((AE_INFO, "Invalid ArgType %X", arg_type));
return_VOID;
}
@@ -484,7 +487,7 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state
u16 opcode;
u32 name;
- ACPI_FUNCTION_TRACE("ps_get_next_field");
+ ACPI_FUNCTION_TRACE(ps_get_next_field);
/* Determine field type */
@@ -590,7 +593,7 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
u32 subop;
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE_PTR("ps_get_next_arg", parser_state);
+ ACPI_FUNCTION_TRACE_PTR(ps_get_next_arg, parser_state);
switch (arg_type) {
case ARGP_BYTEDATA:
@@ -620,6 +623,7 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
case ARGP_FIELDLIST:
if (parser_state->aml < parser_state->pkg_end) {
+
/* Non-empty list */
while (parser_state->aml < parser_state->pkg_end) {
@@ -645,6 +649,7 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
case ARGP_BYTELIST:
if (parser_state->aml < parser_state->pkg_end) {
+
/* Non-empty list */
arg = acpi_ps_alloc_op(AML_INT_BYTELIST_OP);
@@ -673,6 +678,7 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
if (subop == 0 ||
acpi_ps_is_leading_char(subop) ||
acpi_ps_is_prefix_char(subop)) {
+
/* null_name or name_string */
arg = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP);
@@ -703,6 +709,7 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
case ARGP_OBJLIST:
if (parser_state->aml < parser_state->pkg_end) {
+
/* Non-empty list of variable arguments, nothing returned */
walk_state->arg_count = ACPI_VAR_ARGS;
@@ -711,7 +718,7 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
default:
- ACPI_ERROR((AE_INFO, "Invalid arg_type: %X", arg_type));
+ ACPI_ERROR((AE_INFO, "Invalid ArgType: %X", arg_type));
status = AE_AML_OPERAND_TYPE;
break;
}
diff --git a/drivers/acpi/parser/psloop.c b/drivers/acpi/parser/psloop.c
index 00b072e..e1541db 100644
--- a/drivers/acpi/parser/psloop.c
+++ b/drivers/acpi/parser/psloop.c
@@ -83,7 +83,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
struct acpi_parse_state *parser_state;
u8 *aml_op_start = NULL;
- ACPI_FUNCTION_TRACE_PTR("ps_parse_loop", walk_state);
+ ACPI_FUNCTION_TRACE_PTR(ps_parse_loop, walk_state);
if (walk_state->descending_callback == NULL) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -95,6 +95,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) {
+
/* We are restarting a preempted control method */
if (acpi_ps_has_completed_scope(parser_state)) {
@@ -128,7 +129,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
}
ACPI_EXCEPTION((AE_INFO, status,
- "get_predicate Failed"));
+ "GetPredicate Failed"));
return_ACPI_STATUS(status);
}
@@ -143,6 +144,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
"Popped scope, Op=%p\n", op));
} else if (walk_state->prev_op) {
+
/* We were in the middle of an op */
op = walk_state->prev_op;
@@ -156,6 +158,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
while ((parser_state->aml < parser_state->aml_end) || (op)) {
aml_op_start = parser_state->aml;
if (!op) {
+
/* Get the next opcode from the AML stream */
walk_state->aml_offset =
@@ -213,6 +216,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
/* Create Op structure and append to parent's argument list */
if (walk_state->op_info->flags & AML_NAMED) {
+
/* Allocate a new pre_op if necessary */
if (!pre_op) {
@@ -371,7 +375,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
if (walk_state->op_info) {
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "Opcode %4.4X [%s] Op %p Aml %p aml_offset %5.5X\n",
+ "Opcode %4.4X [%s] Op %p Aml %p AmlOffset %5.5X\n",
(u32) op->common.aml_opcode,
walk_state->op_info->name, op,
parser_state->aml,
@@ -388,6 +392,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
/* Are there any arguments that must be processed? */
if (walk_state->arg_types) {
+
/* Get arguments */
switch (op->common.aml_opcode) {
@@ -742,7 +747,19 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
if (ACPI_FAILURE(status2)) {
return_ACPI_STATUS(status2);
}
+
+ status2 =
+ acpi_ds_result_stack_pop
+ (walk_state);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
+ }
+
+ acpi_ut_delete_generic_state
+ (acpi_ut_pop_generic_state
+ (&walk_state->control_state));
}
+
acpi_ps_pop_scope(parser_state, &op,
&walk_state->arg_types,
&walk_state->arg_count);
@@ -762,6 +779,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
return_ACPI_STATUS(status2);
}
}
+
acpi_ps_pop_scope(parser_state, &op,
&walk_state->arg_types,
&walk_state->arg_count);
@@ -853,6 +871,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
}
else if (ACPI_FAILURE(status)) {
+
/* First error is most important */
(void)
diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c
index 11d6351..4bd25e3 100644
--- a/drivers/acpi/parser/psopcode.c
+++ b/drivers/acpi/parser/psopcode.c
@@ -725,12 +725,13 @@ static const u8 acpi_gbl_long_op_index[NUM_EXTENDED_OPCODE] = {
const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode)
{
- ACPI_FUNCTION_NAME("ps_get_opcode_info");
+ ACPI_FUNCTION_NAME(ps_get_opcode_info);
/*
* Detect normal 8-bit opcode or extended 16-bit opcode
*/
if (!(opcode & 0xFF00)) {
+
/* Simple (8-bit) opcode: 0-255, can't index beyond table */
return (&acpi_gbl_aml_op_info
@@ -739,6 +740,7 @@ const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode)
if (((opcode & 0xFF00) == AML_EXTENDED_OPCODE) &&
(((u8) opcode) <= MAX_EXTENDED_OPCODE)) {
+
/* Valid extended (16-bit) opcode */
return (&acpi_gbl_aml_op_info
@@ -779,7 +781,7 @@ char *acpi_ps_get_opcode_name(u16 opcode)
return (op->name);
#else
- return ("AE_NOT_CONFIGURED");
+ return ("OpcodeName unavailable");
#endif
}
diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c
index a9f3229..7ee2f2e 100644
--- a/drivers/acpi/parser/psparse.c
+++ b/drivers/acpi/parser/psparse.c
@@ -106,6 +106,7 @@ u16 acpi_ps_peek_opcode(struct acpi_parse_state * parser_state)
opcode = (u16) ACPI_GET8(aml);
if (opcode == AML_EXTENDED_OP_PREFIX) {
+
/* Extended opcode, get the second opcode byte */
aml++;
@@ -137,7 +138,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
const struct acpi_opcode_info *parent_info;
union acpi_parse_object *replacement_op = NULL;
- ACPI_FUNCTION_TRACE_PTR("ps_complete_this_op", op);
+ ACPI_FUNCTION_TRACE_PTR(ps_complete_this_op, op);
/* Check for null Op, can happen if AML code is corrupt */
@@ -158,6 +159,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
if (op->common.parent) {
prev = op->common.parent->common.value.arg;
if (!prev) {
+
/* Nothing more to do */
goto cleanup;
@@ -245,6 +247,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
/* We must unlink this op from the parent tree */
if (prev == op) {
+
/* This op is the first in the list */
if (replacement_op) {
@@ -265,6 +268,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
else
while (prev) {
+
/* Traverse all siblings in the parent's argument list */
next = prev->common.next;
@@ -329,7 +333,7 @@ acpi_ps_next_parse_state(struct acpi_walk_state *walk_state,
struct acpi_parse_state *parser_state = &walk_state->parser_state;
acpi_status status = AE_CTRL_PENDING;
- ACPI_FUNCTION_TRACE_PTR("ps_next_parse_state", op);
+ ACPI_FUNCTION_TRACE_PTR(ps_next_parse_state, op);
switch (callback_status) {
case AE_CTRL_TERMINATE:
@@ -449,10 +453,10 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
struct acpi_thread_state *prev_walk_list = acpi_gbl_current_walk_list;
struct acpi_walk_state *previous_walk_state;
- ACPI_FUNCTION_TRACE("ps_parse_aml");
+ ACPI_FUNCTION_TRACE(ps_parse_aml);
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "Entered with walk_state=%p Aml=%p size=%X\n",
+ "Entered with WalkState=%p Aml=%p size=%X\n",
walk_state, walk_state->parser_state.aml,
walk_state->parser_state.aml_size));
@@ -460,6 +464,7 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
thread = acpi_ut_create_thread_state();
if (!thread) {
+ acpi_ds_delete_walk_state(walk_state);
return_ACPI_STATUS(AE_NO_MEMORY);
}
@@ -510,6 +515,7 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
} else if (status == AE_CTRL_TERMINATE) {
status = AE_OK;
} else if ((status != AE_OK) && (walk_state->method_desc)) {
+
/* Either the method parse or actual execution failed */
ACPI_ERROR_METHOD("Method parse/execution failed",
@@ -550,20 +556,9 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
*/
if (((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) ==
ACPI_PARSE_EXECUTE) || (ACPI_FAILURE(status))) {
- if (walk_state->method_desc) {
- /* Decrement the thread count on the method parse tree */
-
- if (walk_state->method_desc->method.
- thread_count) {
- walk_state->method_desc->method.
- thread_count--;
- } else {
- ACPI_ERROR((AE_INFO,
- "Invalid zero thread count in method"));
- }
- }
-
- acpi_ds_terminate_control_method(walk_state);
+ acpi_ds_terminate_control_method(walk_state->
+ method_desc,
+ walk_state);
}
/* Delete this walk state and all linked control states */
@@ -572,7 +567,7 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
previous_walk_state = walk_state;
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "return_value=%p, implicit_value=%p State=%p\n",
+ "ReturnValue=%p, ImplicitValue=%p State=%p\n",
walk_state->return_desc,
walk_state->implicit_return_obj, walk_state));
@@ -633,12 +628,14 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
}
} else {
if (previous_walk_state->return_desc) {
+
/* Caller doesn't want it, must delete it */
acpi_ut_remove_reference(previous_walk_state->
return_desc);
}
if (previous_walk_state->implicit_return_obj) {
+
/* Caller doesn't want it, must delete it */
acpi_ut_remove_reference(previous_walk_state->
diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c
index bc6047c..a3e0314d 100644
--- a/drivers/acpi/parser/psscope.c
+++ b/drivers/acpi/parser/psscope.c
@@ -106,14 +106,14 @@ acpi_ps_init_scope(struct acpi_parse_state * parser_state,
{
union acpi_generic_state *scope;
- ACPI_FUNCTION_TRACE_PTR("ps_init_scope", root_op);
+ ACPI_FUNCTION_TRACE_PTR(ps_init_scope, root_op);
scope = acpi_ut_create_generic_state();
if (!scope) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
- scope->common.data_type = ACPI_DESC_TYPE_STATE_RPSCOPE;
+ scope->common.descriptor_type = ACPI_DESC_TYPE_STATE_RPSCOPE;
scope->parse_scope.op = root_op;
scope->parse_scope.arg_count = ACPI_VAR_ARGS;
scope->parse_scope.arg_end = parser_state->aml_end;
@@ -147,14 +147,14 @@ acpi_ps_push_scope(struct acpi_parse_state *parser_state,
{
union acpi_generic_state *scope;
- ACPI_FUNCTION_TRACE_PTR("ps_push_scope", op);
+ ACPI_FUNCTION_TRACE_PTR(ps_push_scope, op);
scope = acpi_ut_create_generic_state();
if (!scope) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
- scope->common.data_type = ACPI_DESC_TYPE_STATE_PSCOPE;
+ scope->common.descriptor_type = ACPI_DESC_TYPE_STATE_PSCOPE;
scope->parse_scope.op = op;
scope->parse_scope.arg_list = remaining_args;
scope->parse_scope.arg_count = arg_count;
@@ -165,6 +165,7 @@ acpi_ps_push_scope(struct acpi_parse_state *parser_state,
acpi_ut_push_generic_state(&parser_state->scope, scope);
if (arg_count == ACPI_VAR_ARGS) {
+
/* Multiple arguments */
scope->parse_scope.arg_end = parser_state->pkg_end;
@@ -199,14 +200,14 @@ acpi_ps_pop_scope(struct acpi_parse_state *parser_state,
{
union acpi_generic_state *scope = parser_state->scope;
- ACPI_FUNCTION_TRACE("ps_pop_scope");
+ ACPI_FUNCTION_TRACE(ps_pop_scope);
/* Only pop the scope if there is in fact a next scope */
if (scope->common.next) {
scope = acpi_ut_pop_generic_state(&parser_state->scope);
- /* return to parsing previous op */
+ /* Return to parsing previous op */
*op = scope->parse_scope.op;
*arg_list = scope->parse_scope.arg_list;
@@ -217,7 +218,7 @@ acpi_ps_pop_scope(struct acpi_parse_state *parser_state,
acpi_ut_delete_generic_state(scope);
} else {
- /* empty parse stack, prepare to fetch next opcode */
+ /* Empty parse stack, prepare to fetch next opcode */
*op = NULL;
*arg_list = 0;
@@ -246,7 +247,7 @@ void acpi_ps_cleanup_scope(struct acpi_parse_state *parser_state)
{
union acpi_generic_state *scope;
- ACPI_FUNCTION_TRACE_PTR("ps_cleanup_scope", parser_state);
+ ACPI_FUNCTION_TRACE_PTR(ps_cleanup_scope, parser_state);
if (!parser_state) {
return_VOID;
diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/parser/pstree.c
index dd6f167..0015717 100644
--- a/drivers/acpi/parser/pstree.c
+++ b/drivers/acpi/parser/pstree.c
@@ -77,6 +77,7 @@ union acpi_parse_object *acpi_ps_get_arg(union acpi_parse_object *op, u32 argn)
op_info = acpi_ps_get_opcode_info(op->common.aml_opcode);
if (op_info->class == AML_CLASS_UNKNOWN) {
+
/* Invalid opcode or ASCII character */
return (NULL);
@@ -85,6 +86,7 @@ union acpi_parse_object *acpi_ps_get_arg(union acpi_parse_object *op, u32 argn)
/* Check if this opcode requires argument sub-objects */
if (!(op_info->flags & AML_HAS_ARGS)) {
+
/* Has no linked argument objects */
return (NULL);
@@ -130,6 +132,7 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg)
op_info = acpi_ps_get_opcode_info(op->common.aml_opcode);
if (op_info->class == AML_CLASS_UNKNOWN) {
+
/* Invalid opcode */
ACPI_ERROR((AE_INFO, "Invalid AML Opcode: 0x%2.2X",
@@ -140,6 +143,7 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg)
/* Check if this opcode requires argument sub-objects */
if (!(op_info->flags & AML_HAS_ARGS)) {
+
/* Has no linked argument objects */
return;
@@ -148,6 +152,7 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg)
/* Append the argument to the linked argument list */
if (op->common.value.arg) {
+
/* Append to existing argument list */
prev_arg = op->common.value.arg;
@@ -222,12 +227,14 @@ union acpi_parse_object *acpi_ps_get_depth_next(union acpi_parse_object *origin,
}
if (arg == origin) {
+
/* Reached parent of origin, end search */
return (NULL);
}
if (parent->common.next) {
+
/* Found sibling of parent */
return (parent->common.next);
@@ -299,5 +306,4 @@ union acpi_parse_object *acpi_ps_get_child(union acpi_parse_object *op)
return (child);
}
#endif
-
#endif /* ACPI_FUTURE_USAGE */
diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c
index 3e07cb9..182474a 100644
--- a/drivers/acpi/parser/psutils.c
+++ b/drivers/acpi/parser/psutils.c
@@ -89,7 +89,7 @@ void acpi_ps_init_op(union acpi_parse_object *op, u16 opcode)
{
ACPI_FUNCTION_ENTRY();
- op->common.data_type = ACPI_DESC_TYPE_PARSER;
+ op->common.descriptor_type = ACPI_DESC_TYPE_PARSER;
op->common.aml_opcode = opcode;
ACPI_DISASM_ONLY_MEMBERS(ACPI_STRNCPY(op->common.aml_op_name,
@@ -135,6 +135,7 @@ union acpi_parse_object *acpi_ps_alloc_op(u16 opcode)
/* Allocate the minimum required size object */
if (flags == ACPI_PARSEOP_GENERIC) {
+
/* The generic op (default) is by far the most common (16 to 1) */
op = acpi_os_acquire_object(acpi_gbl_ps_node_cache);
@@ -171,7 +172,7 @@ union acpi_parse_object *acpi_ps_alloc_op(u16 opcode)
void acpi_ps_free_op(union acpi_parse_object *op)
{
- ACPI_FUNCTION_NAME("ps_free_op");
+ ACPI_FUNCTION_NAME(ps_free_op);
if (op->common.aml_opcode == AML_INT_RETURN_VALUE_OP) {
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Free retval op: %p\n",
diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/parser/pswalk.c
index 06f05bf..a84a547 100644
--- a/drivers/acpi/parser/pswalk.c
+++ b/drivers/acpi/parser/pswalk.c
@@ -64,18 +64,21 @@ void acpi_ps_delete_parse_tree(union acpi_parse_object *subtree_root)
union acpi_parse_object *next = NULL;
union acpi_parse_object *parent = NULL;
- ACPI_FUNCTION_TRACE_PTR("ps_delete_parse_tree", subtree_root);
+ ACPI_FUNCTION_TRACE_PTR(ps_delete_parse_tree, subtree_root);
/* Visit all nodes in the subtree */
while (op) {
+
/* Check if we are not ascending */
if (op != parent) {
+
/* Look for an argument or child of the current op */
next = acpi_ps_get_arg(op, 0);
if (next) {
+
/* Still going downward in tree (Op is not completed yet) */
op = next;
diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c
index 2dd48cb..5d996c1 100644
--- a/drivers/acpi/parser/psxface.c
+++ b/drivers/acpi/parser/psxface.c
@@ -50,14 +50,14 @@
ACPI_MODULE_NAME("psxface")
/* Local Prototypes */
-static void acpi_ps_start_trace(struct acpi_parameter_info *info);
+static void acpi_ps_start_trace(struct acpi_evaluate_info *info);
-static void acpi_ps_stop_trace(struct acpi_parameter_info *info);
+static void acpi_ps_stop_trace(struct acpi_evaluate_info *info);
-static acpi_status acpi_ps_execute_pass(struct acpi_parameter_info *info);
+static acpi_status acpi_ps_execute_pass(struct acpi_evaluate_info *info);
static void
-acpi_ps_update_parameter_list(struct acpi_parameter_info *info, u16 action);
+acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action);
/*******************************************************************************
*
@@ -113,7 +113,7 @@ acpi_debug_trace(char *name, u32 debug_level, u32 debug_layer, u32 flags)
*
******************************************************************************/
-static void acpi_ps_start_trace(struct acpi_parameter_info *info)
+static void acpi_ps_start_trace(struct acpi_evaluate_info *info)
{
acpi_status status;
@@ -125,7 +125,7 @@ static void acpi_ps_start_trace(struct acpi_parameter_info *info)
}
if ((!acpi_gbl_trace_method_name) ||
- (acpi_gbl_trace_method_name != info->node->name.integer)) {
+ (acpi_gbl_trace_method_name != info->resolved_node->name.integer)) {
goto exit;
}
@@ -158,7 +158,7 @@ static void acpi_ps_start_trace(struct acpi_parameter_info *info)
*
******************************************************************************/
-static void acpi_ps_stop_trace(struct acpi_parameter_info *info)
+static void acpi_ps_stop_trace(struct acpi_evaluate_info *info)
{
acpi_status status;
@@ -170,7 +170,7 @@ static void acpi_ps_stop_trace(struct acpi_parameter_info *info)
}
if ((!acpi_gbl_trace_method_name) ||
- (acpi_gbl_trace_method_name != info->node->name.integer)) {
+ (acpi_gbl_trace_method_name != info->resolved_node->name.integer)) {
goto exit;
}
@@ -212,22 +212,23 @@ static void acpi_ps_stop_trace(struct acpi_parameter_info *info)
*
******************************************************************************/
-acpi_status acpi_ps_execute_method(struct acpi_parameter_info *info)
+acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ps_execute_method");
+ ACPI_FUNCTION_TRACE(ps_execute_method);
/* Validate the Info and method Node */
- if (!info || !info->node) {
+ if (!info || !info->resolved_node) {
return_ACPI_STATUS(AE_NULL_ENTRY);
}
/* Init for new method, wait on concurrency semaphore */
status =
- acpi_ds_begin_method_execution(info->node, info->obj_desc, NULL);
+ acpi_ds_begin_method_execution(info->resolved_node, info->obj_desc,
+ NULL);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -248,7 +249,7 @@ acpi_status acpi_ps_execute_method(struct acpi_parameter_info *info)
*/
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
"**** Begin Method Parse **** Entry=%p obj=%p\n",
- info->node, info->obj_desc));
+ info->resolved_node, info->obj_desc));
info->pass_number = 1;
status = acpi_ps_execute_pass(info);
@@ -261,7 +262,7 @@ acpi_status acpi_ps_execute_method(struct acpi_parameter_info *info)
*/
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
"**** Begin Method Execution **** Entry=%p obj=%p\n",
- info->node, info->obj_desc));
+ info->resolved_node, info->obj_desc));
info->pass_number = 3;
status = acpi_ps_execute_pass(info);
@@ -286,8 +287,7 @@ acpi_status acpi_ps_execute_method(struct acpi_parameter_info *info)
* a control exception code
*/
if (info->return_object) {
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "Method returned obj_desc=%p\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Method returned ObjDesc=%p\n",
info->return_object));
ACPI_DUMP_STACK_ENTRY(info->return_object);
@@ -301,7 +301,7 @@ acpi_status acpi_ps_execute_method(struct acpi_parameter_info *info)
*
* FUNCTION: acpi_ps_update_parameter_list
*
- * PARAMETERS: Info - See struct acpi_parameter_info
+ * PARAMETERS: Info - See struct acpi_evaluate_info
* (Used: parameter_type and Parameters)
* Action - Add or Remove reference
*
@@ -312,14 +312,16 @@ acpi_status acpi_ps_execute_method(struct acpi_parameter_info *info)
******************************************************************************/
static void
-acpi_ps_update_parameter_list(struct acpi_parameter_info *info, u16 action)
+acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action)
{
acpi_native_uint i;
if ((info->parameter_type == ACPI_PARAM_ARGS) && (info->parameters)) {
+
/* Update reference count for each parameter */
for (i = 0; info->parameters[i]; i++) {
+
/* Ignore errors, just do them all */
(void)acpi_ut_update_object_reference(info->
@@ -333,7 +335,7 @@ acpi_ps_update_parameter_list(struct acpi_parameter_info *info, u16 action)
*
* FUNCTION: acpi_ps_execute_pass
*
- * PARAMETERS: Info - See struct acpi_parameter_info
+ * PARAMETERS: Info - See struct acpi_evaluate_info
* (Used: pass_number, Node, and obj_desc)
*
* RETURN: Status
@@ -342,13 +344,13 @@ acpi_ps_update_parameter_list(struct acpi_parameter_info *info, u16 action)
*
******************************************************************************/
-static acpi_status acpi_ps_execute_pass(struct acpi_parameter_info *info)
+static acpi_status acpi_ps_execute_pass(struct acpi_evaluate_info *info)
{
acpi_status status;
union acpi_parse_object *op;
struct acpi_walk_state *walk_state;
- ACPI_FUNCTION_TRACE("ps_execute_pass");
+ ACPI_FUNCTION_TRACE(ps_execute_pass);
/* Create and init a Root Node */
@@ -367,7 +369,7 @@ static acpi_status acpi_ps_execute_pass(struct acpi_parameter_info *info)
goto cleanup;
}
- status = acpi_ds_init_aml_walk(walk_state, op, info->node,
+ status = acpi_ds_init_aml_walk(walk_state, op, info->resolved_node,
info->obj_desc->method.aml_start,
info->obj_desc->method.aml_length,
info->pass_number == 1 ? NULL : info,
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 8920e8c..228bdb6 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -38,6 +38,7 @@
#include <linux/spinlock.h>
#include <linux/pm.h>
#include <linux/pci.h>
+#include <linux/mutex.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -91,7 +92,7 @@ static struct {
int count;
struct list_head entries;
} acpi_link;
-DECLARE_MUTEX(acpi_link_lock);
+DEFINE_MUTEX(acpi_link_lock);
/* --------------------------------------------------------------------------
PCI Link Device Management
@@ -641,19 +642,19 @@ acpi_pci_link_allocate_irq(acpi_handle handle,
return_VALUE(-1);
}
- down(&acpi_link_lock);
+ mutex_lock(&acpi_link_lock);
if (acpi_pci_link_allocate(link)) {
- up(&acpi_link_lock);
+ mutex_unlock(&acpi_link_lock);
return_VALUE(-1);
}
if (!link->irq.active) {
- up(&acpi_link_lock);
+ mutex_unlock(&acpi_link_lock);
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link active IRQ is 0!\n"));
return_VALUE(-1);
}
link->refcnt++;
- up(&acpi_link_lock);
+ mutex_unlock(&acpi_link_lock);
if (triggering)
*triggering = link->irq.triggering;
@@ -691,9 +692,9 @@ int acpi_pci_link_free_irq(acpi_handle handle)
return_VALUE(-1);
}
- down(&acpi_link_lock);
+ mutex_lock(&acpi_link_lock);
if (!link->irq.initialized) {
- up(&acpi_link_lock);
+ mutex_unlock(&acpi_link_lock);
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link isn't initialized\n"));
return_VALUE(-1);
}
@@ -716,7 +717,7 @@ int acpi_pci_link_free_irq(acpi_handle handle)
if (link->refcnt == 0) {
acpi_ut_evaluate_object(link->handle, "_DIS", 0, NULL);
}
- up(&acpi_link_lock);
+ mutex_unlock(&acpi_link_lock);
return_VALUE(link->irq.active);
}
@@ -747,7 +748,7 @@ static int acpi_pci_link_add(struct acpi_device *device)
strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS);
acpi_driver_data(device) = link;
- down(&acpi_link_lock);
+ mutex_lock(&acpi_link_lock);
result = acpi_pci_link_get_possible(link);
if (result)
goto end;
@@ -782,7 +783,7 @@ static int acpi_pci_link_add(struct acpi_device *device)
end:
/* disable all links -- to be activated on use */
acpi_ut_evaluate_object(link->handle, "_DIS", 0, NULL);
- up(&acpi_link_lock);
+ mutex_unlock(&acpi_link_lock);
if (result)
kfree(link);
@@ -840,9 +841,9 @@ static int acpi_pci_link_remove(struct acpi_device *device, int type)
link = (struct acpi_pci_link *)acpi_driver_data(device);
- down(&acpi_link_lock);
+ mutex_lock(&acpi_link_lock);
list_del(&link->node);
- up(&acpi_link_lock);
+ mutex_unlock(&acpi_link_lock);
kfree(link);
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 713b763..decaebb 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -110,7 +110,7 @@ static struct file_operations acpi_processor_info_fops = {
};
struct acpi_processor *processors[NR_CPUS];
-struct acpi_processor_errata errata;
+struct acpi_processor_errata errata __read_mostly;
/* --------------------------------------------------------------------------
Errata Handling
@@ -388,7 +388,7 @@ static int acpi_processor_remove_fs(struct acpi_device *device)
/* Use the acpiid in MADT to map cpus in case of SMP */
#ifndef CONFIG_SMP
-#define convert_acpiid_to_cpu(acpi_id) (0xff)
+#define convert_acpiid_to_cpu(acpi_id) (-1)
#else
#ifdef CONFIG_IA64
@@ -401,7 +401,7 @@ static int acpi_processor_remove_fs(struct acpi_device *device)
#define ARCH_BAD_APICID (0xff)
#endif
-static u8 convert_acpiid_to_cpu(u8 acpi_id)
+static int convert_acpiid_to_cpu(u8 acpi_id)
{
u16 apic_id;
int i;
@@ -427,7 +427,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
acpi_status status = 0;
union acpi_object object = { 0 };
struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
- u8 cpu_index;
+ int cpu_index;
static int cpu0_initialized;
ACPI_FUNCTION_TRACE("acpi_processor_get_info");
@@ -473,7 +473,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
cpu_index = convert_acpiid_to_cpu(pr->acpi_id);
/* Handle UP system running SMP kernel, with no LAPIC in MADT */
- if (!cpu0_initialized && (cpu_index == 0xff) &&
+ if (!cpu0_initialized && (cpu_index == -1) &&
(num_online_cpus() == 1)) {
cpu_index = 0;
}
@@ -487,7 +487,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
* less than the max # of CPUs. They should be ignored _iff
* they are physically not present.
*/
- if (cpu_index >= NR_CPUS) {
+ if (cpu_index == -1) {
if (ACPI_FAILURE
(acpi_processor_hotadd_init(pr->handle, &pr->id))) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
@@ -558,8 +558,8 @@ static int acpi_processor_start(struct acpi_device *device)
*/
if (processor_device_array[pr->id] != NULL &&
processor_device_array[pr->id] != (void *)device) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "BIOS reporting wrong ACPI id"
- "for the processor\n"));
+ printk(KERN_WARNING "BIOS reported wrong ACPI id"
+ "for the processor\n");
return_VALUE(-ENODEV);
}
processor_device_array[pr->id] = (void *)device;
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 80fa434..3b97a5e 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -54,10 +54,10 @@ ACPI_MODULE_NAME("acpi_processor")
#define US_TO_PM_TIMER_TICKS(t) ((t * (PM_TIMER_FREQUENCY/1000)) / 1000)
#define C2_OVERHEAD 4 /* 1us (3.579 ticks per us) */
#define C3_OVERHEAD 4 /* 1us (3.579 ticks per us) */
-static void (*pm_idle_save) (void);
+static void (*pm_idle_save) (void) __read_mostly;
module_param(max_cstate, uint, 0644);
-static unsigned int nocst = 0;
+static unsigned int nocst __read_mostly;
module_param(nocst, uint, 0000);
/*
@@ -67,7 +67,7 @@ module_param(nocst, uint, 0000);
* 100 HZ: 0x0000000F: 4 jiffies = 40ms
* reduce history for more aggressive entry into C3
*/
-static unsigned int bm_history =
+static unsigned int bm_history __read_mostly =
(HZ >= 800 ? 0xFFFFFFFF : ((1U << (HZ / 25)) - 1));
module_param(bm_history, uint, 0644);
/* --------------------------------------------------------------------------
@@ -1081,7 +1081,7 @@ int acpi_processor_power_init(struct acpi_processor *pr,
struct acpi_device *device)
{
acpi_status status = 0;
- static int first_run = 0;
+ static int first_run;
struct proc_dir_entry *entry = NULL;
unsigned int i;
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index f36db22..41aaaba 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -34,6 +34,7 @@
#ifdef CONFIG_X86_ACPI_CPUFREQ_PROC_INTF
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#endif
@@ -48,7 +49,7 @@
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("acpi_processor")
-static DECLARE_MUTEX(performance_sem);
+static DEFINE_MUTEX(performance_mutex);
/*
* _PPC support is implemented as a CPUfreq policy notifier:
@@ -72,7 +73,7 @@ static int acpi_processor_ppc_notifier(struct notifier_block *nb,
struct acpi_processor *pr;
unsigned int ppc = 0;
- down(&performance_sem);
+ mutex_lock(&performance_mutex);
if (event != CPUFREQ_INCOMPATIBLE)
goto out;
@@ -93,7 +94,7 @@ static int acpi_processor_ppc_notifier(struct notifier_block *nb,
core_frequency * 1000);
out:
- up(&performance_sem);
+ mutex_unlock(&performance_mutex);
return 0;
}
@@ -553,6 +554,230 @@ static void acpi_cpufreq_remove_file(struct acpi_processor *pr)
}
#endif /* CONFIG_X86_ACPI_CPUFREQ_PROC_INTF */
+static int acpi_processor_get_psd(struct acpi_processor *pr)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ struct acpi_buffer format = {sizeof("NNNNN"), "NNNNN"};
+ struct acpi_buffer state = {0, NULL};
+ union acpi_object *psd = NULL;
+ struct acpi_psd_package *pdomain;
+
+ status = acpi_evaluate_object(pr->handle, "_PSD", NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ return -ENODEV;
+ }
+
+ psd = (union acpi_object *) buffer.pointer;
+ if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
+ result = -EFAULT;
+ goto end;
+ }
+
+ if (psd->package.count != 1) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
+ result = -EFAULT;
+ goto end;
+ }
+
+ pdomain = &(pr->performance->domain_info);
+
+ state.length = sizeof(struct acpi_psd_package);
+ state.pointer = pdomain;
+
+ status = acpi_extract_package(&(psd->package.elements[0]),
+ &format, &state);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
+ result = -EFAULT;
+ goto end;
+ }
+
+ if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:num_entries\n"));
+ result = -EFAULT;
+ goto end;
+ }
+
+ if (pdomain->revision != ACPI_PSD_REV0_REVISION) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:revision\n"));
+ result = -EFAULT;
+ goto end;
+ }
+
+end:
+ acpi_os_free(buffer.pointer);
+ return result;
+}
+
+int acpi_processor_preregister_performance(
+ struct acpi_processor_performance **performance)
+{
+ int count, count_target;
+ int retval = 0;
+ unsigned int i, j;
+ cpumask_t covered_cpus;
+ struct acpi_processor *pr;
+ struct acpi_psd_package *pdomain;
+ struct acpi_processor *match_pr;
+ struct acpi_psd_package *match_pdomain;
+
+ mutex_lock(&performance_mutex);
+
+ retval = 0;
+
+ /* Call _PSD for all CPUs */
+ for_each_possible_cpu(i) {
+ pr = processors[i];
+ if (!pr) {
+ /* Look only at processors in ACPI namespace */
+ continue;
+ }
+
+ if (pr->performance) {
+ retval = -EBUSY;
+ continue;
+ }
+
+ if (!performance || !performance[i]) {
+ retval = -EINVAL;
+ continue;
+ }
+
+ pr->performance = performance[i];
+ cpu_set(i, pr->performance->shared_cpu_map);
+ if (acpi_processor_get_psd(pr)) {
+ retval = -EINVAL;
+ continue;
+ }
+ }
+ if (retval)
+ goto err_ret;
+
+ /*
+ * Now that we have _PSD data from all CPUs, lets setup P-state
+ * domain info.
+ */
+ for_each_possible_cpu(i) {
+ pr = processors[i];
+ if (!pr)
+ continue;
+
+ /* Basic validity check for domain info */
+ pdomain = &(pr->performance->domain_info);
+ if ((pdomain->revision != ACPI_PSD_REV0_REVISION) ||
+ (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES)) {
+ retval = -EINVAL;
+ goto err_ret;
+ }
+ if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL &&
+ pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY &&
+ pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) {
+ retval = -EINVAL;
+ goto err_ret;
+ }
+ }
+
+ cpus_clear(covered_cpus);
+ for_each_possible_cpu(i) {
+ pr = processors[i];
+ if (!pr)
+ continue;
+
+ if (cpu_isset(i, covered_cpus))
+ continue;
+
+ pdomain = &(pr->performance->domain_info);
+ cpu_set(i, pr->performance->shared_cpu_map);
+ cpu_set(i, covered_cpus);
+ if (pdomain->num_processors <= 1)
+ continue;
+
+ /* Validate the Domain info */
+ count_target = pdomain->num_processors;
+ count = 1;
+ if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL ||
+ pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL) {
+ pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL;
+ } else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY) {
+ pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ANY;
+ }
+
+ for_each_possible_cpu(j) {
+ if (i == j)
+ continue;
+
+ match_pr = processors[j];
+ if (!match_pr)
+ continue;
+
+ match_pdomain = &(match_pr->performance->domain_info);
+ if (match_pdomain->domain != pdomain->domain)
+ continue;
+
+ /* Here i and j are in the same domain */
+
+ if (match_pdomain->num_processors != count_target) {
+ retval = -EINVAL;
+ goto err_ret;
+ }
+
+ if (pdomain->coord_type != match_pdomain->coord_type) {
+ retval = -EINVAL;
+ goto err_ret;
+ }
+
+ cpu_set(j, covered_cpus);
+ cpu_set(j, pr->performance->shared_cpu_map);
+ count++;
+ }
+
+ for_each_possible_cpu(j) {
+ if (i == j)
+ continue;
+
+ match_pr = processors[j];
+ if (!match_pr)
+ continue;
+
+ match_pdomain = &(match_pr->performance->domain_info);
+ if (match_pdomain->domain != pdomain->domain)
+ continue;
+
+ match_pr->performance->shared_type =
+ pr->performance->shared_type;
+ match_pr->performance->shared_cpu_map =
+ pr->performance->shared_cpu_map;
+ }
+ }
+
+err_ret:
+ if (retval) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error while parsing _PSD domain information. Assuming no coordination\n"));
+ }
+
+ for_each_possible_cpu(i) {
+ pr = processors[i];
+ if (!pr || !pr->performance)
+ continue;
+
+ /* Assume no coordination on any error parsing domain info */
+ if (retval) {
+ cpus_clear(pr->performance->shared_cpu_map);
+ cpu_set(i, pr->performance->shared_cpu_map);
+ pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL;
+ }
+ pr->performance = NULL; /* Will be set for real in register */
+ }
+
+ mutex_unlock(&performance_mutex);
+ return retval;
+}
+EXPORT_SYMBOL(acpi_processor_preregister_performance);
+
+
int
acpi_processor_register_performance(struct acpi_processor_performance
*performance, unsigned int cpu)
@@ -564,16 +789,16 @@ acpi_processor_register_performance(struct acpi_processor_performance
if (!(acpi_processor_ppc_status & PPC_REGISTERED))
return_VALUE(-EINVAL);
- down(&performance_sem);
+ mutex_lock(&performance_mutex);
pr = processors[cpu];
if (!pr) {
- up(&performance_sem);
+ mutex_unlock(&performance_mutex);
return_VALUE(-ENODEV);
}
if (pr->performance) {
- up(&performance_sem);
+ mutex_unlock(&performance_mutex);
return_VALUE(-EBUSY);
}
@@ -583,13 +808,13 @@ acpi_processor_register_performance(struct acpi_processor_performance
if (acpi_processor_get_performance_info(pr)) {
pr->performance = NULL;
- up(&performance_sem);
+ mutex_unlock(&performance_mutex);
return_VALUE(-EIO);
}
acpi_cpufreq_add_file(pr);
- up(&performance_sem);
+ mutex_unlock(&performance_mutex);
return_VALUE(0);
}
@@ -603,11 +828,11 @@ acpi_processor_unregister_performance(struct acpi_processor_performance
ACPI_FUNCTION_TRACE("acpi_processor_unregister_performance");
- down(&performance_sem);
+ mutex_lock(&performance_mutex);
pr = processors[cpu];
if (!pr) {
- up(&performance_sem);
+ mutex_unlock(&performance_mutex);
return_VOID;
}
@@ -617,7 +842,7 @@ acpi_processor_unregister_performance(struct acpi_processor_performance
acpi_cpufreq_remove_file(pr);
- up(&performance_sem);
+ mutex_unlock(&performance_mutex);
return_VOID;
}
diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c
index 4038dbf..cf87b02 100644
--- a/drivers/acpi/resources/rscalc.c
+++ b/drivers/acpi/resources/rscalc.c
@@ -78,6 +78,7 @@ static u8 acpi_rs_count_set_bits(u16 bit_field)
ACPI_FUNCTION_ENTRY();
for (bits_set = 0; bit_field; bits_set++) {
+
/* Zero the least significant bit that is set */
bit_field &= (bit_field - 1);
@@ -154,15 +155,18 @@ acpi_rs_stream_option_length(u32 resource_length,
* length, minus one byte for the resource_source_index itself.
*/
if (resource_length > minimum_aml_resource_length) {
+
/* Compute the length of the optional string */
string_length =
resource_length - minimum_aml_resource_length - 1;
}
- /* Round up length to 32 bits for internal structure alignment */
-
- return (ACPI_ROUND_UP_to_32_bITS(string_length));
+ /*
+ * Round the length up to a multiple of the native word in order to
+ * guarantee that the entire resource descriptor is native word aligned
+ */
+ return ((u32) ACPI_ROUND_UP_TO_NATIVE_WORD(string_length));
}
/*******************************************************************************
@@ -186,11 +190,12 @@ acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed)
acpi_size aml_size_needed = 0;
acpi_rs_length total_size;
- ACPI_FUNCTION_TRACE("rs_get_aml_length");
+ ACPI_FUNCTION_TRACE(rs_get_aml_length);
/* Traverse entire list of internal resource descriptors */
while (resource) {
+
/* Validate the descriptor type */
if (resource->type > ACPI_RESOURCE_TYPE_MAX) {
@@ -214,6 +219,7 @@ acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed)
* is a Large Resource data type.
*/
if (resource->data.vendor.byte_length > 7) {
+
/* Base size of a Large resource descriptor */
total_size =
@@ -332,20 +338,22 @@ acpi_rs_get_list_length(u8 * aml_buffer,
acpi_status status;
u8 *end_aml;
u8 *buffer;
- u32 buffer_size = 0;
+ u32 buffer_size;
u16 temp16;
u16 resource_length;
u32 extra_struct_bytes;
u8 resource_index;
u8 minimum_aml_resource_length;
- ACPI_FUNCTION_TRACE("rs_get_list_length");
+ ACPI_FUNCTION_TRACE(rs_get_list_length);
+ *size_needed = 0;
end_aml = aml_buffer + aml_buffer_length;
/* Walk the list of AML resource descriptors */
while (aml_buffer < end_aml) {
+
/* Validate the Resource Type and Resource Length */
status = acpi_ut_validate_resource(aml_buffer, &resource_index);
@@ -386,35 +394,28 @@ acpi_rs_get_list_length(u8 * aml_buffer,
break;
case ACPI_RESOURCE_NAME_VENDOR_SMALL:
+ case ACPI_RESOURCE_NAME_VENDOR_LARGE:
/*
* Vendor Resource:
- * Ensure a 32-bit boundary for the structure
+ * Get the number of vendor data bytes
*/
- extra_struct_bytes =
- ACPI_ROUND_UP_to_32_bITS(resource_length);
+ extra_struct_bytes = resource_length;
break;
case ACPI_RESOURCE_NAME_END_TAG:
/*
- * End Tag: This is the normal exit, add size of end_tag
+ * End Tag:
+ * This is the normal exit, add size of end_tag
*/
- *size_needed = buffer_size + ACPI_RS_SIZE_MIN;
+ *size_needed += ACPI_RS_SIZE_MIN;
return_ACPI_STATUS(AE_OK);
- case ACPI_RESOURCE_NAME_VENDOR_LARGE:
- /*
- * Vendor Resource:
- * Add vendor data and ensure a 32-bit boundary for the structure
- */
- extra_struct_bytes =
- ACPI_ROUND_UP_to_32_bITS(resource_length);
- break;
-
case ACPI_RESOURCE_NAME_ADDRESS32:
case ACPI_RESOURCE_NAME_ADDRESS16:
+ case ACPI_RESOURCE_NAME_ADDRESS64:
/*
- * 32-Bit or 16-bit Address Resource:
- * Add the size of any optional data (resource_source)
+ * Address Resource:
+ * Add the size of the optional resource_source
*/
extra_struct_bytes =
acpi_rs_stream_option_length(resource_length,
@@ -423,50 +424,46 @@ acpi_rs_get_list_length(u8 * aml_buffer,
case ACPI_RESOURCE_NAME_EXTENDED_IRQ:
/*
- * Extended IRQ:
- * Point past the interrupt_vector_flags to get the
- * interrupt_table_length.
+ * Extended IRQ Resource:
+ * Using the interrupt_table_length, add 4 bytes for each additional
+ * interrupt. Note: at least one interrupt is required and is
+ * included in the minimum descriptor size (reason for the -1)
*/
- buffer++;
+ extra_struct_bytes = (buffer[1] - 1) * sizeof(u32);
- extra_struct_bytes =
- /*
- * Add 4 bytes for each additional interrupt. Note: at
- * least one interrupt is required and is included in
- * the minimum descriptor size
- */
- ((*buffer - 1) * sizeof(u32)) +
- /* Add the size of any optional data (resource_source) */
+ /* Add the size of the optional resource_source */
+
+ extra_struct_bytes +=
acpi_rs_stream_option_length(resource_length -
extra_struct_bytes,
minimum_aml_resource_length);
break;
- case ACPI_RESOURCE_NAME_ADDRESS64:
- /*
- * 64-Bit Address Resource:
- * Add the size of any optional data (resource_source)
- * Ensure a 64-bit boundary for the structure
- */
- extra_struct_bytes =
- ACPI_ROUND_UP_to_64_bITS
- (acpi_rs_stream_option_length
- (resource_length, minimum_aml_resource_length));
- break;
-
default:
break;
}
- /* Update the required buffer size for the internal descriptor structs */
+ /*
+ * Update the required buffer size for the internal descriptor structs
+ *
+ * Important: Round the size up for the appropriate alignment. This
+ * is a requirement on IA64.
+ */
+ buffer_size = acpi_gbl_resource_struct_sizes[resource_index] +
+ extra_struct_bytes;
+ buffer_size = (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(buffer_size);
- temp16 = (u16) (acpi_gbl_resource_struct_sizes[resource_index] +
- extra_struct_bytes);
- buffer_size += (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(temp16);
+ *size_needed += buffer_size;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
+ "Type %.2X, AmlLength %.2X InternalLength %.2X\n",
+ acpi_ut_get_resource_type(aml_buffer),
+ acpi_ut_get_descriptor_length(aml_buffer),
+ buffer_size));
/*
- * Point to the next resource within the stream
- * using the size of the header plus the length contained in the header
+ * Point to the next resource within the AML stream using the length
+ * contained in the resource descriptor header
*/
aml_buffer += acpi_ut_get_descriptor_length(aml_buffer);
}
@@ -506,7 +503,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
u8 name_found;
u32 table_index;
- ACPI_FUNCTION_TRACE("rs_get_pci_routing_table_length");
+ ACPI_FUNCTION_TRACE(rs_get_pci_routing_table_length);
number_of_elements = package_object->package.count;
@@ -523,6 +520,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
top_object_list = package_object->package.elements;
for (index = 0; index < number_of_elements; index++) {
+
/* Dereference the sub-package */
package_element = *top_object_list;
@@ -581,7 +579,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
/* Round up the size since each element must be aligned */
- temp_size_needed = ACPI_ROUND_UP_to_64_bITS(temp_size_needed);
+ temp_size_needed = ACPI_ROUND_UP_TO_64BIT(temp_size_needed);
/* Point to the next union acpi_operand_object */
@@ -589,7 +587,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
}
/*
- * Adding an extra element to the end of the list, essentially a
+ * Add an extra element to the end of the list, essentially a
* NULL terminator
*/
*buffer_size_needed =
diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c
index 8c128de..008058a 100644
--- a/drivers/acpi/resources/rscreate.c
+++ b/drivers/acpi/resources/rscreate.c
@@ -75,10 +75,11 @@ acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer,
u8 *aml_start;
acpi_size list_size_needed = 0;
u32 aml_buffer_length;
+ void *resource;
- ACPI_FUNCTION_TRACE("rs_create_resource_list");
+ ACPI_FUNCTION_TRACE(rs_create_resource_list);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "aml_buffer = %p\n", aml_buffer));
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AmlBuffer = %p\n", aml_buffer));
/* Params already validated, so we don't re-validate here */
@@ -92,7 +93,7 @@ acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer,
status = acpi_rs_get_list_length(aml_start, aml_buffer_length,
&list_size_needed);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Status=%X list_size_needed=%X\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Status=%X ListSizeNeeded=%X\n",
status, (u32) list_size_needed));
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
@@ -107,13 +108,15 @@ acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer,
/* Do the conversion */
- status = acpi_rs_convert_aml_to_resources(aml_start, aml_buffer_length,
- output_buffer->pointer);
+ resource = output_buffer->pointer;
+ status = acpi_ut_walk_aml_resources(aml_start, aml_buffer_length,
+ acpi_rs_convert_aml_to_resources,
+ &resource);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "output_buffer %p Length %X\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "OutputBuffer %p Length %X\n",
output_buffer->pointer, (u32) output_buffer->length));
return_ACPI_STATUS(AE_OK);
}
@@ -155,7 +158,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
acpi_status status;
struct acpi_buffer path_buffer;
- ACPI_FUNCTION_TRACE("rs_create_pci_routing_table");
+ ACPI_FUNCTION_TRACE(rs_create_pci_routing_table);
/* Params already validated, so we don't re-validate here */
@@ -167,7 +170,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
return_ACPI_STATUS(status);
}
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "buffer_size_needed = %X\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "BufferSizeNeeded = %X\n",
(u32) buffer_size_needed));
/* Validate/Allocate/Clear caller buffer */
@@ -332,7 +335,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
/* Now align the current length */
user_prt->length =
- (u32) ACPI_ROUND_UP_to_64_bITS(user_prt->length);
+ (u32) ACPI_ROUND_UP_TO_64BIT(user_prt->length);
/* 4) Fourth subobject: Dereference the PRT.source_index */
@@ -341,7 +344,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
user_prt->source_index = (u32) obj_desc->integer.value;
} else {
ACPI_ERROR((AE_INFO,
- "(PRT[%X].source_index) Need Integer, found %s",
+ "(PRT[%X].SourceIndex) Need Integer, found %s",
index,
acpi_ut_get_object_type_name(obj_desc)));
return_ACPI_STATUS(AE_BAD_DATA);
@@ -352,7 +355,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
top_object_list++;
}
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "output_buffer %p Length %X\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "OutputBuffer %p Length %X\n",
output_buffer->pointer, (u32) output_buffer->length));
return_ACPI_STATUS(AE_OK);
}
@@ -382,9 +385,9 @@ acpi_rs_create_aml_resources(struct acpi_resource *linked_list_buffer,
acpi_status status;
acpi_size aml_size_needed = 0;
- ACPI_FUNCTION_TRACE("rs_create_aml_resources");
+ ACPI_FUNCTION_TRACE(rs_create_aml_resources);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "linked_list_buffer = %p\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "LinkedListBuffer = %p\n",
linked_list_buffer));
/*
@@ -395,7 +398,7 @@ acpi_rs_create_aml_resources(struct acpi_resource *linked_list_buffer,
*/
status = acpi_rs_get_aml_length(linked_list_buffer, &aml_size_needed);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "aml_size_needed=%X, %s\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AmlSizeNeeded=%X, %s\n",
(u32) aml_size_needed,
acpi_format_exception(status)));
if (ACPI_FAILURE(status)) {
@@ -419,7 +422,7 @@ acpi_rs_create_aml_resources(struct acpi_resource *linked_list_buffer,
return_ACPI_STATUS(status);
}
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "output_buffer %p Length %X\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "OutputBuffer %p Length %X\n",
output_buffer->pointer, (u32) output_buffer->length));
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c
index e7de061..9c99a72 100644
--- a/drivers/acpi/resources/rsdump.c
+++ b/drivers/acpi/resources/rsdump.c
@@ -91,11 +91,11 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table);
struct acpi_rsdump_info acpi_rs_dump_irq[6] = {
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_irq), "IRQ", NULL},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.triggering), "Triggering",
- acpi_gbl_HEdecode},
+ acpi_gbl_he_decode},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.polarity), "Polarity",
- acpi_gbl_LLdecode},
+ acpi_gbl_ll_decode},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.sharable), "Sharing",
- acpi_gbl_SHRdecode},
+ acpi_gbl_shr_decode},
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(irq.interrupt_count),
"Interrupt Count", NULL},
{ACPI_RSD_SHORTLIST, ACPI_RSD_OFFSET(irq.interrupts[0]),
@@ -105,11 +105,11 @@ struct acpi_rsdump_info acpi_rs_dump_irq[6] = {
struct acpi_rsdump_info acpi_rs_dump_dma[6] = {
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_dma), "DMA", NULL},
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(dma.type), "Speed",
- acpi_gbl_TYPdecode},
+ acpi_gbl_typ_decode},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(dma.bus_master), "Mastering",
- acpi_gbl_BMdecode},
+ acpi_gbl_bm_decode},
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(dma.transfer), "Transfer Type",
- acpi_gbl_SIZdecode},
+ acpi_gbl_siz_decode},
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(dma.channel_count), "Channel Count",
NULL},
{ACPI_RSD_SHORTLIST, ACPI_RSD_OFFSET(dma.channels[0]), "Channel List",
@@ -158,7 +158,7 @@ struct acpi_rsdump_info acpi_rs_dump_vendor[3] = {
};
struct acpi_rsdump_info acpi_rs_dump_end_tag[1] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_end_tag), "end_tag",
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_end_tag), "EndTag",
NULL}
};
@@ -166,7 +166,7 @@ struct acpi_rsdump_info acpi_rs_dump_memory24[6] = {
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_memory24),
"24-Bit Memory Range", NULL},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(memory24.write_protect),
- "Write Protect", acpi_gbl_RWdecode},
+ "Write Protect", acpi_gbl_rw_decode},
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.minimum), "Address Minimum",
NULL},
{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.maximum), "Address Maximum",
@@ -181,7 +181,7 @@ struct acpi_rsdump_info acpi_rs_dump_memory32[6] = {
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_memory32),
"32-Bit Memory Range", NULL},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(memory32.write_protect),
- "Write Protect", acpi_gbl_RWdecode},
+ "Write Protect", acpi_gbl_rw_decode},
{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.minimum), "Address Minimum",
NULL},
{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.maximum), "Address Maximum",
@@ -196,7 +196,7 @@ struct acpi_rsdump_info acpi_rs_dump_fixed_memory32[4] = {
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_memory32),
"32-Bit Fixed Memory Range", NULL},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(fixed_memory32.write_protect),
- "Write Protect", acpi_gbl_RWdecode},
+ "Write Protect", acpi_gbl_rw_decode},
{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(fixed_memory32.address), "Address",
NULL},
{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(fixed_memory32.address_length),
@@ -278,11 +278,11 @@ struct acpi_rsdump_info acpi_rs_dump_ext_irq[8] = {
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.producer_consumer),
"Type", acpi_gbl_consume_decode},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.triggering),
- "Triggering", acpi_gbl_HEdecode},
+ "Triggering", acpi_gbl_he_decode},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.polarity), "Polarity",
- acpi_gbl_LLdecode},
+ acpi_gbl_ll_decode},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.sharable), "Sharing",
- acpi_gbl_SHRdecode},
+ acpi_gbl_shr_decode},
{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(extended_irq.resource_source), NULL,
NULL},
{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(extended_irq.interrupt_count),
@@ -314,7 +314,7 @@ static struct acpi_rsdump_info acpi_rs_dump_general_flags[5] = {
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.producer_consumer),
"Consumer/Producer", acpi_gbl_consume_decode},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.decode), "Address Decode",
- acpi_gbl_DECdecode},
+ acpi_gbl_dec_decode},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.min_address_fixed),
"Min Relocatability", acpi_gbl_min_decode},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.max_address_fixed),
@@ -325,24 +325,24 @@ static struct acpi_rsdump_info acpi_rs_dump_memory_flags[5] = {
{ACPI_RSD_LITERAL, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_memory_flags),
"Resource Type", (void *)"Memory Range"},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.mem.write_protect),
- "Write Protect", acpi_gbl_RWdecode},
+ "Write Protect", acpi_gbl_rw_decode},
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(address.info.mem.caching),
- "Caching", acpi_gbl_MEMdecode},
+ "Caching", acpi_gbl_mem_decode},
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(address.info.mem.range_type),
- "Range Type", acpi_gbl_MTPdecode},
+ "Range Type", acpi_gbl_mtp_decode},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.mem.translation),
- "Translation", acpi_gbl_TTPdecode}
+ "Translation", acpi_gbl_ttp_decode}
};
static struct acpi_rsdump_info acpi_rs_dump_io_flags[4] = {
{ACPI_RSD_LITERAL, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_io_flags),
"Resource Type", (void *)"I/O Range"},
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(address.info.io.range_type),
- "Range Type", acpi_gbl_RNGdecode},
+ "Range Type", acpi_gbl_rng_decode},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.io.translation),
- "Translation", acpi_gbl_TTPdecode},
+ "Translation", acpi_gbl_ttp_decode},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.io.translation_type),
- "Translation Type", acpi_gbl_TRSdecode}
+ "Translation Type", acpi_gbl_trs_decode}
};
/*
diff --git a/drivers/acpi/resources/rsinfo.c b/drivers/acpi/resources/rsinfo.c
index d9ae64b..9e7ae2f 100644
--- a/drivers/acpi/resources/rsinfo.c
+++ b/drivers/acpi/resources/rsinfo.c
@@ -141,6 +141,7 @@ struct acpi_rsdump_info *acpi_gbl_dump_resource_dispatch[] = {
acpi_rs_dump_generic_reg, /* ACPI_RESOURCE_TYPE_GENERIC_REGISTER */
};
#endif
+
#endif /* ACPI_FUTURE_USAGE */
/*
* Base sizes for external AML resource descriptors, indexed by internal type.
diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c
index 1434e78..29423ce 100644
--- a/drivers/acpi/resources/rslist.c
+++ b/drivers/acpi/resources/rslist.c
@@ -51,76 +51,62 @@ ACPI_MODULE_NAME("rslist")
*
* FUNCTION: acpi_rs_convert_aml_to_resources
*
- * PARAMETERS: Aml - Pointer to the resource byte stream
- * aml_length - Length of Aml
- * output_buffer - Pointer to the buffer that will
- * contain the output structures
+ * PARAMETERS: acpi_walk_aml_callback
+ * resource_ptr - Pointer to the buffer that will
+ * contain the output structures
*
* RETURN: Status
*
- * DESCRIPTION: Takes the resource byte stream and parses it, creating a
- * linked list of resources in the caller's output buffer
+ * DESCRIPTION: Convert an AML resource to an internal representation of the
+ * resource that is aligned and easier to access.
*
******************************************************************************/
acpi_status
-acpi_rs_convert_aml_to_resources(u8 * aml, u32 aml_length, u8 * output_buffer)
+acpi_rs_convert_aml_to_resources(u8 * aml,
+ u32 length,
+ u32 offset, u8 resource_index, void **context)
{
- struct acpi_resource *resource = (void *)output_buffer;
+ struct acpi_resource **resource_ptr =
+ ACPI_CAST_INDIRECT_PTR(struct acpi_resource, context);
+ struct acpi_resource *resource;
acpi_status status;
- u8 resource_index;
- u8 *end_aml;
-
- ACPI_FUNCTION_TRACE("rs_convert_aml_to_resources");
-
- end_aml = aml + aml_length;
-
- /* Loop until end-of-buffer or an end_tag is found */
-
- while (aml < end_aml) {
- /* Validate the Resource Type and Resource Length */
-
- status = acpi_ut_validate_resource(aml, &resource_index);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- /* Convert the AML byte stream resource to a local resource struct */
-
- status =
- acpi_rs_convert_aml_to_resource(resource,
- ACPI_CAST_PTR(union
- aml_resource,
- aml),
- acpi_gbl_get_resource_dispatch
- [resource_index]);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not convert AML resource (Type %X)",
- *aml));
- return_ACPI_STATUS(status);
- }
+ ACPI_FUNCTION_TRACE(rs_convert_aml_to_resources);
- /* Normal exit on completion of an end_tag resource descriptor */
-
- if (acpi_ut_get_resource_type(aml) ==
- ACPI_RESOURCE_NAME_END_TAG) {
- return_ACPI_STATUS(AE_OK);
- }
-
- /* Point to the next input AML resource */
-
- aml += acpi_ut_get_descriptor_length(aml);
-
- /* Point to the next structure in the output buffer */
+ /*
+ * Check that the input buffer and all subsequent pointers into it
+ * are aligned on a native word boundary. Most important on IA64
+ */
+ resource = *resource_ptr;
+ if (ACPI_IS_MISALIGNED(resource)) {
+ ACPI_WARNING((AE_INFO,
+ "Misaligned resource pointer %p", resource));
+ }
- resource =
- ACPI_ADD_PTR(struct acpi_resource, resource,
- resource->length);
+ /* Convert the AML byte stream resource to a local resource struct */
+
+ status =
+ acpi_rs_convert_aml_to_resource(resource,
+ ACPI_CAST_PTR(union aml_resource,
+ aml),
+ acpi_gbl_get_resource_dispatch
+ [resource_index]);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Could not convert AML resource (Type %X)",
+ *aml));
+ return_ACPI_STATUS(status);
}
- /* Did not find an end_tag resource descriptor */
+ ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
+ "Type %.2X, AmlLength %.2X InternalLength %.2X\n",
+ acpi_ut_get_resource_type(aml), length,
+ resource->length));
- return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
+ /* Point to the next structure in the output buffer */
+
+ *resource_ptr = ACPI_ADD_PTR(void, resource, resource->length);
+ return_ACPI_STATUS(AE_OK);
}
/*******************************************************************************
@@ -150,11 +136,12 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource,
u8 *end_aml = output_buffer + aml_size_needed;
acpi_status status;
- ACPI_FUNCTION_TRACE("rs_convert_resources_to_aml");
+ ACPI_FUNCTION_TRACE(rs_convert_resources_to_aml);
/* Walk the resource descriptor list, convert each descriptor */
while (aml < end_aml) {
+
/* Validate the (internal) Resource Type */
if (resource->type > ACPI_RESOURCE_TYPE_MAX) {
@@ -191,6 +178,7 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource,
/* Check for end-of-list, normal exit */
if (resource->type == ACPI_RESOURCE_TYPE_END_TAG) {
+
/* An End Tag indicates the end of the input Resource Template */
return_ACPI_STATUS(AE_OK);
diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c
index ed866cf..faf6e10 100644
--- a/drivers/acpi/resources/rsmisc.c
+++ b/drivers/acpi/resources/rsmisc.c
@@ -81,9 +81,10 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
u16 item_count = 0;
u16 temp16 = 0;
- ACPI_FUNCTION_TRACE("rs_get_resource");
+ ACPI_FUNCTION_TRACE(rs_convert_aml_to_resource);
if (((acpi_native_uint) resource) & 0x3) {
+
/* Each internal resource struct is expected to be 32-bit aligned */
ACPI_WARNING((AE_INFO,
@@ -295,9 +296,11 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
exit:
if (!flags_mode) {
- /* Round the resource struct length up to the next 32-bit boundary */
- resource->length = ACPI_ROUND_UP_to_32_bITS(resource->length);
+ /* Round the resource struct length up to the next boundary (32 or 64) */
+
+ resource->length =
+ (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(resource->length);
}
return_ACPI_STATUS(AE_OK);
}
@@ -329,7 +332,7 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource,
u16 temp16 = 0;
u16 item_count = 0;
- ACPI_FUNCTION_TRACE("rs_convert_resource_to_aml");
+ ACPI_FUNCTION_TRACE(rs_convert_resource_to_aml);
/*
* First table entry must be ACPI_RSC_INITxxx and must contain the
@@ -535,6 +538,7 @@ if (((aml->irq.flags & 0x09) == 0x00) || ((aml->irq.flags & 0x09) == 0x09)) {
resource->data.extended_irq.interrupt_count = temp8;
if (temp8 < 1) {
+
/* Must have at least one IRQ */
return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH);
diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c
index 25b5aed..a9cbee8 100644
--- a/drivers/acpi/resources/rsutils.c
+++ b/drivers/acpi/resources/rsutils.c
@@ -205,6 +205,7 @@ acpi_rs_set_resource_length(acpi_rsdesc_size total_length,
/* Length is stored differently for large and small descriptors */
if (aml->small_header.descriptor_type & ACPI_RESOURCE_NAME_LARGE) {
+
/* Large descriptor -- bytes 1-2 contain the 16-bit length */
ACPI_MOVE_16_TO_16(&aml->large_header.resource_length,
@@ -298,7 +299,8 @@ static u16 acpi_rs_strcpy(char *destination, char *source)
* string_ptr - (optional) where to store the actual
* resource_source string
*
- * RETURN: Length of the string plus NULL terminator, rounded up to 32 bit
+ * RETURN: Length of the string plus NULL terminator, rounded up to native
+ * word boundary
*
* DESCRIPTION: Copy the optional resource_source data from a raw AML descriptor
* to an internal resource descriptor
@@ -328,6 +330,7 @@ acpi_rs_get_resource_source(acpi_rs_length resource_length,
* we add 1 to the minimum length.
*/
if (total_length > (acpi_rsdesc_size) (minimum_length + 1)) {
+
/* Get the resource_source_index */
resource_source->index = aml_resource_source[0];
@@ -344,23 +347,26 @@ acpi_rs_get_resource_source(acpi_rs_length resource_length,
}
/*
- * In order for the struct_size to fall on a 32-bit boundary, calculate
- * the length of the string (+1 for the NULL terminator) and expand the
- * struct_size to the next 32-bit boundary.
+ * In order for the Resource length to be a multiple of the native
+ * word, calculate the length of the string (+1 for NULL terminator)
+ * and expand to the next word multiple.
*
* Zero the entire area of the buffer.
*/
total_length =
- ACPI_ROUND_UP_to_32_bITS(ACPI_STRLEN
- ((char *)&aml_resource_source[1]) +
- 1);
+ (u32)
+ ACPI_STRLEN(ACPI_CAST_PTR(char, &aml_resource_source[1])) +
+ 1;
+ total_length = (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(total_length);
+
ACPI_MEMSET(resource_source->string_ptr, 0, total_length);
/* Copy the resource_source string to the destination */
resource_source->string_length =
acpi_rs_strcpy(resource_source->string_ptr,
- (char *)&aml_resource_source[1]);
+ ACPI_CAST_PTR(char,
+ &aml_resource_source[1]));
return ((acpi_rs_length) total_length);
}
@@ -405,6 +411,7 @@ acpi_rs_set_resource_source(union aml_resource * aml,
/* Non-zero string length indicates presence of a resource_source */
if (resource_source->string_length) {
+
/* Point to the end of the AML descriptor */
aml_resource_source = ACPI_ADD_PTR(u8, aml, minimum_length);
@@ -415,7 +422,7 @@ acpi_rs_set_resource_source(union aml_resource * aml,
/* Copy the resource_source string */
- ACPI_STRCPY((char *)&aml_resource_source[1],
+ ACPI_STRCPY(ACPI_CAST_PTR(char, &aml_resource_source[1]),
resource_source->string_ptr);
/*
@@ -435,9 +442,9 @@ acpi_rs_set_resource_source(union aml_resource * aml,
*
* FUNCTION: acpi_rs_get_prt_method_data
*
- * PARAMETERS: Handle - a handle to the containing object
- * ret_buffer - a pointer to a buffer structure for the
- * results
+ * PARAMETERS: Node - Device node
+ * ret_buffer - Pointer to a buffer structure for the
+ * results
*
* RETURN: Status
*
@@ -450,18 +457,19 @@ acpi_rs_set_resource_source(union aml_resource * aml,
******************************************************************************/
acpi_status
-acpi_rs_get_prt_method_data(acpi_handle handle, struct acpi_buffer * ret_buffer)
+acpi_rs_get_prt_method_data(struct acpi_namespace_node * node,
+ struct acpi_buffer * ret_buffer)
{
union acpi_operand_object *obj_desc;
acpi_status status;
- ACPI_FUNCTION_TRACE("rs_get_prt_method_data");
+ ACPI_FUNCTION_TRACE(rs_get_prt_method_data);
/* Parameters guaranteed valid by caller */
/* Execute the method, no parameters */
- status = acpi_ut_evaluate_object(handle, METHOD_NAME__PRT,
+ status = acpi_ut_evaluate_object(node, METHOD_NAME__PRT,
ACPI_BTYPE_PACKAGE, &obj_desc);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
@@ -483,9 +491,9 @@ acpi_rs_get_prt_method_data(acpi_handle handle, struct acpi_buffer * ret_buffer)
*
* FUNCTION: acpi_rs_get_crs_method_data
*
- * PARAMETERS: Handle - a handle to the containing object
- * ret_buffer - a pointer to a buffer structure for the
- * results
+ * PARAMETERS: Node - Device node
+ * ret_buffer - Pointer to a buffer structure for the
+ * results
*
* RETURN: Status
*
@@ -498,18 +506,19 @@ acpi_rs_get_prt_method_data(acpi_handle handle, struct acpi_buffer * ret_buffer)
******************************************************************************/
acpi_status
-acpi_rs_get_crs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer)
+acpi_rs_get_crs_method_data(struct acpi_namespace_node *node,
+ struct acpi_buffer *ret_buffer)
{
union acpi_operand_object *obj_desc;
acpi_status status;
- ACPI_FUNCTION_TRACE("rs_get_crs_method_data");
+ ACPI_FUNCTION_TRACE(rs_get_crs_method_data);
/* Parameters guaranteed valid by caller */
/* Execute the method, no parameters */
- status = acpi_ut_evaluate_object(handle, METHOD_NAME__CRS,
+ status = acpi_ut_evaluate_object(node, METHOD_NAME__CRS,
ACPI_BTYPE_BUFFER, &obj_desc);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
@@ -522,7 +531,7 @@ acpi_rs_get_crs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer)
*/
status = acpi_rs_create_resource_list(obj_desc, ret_buffer);
- /* on exit, we must delete the object returned by evaluate_object */
+ /* On exit, we must delete the object returned by evaluate_object */
acpi_ut_remove_reference(obj_desc);
return_ACPI_STATUS(status);
@@ -532,9 +541,9 @@ acpi_rs_get_crs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer)
*
* FUNCTION: acpi_rs_get_prs_method_data
*
- * PARAMETERS: Handle - a handle to the containing object
- * ret_buffer - a pointer to a buffer structure for the
- * results
+ * PARAMETERS: Node - Device node
+ * ret_buffer - Pointer to a buffer structure for the
+ * results
*
* RETURN: Status
*
@@ -548,18 +557,19 @@ acpi_rs_get_crs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer)
#ifdef ACPI_FUTURE_USAGE
acpi_status
-acpi_rs_get_prs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer)
+acpi_rs_get_prs_method_data(struct acpi_namespace_node *node,
+ struct acpi_buffer *ret_buffer)
{
union acpi_operand_object *obj_desc;
acpi_status status;
- ACPI_FUNCTION_TRACE("rs_get_prs_method_data");
+ ACPI_FUNCTION_TRACE(rs_get_prs_method_data);
/* Parameters guaranteed valid by caller */
/* Execute the method, no parameters */
- status = acpi_ut_evaluate_object(handle, METHOD_NAME__PRS,
+ status = acpi_ut_evaluate_object(node, METHOD_NAME__PRS,
ACPI_BTYPE_BUFFER, &obj_desc);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
@@ -572,7 +582,7 @@ acpi_rs_get_prs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer)
*/
status = acpi_rs_create_resource_list(obj_desc, ret_buffer);
- /* on exit, we must delete the object returned by evaluate_object */
+ /* On exit, we must delete the object returned by evaluate_object */
acpi_ut_remove_reference(obj_desc);
return_ACPI_STATUS(status);
@@ -583,10 +593,10 @@ acpi_rs_get_prs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer)
*
* FUNCTION: acpi_rs_get_method_data
*
- * PARAMETERS: Handle - a handle to the containing object
+ * PARAMETERS: Handle - Handle to the containing object
* Path - Path to method, relative to Handle
- * ret_buffer - a pointer to a buffer structure for the
- * results
+ * ret_buffer - Pointer to a buffer structure for the
+ * results
*
* RETURN: Status
*
@@ -605,7 +615,7 @@ acpi_rs_get_method_data(acpi_handle handle,
union acpi_operand_object *obj_desc;
acpi_status status;
- ACPI_FUNCTION_TRACE("rs_get_method_data");
+ ACPI_FUNCTION_TRACE(rs_get_method_data);
/* Parameters guaranteed valid by caller */
@@ -634,9 +644,9 @@ acpi_rs_get_method_data(acpi_handle handle,
*
* FUNCTION: acpi_rs_set_srs_method_data
*
- * PARAMETERS: Handle - a handle to the containing object
- * in_buffer - a pointer to a buffer structure of the
- * parameter
+ * PARAMETERS: Node - Device node
+ * in_buffer - Pointer to a buffer structure of the
+ * parameter
*
* RETURN: Status
*
@@ -646,23 +656,37 @@ acpi_rs_get_method_data(acpi_handle handle,
* If the function fails an appropriate status will be returned
* and the contents of the callers buffer is undefined.
*
+ * Note: Parameters guaranteed valid by caller
+ *
******************************************************************************/
acpi_status
-acpi_rs_set_srs_method_data(acpi_handle handle, struct acpi_buffer *in_buffer)
+acpi_rs_set_srs_method_data(struct acpi_namespace_node *node,
+ struct acpi_buffer *in_buffer)
{
- struct acpi_parameter_info info;
- union acpi_operand_object *params[2];
+ struct acpi_evaluate_info *info;
+ union acpi_operand_object *args[2];
acpi_status status;
struct acpi_buffer buffer;
- ACPI_FUNCTION_TRACE("rs_set_srs_method_data");
+ ACPI_FUNCTION_TRACE(rs_set_srs_method_data);
- /* Parameters guaranteed valid by caller */
+ /* Allocate and initialize the evaluation information block */
+
+ info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
+ if (!info) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ info->prefix_node = node;
+ info->pathname = METHOD_NAME__SRS;
+ info->parameters = args;
+ info->parameter_type = ACPI_PARAM_ARGS;
+ info->flags = ACPI_IGNORE_RETURN_VALUE;
/*
* The in_buffer parameter will point to a linked list of
- * resource parameters. It needs to be formatted into a
+ * resource parameters. It needs to be formatted into a
* byte stream to be sent in as an input parameter to _SRS
*
* Convert the linked list into a byte stream
@@ -670,41 +694,36 @@ acpi_rs_set_srs_method_data(acpi_handle handle, struct acpi_buffer *in_buffer)
buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
status = acpi_rs_create_aml_resources(in_buffer->pointer, &buffer);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto cleanup;
}
- /* Init the param object */
+ /* Create and initialize the method parameter object */
- params[0] = acpi_ut_create_internal_object(ACPI_TYPE_BUFFER);
- if (!params[0]) {
- acpi_os_free(buffer.pointer);
- return_ACPI_STATUS(AE_NO_MEMORY);
+ args[0] = acpi_ut_create_internal_object(ACPI_TYPE_BUFFER);
+ if (!args[0]) {
+ /*
+ * Must free the buffer allocated above (otherwise it is freed
+ * later)
+ */
+ ACPI_FREE(buffer.pointer);
+ status = AE_NO_MEMORY;
+ goto cleanup;
}
- /* Set up the parameter object */
-
- params[0]->buffer.length = (u32) buffer.length;
- params[0]->buffer.pointer = buffer.pointer;
- params[0]->common.flags = AOPOBJ_DATA_VALID;
- params[1] = NULL;
-
- info.node = handle;
- info.parameters = params;
- info.parameter_type = ACPI_PARAM_ARGS;
+ args[0]->buffer.length = (u32) buffer.length;
+ args[0]->buffer.pointer = buffer.pointer;
+ args[0]->common.flags = AOPOBJ_DATA_VALID;
+ args[1] = NULL;
- /* Execute the method, no return value */
+ /* Execute the method, no return value is expected */
- status = acpi_ns_evaluate_relative(METHOD_NAME__SRS, &info);
- if (ACPI_SUCCESS(status)) {
- /* Delete any return object (especially if implicit_return is enabled) */
+ status = acpi_ns_evaluate(info);
- if (info.return_object) {
- acpi_ut_remove_reference(info.return_object);
- }
- }
+ /* Clean up and return the status from acpi_ns_evaluate */
- /* Clean up and return the status from acpi_ns_evaluate_relative */
+ acpi_ut_remove_reference(args[0]);
- acpi_ut_remove_reference(params[0]);
+ cleanup:
+ ACPI_FREE(info);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c
index 88b6707..1999e2a 100644
--- a/drivers/acpi/resources/rsxface.c
+++ b/drivers/acpi/resources/rsxface.c
@@ -41,10 +41,9 @@
* POSSIBILITY OF SUCH DAMAGES.
*/
-#include <linux/module.h>
-
#include <acpi/acpi.h>
#include <acpi/acresrc.h>
+#include <acpi/acnamesp.h>
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME("rsxface")
@@ -68,312 +67,262 @@ ACPI_MODULE_NAME("rsxface")
static acpi_status
acpi_rs_match_vendor_resource(struct acpi_resource *resource, void *context);
+static acpi_status
+acpi_rs_validate_parameters(acpi_handle device_handle,
+ struct acpi_buffer *buffer,
+ struct acpi_namespace_node **return_node);
+
/*******************************************************************************
*
- * FUNCTION: acpi_get_irq_routing_table
+ * FUNCTION: acpi_rs_validate_parameters
*
- * PARAMETERS: device_handle - a handle to the Bus device we are querying
- * ret_buffer - a pointer to a buffer to receive the
- * current resources for the device
+ * PARAMETERS: device_handle - Handle to a device
+ * Buffer - Pointer to a data buffer
+ * return_node - Pointer to where the device node is returned
*
* RETURN: Status
*
- * DESCRIPTION: This function is called to get the IRQ routing table for a
- * specific bus. The caller must first acquire a handle for the
- * desired bus. The routine table is placed in the buffer pointed
- * to by the ret_buffer variable parameter.
- *
- * If the function fails an appropriate status will be returned
- * and the value of ret_buffer is undefined.
- *
- * This function attempts to execute the _PRT method contained in
- * the object indicated by the passed device_handle.
+ * DESCRIPTION: Common parameter validation for resource interfaces
*
******************************************************************************/
-acpi_status
-acpi_get_irq_routing_table(acpi_handle device_handle,
- struct acpi_buffer *ret_buffer)
+static acpi_status
+acpi_rs_validate_parameters(acpi_handle device_handle,
+ struct acpi_buffer *buffer,
+ struct acpi_namespace_node **return_node)
{
acpi_status status;
+ struct acpi_namespace_node *node;
- ACPI_FUNCTION_TRACE("acpi_get_irq_routing_table ");
+ ACPI_FUNCTION_TRACE(rs_validate_parameters);
/*
- * Must have a valid handle and buffer, So we have to have a handle
- * and a return buffer structure, and if there is a non-zero buffer length
- * we also need a valid pointer in the buffer. If it's a zero buffer length,
- * we'll be returning the needed buffer size, so keep going.
+ * Must have a valid handle to an ACPI device
*/
if (!device_handle) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- status = acpi_ut_validate_buffer(ret_buffer);
+ node = acpi_ns_map_handle_to_node(device_handle);
+ if (!node) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ if (node->type != ACPI_TYPE_DEVICE) {
+ return_ACPI_STATUS(AE_TYPE);
+ }
+
+ /*
+ * Validate the user buffer object
+ *
+ * if there is a non-zero buffer length we also need a valid pointer in
+ * the buffer. If it's a zero buffer length, we'll be returning the
+ * needed buffer size (later), so keep going.
+ */
+ status = acpi_ut_validate_buffer(buffer);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
- status = acpi_rs_get_prt_method_data(device_handle, ret_buffer);
- return_ACPI_STATUS(status);
+ *return_node = node;
+ return_ACPI_STATUS(AE_OK);
}
/*******************************************************************************
*
- * FUNCTION: acpi_get_current_resources
+ * FUNCTION: acpi_get_irq_routing_table
*
- * PARAMETERS: device_handle - a handle to the device object for the
- * device we are querying
- * ret_buffer - a pointer to a buffer to receive the
+ * PARAMETERS: device_handle - Handle to the Bus device we are querying
+ * ret_buffer - Pointer to a buffer to receive the
* current resources for the device
*
* RETURN: Status
*
- * DESCRIPTION: This function is called to get the current resources for a
- * specific device. The caller must first acquire a handle for
- * the desired device. The resource data is placed in the buffer
- * pointed to by the ret_buffer variable parameter.
+ * DESCRIPTION: This function is called to get the IRQ routing table for a
+ * specific bus. The caller must first acquire a handle for the
+ * desired bus. The routine table is placed in the buffer pointed
+ * to by the ret_buffer variable parameter.
*
* If the function fails an appropriate status will be returned
* and the value of ret_buffer is undefined.
*
- * This function attempts to execute the _CRS method contained in
+ * This function attempts to execute the _PRT method contained in
* the object indicated by the passed device_handle.
*
******************************************************************************/
acpi_status
-acpi_get_current_resources(acpi_handle device_handle,
+acpi_get_irq_routing_table(acpi_handle device_handle,
struct acpi_buffer *ret_buffer)
{
acpi_status status;
+ struct acpi_namespace_node *node;
- ACPI_FUNCTION_TRACE("acpi_get_current_resources");
+ ACPI_FUNCTION_TRACE(acpi_get_irq_routing_table);
- /*
- * Must have a valid handle and buffer, So we have to have a handle
- * and a return buffer structure, and if there is a non-zero buffer length
- * we also need a valid pointer in the buffer. If it's a zero buffer length,
- * we'll be returning the needed buffer size, so keep going.
- */
- if (!device_handle) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
+ /* Validate parameters then dispatch to internal routine */
- status = acpi_ut_validate_buffer(ret_buffer);
+ status = acpi_rs_validate_parameters(device_handle, ret_buffer, &node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
- status = acpi_rs_get_crs_method_data(device_handle, ret_buffer);
+ status = acpi_rs_get_prt_method_data(node, ret_buffer);
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_get_current_resources);
+ACPI_EXPORT_SYMBOL(acpi_get_irq_routing_table)
/*******************************************************************************
*
- * FUNCTION: acpi_get_possible_resources
+ * FUNCTION: acpi_get_current_resources
*
- * PARAMETERS: device_handle - a handle to the device object for the
+ * PARAMETERS: device_handle - Handle to the device object for the
* device we are querying
- * ret_buffer - a pointer to a buffer to receive the
- * resources for the device
+ * ret_buffer - Pointer to a buffer to receive the
+ * current resources for the device
*
* RETURN: Status
*
- * DESCRIPTION: This function is called to get a list of the possible resources
- * for a specific device. The caller must first acquire a handle
- * for the desired device. The resource data is placed in the
- * buffer pointed to by the ret_buffer variable.
+ * DESCRIPTION: This function is called to get the current resources for a
+ * specific device. The caller must first acquire a handle for
+ * the desired device. The resource data is placed in the buffer
+ * pointed to by the ret_buffer variable parameter.
*
* If the function fails an appropriate status will be returned
* and the value of ret_buffer is undefined.
*
+ * This function attempts to execute the _CRS method contained in
+ * the object indicated by the passed device_handle.
+ *
******************************************************************************/
-
-#ifdef ACPI_FUTURE_USAGE
acpi_status
-acpi_get_possible_resources(acpi_handle device_handle,
- struct acpi_buffer *ret_buffer)
+acpi_get_current_resources(acpi_handle device_handle,
+ struct acpi_buffer *ret_buffer)
{
acpi_status status;
+ struct acpi_namespace_node *node;
- ACPI_FUNCTION_TRACE("acpi_get_possible_resources");
+ ACPI_FUNCTION_TRACE(acpi_get_current_resources);
- /*
- * Must have a valid handle and buffer, So we have to have a handle
- * and a return buffer structure, and if there is a non-zero buffer length
- * we also need a valid pointer in the buffer. If it's a zero buffer length,
- * we'll be returning the needed buffer size, so keep going.
- */
- if (!device_handle) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
+ /* Validate parameters then dispatch to internal routine */
- status = acpi_ut_validate_buffer(ret_buffer);
+ status = acpi_rs_validate_parameters(device_handle, ret_buffer, &node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
- status = acpi_rs_get_prs_method_data(device_handle, ret_buffer);
+ status = acpi_rs_get_crs_method_data(node, ret_buffer);
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_get_possible_resources);
-#endif /* ACPI_FUTURE_USAGE */
+ACPI_EXPORT_SYMBOL(acpi_get_current_resources)
+#ifdef ACPI_FUTURE_USAGE
/*******************************************************************************
*
- * FUNCTION: acpi_walk_resources
+ * FUNCTION: acpi_get_possible_resources
*
* PARAMETERS: device_handle - Handle to the device object for the
* device we are querying
- * Name - Method name of the resources we want
- * (METHOD_NAME__CRS or METHOD_NAME__PRS)
- * user_function - Called for each resource
- * Context - Passed to user_function
+ * ret_buffer - Pointer to a buffer to receive the
+ * resources for the device
*
* RETURN: Status
*
- * DESCRIPTION: Retrieves the current or possible resource list for the
- * specified device. The user_function is called once for
- * each resource in the list.
+ * DESCRIPTION: This function is called to get a list of the possible resources
+ * for a specific device. The caller must first acquire a handle
+ * for the desired device. The resource data is placed in the
+ * buffer pointed to by the ret_buffer variable.
+ *
+ * If the function fails an appropriate status will be returned
+ * and the value of ret_buffer is undefined.
*
******************************************************************************/
-
acpi_status
-acpi_walk_resources(acpi_handle device_handle,
- char *name,
- ACPI_WALK_RESOURCE_CALLBACK user_function, void *context)
+acpi_get_possible_resources(acpi_handle device_handle,
+ struct acpi_buffer *ret_buffer)
{
acpi_status status;
- struct acpi_buffer buffer;
- struct acpi_resource *resource;
- struct acpi_resource *resource_end;
-
- ACPI_FUNCTION_TRACE("acpi_walk_resources");
-
- /* Parameter validation */
+ struct acpi_namespace_node *node;
- if (!device_handle || !user_function || !name ||
- (ACPI_STRNCMP(name, METHOD_NAME__CRS, sizeof(METHOD_NAME__CRS)) &&
- ACPI_STRNCMP(name, METHOD_NAME__PRS, sizeof(METHOD_NAME__PRS)))) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
+ ACPI_FUNCTION_TRACE(acpi_get_possible_resources);
- /* Get the _CRS or _PRS resource list */
+ /* Validate parameters then dispatch to internal routine */
- buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
- status = acpi_rs_get_method_data(device_handle, name, &buffer);
+ status = acpi_rs_validate_parameters(device_handle, ret_buffer, &node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
- /* Buffer now contains the resource list */
-
- resource = ACPI_CAST_PTR(struct acpi_resource, buffer.pointer);
- resource_end =
- ACPI_ADD_PTR(struct acpi_resource, buffer.pointer, buffer.length);
-
- /* Walk the resource list until the end_tag is found (or buffer end) */
-
- while (resource < resource_end) {
- /* Sanity check the resource */
-
- if (resource->type > ACPI_RESOURCE_TYPE_MAX) {
- status = AE_AML_INVALID_RESOURCE_TYPE;
- break;
- }
-
- /* Invoke the user function, abort on any error returned */
-
- status = user_function(resource, context);
- if (ACPI_FAILURE(status)) {
- if (status == AE_CTRL_TERMINATE) {
- /* This is an OK termination by the user function */
-
- status = AE_OK;
- }
- break;
- }
-
- /* end_tag indicates end-of-list */
-
- if (resource->type == ACPI_RESOURCE_TYPE_END_TAG) {
- break;
- }
-
- /* Get the next resource descriptor */
-
- resource =
- ACPI_ADD_PTR(struct acpi_resource, resource,
- resource->length);
- }
-
- ACPI_MEM_FREE(buffer.pointer);
+ status = acpi_rs_get_prs_method_data(node, ret_buffer);
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_walk_resources);
+ACPI_EXPORT_SYMBOL(acpi_get_possible_resources)
+#endif /* ACPI_FUTURE_USAGE */
/*******************************************************************************
*
* FUNCTION: acpi_set_current_resources
*
- * PARAMETERS: device_handle - a handle to the device object for the
- * device we are changing the resources of
- * in_buffer - a pointer to a buffer containing the
+ * PARAMETERS: device_handle - Handle to the device object for the
+ * device we are setting resources
+ * in_buffer - Pointer to a buffer containing the
* resources to be set for the device
*
* RETURN: Status
*
* DESCRIPTION: This function is called to set the current resources for a
- * specific device. The caller must first acquire a handle for
- * the desired device. The resource data is passed to the routine
+ * specific device. The caller must first acquire a handle for
+ * the desired device. The resource data is passed to the routine
* the buffer pointed to by the in_buffer variable.
*
******************************************************************************/
-
acpi_status
acpi_set_current_resources(acpi_handle device_handle,
struct acpi_buffer *in_buffer)
{
acpi_status status;
+ struct acpi_namespace_node *node;
- ACPI_FUNCTION_TRACE("acpi_set_current_resources");
+ ACPI_FUNCTION_TRACE(acpi_set_current_resources);
- /* Must have a valid handle and buffer */
+ /* Validate the buffer, don't allow zero length */
- if ((!device_handle) ||
- (!in_buffer) || (!in_buffer->pointer) || (!in_buffer->length)) {
+ if ((!in_buffer) || (!in_buffer->pointer) || (!in_buffer->length)) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- status = acpi_rs_set_srs_method_data(device_handle, in_buffer);
+ /* Validate parameters then dispatch to internal routine */
+
+ status = acpi_rs_validate_parameters(device_handle, in_buffer, &node);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ status = acpi_rs_set_srs_method_data(node, in_buffer);
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_set_current_resources);
+ACPI_EXPORT_SYMBOL(acpi_set_current_resources)
/******************************************************************************
*
* FUNCTION: acpi_resource_to_address64
*
- * PARAMETERS: Resource - Pointer to a resource
- * Out - Pointer to the users's return
- * buffer (a struct
- * struct acpi_resource_address64)
+ * PARAMETERS: Resource - Pointer to a resource
+ * Out - Pointer to the users's return buffer
+ * (a struct acpi_resource_address64)
*
* RETURN: Status
*
* DESCRIPTION: If the resource is an address16, address32, or address64,
- * copy it to the address64 return buffer. This saves the
+ * copy it to the address64 return buffer. This saves the
* caller from having to duplicate code for different-sized
* addresses.
*
******************************************************************************/
-
acpi_status
acpi_resource_to_address64(struct acpi_resource *resource,
struct acpi_resource_address64 *out)
@@ -415,18 +364,18 @@ acpi_resource_to_address64(struct acpi_resource *resource,
return (AE_OK);
}
-EXPORT_SYMBOL(acpi_resource_to_address64);
+ACPI_EXPORT_SYMBOL(acpi_resource_to_address64)
/*******************************************************************************
*
* FUNCTION: acpi_get_vendor_resource
*
- * PARAMETERS: device_handle - Handle for the parent device object
- * Name - Method name for the parent resource
- * (METHOD_NAME__CRS or METHOD_NAME__PRS)
- * Uuid - Pointer to the UUID to be matched.
- * includes both subtype and 16-byte UUID
- * ret_buffer - Where the vendor resource is returned
+ * PARAMETERS: device_handle - Handle for the parent device object
+ * Name - Method name for the parent resource
+ * (METHOD_NAME__CRS or METHOD_NAME__PRS)
+ * Uuid - Pointer to the UUID to be matched.
+ * includes both subtype and 16-byte UUID
+ * ret_buffer - Where the vendor resource is returned
*
* RETURN: Status
*
@@ -435,7 +384,6 @@ EXPORT_SYMBOL(acpi_resource_to_address64);
* UUID subtype. Returns a struct acpi_resource of type Vendor.
*
******************************************************************************/
-
acpi_status
acpi_get_vendor_resource(acpi_handle device_handle,
char *name,
@@ -467,18 +415,19 @@ acpi_get_vendor_resource(acpi_handle device_handle,
return (info.status);
}
+ACPI_EXPORT_SYMBOL(acpi_get_vendor_resource)
+
/*******************************************************************************
*
* FUNCTION: acpi_rs_match_vendor_resource
*
- * PARAMETERS: ACPI_WALK_RESOURCE_CALLBACK
+ * PARAMETERS: acpi_walk_resource_callback
*
* RETURN: Status
*
* DESCRIPTION: Match a vendor resource via the ACPI 3.0 UUID
*
******************************************************************************/
-
static acpi_status
acpi_rs_match_vendor_resource(struct acpi_resource *resource, void *context)
{
@@ -526,3 +475,101 @@ acpi_rs_match_vendor_resource(struct acpi_resource *resource, void *context)
info->status = AE_OK;
return (AE_CTRL_TERMINATE);
}
+
+ACPI_EXPORT_SYMBOL(acpi_rs_match_vendor_resource)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_walk_resources
+ *
+ * PARAMETERS: device_handle - Handle to the device object for the
+ * device we are querying
+ * Name - Method name of the resources we want
+ * (METHOD_NAME__CRS or METHOD_NAME__PRS)
+ * user_function - Called for each resource
+ * Context - Passed to user_function
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Retrieves the current or possible resource list for the
+ * specified device. The user_function is called once for
+ * each resource in the list.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_walk_resources(acpi_handle device_handle,
+ char *name,
+ acpi_walk_resource_callback user_function, void *context)
+{
+ acpi_status status;
+ struct acpi_buffer buffer;
+ struct acpi_resource *resource;
+ struct acpi_resource *resource_end;
+
+ ACPI_FUNCTION_TRACE(acpi_walk_resources);
+
+ /* Parameter validation */
+
+ if (!device_handle || !user_function || !name ||
+ (!ACPI_COMPARE_NAME(name, METHOD_NAME__CRS) &&
+ !ACPI_COMPARE_NAME(name, METHOD_NAME__PRS))) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ /* Get the _CRS or _PRS resource list */
+
+ buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+ status = acpi_rs_get_method_data(device_handle, name, &buffer);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Buffer now contains the resource list */
+
+ resource = ACPI_CAST_PTR(struct acpi_resource, buffer.pointer);
+ resource_end =
+ ACPI_ADD_PTR(struct acpi_resource, buffer.pointer, buffer.length);
+
+ /* Walk the resource list until the end_tag is found (or buffer end) */
+
+ while (resource < resource_end) {
+
+ /* Sanity check the resource */
+
+ if (resource->type > ACPI_RESOURCE_TYPE_MAX) {
+ status = AE_AML_INVALID_RESOURCE_TYPE;
+ break;
+ }
+
+ /* Invoke the user function, abort on any error returned */
+
+ status = user_function(resource, context);
+ if (ACPI_FAILURE(status)) {
+ if (status == AE_CTRL_TERMINATE) {
+
+ /* This is an OK termination by the user function */
+
+ status = AE_OK;
+ }
+ break;
+ }
+
+ /* end_tag indicates end-of-list */
+
+ if (resource->type == ACPI_RESOURCE_TYPE_END_TAG) {
+ break;
+ }
+
+ /* Get the next resource descriptor */
+
+ resource =
+ ACPI_ADD_PTR(struct acpi_resource, resource,
+ resource->length);
+ }
+
+ ACPI_FREE(buffer.pointer);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_walk_resources)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index a0ab828..f8316a0 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -142,7 +142,7 @@ static void acpi_device_register(struct acpi_device *device,
create_sysfs_device_files(device);
}
-static int acpi_device_unregister(struct acpi_device *device, int type)
+static void acpi_device_unregister(struct acpi_device *device, int type)
{
spin_lock(&acpi_device_lock);
if (device->parent) {
@@ -158,7 +158,6 @@ static int acpi_device_unregister(struct acpi_device *device, int type)
acpi_detach_data(device->handle, acpi_bus_data_handler);
remove_sysfs_device_files(device);
kobject_unregister(&device->kobj);
- return 0;
}
void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context)
@@ -234,12 +233,9 @@ static int acpi_bus_get_power_flags(struct acpi_device *device)
int acpi_match_ids(struct acpi_device *device, char *ids)
{
- int error = 0;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-
if (device->flags.hardware_id)
if (strstr(ids, device->pnp.hardware_id))
- goto Done;
+ return 0;
if (device->flags.compatible_ids) {
struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;
@@ -248,15 +244,10 @@ int acpi_match_ids(struct acpi_device *device, char *ids)
/* compare multiple _CID entries against driver ids */
for (i = 0; i < cid_list->count; i++) {
if (strstr(ids, cid_list->id[i].value))
- goto Done;
+ return 0;
}
}
- error = -ENOENT;
-
- Done:
- if (buffer.pointer)
- acpi_os_free(buffer.pointer);
- return error;
+ return -ENOENT;
}
static acpi_status
@@ -441,10 +432,7 @@ acpi_eject_store(struct acpi_device *device, const char *buf, size_t count)
islockable = device->flags.lockable;
handle = device->handle;
- if (type == ACPI_TYPE_PROCESSOR)
- result = acpi_bus_trim(device, 0);
- else
- result = acpi_bus_trim(device, 1);
+ result = acpi_bus_trim(device, 1);
if (!result)
result = acpi_eject_operation(handle, islockable);
@@ -471,7 +459,6 @@ static int acpi_bus_get_perf_flags(struct acpi_device *device)
-------------------------------------------------------------------------- */
static LIST_HEAD(acpi_bus_drivers);
-static DECLARE_MUTEX(acpi_bus_drivers_lock);
/**
* acpi_bus_match - match device IDs to driver's supported IDs
@@ -548,10 +535,9 @@ static int acpi_start_single_object(struct acpi_device *device)
return_VALUE(result);
}
-static int acpi_driver_attach(struct acpi_driver *drv)
+static void acpi_driver_attach(struct acpi_driver *drv)
{
struct list_head *node, *next;
- int count = 0;
ACPI_FUNCTION_TRACE("acpi_driver_attach");
@@ -568,7 +554,6 @@ static int acpi_driver_attach(struct acpi_driver *drv)
if (!acpi_bus_driver_init(dev, drv)) {
acpi_start_single_object(dev);
atomic_inc(&drv->references);
- count++;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Found driver [%s] for device [%s]\n",
drv->name, dev->pnp.bus_id));
@@ -577,10 +562,9 @@ static int acpi_driver_attach(struct acpi_driver *drv)
spin_lock(&acpi_device_lock);
}
spin_unlock(&acpi_device_lock);
- return_VALUE(count);
}
-static int acpi_driver_detach(struct acpi_driver *drv)
+static void acpi_driver_detach(struct acpi_driver *drv)
{
struct list_head *node, *next;
@@ -602,7 +586,6 @@ static int acpi_driver_detach(struct acpi_driver *drv)
}
}
spin_unlock(&acpi_device_lock);
- return_VALUE(0);
}
/**
@@ -610,28 +593,22 @@ static int acpi_driver_detach(struct acpi_driver *drv)
* @driver: driver being registered
*
* Registers a driver with the ACPI bus. Searches the namespace for all
- * devices that match the driver's criteria and binds. Returns the
- * number of devices that were claimed by the driver, or a negative
- * error status for failure.
+ * devices that match the driver's criteria and binds. Returns zero for
+ * success or a negative error status for failure.
*/
int acpi_bus_register_driver(struct acpi_driver *driver)
{
- int count;
-
ACPI_FUNCTION_TRACE("acpi_bus_register_driver");
if (acpi_disabled)
return_VALUE(-ENODEV);
- if (!driver)
- return_VALUE(-EINVAL);
-
spin_lock(&acpi_device_lock);
list_add_tail(&driver->node, &acpi_bus_drivers);
spin_unlock(&acpi_device_lock);
- count = acpi_driver_attach(driver);
+ acpi_driver_attach(driver);
- return_VALUE(count);
+ return_VALUE(0);
}
EXPORT_SYMBOL(acpi_bus_register_driver);
@@ -643,23 +620,16 @@ EXPORT_SYMBOL(acpi_bus_register_driver);
* Unregisters a driver with the ACPI bus. Searches the namespace for all
* devices that match the driver's criteria and unbinds.
*/
-int acpi_bus_unregister_driver(struct acpi_driver *driver)
+void acpi_bus_unregister_driver(struct acpi_driver *driver)
{
- int error = 0;
+ acpi_driver_detach(driver);
- ACPI_FUNCTION_TRACE("acpi_bus_unregister_driver");
-
- if (driver) {
- acpi_driver_detach(driver);
-
- if (!atomic_read(&driver->references)) {
- spin_lock(&acpi_device_lock);
- list_del_init(&driver->node);
- spin_unlock(&acpi_device_lock);
- }
- } else
- error = -EINVAL;
- return_VALUE(error);
+ if (!atomic_read(&driver->references)) {
+ spin_lock(&acpi_device_lock);
+ list_del_init(&driver->node);
+ spin_unlock(&acpi_device_lock);
+ }
+ return;
}
EXPORT_SYMBOL(acpi_bus_unregister_driver);
@@ -1371,6 +1341,100 @@ static int acpi_bus_scan_fixed(struct acpi_device *root)
return_VALUE(result);
}
+
+static inline struct acpi_device * to_acpi_dev(struct device * dev)
+{
+ return container_of(dev, struct acpi_device, dev);
+}
+
+
+static int root_suspend(struct acpi_device * acpi_dev, pm_message_t state)
+{
+ struct acpi_device * dev, * next;
+ int result;
+
+ spin_lock(&acpi_device_lock);
+ list_for_each_entry_safe_reverse(dev, next, &acpi_device_list, g_list) {
+ if (dev->driver && dev->driver->ops.suspend) {
+ spin_unlock(&acpi_device_lock);
+ result = dev->driver->ops.suspend(dev, 0);
+ if (result) {
+ printk(KERN_ERR PREFIX "[%s - %s] Suspend failed: %d\n",
+ acpi_device_name(dev),
+ acpi_device_bid(dev), result);
+ }
+ spin_lock(&acpi_device_lock);
+ }
+ }
+ spin_unlock(&acpi_device_lock);
+ return 0;
+}
+
+
+static int acpi_device_suspend(struct device * dev, pm_message_t state)
+{
+ struct acpi_device * acpi_dev = to_acpi_dev(dev);
+
+ /*
+ * For now, we should only register 1 generic device -
+ * the ACPI root device - and from there, we walk the
+ * tree of ACPI devices to suspend each one using the
+ * ACPI driver methods.
+ */
+ if (acpi_dev->handle == ACPI_ROOT_OBJECT)
+ root_suspend(acpi_dev, state);
+ return 0;
+}
+
+
+
+static int root_resume(struct acpi_device * acpi_dev)
+{
+ struct acpi_device * dev, * next;
+ int result;
+
+ spin_lock(&acpi_device_lock);
+ list_for_each_entry_safe(dev, next, &acpi_device_list, g_list) {
+ if (dev->driver && dev->driver->ops.resume) {
+ spin_unlock(&acpi_device_lock);
+ result = dev->driver->ops.resume(dev, 0);
+ if (result) {
+ printk(KERN_ERR PREFIX "[%s - %s] resume failed: %d\n",
+ acpi_device_name(dev),
+ acpi_device_bid(dev), result);
+ }
+ spin_lock(&acpi_device_lock);
+ }
+ }
+ spin_unlock(&acpi_device_lock);
+ return 0;
+}
+
+
+static int acpi_device_resume(struct device * dev)
+{
+ struct acpi_device * acpi_dev = to_acpi_dev(dev);
+
+ /*
+ * For now, we should only register 1 generic device -
+ * the ACPI root device - and from there, we walk the
+ * tree of ACPI devices to resume each one using the
+ * ACPI driver methods.
+ */
+ if (acpi_dev->handle == ACPI_ROOT_OBJECT)
+ root_resume(acpi_dev);
+ return 0;
+}
+
+
+struct bus_type acpi_bus_type = {
+ .name = "acpi",
+ .suspend = acpi_device_suspend,
+ .resume = acpi_device_resume,
+};
+
+
+
static int __init acpi_scan_init(void)
{
int result;
@@ -1383,6 +1447,12 @@ static int __init acpi_scan_init(void)
kset_register(&acpi_namespace_kset);
+ result = bus_register(&acpi_bus_type);
+ if (result) {
+ /* We don't want to quit even if we failed to add suspend/resume */
+ printk(KERN_ERR PREFIX "Could not register bus type\n");
+ }
+
/*
* Create the root device in the bus's device tree
*/
@@ -1392,6 +1462,16 @@ static int __init acpi_scan_init(void)
goto Done;
result = acpi_start_single_object(acpi_root);
+ if (result)
+ goto Done;
+
+ acpi_root->dev.bus = &acpi_bus_type;
+ snprintf(acpi_root->dev.bus_id, BUS_ID_SIZE, "%s", acpi_bus_type.name);
+ result = device_register(&acpi_root->dev);
+ if (result) {
+ /* We don't want to quit even if we failed to add suspend/resume */
+ printk(KERN_ERR PREFIX "Could not register device\n");
+ }
/*
* Enumerate devices in the ACPI namespace.
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 930427f..62ce87d 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -105,6 +105,14 @@ static int acpi_pm_enter(suspend_state_t pm_state)
default:
return -EINVAL;
}
+
+ /* ACPI 3.0 specs (P62) says that it's the responsabilty
+ * of the OSPM to clear the status bit [ implying that the
+ * POWER_BUTTON event should not reach userspace ]
+ */
+ if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3))
+ acpi_clear_event(ACPI_EVENT_POWER_BUTTON);
+
local_irq_restore(flags);
printk(KERN_DEBUG "Back to C!\n");
diff --git a/drivers/acpi/sleep/wakeup.c b/drivers/acpi/sleep/wakeup.c
index 85df0ce..af1dbab 100644
--- a/drivers/acpi/sleep/wakeup.c
+++ b/drivers/acpi/sleep/wakeup.c
@@ -155,7 +155,6 @@ static int __init acpi_wakeup_device_init(void)
if (acpi_disabled)
return 0;
- printk("ACPI wakeup devices: \n");
spin_lock(&acpi_device_lock);
list_for_each_safe(node, next, &acpi_wakeup_device_list) {
@@ -174,10 +173,8 @@ static int __init acpi_wakeup_device_init(void)
dev->wakeup.state.enabled = 1;
spin_lock(&acpi_device_lock);
}
- printk("%4s ", dev->pnp.bus_id);
}
spin_unlock(&acpi_device_lock);
- printk("\n");
return 0;
}
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index e4308c7..a934ac4 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -39,7 +39,7 @@ ACPI_MODULE_NAME("acpi_system")
#define ACPI_SYSTEM_FILE_EVENT "event"
#define ACPI_SYSTEM_FILE_DSDT "dsdt"
#define ACPI_SYSTEM_FILE_FADT "fadt"
-extern FADT_DESCRIPTOR acpi_fadt;
+extern struct fadt_descriptor acpi_fadt;
/* --------------------------------------------------------------------------
FS Interface (/proc)
@@ -82,7 +82,7 @@ acpi_system_read_dsdt(struct file *file,
ACPI_FUNCTION_TRACE("acpi_system_read_dsdt");
- status = acpi_get_table(ACPI_TABLE_DSDT, 1, &dsdt);
+ status = acpi_get_table(ACPI_TABLE_ID_DSDT, 1, &dsdt);
if (ACPI_FAILURE(status))
return_VALUE(-ENODEV);
@@ -110,7 +110,7 @@ acpi_system_read_fadt(struct file *file,
ACPI_FUNCTION_TRACE("acpi_system_read_fadt");
- status = acpi_get_table(ACPI_TABLE_FADT, 1, &fadt);
+ status = acpi_get_table(ACPI_TABLE_ID_FADT, 1, &fadt);
if (ACPI_FAILURE(status))
return_VALUE(-ENODEV);
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 7f37c7c..ed5e881 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -282,8 +282,8 @@ acpi_get_table_header_early(enum acpi_table_id id,
/* Map the DSDT header via the pointer in the FADT */
if (id == ACPI_DSDT) {
- struct fadt_descriptor_rev2 *fadt =
- (struct fadt_descriptor_rev2 *)*header;
+ struct fadt_descriptor *fadt =
+ (struct fadt_descriptor *)*header;
if (fadt->revision == 3 && fadt->Xdsdt) {
*header = (void *)__acpi_map_table(fadt->Xdsdt,
diff --git a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c
index 03b37d2..d697fcb 100644
--- a/drivers/acpi/tables/tbconvrt.c
+++ b/drivers/acpi/tables/tbconvrt.c
@@ -41,8 +41,6 @@
* POSSIBILITY OF SUCH DAMAGES.
*/
-#include <linux/module.h>
-
#include <acpi/acpi.h>
#include <acpi/actables.h>
@@ -56,15 +54,15 @@ acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct,
acpi_physical_address address);
static void
-acpi_tb_convert_fadt1(struct fadt_descriptor_rev2 *local_fadt,
+acpi_tb_convert_fadt1(struct fadt_descriptor *local_fadt,
struct fadt_descriptor_rev1 *original_fadt);
static void
-acpi_tb_convert_fadt2(struct fadt_descriptor_rev2 *local_fadt,
- struct fadt_descriptor_rev2 *original_fadt);
+acpi_tb_convert_fadt2(struct fadt_descriptor *local_fadt,
+ struct fadt_descriptor *original_fadt);
u8 acpi_fadt_is_v1;
-EXPORT_SYMBOL(acpi_fadt_is_v1);
+ACPI_EXPORT_SYMBOL(acpi_fadt_is_v1)
/*******************************************************************************
*
@@ -122,7 +120,7 @@ acpi_status acpi_tb_convert_to_xsdt(struct acpi_table_desc *table_info)
{
acpi_size table_size;
u32 i;
- XSDT_DESCRIPTOR *new_table;
+ struct xsdt_descriptor *new_table;
ACPI_FUNCTION_ENTRY();
@@ -133,7 +131,7 @@ acpi_status acpi_tb_convert_to_xsdt(struct acpi_table_desc *table_info)
/* Allocate an XSDT */
- new_table = ACPI_MEM_CALLOCATE(table_size);
+ new_table = ACPI_ALLOCATE_ZEROED(table_size);
if (!new_table) {
return (AE_NO_MEMORY);
}
@@ -147,17 +145,18 @@ acpi_status acpi_tb_convert_to_xsdt(struct acpi_table_desc *table_info)
/* Copy the table pointers */
for (i = 0; i < acpi_gbl_rsdt_table_count; i++) {
+
/* RSDT pointers are 32 bits, XSDT pointers are 64 bits */
if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
ACPI_STORE_ADDRESS(new_table->table_offset_entry[i],
(ACPI_CAST_PTR
- (struct rsdt_descriptor_rev1,
+ (struct rsdt_descriptor,
table_info->pointer))->
table_offset_entry[i]);
} else {
new_table->table_offset_entry[i] =
- (ACPI_CAST_PTR(XSDT_DESCRIPTOR,
+ (ACPI_CAST_PTR(struct xsdt_descriptor,
table_info->pointer))->
table_offset_entry[i];
}
@@ -219,7 +218,7 @@ acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct,
******************************************************************************/
static void
-acpi_tb_convert_fadt1(struct fadt_descriptor_rev2 *local_fadt,
+acpi_tb_convert_fadt1(struct fadt_descriptor *local_fadt,
struct fadt_descriptor_rev1 *original_fadt)
{
@@ -365,14 +364,13 @@ acpi_tb_convert_fadt1(struct fadt_descriptor_rev2 *local_fadt,
******************************************************************************/
static void
-acpi_tb_convert_fadt2(struct fadt_descriptor_rev2 *local_fadt,
- struct fadt_descriptor_rev2 *original_fadt)
+acpi_tb_convert_fadt2(struct fadt_descriptor *local_fadt,
+ struct fadt_descriptor *original_fadt)
{
/* We have an ACPI 2.0 FADT but we must copy it to our local buffer */
- ACPI_MEMCPY(local_fadt, original_fadt,
- sizeof(struct fadt_descriptor_rev2));
+ ACPI_MEMCPY(local_fadt, original_fadt, sizeof(struct fadt_descriptor));
/*
* "X" fields are optional extensions to the original V1.0 fields, so
@@ -491,10 +489,10 @@ acpi_tb_convert_fadt2(struct fadt_descriptor_rev2 *local_fadt,
acpi_status acpi_tb_convert_table_fadt(void)
{
- struct fadt_descriptor_rev2 *local_fadt;
+ struct fadt_descriptor *local_fadt;
struct acpi_table_desc *table_desc;
- ACPI_FUNCTION_TRACE("tb_convert_table_fadt");
+ ACPI_FUNCTION_TRACE(tb_convert_table_fadt);
/*
* acpi_gbl_FADT is valid. Validate the FADT length. The table must be
@@ -508,13 +506,14 @@ acpi_status acpi_tb_convert_table_fadt(void)
/* Allocate buffer for the ACPI 2.0(+) FADT */
- local_fadt = ACPI_MEM_CALLOCATE(sizeof(struct fadt_descriptor_rev2));
+ local_fadt = ACPI_ALLOCATE_ZEROED(sizeof(struct fadt_descriptor));
if (!local_fadt) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
if (acpi_gbl_FADT->revision >= FADT2_REVISION_ID) {
- if (acpi_gbl_FADT->length < sizeof(struct fadt_descriptor_rev2)) {
+ if (acpi_gbl_FADT->length < sizeof(struct fadt_descriptor)) {
+
/* Length is too short to be a V2.0 table */
ACPI_WARNING((AE_INFO,
@@ -538,11 +537,11 @@ acpi_status acpi_tb_convert_table_fadt(void)
/* Global FADT pointer will point to the new common V2.0 FADT */
acpi_gbl_FADT = local_fadt;
- acpi_gbl_FADT->length = sizeof(FADT_DESCRIPTOR);
+ acpi_gbl_FADT->length = sizeof(struct fadt_descriptor);
/* Free the original table */
- table_desc = acpi_gbl_table_lists[ACPI_TABLE_FADT].next;
+ table_desc = acpi_gbl_table_lists[ACPI_TABLE_ID_FADT].next;
acpi_tb_delete_single_table(table_desc);
/* Install the new table */
@@ -550,7 +549,7 @@ acpi_status acpi_tb_convert_table_fadt(void)
table_desc->pointer =
ACPI_CAST_PTR(struct acpi_table_header, acpi_gbl_FADT);
table_desc->allocation = ACPI_MEM_ALLOCATED;
- table_desc->length = sizeof(struct fadt_descriptor_rev2);
+ table_desc->length = sizeof(struct fadt_descriptor);
/* Dump the entire FADT */
@@ -580,7 +579,7 @@ acpi_status acpi_tb_convert_table_fadt(void)
acpi_status acpi_tb_build_common_facs(struct acpi_table_desc *table_info)
{
- ACPI_FUNCTION_TRACE("tb_build_common_facs");
+ ACPI_FUNCTION_TRACE(tb_build_common_facs);
/* Absolute minimum length is 24, but the ACPI spec says 64 */
@@ -603,6 +602,7 @@ acpi_status acpi_tb_build_common_facs(struct acpi_table_desc *table_info)
if ((acpi_gbl_RSDP->revision < 2) ||
(acpi_gbl_FACS->length < 32) ||
(!(acpi_gbl_FACS->xfirmware_waking_vector))) {
+
/* ACPI 1.0 FACS or short table or optional X_ field is zero */
acpi_gbl_common_fACS.firmware_waking_vector = ACPI_CAST_PTR(u64,
diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c
index 09b4ee6..99eacce 100644
--- a/drivers/acpi/tables/tbget.c
+++ b/drivers/acpi/tables/tbget.c
@@ -78,7 +78,7 @@ acpi_tb_get_table(struct acpi_pointer *address,
acpi_status status;
struct acpi_table_header header;
- ACPI_FUNCTION_TRACE("tb_get_table");
+ ACPI_FUNCTION_TRACE(tb_get_table);
/* Get the header in order to get signature and table size */
@@ -124,7 +124,7 @@ acpi_tb_get_table_header(struct acpi_pointer *address,
acpi_status status = AE_OK;
struct acpi_table_header *header = NULL;
- ACPI_FUNCTION_TRACE("tb_get_table_header");
+ ACPI_FUNCTION_TRACE(tb_get_table_header);
/*
* Flags contains the current processor mode (Virtual or Physical
@@ -148,6 +148,10 @@ acpi_tb_get_table_header(struct acpi_pointer *address,
sizeof(struct acpi_table_header),
(void *)&header);
if (ACPI_FAILURE(status)) {
+ ACPI_ERROR((AE_INFO,
+ "Could not map memory at %8.8X%8.8X for table header",
+ ACPI_FORMAT_UINT64(address->pointer.
+ physical)));
return_ACPI_STATUS(status);
}
@@ -198,7 +202,7 @@ acpi_tb_get_table_body(struct acpi_pointer *address,
{
acpi_status status;
- ACPI_FUNCTION_TRACE("tb_get_table_body");
+ ACPI_FUNCTION_TRACE(tb_get_table_body);
if (!table_info || !address) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -208,6 +212,7 @@ acpi_tb_get_table_body(struct acpi_pointer *address,
status = acpi_tb_table_override(header, table_info);
if (ACPI_SUCCESS(status)) {
+
/* Table was overridden by the host OS */
return_ACPI_STATUS(status);
@@ -241,7 +246,7 @@ acpi_tb_table_override(struct acpi_table_header *header,
acpi_status status;
struct acpi_pointer address;
- ACPI_FUNCTION_TRACE("tb_table_override");
+ ACPI_FUNCTION_TRACE(tb_table_override);
/*
* The OSL will examine the header and decide whether to override this
@@ -250,6 +255,7 @@ acpi_tb_table_override(struct acpi_table_header *header,
*/
status = acpi_os_table_override(header, &new_table);
if (ACPI_FAILURE(status)) {
+
/* Some severe error from the OSL, but we basically ignore it */
ACPI_EXCEPTION((AE_INFO, status,
@@ -258,6 +264,7 @@ acpi_tb_table_override(struct acpi_table_header *header,
}
if (!new_table) {
+
/* No table override */
return_ACPI_STATUS(AE_NO_ACPI_TABLES);
@@ -311,7 +318,7 @@ acpi_tb_get_this_table(struct acpi_pointer *address,
u8 allocation;
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("tb_get_this_table");
+ ACPI_FUNCTION_TRACE(tb_get_this_table);
/*
* Flags contains the current processor mode (Virtual or Physical
@@ -323,7 +330,7 @@ acpi_tb_get_this_table(struct acpi_pointer *address,
/* Pointer matches processor mode, copy the table to a new buffer */
- full_table = ACPI_MEM_ALLOCATE(header->length);
+ full_table = ACPI_ALLOCATE(header->length);
if (!full_table) {
ACPI_ERROR((AE_INFO,
"Could not allocate table memory for [%4.4s] length %X",
@@ -376,11 +383,12 @@ acpi_tb_get_this_table(struct acpi_pointer *address,
* Validate checksum for _most_ tables,
* even the ones whose signature we don't recognize
*/
- if (table_info->type != ACPI_TABLE_FACS) {
+ if (table_info->type != ACPI_TABLE_ID_FACS) {
status = acpi_tb_verify_table_checksum(full_table);
#if (!ACPI_CHECKSUM_ABORT)
if (ACPI_FAILURE(status)) {
+
/* Ignore the error if configuration says so */
status = AE_OK;
@@ -409,7 +417,7 @@ acpi_tb_get_this_table(struct acpi_pointer *address,
*
* PARAMETERS: table_type - one of the defined table types
* Instance - Which table of this type
- * table_ptr_loc - pointer to location to place the pointer for
+ * return_table - pointer to location to place the pointer for
* return
*
* RETURN: Status
@@ -420,57 +428,34 @@ acpi_tb_get_this_table(struct acpi_pointer *address,
acpi_status
acpi_tb_get_table_ptr(acpi_table_type table_type,
- u32 instance, struct acpi_table_header **table_ptr_loc)
+ u32 instance, struct acpi_table_header **return_table)
{
struct acpi_table_desc *table_desc;
u32 i;
- ACPI_FUNCTION_TRACE("tb_get_table_ptr");
-
- if (!acpi_gbl_DSDT) {
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
+ ACPI_FUNCTION_TRACE(tb_get_table_ptr);
- if (table_type > ACPI_TABLE_MAX) {
+ if (table_type > ACPI_TABLE_ID_MAX) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /*
- * For all table types (Single/Multiple), the first
- * instance is always in the list head.
- */
- if (instance == 1) {
- /* Get the first */
-
- *table_ptr_loc = NULL;
- if (acpi_gbl_table_lists[table_type].next) {
- *table_ptr_loc =
- acpi_gbl_table_lists[table_type].next->pointer;
- }
- return_ACPI_STATUS(AE_OK);
- }
-
- /* Check for instance out of range */
+ /* Check for instance out of range of the current table count */
if (instance > acpi_gbl_table_lists[table_type].count) {
return_ACPI_STATUS(AE_NOT_EXIST);
}
- /* Walk the list to get the desired table
- * Since the if (Instance == 1) check above checked for the
- * first table, setting table_desc equal to the .Next member
- * is actually pointing to the second table. Therefore, we
- * need to walk from the 2nd table until we reach the Instance
- * that the user is looking for and return its table pointer.
+ /*
+ * Walk the list to get the desired table
+ * Note: Instance is one-based
*/
table_desc = acpi_gbl_table_lists[table_type].next;
- for (i = 2; i < instance; i++) {
+ for (i = 1; i < instance; i++) {
table_desc = table_desc->next;
}
/* We are now pointing to the requested table's descriptor */
- *table_ptr_loc = table_desc->pointer;
-
+ *return_table = table_desc->pointer;
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/tables/tbgetall.c b/drivers/acpi/tables/tbgetall.c
index 134e5dc..ad982112 100644
--- a/drivers/acpi/tables/tbgetall.c
+++ b/drivers/acpi/tables/tbgetall.c
@@ -77,7 +77,7 @@ acpi_tb_get_primary_table(struct acpi_pointer *address,
acpi_status status;
struct acpi_table_header header;
- ACPI_FUNCTION_TRACE("tb_get_primary_table");
+ ACPI_FUNCTION_TRACE(tb_get_primary_table);
/* Ignore a NULL address in the RSDT */
@@ -140,7 +140,7 @@ acpi_tb_get_secondary_table(struct acpi_pointer *address,
acpi_status status;
struct acpi_table_header header;
- ACPI_FUNCTION_TRACE_STR("tb_get_secondary_table", signature);
+ ACPI_FUNCTION_TRACE_STR(tb_get_secondary_table, signature);
/* Get the header in order to match the signature */
@@ -151,7 +151,7 @@ acpi_tb_get_secondary_table(struct acpi_pointer *address,
/* Signature must match request */
- if (ACPI_STRNCMP(header.signature, signature, ACPI_NAME_SIZE)) {
+ if (!ACPI_COMPARE_NAME(header.signature, signature)) {
ACPI_ERROR((AE_INFO,
"Incorrect table signature - wanted [%s] found [%4.4s]",
signature, header.signature));
@@ -207,7 +207,7 @@ acpi_status acpi_tb_get_required_tables(void)
struct acpi_table_desc table_info;
struct acpi_pointer address;
- ACPI_FUNCTION_TRACE("tb_get_required_tables");
+ ACPI_FUNCTION_TRACE(tb_get_required_tables);
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%d ACPI tables in RSDT\n",
acpi_gbl_rsdt_table_count));
@@ -223,6 +223,7 @@ acpi_status acpi_tb_get_required_tables(void)
* any SSDTs.
*/
for (i = 0; i < acpi_gbl_rsdt_table_count; i++) {
+
/* Get the table address from the common internal XSDT */
address.pointer.value = acpi_gbl_XSDT->table_offset_entry[i];
@@ -305,6 +306,6 @@ acpi_status acpi_tb_get_required_tables(void)
/* Always delete the RSDP mapping, we are done with it */
- acpi_tb_delete_tables_by_type(ACPI_TABLE_RSDP);
+ acpi_tb_delete_tables_by_type(ACPI_TABLE_ID_RSDP);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c
index 7ffd0fd..7ca2df7 100644
--- a/drivers/acpi/tables/tbinstal.c
+++ b/drivers/acpi/tables/tbinstal.c
@@ -73,17 +73,18 @@ acpi_tb_match_signature(char *signature,
{
acpi_native_uint i;
- ACPI_FUNCTION_TRACE("tb_match_signature");
+ ACPI_FUNCTION_TRACE(tb_match_signature);
/* Search for a signature match among the known table types */
- for (i = 0; i < NUM_ACPI_TABLE_TYPES; i++) {
+ for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) {
if (!(acpi_gbl_table_data[i].flags & search_type)) {
continue;
}
if (!ACPI_STRNCMP(signature, acpi_gbl_table_data[i].signature,
acpi_gbl_table_data[i].sig_length)) {
+
/* Found a signature match, return index if requested */
if (table_info) {
@@ -122,7 +123,7 @@ acpi_status acpi_tb_install_table(struct acpi_table_desc *table_info)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("tb_install_table");
+ ACPI_FUNCTION_TRACE(tb_install_table);
/* Lock tables while installing */
@@ -187,7 +188,7 @@ acpi_tb_recognize_table(struct acpi_table_desc *table_info, u8 search_type)
struct acpi_table_header *table_header;
acpi_status status;
- ACPI_FUNCTION_TRACE("tb_recognize_table");
+ ACPI_FUNCTION_TRACE(tb_recognize_table);
/* Ensure that we have a valid table pointer */
@@ -218,7 +219,6 @@ acpi_tb_recognize_table(struct acpi_table_desc *table_info, u8 search_type)
/* Return the table type and length via the info struct */
table_info->length = (acpi_size) table_header->length;
-
return_ACPI_STATUS(status);
}
@@ -243,11 +243,11 @@ acpi_tb_init_table_descriptor(acpi_table_type table_type,
struct acpi_table_desc *table_desc;
acpi_status status;
- ACPI_FUNCTION_TRACE_U32("tb_init_table_descriptor", table_type);
+ ACPI_FUNCTION_TRACE_U32(tb_init_table_descriptor, table_type);
/* Allocate a descriptor for this table */
- table_desc = ACPI_MEM_CALLOCATE(sizeof(struct acpi_table_desc));
+ table_desc = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_table_desc));
if (!table_desc) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
@@ -274,7 +274,7 @@ acpi_tb_init_table_descriptor(acpi_table_type table_type,
* at this location, so return an error.
*/
if (list_head->next) {
- ACPI_MEM_FREE(table_desc);
+ ACPI_FREE(table_desc);
return_ACPI_STATUS(AE_ALREADY_EXISTS);
}
@@ -312,15 +312,14 @@ acpi_tb_init_table_descriptor(acpi_table_type table_type,
/* Finish initialization of the table descriptor */
+ table_desc->loaded_into_namespace = FALSE;
table_desc->type = (u8) table_type;
table_desc->pointer = table_info->pointer;
table_desc->length = table_info->length;
table_desc->allocation = table_info->allocation;
table_desc->aml_start = (u8 *) (table_desc->pointer + 1),
- table_desc->aml_length = (u32) (table_desc->length -
- (u32) sizeof(struct
- acpi_table_header));
- table_desc->loaded_into_namespace = FALSE;
+ table_desc->aml_length = (u32)
+ (table_desc->length - (u32) sizeof(struct acpi_table_header));
/*
* Set the appropriate global pointer (if there is one) to point to the
@@ -335,7 +334,6 @@ acpi_tb_init_table_descriptor(acpi_table_type table_type,
table_info->owner_id = table_desc->owner_id;
table_info->installed_desc = table_desc;
-
return_ACPI_STATUS(AE_OK);
}
@@ -359,7 +357,7 @@ void acpi_tb_delete_all_tables(void)
* Free memory allocated for ACPI tables
* Memory can either be mapped or allocated
*/
- for (type = 0; type < NUM_ACPI_TABLE_TYPES; type++) {
+ for (type = 0; type < (ACPI_TABLE_ID_MAX + 1); type++) {
acpi_tb_delete_tables_by_type(type);
}
}
@@ -383,9 +381,9 @@ void acpi_tb_delete_tables_by_type(acpi_table_type type)
u32 count;
u32 i;
- ACPI_FUNCTION_TRACE_U32("tb_delete_tables_by_type", type);
+ ACPI_FUNCTION_TRACE_U32(tb_delete_tables_by_type, type);
- if (type > ACPI_TABLE_MAX) {
+ if (type > ACPI_TABLE_ID_MAX) {
return_VOID;
}
@@ -396,28 +394,28 @@ void acpi_tb_delete_tables_by_type(acpi_table_type type)
/* Clear the appropriate "typed" global table pointer */
switch (type) {
- case ACPI_TABLE_RSDP:
+ case ACPI_TABLE_ID_RSDP:
acpi_gbl_RSDP = NULL;
break;
- case ACPI_TABLE_DSDT:
+ case ACPI_TABLE_ID_DSDT:
acpi_gbl_DSDT = NULL;
break;
- case ACPI_TABLE_FADT:
+ case ACPI_TABLE_ID_FADT:
acpi_gbl_FADT = NULL;
break;
- case ACPI_TABLE_FACS:
+ case ACPI_TABLE_ID_FACS:
acpi_gbl_FACS = NULL;
break;
- case ACPI_TABLE_XSDT:
+ case ACPI_TABLE_ID_XSDT:
acpi_gbl_XSDT = NULL;
break;
- case ACPI_TABLE_SSDT:
- case ACPI_TABLE_PSDT:
+ case ACPI_TABLE_ID_SSDT:
+ case ACPI_TABLE_ID_PSDT:
default:
break;
}
@@ -471,7 +469,7 @@ void acpi_tb_delete_single_table(struct acpi_table_desc *table_desc)
case ACPI_MEM_ALLOCATED:
- ACPI_MEM_FREE(table_desc->pointer);
+ ACPI_FREE(table_desc->pointer);
break;
case ACPI_MEM_MAPPED:
@@ -503,7 +501,7 @@ struct acpi_table_desc *acpi_tb_uninstall_table(struct acpi_table_desc
{
struct acpi_table_desc *next_desc;
- ACPI_FUNCTION_TRACE_PTR("tb_uninstall_table", table_desc);
+ ACPI_FUNCTION_TRACE_PTR(tb_uninstall_table, table_desc);
if (!table_desc) {
return_PTR(NULL);
@@ -530,7 +528,7 @@ struct acpi_table_desc *acpi_tb_uninstall_table(struct acpi_table_desc
/* Free the table descriptor */
next_desc = table_desc->next;
- ACPI_MEM_FREE(table_desc);
+ ACPI_FREE(table_desc);
/* Return pointer to the next descriptor */
diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c
index 4d30822..abcb08c 100644
--- a/drivers/acpi/tables/tbrsdt.c
+++ b/drivers/acpi/tables/tbrsdt.c
@@ -64,7 +64,7 @@ acpi_status acpi_tb_verify_rsdp(struct acpi_pointer *address)
acpi_status status;
struct rsdp_descriptor *rsdp;
- ACPI_FUNCTION_TRACE("tb_verify_rsdp");
+ ACPI_FUNCTION_TRACE(tb_verify_rsdp);
switch (address->pointer_type) {
case ACPI_LOGICAL_POINTER:
@@ -78,7 +78,7 @@ acpi_status acpi_tb_verify_rsdp(struct acpi_pointer *address)
*/
status = acpi_os_map_memory(address->pointer.physical,
sizeof(struct rsdp_descriptor),
- (void *)&rsdp);
+ ACPI_CAST_PTR(void, &rsdp));
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -95,15 +95,20 @@ acpi_status acpi_tb_verify_rsdp(struct acpi_pointer *address)
goto cleanup;
}
- /* The RSDP supplied is OK */
+ /* RSDP is ok. Init the table info */
table_info.pointer = ACPI_CAST_PTR(struct acpi_table_header, rsdp);
table_info.length = sizeof(struct rsdp_descriptor);
- table_info.allocation = ACPI_MEM_MAPPED;
+
+ if (address->pointer_type == ACPI_PHYSICAL_POINTER) {
+ table_info.allocation = ACPI_MEM_MAPPED;
+ } else {
+ table_info.allocation = ACPI_MEM_NOT_ALLOCATED;
+ }
/* Save the table pointers and allocation info */
- status = acpi_tb_init_table_descriptor(ACPI_TABLE_RSDP, &table_info);
+ status = acpi_tb_init_table_descriptor(ACPI_TABLE_ID_RSDP, &table_info);
if (ACPI_FAILURE(status)) {
goto cleanup;
}
@@ -174,22 +179,20 @@ void acpi_tb_get_rsdt_address(struct acpi_pointer *out_address)
acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr)
{
- int no_match;
+ char *signature;
ACPI_FUNCTION_ENTRY();
- /*
- * Search for appropriate signature, RSDT or XSDT
- */
+ /* Search for appropriate signature, RSDT or XSDT */
+
if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
- no_match = ACPI_STRNCMP((char *)table_ptr, RSDT_SIG,
- sizeof(RSDT_SIG) - 1);
+ signature = RSDT_SIG;
} else {
- no_match = ACPI_STRNCMP((char *)table_ptr, XSDT_SIG,
- sizeof(XSDT_SIG) - 1);
+ signature = XSDT_SIG;
}
- if (no_match) {
+ if (!ACPI_COMPARE_NAME(table_ptr->signature, signature)) {
+
/* Invalid RSDT or XSDT signature */
ACPI_ERROR((AE_INFO,
@@ -198,10 +201,8 @@ acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr)
ACPI_DUMP_BUFFER(acpi_gbl_RSDP, 20);
ACPI_ERROR((AE_INFO,
- "RSDT/XSDT signature at %X (%p) is invalid",
- acpi_gbl_RSDP->rsdt_physical_address,
- (void *)(acpi_native_uint) acpi_gbl_RSDP->
- rsdt_physical_address));
+ "RSDT/XSDT signature at %X is invalid",
+ acpi_gbl_RSDP->rsdt_physical_address));
if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
ACPI_ERROR((AE_INFO, "Looking for RSDT"));
@@ -234,13 +235,13 @@ acpi_status acpi_tb_get_table_rsdt(void)
acpi_status status;
struct acpi_pointer address;
- ACPI_FUNCTION_TRACE("tb_get_table_rsdt");
+ ACPI_FUNCTION_TRACE(tb_get_table_rsdt);
/* Get the RSDT/XSDT via the RSDP */
acpi_tb_get_rsdt_address(&address);
- table_info.type = ACPI_TABLE_XSDT;
+ table_info.type = ACPI_TABLE_ID_XSDT;
status = acpi_tb_get_table(&address, &table_info);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
@@ -274,12 +275,13 @@ acpi_status acpi_tb_get_table_rsdt(void)
/* Save the table pointers and allocation info */
- status = acpi_tb_init_table_descriptor(ACPI_TABLE_XSDT, &table_info);
+ status = acpi_tb_init_table_descriptor(ACPI_TABLE_ID_XSDT, &table_info);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
- acpi_gbl_XSDT = ACPI_CAST_PTR(XSDT_DESCRIPTOR, table_info.pointer);
+ acpi_gbl_XSDT =
+ ACPI_CAST_PTR(struct xsdt_descriptor, table_info.pointer);
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "XSDT located at %p\n", acpi_gbl_XSDT));
return_ACPI_STATUS(status);
diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c
index bc57159..209a401 100644
--- a/drivers/acpi/tables/tbutils.c
+++ b/drivers/acpi/tables/tbutils.c
@@ -71,7 +71,7 @@ acpi_status acpi_tb_is_table_installed(struct acpi_table_desc *new_table_desc)
{
struct acpi_table_desc *table_desc;
- ACPI_FUNCTION_TRACE("tb_is_table_installed");
+ ACPI_FUNCTION_TRACE(tb_is_table_installed);
/* Get the list descriptor and first table descriptor */
@@ -96,10 +96,11 @@ acpi_status acpi_tb_is_table_installed(struct acpi_table_desc *new_table_desc)
(!ACPI_MEMCMP
(table_desc->pointer, new_table_desc->pointer,
new_table_desc->pointer->length))) {
+
/* Match: this table is already installed */
ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
- "Table [%4.4s] already installed: Rev %X oem_table_id [%8.8s]\n",
+ "Table [%4.4s] already installed: Rev %X OemTableId [%8.8s]\n",
new_table_desc->pointer->signature,
new_table_desc->pointer->revision,
new_table_desc->pointer->
@@ -159,12 +160,8 @@ acpi_tb_validate_table_header(struct acpi_table_header *table_header)
ACPI_MOVE_32_TO_32(&signature, table_header->signature);
if (!acpi_ut_valid_acpi_name(signature)) {
- ACPI_ERROR((AE_INFO,
- "Table signature at %p [%p] has invalid characters",
- table_header, &signature));
-
- ACPI_WARNING((AE_INFO, "Invalid table signature found: [%4.4s]",
- ACPI_CAST_PTR(char, &signature)));
+ ACPI_ERROR((AE_INFO, "Invalid table signature 0x%8.8X",
+ signature));
ACPI_DUMP_BUFFER(table_header,
sizeof(struct acpi_table_header));
@@ -175,12 +172,9 @@ acpi_tb_validate_table_header(struct acpi_table_header *table_header)
if (table_header->length < sizeof(struct acpi_table_header)) {
ACPI_ERROR((AE_INFO,
- "Invalid length in table header %p name %4.4s",
- table_header, (char *)&signature));
-
- ACPI_WARNING((AE_INFO,
- "Invalid table header length (0x%X) found",
- (u32) table_header->length));
+ "Invalid length 0x%X in table with signature %4.4s",
+ (u32) table_header->length,
+ ACPI_CAST_PTR(char, &signature)));
ACPI_DUMP_BUFFER(table_header,
sizeof(struct acpi_table_header));
@@ -192,72 +186,119 @@ acpi_tb_validate_table_header(struct acpi_table_header *table_header)
/*******************************************************************************
*
- * FUNCTION: acpi_tb_verify_table_checksum
+ * FUNCTION: acpi_tb_sum_table
*
- * PARAMETERS: *table_header - ACPI table to verify
+ * PARAMETERS: Buffer - Buffer to sum
+ * Length - Size of the buffer
*
- * RETURN: 8 bit checksum of table
+ * RETURN: 8 bit sum of buffer
*
- * DESCRIPTION: Does an 8 bit checksum of table and returns status. A correct
- * table should have a checksum of 0.
+ * DESCRIPTION: Computes an 8 bit sum of the buffer(length) and returns it.
*
******************************************************************************/
-acpi_status
-acpi_tb_verify_table_checksum(struct acpi_table_header * table_header)
+u8 acpi_tb_sum_table(void *buffer, u32 length)
+{
+ acpi_native_uint i;
+ u8 sum = 0;
+
+ if (!buffer || !length) {
+ return (0);
+ }
+
+ for (i = 0; i < length; i++) {
+ sum = (u8) (sum + ((u8 *) buffer)[i]);
+ }
+ return (sum);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_generate_checksum
+ *
+ * PARAMETERS: Table - Pointer to a valid ACPI table (with a
+ * standard ACPI header)
+ *
+ * RETURN: 8 bit checksum of buffer
+ *
+ * DESCRIPTION: Computes an 8 bit checksum of the table.
+ *
+ ******************************************************************************/
+
+u8 acpi_tb_generate_checksum(struct acpi_table_header * table)
{
u8 checksum;
- acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("tb_verify_table_checksum");
+ /* Sum the entire table as-is */
- /* Compute the checksum on the table */
+ checksum = acpi_tb_sum_table(table, table->length);
- checksum =
- acpi_tb_generate_checksum(table_header, table_header->length);
+ /* Subtract off the existing checksum value in the table */
- /* Return the appropriate exception */
+ checksum = (u8) (checksum - table->checksum);
- if (checksum) {
- ACPI_WARNING((AE_INFO,
- "Invalid checksum in table [%4.4s] (%02X, sum %02X is not zero)",
- table_header->signature,
- (u32) table_header->checksum, (u32) checksum));
+ /* Compute the final checksum */
- status = AE_BAD_CHECKSUM;
- }
- return_ACPI_STATUS(status);
+ checksum = (u8) (0 - checksum);
+ return (checksum);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_generate_checksum
+ * FUNCTION: acpi_tb_set_checksum
*
- * PARAMETERS: Buffer - Buffer to checksum
- * Length - Size of the buffer
+ * PARAMETERS: Table - Pointer to a valid ACPI table (with a
+ * standard ACPI header)
*
- * RETURN: 8 bit checksum of buffer
+ * RETURN: None. Sets the table checksum field
*
- * DESCRIPTION: Computes an 8 bit checksum of the buffer(length) and returns it.
+ * DESCRIPTION: Computes an 8 bit checksum of the table and inserts the
+ * checksum into the table header.
*
******************************************************************************/
-u8 acpi_tb_generate_checksum(void *buffer, u32 length)
+void acpi_tb_set_checksum(struct acpi_table_header *table)
{
- u8 *end_buffer;
- u8 *rover;
- u8 sum = 0;
- if (buffer && length) {
- /* Buffer and Length are valid */
+ table->checksum = acpi_tb_generate_checksum(table);
+}
- end_buffer = ACPI_ADD_PTR(u8, buffer, length);
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_verify_table_checksum
+ *
+ * PARAMETERS: *table_header - ACPI table to verify
+ *
+ * RETURN: 8 bit checksum of table
+ *
+ * DESCRIPTION: Generates an 8 bit checksum of table and returns and compares
+ * it to the existing checksum value.
+ *
+ ******************************************************************************/
- for (rover = buffer; rover < end_buffer; rover++) {
- sum = (u8) (sum + *rover);
- }
+acpi_status
+acpi_tb_verify_table_checksum(struct acpi_table_header *table_header)
+{
+ u8 checksum;
+
+ ACPI_FUNCTION_TRACE(tb_verify_table_checksum);
+
+ /* Compute the checksum on the table */
+
+ checksum = acpi_tb_generate_checksum(table_header);
+
+ /* Checksum ok? */
+
+ if (checksum == table_header->checksum) {
+ return_ACPI_STATUS(AE_OK);
}
- return (sum);
+
+ ACPI_WARNING((AE_INFO,
+ "Incorrect checksum in table [%4.4s] - is %2.2X, should be %2.2X",
+ table_header->signature, table_header->checksum,
+ checksum));
+
+ return_ACPI_STATUS(AE_BAD_CHECKSUM);
}
#ifdef ACPI_OBSOLETE_FUNCTIONS
@@ -276,12 +317,12 @@ u8 acpi_tb_generate_checksum(void *buffer, u32 length)
acpi_status
acpi_tb_handle_to_object(u16 table_id,
- struct acpi_table_desc ** return_table_desc)
+ struct acpi_table_desc **return_table_desc)
{
u32 i;
struct acpi_table_desc *table_desc;
- ACPI_FUNCTION_NAME("tb_handle_to_object");
+ ACPI_FUNCTION_NAME(tb_handle_to_object);
for (i = 0; i < ACPI_TABLE_MAX; i++) {
table_desc = acpi_gbl_table_lists[i].next;
@@ -295,7 +336,7 @@ acpi_tb_handle_to_object(u16 table_id,
}
}
- ACPI_ERROR((AE_INFO, "table_id=%X does not exist", table_id));
+ ACPI_ERROR((AE_INFO, "TableId=%X does not exist", table_id));
return (AE_BAD_PARAMETER);
}
#endif
diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c
index 9fe53c9..4e91f29 100644
--- a/drivers/acpi/tables/tbxface.c
+++ b/drivers/acpi/tables/tbxface.c
@@ -42,8 +42,6 @@
* POSSIBILITY OF SUCH DAMAGES.
*/
-#include <linux/module.h>
-
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
#include <acpi/actables.h>
@@ -68,7 +66,7 @@ acpi_status acpi_load_tables(void)
struct acpi_pointer rsdp_address;
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_load_tables");
+ ACPI_FUNCTION_TRACE(acpi_load_tables);
/* Get the RSDP */
@@ -123,6 +121,8 @@ acpi_status acpi_load_tables(void)
return_ACPI_STATUS(status);
}
+ACPI_EXPORT_SYMBOL(acpi_load_tables)
+
#ifdef ACPI_FUTURE_USAGE
/*******************************************************************************
*
@@ -139,14 +139,13 @@ acpi_status acpi_load_tables(void)
* is determined that the table is invalid, the call will fail.
*
******************************************************************************/
-
acpi_status acpi_load_table(struct acpi_table_header *table_ptr)
{
acpi_status status;
struct acpi_table_desc table_info;
struct acpi_pointer address;
- ACPI_FUNCTION_TRACE("acpi_load_table");
+ ACPI_FUNCTION_TRACE(acpi_load_table);
if (!table_ptr) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -174,6 +173,7 @@ acpi_status acpi_load_table(struct acpi_table_header *table_ptr)
status = acpi_tb_install_table(&table_info);
if (ACPI_FAILURE(status)) {
if (status == AE_ALREADY_EXISTS) {
+
/* Table already exists, no error */
status = AE_OK;
@@ -188,12 +188,12 @@ acpi_status acpi_load_table(struct acpi_table_header *table_ptr)
/* Convert the table to common format if necessary */
switch (table_info.type) {
- case ACPI_TABLE_FADT:
+ case ACPI_TABLE_ID_FADT:
status = acpi_tb_convert_table_fadt();
break;
- case ACPI_TABLE_FACS:
+ case ACPI_TABLE_ID_FACS:
status = acpi_tb_build_common_facs(&table_info);
break;
@@ -208,6 +208,7 @@ acpi_status acpi_load_table(struct acpi_table_header *table_ptr)
}
if (ACPI_FAILURE(status)) {
+
/* Uninstall table and free the buffer */
(void)acpi_tb_uninstall_table(table_info.installed_desc);
@@ -216,6 +217,8 @@ acpi_status acpi_load_table(struct acpi_table_header *table_ptr)
return_ACPI_STATUS(status);
}
+ACPI_EXPORT_SYMBOL(acpi_load_table)
+
/*******************************************************************************
*
* FUNCTION: acpi_unload_table
@@ -227,16 +230,15 @@ acpi_status acpi_load_table(struct acpi_table_header *table_ptr)
* DESCRIPTION: This routine is used to force the unload of a table
*
******************************************************************************/
-
acpi_status acpi_unload_table(acpi_table_type table_type)
{
struct acpi_table_desc *table_desc;
- ACPI_FUNCTION_TRACE("acpi_unload_table");
+ ACPI_FUNCTION_TRACE(acpi_unload_table);
/* Parameter validation */
- if (table_type > ACPI_TABLE_MAX) {
+ if (table_type > ACPI_TABLE_ID_MAX) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
@@ -261,6 +263,8 @@ acpi_status acpi_unload_table(acpi_table_type table_type)
return_ACPI_STATUS(AE_OK);
}
+ACPI_EXPORT_SYMBOL(acpi_unload_table)
+
/*******************************************************************************
*
* FUNCTION: acpi_get_table_header
@@ -281,7 +285,6 @@ acpi_status acpi_unload_table(acpi_table_type table_type)
* have a standard header and is fixed length.
*
******************************************************************************/
-
acpi_status
acpi_get_table_header(acpi_table_type table_type,
u32 instance, struct acpi_table_header *out_table_header)
@@ -289,16 +292,16 @@ acpi_get_table_header(acpi_table_type table_type,
struct acpi_table_header *tbl_ptr;
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_get_table_header");
+ ACPI_FUNCTION_TRACE(acpi_get_table_header);
if ((instance == 0) ||
- (table_type == ACPI_TABLE_RSDP) || (!out_table_header)) {
+ (table_type == ACPI_TABLE_ID_RSDP) || (!out_table_header)) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
/* Check the table type and instance */
- if ((table_type > ACPI_TABLE_MAX) ||
+ if ((table_type > ACPI_TABLE_ID_MAX) ||
(ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags) &&
instance > 1)) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -325,6 +328,7 @@ acpi_get_table_header(acpi_table_type table_type,
return_ACPI_STATUS(status);
}
+ACPI_EXPORT_SYMBOL(acpi_get_table_header)
#endif /* ACPI_FUTURE_USAGE */
/*******************************************************************************
@@ -349,7 +353,6 @@ acpi_get_table_header(acpi_table_type table_type,
* a complete table including the header.
*
******************************************************************************/
-
acpi_status
acpi_get_table(acpi_table_type table_type,
u32 instance, struct acpi_buffer *ret_buffer)
@@ -358,7 +361,7 @@ acpi_get_table(acpi_table_type table_type,
acpi_status status;
acpi_size table_length;
- ACPI_FUNCTION_TRACE("acpi_get_table");
+ ACPI_FUNCTION_TRACE(acpi_get_table);
/* Parameter validation */
@@ -373,7 +376,7 @@ acpi_get_table(acpi_table_type table_type,
/* Check the table type and instance */
- if ((table_type > ACPI_TABLE_MAX) ||
+ if ((table_type > ACPI_TABLE_ID_MAX) ||
(ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags) &&
instance > 1)) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -396,7 +399,8 @@ acpi_get_table(acpi_table_type table_type,
/* Get the table length */
- if (table_type == ACPI_TABLE_RSDP) {
+ if (table_type == ACPI_TABLE_ID_RSDP) {
+
/* RSD PTR is the only "table" without a header */
table_length = sizeof(struct rsdp_descriptor);
@@ -417,4 +421,4 @@ acpi_get_table(acpi_table_type table_type,
return_ACPI_STATUS(AE_OK);
}
-EXPORT_SYMBOL(acpi_get_table);
+ACPI_EXPORT_SYMBOL(acpi_get_table)
diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c
index a62db6a..da2648b 100644
--- a/drivers/acpi/tables/tbxfroot.c
+++ b/drivers/acpi/tables/tbxfroot.c
@@ -41,8 +41,6 @@
* POSSIBILITY OF SUCH DAMAGES.
*/
-#include <linux/module.h>
-
#include <acpi/acpi.h>
#include <acpi/actables.h>
@@ -75,6 +73,7 @@ acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp)
* The signature and checksum must both be correct
*/
if (ACPI_STRNCMP((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0) {
+
/* Nope, BAD Signature */
return (AE_BAD_SIGNATURE);
@@ -82,15 +81,14 @@ acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp)
/* Check the standard checksum */
- if (acpi_tb_generate_checksum(rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
+ if (acpi_tb_sum_table(rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
return (AE_BAD_CHECKSUM);
}
/* Check extended checksum if table version >= 2 */
if ((rsdp->revision >= 2) &&
- (acpi_tb_generate_checksum(rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) !=
- 0)) {
+ (acpi_tb_sum_table(rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) {
return (AE_BAD_CHECKSUM);
}
@@ -121,7 +119,7 @@ acpi_tb_find_table(char *signature,
acpi_status status;
struct acpi_table_header *table;
- ACPI_FUNCTION_TRACE("tb_find_table");
+ ACPI_FUNCTION_TRACE(tb_find_table);
/* Validate string lengths */
@@ -131,7 +129,7 @@ acpi_tb_find_table(char *signature,
return_ACPI_STATUS(AE_AML_STRING_LIMIT);
}
- if (!ACPI_STRNCMP(signature, DSDT_SIG, ACPI_NAME_SIZE)) {
+ if (ACPI_COMPARE_NAME(signature, DSDT_SIG)) {
/*
* The DSDT pointer is contained in the FADT, not the RSDT.
* This code should suffice, because the only code that would perform
@@ -156,10 +154,12 @@ acpi_tb_find_table(char *signature,
/* Check oem_id and oem_table_id */
- if ((oem_id[0] && ACPI_STRNCMP(oem_id, table->oem_id,
- sizeof(table->oem_id))) ||
- (oem_table_id[0] && ACPI_STRNCMP(oem_table_id, table->oem_table_id,
- sizeof(table->oem_table_id)))) {
+ if ((oem_id[0] &&
+ ACPI_STRNCMP(oem_id, table->oem_id,
+ sizeof(table->oem_id))) ||
+ (oem_table_id[0] &&
+ ACPI_STRNCMP(oem_table_id, table->oem_table_id,
+ sizeof(table->oem_table_id)))) {
return_ACPI_STATUS(AE_AML_NAME_NOT_FOUND);
}
@@ -203,7 +203,7 @@ acpi_get_firmware_table(acpi_string signature,
u32 i;
u32 j;
- ACPI_FUNCTION_TRACE("acpi_get_firmware_table");
+ ACPI_FUNCTION_TRACE(acpi_get_firmware_table);
/*
* Ensure that at least the table manager is initialized. We don't
@@ -217,6 +217,7 @@ acpi_get_firmware_table(acpi_string signature,
/* Ensure that we have a RSDP */
if (!acpi_gbl_RSDP) {
+
/* Get the RSDP */
status = acpi_os_get_root_pointer(flags, &address);
@@ -261,7 +262,7 @@ acpi_get_firmware_table(acpi_string signature,
/* Get and validate the RSDT */
- rsdt_info = ACPI_MEM_CALLOCATE(sizeof(struct acpi_table_desc));
+ rsdt_info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_table_desc));
if (!rsdt_info) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
@@ -278,13 +279,13 @@ acpi_get_firmware_table(acpi_string signature,
/* Allocate a scratch table header and table descriptor */
- header = ACPI_MEM_ALLOCATE(sizeof(struct acpi_table_header));
+ header = ACPI_ALLOCATE(sizeof(struct acpi_table_header));
if (!header) {
status = AE_NO_MEMORY;
goto cleanup;
}
- table_info = ACPI_MEM_ALLOCATE(sizeof(struct acpi_table_desc));
+ table_info = ACPI_ALLOCATE(sizeof(struct acpi_table_desc));
if (!table_info) {
status = AE_NO_MEMORY;
goto cleanup;
@@ -308,12 +309,12 @@ acpi_get_firmware_table(acpi_string signature,
if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
address.pointer.value =
(ACPI_CAST_PTR
- (RSDT_DESCRIPTOR,
+ (struct rsdt_descriptor,
rsdt_info->pointer))->table_offset_entry[i];
} else {
address.pointer.value =
(ACPI_CAST_PTR
- (XSDT_DESCRIPTOR,
+ (struct xsdt_descriptor,
rsdt_info->pointer))->table_offset_entry[i];
}
@@ -326,11 +327,13 @@ acpi_get_firmware_table(acpi_string signature,
/* Compare table signatures and table instance */
- if (!ACPI_STRNCMP(header->signature, signature, ACPI_NAME_SIZE)) {
+ if (ACPI_COMPARE_NAME(header->signature, signature)) {
+
/* An instance of the table was found */
j++;
if (j >= instance) {
+
/* Found the correct instance, get the entire table */
status =
@@ -355,23 +358,21 @@ acpi_get_firmware_table(acpi_string signature,
acpi_os_unmap_memory(rsdt_info->pointer,
(acpi_size) rsdt_info->pointer->length);
}
- ACPI_MEM_FREE(rsdt_info);
+ ACPI_FREE(rsdt_info);
if (header) {
- ACPI_MEM_FREE(header);
+ ACPI_FREE(header);
}
if (table_info) {
- ACPI_MEM_FREE(table_info);
+ ACPI_FREE(table_info);
}
return_ACPI_STATUS(status);
}
-EXPORT_SYMBOL(acpi_get_firmware_table);
+ACPI_EXPORT_SYMBOL(acpi_get_firmware_table)
/* TBD: Move to a new file */
-
#if ACPI_MACHINE_WIDTH != 16
-
/*******************************************************************************
*
* FUNCTION: acpi_find_root_pointer
@@ -384,13 +385,12 @@ EXPORT_SYMBOL(acpi_get_firmware_table);
* DESCRIPTION: Find the RSDP
*
******************************************************************************/
-
acpi_status acpi_find_root_pointer(u32 flags, struct acpi_pointer *rsdp_address)
{
struct acpi_table_desc table_info;
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_find_root_pointer");
+ ACPI_FUNCTION_TRACE(acpi_find_root_pointer);
/* Get the RSDP */
@@ -407,6 +407,8 @@ acpi_status acpi_find_root_pointer(u32 flags, struct acpi_pointer *rsdp_address)
return_ACPI_STATUS(AE_OK);
}
+ACPI_EXPORT_SYMBOL(acpi_find_root_pointer)
+
/*******************************************************************************
*
* FUNCTION: acpi_tb_scan_memory_for_rsdp
@@ -419,14 +421,13 @@ acpi_status acpi_find_root_pointer(u32 flags, struct acpi_pointer *rsdp_address)
* DESCRIPTION: Search a block of memory for the RSDP signature
*
******************************************************************************/
-
static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length)
{
acpi_status status;
u8 *mem_rover;
u8 *end_address;
- ACPI_FUNCTION_TRACE("tb_scan_memory_for_rsdp");
+ ACPI_FUNCTION_TRACE(tb_scan_memory_for_rsdp);
end_address = start_address + length;
@@ -434,12 +435,14 @@ static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length)
for (mem_rover = start_address; mem_rover < end_address;
mem_rover += ACPI_RSDP_SCAN_STEP) {
+
/* The RSDP signature and checksum must both be correct */
status =
acpi_tb_validate_rsdp(ACPI_CAST_PTR
(struct rsdp_descriptor, mem_rover));
if (ACPI_SUCCESS(status)) {
+
/* Sig and checksum valid, we have found a real RSDP */
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -469,10 +472,10 @@ static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length)
*
* RETURN: Status, RSDP physical address
*
- * DESCRIPTION: search lower 1_mbyte of memory for the root system descriptor
+ * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor
* pointer structure. If it is found, set *RSDP to point to it.
*
- * NOTE1: The RSDp must be either in the first 1_k of the Extended
+ * NOTE1: The RSDP must be either in the first 1_k of the Extended
* BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.)
* Only a 32-bit physical address is necessary.
*
@@ -489,12 +492,13 @@ acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags)
u32 physical_address;
acpi_status status;
- ACPI_FUNCTION_TRACE("tb_find_rsdp");
+ ACPI_FUNCTION_TRACE(tb_find_rsdp);
/*
* Scan supports either logical addressing or physical addressing
*/
if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) {
+
/* 1a) Get the location of the Extended BIOS Data Area (EBDA) */
status = acpi_os_map_memory((acpi_physical_address)
@@ -521,7 +525,7 @@ acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags)
if (physical_address > 0x400) {
/*
- * 1b) Search EBDA paragraphs (EBDa is required to be a
+ * 1b) Search EBDA paragraphs (EBDA is required to be a
* minimum of 1_k length)
*/
status = acpi_os_map_memory((acpi_physical_address)
@@ -542,10 +546,11 @@ acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags)
acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE);
if (mem_rover) {
+
/* Return the physical address */
physical_address +=
- ACPI_PTR_DIFF(mem_rover, table_ptr);
+ (u32) ACPI_PTR_DIFF(mem_rover, table_ptr);
table_info->physical_address =
(acpi_physical_address) physical_address;
@@ -576,11 +581,12 @@ acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags)
acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
if (mem_rover) {
+
/* Return the physical address */
- physical_address =
- ACPI_HI_RSDP_WINDOW_BASE + ACPI_PTR_DIFF(mem_rover,
- table_ptr);
+ physical_address = (u32)
+ (ACPI_HI_RSDP_WINDOW_BASE +
+ ACPI_PTR_DIFF(mem_rover, table_ptr));
table_info->physical_address =
(acpi_physical_address) physical_address;
@@ -601,7 +607,7 @@ acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags)
if (physical_address > 0x400) {
/*
- * 1b) Search EBDA paragraphs (EBDa is required to be a minimum of
+ * 1b) Search EBDA paragraphs (EBDA is required to be a minimum of
* 1_k length)
*/
mem_rover =
@@ -609,6 +615,7 @@ acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags)
(physical_address),
ACPI_EBDA_WINDOW_SIZE);
if (mem_rover) {
+
/* Return the physical address */
table_info->physical_address =
@@ -624,6 +631,7 @@ acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags)
(ACPI_HI_RSDP_WINDOW_BASE),
ACPI_HI_RSDP_WINDOW_SIZE);
if (mem_rover) {
+
/* Found it, return the physical address */
table_info->physical_address =
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 19f3ea4..e7fe3a1 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -82,6 +82,7 @@ MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n");
static int acpi_thermal_add(struct acpi_device *device);
static int acpi_thermal_remove(struct acpi_device *device, int type);
+static int acpi_thermal_resume(struct acpi_device *device, int state);
static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file);
static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file);
static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file);
@@ -103,6 +104,7 @@ static struct acpi_driver acpi_thermal_driver = {
.ops = {
.add = acpi_thermal_add,
.remove = acpi_thermal_remove,
+ .resume = acpi_thermal_resume,
},
};
@@ -684,8 +686,7 @@ static void acpi_thermal_run(unsigned long data)
{
struct acpi_thermal *tz = (struct acpi_thermal *)data;
if (!tz->zombie)
- acpi_os_queue_for_execution(OSD_PRIORITY_GPE,
- acpi_thermal_check, (void *)data);
+ acpi_os_execute(OSL_GPE_HANDLER, acpi_thermal_check, (void *)data);
}
static void acpi_thermal_check(void *data)
@@ -942,8 +943,10 @@ acpi_thermal_write_trip_points(struct file *file,
memset(limit_string, 0, ACPI_THERMAL_MAX_LIMIT_STR_LEN);
active = kmalloc(ACPI_THERMAL_MAX_ACTIVE * sizeof(int), GFP_KERNEL);
- if (!active)
+ if (!active) {
+ kfree(limit_string);
return_VALUE(-ENOMEM);
+ }
if (!tz || (count > ACPI_THERMAL_MAX_LIMIT_STR_LEN - 1)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument\n"));
@@ -1342,7 +1345,7 @@ static int acpi_thermal_add(struct acpi_device *device)
result = acpi_thermal_add_fs(device);
if (result)
- return_VALUE(result);
+ goto end;
init_timer(&tz->timer);
@@ -1416,6 +1419,20 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
return_VALUE(0);
}
+static int acpi_thermal_resume(struct acpi_device *device, int state)
+{
+ struct acpi_thermal *tz = NULL;
+
+ if (!device || !acpi_driver_data(device))
+ return_VALUE(-EINVAL);
+
+ tz = (struct acpi_thermal *)acpi_driver_data(device);
+
+ acpi_thermal_check(tz);
+
+ return AE_OK;
+}
+
static int __init acpi_thermal_init(void)
{
int result = 0;
diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c
index 03b0044..7940fc1 100644
--- a/drivers/acpi/utilities/utalloc.c
+++ b/drivers/acpi/utilities/utalloc.c
@@ -46,24 +46,6 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utalloc")
-/* Local prototypes */
-#ifdef ACPI_DBG_TRACK_ALLOCATIONS
-static struct acpi_debug_mem_block *acpi_ut_find_allocation(void *allocation);
-
-static acpi_status
-acpi_ut_track_allocation(struct acpi_debug_mem_block *address,
- acpi_size size,
- u8 alloc_type, u32 component, char *module, u32 line);
-
-static acpi_status
-acpi_ut_remove_allocation(struct acpi_debug_mem_block *address,
- u32 component, char *module, u32 line);
-
-static acpi_status
-acpi_ut_create_list(char *list_name,
- u16 object_size, struct acpi_memory_list **return_cache);
-#endif
-
/*******************************************************************************
*
* FUNCTION: acpi_ut_create_caches
@@ -75,33 +57,23 @@ acpi_ut_create_list(char *list_name,
* DESCRIPTION: Create all local caches
*
******************************************************************************/
-
acpi_status acpi_ut_create_caches(void)
{
acpi_status status;
-#ifdef ACPI_DBG_TRACK_ALLOCATIONS
-
- /* Memory allocation lists */
-
- status = acpi_ut_create_list("Acpi-Global", 0, &acpi_gbl_global_list);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
+ /* Object Caches, for frequently used objects */
status =
- acpi_ut_create_list("Acpi-Namespace",
- sizeof(struct acpi_namespace_node),
- &acpi_gbl_ns_node_list);
+ acpi_os_create_cache("Acpi-Namespace",
+ sizeof(struct acpi_namespace_node),
+ ACPI_MAX_NAMESPACE_CACHE_DEPTH,
+ &acpi_gbl_namespace_cache);
if (ACPI_FAILURE(status)) {
return (status);
}
-#endif
-
- /* Object Caches, for frequently used objects */
status =
- acpi_os_create_cache("acpi_state", sizeof(union acpi_generic_state),
+ acpi_os_create_cache("Acpi-State", sizeof(union acpi_generic_state),
ACPI_MAX_STATE_CACHE_DEPTH,
&acpi_gbl_state_cache);
if (ACPI_FAILURE(status)) {
@@ -109,7 +81,7 @@ acpi_status acpi_ut_create_caches(void)
}
status =
- acpi_os_create_cache("acpi_parse",
+ acpi_os_create_cache("Acpi-Parse",
sizeof(struct acpi_parse_obj_common),
ACPI_MAX_PARSE_CACHE_DEPTH,
&acpi_gbl_ps_node_cache);
@@ -118,7 +90,7 @@ acpi_status acpi_ut_create_caches(void)
}
status =
- acpi_os_create_cache("acpi_parse_ext",
+ acpi_os_create_cache("Acpi-ParseExt",
sizeof(struct acpi_parse_obj_named),
ACPI_MAX_EXTPARSE_CACHE_DEPTH,
&acpi_gbl_ps_node_ext_cache);
@@ -127,7 +99,7 @@ acpi_status acpi_ut_create_caches(void)
}
status =
- acpi_os_create_cache("acpi_operand",
+ acpi_os_create_cache("Acpi-Operand",
sizeof(union acpi_operand_object),
ACPI_MAX_OBJECT_CACHE_DEPTH,
&acpi_gbl_operand_cache);
@@ -135,6 +107,24 @@ acpi_status acpi_ut_create_caches(void)
return (status);
}
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+
+ /* Memory allocation lists */
+
+ status = acpi_ut_create_list("Acpi-Global", 0, &acpi_gbl_global_list);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ status =
+ acpi_ut_create_list("Acpi-Namespace",
+ sizeof(struct acpi_namespace_node),
+ &acpi_gbl_ns_node_list);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+#endif
+
return (AE_OK);
}
@@ -153,6 +143,9 @@ acpi_status acpi_ut_create_caches(void)
acpi_status acpi_ut_delete_caches(void)
{
+ (void)acpi_os_delete_cache(acpi_gbl_namespace_cache);
+ acpi_gbl_namespace_cache = NULL;
+
(void)acpi_os_delete_cache(acpi_gbl_state_cache);
acpi_gbl_state_cache = NULL;
@@ -165,6 +158,21 @@ acpi_status acpi_ut_delete_caches(void)
(void)acpi_os_delete_cache(acpi_gbl_ps_node_ext_cache);
acpi_gbl_ps_node_ext_cache = NULL;
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+
+ /* Debug only - display leftover memory allocation, if any */
+
+ acpi_ut_dump_allocations(ACPI_UINT32_MAX, NULL);
+
+ /* Free memory lists */
+
+ acpi_os_free(acpi_gbl_global_list);
+ acpi_gbl_global_list = NULL;
+
+ acpi_os_free(acpi_gbl_ns_node_list);
+ acpi_gbl_ns_node_list = NULL;
+#endif
+
return (AE_OK);
}
@@ -252,7 +260,7 @@ acpi_ut_initialize_buffer(struct acpi_buffer * buffer,
/* Allocate a new buffer with local interface to allow tracking */
- buffer->pointer = ACPI_MEM_CALLOCATE(required_length);
+ buffer->pointer = ACPI_ALLOCATE_ZEROED(required_length);
if (!buffer->pointer) {
return (AE_NO_MEMORY);
}
@@ -288,7 +296,7 @@ acpi_ut_initialize_buffer(struct acpi_buffer * buffer,
*
* RETURN: Address of the allocated memory on success, NULL on failure.
*
- * DESCRIPTION: The subsystem's equivalent of malloc.
+ * DESCRIPTION: Subsystem equivalent of malloc.
*
******************************************************************************/
@@ -296,23 +304,23 @@ void *acpi_ut_allocate(acpi_size size, u32 component, char *module, u32 line)
{
void *allocation;
- ACPI_FUNCTION_TRACE_U32("ut_allocate", size);
+ ACPI_FUNCTION_TRACE_U32(ut_allocate, size);
/* Check for an inadvertent size of zero bytes */
if (!size) {
- ACPI_ERROR((module, line,
- "ut_allocate: Attempt to allocate zero bytes, allocating 1 byte"));
+ ACPI_WARNING((module, line,
+ "Attempt to allocate zero bytes, allocating 1 byte"));
size = 1;
}
allocation = acpi_os_allocate(size);
if (!allocation) {
+
/* Report allocation error */
- ACPI_ERROR((module, line,
- "ut_allocate: Could not allocate size %X",
- (u32) size));
+ ACPI_WARNING((module, line,
+ "Could not allocate size %X", (u32) size));
return_PTR(NULL);
}
@@ -322,7 +330,7 @@ void *acpi_ut_allocate(acpi_size size, u32 component, char *module, u32 line)
/*******************************************************************************
*
- * FUNCTION: acpi_ut_callocate
+ * FUNCTION: acpi_ut_allocate_zeroed
*
* PARAMETERS: Size - Size of the allocation
* Component - Component type of caller
@@ -331,542 +339,24 @@ void *acpi_ut_allocate(acpi_size size, u32 component, char *module, u32 line)
*
* RETURN: Address of the allocated memory on success, NULL on failure.
*
- * DESCRIPTION: Subsystem equivalent of calloc.
+ * DESCRIPTION: Subsystem equivalent of calloc. Allocate and zero memory.
*
******************************************************************************/
-void *acpi_ut_callocate(acpi_size size, u32 component, char *module, u32 line)
+void *acpi_ut_allocate_zeroed(acpi_size size,
+ u32 component, char *module, u32 line)
{
void *allocation;
- ACPI_FUNCTION_TRACE_U32("ut_callocate", size);
-
- /* Check for an inadvertent size of zero bytes */
-
- if (!size) {
- ACPI_ERROR((module, line,
- "Attempt to allocate zero bytes, allocating 1 byte"));
- size = 1;
- }
-
- allocation = acpi_os_allocate(size);
- if (!allocation) {
- /* Report allocation error */
-
- ACPI_ERROR((module, line,
- "Could not allocate size %X", (u32) size));
- return_PTR(NULL);
- }
-
- /* Clear the memory block */
-
- ACPI_MEMSET(allocation, 0, size);
- return_PTR(allocation);
-}
-
-#ifdef ACPI_DBG_TRACK_ALLOCATIONS
-/*
- * These procedures are used for tracking memory leaks in the subsystem, and
- * they get compiled out when the ACPI_DBG_TRACK_ALLOCATIONS is not set.
- *
- * Each memory allocation is tracked via a doubly linked list. Each
- * element contains the caller's component, module name, function name, and
- * line number. acpi_ut_allocate and acpi_ut_callocate call
- * acpi_ut_track_allocation to add an element to the list; deletion
- * occurs in the body of acpi_ut_free.
- */
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_create_list
- *
- * PARAMETERS: cache_name - Ascii name for the cache
- * object_size - Size of each cached object
- * return_cache - Where the new cache object is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Create a local memory list for tracking purposed
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ut_create_list(char *list_name,
- u16 object_size, struct acpi_memory_list **return_cache)
-{
- struct acpi_memory_list *cache;
-
- cache = acpi_os_allocate(sizeof(struct acpi_memory_list));
- if (!cache) {
- return (AE_NO_MEMORY);
- }
-
- ACPI_MEMSET(cache, 0, sizeof(struct acpi_memory_list));
-
- cache->list_name = list_name;
- cache->object_size = object_size;
-
- *return_cache = cache;
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_allocate_and_track
- *
- * PARAMETERS: Size - Size of the allocation
- * Component - Component type of caller
- * Module - Source file name of caller
- * Line - Line number of caller
- *
- * RETURN: Address of the allocated memory on success, NULL on failure.
- *
- * DESCRIPTION: The subsystem's equivalent of malloc.
- *
- ******************************************************************************/
-
-void *acpi_ut_allocate_and_track(acpi_size size,
- u32 component, char *module, u32 line)
-{
- struct acpi_debug_mem_block *allocation;
- acpi_status status;
-
- allocation =
- acpi_ut_allocate(size + sizeof(struct acpi_debug_mem_header),
- component, module, line);
- if (!allocation) {
- return (NULL);
- }
-
- status = acpi_ut_track_allocation(allocation, size,
- ACPI_MEM_MALLOC, component, module,
- line);
- if (ACPI_FAILURE(status)) {
- acpi_os_free(allocation);
- return (NULL);
- }
-
- acpi_gbl_global_list->total_allocated++;
- acpi_gbl_global_list->current_total_size += (u32) size;
-
- return ((void *)&allocation->user_space);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_callocate_and_track
- *
- * PARAMETERS: Size - Size of the allocation
- * Component - Component type of caller
- * Module - Source file name of caller
- * Line - Line number of caller
- *
- * RETURN: Address of the allocated memory on success, NULL on failure.
- *
- * DESCRIPTION: Subsystem equivalent of calloc.
- *
- ******************************************************************************/
-
-void *acpi_ut_callocate_and_track(acpi_size size,
- u32 component, char *module, u32 line)
-{
- struct acpi_debug_mem_block *allocation;
- acpi_status status;
-
- allocation =
- acpi_ut_callocate(size + sizeof(struct acpi_debug_mem_header),
- component, module, line);
- if (!allocation) {
- /* Report allocation error */
-
- ACPI_ERROR((module, line,
- "Could not allocate size %X", (u32) size));
- return (NULL);
- }
-
- status = acpi_ut_track_allocation(allocation, size,
- ACPI_MEM_CALLOC, component, module,
- line);
- if (ACPI_FAILURE(status)) {
- acpi_os_free(allocation);
- return (NULL);
- }
-
- acpi_gbl_global_list->total_allocated++;
- acpi_gbl_global_list->current_total_size += (u32) size;
-
- return ((void *)&allocation->user_space);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_free_and_track
- *
- * PARAMETERS: Allocation - Address of the memory to deallocate
- * Component - Component type of caller
- * Module - Source file name of caller
- * Line - Line number of caller
- *
- * RETURN: None
- *
- * DESCRIPTION: Frees the memory at Allocation
- *
- ******************************************************************************/
-
-void
-acpi_ut_free_and_track(void *allocation, u32 component, char *module, u32 line)
-{
- struct acpi_debug_mem_block *debug_block;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE_PTR("ut_free", allocation);
-
- if (NULL == allocation) {
- ACPI_ERROR((module, line, "Attempt to delete a NULL address"));
-
- return_VOID;
- }
-
- debug_block = ACPI_CAST_PTR(struct acpi_debug_mem_block,
- (((char *)allocation) -
- sizeof(struct acpi_debug_mem_header)));
-
- acpi_gbl_global_list->total_freed++;
- acpi_gbl_global_list->current_total_size -= debug_block->size;
-
- status = acpi_ut_remove_allocation(debug_block,
- component, module, line);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Could not free memory"));
- }
-
- acpi_os_free(debug_block);
- ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "%p freed\n", allocation));
- return_VOID;
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_find_allocation
- *
- * PARAMETERS: Allocation - Address of allocated memory
- *
- * RETURN: A list element if found; NULL otherwise.
- *
- * DESCRIPTION: Searches for an element in the global allocation tracking list.
- *
- ******************************************************************************/
-
-static struct acpi_debug_mem_block *acpi_ut_find_allocation(void *allocation)
-{
- struct acpi_debug_mem_block *element;
-
ACPI_FUNCTION_ENTRY();
- element = acpi_gbl_global_list->list_head;
-
- /* Search for the address. */
-
- while (element) {
- if (element == allocation) {
- return (element);
- }
-
- element = element->next;
- }
-
- return (NULL);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_track_allocation
- *
- * PARAMETERS: Allocation - Address of allocated memory
- * Size - Size of the allocation
- * alloc_type - MEM_MALLOC or MEM_CALLOC
- * Component - Component type of caller
- * Module - Source file name of caller
- * Line - Line number of caller
- *
- * RETURN: None.
- *
- * DESCRIPTION: Inserts an element into the global allocation tracking list.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ut_track_allocation(struct acpi_debug_mem_block *allocation,
- acpi_size size,
- u8 alloc_type, u32 component, char *module, u32 line)
-{
- struct acpi_memory_list *mem_list;
- struct acpi_debug_mem_block *element;
- acpi_status status = AE_OK;
-
- ACPI_FUNCTION_TRACE_PTR("ut_track_allocation", allocation);
-
- mem_list = acpi_gbl_global_list;
- status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /*
- * Search list for this address to make sure it is not already on the list.
- * This will catch several kinds of problems.
- */
- element = acpi_ut_find_allocation(allocation);
- if (element) {
- ACPI_ERROR((AE_INFO,
- "ut_track_allocation: Allocation already present in list! (%p)",
- allocation));
-
- ACPI_ERROR((AE_INFO, "Element %p Address %p",
- element, allocation));
-
- goto unlock_and_exit;
- }
-
- /* Fill in the instance data. */
-
- allocation->size = (u32) size;
- allocation->alloc_type = alloc_type;
- allocation->component = component;
- allocation->line = line;
-
- ACPI_STRNCPY(allocation->module, module, ACPI_MAX_MODULE_NAME);
- allocation->module[ACPI_MAX_MODULE_NAME - 1] = 0;
-
- /* Insert at list head */
-
- if (mem_list->list_head) {
- ((struct acpi_debug_mem_block *)(mem_list->list_head))->
- previous = allocation;
- }
-
- allocation->next = mem_list->list_head;
- allocation->previous = NULL;
-
- mem_list->list_head = allocation;
-
- unlock_and_exit:
- status = acpi_ut_release_mutex(ACPI_MTX_MEMORY);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_remove_allocation
- *
- * PARAMETERS: Allocation - Address of allocated memory
- * Component - Component type of caller
- * Module - Source file name of caller
- * Line - Line number of caller
- *
- * RETURN:
- *
- * DESCRIPTION: Deletes an element from the global allocation tracking list.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ut_remove_allocation(struct acpi_debug_mem_block *allocation,
- u32 component, char *module, u32 line)
-{
- struct acpi_memory_list *mem_list;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE("ut_remove_allocation");
-
- mem_list = acpi_gbl_global_list;
- if (NULL == mem_list->list_head) {
- /* No allocations! */
-
- ACPI_ERROR((module, line,
- "Empty allocation list, nothing to free!"));
-
- return_ACPI_STATUS(AE_OK);
- }
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Unlink */
-
- if (allocation->previous) {
- (allocation->previous)->next = allocation->next;
- } else {
- mem_list->list_head = allocation->next;
- }
-
- if (allocation->next) {
- (allocation->next)->previous = allocation->previous;
- }
-
- /* Mark the segment as deleted */
-
- ACPI_MEMSET(&allocation->user_space, 0xEA, allocation->size);
-
- ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Freeing size 0%X\n",
- allocation->size));
+ allocation = acpi_ut_allocate(size, component, module, line);
+ if (allocation) {
- status = acpi_ut_release_mutex(ACPI_MTX_MEMORY);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_dump_allocation_info
- *
- * PARAMETERS:
- *
- * RETURN: None
- *
- * DESCRIPTION: Print some info about the outstanding allocations.
- *
- ******************************************************************************/
+ /* Clear the memory block */
-#ifdef ACPI_FUTURE_USAGE
-void acpi_ut_dump_allocation_info(void)
-{
-/*
- struct acpi_memory_list *mem_list;
-*/
-
- ACPI_FUNCTION_TRACE("ut_dump_allocation_info");
-
-/*
- ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
- ("%30s: %4d (%3d Kb)\n", "Current allocations",
- mem_list->current_count,
- ROUND_UP_TO_1K (mem_list->current_size)));
-
- ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
- ("%30s: %4d (%3d Kb)\n", "Max concurrent allocations",
- mem_list->max_concurrent_count,
- ROUND_UP_TO_1K (mem_list->max_concurrent_size)));
-
- ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
- ("%30s: %4d (%3d Kb)\n", "Total (all) internal objects",
- running_object_count,
- ROUND_UP_TO_1K (running_object_size)));
-
- ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
- ("%30s: %4d (%3d Kb)\n", "Total (all) allocations",
- running_alloc_count,
- ROUND_UP_TO_1K (running_alloc_size)));
-
- ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
- ("%30s: %4d (%3d Kb)\n", "Current Nodes",
- acpi_gbl_current_node_count,
- ROUND_UP_TO_1K (acpi_gbl_current_node_size)));
-
- ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
- ("%30s: %4d (%3d Kb)\n", "Max Nodes",
- acpi_gbl_max_concurrent_node_count,
- ROUND_UP_TO_1K ((acpi_gbl_max_concurrent_node_count *
- sizeof (struct acpi_namespace_node)))));
-*/
- return_VOID;
-}
-#endif /* ACPI_FUTURE_USAGE */
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_dump_allocations
- *
- * PARAMETERS: Component - Component(s) to dump info for.
- * Module - Module to dump info for. NULL means all.
- *
- * RETURN: None
- *
- * DESCRIPTION: Print a list of all outstanding allocations.
- *
- ******************************************************************************/
-
-void acpi_ut_dump_allocations(u32 component, char *module)
-{
- struct acpi_debug_mem_block *element;
- union acpi_descriptor *descriptor;
- u32 num_outstanding = 0;
-
- ACPI_FUNCTION_TRACE("ut_dump_allocations");
-
- /*
- * Walk the allocation list.
- */
- if (ACPI_FAILURE(acpi_ut_acquire_mutex(ACPI_MTX_MEMORY))) {
- return;
+ ACPI_MEMSET(allocation, 0, size);
}
- element = acpi_gbl_global_list->list_head;
- while (element) {
- if ((element->component & component) &&
- ((module == NULL)
- || (0 == ACPI_STRCMP(module, element->module)))) {
- /* Ignore allocated objects that are in a cache */
-
- descriptor =
- ACPI_CAST_PTR(union acpi_descriptor,
- &element->user_space);
- if (descriptor->descriptor_id != ACPI_DESC_TYPE_CACHED) {
- acpi_os_printf("%p Len %04X %9.9s-%d [%s] ",
- descriptor, element->size,
- element->module, element->line,
- acpi_ut_get_descriptor_name
- (descriptor));
-
- /* Most of the elements will be Operand objects. */
-
- switch (ACPI_GET_DESCRIPTOR_TYPE(descriptor)) {
- case ACPI_DESC_TYPE_OPERAND:
- acpi_os_printf("%12.12s R%hd",
- acpi_ut_get_type_name
- (descriptor->object.
- common.type),
- descriptor->object.
- common.reference_count);
- break;
-
- case ACPI_DESC_TYPE_PARSER:
- acpi_os_printf("aml_opcode %04hX",
- descriptor->op.asl.
- aml_opcode);
- break;
-
- case ACPI_DESC_TYPE_NAMED:
- acpi_os_printf("%4.4s",
- acpi_ut_get_node_name
- (&descriptor->node));
- break;
-
- default:
- break;
- }
-
- acpi_os_printf("\n");
- num_outstanding++;
- }
- }
- element = element->next;
- }
-
- (void)acpi_ut_release_mutex(ACPI_MTX_MEMORY);
-
- /* Print summary */
-
- if (!num_outstanding) {
- ACPI_INFO((AE_INFO, "No outstanding allocations"));
- } else {
- ACPI_ERROR((AE_INFO,
- "%d(%X) Outstanding allocations",
- num_outstanding, num_outstanding));
- }
-
- return_VOID;
+ return (allocation);
}
-
-#endif /* #ifdef ACPI_DBG_TRACK_ALLOCATIONS */
diff --git a/drivers/acpi/utilities/utcache.c b/drivers/acpi/utilities/utcache.c
index 2177cb1..56270a3 100644
--- a/drivers/acpi/utilities/utcache.c
+++ b/drivers/acpi/utilities/utcache.c
@@ -118,13 +118,14 @@ acpi_status acpi_os_purge_cache(struct acpi_memory_list * cache)
/* Walk the list of objects in this cache */
while (cache->list_head) {
+
/* Delete and unlink one cached state object */
next = *(ACPI_CAST_INDIRECT_PTR(char,
&(((char *)cache->
list_head)[cache->
link_offset])));
- ACPI_MEM_FREE(cache->list_head);
+ ACPI_FREE(cache->list_head);
cache->list_head = next;
cache->current_depth--;
@@ -193,7 +194,7 @@ acpi_os_release_object(struct acpi_memory_list * cache, void *object)
/* If cache is full, just free this object */
if (cache->current_depth >= cache->max_depth) {
- ACPI_MEM_FREE(object);
+ ACPI_FREE(object);
ACPI_MEM_TRACKING(cache->total_freed++);
}
@@ -243,7 +244,7 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache)
acpi_status status;
void *object;
- ACPI_FUNCTION_NAME("os_acquire_object");
+ ACPI_FUNCTION_NAME(os_acquire_object);
if (!cache) {
return (NULL);
@@ -259,6 +260,7 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache)
/* Check the cache first */
if (cache->list_head) {
+
/* There is an object available, use it */
object = cache->list_head;
@@ -270,9 +272,9 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache)
cache->current_depth--;
ACPI_MEM_TRACKING(cache->hits++);
- ACPI_MEM_TRACKING(ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Object %p from %s cache\n",
- object, cache->list_name)));
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Object %p from %s cache\n", object,
+ cache->list_name));
status = acpi_ut_release_mutex(ACPI_MTX_CACHES);
if (ACPI_FAILURE(status)) {
@@ -287,14 +289,14 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache)
ACPI_MEM_TRACKING(cache->total_allocated++);
- /* Avoid deadlock with ACPI_MEM_CALLOCATE */
+ /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */
status = acpi_ut_release_mutex(ACPI_MTX_CACHES);
if (ACPI_FAILURE(status)) {
return (NULL);
}
- object = ACPI_MEM_CALLOCATE(cache->object_size);
+ object = ACPI_ALLOCATE_ZEROED(cache->object_size);
if (!object) {
return (NULL);
}
diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c
index df2d320..5e1a80d 100644
--- a/drivers/acpi/utilities/utcopy.c
+++ b/drivers/acpi/utilities/utcopy.c
@@ -109,7 +109,7 @@ acpi_ut_copy_isimple_to_esimple(union acpi_operand_object *internal_object,
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("ut_copy_isimple_to_esimple");
+ ACPI_FUNCTION_TRACE(ut_copy_isimple_to_esimple);
*buffer_space_used = 0;
@@ -325,7 +325,7 @@ acpi_ut_copy_ipackage_to_epackage(union acpi_operand_object *internal_object,
acpi_status status;
struct acpi_pkg_info info;
- ACPI_FUNCTION_TRACE("ut_copy_ipackage_to_epackage");
+ ACPI_FUNCTION_TRACE(ut_copy_ipackage_to_epackage);
/*
* First package at head of the buffer
@@ -383,7 +383,7 @@ acpi_ut_copy_iobject_to_eobject(union acpi_operand_object *internal_object,
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ut_copy_iobject_to_eobject");
+ ACPI_FUNCTION_TRACE(ut_copy_iobject_to_eobject);
if (ACPI_GET_OBJECT_TYPE(internal_object) == ACPI_TYPE_PACKAGE) {
/*
@@ -442,7 +442,7 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object,
{
union acpi_operand_object *internal_object;
- ACPI_FUNCTION_TRACE("ut_copy_esimple_to_isimple");
+ ACPI_FUNCTION_TRACE(ut_copy_esimple_to_isimple);
/*
* Simple types supported are: String, Buffer, Integer
@@ -472,8 +472,8 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object,
case ACPI_TYPE_STRING:
internal_object->string.pointer =
- ACPI_MEM_CALLOCATE((acpi_size) external_object->string.
- length + 1);
+ ACPI_ALLOCATE_ZEROED((acpi_size) external_object->string.
+ length + 1);
if (!internal_object->string.pointer) {
goto error_exit;
}
@@ -488,7 +488,7 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object,
case ACPI_TYPE_BUFFER:
internal_object->buffer.pointer =
- ACPI_MEM_CALLOCATE(external_object->buffer.length);
+ ACPI_ALLOCATE_ZEROED(external_object->buffer.length);
if (!internal_object->buffer.pointer) {
goto error_exit;
}
@@ -552,7 +552,7 @@ acpi_ut_copy_epackage_to_ipackage(union acpi_operand_object *internal_object,
union acpi_operand_object *this_internal_obj;
union acpi_object *this_external_obj;
- ACPI_FUNCTION_TRACE("ut_copy_epackage_to_ipackage");
+ ACPI_FUNCTION_TRACE(ut_copy_epackage_to_ipackage);
/*
* First package at head of the buffer
@@ -600,7 +600,7 @@ acpi_ut_copy_eobject_to_iobject(union acpi_object *external_object,
{
acpi_status status;
- ACPI_FUNCTION_TRACE("ut_copy_eobject_to_iobject");
+ ACPI_FUNCTION_TRACE(ut_copy_eobject_to_iobject);
if (external_object->type == ACPI_TYPE_PACKAGE) {
/*
@@ -676,7 +676,7 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc,
if ((source_desc->buffer.pointer) &&
(source_desc->buffer.length)) {
dest_desc->buffer.pointer =
- ACPI_MEM_ALLOCATE(source_desc->buffer.length);
+ ACPI_ALLOCATE(source_desc->buffer.length);
if (!dest_desc->buffer.pointer) {
return (AE_NO_MEMORY);
}
@@ -697,8 +697,8 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc,
*/
if (source_desc->string.pointer) {
dest_desc->string.pointer =
- ACPI_MEM_ALLOCATE((acpi_size) source_desc->string.
- length + 1);
+ ACPI_ALLOCATE((acpi_size) source_desc->string.
+ length + 1);
if (!dest_desc->string.pointer) {
return (AE_NO_MEMORY);
}
@@ -805,9 +805,7 @@ acpi_ut_copy_ielement_to_ielement(u8 object_type,
/*
* Create the object array
*/
- target_object->package.elements =
- ACPI_MEM_CALLOCATE(((acpi_size) source_object->package.
- count + 1) * sizeof(void *));
+ target_object->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size) source_object->package.count + 1) * sizeof(void *));
if (!target_object->package.elements) {
status = AE_NO_MEMORY;
goto error_exit;
@@ -856,7 +854,7 @@ acpi_ut_copy_ipackage_to_ipackage(union acpi_operand_object *source_obj,
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("ut_copy_ipackage_to_ipackage");
+ ACPI_FUNCTION_TRACE(ut_copy_ipackage_to_ipackage);
dest_obj->common.type = ACPI_GET_OBJECT_TYPE(source_obj);
dest_obj->common.flags = source_obj->common.flags;
@@ -865,10 +863,10 @@ acpi_ut_copy_ipackage_to_ipackage(union acpi_operand_object *source_obj,
/*
* Create the object array and walk the source package tree
*/
- dest_obj->package.elements = ACPI_MEM_CALLOCATE(((acpi_size)
- source_obj->package.
- count +
- 1) * sizeof(void *));
+ dest_obj->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size)
+ source_obj->package.
+ count +
+ 1) * sizeof(void *));
if (!dest_obj->package.elements) {
ACPI_ERROR((AE_INFO, "Package allocation failure"));
return_ACPI_STATUS(AE_NO_MEMORY);
@@ -882,6 +880,7 @@ acpi_ut_copy_ipackage_to_ipackage(union acpi_operand_object *source_obj,
acpi_ut_copy_ielement_to_ielement,
walk_state);
if (ACPI_FAILURE(status)) {
+
/* On failure, delete the destination package object */
acpi_ut_remove_reference(dest_obj);
@@ -911,7 +910,7 @@ acpi_ut_copy_iobject_to_iobject(union acpi_operand_object *source_desc,
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("ut_copy_iobject_to_iobject");
+ ACPI_FUNCTION_TRACE(ut_copy_iobject_to_iobject);
/* Create the top level object */
diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c
index 35f3d58..5ec1cfc 100644
--- a/drivers/acpi/utilities/utdebug.c
+++ b/drivers/acpi/utilities/utdebug.c
@@ -41,8 +41,6 @@
* POSSIBILITY OF SUCH DAMAGES.
*/
-#include <linux/module.h>
-
#include <acpi/acpi.h>
#define _COMPONENT ACPI_UTILITIES
@@ -123,12 +121,14 @@ static const char *acpi_ut_trim_function_name(const char *function_name)
/* All Function names are longer than 4 chars, check is safe */
if (*(ACPI_CAST_PTR(u32, function_name)) == ACPI_PREFIX_MIXED) {
+
/* This is the case where the original source has not been modified */
return (function_name + 4);
}
if (*(ACPI_CAST_PTR(u32, function_name)) == ACPI_PREFIX_LOWER) {
+
/* This is the case where the source has been 'linuxized' */
return (function_name + 5);
@@ -162,7 +162,7 @@ acpi_ut_debug_print(u32 requested_debug_level,
const char *function_name,
char *module_name, u32 component_id, char *format, ...)
{
- u32 thread_id;
+ acpi_thread_id thread_id;
va_list args;
/*
@@ -177,7 +177,6 @@ acpi_ut_debug_print(u32 requested_debug_level,
* Thread tracking and context switch notification
*/
thread_id = acpi_os_get_thread_id();
-
if (thread_id != acpi_gbl_prev_thread_id) {
if (ACPI_LV_THREADS & acpi_dbg_level) {
acpi_os_printf
@@ -206,7 +205,7 @@ acpi_ut_debug_print(u32 requested_debug_level,
acpi_os_vprintf(format, args);
}
-EXPORT_SYMBOL(acpi_ut_debug_print);
+ACPI_EXPORT_SYMBOL(acpi_ut_debug_print)
/*******************************************************************************
*
@@ -226,7 +225,6 @@ EXPORT_SYMBOL(acpi_ut_debug_print);
* debug_print so that the same macros can be used.
*
******************************************************************************/
-
void ACPI_INTERNAL_VAR_XFACE
acpi_ut_debug_print_raw(u32 requested_debug_level,
u32 line_number,
@@ -244,7 +242,7 @@ acpi_ut_debug_print_raw(u32 requested_debug_level,
acpi_os_vprintf(format, args);
}
-EXPORT_SYMBOL(acpi_ut_debug_print_raw);
+ACPI_EXPORT_SYMBOL(acpi_ut_debug_print_raw)
/*******************************************************************************
*
@@ -261,7 +259,6 @@ EXPORT_SYMBOL(acpi_ut_debug_print_raw);
* set in debug_level
*
******************************************************************************/
-
void
acpi_ut_trace(u32 line_number,
const char *function_name, char *module_name, u32 component_id)
@@ -275,7 +272,7 @@ acpi_ut_trace(u32 line_number,
component_id, "%s\n", acpi_gbl_fn_entry_str);
}
-EXPORT_SYMBOL(acpi_ut_trace);
+ACPI_EXPORT_SYMBOL(acpi_ut_trace)
/*******************************************************************************
*
@@ -293,7 +290,6 @@ EXPORT_SYMBOL(acpi_ut_trace);
* set in debug_level
*
******************************************************************************/
-
void
acpi_ut_trace_ptr(u32 line_number,
const char *function_name,
@@ -400,7 +396,7 @@ acpi_ut_exit(u32 line_number,
acpi_gbl_nesting_level--;
}
-EXPORT_SYMBOL(acpi_ut_exit);
+ACPI_EXPORT_SYMBOL(acpi_ut_exit)
/*******************************************************************************
*
@@ -418,7 +414,6 @@ EXPORT_SYMBOL(acpi_ut_exit);
* set in debug_level. Prints exit status also.
*
******************************************************************************/
-
void
acpi_ut_status_exit(u32 line_number,
const char *function_name,
@@ -442,7 +437,7 @@ acpi_ut_status_exit(u32 line_number,
acpi_gbl_nesting_level--;
}
-EXPORT_SYMBOL(acpi_ut_status_exit);
+ACPI_EXPORT_SYMBOL(acpi_ut_status_exit)
/*******************************************************************************
*
@@ -460,7 +455,6 @@ EXPORT_SYMBOL(acpi_ut_status_exit);
* set in debug_level. Prints exit value also.
*
******************************************************************************/
-
void
acpi_ut_value_exit(u32 line_number,
const char *function_name,
@@ -475,7 +469,7 @@ acpi_ut_value_exit(u32 line_number,
acpi_gbl_nesting_level--;
}
-EXPORT_SYMBOL(acpi_ut_value_exit);
+ACPI_EXPORT_SYMBOL(acpi_ut_value_exit)
/*******************************************************************************
*
@@ -493,7 +487,6 @@ EXPORT_SYMBOL(acpi_ut_value_exit);
* set in debug_level. Prints exit value also.
*
******************************************************************************/
-
void
acpi_ut_ptr_exit(u32 line_number,
const char *function_name,
@@ -524,20 +517,13 @@ acpi_ut_ptr_exit(u32 line_number,
*
******************************************************************************/
-void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id)
+void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display)
{
acpi_native_uint i = 0;
acpi_native_uint j;
u32 temp32;
u8 buf_char;
- /* Only dump the buffer if tracing is enabled */
-
- if (!((ACPI_LV_TABLES & acpi_dbg_level) &&
- (component_id & acpi_dbg_layer))) {
- return;
- }
-
if ((count < 4) || (count & 0x01)) {
display = DB_BYTE_DISPLAY;
}
@@ -545,6 +531,7 @@ void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id)
/* Nasty little dump buffer routine! */
while (i < count) {
+
/* Print current offset */
acpi_os_printf("%6.4X: ", (u32) i);
@@ -553,6 +540,7 @@ void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id)
for (j = 0; j < 16;) {
if (i + j >= count) {
+
/* Dump fill spaces */
acpi_os_printf("%*s", ((display * 2) + 1), " ");
@@ -561,6 +549,7 @@ void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id)
}
switch (display) {
+ case DB_BYTE_DISPLAY:
default: /* Default is BYTE display */
acpi_os_printf("%02X ", buffer[i + j]);
@@ -618,3 +607,31 @@ void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id)
return;
}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_dump_buffer
+ *
+ * PARAMETERS: Buffer - Buffer to dump
+ * Count - Amount to dump, in bytes
+ * Display - BYTE, WORD, DWORD, or QWORD display
+ * component_iD - Caller's component ID
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Generic dump buffer in both hex and ascii.
+ *
+ ******************************************************************************/
+
+void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id)
+{
+
+ /* Only dump the buffer if tracing is enabled */
+
+ if (!((ACPI_LV_TABLES & acpi_dbg_level) &&
+ (component_id & acpi_dbg_layer))) {
+ return;
+ }
+
+ acpi_ut_dump_buffer2(buffer, count, display);
+}
diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c
index 1db9695..67b9f32 100644
--- a/drivers/acpi/utilities/utdelete.c
+++ b/drivers/acpi/utilities/utdelete.c
@@ -76,7 +76,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
union acpi_operand_object *second_desc;
union acpi_operand_object *next_desc;
- ACPI_FUNCTION_TRACE_PTR("ut_delete_internal_obj", object);
+ ACPI_FUNCTION_TRACE_PTR(ut_delete_internal_obj, object);
if (!object) {
return_VOID;
@@ -96,6 +96,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
/* Free the actual string buffer */
if (!(object->common.flags & AOPOBJ_STATIC_POINTER)) {
+
/* But only if it is NOT a pointer into an ACPI table */
obj_pointer = object->string.pointer;
@@ -111,6 +112,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
/* Free the actual buffer */
if (!(object->common.flags & AOPOBJ_STATIC_POINTER)) {
+
/* But only if it is NOT a pointer into an ACPI table */
obj_pointer = object->buffer.pointer;
@@ -198,11 +200,22 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
*/
handler_desc = object->region.handler;
if (handler_desc) {
- if (handler_desc->address_space.
- hflags &
+ if (handler_desc->address_space.handler_flags &
ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) {
- obj_pointer =
- second_desc->extra.region_context;
+
+ /* Deactivate region and free region context */
+
+ if (handler_desc->address_space.setup) {
+ (void)handler_desc->
+ address_space.setup(object,
+ ACPI_REGION_DEACTIVATE,
+ handler_desc->
+ address_space.
+ context,
+ &second_desc->
+ extra.
+ region_context);
+ }
}
acpi_ut_remove_reference(handler_desc);
@@ -234,7 +247,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
if (obj_pointer) {
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
"Deleting Object Subptr %p\n", obj_pointer));
- ACPI_MEM_FREE(obj_pointer);
+ ACPI_FREE(obj_pointer);
}
/* Now the object can be safely deleted */
@@ -263,7 +276,7 @@ void acpi_ut_delete_internal_object_list(union acpi_operand_object **obj_list)
{
union acpi_operand_object **internal_obj;
- ACPI_FUNCTION_TRACE("ut_delete_internal_object_list");
+ ACPI_FUNCTION_TRACE(ut_delete_internal_object_list);
/* Walk the null-terminated internal list */
@@ -273,7 +286,7 @@ void acpi_ut_delete_internal_object_list(union acpi_operand_object **obj_list)
/* Free the combined parameter pointer list and object array */
- ACPI_MEM_FREE(obj_list);
+ ACPI_FREE(obj_list);
return_VOID;
}
@@ -296,7 +309,7 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action)
u16 count;
u16 new_count;
- ACPI_FUNCTION_NAME("ut_update_ref_count");
+ ACPI_FUNCTION_NAME(ut_update_ref_count);
if (!object) {
return;
@@ -306,11 +319,9 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action)
new_count = count;
/*
- * Perform the reference count action
- * (increment, decrement, or force delete)
+ * Perform the reference count action (increment, decrement, force delete)
*/
switch (action) {
-
case REF_INCREMENT:
new_count++;
@@ -347,7 +358,6 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action)
if (new_count == 0) {
acpi_ut_delete_internal_obj(object);
}
-
break;
case REF_FORCE_DELETE:
@@ -372,13 +382,10 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action)
* (A deleted object will have a huge reference count)
*/
if (count > ACPI_MAX_REFERENCE_COUNT) {
-
ACPI_WARNING((AE_INFO,
- "Large Reference Count (%X) in object %p",
- count, object));
+ "Large Reference Count (%X) in object %p", count,
+ object));
}
-
- return;
}
/*******************************************************************************
@@ -404,7 +411,7 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action)
******************************************************************************/
acpi_status
-acpi_ut_update_object_reference(union acpi_operand_object * object, u16 action)
+acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
{
acpi_status status = AE_OK;
union acpi_generic_state *state_list = NULL;
@@ -412,9 +419,10 @@ acpi_ut_update_object_reference(union acpi_operand_object * object, u16 action)
union acpi_generic_state *state;
acpi_native_uint i;
- ACPI_FUNCTION_TRACE_PTR("ut_update_object_reference", object);
+ ACPI_FUNCTION_TRACE_PTR(ut_update_object_reference, object);
while (object) {
+
/* Make sure that this isn't a namespace handle */
if (ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_NAMED) {
@@ -507,11 +515,11 @@ acpi_ut_update_object_reference(union acpi_operand_object * object, u16 action)
case ACPI_TYPE_REGION:
default:
- break; /* No subobjects */
+ break; /* No subobjects for all other types */
}
/*
- * Now we can update the count in the main object. This can only
+ * Now we can update the count in the main object. This can only
* happen after we update the sub-objects in case this causes the
* main object to be deleted.
*/
@@ -556,7 +564,7 @@ acpi_ut_update_object_reference(union acpi_operand_object * object, u16 action)
void acpi_ut_add_reference(union acpi_operand_object *object)
{
- ACPI_FUNCTION_TRACE_PTR("ut_add_reference", object);
+ ACPI_FUNCTION_TRACE_PTR(ut_add_reference, object);
/* Ensure that we have a valid object */
@@ -589,11 +597,11 @@ void acpi_ut_add_reference(union acpi_operand_object *object)
void acpi_ut_remove_reference(union acpi_operand_object *object)
{
- ACPI_FUNCTION_TRACE_PTR("ut_remove_reference", object);
+ ACPI_FUNCTION_TRACE_PTR(ut_remove_reference, object);
/*
- * Allow a NULL pointer to be passed in, just ignore it. This saves
- * each caller from having to check. Also, ignore NS nodes.
+ * Allow a NULL pointer to be passed in, just ignore it. This saves
+ * each caller from having to check. Also, ignore NS nodes.
*
*/
if (!object ||
@@ -613,7 +621,7 @@ void acpi_ut_remove_reference(union acpi_operand_object *object)
/*
* Decrement the reference count, and only actually delete the object
- * if the reference count becomes 0. (Must also decrement the ref count
+ * if the reference count becomes 0. (Must also decrement the ref count
* of all subobjects!)
*/
(void)acpi_ut_update_object_reference(object, REF_DECREMENT);
diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c
index 106cc97..d6d7121 100644
--- a/drivers/acpi/utilities/uteval.c
+++ b/drivers/acpi/utilities/uteval.c
@@ -56,6 +56,34 @@ static acpi_status
acpi_ut_translate_one_cid(union acpi_operand_object *obj_desc,
struct acpi_compatible_id *one_cid);
+/*
+ * Strings supported by the _OSI predefined (internal) method.
+ */
+static const char *acpi_interfaces_supported[] = {
+ /* Operating System Vendor Strings */
+
+ "Linux",
+ "Windows 2000",
+ "Windows 2001",
+ "Windows 2001 SP0",
+ "Windows 2001 SP1",
+ "Windows 2001 SP2",
+ "Windows 2001 SP3",
+ "Windows 2001 SP4",
+ "Windows 2001.1",
+ "Windows 2001.1 SP1", /* Added 03/2006 */
+ "Windows 2006", /* Added 03/2006 */
+
+ /* Feature Group Strings */
+
+ "Extended Address Space Descriptor"
+ /*
+ * All "optional" feature group strings (features that are implemented
+ * by the host) should be implemented in the host version of
+ * acpi_os_validate_interface and should not be added here.
+ */
+};
+
/*******************************************************************************
*
* FUNCTION: acpi_ut_osi_implementation
@@ -64,18 +92,18 @@ acpi_ut_translate_one_cid(union acpi_operand_object *obj_desc,
*
* RETURN: Status
*
- * DESCRIPTION: Implementation of _OSI predefined control method
- * Supported = _OSI (String)
+ * DESCRIPTION: Implementation of the _OSI predefined control method
*
******************************************************************************/
acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state)
{
+ acpi_status status;
union acpi_operand_object *string_desc;
union acpi_operand_object *return_desc;
acpi_native_uint i;
- ACPI_FUNCTION_TRACE("ut_osi_implementation");
+ ACPI_FUNCTION_TRACE(ut_osi_implementation);
/* Validate the string input argument */
@@ -84,28 +112,47 @@ acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state)
return_ACPI_STATUS(AE_TYPE);
}
- /* Create a return object (Default value = 0) */
+ /* Create a return object */
return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
if (!return_desc) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
- /* Compare input string to table of supported strings */
+ /* Default return value is SUPPORTED */
+
+ return_desc->integer.value = ACPI_UINT32_MAX;
+ walk_state->return_desc = return_desc;
+
+ /* Compare input string to static table of supported interfaces */
- for (i = 0; i < ACPI_NUM_OSI_STRINGS; i++) {
- if (!ACPI_STRCMP(string_desc->string.pointer,
- ACPI_CAST_PTR(char,
- acpi_gbl_valid_osi_strings[i])))
- {
- /* This string is supported */
+ for (i = 0; i < ACPI_ARRAY_LENGTH(acpi_interfaces_supported); i++) {
+ if (!ACPI_STRCMP
+ (string_desc->string.pointer,
+ acpi_interfaces_supported[i])) {
- return_desc->integer.value = 0xFFFFFFFF;
- break;
+ /* The interface is supported */
+
+ return_ACPI_STATUS(AE_CTRL_TERMINATE);
}
}
- walk_state->return_desc = return_desc;
+ /*
+ * Did not match the string in the static table, call the host OSL to
+ * check for a match with one of the optional strings (such as
+ * "Module Device", "3.0 Thermal Model", etc.)
+ */
+ status = acpi_os_validate_interface(string_desc->string.pointer);
+ if (ACPI_SUCCESS(status)) {
+
+ /* The interface is supported */
+
+ return_ACPI_STATUS(AE_CTRL_TERMINATE);
+ }
+
+ /* The interface is not supported */
+
+ return_desc->integer.value = 0;
return_ACPI_STATUS(AE_CTRL_TERMINATE);
}
@@ -134,19 +181,26 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
u32 expected_return_btypes,
union acpi_operand_object **return_desc)
{
- struct acpi_parameter_info info;
+ struct acpi_evaluate_info *info;
acpi_status status;
u32 return_btype;
- ACPI_FUNCTION_TRACE("ut_evaluate_object");
+ ACPI_FUNCTION_TRACE(ut_evaluate_object);
- info.node = prefix_node;
- info.parameters = NULL;
- info.parameter_type = ACPI_PARAM_ARGS;
+ /* Allocate the evaluation information block */
+
+ info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
+ if (!info) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ info->prefix_node = prefix_node;
+ info->pathname = path;
+ info->parameter_type = ACPI_PARAM_ARGS;
/* Evaluate the object/method */
- status = acpi_ns_evaluate_relative(path, &info);
+ status = acpi_ns_evaluate(info);
if (ACPI_FAILURE(status)) {
if (status == AE_NOT_FOUND) {
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
@@ -158,25 +212,25 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
prefix_node, path, status);
}
- return_ACPI_STATUS(status);
+ goto cleanup;
}
/* Did we get a return object? */
- if (!info.return_object) {
+ if (!info->return_object) {
if (expected_return_btypes) {
ACPI_ERROR_METHOD("No object was returned from",
prefix_node, path, AE_NOT_EXIST);
- return_ACPI_STATUS(AE_NOT_EXIST);
+ status = AE_NOT_EXIST;
}
- return_ACPI_STATUS(AE_OK);
+ goto cleanup;
}
/* Map the return object type to the bitmapped type */
- switch (ACPI_GET_OBJECT_TYPE(info.return_object)) {
+ switch (ACPI_GET_OBJECT_TYPE(info->return_object)) {
case ACPI_TYPE_INTEGER:
return_btype = ACPI_BTYPE_INTEGER;
break;
@@ -204,8 +258,8 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
* happen frequently if the "implicit return" feature is enabled.
* Just delete the return object and return AE_OK.
*/
- acpi_ut_remove_reference(info.return_object);
- return_ACPI_STATUS(AE_OK);
+ acpi_ut_remove_reference(info->return_object);
+ goto cleanup;
}
/* Is the return object one of the expected types? */
@@ -217,19 +271,23 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
ACPI_ERROR((AE_INFO,
"Type returned from %s was incorrect: %s, expected Btypes: %X",
path,
- acpi_ut_get_object_type_name(info.return_object),
+ acpi_ut_get_object_type_name(info->return_object),
expected_return_btypes));
/* On error exit, we must delete the return object */
- acpi_ut_remove_reference(info.return_object);
- return_ACPI_STATUS(AE_TYPE);
+ acpi_ut_remove_reference(info->return_object);
+ status = AE_TYPE;
+ goto cleanup;
}
/* Object type is OK, return it */
- *return_desc = info.return_object;
- return_ACPI_STATUS(AE_OK);
+ *return_desc = info->return_object;
+
+ cleanup:
+ ACPI_FREE(info);
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
@@ -257,7 +315,7 @@ acpi_ut_evaluate_numeric_object(char *object_name,
union acpi_operand_object *obj_desc;
acpi_status status;
- ACPI_FUNCTION_TRACE("ut_evaluate_numeric_object");
+ ACPI_FUNCTION_TRACE(ut_evaluate_numeric_object);
status = acpi_ut_evaluate_object(device_node, object_name,
ACPI_BTYPE_INTEGER, &obj_desc);
@@ -333,7 +391,7 @@ acpi_ut_execute_HID(struct acpi_namespace_node *device_node,
union acpi_operand_object *obj_desc;
acpi_status status;
- ACPI_FUNCTION_TRACE("ut_execute_HID");
+ ACPI_FUNCTION_TRACE(ut_execute_HID);
status = acpi_ut_evaluate_object(device_node, METHOD_NAME__HID,
ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING,
@@ -343,6 +401,7 @@ acpi_ut_execute_HID(struct acpi_namespace_node *device_node,
}
if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) {
+
/* Convert the Numeric HID to string */
acpi_ex_eisa_id_to_string((u32) obj_desc->integer.value,
@@ -436,7 +495,7 @@ acpi_ut_execute_CID(struct acpi_namespace_node * device_node,
struct acpi_compatible_id_list *cid_list;
acpi_native_uint i;
- ACPI_FUNCTION_TRACE("ut_execute_CID");
+ ACPI_FUNCTION_TRACE(ut_execute_CID);
/* Evaluate the _CID method for this device */
@@ -459,7 +518,7 @@ acpi_ut_execute_CID(struct acpi_namespace_node * device_node,
size = (((count - 1) * sizeof(struct acpi_compatible_id)) +
sizeof(struct acpi_compatible_id_list));
- cid_list = ACPI_MEM_CALLOCATE((acpi_size) size);
+ cid_list = ACPI_ALLOCATE_ZEROED((acpi_size) size);
if (!cid_list) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
@@ -479,6 +538,7 @@ acpi_ut_execute_CID(struct acpi_namespace_node * device_node,
/* The _CID object can be either a single CID or a package (list) of CIDs */
if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_PACKAGE) {
+
/* Translate each package element */
for (i = 0; i < count; i++) {
@@ -499,7 +559,7 @@ acpi_ut_execute_CID(struct acpi_namespace_node * device_node,
/* Cleanup on error */
if (ACPI_FAILURE(status)) {
- ACPI_MEM_FREE(cid_list);
+ ACPI_FREE(cid_list);
} else {
*return_cid_list = cid_list;
}
@@ -533,7 +593,7 @@ acpi_ut_execute_UID(struct acpi_namespace_node *device_node,
union acpi_operand_object *obj_desc;
acpi_status status;
- ACPI_FUNCTION_TRACE("ut_execute_UID");
+ ACPI_FUNCTION_TRACE(ut_execute_UID);
status = acpi_ut_evaluate_object(device_node, METHOD_NAME__UID,
ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING,
@@ -543,6 +603,7 @@ acpi_ut_execute_UID(struct acpi_namespace_node *device_node,
}
if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) {
+
/* Convert the Numeric UID to string */
acpi_ex_unsigned_integer_to_string(obj_desc->integer.value,
@@ -582,7 +643,7 @@ acpi_ut_execute_STA(struct acpi_namespace_node *device_node, u32 * flags)
union acpi_operand_object *obj_desc;
acpi_status status;
- ACPI_FUNCTION_TRACE("ut_execute_STA");
+ ACPI_FUNCTION_TRACE(ut_execute_STA);
status = acpi_ut_evaluate_object(device_node, METHOD_NAME__STA,
ACPI_BTYPE_INTEGER, &obj_desc);
@@ -632,7 +693,7 @@ acpi_ut_execute_sxds(struct acpi_namespace_node *device_node, u8 * highest)
acpi_status status;
u32 i;
- ACPI_FUNCTION_TRACE("ut_execute_Sxds");
+ ACPI_FUNCTION_TRACE(ut_execute_sxds);
for (i = 0; i < 4; i++) {
highest[i] = 0xFF;
diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
index ffd1338..e5999c6 100644
--- a/drivers/acpi/utilities/utglobal.c
+++ b/drivers/acpi/utilities/utglobal.c
@@ -43,7 +43,6 @@
#define DEFINE_ACPI_GLOBALS
-#include <linux/module.h>
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
@@ -119,6 +118,7 @@ const char *acpi_format_exception(acpi_status status)
}
if (!exception) {
+
/* Exception code was not recognized */
ACPI_ERROR((AE_INFO,
@@ -143,12 +143,10 @@ const char *acpi_format_exception(acpi_status status)
/* Debug switch - level and trace mask */
u32 acpi_dbg_level = ACPI_DEBUG_DEFAULT;
-EXPORT_SYMBOL(acpi_dbg_level);
/* Debug switch - layer (component) mask */
u32 acpi_dbg_layer = ACPI_COMPONENT_DEFAULT | ACPI_ALL_DRIVERS;
-EXPORT_SYMBOL(acpi_dbg_layer);
u32 acpi_gbl_nesting_level = 0;
/* Debugger globals */
@@ -183,28 +181,6 @@ const char *acpi_gbl_highest_dstate_names[4] = {
"_S4D"
};
-/*
- * Strings supported by the _OSI predefined (internal) method.
- * When adding strings, be sure to update ACPI_NUM_OSI_STRINGS.
- */
-const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS] = {
- /* Operating System Vendor Strings */
-
- "Linux",
- "Windows 2000",
- "Windows 2001",
- "Windows 2001.1",
- "Windows 2001 SP0",
- "Windows 2001 SP1",
- "Windows 2001 SP2",
- "Windows 2001 SP3",
- "Windows 2001 SP4",
-
- /* Feature Group Strings */
-
- "Extended Address Space Descriptor"
-};
-
/*******************************************************************************
*
* Namespace globals
@@ -317,9 +293,9 @@ char acpi_ut_hex_to_ascii_char(acpi_integer integer, u32 position)
*
******************************************************************************/
-struct acpi_table_list acpi_gbl_table_lists[NUM_ACPI_TABLE_TYPES];
+struct acpi_table_list acpi_gbl_table_lists[ACPI_TABLE_ID_MAX + 1];
-struct acpi_table_support acpi_gbl_table_data[NUM_ACPI_TABLE_TYPES] = {
+struct acpi_table_support acpi_gbl_table_data[ACPI_TABLE_ID_MAX + 1] = {
/*********** Name, Signature, Global typed pointer Signature size, Type How many allowed?, Contains valid AML? */
/* RSDP 0 */ {RSDP_NAME, RSDP_SIG, NULL, sizeof(RSDP_SIG) - 1,
@@ -467,7 +443,6 @@ struct acpi_fixed_event_info acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS] =
/* Region type decoding */
const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = {
-/*! [Begin] no source code translation (keep these ASL Keywords as-is) */
"SystemMemory",
"SystemIO",
"PCI_Config",
@@ -476,16 +451,15 @@ const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = {
"CMOS",
"PCIBARTarget",
"DataTable"
-/*! [End] no source code translation !*/
};
char *acpi_ut_get_region_name(u8 space_id)
{
if (space_id >= ACPI_USER_REGION_BEGIN) {
- return ("user_defined_region");
+ return ("UserDefinedRegion");
} else if (space_id >= ACPI_NUM_PREDEFINED_REGIONS) {
- return ("invalid_space_id");
+ return ("InvalidSpaceId");
}
return (ACPI_CAST_PTR(char, acpi_gbl_region_types[space_id]));
@@ -506,20 +480,18 @@ char *acpi_ut_get_region_name(u8 space_id)
/* Event type decoding */
static const char *acpi_gbl_event_types[ACPI_NUM_FIXED_EVENTS] = {
-/*! [Begin] no source code translation (keep these strings as-is) */
"PM_Timer",
"GlobalLock",
"PowerButton",
"SleepButton",
"RealTimeClock",
-/*! [End] no source code translation !*/
};
char *acpi_ut_get_event_name(u32 event_id)
{
if (event_id > ACPI_EVENT_MAX) {
- return ("invalid_event_iD");
+ return ("InvalidEventID");
}
return (ACPI_CAST_PTR(char, acpi_gbl_event_types[event_id]));
@@ -550,7 +522,6 @@ static const char acpi_gbl_bad_type[] = "UNDEFINED";
/* Printable names of the ACPI object types */
static const char *acpi_gbl_ns_type_names[] = {
-/*! [Begin] no source code translation (keep these strings as-is) */
/* 00 */ "Untyped",
/* 01 */ "Integer",
/* 02 */ "String",
@@ -582,7 +553,6 @@ static const char *acpi_gbl_ns_type_names[] = {
/* 28 */ "Extra",
/* 29 */ "Data",
/* 30 */ "Invalid"
-/*! [End] no source code translation !*/
};
char *acpi_ut_get_type_name(acpi_object_type type)
@@ -635,14 +605,14 @@ char *acpi_ut_get_node_name(void *object)
/* Descriptor must be a namespace node */
- if (node->descriptor != ACPI_DESC_TYPE_NAMED) {
+ if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) {
return ("####");
}
/* Name must be a valid ACPI name */
if (!acpi_ut_valid_acpi_name(node->name.integer)) {
- return ("????");
+ node->name.integer = acpi_ut_repair_name(node->name.integer);
}
/* Return the name */
@@ -665,7 +635,6 @@ char *acpi_ut_get_node_name(void *object)
/* Printable names of object descriptor types */
static const char *acpi_gbl_desc_type_names[] = {
-/*! [Begin] no source code translation (keep these ASL Keywords as-is) */
/* 00 */ "Invalid",
/* 01 */ "Cached",
/* 02 */ "State-Generic",
@@ -682,7 +651,6 @@ static const char *acpi_gbl_desc_type_names[] = {
/* 13 */ "Parser",
/* 14 */ "Operand",
/* 15 */ "Node"
-/*! [End] no source code translation !*/
};
char *acpi_ut_get_descriptor_name(void *object)
@@ -723,7 +691,7 @@ char *acpi_ut_get_descriptor_name(void *object)
char *acpi_ut_get_mutex_name(u32 mutex_id)
{
- if (mutex_id > MAX_MUTEX) {
+ if (mutex_id > ACPI_MAX_MUTEX) {
return ("Invalid Mutex ID");
}
@@ -747,6 +715,7 @@ u8 acpi_ut_valid_object_type(acpi_object_type type)
{
if (type > ACPI_TYPE_LOCAL_MAX) {
+
/* Note: Assumes all TYPEs are contiguous (external/local) */
return (FALSE);
@@ -773,7 +742,7 @@ void acpi_ut_init_globals(void)
acpi_status status;
u32 i;
- ACPI_FUNCTION_TRACE("ut_init_globals");
+ ACPI_FUNCTION_TRACE(ut_init_globals);
/* Create all memory caches */
@@ -784,14 +753,14 @@ void acpi_ut_init_globals(void)
/* ACPI table structure */
- for (i = 0; i < NUM_ACPI_TABLE_TYPES; i++) {
+ for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) {
acpi_gbl_table_lists[i].next = NULL;
acpi_gbl_table_lists[i].count = 0;
}
/* Mutex locked flags */
- for (i = 0; i < NUM_MUTEX; i++) {
+ for (i = 0; i < ACPI_NUM_MUTEX; i++) {
acpi_gbl_mutex_info[i].mutex = NULL;
acpi_gbl_mutex_info[i].thread_id = ACPI_MUTEX_NOT_ACQUIRED;
acpi_gbl_mutex_info[i].use_count = 0;
@@ -856,7 +825,7 @@ void acpi_ut_init_globals(void)
acpi_gbl_root_node = NULL;
acpi_gbl_root_node_struct.name.integer = ACPI_ROOT_NAME;
- acpi_gbl_root_node_struct.descriptor = ACPI_DESC_TYPE_NAMED;
+ acpi_gbl_root_node_struct.descriptor_type = ACPI_DESC_TYPE_NAMED;
acpi_gbl_root_node_struct.type = ACPI_TYPE_DEVICE;
acpi_gbl_root_node_struct.child = NULL;
acpi_gbl_root_node_struct.peer = NULL;
@@ -869,3 +838,6 @@ void acpi_ut_init_globals(void)
return_VOID;
}
+
+ACPI_EXPORT_SYMBOL(acpi_dbg_level)
+ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c
index ba771b4..ff76055 100644
--- a/drivers/acpi/utilities/utinit.c
+++ b/drivers/acpi/utilities/utinit.c
@@ -50,7 +50,7 @@ ACPI_MODULE_NAME("utinit")
/* Local prototypes */
static void
-acpi_ut_fadt_register_error(char *register_name, u32 value, acpi_size offset);
+acpi_ut_fadt_register_error(char *register_name, u32 value, u8 offset);
static void acpi_ut_terminate(void);
@@ -69,12 +69,12 @@ static void acpi_ut_terminate(void);
******************************************************************************/
static void
-acpi_ut_fadt_register_error(char *register_name, u32 value, acpi_size offset)
+acpi_ut_fadt_register_error(char *register_name, u32 value, u8 offset)
{
ACPI_WARNING((AE_INFO,
"Invalid FADT value %s=%X at offset %X FADT=%p",
- register_name, value, (u32) offset, acpi_gbl_FADT));
+ register_name, value, offset, acpi_gbl_FADT));
}
/******************************************************************************
@@ -176,7 +176,7 @@ static void acpi_ut_terminate(void)
struct acpi_gpe_xrupt_info *gpe_xrupt_info;
struct acpi_gpe_xrupt_info *next_gpe_xrupt_info;
- ACPI_FUNCTION_TRACE("ut_terminate");
+ ACPI_FUNCTION_TRACE(ut_terminate);
/* Free global tables, etc. */
/* Free global GPE blocks and related info structures */
@@ -186,14 +186,14 @@ static void acpi_ut_terminate(void)
gpe_block = gpe_xrupt_info->gpe_block_list_head;
while (gpe_block) {
next_gpe_block = gpe_block->next;
- ACPI_MEM_FREE(gpe_block->event_info);
- ACPI_MEM_FREE(gpe_block->register_info);
- ACPI_MEM_FREE(gpe_block);
+ ACPI_FREE(gpe_block->event_info);
+ ACPI_FREE(gpe_block->register_info);
+ ACPI_FREE(gpe_block);
gpe_block = next_gpe_block;
}
next_gpe_xrupt_info = gpe_xrupt_info->next;
- ACPI_MEM_FREE(gpe_xrupt_info);
+ ACPI_FREE(gpe_xrupt_info);
gpe_xrupt_info = next_gpe_xrupt_info;
}
@@ -216,7 +216,7 @@ static void acpi_ut_terminate(void)
void acpi_ut_subsystem_shutdown(void)
{
- ACPI_FUNCTION_TRACE("ut_subsystem_shutdown");
+ ACPI_FUNCTION_TRACE(ut_subsystem_shutdown);
/* Just exit if subsystem is already shutdown */
@@ -228,6 +228,7 @@ void acpi_ut_subsystem_shutdown(void)
/* Subsystem appears active, go ahead and shut it down */
acpi_gbl_shutdown = TRUE;
+ acpi_gbl_startup_flags = 0;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Shutting down ACPI Subsystem\n"));
/* Close the acpi_event Handling */
@@ -245,12 +246,5 @@ void acpi_ut_subsystem_shutdown(void)
/* Purge the local caches */
(void)acpi_ut_delete_caches();
-
- /* Debug only - display leftover memory allocation, if any */
-
-#ifdef ACPI_DBG_TRACK_ALLOCATIONS
- acpi_ut_dump_allocations(ACPI_UINT32_MAX, NULL);
-#endif
-
return_VOID;
}
diff --git a/drivers/acpi/utilities/utmath.c b/drivers/acpi/utilities/utmath.c
index 4a33604..19d74be 100644
--- a/drivers/acpi/utilities/utmath.c
+++ b/drivers/acpi/utilities/utmath.c
@@ -77,7 +77,7 @@ acpi_ut_short_divide(acpi_integer dividend,
union uint64_overlay quotient;
u32 remainder32;
- ACPI_FUNCTION_TRACE("ut_short_divide");
+ ACPI_FUNCTION_TRACE(ut_short_divide);
/* Always check for a zero divisor */
@@ -139,7 +139,7 @@ acpi_ut_divide(acpi_integer in_dividend,
union uint64_overlay partial2;
union uint64_overlay partial3;
- ACPI_FUNCTION_TRACE("ut_divide");
+ ACPI_FUNCTION_TRACE(ut_divide);
/* Always check for a zero divisor */
@@ -261,7 +261,7 @@ acpi_ut_short_divide(acpi_integer in_dividend,
acpi_integer * out_quotient, u32 * out_remainder)
{
- ACPI_FUNCTION_TRACE("ut_short_divide");
+ ACPI_FUNCTION_TRACE(ut_short_divide);
/* Always check for a zero divisor */
@@ -287,7 +287,7 @@ acpi_ut_divide(acpi_integer in_dividend,
acpi_integer in_divisor,
acpi_integer * out_quotient, acpi_integer * out_remainder)
{
- ACPI_FUNCTION_TRACE("ut_divide");
+ ACPI_FUNCTION_TRACE(ut_divide);
/* Always check for a zero divisor */
diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c
index 7364f5f..5c75d35 100644
--- a/drivers/acpi/utilities/utmisc.c
+++ b/drivers/acpi/utilities/utmisc.c
@@ -49,6 +49,33 @@ ACPI_MODULE_NAME("utmisc")
/*******************************************************************************
*
+ * FUNCTION: acpi_ut_is_aml_table
+ *
+ * PARAMETERS: Table - An ACPI table
+ *
+ * RETURN: TRUE if table contains executable AML; FALSE otherwise
+ *
+ * DESCRIPTION: Check ACPI Signature for a table that contains AML code.
+ * Currently, these are DSDT,SSDT,PSDT. All other table types are
+ * data tables that do not contain AML code.
+ *
+ ******************************************************************************/
+u8 acpi_ut_is_aml_table(struct acpi_table_header *table)
+{
+
+ /* Ignore tables that contain AML */
+
+ if (ACPI_COMPARE_NAME(table->signature, DSDT_SIG) ||
+ ACPI_COMPARE_NAME(table->signature, PSDT_SIG) ||
+ ACPI_COMPARE_NAME(table->signature, SSDT_SIG)) {
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ut_allocate_owner_id
*
* PARAMETERS: owner_id - Where the new owner ID is returned
@@ -60,6 +87,7 @@ ACPI_MODULE_NAME("utmisc")
* when the method exits or the table is unloaded.
*
******************************************************************************/
+
acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id)
{
acpi_native_uint i;
@@ -67,7 +95,7 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id)
acpi_native_uint k;
acpi_status status;
- ACPI_FUNCTION_TRACE("ut_allocate_owner_id");
+ ACPI_FUNCTION_TRACE(ut_allocate_owner_id);
/* Guard against multiple allocations of ID to the same location */
@@ -97,6 +125,7 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id)
for (k = acpi_gbl_next_owner_id_offset; k < 32; k++) {
if (acpi_gbl_owner_id_mask[j] == ACPI_UINT32_MAX) {
+
/* There are no free IDs in this mask */
break;
@@ -123,7 +152,7 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id)
(acpi_owner_id) ((k + 1) + ACPI_MUL_32(j));
ACPI_DEBUG_PRINT((ACPI_DB_VALUES,
- "Allocated owner_id: %2.2X\n",
+ "Allocated OwnerId: %2.2X\n",
(unsigned int)*owner_id));
goto exit;
}
@@ -144,7 +173,7 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id)
*/
status = AE_OWNER_ID_LIMIT;
ACPI_ERROR((AE_INFO,
- "Could not allocate new owner_id (255 max), AE_OWNER_ID_LIMIT"));
+ "Could not allocate new OwnerId (255 max), AE_OWNER_ID_LIMIT"));
exit:
(void)acpi_ut_release_mutex(ACPI_MTX_CACHES);
@@ -172,7 +201,7 @@ void acpi_ut_release_owner_id(acpi_owner_id * owner_id_ptr)
acpi_native_uint index;
u32 bit;
- ACPI_FUNCTION_TRACE_U32("ut_release_owner_id", owner_id);
+ ACPI_FUNCTION_TRACE_U32(ut_release_owner_id, owner_id);
/* Always clear the input owner_id (zero is an invalid ID) */
@@ -181,7 +210,7 @@ void acpi_ut_release_owner_id(acpi_owner_id * owner_id_ptr)
/* Zero is not a valid owner_iD */
if (owner_id == 0) {
- ACPI_ERROR((AE_INFO, "Invalid owner_id: %2.2X", owner_id));
+ ACPI_ERROR((AE_INFO, "Invalid OwnerId: %2.2X", owner_id));
return_VOID;
}
@@ -207,7 +236,7 @@ void acpi_ut_release_owner_id(acpi_owner_id * owner_id_ptr)
acpi_gbl_owner_id_mask[index] ^= bit;
} else {
ACPI_ERROR((AE_INFO,
- "Release of non-allocated owner_id: %2.2X",
+ "Release of non-allocated OwnerId: %2.2X",
owner_id + 1));
}
@@ -273,6 +302,7 @@ void acpi_ut_print_string(char *string, u8 max_length)
acpi_os_printf("\"");
for (i = 0; string[i] && (i < max_length); i++) {
+
/* Escape sequences */
switch (string[i]) {
@@ -461,12 +491,47 @@ acpi_ut_display_init_pathname(u8 type,
}
acpi_os_printf("\n");
- ACPI_MEM_FREE(buffer.pointer);
+ ACPI_FREE(buffer.pointer);
}
#endif
/*******************************************************************************
*
+ * FUNCTION: acpi_ut_valid_acpi_char
+ *
+ * PARAMETERS: Char - The character to be examined
+ *
+ * RETURN: TRUE if the character is valid, FALSE otherwise
+ *
+ * DESCRIPTION: Check for a valid ACPI character. Must be one of:
+ * 1) Upper case alpha
+ * 2) numeric
+ * 3) underscore
+ *
+ * We allow a '!' as the last character because of the ASF! table
+ *
+ ******************************************************************************/
+
+u8 acpi_ut_valid_acpi_char(char character, acpi_native_uint position)
+{
+
+ if (!((character >= 'A' && character <= 'Z') ||
+ (character >= '0' && character <= '9') || (character == '_'))) {
+
+ /* Allow a '!' in the last position */
+
+ if (character == '!' && position == 3) {
+ return (TRUE);
+ }
+
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ut_valid_acpi_name
*
* PARAMETERS: Name - The name to be examined
@@ -482,19 +547,13 @@ acpi_ut_display_init_pathname(u8 type,
u8 acpi_ut_valid_acpi_name(u32 name)
{
- char *name_ptr = (char *)&name;
- char character;
acpi_native_uint i;
ACPI_FUNCTION_ENTRY();
for (i = 0; i < ACPI_NAME_SIZE; i++) {
- character = *name_ptr;
- name_ptr++;
-
- if (!((character == '_') ||
- (character >= 'A' && character <= 'Z') ||
- (character >= '0' && character <= '9'))) {
+ if (!acpi_ut_valid_acpi_char
+ ((ACPI_CAST_PTR(char, &name))[i], i)) {
return (FALSE);
}
}
@@ -504,24 +563,37 @@ u8 acpi_ut_valid_acpi_name(u32 name)
/*******************************************************************************
*
- * FUNCTION: acpi_ut_valid_acpi_character
+ * FUNCTION: acpi_ut_repair_name
*
- * PARAMETERS: Character - The character to be examined
+ * PARAMETERS: Name - The ACPI name to be repaired
*
- * RETURN: 1 if Character may appear in a name, else 0
+ * RETURN: Repaired version of the name
*
- * DESCRIPTION: Check for a printable character
+ * DESCRIPTION: Repair an ACPI name: Change invalid characters to '*' and
+ * return the new name.
*
******************************************************************************/
-u8 acpi_ut_valid_acpi_character(char character)
+acpi_name acpi_ut_repair_name(acpi_name name)
{
+ char *name_ptr = ACPI_CAST_PTR(char, &name);
+ char new_name[ACPI_NAME_SIZE];
+ acpi_native_uint i;
- ACPI_FUNCTION_ENTRY();
+ for (i = 0; i < ACPI_NAME_SIZE; i++) {
+ new_name[i] = name_ptr[i];
- return ((u8) ((character == '_') ||
- (character >= 'A' && character <= 'Z') ||
- (character >= '0' && character <= '9')));
+ /*
+ * Replace a bad character with something printable, yet technically
+ * still invalid. This prevents any collisions with existing "good"
+ * names in the namespace.
+ */
+ if (!acpi_ut_valid_acpi_char(name_ptr[i], i)) {
+ new_name[i] = '*';
+ }
+ }
+
+ return (*ACPI_CAST_PTR(u32, new_name));
}
/*******************************************************************************
@@ -529,7 +601,8 @@ u8 acpi_ut_valid_acpi_character(char character)
* FUNCTION: acpi_ut_strtoul64
*
* PARAMETERS: String - Null terminated string
- * Base - Radix of the string: 10, 16, or ACPI_ANY_BASE
+ * Base - Radix of the string: 16 or ACPI_ANY_BASE;
+ * ACPI_ANY_BASE means 'in behalf of to_integer'
* ret_integer - Where the converted integer is returned
*
* RETURN: Status and Converted value
@@ -545,16 +618,17 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer)
u32 this_digit = 0;
acpi_integer return_value = 0;
acpi_integer quotient;
+ acpi_integer dividend;
+ u32 to_integer_op = (base == ACPI_ANY_BASE);
+ u32 mode32 = (acpi_gbl_integer_byte_width == 4);
+ u8 valid_digits = 0;
+ u8 sign_of0x = 0;
+ u8 term = 0;
- ACPI_FUNCTION_TRACE("ut_stroul64");
-
- if ((!string) || !(*string)) {
- goto error_exit;
- }
+ ACPI_FUNCTION_TRACE(ut_stroul64);
switch (base) {
case ACPI_ANY_BASE:
- case 10:
case 16:
break;
@@ -563,76 +637,110 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
+ if (!string) {
+ goto error_exit;
+ }
+
/* Skip over any white space in the buffer */
- while (ACPI_IS_SPACE(*string) || *string == '\t') {
+ while ((*string) && (ACPI_IS_SPACE(*string) || *string == '\t')) {
string++;
}
- /*
- * If the input parameter Base is zero, then we need to
- * determine if it is decimal or hexadecimal:
- */
- if (base == 0) {
+ if (to_integer_op) {
+ /*
+ * Base equal to ACPI_ANY_BASE means 'to_integer operation case'.
+ * We need to determine if it is decimal or hexadecimal.
+ */
if ((*string == '0') && (ACPI_TOLOWER(*(string + 1)) == 'x')) {
+ sign_of0x = 1;
base = 16;
+
+ /* Skip over the leading '0x' */
string += 2;
} else {
base = 10;
}
}
- /*
- * For hexadecimal base, skip over the leading
- * 0 or 0x, if they are present.
- */
- if ((base == 16) &&
- (*string == '0') && (ACPI_TOLOWER(*(string + 1)) == 'x')) {
- string += 2;
+ /* Any string left? Check that '0x' is not followed by white space. */
+
+ if (!(*string) || ACPI_IS_SPACE(*string) || *string == '\t') {
+ if (to_integer_op) {
+ goto error_exit;
+ } else {
+ goto all_done;
+ }
}
- /* Any string left? */
+ dividend = (mode32) ? ACPI_UINT32_MAX : ACPI_UINT64_MAX;
- if (!(*string)) {
- goto error_exit;
- }
+ /* At least one character in the string here */
/* Main loop: convert the string to a 64-bit integer */
while (*string) {
if (ACPI_IS_DIGIT(*string)) {
+
/* Convert ASCII 0-9 to Decimal value */
this_digit = ((u8) * string) - '0';
- } else {
- if (base == 10) {
- /* Digit is out of range */
+ } else if (base == 10) {
- goto error_exit;
- }
+ /* Digit is out of range; possible in to_integer case only */
+ term = 1;
+ } else {
this_digit = (u8) ACPI_TOUPPER(*string);
if (ACPI_IS_XDIGIT((char)this_digit)) {
+
/* Convert ASCII Hex char to value */
this_digit = this_digit - 'A' + 10;
} else {
- /*
- * We allow non-hex chars, just stop now, same as end-of-string.
- * See ACPI spec, string-to-integer conversion.
- */
+ term = 1;
+ }
+ }
+
+ if (term) {
+ if (to_integer_op) {
+ goto error_exit;
+ } else {
break;
}
+ } else if ((valid_digits == 0) && (this_digit == 0)
+ && !sign_of0x) {
+
+ /* Skip zeros */
+ string++;
+ continue;
+ }
+
+ valid_digits++;
+
+ if (sign_of0x
+ && ((valid_digits > 16)
+ || ((valid_digits > 8) && mode32))) {
+ /*
+ * This is to_integer operation case.
+ * No any restrictions for string-to-integer conversion,
+ * see ACPI spec.
+ */
+ goto error_exit;
}
/* Divide the digit into the correct position */
(void)
- acpi_ut_short_divide((ACPI_INTEGER_MAX -
- (acpi_integer) this_digit), base,
- &quotient, NULL);
+ acpi_ut_short_divide((dividend - (acpi_integer) this_digit),
+ base, &quotient, NULL);
+
if (return_value > quotient) {
- goto error_exit;
+ if (to_integer_op) {
+ goto error_exit;
+ } else {
+ break;
+ }
}
return_value *= base;
@@ -642,6 +750,8 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer)
/* All done, normal exit */
+ all_done:
+
*ret_integer = return_value;
return_ACPI_STATUS(AE_OK);
@@ -719,7 +829,7 @@ acpi_ut_walk_package_tree(union acpi_operand_object * source_object,
u32 this_index;
union acpi_operand_object *this_source_obj;
- ACPI_FUNCTION_TRACE("ut_walk_package_tree");
+ ACPI_FUNCTION_TRACE(ut_walk_package_tree);
state = acpi_ut_create_pkg_state(source_object, target_object, 0);
if (!state) {
@@ -727,6 +837,7 @@ acpi_ut_walk_package_tree(union acpi_operand_object * source_object,
}
while (state) {
+
/* Get one element of the package */
this_index = state->pkg.index;
@@ -814,31 +925,6 @@ acpi_ut_walk_package_tree(union acpi_operand_object * source_object,
/*******************************************************************************
*
- * FUNCTION: acpi_ut_generate_checksum
- *
- * PARAMETERS: Buffer - Buffer to be scanned
- * Length - number of bytes to examine
- *
- * RETURN: The generated checksum
- *
- * DESCRIPTION: Generate a checksum on a raw buffer
- *
- ******************************************************************************/
-
-u8 acpi_ut_generate_checksum(u8 * buffer, u32 length)
-{
- u32 i;
- signed char sum = 0;
-
- for (i = 0; i < length; i++) {
- sum = (signed char)(sum + buffer[i]);
- }
-
- return ((u8) (0 - sum));
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ut_error, acpi_ut_warning, acpi_ut_info
*
* PARAMETERS: module_name - Caller's module name (for error output)
@@ -900,36 +986,3 @@ acpi_ut_info(char *module_name, u32 line_number, char *format, ...)
acpi_os_vprintf(format, args);
acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_report_error, Warning, Info
- *
- * PARAMETERS: module_name - Caller's module name (for error output)
- * line_number - Caller's line number (for error output)
- *
- * RETURN: None
- *
- * DESCRIPTION: Print error message
- *
- * Note: Legacy only, should be removed when no longer used by drivers.
- *
- ******************************************************************************/
-
-void acpi_ut_report_error(char *module_name, u32 line_number)
-{
-
- acpi_os_printf("ACPI Error (%s-%04d): ", module_name, line_number);
-}
-
-void acpi_ut_report_warning(char *module_name, u32 line_number)
-{
-
- acpi_os_printf("ACPI Warning (%s-%04d): ", module_name, line_number);
-}
-
-void acpi_ut_report_info(char *module_name, u32 line_number)
-{
-
- acpi_os_printf("ACPI (%s-%04d): ", module_name, line_number);
-}
diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c
index 45a7244..25eb343 100644
--- a/drivers/acpi/utilities/utmutex.c
+++ b/drivers/acpi/utilities/utmutex.c
@@ -68,19 +68,26 @@ acpi_status acpi_ut_mutex_initialize(void)
u32 i;
acpi_status status;
- ACPI_FUNCTION_TRACE("ut_mutex_initialize");
+ ACPI_FUNCTION_TRACE(ut_mutex_initialize);
/*
* Create each of the predefined mutex objects
*/
- for (i = 0; i < NUM_MUTEX; i++) {
+ for (i = 0; i < ACPI_NUM_MUTEX; i++) {
status = acpi_ut_create_mutex(i);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
}
+ /* Create the spinlocks for use at interrupt level */
+
status = acpi_os_create_lock(&acpi_gbl_gpe_lock);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ status = acpi_os_create_lock(&acpi_gbl_hardware_lock);
return_ACPI_STATUS(status);
}
@@ -100,16 +107,19 @@ void acpi_ut_mutex_terminate(void)
{
u32 i;
- ACPI_FUNCTION_TRACE("ut_mutex_terminate");
+ ACPI_FUNCTION_TRACE(ut_mutex_terminate);
/*
* Delete each predefined mutex object
*/
- for (i = 0; i < NUM_MUTEX; i++) {
+ for (i = 0; i < ACPI_NUM_MUTEX; i++) {
(void)acpi_ut_delete_mutex(i);
}
+ /* Delete the spinlocks */
+
acpi_os_delete_lock(acpi_gbl_gpe_lock);
+ acpi_os_delete_lock(acpi_gbl_hardware_lock);
return_VOID;
}
@@ -129,9 +139,9 @@ static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id)
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE_U32("ut_create_mutex", mutex_id);
+ ACPI_FUNCTION_TRACE_U32(ut_create_mutex, mutex_id);
- if (mutex_id > MAX_MUTEX) {
+ if (mutex_id > ACPI_MAX_MUTEX) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
@@ -163,9 +173,9 @@ static acpi_status acpi_ut_delete_mutex(acpi_mutex_handle mutex_id)
{
acpi_status status;
- ACPI_FUNCTION_TRACE_U32("ut_delete_mutex", mutex_id);
+ ACPI_FUNCTION_TRACE_U32(ut_delete_mutex, mutex_id);
- if (mutex_id > MAX_MUTEX) {
+ if (mutex_id > ACPI_MAX_MUTEX) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
@@ -192,11 +202,11 @@ static acpi_status acpi_ut_delete_mutex(acpi_mutex_handle mutex_id)
acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
{
acpi_status status;
- u32 this_thread_id;
+ acpi_thread_id this_thread_id;
- ACPI_FUNCTION_NAME("ut_acquire_mutex");
+ ACPI_FUNCTION_NAME(ut_acquire_mutex);
- if (mutex_id > MAX_MUTEX) {
+ if (mutex_id > ACPI_MAX_MUTEX) {
return (AE_BAD_PARAMETER);
}
@@ -213,7 +223,7 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
* the mutex ordering rule. This indicates a coding error somewhere in
* the ACPI subsystem code.
*/
- for (i = mutex_id; i < MAX_MUTEX; i++) {
+ for (i = mutex_id; i < ACPI_MAX_MUTEX; i++) {
if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) {
if (i == mutex_id) {
ACPI_ERROR((AE_INFO,
@@ -275,16 +285,16 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id)
{
acpi_status status;
- u32 this_thread_id;
+ acpi_thread_id this_thread_id;
- ACPI_FUNCTION_NAME("ut_release_mutex");
+ ACPI_FUNCTION_NAME(ut_release_mutex);
this_thread_id = acpi_os_get_thread_id();
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
"Thread %X releasing Mutex [%s]\n", this_thread_id,
acpi_ut_get_mutex_name(mutex_id)));
- if (mutex_id > MAX_MUTEX) {
+ if (mutex_id > ACPI_MAX_MUTEX) {
return (AE_BAD_PARAMETER);
}
@@ -309,7 +319,7 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id)
* ordering rule. This indicates a coding error somewhere in
* the ACPI subsystem code.
*/
- for (i = mutex_id; i < MAX_MUTEX; i++) {
+ for (i = mutex_id; i < ACPI_MAX_MUTEX; i++) {
if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) {
if (i == mutex_id) {
continue;
diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c
index 7ee2d1d..ba7d8ac 100644
--- a/drivers/acpi/utilities/utobject.c
+++ b/drivers/acpi/utilities/utobject.c
@@ -92,7 +92,7 @@ union acpi_operand_object *acpi_ut_create_internal_object_dbg(char *module_name,
union acpi_operand_object *object;
union acpi_operand_object *second_object;
- ACPI_FUNCTION_TRACE_STR("ut_create_internal_object_dbg",
+ ACPI_FUNCTION_TRACE_STR(ut_create_internal_object_dbg,
acpi_ut_get_type_name(type));
/* Allocate the raw object descriptor */
@@ -161,7 +161,7 @@ union acpi_operand_object *acpi_ut_create_buffer_object(acpi_size buffer_size)
union acpi_operand_object *buffer_desc;
u8 *buffer = NULL;
- ACPI_FUNCTION_TRACE_U32("ut_create_buffer_object", buffer_size);
+ ACPI_FUNCTION_TRACE_U32(ut_create_buffer_object, buffer_size);
/* Create a new Buffer object */
@@ -173,9 +173,10 @@ union acpi_operand_object *acpi_ut_create_buffer_object(acpi_size buffer_size)
/* Create an actual buffer only if size > 0 */
if (buffer_size > 0) {
+
/* Allocate the actual buffer */
- buffer = ACPI_MEM_CALLOCATE(buffer_size);
+ buffer = ACPI_ALLOCATE_ZEROED(buffer_size);
if (!buffer) {
ACPI_ERROR((AE_INFO, "Could not allocate size %X",
(u32) buffer_size));
@@ -214,7 +215,7 @@ union acpi_operand_object *acpi_ut_create_string_object(acpi_size string_size)
union acpi_operand_object *string_desc;
char *string;
- ACPI_FUNCTION_TRACE_U32("ut_create_string_object", string_size);
+ ACPI_FUNCTION_TRACE_U32(ut_create_string_object, string_size);
/* Create a new String object */
@@ -227,7 +228,7 @@ union acpi_operand_object *acpi_ut_create_string_object(acpi_size string_size)
* Allocate the actual string buffer -- (Size + 1) for NULL terminator.
* NOTE: Zero-length strings are NULL terminated
*/
- string = ACPI_MEM_CALLOCATE(string_size + 1);
+ string = ACPI_ALLOCATE_ZEROED(string_size + 1);
if (!string) {
ACPI_ERROR((AE_INFO, "Could not allocate size %X",
(u32) string_size));
@@ -260,7 +261,7 @@ union acpi_operand_object *acpi_ut_create_string_object(acpi_size string_size)
u8 acpi_ut_valid_internal_object(void *object)
{
- ACPI_FUNCTION_NAME("ut_valid_internal_object");
+ ACPI_FUNCTION_NAME(ut_valid_internal_object);
/* Check for a null pointer */
@@ -308,7 +309,7 @@ void *acpi_ut_allocate_object_desc_dbg(char *module_name,
{
union acpi_operand_object *object;
- ACPI_FUNCTION_TRACE("ut_allocate_object_desc_dbg");
+ ACPI_FUNCTION_TRACE(ut_allocate_object_desc_dbg);
object = acpi_os_acquire_object(acpi_gbl_operand_cache);
if (!object) {
@@ -319,6 +320,7 @@ void *acpi_ut_allocate_object_desc_dbg(char *module_name,
}
/* Mark the descriptor type */
+
memset(object, 0, sizeof(union acpi_operand_object));
ACPI_SET_DESCRIPTOR_TYPE(object, ACPI_DESC_TYPE_OPERAND);
@@ -342,7 +344,7 @@ void *acpi_ut_allocate_object_desc_dbg(char *module_name,
void acpi_ut_delete_object_desc(union acpi_operand_object *object)
{
- ACPI_FUNCTION_TRACE_PTR("ut_delete_object_desc", object);
+ ACPI_FUNCTION_TRACE_PTR(ut_delete_object_desc, object);
/* Object must be an union acpi_operand_object */
@@ -381,7 +383,7 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object,
acpi_size length;
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE_PTR("ut_get_simple_object_size", internal_object);
+ ACPI_FUNCTION_TRACE_PTR(ut_get_simple_object_size, internal_object);
/*
* Handle a null object (Could be a uninitialized package
@@ -397,6 +399,7 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object,
length = sizeof(union acpi_object);
if (ACPI_GET_DESCRIPTOR_TYPE(internal_object) == ACPI_DESC_TYPE_NAMED) {
+
/* Object is a named object (reference), just return the length */
*obj_length = ACPI_ROUND_UP_TO_NATIVE_WORD(length);
@@ -559,7 +562,7 @@ acpi_ut_get_package_object_size(union acpi_operand_object *internal_object,
acpi_status status;
struct acpi_pkg_info info;
- ACPI_FUNCTION_TRACE_PTR("ut_get_package_object_size", internal_object);
+ ACPI_FUNCTION_TRACE_PTR(ut_get_package_object_size, internal_object);
info.length = 0;
info.object_space = 0;
diff --git a/drivers/acpi/utilities/utresrc.c b/drivers/acpi/utilities/utresrc.c
index 1646131..5a2de92 100644
--- a/drivers/acpi/utilities/utresrc.c
+++ b/drivers/acpi/utilities/utresrc.c
@@ -45,113 +45,113 @@
#include <acpi/amlresrc.h>
#define _COMPONENT ACPI_UTILITIES
-ACPI_MODULE_NAME("utmisc")
+ACPI_MODULE_NAME("utresrc")
#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER)
/*
* Strings used to decode resource descriptors.
* Used by both the disasssembler and the debugger resource dump routines
*/
-const char *acpi_gbl_BMdecode[2] = {
- "not_bus_master",
- "bus_master"
+const char *acpi_gbl_bm_decode[] = {
+ "NotBusMaster",
+ "BusMaster"
};
-const char *acpi_gbl_config_decode[4] = {
+const char *acpi_gbl_config_decode[] = {
"0 - Good Configuration",
"1 - Acceptable Configuration",
"2 - Suboptimal Configuration",
"3 - ***Invalid Configuration***",
};
-const char *acpi_gbl_consume_decode[2] = {
- "resource_producer",
- "resource_consumer"
+const char *acpi_gbl_consume_decode[] = {
+ "ResourceProducer",
+ "ResourceConsumer"
};
-const char *acpi_gbl_DECdecode[2] = {
- "pos_decode",
- "sub_decode"
+const char *acpi_gbl_dec_decode[] = {
+ "PosDecode",
+ "SubDecode"
};
-const char *acpi_gbl_HEdecode[2] = {
+const char *acpi_gbl_he_decode[] = {
"Level",
"Edge"
};
-const char *acpi_gbl_io_decode[2] = {
+const char *acpi_gbl_io_decode[] = {
"Decode10",
"Decode16"
};
-const char *acpi_gbl_LLdecode[2] = {
- "active_high",
- "active_low"
+const char *acpi_gbl_ll_decode[] = {
+ "ActiveHigh",
+ "ActiveLow"
};
-const char *acpi_gbl_max_decode[2] = {
- "max_not_fixed",
- "max_fixed"
+const char *acpi_gbl_max_decode[] = {
+ "MaxNotFixed",
+ "MaxFixed"
};
-const char *acpi_gbl_MEMdecode[4] = {
- "non_cacheable",
+const char *acpi_gbl_mem_decode[] = {
+ "NonCacheable",
"Cacheable",
- "write_combining",
+ "WriteCombining",
"Prefetchable"
};
-const char *acpi_gbl_min_decode[2] = {
- "min_not_fixed",
- "min_fixed"
+const char *acpi_gbl_min_decode[] = {
+ "MinNotFixed",
+ "MinFixed"
};
-const char *acpi_gbl_MTPdecode[4] = {
- "address_range_memory",
- "address_range_reserved",
- "address_range_aCPI",
- "address_range_nVS"
+const char *acpi_gbl_mtp_decode[] = {
+ "AddressRangeMemory",
+ "AddressRangeReserved",
+ "AddressRangeACPI",
+ "AddressRangeNVS"
};
-const char *acpi_gbl_RNGdecode[4] = {
- "invalid_ranges",
- "non_iSAonly_ranges",
- "ISAonly_ranges",
- "entire_range"
+const char *acpi_gbl_rng_decode[] = {
+ "InvalidRanges",
+ "NonISAOnlyRanges",
+ "ISAOnlyRanges",
+ "EntireRange"
};
-const char *acpi_gbl_RWdecode[2] = {
- "read_only",
- "read_write"
+const char *acpi_gbl_rw_decode[] = {
+ "ReadOnly",
+ "ReadWrite"
};
-const char *acpi_gbl_SHRdecode[2] = {
+const char *acpi_gbl_shr_decode[] = {
"Exclusive",
"Shared"
};
-const char *acpi_gbl_SIZdecode[4] = {
+const char *acpi_gbl_siz_decode[] = {
"Transfer8",
"Transfer8_16",
"Transfer16",
- "invalid_size"
+ "InvalidSize"
};
-const char *acpi_gbl_TRSdecode[2] = {
- "dense_translation",
- "sparse_translation"
+const char *acpi_gbl_trs_decode[] = {
+ "DenseTranslation",
+ "SparseTranslation"
};
-const char *acpi_gbl_TTPdecode[2] = {
- "type_static",
- "type_translation"
+const char *acpi_gbl_ttp_decode[] = {
+ "TypeStatic",
+ "TypeTranslation"
};
-const char *acpi_gbl_TYPdecode[4] = {
+const char *acpi_gbl_typ_decode[] = {
"Compatibility",
- "type_a",
- "type_b",
- "type_f"
+ "TypeA",
+ "TypeB",
+ "TypeF"
};
#endif
@@ -240,6 +240,104 @@ static const u8 acpi_gbl_resource_types[] = {
/*******************************************************************************
*
+ * FUNCTION: acpi_ut_walk_aml_resources
+ *
+ * PARAMETERS: Aml - Pointer to the raw AML resource template
+ * aml_length - Length of the entire template
+ * user_function - Called once for each descriptor found. If
+ * NULL, a pointer to the end_tag is returned
+ * Context - Passed to user_function
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Walk a raw AML resource list(buffer). User function called
+ * once for each resource found.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_walk_aml_resources(u8 * aml,
+ acpi_size aml_length,
+ acpi_walk_aml_callback user_function, void **context)
+{
+ acpi_status status;
+ u8 *end_aml;
+ u8 resource_index;
+ u32 length;
+ u32 offset = 0;
+
+ ACPI_FUNCTION_TRACE(ut_walk_aml_resources);
+
+ /* The absolute minimum resource template is one end_tag descriptor */
+
+ if (aml_length < sizeof(struct aml_resource_end_tag)) {
+ return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
+ }
+
+ /* Point to the end of the resource template buffer */
+
+ end_aml = aml + aml_length;
+
+ /* Walk the byte list, abort on any invalid descriptor type or length */
+
+ while (aml < end_aml) {
+
+ /* Validate the Resource Type and Resource Length */
+
+ status = acpi_ut_validate_resource(aml, &resource_index);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Get the length of this descriptor */
+
+ length = acpi_ut_get_descriptor_length(aml);
+
+ /* Invoke the user function */
+
+ if (user_function) {
+ status =
+ user_function(aml, length, offset, resource_index,
+ context);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ }
+
+ /* An end_tag descriptor terminates this resource template */
+
+ if (acpi_ut_get_resource_type(aml) ==
+ ACPI_RESOURCE_NAME_END_TAG) {
+ /*
+ * There must be at least one more byte in the buffer for
+ * the 2nd byte of the end_tag
+ */
+ if ((aml + 1) >= end_aml) {
+ return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
+ }
+
+ /* Return the pointer to the end_tag if requested */
+
+ if (!user_function) {
+ *context = aml;
+ }
+
+ /* Normal exit */
+
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ aml += length;
+ offset += length;
+ }
+
+ /* Did not find an end_tag descriptor */
+
+ return (AE_AML_NO_RESOURCE_END_TAG);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ut_validate_resource
*
* PARAMETERS: Aml - Pointer to the raw AML resource descriptor
@@ -273,6 +371,7 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index)
* Examine the large/small bit in the resource header
*/
if (resource_type & ACPI_RESOURCE_NAME_LARGE) {
+
/* Verify the large resource type (name) against the max */
if (resource_type > ACPI_RESOURCE_NAME_LARGE_MAX) {
@@ -376,6 +475,7 @@ u8 acpi_ut_get_resource_type(void *aml)
* Examine the large/small bit in the resource header
*/
if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
+
/* Large Resource Type -- bits 6:0 contain the name */
return (ACPI_GET8(aml));
@@ -411,6 +511,7 @@ u16 acpi_ut_get_resource_length(void *aml)
* Examine the large/small bit in the resource header
*/
if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
+
/* Large Resource type -- bytes 1-2 contain the 16-bit length */
ACPI_MOVE_16_TO_16(&resource_length, ACPI_ADD_PTR(u8, aml, 1));
@@ -495,60 +596,21 @@ acpi_ut_get_resource_end_tag(union acpi_operand_object * obj_desc,
u8 ** end_tag)
{
acpi_status status;
- u8 *aml;
- u8 *end_aml;
-
- ACPI_FUNCTION_TRACE("ut_get_resource_end_tag");
- /* Get start and end pointers */
-
- aml = obj_desc->buffer.pointer;
- end_aml = aml + obj_desc->buffer.length;
+ ACPI_FUNCTION_TRACE(ut_get_resource_end_tag);
/* Allow a buffer length of zero */
if (!obj_desc->buffer.length) {
- *end_tag = aml;
+ *end_tag = obj_desc->buffer.pointer;
return_ACPI_STATUS(AE_OK);
}
- /* Walk the resource template, one descriptor per iteration */
-
- while (aml < end_aml) {
- /* Validate the Resource Type and Resource Length */
-
- status = acpi_ut_validate_resource(aml, NULL);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* end_tag resource indicates the end of the resource template */
-
- if (acpi_ut_get_resource_type(aml) ==
- ACPI_RESOURCE_NAME_END_TAG) {
- /*
- * There must be at least one more byte in the buffer for
- * the 2nd byte of the end_tag
- */
- if ((aml + 1) >= end_aml) {
- return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
- }
-
- /* Return the pointer to the end_tag */
-
- *end_tag = aml;
- return_ACPI_STATUS(AE_OK);
- }
-
- /*
- * Point to the next resource descriptor in the AML buffer. The
- * descriptor length is guaranteed to be non-zero by resource
- * validation above.
- */
- aml += acpi_ut_get_descriptor_length(aml);
- }
+ /* Validate the template and get a pointer to the end_tag */
- /* Did not find an end_tag resource descriptor */
+ status = acpi_ut_walk_aml_resources(obj_desc->buffer.pointer,
+ obj_desc->buffer.length, NULL,
+ (void **)end_tag);
- return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
+ return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/utilities/utstate.c b/drivers/acpi/utilities/utstate.c
index 4b134a7..0f5c5bb 100644
--- a/drivers/acpi/utilities/utstate.c
+++ b/drivers/acpi/utilities/utstate.c
@@ -96,7 +96,7 @@ void
acpi_ut_push_generic_state(union acpi_generic_state **list_head,
union acpi_generic_state *state)
{
- ACPI_FUNCTION_TRACE("ut_push_generic_state");
+ ACPI_FUNCTION_TRACE(ut_push_generic_state);
/* Push the state object onto the front of the list (stack) */
@@ -123,12 +123,13 @@ union acpi_generic_state *acpi_ut_pop_generic_state(union acpi_generic_state
{
union acpi_generic_state *state;
- ACPI_FUNCTION_TRACE("ut_pop_generic_state");
+ ACPI_FUNCTION_TRACE(ut_pop_generic_state);
/* Remove the state object at the head of the list (stack) */
state = *list_head;
if (state) {
+
/* Update the list head */
*list_head = state->common.next;
@@ -158,9 +159,10 @@ union acpi_generic_state *acpi_ut_create_generic_state(void)
state = acpi_os_acquire_object(acpi_gbl_state_cache);
if (state) {
+
/* Initialize */
memset(state, 0, sizeof(union acpi_generic_state));
- state->common.data_type = ACPI_DESC_TYPE_STATE;
+ state->common.descriptor_type = ACPI_DESC_TYPE_STATE;
}
return (state);
@@ -183,7 +185,7 @@ struct acpi_thread_state *acpi_ut_create_thread_state(void)
{
union acpi_generic_state *state;
- ACPI_FUNCTION_TRACE("ut_create_thread_state");
+ ACPI_FUNCTION_TRACE(ut_create_thread_state);
/* Create the generic state object */
@@ -194,7 +196,7 @@ struct acpi_thread_state *acpi_ut_create_thread_state(void)
/* Init fields specific to the update struct */
- state->common.data_type = ACPI_DESC_TYPE_STATE_THREAD;
+ state->common.descriptor_type = ACPI_DESC_TYPE_STATE_THREAD;
state->thread.thread_id = acpi_os_get_thread_id();
return_PTR((struct acpi_thread_state *)state);
@@ -220,7 +222,7 @@ union acpi_generic_state *acpi_ut_create_update_state(union acpi_operand_object
{
union acpi_generic_state *state;
- ACPI_FUNCTION_TRACE_PTR("ut_create_update_state", object);
+ ACPI_FUNCTION_TRACE_PTR(ut_create_update_state, object);
/* Create the generic state object */
@@ -231,7 +233,7 @@ union acpi_generic_state *acpi_ut_create_update_state(union acpi_operand_object
/* Init fields specific to the update struct */
- state->common.data_type = ACPI_DESC_TYPE_STATE_UPDATE;
+ state->common.descriptor_type = ACPI_DESC_TYPE_STATE_UPDATE;
state->update.object = object;
state->update.value = action;
@@ -257,7 +259,7 @@ union acpi_generic_state *acpi_ut_create_pkg_state(void *internal_object,
{
union acpi_generic_state *state;
- ACPI_FUNCTION_TRACE_PTR("ut_create_pkg_state", internal_object);
+ ACPI_FUNCTION_TRACE_PTR(ut_create_pkg_state, internal_object);
/* Create the generic state object */
@@ -268,7 +270,7 @@ union acpi_generic_state *acpi_ut_create_pkg_state(void *internal_object,
/* Init fields specific to the update struct */
- state->common.data_type = ACPI_DESC_TYPE_STATE_PACKAGE;
+ state->common.descriptor_type = ACPI_DESC_TYPE_STATE_PACKAGE;
state->pkg.source_object = (union acpi_operand_object *)internal_object;
state->pkg.dest_object = external_object;
state->pkg.index = index;
@@ -294,7 +296,7 @@ union acpi_generic_state *acpi_ut_create_control_state(void)
{
union acpi_generic_state *state;
- ACPI_FUNCTION_TRACE("ut_create_control_state");
+ ACPI_FUNCTION_TRACE(ut_create_control_state);
/* Create the generic state object */
@@ -305,7 +307,7 @@ union acpi_generic_state *acpi_ut_create_control_state(void)
/* Init fields specific to the control struct */
- state->common.data_type = ACPI_DESC_TYPE_STATE_CONTROL;
+ state->common.descriptor_type = ACPI_DESC_TYPE_STATE_CONTROL;
state->common.state = ACPI_CONTROL_CONDITIONAL_EXECUTING;
return_PTR(state);
@@ -319,15 +321,19 @@ union acpi_generic_state *acpi_ut_create_control_state(void)
*
* RETURN: None
*
- * DESCRIPTION: Put a state object back into the global state cache. The object
- * is not actually freed at this time.
+ * DESCRIPTION: Release a state object to the state cache. NULL state objects
+ * are ignored.
*
******************************************************************************/
void acpi_ut_delete_generic_state(union acpi_generic_state *state)
{
- ACPI_FUNCTION_TRACE("ut_delete_generic_state");
+ ACPI_FUNCTION_TRACE(ut_delete_generic_state);
+
+ /* Ignore null state */
- (void)acpi_os_release_object(acpi_gbl_state_cache, state);
+ if (state) {
+ (void)acpi_os_release_object(acpi_gbl_state_cache, state);
+ }
return_VOID;
}
diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c
index 308a960..3538f69 100644
--- a/drivers/acpi/utilities/utxface.c
+++ b/drivers/acpi/utilities/utxface.c
@@ -41,8 +41,6 @@
* POSSIBILITY OF SUCH DAMAGES.
*/
-#include <linux/module.h>
-
#include <acpi/acpi.h>
#include <acpi/acevents.h>
#include <acpi/acnamesp.h>
@@ -67,7 +65,7 @@ acpi_status acpi_initialize_subsystem(void)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_initialize_subsystem");
+ ACPI_FUNCTION_TRACE(acpi_initialize_subsystem);
ACPI_DEBUG_EXEC(acpi_ut_init_stack_ptr_trace());
@@ -109,6 +107,8 @@ acpi_status acpi_initialize_subsystem(void)
return_ACPI_STATUS(status);
}
+ACPI_EXPORT_SYMBOL(acpi_initialize_subsystem)
+
/*******************************************************************************
*
* FUNCTION: acpi_enable_subsystem
@@ -121,12 +121,11 @@ acpi_status acpi_initialize_subsystem(void)
* Puts system into ACPI mode if it isn't already.
*
******************************************************************************/
-
acpi_status acpi_enable_subsystem(u32 flags)
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("acpi_enable_subsystem");
+ ACPI_FUNCTION_TRACE(acpi_enable_subsystem);
/*
* We must initialize the hardware before we can enable ACPI.
@@ -152,7 +151,7 @@ acpi_status acpi_enable_subsystem(u32 flags)
status = acpi_enable();
if (ACPI_FAILURE(status)) {
- ACPI_WARNING((AE_INFO, "acpi_enable failed"));
+ ACPI_WARNING((AE_INFO, "AcpiEnable failed"));
return_ACPI_STATUS(status);
}
}
@@ -229,6 +228,8 @@ acpi_status acpi_enable_subsystem(u32 flags)
return_ACPI_STATUS(status);
}
+ACPI_EXPORT_SYMBOL(acpi_enable_subsystem)
+
/*******************************************************************************
*
* FUNCTION: acpi_initialize_objects
@@ -241,12 +242,11 @@ acpi_status acpi_enable_subsystem(u32 flags)
* objects and executing AML code for Regions, buffers, etc.
*
******************************************************************************/
-
acpi_status acpi_initialize_objects(u32 flags)
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("acpi_initialize_objects");
+ ACPI_FUNCTION_TRACE(acpi_initialize_objects);
/*
* Run all _REG methods
@@ -257,7 +257,7 @@ acpi_status acpi_initialize_objects(u32 flags)
*/
if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) {
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "[Init] Executing _REG op_region methods\n"));
+ "[Init] Executing _REG OpRegion methods\n"));
status = acpi_ev_initialize_op_regions();
if (ACPI_FAILURE(status)) {
@@ -305,6 +305,8 @@ acpi_status acpi_initialize_objects(u32 flags)
return_ACPI_STATUS(status);
}
+ACPI_EXPORT_SYMBOL(acpi_initialize_objects)
+
/*******************************************************************************
*
* FUNCTION: acpi_terminate
@@ -316,12 +318,11 @@ acpi_status acpi_initialize_objects(u32 flags)
* DESCRIPTION: Shutdown the ACPI subsystem. Release all resources.
*
******************************************************************************/
-
acpi_status acpi_terminate(void)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_terminate");
+ ACPI_FUNCTION_TRACE(acpi_terminate);
/* Terminate the AML Debugger if present */
@@ -348,6 +349,8 @@ acpi_status acpi_terminate(void)
return_ACPI_STATUS(status);
}
+ACPI_EXPORT_SYMBOL(acpi_terminate)
+
#ifdef ACPI_FUTURE_USAGE
/*******************************************************************************
*
@@ -362,7 +365,6 @@ acpi_status acpi_terminate(void)
* initialized successfully.
*
******************************************************************************/
-
acpi_status acpi_subsystem_status(void)
{
@@ -373,6 +375,8 @@ acpi_status acpi_subsystem_status(void)
}
}
+ACPI_EXPORT_SYMBOL(acpi_subsystem_status)
+
/*******************************************************************************
*
* FUNCTION: acpi_get_system_info
@@ -390,14 +394,13 @@ acpi_status acpi_subsystem_status(void)
* and the value of out_buffer is undefined.
*
******************************************************************************/
-
acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer)
{
struct acpi_system_info *info_ptr;
acpi_status status;
u32 i;
- ACPI_FUNCTION_TRACE("acpi_get_system_info");
+ ACPI_FUNCTION_TRACE(acpi_get_system_info);
/* Parameter validation */
@@ -448,15 +451,15 @@ acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer)
/* Current status of the ACPI tables, per table type */
- info_ptr->num_table_types = NUM_ACPI_TABLE_TYPES;
- for (i = 0; i < NUM_ACPI_TABLE_TYPES; i++) {
+ info_ptr->num_table_types = ACPI_TABLE_ID_MAX + 1;
+ for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) {
info_ptr->table_info[i].count = acpi_gbl_table_lists[i].count;
}
return_ACPI_STATUS(AE_OK);
}
-EXPORT_SYMBOL(acpi_get_system_info);
+ACPI_EXPORT_SYMBOL(acpi_get_system_info)
/*****************************************************************************
*
@@ -472,7 +475,6 @@ EXPORT_SYMBOL(acpi_get_system_info);
* TBD: When a second function is added, must save the Function also.
*
****************************************************************************/
-
acpi_status
acpi_install_initialization_handler(acpi_init_handler handler, u32 function)
{
@@ -489,6 +491,7 @@ acpi_install_initialization_handler(acpi_init_handler handler, u32 function)
return AE_OK;
}
+ACPI_EXPORT_SYMBOL(acpi_install_initialization_handler)
#endif /* ACPI_FUTURE_USAGE */
/*****************************************************************************
@@ -502,10 +505,9 @@ acpi_install_initialization_handler(acpi_init_handler handler, u32 function)
* DESCRIPTION: Empty all caches (delete the cached objects)
*
****************************************************************************/
-
acpi_status acpi_purge_cached_objects(void)
{
- ACPI_FUNCTION_TRACE("acpi_purge_cached_objects");
+ ACPI_FUNCTION_TRACE(acpi_purge_cached_objects);
(void)acpi_os_purge_cache(acpi_gbl_state_cache);
(void)acpi_os_purge_cache(acpi_gbl_operand_cache);
@@ -513,3 +515,5 @@ acpi_status acpi_purge_cached_objects(void)
(void)acpi_os_purge_cache(acpi_gbl_ps_node_ext_cache);
return_ACPI_STATUS(AE_OK);
}
+
+ACPI_EXPORT_SYMBOL(acpi_purge_cached_objects)
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 6458c47..6b51685 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -273,11 +273,13 @@ acpi_evaluate_integer(acpi_handle handle,
status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
if (ACPI_FAILURE(status)) {
acpi_util_eval_error(handle, pathname, status);
+ kfree(element);
return_ACPI_STATUS(status);
}
if (element->type != ACPI_TYPE_INTEGER) {
acpi_util_eval_error(handle, pathname, AE_BAD_DATA);
+ kfree(element);
return_ACPI_STATUS(AE_BAD_DATA);
}
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index bd48875..e7e9a693 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -323,7 +323,7 @@ acpi_video_device_lcd_query_levels(struct acpi_video_device *device,
if (!ACPI_SUCCESS(status))
return_VALUE(status);
obj = (union acpi_object *)buffer.pointer;
- if (!obj && (obj->type != ACPI_TYPE_PACKAGE)) {
+ if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _BCL data\n"));
status = -EFAULT;
goto err;
@@ -1294,7 +1294,7 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
struct acpi_video_bus *video)
{
unsigned long device_id;
- int status, result;
+ int status;
struct acpi_video_device *data;
ACPI_FUNCTION_TRACE("acpi_video_bus_get_one_device");
@@ -1346,8 +1346,11 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error installing notify handler\n"));
- result = -ENODEV;
- goto end;
+ if(data->brightness)
+ kfree(data->brightness->levels);
+ kfree(data->brightness);
+ kfree(data);
+ return -ENODEV;
}
down(&video->sem);
@@ -1359,7 +1362,6 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
return_VALUE(0);
}
- end:
return_VALUE(-ENOENT);
}
@@ -1643,8 +1645,9 @@ static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
printk(KERN_WARNING PREFIX
"hhuuhhuu bug in acpi video driver.\n");
+ if (data->brightness)
+ kfree(data->brightness->levels);
kfree(data->brightness);
-
kfree(data);
}
@@ -1785,6 +1788,10 @@ static int acpi_video_bus_add(struct acpi_device *device)
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error installing notify handler\n"));
+ acpi_video_bus_stop_devices(video);
+ acpi_video_bus_put_devices(video);
+ kfree(video->attached_array);
+ acpi_video_bus_remove_fs(device);
result = -ENODEV;
goto end;
}
@@ -1796,10 +1803,8 @@ static int acpi_video_bus_add(struct acpi_device *device)
video->flags.post ? "yes" : "no");
end:
- if (result) {
- acpi_video_bus_remove_fs(device);
+ if (result)
kfree(video);
- }
return_VALUE(result);
}
diff --git a/drivers/base/core.c b/drivers/base/core.c
index d0f84ff..27c2176 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -356,6 +356,13 @@ int device_add(struct device *dev)
if (parent)
klist_add_tail(&dev->knode_parent, &parent->klist_children);
+ if (dev->class) {
+ /* tie the class to the device */
+ down(&dev->class->sem);
+ list_add_tail(&dev->node, &dev->class->devices);
+ up(&dev->class->sem);
+ }
+
/* notify platform of device entry */
if (platform_notify)
platform_notify(dev);
@@ -455,6 +462,9 @@ void device_del(struct device * dev)
sysfs_remove_link(&dev->kobj, "device");
sysfs_remove_link(&dev->parent->kobj, class_name);
kfree(class_name);
+ down(&dev->class->sem);
+ list_del_init(&dev->node);
+ up(&dev->class->sem);
}
device_remove_file(dev, &dev->uevent_attr);
@@ -601,11 +611,6 @@ struct device *device_create(struct class *class, struct device *parent,
if (retval)
goto error;
- /* tie the class to the device */
- down(&class->sem);
- list_add_tail(&dev->node, &class->devices);
- up(&class->sem);
-
return dev;
error:
@@ -636,9 +641,7 @@ void device_destroy(struct class *class, dev_t devt)
}
up(&class->sem);
- if (dev) {
- list_del_init(&dev->node);
+ if (dev)
device_unregister(dev);
- }
}
EXPORT_SYMBOL_GPL(device_destroy);
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index ceeeba2..91f2309 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,5 +1,6 @@
obj-y := shutdown.o
obj-$(CONFIG_PM) += main.o suspend.o resume.o runtime.o sysfs.o
+obj-$(CONFIG_PM_TRACE) += trace.o
ifeq ($(CONFIG_DEBUG_DRIVER),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c
index 317edbf..520679c 100644
--- a/drivers/base/power/resume.c
+++ b/drivers/base/power/resume.c
@@ -9,6 +9,7 @@
*/
#include <linux/device.h>
+#include <linux/resume-trace.h>
#include "../base.h"
#include "power.h"
@@ -23,6 +24,8 @@ int resume_device(struct device * dev)
{
int error = 0;
+ TRACE_DEVICE(dev);
+ TRACE_RESUME(0);
down(&dev->sem);
if (dev->power.pm_parent
&& dev->power.pm_parent->power.power_state.event) {
@@ -36,6 +39,7 @@ int resume_device(struct device * dev)
error = dev->bus->resume(dev);
}
up(&dev->sem);
+ TRACE_RESUME(error);
return error;
}
diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c
new file mode 100644
index 0000000..a9ab30f
--- /dev/null
+++ b/drivers/base/power/trace.c
@@ -0,0 +1,228 @@
+/*
+ * drivers/base/power/trace.c
+ *
+ * Copyright (C) 2006 Linus Torvalds
+ *
+ * Trace facility for suspend/resume problems, when none of the
+ * devices may be working.
+ */
+
+#include <linux/resume-trace.h>
+#include <linux/rtc.h>
+
+#include <asm/rtc.h>
+
+#include "power.h"
+
+/*
+ * Horrid, horrid, horrid.
+ *
+ * It turns out that the _only_ piece of hardware that actually
+ * keeps its value across a hard boot (and, more importantly, the
+ * POST init sequence) is literally the realtime clock.
+ *
+ * Never mind that an RTC chip has 114 bytes (and often a whole
+ * other bank of an additional 128 bytes) of nice SRAM that is
+ * _designed_ to keep data - the POST will clear it. So we literally
+ * can just use the few bytes of actual time data, which means that
+ * we're really limited.
+ *
+ * It means, for example, that we can't use the seconds at all
+ * (since the time between the hang and the boot might be more
+ * than a minute), and we'd better not depend on the low bits of
+ * the minutes either.
+ *
+ * There are the wday fields etc, but I wouldn't guarantee those
+ * are dependable either. And if the date isn't valid, either the
+ * hw or POST will do strange things.
+ *
+ * So we're left with:
+ * - year: 0-99
+ * - month: 0-11
+ * - day-of-month: 1-28
+ * - hour: 0-23
+ * - min: (0-30)*2
+ *
+ * Giving us a total range of 0-16128000 (0xf61800), ie less
+ * than 24 bits of actual data we can save across reboots.
+ *
+ * And if your box can't boot in less than three minutes,
+ * you're screwed.
+ *
+ * Now, almost 24 bits of data is pitifully small, so we need
+ * to be pretty dense if we want to use it for anything nice.
+ * What we do is that instead of saving off nice readable info,
+ * we save off _hashes_ of information that we can hopefully
+ * regenerate after the reboot.
+ *
+ * In particular, this means that we might be unlucky, and hit
+ * a case where we have a hash collision, and we end up not
+ * being able to tell for certain exactly which case happened.
+ * But that's hopefully unlikely.
+ *
+ * What we do is to take the bits we can fit, and split them
+ * into three parts (16*997*1009 = 16095568), and use the values
+ * for:
+ * - 0-15: user-settable
+ * - 0-996: file + line number
+ * - 0-1008: device
+ */
+#define USERHASH (16)
+#define FILEHASH (997)
+#define DEVHASH (1009)
+
+#define DEVSEED (7919)
+
+static unsigned int dev_hash_value;
+
+static int set_magic_time(unsigned int user, unsigned int file, unsigned int device)
+{
+ unsigned int n = user + USERHASH*(file + FILEHASH*device);
+
+ // June 7th, 2006
+ static struct rtc_time time = {
+ .tm_sec = 0,
+ .tm_min = 0,
+ .tm_hour = 0,
+ .tm_mday = 7,
+ .tm_mon = 5, // June - counting from zero
+ .tm_year = 106,
+ .tm_wday = 3,
+ .tm_yday = 160,
+ .tm_isdst = 1
+ };
+
+ time.tm_year = (n % 100);
+ n /= 100;
+ time.tm_mon = (n % 12);
+ n /= 12;
+ time.tm_mday = (n % 28) + 1;
+ n /= 28;
+ time.tm_hour = (n % 24);
+ n /= 24;
+ time.tm_min = (n % 20) * 3;
+ n /= 20;
+ set_rtc_time(&time);
+ return n ? -1 : 0;
+}
+
+static unsigned int read_magic_time(void)
+{
+ struct rtc_time time;
+ unsigned int val;
+
+ get_rtc_time(&time);
+ printk("Time: %2d:%02d:%02d Date: %02d/%02d/%02d\n",
+ time.tm_hour, time.tm_min, time.tm_sec,
+ time.tm_mon, time.tm_mday, time.tm_year);
+ val = time.tm_year; /* 100 years */
+ if (val > 100)
+ val -= 100;
+ val += time.tm_mon * 100; /* 12 months */
+ val += (time.tm_mday-1) * 100 * 12; /* 28 month-days */
+ val += time.tm_hour * 100 * 12 * 28; /* 24 hours */
+ val += (time.tm_min / 3) * 100 * 12 * 28 * 24; /* 20 3-minute intervals */
+ return val;
+}
+
+/*
+ * This is just the sdbm hash function with a user-supplied
+ * seed and final size parameter.
+ */
+static unsigned int hash_string(unsigned int seed, const char *data, unsigned int mod)
+{
+ unsigned char c;
+ while ((c = *data++) != 0) {
+ seed = (seed << 16) + (seed << 6) - seed + c;
+ }
+ return seed % mod;
+}
+
+void set_trace_device(struct device *dev)
+{
+ dev_hash_value = hash_string(DEVSEED, dev->bus_id, DEVHASH);
+}
+
+/*
+ * We could just take the "tracedata" index into the .tracedata
+ * section instead. Generating a hash of the data gives us a
+ * chance to work across kernel versions, and perhaps more
+ * importantly it also gives us valid/invalid check (ie we will
+ * likely not give totally bogus reports - if the hash matches,
+ * it's not any guarantee, but it's a high _likelihood_ that
+ * the match is valid).
+ */
+void generate_resume_trace(void *tracedata, unsigned int user)
+{
+ unsigned short lineno = *(unsigned short *)tracedata;
+ const char *file = *(const char **)(tracedata + 2);
+ unsigned int user_hash_value, file_hash_value;
+
+ user_hash_value = user % USERHASH;
+ file_hash_value = hash_string(lineno, file, FILEHASH);
+ set_magic_time(user_hash_value, file_hash_value, dev_hash_value);
+}
+
+extern char __tracedata_start, __tracedata_end;
+static int show_file_hash(unsigned int value)
+{
+ int match;
+ char *tracedata;
+
+ match = 0;
+ for (tracedata = &__tracedata_start ; tracedata < &__tracedata_end ; tracedata += 6) {
+ unsigned short lineno = *(unsigned short *)tracedata;
+ const char *file = *(const char **)(tracedata + 2);
+ unsigned int hash = hash_string(lineno, file, FILEHASH);
+ if (hash != value)
+ continue;
+ printk(" hash matches %s:%u\n", file, lineno);
+ match++;
+ }
+ return match;
+}
+
+static int show_dev_hash(unsigned int value)
+{
+ int match = 0;
+ struct list_head * entry = dpm_active.prev;
+
+ while (entry != &dpm_active) {
+ struct device * dev = to_device(entry);
+ unsigned int hash = hash_string(DEVSEED, dev->bus_id, DEVHASH);
+ if (hash == value) {
+ printk(" hash matches device %s\n", dev->bus_id);
+ match++;
+ }
+ entry = entry->prev;
+ }
+ return match;
+}
+
+static unsigned int hash_value_early_read;
+
+static int early_resume_init(void)
+{
+ hash_value_early_read = read_magic_time();
+ return 0;
+}
+
+static int late_resume_init(void)
+{
+ unsigned int val = hash_value_early_read;
+ unsigned int user, file, dev;
+
+ user = val % USERHASH;
+ val = val / USERHASH;
+ file = val % FILEHASH;
+ val = val / FILEHASH;
+ dev = val /* % DEVHASH */;
+
+ printk(" Magic number: %d:%d:%d\n", user, file, dev);
+ show_file_hash(file);
+ show_dev_hash(dev);
+ return 0;
+}
+
+core_initcall(early_resume_init);
+late_initcall(late_resume_init);
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index ae0949b..93d9474 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -402,6 +402,7 @@ config BLK_DEV_RAM_SIZE
config BLK_DEV_INITRD
bool "Initial RAM filesystem and RAM disk (initramfs/initrd) support"
+ depends on BROKEN || !FRV
help
The initial RAM filesystem is a ramfs which is loaded by the
boot loader (loadlin or lilo) and that is mounted as root
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 2a8af68..2641597 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -64,6 +64,7 @@
#include <linux/buffer_head.h>
#include <linux/blkdev.h>
#include <linux/elevator.h>
+#include <linux/interrupt.h>
#include <asm/setup.h>
#include <asm/uaccess.h>
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 25c3c4a..39b0f53 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -34,7 +34,7 @@
#include <linux/blkpg.h>
#include <linux/timer.h>
#include <linux/proc_fs.h>
-#include <linux/init.h>
+#include <linux/init.h>
#include <linux/hdreg.h>
#include <linux/spinlock.h>
#include <linux/compat.h>
@@ -64,143 +64,129 @@ MODULE_LICENSE("GPL");
/* define the PCI info for the cards we can control */
static const struct pci_device_id cciss_pci_device_id[] = {
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISS,
- 0x0E11, 0x4070, 0, 0, 0},
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
- 0x0E11, 0x4080, 0, 0, 0},
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
- 0x0E11, 0x4082, 0, 0, 0},
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
- 0x0E11, 0x4083, 0, 0, 0},
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
- 0x0E11, 0x409A, 0, 0, 0},
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
- 0x0E11, 0x409B, 0, 0, 0},
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
- 0x0E11, 0x409C, 0, 0, 0},
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
- 0x0E11, 0x409D, 0, 0, 0},
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
- 0x0E11, 0x4091, 0, 0, 0},
- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSA,
- 0x103C, 0x3225, 0, 0, 0},
- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
- 0x103c, 0x3223, 0, 0, 0},
- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
- 0x103c, 0x3234, 0, 0, 0},
- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
- 0x103c, 0x3235, 0, 0, 0},
- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
- 0x103c, 0x3211, 0, 0, 0},
- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
- 0x103c, 0x3212, 0, 0, 0},
- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
- 0x103c, 0x3213, 0, 0, 0},
- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
- 0x103c, 0x3214, 0, 0, 0},
- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
- 0x103c, 0x3215, 0, 0, 0},
+ {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISS, 0x0E11, 0x4070},
+ {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, 0x0E11, 0x4080},
+ {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, 0x0E11, 0x4082},
+ {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, 0x0E11, 0x4083},
+ {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x4091},
+ {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409A},
+ {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409B},
+ {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409C},
+ {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409D},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSA, 0x103C, 0x3225},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x3223},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x3234},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x3235},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, 0x103C, 0x3211},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, 0x103C, 0x3212},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, 0x103C, 0x3213},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, 0x103C, 0x3214},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, 0x103C, 0x3215},
{0,}
};
-MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
-#define NR_PRODUCTS ARRAY_SIZE(products)
+MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
/* board_id = Subsystem Device ID & Vendor ID
* product = Marketing Name for the board
- * access = Address of the struct of function pointers
+ * access = Address of the struct of function pointers
*/
static struct board_type products[] = {
- { 0x40700E11, "Smart Array 5300", &SA5_access },
- { 0x40800E11, "Smart Array 5i", &SA5B_access},
- { 0x40820E11, "Smart Array 532", &SA5B_access},
- { 0x40830E11, "Smart Array 5312", &SA5B_access},
- { 0x409A0E11, "Smart Array 641", &SA5_access},
- { 0x409B0E11, "Smart Array 642", &SA5_access},
- { 0x409C0E11, "Smart Array 6400", &SA5_access},
- { 0x409D0E11, "Smart Array 6400 EM", &SA5_access},
- { 0x40910E11, "Smart Array 6i", &SA5_access},
- { 0x3225103C, "Smart Array P600", &SA5_access},
- { 0x3223103C, "Smart Array P800", &SA5_access},
- { 0x3234103C, "Smart Array P400", &SA5_access},
- { 0x3235103C, "Smart Array P400i", &SA5_access},
- { 0x3211103C, "Smart Array E200i", &SA5_access},
- { 0x3212103C, "Smart Array E200", &SA5_access},
- { 0x3213103C, "Smart Array E200i", &SA5_access},
- { 0x3214103C, "Smart Array E200i", &SA5_access},
- { 0x3215103C, "Smart Array E200i", &SA5_access},
+ {0x40700E11, "Smart Array 5300", &SA5_access},
+ {0x40800E11, "Smart Array 5i", &SA5B_access},
+ {0x40820E11, "Smart Array 532", &SA5B_access},
+ {0x40830E11, "Smart Array 5312", &SA5B_access},
+ {0x409A0E11, "Smart Array 641", &SA5_access},
+ {0x409B0E11, "Smart Array 642", &SA5_access},
+ {0x409C0E11, "Smart Array 6400", &SA5_access},
+ {0x409D0E11, "Smart Array 6400 EM", &SA5_access},
+ {0x40910E11, "Smart Array 6i", &SA5_access},
+ {0x3225103C, "Smart Array P600", &SA5_access},
+ {0x3223103C, "Smart Array P800", &SA5_access},
+ {0x3234103C, "Smart Array P400", &SA5_access},
+ {0x3235103C, "Smart Array P400i", &SA5_access},
+ {0x3211103C, "Smart Array E200i", &SA5_access},
+ {0x3212103C, "Smart Array E200", &SA5_access},
+ {0x3213103C, "Smart Array E200i", &SA5_access},
+ {0x3214103C, "Smart Array E200i", &SA5_access},
+ {0x3215103C, "Smart Array E200i", &SA5_access},
};
-/* How long to wait (in millesconds) for board to go into simple mode */
-#define MAX_CONFIG_WAIT 30000
+/* How long to wait (in milliseconds) for board to go into simple mode */
+#define MAX_CONFIG_WAIT 30000
#define MAX_IOCTL_CONFIG_WAIT 1000
/*define how many times we will try a command because of bus resets */
#define MAX_CMD_RETRIES 3
#define READ_AHEAD 1024
-#define NR_CMDS 384 /* #commands that can be outstanding */
+#define NR_CMDS 384 /* #commands that can be outstanding */
#define MAX_CTLR 32
/* Originally cciss driver only supports 8 major numbers */
#define MAX_CTLR_ORIG 8
-
static ctlr_info_t *hba[MAX_CTLR];
static void do_cciss_request(request_queue_t *q);
static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs);
static int cciss_open(struct inode *inode, struct file *filep);
static int cciss_release(struct inode *inode, struct file *filep);
-static int cciss_ioctl(struct inode *inode, struct file *filep,
- unsigned int cmd, unsigned long arg);
+static int cciss_ioctl(struct inode *inode, struct file *filep,
+ unsigned int cmd, unsigned long arg);
static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo);
static int revalidate_allvol(ctlr_info_t *host);
static int cciss_revalidate(struct gendisk *disk);
static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk);
-static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, int clear_all);
+static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
+ int clear_all);
static void cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf,
- int withirq, unsigned int *total_size, unsigned int *block_size);
-static void cciss_geometry_inquiry(int ctlr, int logvol,
- int withirq, unsigned int total_size,
- unsigned int block_size, InquiryData_struct *inq_buff,
- drive_info_struct *drv);
+ int withirq, unsigned int *total_size,
+ unsigned int *block_size);
+static void cciss_geometry_inquiry(int ctlr, int logvol, int withirq,
+ unsigned int total_size,
+ unsigned int block_size,
+ InquiryData_struct *inq_buff,
+ drive_info_struct *drv);
static void cciss_getgeometry(int cntl_num);
-static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *, __u32);
-static void start_io( ctlr_info_t *h);
-static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size,
- unsigned int use_unit_num, unsigned int log_unit, __u8 page_code,
- unsigned char *scsi3addr, int cmd_type);
-static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size,
- unsigned int use_unit_num, unsigned int log_unit, __u8 page_code,
- int cmd_type);
+static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *,
+ __u32);
+static void start_io(ctlr_info_t *h);
+static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size,
+ unsigned int use_unit_num, unsigned int log_unit,
+ __u8 page_code, unsigned char *scsi3addr, int cmd_type);
+static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size,
+ unsigned int use_unit_num, unsigned int log_unit,
+ __u8 page_code, int cmd_type);
static void fail_all_cmds(unsigned long ctlr);
#ifdef CONFIG_PROC_FS
-static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
- int length, int *eof, void *data);
+static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
+ int length, int *eof, void *data);
static void cciss_procinit(int i);
#else
-static void cciss_procinit(int i) {}
-#endif /* CONFIG_PROC_FS */
+static void cciss_procinit(int i)
+{
+}
+#endif /* CONFIG_PROC_FS */
#ifdef CONFIG_COMPAT
static long cciss_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg);
#endif
-static struct block_device_operations cciss_fops = {
- .owner = THIS_MODULE,
- .open = cciss_open,
- .release = cciss_release,
- .ioctl = cciss_ioctl,
- .getgeo = cciss_getgeo,
+static struct block_device_operations cciss_fops = {
+ .owner = THIS_MODULE,
+ .open = cciss_open,
+ .release = cciss_release,
+ .ioctl = cciss_ioctl,
+ .getgeo = cciss_getgeo,
#ifdef CONFIG_COMPAT
- .compat_ioctl = cciss_compat_ioctl,
+ .compat_ioctl = cciss_compat_ioctl,
#endif
- .revalidate_disk= cciss_revalidate,
+ .revalidate_disk = cciss_revalidate,
};
/*
@@ -208,28 +194,29 @@ static struct block_device_operations cciss_fops = {
*/
static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c)
{
- if (*Qptr == NULL) {
- *Qptr = c;
- c->next = c->prev = c;
- } else {
- c->prev = (*Qptr)->prev;
- c->next = (*Qptr);
- (*Qptr)->prev->next = c;
- (*Qptr)->prev = c;
- }
+ if (*Qptr == NULL) {
+ *Qptr = c;
+ c->next = c->prev = c;
+ } else {
+ c->prev = (*Qptr)->prev;
+ c->next = (*Qptr);
+ (*Qptr)->prev->next = c;
+ (*Qptr)->prev = c;
+ }
}
-static inline CommandList_struct *removeQ(CommandList_struct **Qptr,
- CommandList_struct *c)
+static inline CommandList_struct *removeQ(CommandList_struct **Qptr,
+ CommandList_struct *c)
{
- if (c && c->next != c) {
- if (*Qptr == c) *Qptr = c->next;
- c->prev->next = c->next;
- c->next->prev = c->prev;
- } else {
- *Qptr = NULL;
- }
- return c;
+ if (c && c->next != c) {
+ if (*Qptr == c)
+ *Qptr = c->next;
+ c->prev->next = c->next;
+ c->next->prev = c->prev;
+ } else {
+ *Qptr = NULL;
+ }
+ return c;
}
#include "cciss_scsi.c" /* For SCSI tape support */
@@ -242,23 +229,24 @@ static inline CommandList_struct *removeQ(CommandList_struct **Qptr,
#define ENG_GIG 1000000000
#define ENG_GIG_FACTOR (ENG_GIG/512)
#define RAID_UNKNOWN 6
-static const char *raid_label[] = {"0","4","1(1+0)","5","5+1","ADG",
- "UNKNOWN"};
+static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
+ "UNKNOWN"
+};
static struct proc_dir_entry *proc_cciss;
-static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
- int length, int *eof, void *data)
+static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
+ int length, int *eof, void *data)
{
- off_t pos = 0;
- off_t len = 0;
- int size, i, ctlr;
- ctlr_info_t *h = (ctlr_info_t*)data;
- drive_info_struct *drv;
+ off_t pos = 0;
+ off_t len = 0;
+ int size, i, ctlr;
+ ctlr_info_t *h = (ctlr_info_t *) data;
+ drive_info_struct *drv;
unsigned long flags;
- sector_t vol_sz, vol_sz_frac;
+ sector_t vol_sz, vol_sz_frac;
- ctlr = h->ctlr;
+ ctlr = h->ctlr;
/* prevent displaying bogus info during configuration
* or deconfiguration of a logical volume
@@ -266,35 +254,35 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
if (h->busy_configuring) {
spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
- return -EBUSY;
+ return -EBUSY;
}
h->busy_configuring = 1;
spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
- size = sprintf(buffer, "%s: HP %s Controller\n"
- "Board ID: 0x%08lx\n"
- "Firmware Version: %c%c%c%c\n"
- "IRQ: %d\n"
- "Logical drives: %d\n"
- "Current Q depth: %d\n"
- "Current # commands on controller: %d\n"
- "Max Q depth since init: %d\n"
- "Max # commands on controller since init: %d\n"
- "Max SG entries since init: %d\n\n",
- h->devname,
- h->product_name,
- (unsigned long)h->board_id,
- h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[3],
- (unsigned int)h->intr[SIMPLE_MODE_INT],
- h->num_luns,
- h->Qdepth, h->commands_outstanding,
- h->maxQsinceinit, h->max_outstanding, h->maxSG);
-
- pos += size; len += size;
+ size = sprintf(buffer, "%s: HP %s Controller\n"
+ "Board ID: 0x%08lx\n"
+ "Firmware Version: %c%c%c%c\n"
+ "IRQ: %d\n"
+ "Logical drives: %d\n"
+ "Current Q depth: %d\n"
+ "Current # commands on controller: %d\n"
+ "Max Q depth since init: %d\n"
+ "Max # commands on controller since init: %d\n"
+ "Max SG entries since init: %d\n\n",
+ h->devname,
+ h->product_name,
+ (unsigned long)h->board_id,
+ h->firm_ver[0], h->firm_ver[1], h->firm_ver[2],
+ h->firm_ver[3], (unsigned int)h->intr[SIMPLE_MODE_INT],
+ h->num_luns, h->Qdepth, h->commands_outstanding,
+ h->maxQsinceinit, h->max_outstanding, h->maxSG);
+
+ pos += size;
+ len += size;
cciss_proc_tape_report(ctlr, buffer, &pos, &len);
- for(i=0; i<=h->highest_lun; i++) {
+ for (i = 0; i <= h->highest_lun; i++) {
- drv = &h->drv[i];
+ drv = &h->drv[i];
if (drv->heads == 0)
continue;
@@ -305,25 +293,26 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
if (drv->raid_level > 5)
drv->raid_level = RAID_UNKNOWN;
- size = sprintf(buffer+len, "cciss/c%dd%d:"
- "\t%4u.%02uGB\tRAID %s\n",
- ctlr, i, (int)vol_sz, (int)vol_sz_frac,
- raid_label[drv->raid_level]);
- pos += size; len += size;
- }
-
- *eof = 1;
- *start = buffer+offset;
- len -= offset;
- if (len>length)
- len = length;
+ size = sprintf(buffer + len, "cciss/c%dd%d:"
+ "\t%4u.%02uGB\tRAID %s\n",
+ ctlr, i, (int)vol_sz, (int)vol_sz_frac,
+ raid_label[drv->raid_level]);
+ pos += size;
+ len += size;
+ }
+
+ *eof = 1;
+ *start = buffer + offset;
+ len -= offset;
+ if (len > length)
+ len = length;
h->busy_configuring = 0;
- return len;
+ return len;
}
-static int
-cciss_proc_write(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
+static int
+cciss_proc_write(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
{
unsigned char cmd[80];
int len;
@@ -332,20 +321,23 @@ cciss_proc_write(struct file *file, const char __user *buffer,
int rc;
#endif
- if (count > sizeof(cmd)-1) return -EINVAL;
- if (copy_from_user(cmd, buffer, count)) return -EFAULT;
+ if (count > sizeof(cmd) - 1)
+ return -EINVAL;
+ if (copy_from_user(cmd, buffer, count))
+ return -EFAULT;
cmd[count] = '\0';
len = strlen(cmd); // above 3 lines ensure safety
- if (len && cmd[len-1] == '\n')
+ if (len && cmd[len - 1] == '\n')
cmd[--len] = '\0';
# ifdef CONFIG_CISS_SCSI_TAPE
- if (strcmp("engage scsi", cmd)==0) {
- rc = cciss_engage_scsi(h->ctlr);
- if (rc != 0) return -rc;
- return count;
- }
- /* might be nice to have "disengage" too, but it's not
- safely possible. (only 1 module use count, lock issues.) */
+ if (strcmp("engage scsi", cmd) == 0) {
+ rc = cciss_engage_scsi(h->ctlr);
+ if (rc != 0)
+ return -rc;
+ return count;
+ }
+ /* might be nice to have "disengage" too, but it's not
+ safely possible. (only 1 module use count, lock issues.) */
# endif
return -EINVAL;
}
@@ -358,116 +350,113 @@ static void __devinit cciss_procinit(int i)
{
struct proc_dir_entry *pde;
- if (proc_cciss == NULL) {
- proc_cciss = proc_mkdir("cciss", proc_root_driver);
- if (!proc_cciss)
+ if (proc_cciss == NULL) {
+ proc_cciss = proc_mkdir("cciss", proc_root_driver);
+ if (!proc_cciss)
return;
- }
+ }
- pde = create_proc_read_entry(hba[i]->devname,
- S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH,
- proc_cciss, cciss_proc_get_info, hba[i]);
+ pde = create_proc_read_entry(hba[i]->devname,
+ S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH,
+ proc_cciss, cciss_proc_get_info, hba[i]);
pde->write_proc = cciss_proc_write;
}
-#endif /* CONFIG_PROC_FS */
+#endif /* CONFIG_PROC_FS */
-/*
- * For operations that cannot sleep, a command block is allocated at init,
+/*
+ * For operations that cannot sleep, a command block is allocated at init,
* and managed by cmd_alloc() and cmd_free() using a simple bitmap to track
- * which ones are free or in use. For operations that can wait for kmalloc
- * to possible sleep, this routine can be called with get_from_pool set to 0.
- * cmd_free() MUST be called with a got_from_pool set to 0 if cmd_alloc was.
- */
-static CommandList_struct * cmd_alloc(ctlr_info_t *h, int get_from_pool)
+ * which ones are free or in use. For operations that can wait for kmalloc
+ * to possible sleep, this routine can be called with get_from_pool set to 0.
+ * cmd_free() MUST be called with a got_from_pool set to 0 if cmd_alloc was.
+ */
+static CommandList_struct *cmd_alloc(ctlr_info_t *h, int get_from_pool)
{
CommandList_struct *c;
- int i;
+ int i;
u64bit temp64;
dma_addr_t cmd_dma_handle, err_dma_handle;
- if (!get_from_pool)
- {
- c = (CommandList_struct *) pci_alloc_consistent(
- h->pdev, sizeof(CommandList_struct), &cmd_dma_handle);
- if(c==NULL)
- return NULL;
+ if (!get_from_pool) {
+ c = (CommandList_struct *) pci_alloc_consistent(h->pdev,
+ sizeof(CommandList_struct), &cmd_dma_handle);
+ if (c == NULL)
+ return NULL;
memset(c, 0, sizeof(CommandList_struct));
c->cmdindex = -1;
- c->err_info = (ErrorInfo_struct *)pci_alloc_consistent(
- h->pdev, sizeof(ErrorInfo_struct),
- &err_dma_handle);
-
- if (c->err_info == NULL)
- {
- pci_free_consistent(h->pdev,
+ c->err_info = (ErrorInfo_struct *)
+ pci_alloc_consistent(h->pdev, sizeof(ErrorInfo_struct),
+ &err_dma_handle);
+
+ if (c->err_info == NULL) {
+ pci_free_consistent(h->pdev,
sizeof(CommandList_struct), c, cmd_dma_handle);
return NULL;
}
memset(c->err_info, 0, sizeof(ErrorInfo_struct));
- } else /* get it out of the controllers pool */
- {
- do {
- i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS);
- if (i == NR_CMDS)
- return NULL;
- } while(test_and_set_bit(i & (BITS_PER_LONG - 1), h->cmd_pool_bits+(i/BITS_PER_LONG)) != 0);
+ } else { /* get it out of the controllers pool */
+
+ do {
+ i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS);
+ if (i == NR_CMDS)
+ return NULL;
+ } while (test_and_set_bit
+ (i & (BITS_PER_LONG - 1),
+ h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0);
#ifdef CCISS_DEBUG
printk(KERN_DEBUG "cciss: using command buffer %d\n", i);
#endif
- c = h->cmd_pool + i;
+ c = h->cmd_pool + i;
memset(c, 0, sizeof(CommandList_struct));
- cmd_dma_handle = h->cmd_pool_dhandle
- + i*sizeof(CommandList_struct);
+ cmd_dma_handle = h->cmd_pool_dhandle
+ + i * sizeof(CommandList_struct);
c->err_info = h->errinfo_pool + i;
memset(c->err_info, 0, sizeof(ErrorInfo_struct));
- err_dma_handle = h->errinfo_pool_dhandle
- + i*sizeof(ErrorInfo_struct);
- h->nr_allocs++;
+ err_dma_handle = h->errinfo_pool_dhandle
+ + i * sizeof(ErrorInfo_struct);
+ h->nr_allocs++;
c->cmdindex = i;
- }
+ }
c->busaddr = (__u32) cmd_dma_handle;
- temp64.val = (__u64) err_dma_handle;
+ temp64.val = (__u64) err_dma_handle;
c->ErrDesc.Addr.lower = temp64.val32.lower;
c->ErrDesc.Addr.upper = temp64.val32.upper;
c->ErrDesc.Len = sizeof(ErrorInfo_struct);
-
- c->ctlr = h->ctlr;
- return c;
-
+ c->ctlr = h->ctlr;
+ return c;
}
-/*
- * Frees a command block that was previously allocated with cmd_alloc().
+/*
+ * Frees a command block that was previously allocated with cmd_alloc().
*/
static void cmd_free(ctlr_info_t *h, CommandList_struct *c, int got_from_pool)
{
int i;
u64bit temp64;
- if( !got_from_pool)
- {
+ if (!got_from_pool) {
temp64.val32.lower = c->ErrDesc.Addr.lower;
temp64.val32.upper = c->ErrDesc.Addr.upper;
- pci_free_consistent(h->pdev, sizeof(ErrorInfo_struct),
- c->err_info, (dma_addr_t) temp64.val);
- pci_free_consistent(h->pdev, sizeof(CommandList_struct),
- c, (dma_addr_t) c->busaddr);
- } else
- {
+ pci_free_consistent(h->pdev, sizeof(ErrorInfo_struct),
+ c->err_info, (dma_addr_t) temp64.val);
+ pci_free_consistent(h->pdev, sizeof(CommandList_struct),
+ c, (dma_addr_t) c->busaddr);
+ } else {
i = c - h->cmd_pool;
- clear_bit(i&(BITS_PER_LONG-1), h->cmd_pool_bits+(i/BITS_PER_LONG));
- h->nr_frees++;
- }
+ clear_bit(i & (BITS_PER_LONG - 1),
+ h->cmd_pool_bits + (i / BITS_PER_LONG));
+ h->nr_frees++;
+ }
}
static inline ctlr_info_t *get_host(struct gendisk *disk)
{
- return disk->queue->queuedata;
+ return disk->queue->queuedata;
}
static inline drive_info_struct *get_drv(struct gendisk *disk)
@@ -485,7 +474,7 @@ static int cciss_open(struct inode *inode, struct file *filep)
#ifdef CCISS_DEBUG
printk(KERN_DEBUG "cciss_open %s\n", inode->i_bdev->bd_disk->disk_name);
-#endif /* CCISS_DEBUG */
+#endif /* CCISS_DEBUG */
if (host->busy_initializing || drv->busy_configuring)
return -EBUSY;
@@ -498,10 +487,10 @@ static int cciss_open(struct inode *inode, struct file *filep)
* for "raw controller".
*/
if (drv->nr_blocks == 0) {
- if (iminor(inode) != 0) { /* not node 0? */
+ if (iminor(inode) != 0) { /* not node 0? */
/* if not node 0 make sure it is a partition = 0 */
if (iminor(inode) & 0x0f) {
- return -ENXIO;
+ return -ENXIO;
/* if it is, make sure we have a LUN ID */
} else if (drv->LunID == 0) {
return -ENXIO;
@@ -514,6 +503,7 @@ static int cciss_open(struct inode *inode, struct file *filep)
host->usage_count++;
return 0;
}
+
/*
* Close. Sync first.
*/
@@ -523,8 +513,9 @@ static int cciss_release(struct inode *inode, struct file *filep)
drive_info_struct *drv = get_drv(inode->i_bdev->bd_disk);
#ifdef CCISS_DEBUG
- printk(KERN_DEBUG "cciss_release %s\n", inode->i_bdev->bd_disk->disk_name);
-#endif /* CCISS_DEBUG */
+ printk(KERN_DEBUG "cciss_release %s\n",
+ inode->i_bdev->bd_disk->disk_name);
+#endif /* CCISS_DEBUG */
drv->usage_count--;
host->usage_count--;
@@ -542,8 +533,10 @@ static int do_ioctl(struct file *f, unsigned cmd, unsigned long arg)
return ret;
}
-static int cciss_ioctl32_passthru(struct file *f, unsigned cmd, unsigned long arg);
-static int cciss_ioctl32_big_passthru(struct file *f, unsigned cmd, unsigned long arg);
+static int cciss_ioctl32_passthru(struct file *f, unsigned cmd,
+ unsigned long arg);
+static int cciss_ioctl32_big_passthru(struct file *f, unsigned cmd,
+ unsigned long arg);
static long cciss_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg)
{
@@ -575,19 +568,26 @@ static long cciss_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg)
}
}
-static int cciss_ioctl32_passthru(struct file *f, unsigned cmd, unsigned long arg)
+static int cciss_ioctl32_passthru(struct file *f, unsigned cmd,
+ unsigned long arg)
{
IOCTL32_Command_struct __user *arg32 =
- (IOCTL32_Command_struct __user *) arg;
+ (IOCTL32_Command_struct __user *) arg;
IOCTL_Command_struct arg64;
IOCTL_Command_struct __user *p = compat_alloc_user_space(sizeof(arg64));
int err;
u32 cp;
err = 0;
- err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info));
- err |= copy_from_user(&arg64.Request, &arg32->Request, sizeof(arg64.Request));
- err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info));
+ err |=
+ copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
+ sizeof(arg64.LUN_info));
+ err |=
+ copy_from_user(&arg64.Request, &arg32->Request,
+ sizeof(arg64.Request));
+ err |=
+ copy_from_user(&arg64.error_info, &arg32->error_info,
+ sizeof(arg64.error_info));
err |= get_user(arg64.buf_size, &arg32->buf_size);
err |= get_user(cp, &arg32->buf);
arg64.buf = compat_ptr(cp);
@@ -596,28 +596,38 @@ static int cciss_ioctl32_passthru(struct file *f, unsigned cmd, unsigned long ar
if (err)
return -EFAULT;
- err = do_ioctl(f, CCISS_PASSTHRU, (unsigned long) p);
+ err = do_ioctl(f, CCISS_PASSTHRU, (unsigned long)p);
if (err)
return err;
- err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info));
+ err |=
+ copy_in_user(&arg32->error_info, &p->error_info,
+ sizeof(arg32->error_info));
if (err)
return -EFAULT;
return err;
}
-static int cciss_ioctl32_big_passthru(struct file *file, unsigned cmd, unsigned long arg)
+static int cciss_ioctl32_big_passthru(struct file *file, unsigned cmd,
+ unsigned long arg)
{
BIG_IOCTL32_Command_struct __user *arg32 =
- (BIG_IOCTL32_Command_struct __user *) arg;
+ (BIG_IOCTL32_Command_struct __user *) arg;
BIG_IOCTL_Command_struct arg64;
- BIG_IOCTL_Command_struct __user *p = compat_alloc_user_space(sizeof(arg64));
+ BIG_IOCTL_Command_struct __user *p =
+ compat_alloc_user_space(sizeof(arg64));
int err;
u32 cp;
err = 0;
- err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info));
- err |= copy_from_user(&arg64.Request, &arg32->Request, sizeof(arg64.Request));
- err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info));
+ err |=
+ copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
+ sizeof(arg64.LUN_info));
+ err |=
+ copy_from_user(&arg64.Request, &arg32->Request,
+ sizeof(arg64.Request));
+ err |=
+ copy_from_user(&arg64.error_info, &arg32->error_info,
+ sizeof(arg64.error_info));
err |= get_user(arg64.buf_size, &arg32->buf_size);
err |= get_user(arg64.malloc_size, &arg32->malloc_size);
err |= get_user(cp, &arg32->buf);
@@ -625,12 +635,14 @@ static int cciss_ioctl32_big_passthru(struct file *file, unsigned cmd, unsigned
err |= copy_to_user(p, &arg64, sizeof(arg64));
if (err)
- return -EFAULT;
+ return -EFAULT;
- err = do_ioctl(file, CCISS_BIG_PASSTHRU, (unsigned long) p);
+ err = do_ioctl(file, CCISS_BIG_PASSTHRU, (unsigned long)p);
if (err)
return err;
- err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info));
+ err |=
+ copy_in_user(&arg32->error_info, &p->error_info,
+ sizeof(arg32->error_info));
if (err)
return -EFAULT;
return err;
@@ -651,10 +663,10 @@ static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo)
}
/*
- * ioctl
+ * ioctl
*/
-static int cciss_ioctl(struct inode *inode, struct file *filep,
- unsigned int cmd, unsigned long arg)
+static int cciss_ioctl(struct inode *inode, struct file *filep,
+ unsigned int cmd, unsigned long arg)
{
struct block_device *bdev = inode->i_bdev;
struct gendisk *disk = bdev->bd_disk;
@@ -665,171 +677,193 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
#ifdef CCISS_DEBUG
printk(KERN_DEBUG "cciss_ioctl: Called with cmd=%x %lx\n", cmd, arg);
-#endif /* CCISS_DEBUG */
-
- switch(cmd) {
+#endif /* CCISS_DEBUG */
+
+ switch (cmd) {
case CCISS_GETPCIINFO:
- {
- cciss_pci_info_struct pciinfo;
-
- if (!arg) return -EINVAL;
- pciinfo.domain = pci_domain_nr(host->pdev->bus);
- pciinfo.bus = host->pdev->bus->number;
- pciinfo.dev_fn = host->pdev->devfn;
- pciinfo.board_id = host->board_id;
- if (copy_to_user(argp, &pciinfo, sizeof( cciss_pci_info_struct )))
- return -EFAULT;
- return(0);
- }
+ {
+ cciss_pci_info_struct pciinfo;
+
+ if (!arg)
+ return -EINVAL;
+ pciinfo.domain = pci_domain_nr(host->pdev->bus);
+ pciinfo.bus = host->pdev->bus->number;
+ pciinfo.dev_fn = host->pdev->devfn;
+ pciinfo.board_id = host->board_id;
+ if (copy_to_user
+ (argp, &pciinfo, sizeof(cciss_pci_info_struct)))
+ return -EFAULT;
+ return 0;
+ }
case CCISS_GETINTINFO:
- {
- cciss_coalint_struct intinfo;
- if (!arg) return -EINVAL;
- intinfo.delay = readl(&host->cfgtable->HostWrite.CoalIntDelay);
- intinfo.count = readl(&host->cfgtable->HostWrite.CoalIntCount);
- if (copy_to_user(argp, &intinfo, sizeof( cciss_coalint_struct )))
- return -EFAULT;
- return(0);
- }
+ {
+ cciss_coalint_struct intinfo;
+ if (!arg)
+ return -EINVAL;
+ intinfo.delay =
+ readl(&host->cfgtable->HostWrite.CoalIntDelay);
+ intinfo.count =
+ readl(&host->cfgtable->HostWrite.CoalIntCount);
+ if (copy_to_user
+ (argp, &intinfo, sizeof(cciss_coalint_struct)))
+ return -EFAULT;
+ return 0;
+ }
case CCISS_SETINTINFO:
- {
- cciss_coalint_struct intinfo;
- unsigned long flags;
- int i;
-
- if (!arg) return -EINVAL;
- if (!capable(CAP_SYS_ADMIN)) return -EPERM;
- if (copy_from_user(&intinfo, argp, sizeof( cciss_coalint_struct)))
- return -EFAULT;
- if ( (intinfo.delay == 0 ) && (intinfo.count == 0))
-
{
-// printk("cciss_ioctl: delay and count cannot be 0\n");
- return( -EINVAL);
+ cciss_coalint_struct intinfo;
+ unsigned long flags;
+ int i;
+
+ if (!arg)
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (copy_from_user
+ (&intinfo, argp, sizeof(cciss_coalint_struct)))
+ return -EFAULT;
+ if ((intinfo.delay == 0) && (intinfo.count == 0))
+ {
+// printk("cciss_ioctl: delay and count cannot be 0\n");
+ return -EINVAL;
+ }
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+ /* Update the field, and then ring the doorbell */
+ writel(intinfo.delay,
+ &(host->cfgtable->HostWrite.CoalIntDelay));
+ writel(intinfo.count,
+ &(host->cfgtable->HostWrite.CoalIntCount));
+ writel(CFGTBL_ChangeReq, host->vaddr + SA5_DOORBELL);
+
+ for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
+ if (!(readl(host->vaddr + SA5_DOORBELL)
+ & CFGTBL_ChangeReq))
+ break;
+ /* delay and try again */
+ udelay(1000);
+ }
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ if (i >= MAX_IOCTL_CONFIG_WAIT)
+ return -EAGAIN;
+ return 0;
}
- spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
- /* Update the field, and then ring the doorbell */
- writel( intinfo.delay,
- &(host->cfgtable->HostWrite.CoalIntDelay));
- writel( intinfo.count,
- &(host->cfgtable->HostWrite.CoalIntCount));
- writel( CFGTBL_ChangeReq, host->vaddr + SA5_DOORBELL);
-
- for(i=0;i<MAX_IOCTL_CONFIG_WAIT;i++) {
- if (!(readl(host->vaddr + SA5_DOORBELL)
- & CFGTBL_ChangeReq))
- break;
- /* delay and try again */
- udelay(1000);
- }
- spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
- if (i >= MAX_IOCTL_CONFIG_WAIT)
- return -EAGAIN;
- return(0);
- }
case CCISS_GETNODENAME:
- {
- NodeName_type NodeName;
- int i;
-
- if (!arg) return -EINVAL;
- for(i=0;i<16;i++)
- NodeName[i] = readb(&host->cfgtable->ServerName[i]);
- if (copy_to_user(argp, NodeName, sizeof( NodeName_type)))
- return -EFAULT;
- return(0);
- }
+ {
+ NodeName_type NodeName;
+ int i;
+
+ if (!arg)
+ return -EINVAL;
+ for (i = 0; i < 16; i++)
+ NodeName[i] =
+ readb(&host->cfgtable->ServerName[i]);
+ if (copy_to_user(argp, NodeName, sizeof(NodeName_type)))
+ return -EFAULT;
+ return 0;
+ }
case CCISS_SETNODENAME:
- {
- NodeName_type NodeName;
- unsigned long flags;
- int i;
-
- if (!arg) return -EINVAL;
- if (!capable(CAP_SYS_ADMIN)) return -EPERM;
-
- if (copy_from_user(NodeName, argp, sizeof( NodeName_type)))
- return -EFAULT;
-
- spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
-
- /* Update the field, and then ring the doorbell */
- for(i=0;i<16;i++)
- writeb( NodeName[i], &host->cfgtable->ServerName[i]);
-
- writel( CFGTBL_ChangeReq, host->vaddr + SA5_DOORBELL);
-
- for(i=0;i<MAX_IOCTL_CONFIG_WAIT;i++) {
- if (!(readl(host->vaddr + SA5_DOORBELL)
- & CFGTBL_ChangeReq))
- break;
- /* delay and try again */
- udelay(1000);
- }
- spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
- if (i >= MAX_IOCTL_CONFIG_WAIT)
- return -EAGAIN;
- return(0);
- }
+ {
+ NodeName_type NodeName;
+ unsigned long flags;
+ int i;
+
+ if (!arg)
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (copy_from_user
+ (NodeName, argp, sizeof(NodeName_type)))
+ return -EFAULT;
+
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+
+ /* Update the field, and then ring the doorbell */
+ for (i = 0; i < 16; i++)
+ writeb(NodeName[i],
+ &host->cfgtable->ServerName[i]);
+
+ writel(CFGTBL_ChangeReq, host->vaddr + SA5_DOORBELL);
+
+ for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
+ if (!(readl(host->vaddr + SA5_DOORBELL)
+ & CFGTBL_ChangeReq))
+ break;
+ /* delay and try again */
+ udelay(1000);
+ }
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ if (i >= MAX_IOCTL_CONFIG_WAIT)
+ return -EAGAIN;
+ return 0;
+ }
case CCISS_GETHEARTBEAT:
- {
- Heartbeat_type heartbeat;
-
- if (!arg) return -EINVAL;
- heartbeat = readl(&host->cfgtable->HeartBeat);
- if (copy_to_user(argp, &heartbeat, sizeof( Heartbeat_type)))
- return -EFAULT;
- return(0);
- }
+ {
+ Heartbeat_type heartbeat;
+
+ if (!arg)
+ return -EINVAL;
+ heartbeat = readl(&host->cfgtable->HeartBeat);
+ if (copy_to_user
+ (argp, &heartbeat, sizeof(Heartbeat_type)))
+ return -EFAULT;
+ return 0;
+ }
case CCISS_GETBUSTYPES:
- {
- BusTypes_type BusTypes;
-
- if (!arg) return -EINVAL;
- BusTypes = readl(&host->cfgtable->BusTypes);
- if (copy_to_user(argp, &BusTypes, sizeof( BusTypes_type) ))
- return -EFAULT;
- return(0);
- }
+ {
+ BusTypes_type BusTypes;
+
+ if (!arg)
+ return -EINVAL;
+ BusTypes = readl(&host->cfgtable->BusTypes);
+ if (copy_to_user
+ (argp, &BusTypes, sizeof(BusTypes_type)))
+ return -EFAULT;
+ return 0;
+ }
case CCISS_GETFIRMVER:
- {
- FirmwareVer_type firmware;
+ {
+ FirmwareVer_type firmware;
- if (!arg) return -EINVAL;
- memcpy(firmware, host->firm_ver, 4);
+ if (!arg)
+ return -EINVAL;
+ memcpy(firmware, host->firm_ver, 4);
- if (copy_to_user(argp, firmware, sizeof( FirmwareVer_type)))
- return -EFAULT;
- return(0);
- }
- case CCISS_GETDRIVVER:
- {
- DriverVer_type DriverVer = DRIVER_VERSION;
+ if (copy_to_user
+ (argp, firmware, sizeof(FirmwareVer_type)))
+ return -EFAULT;
+ return 0;
+ }
+ case CCISS_GETDRIVVER:
+ {
+ DriverVer_type DriverVer = DRIVER_VERSION;
- if (!arg) return -EINVAL;
+ if (!arg)
+ return -EINVAL;
- if (copy_to_user(argp, &DriverVer, sizeof( DriverVer_type) ))
- return -EFAULT;
- return(0);
- }
+ if (copy_to_user
+ (argp, &DriverVer, sizeof(DriverVer_type)))
+ return -EFAULT;
+ return 0;
+ }
case CCISS_REVALIDVOLS:
if (bdev != bdev->bd_contains || drv != host->drv)
return -ENXIO;
- return revalidate_allvol(host);
-
- case CCISS_GETLUNINFO: {
- LogvolInfo_struct luninfo;
-
- luninfo.LunID = drv->LunID;
- luninfo.num_opens = drv->usage_count;
- luninfo.num_parts = 0;
- if (copy_to_user(argp, &luninfo,
- sizeof(LogvolInfo_struct)))
- return -EFAULT;
- return(0);
- }
+ return revalidate_allvol(host);
+
+ case CCISS_GETLUNINFO:{
+ LogvolInfo_struct luninfo;
+
+ luninfo.LunID = drv->LunID;
+ luninfo.num_opens = drv->usage_count;
+ luninfo.num_parts = 0;
+ if (copy_to_user(argp, &luninfo,
+ sizeof(LogvolInfo_struct)))
+ return -EFAULT;
+ return 0;
+ }
case CCISS_DEREGDISK:
return rebuild_lun_table(host, disk);
@@ -837,278 +871,284 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
return rebuild_lun_table(host, NULL);
case CCISS_PASSTHRU:
- {
- IOCTL_Command_struct iocommand;
- CommandList_struct *c;
- char *buff = NULL;
- u64bit temp64;
- unsigned long flags;
- DECLARE_COMPLETION(wait);
-
- if (!arg) return -EINVAL;
-
- if (!capable(CAP_SYS_RAWIO)) return -EPERM;
-
- if (copy_from_user(&iocommand, argp, sizeof( IOCTL_Command_struct) ))
- return -EFAULT;
- if((iocommand.buf_size < 1) &&
- (iocommand.Request.Type.Direction != XFER_NONE))
- {
- return -EINVAL;
- }
-#if 0 /* 'buf_size' member is 16-bits, and always smaller than kmalloc limit */
- /* Check kmalloc limits */
- if(iocommand.buf_size > 128000)
- return -EINVAL;
-#endif
- if(iocommand.buf_size > 0)
- {
- buff = kmalloc(iocommand.buf_size, GFP_KERNEL);
- if( buff == NULL)
- return -EFAULT;
- }
- if (iocommand.Request.Type.Direction == XFER_WRITE)
- {
- /* Copy the data into the buffer we created */
- if (copy_from_user(buff, iocommand.buf, iocommand.buf_size))
- {
- kfree(buff);
- return -EFAULT;
- }
- } else {
- memset(buff, 0, iocommand.buf_size);
- }
- if ((c = cmd_alloc(host , 0)) == NULL)
- {
- kfree(buff);
- return -ENOMEM;
- }
- // Fill in the command type
- c->cmd_type = CMD_IOCTL_PEND;
- // Fill in Command Header
- c->Header.ReplyQueue = 0; // unused in simple mode
- if( iocommand.buf_size > 0) // buffer to fill
{
- c->Header.SGList = 1;
- c->Header.SGTotal= 1;
- } else // no buffers to fill
- {
- c->Header.SGList = 0;
- c->Header.SGTotal= 0;
- }
- c->Header.LUN = iocommand.LUN_info;
- c->Header.Tag.lower = c->busaddr; // use the kernel address the cmd block for tag
-
- // Fill in Request block
- c->Request = iocommand.Request;
-
- // Fill in the scatter gather information
- if (iocommand.buf_size > 0 )
- {
- temp64.val = pci_map_single( host->pdev, buff,
- iocommand.buf_size,
- PCI_DMA_BIDIRECTIONAL);
- c->SG[0].Addr.lower = temp64.val32.lower;
- c->SG[0].Addr.upper = temp64.val32.upper;
- c->SG[0].Len = iocommand.buf_size;
- c->SG[0].Ext = 0; // we are not chaining
- }
- c->waiting = &wait;
+ IOCTL_Command_struct iocommand;
+ CommandList_struct *c;
+ char *buff = NULL;
+ u64bit temp64;
+ unsigned long flags;
+ DECLARE_COMPLETION(wait);
- /* Put the request on the tail of the request queue */
- spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
- addQ(&host->reqQ, c);
- host->Qdepth++;
- start_io(host);
- spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ if (!arg)
+ return -EINVAL;
- wait_for_completion(&wait);
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
- /* unlock the buffers from DMA */
- temp64.val32.lower = c->SG[0].Addr.lower;
- temp64.val32.upper = c->SG[0].Addr.upper;
- pci_unmap_single( host->pdev, (dma_addr_t) temp64.val,
- iocommand.buf_size, PCI_DMA_BIDIRECTIONAL);
+ if (copy_from_user
+ (&iocommand, argp, sizeof(IOCTL_Command_struct)))
+ return -EFAULT;
+ if ((iocommand.buf_size < 1) &&
+ (iocommand.Request.Type.Direction != XFER_NONE)) {
+ return -EINVAL;
+ }
+#if 0 /* 'buf_size' member is 16-bits, and always smaller than kmalloc limit */
+ /* Check kmalloc limits */
+ if (iocommand.buf_size > 128000)
+ return -EINVAL;
+#endif
+ if (iocommand.buf_size > 0) {
+ buff = kmalloc(iocommand.buf_size, GFP_KERNEL);
+ if (buff == NULL)
+ return -EFAULT;
+ }
+ if (iocommand.Request.Type.Direction == XFER_WRITE) {
+ /* Copy the data into the buffer we created */
+ if (copy_from_user
+ (buff, iocommand.buf, iocommand.buf_size)) {
+ kfree(buff);
+ return -EFAULT;
+ }
+ } else {
+ memset(buff, 0, iocommand.buf_size);
+ }
+ if ((c = cmd_alloc(host, 0)) == NULL) {
+ kfree(buff);
+ return -ENOMEM;
+ }
+ // Fill in the command type
+ c->cmd_type = CMD_IOCTL_PEND;
+ // Fill in Command Header
+ c->Header.ReplyQueue = 0; // unused in simple mode
+ if (iocommand.buf_size > 0) // buffer to fill
+ {
+ c->Header.SGList = 1;
+ c->Header.SGTotal = 1;
+ } else // no buffers to fill
+ {
+ c->Header.SGList = 0;
+ c->Header.SGTotal = 0;
+ }
+ c->Header.LUN = iocommand.LUN_info;
+ c->Header.Tag.lower = c->busaddr; // use the kernel address the cmd block for tag
- /* Copy the error information out */
- iocommand.error_info = *(c->err_info);
- if ( copy_to_user(argp, &iocommand, sizeof( IOCTL_Command_struct) ) )
- {
- kfree(buff);
- cmd_free(host, c, 0);
- return( -EFAULT);
- }
+ // Fill in Request block
+ c->Request = iocommand.Request;
- if (iocommand.Request.Type.Direction == XFER_READ)
- {
- /* Copy the data out of the buffer we created */
- if (copy_to_user(iocommand.buf, buff, iocommand.buf_size))
- {
- kfree(buff);
+ // Fill in the scatter gather information
+ if (iocommand.buf_size > 0) {
+ temp64.val = pci_map_single(host->pdev, buff,
+ iocommand.buf_size,
+ PCI_DMA_BIDIRECTIONAL);
+ c->SG[0].Addr.lower = temp64.val32.lower;
+ c->SG[0].Addr.upper = temp64.val32.upper;
+ c->SG[0].Len = iocommand.buf_size;
+ c->SG[0].Ext = 0; // we are not chaining
+ }
+ c->waiting = &wait;
+
+ /* Put the request on the tail of the request queue */
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+ addQ(&host->reqQ, c);
+ host->Qdepth++;
+ start_io(host);
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+
+ wait_for_completion(&wait);
+
+ /* unlock the buffers from DMA */
+ temp64.val32.lower = c->SG[0].Addr.lower;
+ temp64.val32.upper = c->SG[0].Addr.upper;
+ pci_unmap_single(host->pdev, (dma_addr_t) temp64.val,
+ iocommand.buf_size,
+ PCI_DMA_BIDIRECTIONAL);
+
+ /* Copy the error information out */
+ iocommand.error_info = *(c->err_info);
+ if (copy_to_user
+ (argp, &iocommand, sizeof(IOCTL_Command_struct))) {
+ kfree(buff);
cmd_free(host, c, 0);
return -EFAULT;
}
- }
- kfree(buff);
- cmd_free(host, c, 0);
- return(0);
- }
- case CCISS_BIG_PASSTHRU: {
- BIG_IOCTL_Command_struct *ioc;
- CommandList_struct *c;
- unsigned char **buff = NULL;
- int *buff_size = NULL;
- u64bit temp64;
- unsigned long flags;
- BYTE sg_used = 0;
- int status = 0;
- int i;
- DECLARE_COMPLETION(wait);
- __u32 left;
- __u32 sz;
- BYTE __user *data_ptr;
-
- if (!arg)
- return -EINVAL;
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- ioc = (BIG_IOCTL_Command_struct *)
- kmalloc(sizeof(*ioc), GFP_KERNEL);
- if (!ioc) {
- status = -ENOMEM;
- goto cleanup1;
- }
- if (copy_from_user(ioc, argp, sizeof(*ioc))) {
- status = -EFAULT;
- goto cleanup1;
+
+ if (iocommand.Request.Type.Direction == XFER_READ) {
+ /* Copy the data out of the buffer we created */
+ if (copy_to_user
+ (iocommand.buf, buff, iocommand.buf_size)) {
+ kfree(buff);
+ cmd_free(host, c, 0);
+ return -EFAULT;
+ }
+ }
+ kfree(buff);
+ cmd_free(host, c, 0);
+ return 0;
}
- if ((ioc->buf_size < 1) &&
- (ioc->Request.Type.Direction != XFER_NONE)) {
+ case CCISS_BIG_PASSTHRU:{
+ BIG_IOCTL_Command_struct *ioc;
+ CommandList_struct *c;
+ unsigned char **buff = NULL;
+ int *buff_size = NULL;
+ u64bit temp64;
+ unsigned long flags;
+ BYTE sg_used = 0;
+ int status = 0;
+ int i;
+ DECLARE_COMPLETION(wait);
+ __u32 left;
+ __u32 sz;
+ BYTE __user *data_ptr;
+
+ if (!arg)
+ return -EINVAL;
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ ioc = (BIG_IOCTL_Command_struct *)
+ kmalloc(sizeof(*ioc), GFP_KERNEL);
+ if (!ioc) {
+ status = -ENOMEM;
+ goto cleanup1;
+ }
+ if (copy_from_user(ioc, argp, sizeof(*ioc))) {
+ status = -EFAULT;
+ goto cleanup1;
+ }
+ if ((ioc->buf_size < 1) &&
+ (ioc->Request.Type.Direction != XFER_NONE)) {
status = -EINVAL;
goto cleanup1;
- }
- /* Check kmalloc limits using all SGs */
- if (ioc->malloc_size > MAX_KMALLOC_SIZE) {
- status = -EINVAL;
- goto cleanup1;
- }
- if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) {
- status = -EINVAL;
- goto cleanup1;
- }
- buff = kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL);
- if (!buff) {
- status = -ENOMEM;
- goto cleanup1;
- }
- buff_size = (int *) kmalloc(MAXSGENTRIES * sizeof(int),
- GFP_KERNEL);
- if (!buff_size) {
- status = -ENOMEM;
- goto cleanup1;
- }
- left = ioc->buf_size;
- data_ptr = ioc->buf;
- while (left) {
- sz = (left > ioc->malloc_size) ? ioc->malloc_size : left;
- buff_size[sg_used] = sz;
- buff[sg_used] = kmalloc(sz, GFP_KERNEL);
- if (buff[sg_used] == NULL) {
+ }
+ /* Check kmalloc limits using all SGs */
+ if (ioc->malloc_size > MAX_KMALLOC_SIZE) {
+ status = -EINVAL;
+ goto cleanup1;
+ }
+ if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) {
+ status = -EINVAL;
+ goto cleanup1;
+ }
+ buff =
+ kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL);
+ if (!buff) {
status = -ENOMEM;
goto cleanup1;
}
- if (ioc->Request.Type.Direction == XFER_WRITE) {
- if (copy_from_user(buff[sg_used], data_ptr, sz)) {
+ buff_size = (int *)kmalloc(MAXSGENTRIES * sizeof(int),
+ GFP_KERNEL);
+ if (!buff_size) {
+ status = -ENOMEM;
+ goto cleanup1;
+ }
+ left = ioc->buf_size;
+ data_ptr = ioc->buf;
+ while (left) {
+ sz = (left >
+ ioc->malloc_size) ? ioc->
+ malloc_size : left;
+ buff_size[sg_used] = sz;
+ buff[sg_used] = kmalloc(sz, GFP_KERNEL);
+ if (buff[sg_used] == NULL) {
status = -ENOMEM;
goto cleanup1;
}
+ if (ioc->Request.Type.Direction == XFER_WRITE) {
+ if (copy_from_user
+ (buff[sg_used], data_ptr, sz)) {
+ status = -ENOMEM;
+ goto cleanup1;
+ }
+ } else {
+ memset(buff[sg_used], 0, sz);
+ }
+ left -= sz;
+ data_ptr += sz;
+ sg_used++;
+ }
+ if ((c = cmd_alloc(host, 0)) == NULL) {
+ status = -ENOMEM;
+ goto cleanup1;
+ }
+ c->cmd_type = CMD_IOCTL_PEND;
+ c->Header.ReplyQueue = 0;
+
+ if (ioc->buf_size > 0) {
+ c->Header.SGList = sg_used;
+ c->Header.SGTotal = sg_used;
} else {
- memset(buff[sg_used], 0, sz);
+ c->Header.SGList = 0;
+ c->Header.SGTotal = 0;
}
- left -= sz;
- data_ptr += sz;
- sg_used++;
- }
- if ((c = cmd_alloc(host , 0)) == NULL) {
- status = -ENOMEM;
- goto cleanup1;
- }
- c->cmd_type = CMD_IOCTL_PEND;
- c->Header.ReplyQueue = 0;
-
- if( ioc->buf_size > 0) {
- c->Header.SGList = sg_used;
- c->Header.SGTotal= sg_used;
- } else {
- c->Header.SGList = 0;
- c->Header.SGTotal= 0;
- }
- c->Header.LUN = ioc->LUN_info;
- c->Header.Tag.lower = c->busaddr;
-
- c->Request = ioc->Request;
- if (ioc->buf_size > 0 ) {
- int i;
- for(i=0; i<sg_used; i++) {
- temp64.val = pci_map_single( host->pdev, buff[i],
- buff_size[i],
+ c->Header.LUN = ioc->LUN_info;
+ c->Header.Tag.lower = c->busaddr;
+
+ c->Request = ioc->Request;
+ if (ioc->buf_size > 0) {
+ int i;
+ for (i = 0; i < sg_used; i++) {
+ temp64.val =
+ pci_map_single(host->pdev, buff[i],
+ buff_size[i],
+ PCI_DMA_BIDIRECTIONAL);
+ c->SG[i].Addr.lower =
+ temp64.val32.lower;
+ c->SG[i].Addr.upper =
+ temp64.val32.upper;
+ c->SG[i].Len = buff_size[i];
+ c->SG[i].Ext = 0; /* we are not chaining */
+ }
+ }
+ c->waiting = &wait;
+ /* Put the request on the tail of the request queue */
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+ addQ(&host->reqQ, c);
+ host->Qdepth++;
+ start_io(host);
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ wait_for_completion(&wait);
+ /* unlock the buffers from DMA */
+ for (i = 0; i < sg_used; i++) {
+ temp64.val32.lower = c->SG[i].Addr.lower;
+ temp64.val32.upper = c->SG[i].Addr.upper;
+ pci_unmap_single(host->pdev,
+ (dma_addr_t) temp64.val, buff_size[i],
PCI_DMA_BIDIRECTIONAL);
- c->SG[i].Addr.lower = temp64.val32.lower;
- c->SG[i].Addr.upper = temp64.val32.upper;
- c->SG[i].Len = buff_size[i];
- c->SG[i].Ext = 0; /* we are not chaining */
}
- }
- c->waiting = &wait;
- /* Put the request on the tail of the request queue */
- spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
- addQ(&host->reqQ, c);
- host->Qdepth++;
- start_io(host);
- spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
- wait_for_completion(&wait);
- /* unlock the buffers from DMA */
- for(i=0; i<sg_used; i++) {
- temp64.val32.lower = c->SG[i].Addr.lower;
- temp64.val32.upper = c->SG[i].Addr.upper;
- pci_unmap_single( host->pdev, (dma_addr_t) temp64.val,
- buff_size[i], PCI_DMA_BIDIRECTIONAL);
- }
- /* Copy the error information out */
- ioc->error_info = *(c->err_info);
- if (copy_to_user(argp, ioc, sizeof(*ioc))) {
- cmd_free(host, c, 0);
- status = -EFAULT;
- goto cleanup1;
- }
- if (ioc->Request.Type.Direction == XFER_READ) {
- /* Copy the data out of the buffer we created */
- BYTE __user *ptr = ioc->buf;
- for(i=0; i< sg_used; i++) {
- if (copy_to_user(ptr, buff[i], buff_size[i])) {
- cmd_free(host, c, 0);
- status = -EFAULT;
- goto cleanup1;
+ /* Copy the error information out */
+ ioc->error_info = *(c->err_info);
+ if (copy_to_user(argp, ioc, sizeof(*ioc))) {
+ cmd_free(host, c, 0);
+ status = -EFAULT;
+ goto cleanup1;
+ }
+ if (ioc->Request.Type.Direction == XFER_READ) {
+ /* Copy the data out of the buffer we created */
+ BYTE __user *ptr = ioc->buf;
+ for (i = 0; i < sg_used; i++) {
+ if (copy_to_user
+ (ptr, buff[i], buff_size[i])) {
+ cmd_free(host, c, 0);
+ status = -EFAULT;
+ goto cleanup1;
+ }
+ ptr += buff_size[i];
}
- ptr += buff_size[i];
}
+ cmd_free(host, c, 0);
+ status = 0;
+ cleanup1:
+ if (buff) {
+ for (i = 0; i < sg_used; i++)
+ kfree(buff[i]);
+ kfree(buff);
+ }
+ kfree(buff_size);
+ kfree(ioc);
+ return status;
}
- cmd_free(host, c, 0);
- status = 0;
-cleanup1:
- if (buff) {
- for(i=0; i<sg_used; i++)
- kfree(buff[i]);
- kfree(buff);
- }
- kfree(buff_size);
- kfree(ioc);
- return(status);
- }
default:
return -ENOTTY;
}
-
}
/*
@@ -1119,7 +1159,7 @@ cleanup1:
*
* Right now I'm using the getgeometry() function to do this, but this
* function should probably be finer grained and allow you to revalidate one
- * particualar logical volume (instead of all of them on a particular
+ * particular logical volume (instead of all of them on a particular
* controller).
*/
static int revalidate_allvol(ctlr_info_t *host)
@@ -1127,17 +1167,17 @@ static int revalidate_allvol(ctlr_info_t *host)
int ctlr = host->ctlr, i;
unsigned long flags;
- spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
- if (host->usage_count > 1) {
- spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
- printk(KERN_WARNING "cciss: Device busy for volume"
- " revalidation (usage=%d)\n", host->usage_count);
- return -EBUSY;
- }
- host->usage_count++;
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+ if (host->usage_count > 1) {
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ printk(KERN_WARNING "cciss: Device busy for volume"
+ " revalidation (usage=%d)\n", host->usage_count);
+ return -EBUSY;
+ }
+ host->usage_count++;
spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
- for(i=0; i< NWD; i++) {
+ for (i = 0; i < NWD; i++) {
struct gendisk *disk = host->gendisk[i];
if (disk) {
request_queue_t *q = disk->queue;
@@ -1149,22 +1189,22 @@ static int revalidate_allvol(ctlr_info_t *host)
}
}
- /*
- * Set the partition and block size structures for all volumes
- * on this controller to zero. We will reread all of this data
- */
- memset(host->drv, 0, sizeof(drive_info_struct)
- * CISS_MAX_LUN);
- /*
- * Tell the array controller not to give us any interrupts while
- * we check the new geometry. Then turn interrupts back on when
- * we're done.
- */
- host->access.set_intr_mask(host, CCISS_INTR_OFF);
- cciss_getgeometry(ctlr);
- host->access.set_intr_mask(host, CCISS_INTR_ON);
-
- /* Loop through each real device */
+ /*
+ * Set the partition and block size structures for all volumes
+ * on this controller to zero. We will reread all of this data
+ */
+ memset(host->drv, 0, sizeof(drive_info_struct)
+ * CISS_MAX_LUN);
+ /*
+ * Tell the array controller not to give us any interrupts while
+ * we check the new geometry. Then turn interrupts back on when
+ * we're done.
+ */
+ host->access.set_intr_mask(host, CCISS_INTR_OFF);
+ cciss_getgeometry(ctlr);
+ host->access.set_intr_mask(host, CCISS_INTR_ON);
+
+ /* Loop through each real device */
for (i = 0; i < NWD; i++) {
struct gendisk *disk = host->gendisk[i];
drive_info_struct *drv = &(host->drv[i]);
@@ -1176,8 +1216,8 @@ static int revalidate_allvol(ctlr_info_t *host)
set_capacity(disk, drv->nr_blocks);
add_disk(disk);
}
- host->usage_count--;
- return 0;
+ host->usage_count--;
+ return 0;
}
static inline void complete_buffers(struct bio *bio, int status)
@@ -1191,7 +1231,6 @@ static inline void complete_buffers(struct bio *bio, int status)
bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO);
bio = xbh;
}
-
}
static void cciss_softirq_done(struct request *rq)
@@ -1209,7 +1248,7 @@ static void cciss_softirq_done(struct request *rq)
/* command did not need to be retried */
/* unmap the DMA mapping for all the scatter gather elements */
- for(i=0; i<cmd->Header.SGList; i++) {
+ for (i = 0; i < cmd->Header.SGList; i++) {
temp64.val32.lower = cmd->SG[i].Addr.lower;
temp64.val32.upper = cmd->SG[i].Addr.upper;
pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir);
@@ -1219,11 +1258,12 @@ static void cciss_softirq_done(struct request *rq)
#ifdef CCISS_DEBUG
printk("Done with %p\n", rq);
-#endif /* CCISS_DEBUG */
+#endif /* CCISS_DEBUG */
+ add_disk_randomness(rq->rq_disk);
spin_lock_irqsave(&h->lock, flags);
end_that_request_last(rq, rq->errors);
- cmd_free(h, cmd,1);
+ cmd_free(h, cmd, 1);
spin_unlock_irqrestore(&h->lock, flags);
}
@@ -1234,9 +1274,9 @@ static void cciss_softirq_done(struct request *rq)
* will always be left registered with the kernel since it is also the
* controller node. Any changes to disk 0 will show up on the next
* reboot.
-*/
+ */
static void cciss_update_drive_info(int ctlr, int drv_index)
- {
+{
ctlr_info_t *h = hba[ctlr];
struct gendisk *disk;
ReadCapdata_struct *size_buff = NULL;
@@ -1246,13 +1286,13 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
unsigned long flags = 0;
int ret = 0;
- /* if the disk already exists then deregister it before proceeding*/
- if (h->drv[drv_index].raid_level != -1){
+ /* if the disk already exists then deregister it before proceeding */
+ if (h->drv[drv_index].raid_level != -1) {
spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
h->drv[drv_index].busy_configuring = 1;
spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
ret = deregister_disk(h->gendisk[drv_index],
- &h->drv[drv_index], 0);
+ &h->drv[drv_index], 0);
h->drv[drv_index].busy_configuring = 0;
}
@@ -1260,27 +1300,25 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
if (ret)
return;
-
- /* Get information about the disk and modify the driver sturcture */
- size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
- if (size_buff == NULL)
+ /* Get information about the disk and modify the driver structure */
+ size_buff = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
+ if (size_buff == NULL)
goto mem_msg;
- inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+ inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
if (inq_buff == NULL)
goto mem_msg;
cciss_read_capacity(ctlr, drv_index, size_buff, 1,
- &total_size, &block_size);
+ &total_size, &block_size);
cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size,
- inq_buff, &h->drv[drv_index]);
+ inq_buff, &h->drv[drv_index]);
++h->num_luns;
disk = h->gendisk[drv_index];
set_capacity(disk, h->drv[drv_index].nr_blocks);
-
/* if it's the controller it's already added */
- if (drv_index){
+ if (drv_index) {
disk->queue = blk_init_queue(do_cciss_request, &h->lock);
/* Set up queue information */
@@ -1300,17 +1338,17 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
disk->queue->queuedata = hba[ctlr];
blk_queue_hardsect_size(disk->queue,
- hba[ctlr]->drv[drv_index].block_size);
+ hba[ctlr]->drv[drv_index].block_size);
h->drv[drv_index].queue = disk->queue;
add_disk(disk);
}
-freeret:
+ freeret:
kfree(size_buff);
kfree(inq_buff);
return;
-mem_msg:
+ mem_msg:
printk(KERN_ERR "cciss: out of memory\n");
goto freeret;
}
@@ -1320,13 +1358,13 @@ mem_msg:
* where new drives will be added. If the index to be returned is greater
* than the highest_lun index for the controller then highest_lun is set
* to this new index. If there are no available indexes then -1 is returned.
-*/
+ */
static int cciss_find_free_drive_index(int ctlr)
{
int i;
- for (i=0; i < CISS_MAX_LUN; i++){
- if (hba[ctlr]->drv[i].raid_level == -1){
+ for (i = 0; i < CISS_MAX_LUN; i++) {
+ if (hba[ctlr]->drv[i].raid_level == -1) {
if (i > hba[ctlr]->highest_lun)
hba[ctlr]->highest_lun = i;
return i;
@@ -1336,7 +1374,7 @@ static int cciss_find_free_drive_index(int ctlr)
}
/* This function will add and remove logical drives from the Logical
- * drive array of the controller and maintain persistancy of ordering
+ * drive array of the controller and maintain persistency of ordering
* so that mount points are preserved until the next reboot. This allows
* for the removal of logical drives in the middle of the drive array
* without a re-ordering of those drives.
@@ -1344,7 +1382,7 @@ static int cciss_find_free_drive_index(int ctlr)
* h = The controller to perform the operations on
* del_disk = The disk to remove if specified. If the value given
* is NULL then no disk is removed.
-*/
+ */
static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
{
int ctlr = h->ctlr;
@@ -1361,12 +1399,12 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
/* Set busy_configuring flag for this operation */
spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
- if (h->num_luns >= CISS_MAX_LUN){
+ if (h->num_luns >= CISS_MAX_LUN) {
spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
return -EINVAL;
}
- if (h->busy_configuring){
+ if (h->busy_configuring) {
spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
return -EBUSY;
}
@@ -1376,7 +1414,7 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
* and update the logical drive table. If it is not NULL then
* we will check if the disk is in use or not.
*/
- if (del_disk != NULL){
+ if (del_disk != NULL) {
drv = get_drv(del_disk);
drv->busy_configuring = 1;
spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
@@ -1394,61 +1432,67 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
goto mem_msg;
return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff,
- sizeof(ReportLunData_struct), 0, 0, 0,
- TYPE_CMD);
-
- if (return_code == IO_OK){
- listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
- listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
- listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;
- listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
- } else{ /* reading number of logical volumes failed */
+ sizeof(ReportLunData_struct), 0,
+ 0, 0, TYPE_CMD);
+
+ if (return_code == IO_OK) {
+ listlength |=
+ (0xff & (unsigned int)(ld_buff->LUNListLength[0]))
+ << 24;
+ listlength |=
+ (0xff & (unsigned int)(ld_buff->LUNListLength[1]))
+ << 16;
+ listlength |=
+ (0xff & (unsigned int)(ld_buff->LUNListLength[2]))
+ << 8;
+ listlength |=
+ 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
+ } else { /* reading number of logical volumes failed */
printk(KERN_WARNING "cciss: report logical volume"
- " command failed\n");
+ " command failed\n");
listlength = 0;
goto freeret;
}
num_luns = listlength / 8; /* 8 bytes per entry */
- if (num_luns > CISS_MAX_LUN){
+ if (num_luns > CISS_MAX_LUN) {
num_luns = CISS_MAX_LUN;
printk(KERN_WARNING "cciss: more luns configured"
- " on controller than can be handled by"
- " this driver.\n");
+ " on controller than can be handled by"
+ " this driver.\n");
}
/* Compare controller drive array to drivers drive array.
- * Check for updates in the drive information and any new drives
- * on the controller.
- */
- for (i=0; i < num_luns; i++){
+ * Check for updates in the drive information and any new drives
+ * on the controller.
+ */
+ for (i = 0; i < num_luns; i++) {
int j;
drv_found = 0;
- lunid = (0xff &
- (unsigned int)(ld_buff->LUN[i][3])) << 24;
- lunid |= (0xff &
- (unsigned int)(ld_buff->LUN[i][2])) << 16;
- lunid |= (0xff &
- (unsigned int)(ld_buff->LUN[i][1])) << 8;
- lunid |= 0xff &
- (unsigned int)(ld_buff->LUN[i][0]);
+ lunid = (0xff &
+ (unsigned int)(ld_buff->LUN[i][3])) << 24;
+ lunid |= (0xff &
+ (unsigned int)(ld_buff->LUN[i][2])) << 16;
+ lunid |= (0xff &
+ (unsigned int)(ld_buff->LUN[i][1])) << 8;
+ lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
/* Find if the LUN is already in the drive array
* of the controller. If so then update its info
* if not is use. If it does not exist then find
* the first free index and add it.
- */
- for (j=0; j <= h->highest_lun; j++){
- if (h->drv[j].LunID == lunid){
+ */
+ for (j = 0; j <= h->highest_lun; j++) {
+ if (h->drv[j].LunID == lunid) {
drv_index = j;
drv_found = 1;
}
}
/* check if the drive was found already in the array */
- if (!drv_found){
+ if (!drv_found) {
drv_index = cciss_find_free_drive_index(ctlr);
if (drv_index == -1)
goto freeret;
@@ -1456,18 +1500,18 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
}
h->drv[drv_index].LunID = lunid;
cciss_update_drive_info(ctlr, drv_index);
- } /* end for */
- } /* end else */
+ } /* end for */
+ } /* end else */
-freeret:
+ freeret:
kfree(ld_buff);
h->busy_configuring = 0;
/* We return -1 here to tell the ACU that we have registered/updated
* all of the drives that we can and to keep it from calling us
* additional times.
- */
+ */
return -1;
-mem_msg:
+ mem_msg:
printk(KERN_ERR "cciss: out of memory\n");
goto freeret;
}
@@ -1483,7 +1527,7 @@ mem_msg:
* clear_all = This flag determines whether or not the disk information
* is going to be completely cleared out and the highest_lun
* reset. Sometimes we want to clear out information about
- * the disk in preperation for re-adding it. In this case
+ * the disk in preparation for re-adding it. In this case
* the highest_lun should be left unchanged and the LunID
* should not be cleared.
*/
@@ -1496,19 +1540,17 @@ static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
return -EPERM;
/* make sure logical volume is NOT is use */
- if(clear_all || (h->gendisk[0] == disk)) {
- if (drv->usage_count > 1)
- return -EBUSY;
- }
- else
- if( drv->usage_count > 0 )
- return -EBUSY;
+ if (clear_all || (h->gendisk[0] == disk)) {
+ if (drv->usage_count > 1)
+ return -EBUSY;
+ } else if (drv->usage_count > 0)
+ return -EBUSY;
/* invalidate the devices and deregister the disk. If it is disk
* zero do not deregister it but just zero out it's values. This
* allows us to delete disk zero but keep the controller registered.
- */
- if (h->gendisk[0] != disk){
+ */
+ if (h->gendisk[0] != disk) {
if (disk) {
request_queue_t *q = disk->queue;
if (disk->flags & GENHD_FL_UP)
@@ -1530,91 +1572,90 @@ static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
drv->raid_level = -1; /* This can be used as a flag variable to
* indicate that this element of the drive
* array is free.
- */
-
- if (clear_all){
- /* check to see if it was the last disk */
- if (drv == h->drv + h->highest_lun) {
- /* if so, find the new hightest lun */
- int i, newhighest =-1;
- for(i=0; i<h->highest_lun; i++) {
- /* if the disk has size > 0, it is available */
+ */
+
+ if (clear_all) {
+ /* check to see if it was the last disk */
+ if (drv == h->drv + h->highest_lun) {
+ /* if so, find the new hightest lun */
+ int i, newhighest = -1;
+ for (i = 0; i < h->highest_lun; i++) {
+ /* if the disk has size > 0, it is available */
if (h->drv[i].heads)
- newhighest = i;
+ newhighest = i;
+ }
+ h->highest_lun = newhighest;
}
- h->highest_lun = newhighest;
- }
- drv->LunID = 0;
+ drv->LunID = 0;
}
- return(0);
+ return 0;
}
-static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
- size_t size,
- unsigned int use_unit_num, /* 0: address the controller,
- 1: address logical volume log_unit,
- 2: periph device address is scsi3addr */
- unsigned int log_unit, __u8 page_code, unsigned char *scsi3addr,
- int cmd_type)
+static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num, /* 0: address the controller,
+ 1: address logical volume log_unit,
+ 2: periph device address is scsi3addr */
+ unsigned int log_unit, __u8 page_code,
+ unsigned char *scsi3addr, int cmd_type)
{
- ctlr_info_t *h= hba[ctlr];
+ ctlr_info_t *h = hba[ctlr];
u64bit buff_dma_handle;
int status = IO_OK;
c->cmd_type = CMD_IOCTL_PEND;
c->Header.ReplyQueue = 0;
- if( buff != NULL) {
+ if (buff != NULL) {
c->Header.SGList = 1;
- c->Header.SGTotal= 1;
+ c->Header.SGTotal = 1;
} else {
c->Header.SGList = 0;
- c->Header.SGTotal= 0;
+ c->Header.SGTotal = 0;
}
c->Header.Tag.lower = c->busaddr;
c->Request.Type.Type = cmd_type;
if (cmd_type == TYPE_CMD) {
- switch(cmd) {
- case CISS_INQUIRY:
+ switch (cmd) {
+ case CISS_INQUIRY:
/* If the logical unit number is 0 then, this is going
- to controller so It's a physical command
- mode = 0 target = 0. So we have nothing to write.
- otherwise, if use_unit_num == 1,
- mode = 1(volume set addressing) target = LUNID
- otherwise, if use_unit_num == 2,
- mode = 0(periph dev addr) target = scsi3addr */
+ to controller so It's a physical command
+ mode = 0 target = 0. So we have nothing to write.
+ otherwise, if use_unit_num == 1,
+ mode = 1(volume set addressing) target = LUNID
+ otherwise, if use_unit_num == 2,
+ mode = 0(periph dev addr) target = scsi3addr */
if (use_unit_num == 1) {
- c->Header.LUN.LogDev.VolId=
- h->drv[log_unit].LunID;
- c->Header.LUN.LogDev.Mode = 1;
+ c->Header.LUN.LogDev.VolId =
+ h->drv[log_unit].LunID;
+ c->Header.LUN.LogDev.Mode = 1;
} else if (use_unit_num == 2) {
- memcpy(c->Header.LUN.LunAddrBytes,scsi3addr,8);
+ memcpy(c->Header.LUN.LunAddrBytes, scsi3addr,
+ 8);
c->Header.LUN.LogDev.Mode = 0;
}
/* are we trying to read a vital product page */
- if(page_code != 0) {
+ if (page_code != 0) {
c->Request.CDB[1] = 0x01;
c->Request.CDB[2] = page_code;
}
c->Request.CDBLen = 6;
- c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Attribute = ATTR_SIMPLE;
c->Request.Type.Direction = XFER_READ;
c->Request.Timeout = 0;
- c->Request.CDB[0] = CISS_INQUIRY;
- c->Request.CDB[4] = size & 0xFF;
- break;
+ c->Request.CDB[0] = CISS_INQUIRY;
+ c->Request.CDB[4] = size & 0xFF;
+ break;
case CISS_REPORT_LOG:
case CISS_REPORT_PHYS:
- /* Talking to controller so It's a physical command
+ /* Talking to controller so It's a physical command
mode = 00 target = 0. Nothing to write.
- */
+ */
c->Request.CDBLen = 12;
c->Request.Type.Attribute = ATTR_SIMPLE;
c->Request.Type.Direction = XFER_READ;
c->Request.Timeout = 0;
c->Request.CDB[0] = cmd;
- c->Request.CDB[6] = (size >> 24) & 0xFF; //MSB
+ c->Request.CDB[6] = (size >> 24) & 0xFF; //MSB
c->Request.CDB[7] = (size >> 16) & 0xFF;
c->Request.CDB[8] = (size >> 8) & 0xFF;
c->Request.CDB[9] = size & 0xFF;
@@ -1628,7 +1669,7 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
c->Request.Type.Direction = XFER_READ;
c->Request.Timeout = 0;
c->Request.CDB[0] = cmd;
- break;
+ break;
case CCISS_CACHE_FLUSH:
c->Request.CDBLen = 12;
c->Request.Type.Attribute = ATTR_SIMPLE;
@@ -1636,32 +1677,32 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
c->Request.Timeout = 0;
c->Request.CDB[0] = BMIC_WRITE;
c->Request.CDB[6] = BMIC_CACHE_FLUSH;
- break;
+ break;
default:
printk(KERN_WARNING
- "cciss%d: Unknown Command 0x%c\n", ctlr, cmd);
- return(IO_ERROR);
+ "cciss%d: Unknown Command 0x%c\n", ctlr, cmd);
+ return IO_ERROR;
}
} else if (cmd_type == TYPE_MSG) {
switch (cmd) {
- case 0: /* ABORT message */
+ case 0: /* ABORT message */
c->Request.CDBLen = 12;
c->Request.Type.Attribute = ATTR_SIMPLE;
c->Request.Type.Direction = XFER_WRITE;
c->Request.Timeout = 0;
- c->Request.CDB[0] = cmd; /* abort */
- c->Request.CDB[1] = 0; /* abort a command */
+ c->Request.CDB[0] = cmd; /* abort */
+ c->Request.CDB[1] = 0; /* abort a command */
/* buff contains the tag of the command to abort */
memcpy(&c->Request.CDB[4], buff, 8);
break;
- case 1: /* RESET message */
+ case 1: /* RESET message */
c->Request.CDBLen = 12;
c->Request.Type.Attribute = ATTR_SIMPLE;
c->Request.Type.Direction = XFER_WRITE;
c->Request.Timeout = 0;
memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
- c->Request.CDB[0] = cmd; /* reset */
- c->Request.CDB[1] = 0x04; /* reset a LUN */
+ c->Request.CDB[0] = cmd; /* reset */
+ c->Request.CDB[1] = 0x04; /* reset a LUN */
case 3: /* No-Op message */
c->Request.CDBLen = 1;
c->Request.Type.Attribute = ATTR_SIMPLE;
@@ -1671,168 +1712,164 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
break;
default:
printk(KERN_WARNING
- "cciss%d: unknown message type %d\n",
- ctlr, cmd);
+ "cciss%d: unknown message type %d\n", ctlr, cmd);
return IO_ERROR;
}
} else {
printk(KERN_WARNING
- "cciss%d: unknown command type %d\n", ctlr, cmd_type);
+ "cciss%d: unknown command type %d\n", ctlr, cmd_type);
return IO_ERROR;
}
/* Fill in the scatter gather information */
if (size > 0) {
buff_dma_handle.val = (__u64) pci_map_single(h->pdev,
- buff, size, PCI_DMA_BIDIRECTIONAL);
+ buff, size,
+ PCI_DMA_BIDIRECTIONAL);
c->SG[0].Addr.lower = buff_dma_handle.val32.lower;
c->SG[0].Addr.upper = buff_dma_handle.val32.upper;
c->SG[0].Len = size;
- c->SG[0].Ext = 0; /* we are not chaining */
+ c->SG[0].Ext = 0; /* we are not chaining */
}
return status;
}
-static int sendcmd_withirq(__u8 cmd,
- int ctlr,
- void *buff,
- size_t size,
- unsigned int use_unit_num,
- unsigned int log_unit,
- __u8 page_code,
- int cmd_type)
+
+static int sendcmd_withirq(__u8 cmd,
+ int ctlr,
+ void *buff,
+ size_t size,
+ unsigned int use_unit_num,
+ unsigned int log_unit, __u8 page_code, int cmd_type)
{
ctlr_info_t *h = hba[ctlr];
CommandList_struct *c;
- u64bit buff_dma_handle;
+ u64bit buff_dma_handle;
unsigned long flags;
int return_status;
DECLARE_COMPLETION(wait);
-
- if ((c = cmd_alloc(h , 0)) == NULL)
+
+ if ((c = cmd_alloc(h, 0)) == NULL)
return -ENOMEM;
return_status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num,
- log_unit, page_code, NULL, cmd_type);
+ log_unit, page_code, NULL, cmd_type);
if (return_status != IO_OK) {
cmd_free(h, c, 0);
return return_status;
}
-resend_cmd2:
+ resend_cmd2:
c->waiting = &wait;
-
+
/* Put the request on the tail of the queue and send it */
spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
addQ(&h->reqQ, c);
h->Qdepth++;
start_io(h);
spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-
+
wait_for_completion(&wait);
- if(c->err_info->CommandStatus != 0)
- { /* an error has occurred */
- switch(c->err_info->CommandStatus)
- {
- case CMD_TARGET_STATUS:
- printk(KERN_WARNING "cciss: cmd %p has "
- " completed with errors\n", c);
- if( c->err_info->ScsiStatus)
- {
- printk(KERN_WARNING "cciss: cmd %p "
- "has SCSI Status = %x\n",
- c,
- c->err_info->ScsiStatus);
- }
+ if (c->err_info->CommandStatus != 0) { /* an error has occurred */
+ switch (c->err_info->CommandStatus) {
+ case CMD_TARGET_STATUS:
+ printk(KERN_WARNING "cciss: cmd %p has "
+ " completed with errors\n", c);
+ if (c->err_info->ScsiStatus) {
+ printk(KERN_WARNING "cciss: cmd %p "
+ "has SCSI Status = %x\n",
+ c, c->err_info->ScsiStatus);
+ }
break;
- case CMD_DATA_UNDERRUN:
- case CMD_DATA_OVERRUN:
+ case CMD_DATA_UNDERRUN:
+ case CMD_DATA_OVERRUN:
/* expected for inquire and report lun commands */
break;
- case CMD_INVALID:
- printk(KERN_WARNING "cciss: Cmd %p is "
- "reported invalid\n", c);
- return_status = IO_ERROR;
+ case CMD_INVALID:
+ printk(KERN_WARNING "cciss: Cmd %p is "
+ "reported invalid\n", c);
+ return_status = IO_ERROR;
break;
- case CMD_PROTOCOL_ERR:
- printk(KERN_WARNING "cciss: cmd %p has "
- "protocol error \n", c);
- return_status = IO_ERROR;
- break;
-case CMD_HARDWARE_ERR:
- printk(KERN_WARNING "cciss: cmd %p had "
- " hardware error\n", c);
- return_status = IO_ERROR;
- break;
- case CMD_CONNECTION_LOST:
- printk(KERN_WARNING "cciss: cmd %p had "
- "connection lost\n", c);
- return_status = IO_ERROR;
+ case CMD_PROTOCOL_ERR:
+ printk(KERN_WARNING "cciss: cmd %p has "
+ "protocol error \n", c);
+ return_status = IO_ERROR;
break;
- case CMD_ABORTED:
- printk(KERN_WARNING "cciss: cmd %p was "
- "aborted\n", c);
- return_status = IO_ERROR;
+ case CMD_HARDWARE_ERR:
+ printk(KERN_WARNING "cciss: cmd %p had "
+ " hardware error\n", c);
+ return_status = IO_ERROR;
break;
- case CMD_ABORT_FAILED:
- printk(KERN_WARNING "cciss: cmd %p reports "
- "abort failed\n", c);
- return_status = IO_ERROR;
+ case CMD_CONNECTION_LOST:
+ printk(KERN_WARNING "cciss: cmd %p had "
+ "connection lost\n", c);
+ return_status = IO_ERROR;
break;
- case CMD_UNSOLICITED_ABORT:
- printk(KERN_WARNING
- "cciss%d: unsolicited abort %p\n",
- ctlr, c);
- if (c->retry_count < MAX_CMD_RETRIES) {
- printk(KERN_WARNING
- "cciss%d: retrying %p\n",
- ctlr, c);
- c->retry_count++;
- /* erase the old error information */
- memset(c->err_info, 0,
- sizeof(ErrorInfo_struct));
- return_status = IO_OK;
- INIT_COMPLETION(wait);
- goto resend_cmd2;
- }
- return_status = IO_ERROR;
+ case CMD_ABORTED:
+ printk(KERN_WARNING "cciss: cmd %p was "
+ "aborted\n", c);
+ return_status = IO_ERROR;
+ break;
+ case CMD_ABORT_FAILED:
+ printk(KERN_WARNING "cciss: cmd %p reports "
+ "abort failed\n", c);
+ return_status = IO_ERROR;
break;
- default:
- printk(KERN_WARNING "cciss: cmd %p returned "
- "unknown status %x\n", c,
- c->err_info->CommandStatus);
- return_status = IO_ERROR;
+ case CMD_UNSOLICITED_ABORT:
+ printk(KERN_WARNING
+ "cciss%d: unsolicited abort %p\n", ctlr, c);
+ if (c->retry_count < MAX_CMD_RETRIES) {
+ printk(KERN_WARNING
+ "cciss%d: retrying %p\n", ctlr, c);
+ c->retry_count++;
+ /* erase the old error information */
+ memset(c->err_info, 0,
+ sizeof(ErrorInfo_struct));
+ return_status = IO_OK;
+ INIT_COMPLETION(wait);
+ goto resend_cmd2;
+ }
+ return_status = IO_ERROR;
+ break;
+ default:
+ printk(KERN_WARNING "cciss: cmd %p returned "
+ "unknown status %x\n", c,
+ c->err_info->CommandStatus);
+ return_status = IO_ERROR;
}
- }
+ }
/* unlock the buffers from DMA */
buff_dma_handle.val32.lower = c->SG[0].Addr.lower;
buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
- pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val,
- c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
+ pci_unmap_single(h->pdev, (dma_addr_t) buff_dma_handle.val,
+ c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
cmd_free(h, c, 0);
- return(return_status);
-
+ return return_status;
}
+
static void cciss_geometry_inquiry(int ctlr, int logvol,
- int withirq, unsigned int total_size,
- unsigned int block_size, InquiryData_struct *inq_buff,
- drive_info_struct *drv)
+ int withirq, unsigned int total_size,
+ unsigned int block_size,
+ InquiryData_struct *inq_buff,
+ drive_info_struct *drv)
{
int return_code;
memset(inq_buff, 0, sizeof(InquiryData_struct));
if (withirq)
return_code = sendcmd_withirq(CISS_INQUIRY, ctlr,
- inq_buff, sizeof(*inq_buff), 1, logvol ,0xC1, TYPE_CMD);
+ inq_buff, sizeof(*inq_buff), 1,
+ logvol, 0xC1, TYPE_CMD);
else
return_code = sendcmd(CISS_INQUIRY, ctlr, inq_buff,
- sizeof(*inq_buff), 1, logvol ,0xC1, NULL, TYPE_CMD);
+ sizeof(*inq_buff), 1, logvol, 0xC1, NULL,
+ TYPE_CMD);
if (return_code == IO_OK) {
- if(inq_buff->data_byte[8] == 0xFF) {
+ if (inq_buff->data_byte[8] == 0xFF) {
printk(KERN_WARNING
- "cciss: reading geometry failed, volume "
- "does not support reading geometry\n");
+ "cciss: reading geometry failed, volume "
+ "does not support reading geometry\n");
drv->block_size = block_size;
drv->nr_blocks = total_size;
drv->heads = 255;
- drv->sectors = 32; // Sectors per track
+ drv->sectors = 32; // Sectors per track
drv->cylinders = total_size / 255 / 32;
} else {
unsigned int t;
@@ -1846,37 +1883,42 @@ static void cciss_geometry_inquiry(int ctlr, int logvol,
drv->raid_level = inq_buff->data_byte[8];
t = drv->heads * drv->sectors;
if (t > 1) {
- drv->cylinders = total_size/t;
+ drv->cylinders = total_size / t;
}
}
- } else { /* Get geometry failed */
+ } else { /* Get geometry failed */
printk(KERN_WARNING "cciss: reading geometry failed\n");
}
printk(KERN_INFO " heads= %d, sectors= %d, cylinders= %d\n\n",
- drv->heads, drv->sectors, drv->cylinders);
+ drv->heads, drv->sectors, drv->cylinders);
}
+
static void
cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf,
- int withirq, unsigned int *total_size, unsigned int *block_size)
+ int withirq, unsigned int *total_size,
+ unsigned int *block_size)
{
int return_code;
memset(buf, 0, sizeof(*buf));
if (withirq)
return_code = sendcmd_withirq(CCISS_READ_CAPACITY,
- ctlr, buf, sizeof(*buf), 1, logvol, 0, TYPE_CMD);
+ ctlr, buf, sizeof(*buf), 1,
+ logvol, 0, TYPE_CMD);
else
return_code = sendcmd(CCISS_READ_CAPACITY,
- ctlr, buf, sizeof(*buf), 1, logvol, 0, NULL, TYPE_CMD);
+ ctlr, buf, sizeof(*buf), 1, logvol, 0,
+ NULL, TYPE_CMD);
if (return_code == IO_OK) {
- *total_size = be32_to_cpu(*((__be32 *) &buf->total_size[0]))+1;
- *block_size = be32_to_cpu(*((__be32 *) &buf->block_size[0]));
- } else { /* read capacity command failed */
+ *total_size =
+ be32_to_cpu(*((__be32 *) & buf->total_size[0])) + 1;
+ *block_size = be32_to_cpu(*((__be32 *) & buf->block_size[0]));
+ } else { /* read capacity command failed */
printk(KERN_WARNING "cciss: read capacity failed\n");
*total_size = 0;
*block_size = BLOCK_SIZE;
}
printk(KERN_INFO " blocks= %u block_size= %d\n",
- *total_size, *block_size);
+ *total_size, *block_size);
return;
}
@@ -1885,38 +1927,38 @@ static int cciss_revalidate(struct gendisk *disk)
ctlr_info_t *h = get_host(disk);
drive_info_struct *drv = get_drv(disk);
int logvol;
- int FOUND=0;
+ int FOUND = 0;
unsigned int block_size;
unsigned int total_size;
ReadCapdata_struct *size_buff = NULL;
InquiryData_struct *inq_buff = NULL;
- for(logvol=0; logvol < CISS_MAX_LUN; logvol++)
- {
- if(h->drv[logvol].LunID == drv->LunID) {
- FOUND=1;
+ for (logvol = 0; logvol < CISS_MAX_LUN; logvol++) {
+ if (h->drv[logvol].LunID == drv->LunID) {
+ FOUND = 1;
break;
}
}
- if (!FOUND) return 1;
+ if (!FOUND)
+ return 1;
- size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
- if (size_buff == NULL)
- {
- printk(KERN_WARNING "cciss: out of memory\n");
- return 1;
- }
- inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
- if (inq_buff == NULL)
- {
- printk(KERN_WARNING "cciss: out of memory\n");
+ size_buff = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
+ if (size_buff == NULL) {
+ printk(KERN_WARNING "cciss: out of memory\n");
+ return 1;
+ }
+ inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
+ if (inq_buff == NULL) {
+ printk(KERN_WARNING "cciss: out of memory\n");
kfree(size_buff);
- return 1;
- }
+ return 1;
+ }
- cciss_read_capacity(h->ctlr, logvol, size_buff, 1, &total_size, &block_size);
- cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size, inq_buff, drv);
+ cciss_read_capacity(h->ctlr, logvol, size_buff, 1, &total_size,
+ &block_size);
+ cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size,
+ inq_buff, drv);
blk_queue_hardsect_size(drv->queue, drv->block_size);
set_capacity(disk, drv->nr_blocks);
@@ -1943,7 +1985,7 @@ static unsigned long pollcomplete(int ctlr)
if (done == FIFO_EMPTY)
schedule_timeout_uninterruptible(1);
else
- return (done);
+ return done;
}
/* Invalid address to tell caller we ran out of time */
return 1;
@@ -1952,28 +1994,28 @@ static unsigned long pollcomplete(int ctlr)
static int add_sendcmd_reject(__u8 cmd, int ctlr, unsigned long complete)
{
/* We get in here if sendcmd() is polling for completions
- and gets some command back that it wasn't expecting --
- something other than that which it just sent down.
- Ordinarily, that shouldn't happen, but it can happen when
+ and gets some command back that it wasn't expecting --
+ something other than that which it just sent down.
+ Ordinarily, that shouldn't happen, but it can happen when
the scsi tape stuff gets into error handling mode, and
- starts using sendcmd() to try to abort commands and
+ starts using sendcmd() to try to abort commands and
reset tape drives. In that case, sendcmd may pick up
completions of commands that were sent to logical drives
- through the block i/o system, or cciss ioctls completing, etc.
+ through the block i/o system, or cciss ioctls completing, etc.
In that case, we need to save those completions for later
processing by the interrupt handler.
- */
+ */
#ifdef CONFIG_CISS_SCSI_TAPE
- struct sendcmd_reject_list *srl = &hba[ctlr]->scsi_rejects;
+ struct sendcmd_reject_list *srl = &hba[ctlr]->scsi_rejects;
/* If it's not the scsi tape stuff doing error handling, (abort */
/* or reset) then we don't expect anything weird. */
if (cmd != CCISS_RESET_MSG && cmd != CCISS_ABORT_MSG) {
#endif
- printk( KERN_WARNING "cciss cciss%d: SendCmd "
- "Invalid command list address returned! (%lx)\n",
- ctlr, complete);
+ printk(KERN_WARNING "cciss cciss%d: SendCmd "
+ "Invalid command list address returned! (%lx)\n",
+ ctlr, complete);
/* not much we can do. */
#ifdef CONFIG_CISS_SCSI_TAPE
return 1;
@@ -1984,7 +2026,7 @@ static int add_sendcmd_reject(__u8 cmd, int ctlr, unsigned long complete)
if (srl->ncompletions >= (NR_CMDS + 2)) {
/* Uh oh. No room to save it for later... */
printk(KERN_WARNING "cciss%d: Sendcmd: Invalid command addr, "
- "reject list overflow, command lost!\n", ctlr);
+ "reject list overflow, command lost!\n", ctlr);
return 1;
}
/* Save it for later */
@@ -1995,340 +2037,327 @@ static int add_sendcmd_reject(__u8 cmd, int ctlr, unsigned long complete)
}
/*
- * Send a command to the controller, and wait for it to complete.
- * Only used at init time.
+ * Send a command to the controller, and wait for it to complete.
+ * Only used at init time.
*/
-static int sendcmd(
- __u8 cmd,
- int ctlr,
- void *buff,
- size_t size,
- unsigned int use_unit_num, /* 0: address the controller,
- 1: address logical volume log_unit,
- 2: periph device address is scsi3addr */
- unsigned int log_unit,
- __u8 page_code,
- unsigned char *scsi3addr,
- int cmd_type)
+static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num, /* 0: address the controller,
+ 1: address logical volume log_unit,
+ 2: periph device address is scsi3addr */
+ unsigned int log_unit,
+ __u8 page_code, unsigned char *scsi3addr, int cmd_type)
{
CommandList_struct *c;
int i;
unsigned long complete;
- ctlr_info_t *info_p= hba[ctlr];
+ ctlr_info_t *info_p = hba[ctlr];
u64bit buff_dma_handle;
int status, done = 0;
if ((c = cmd_alloc(info_p, 1)) == NULL) {
printk(KERN_WARNING "cciss: unable to get memory");
- return(IO_ERROR);
+ return IO_ERROR;
}
status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num,
- log_unit, page_code, scsi3addr, cmd_type);
+ log_unit, page_code, scsi3addr, cmd_type);
if (status != IO_OK) {
cmd_free(info_p, c, 1);
return status;
}
-resend_cmd1:
+ resend_cmd1:
/*
- * Disable interrupt
- */
+ * Disable interrupt
+ */
#ifdef CCISS_DEBUG
printk(KERN_DEBUG "cciss: turning intr off\n");
-#endif /* CCISS_DEBUG */
- info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF);
-
+#endif /* CCISS_DEBUG */
+ info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF);
+
/* Make sure there is room in the command FIFO */
- /* Actually it should be completely empty at this time */
+ /* Actually it should be completely empty at this time */
/* unless we are in here doing error handling for the scsi */
/* tape side of the driver. */
- for (i = 200000; i > 0; i--)
- {
+ for (i = 200000; i > 0; i--) {
/* if fifo isn't full go */
- if (!(info_p->access.fifo_full(info_p)))
- {
-
- break;
- }
- udelay(10);
- printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full,"
- " waiting!\n", ctlr);
- }
- /*
- * Send the cmd
- */
- info_p->access.submit_command(info_p, c);
+ if (!(info_p->access.fifo_full(info_p))) {
+
+ break;
+ }
+ udelay(10);
+ printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full,"
+ " waiting!\n", ctlr);
+ }
+ /*
+ * Send the cmd
+ */
+ info_p->access.submit_command(info_p, c);
done = 0;
do {
complete = pollcomplete(ctlr);
#ifdef CCISS_DEBUG
printk(KERN_DEBUG "cciss: command completed\n");
-#endif /* CCISS_DEBUG */
+#endif /* CCISS_DEBUG */
if (complete == 1) {
- printk( KERN_WARNING
- "cciss cciss%d: SendCmd Timeout out, "
- "No command list address returned!\n",
- ctlr);
+ printk(KERN_WARNING
+ "cciss cciss%d: SendCmd Timeout out, "
+ "No command list address returned!\n", ctlr);
status = IO_ERROR;
done = 1;
break;
}
/* This will need to change for direct lookup completions */
- if ( (complete & CISS_ERROR_BIT)
- && (complete & ~CISS_ERROR_BIT) == c->busaddr)
- {
- /* if data overrun or underun on Report command
- ignore it
- */
+ if ((complete & CISS_ERROR_BIT)
+ && (complete & ~CISS_ERROR_BIT) == c->busaddr) {
+ /* if data overrun or underun on Report command
+ ignore it
+ */
if (((c->Request.CDB[0] == CISS_REPORT_LOG) ||
(c->Request.CDB[0] == CISS_REPORT_PHYS) ||
(c->Request.CDB[0] == CISS_INQUIRY)) &&
- ((c->err_info->CommandStatus ==
- CMD_DATA_OVERRUN) ||
- (c->err_info->CommandStatus ==
- CMD_DATA_UNDERRUN)
- ))
- {
+ ((c->err_info->CommandStatus ==
+ CMD_DATA_OVERRUN) ||
+ (c->err_info->CommandStatus == CMD_DATA_UNDERRUN)
+ )) {
complete = c->busaddr;
} else {
if (c->err_info->CommandStatus ==
- CMD_UNSOLICITED_ABORT) {
+ CMD_UNSOLICITED_ABORT) {
printk(KERN_WARNING "cciss%d: "
- "unsolicited abort %p\n",
- ctlr, c);
+ "unsolicited abort %p\n",
+ ctlr, c);
if (c->retry_count < MAX_CMD_RETRIES) {
printk(KERN_WARNING
- "cciss%d: retrying %p\n",
- ctlr, c);
+ "cciss%d: retrying %p\n",
+ ctlr, c);
c->retry_count++;
/* erase the old error */
/* information */
memset(c->err_info, 0,
- sizeof(ErrorInfo_struct));
+ sizeof
+ (ErrorInfo_struct));
goto resend_cmd1;
} else {
printk(KERN_WARNING
- "cciss%d: retried %p too "
- "many times\n", ctlr, c);
+ "cciss%d: retried %p too "
+ "many times\n", ctlr, c);
status = IO_ERROR;
goto cleanup1;
}
- } else if (c->err_info->CommandStatus == CMD_UNABORTABLE) {
- printk(KERN_WARNING "cciss%d: command could not be aborted.\n", ctlr);
+ } else if (c->err_info->CommandStatus ==
+ CMD_UNABORTABLE) {
+ printk(KERN_WARNING
+ "cciss%d: command could not be aborted.\n",
+ ctlr);
status = IO_ERROR;
goto cleanup1;
}
printk(KERN_WARNING "ciss ciss%d: sendcmd"
- " Error %x \n", ctlr,
- c->err_info->CommandStatus);
+ " Error %x \n", ctlr,
+ c->err_info->CommandStatus);
printk(KERN_WARNING "ciss ciss%d: sendcmd"
- " offensive info\n"
- " size %x\n num %x value %x\n", ctlr,
- c->err_info->MoreErrInfo.Invalid_Cmd.offense_size,
- c->err_info->MoreErrInfo.Invalid_Cmd.offense_num,
- c->err_info->MoreErrInfo.Invalid_Cmd.offense_value);
+ " offensive info\n"
+ " size %x\n num %x value %x\n",
+ ctlr,
+ c->err_info->MoreErrInfo.Invalid_Cmd.
+ offense_size,
+ c->err_info->MoreErrInfo.Invalid_Cmd.
+ offense_num,
+ c->err_info->MoreErrInfo.Invalid_Cmd.
+ offense_value);
status = IO_ERROR;
goto cleanup1;
}
}
/* This will need changing for direct lookup completions */
- if (complete != c->busaddr) {
+ if (complete != c->busaddr) {
if (add_sendcmd_reject(cmd, ctlr, complete) != 0) {
- BUG(); /* we are pretty much hosed if we get here. */
+ BUG(); /* we are pretty much hosed if we get here. */
}
continue;
- } else
+ } else
done = 1;
- } while (!done);
-
-cleanup1:
+ } while (!done);
+
+ cleanup1:
/* unlock the data buffer from DMA */
buff_dma_handle.val32.lower = c->SG[0].Addr.lower;
buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
- c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
+ c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
#ifdef CONFIG_CISS_SCSI_TAPE
/* if we saved some commands for later, process them now. */
if (info_p->scsi_rejects.ncompletions > 0)
do_cciss_intr(0, info_p, NULL);
#endif
cmd_free(info_p, c, 1);
- return (status);
-}
+ return status;
+}
+
/*
* Map (physical) PCI mem into (virtual) kernel space
*/
static void __iomem *remap_pci_mem(ulong base, ulong size)
{
- ulong page_base = ((ulong) base) & PAGE_MASK;
- ulong page_offs = ((ulong) base) - page_base;
- void __iomem *page_remapped = ioremap(page_base, page_offs+size);
+ ulong page_base = ((ulong) base) & PAGE_MASK;
+ ulong page_offs = ((ulong) base) - page_base;
+ void __iomem *page_remapped = ioremap(page_base, page_offs + size);
- return page_remapped ? (page_remapped + page_offs) : NULL;
+ return page_remapped ? (page_remapped + page_offs) : NULL;
}
-/*
- * Takes jobs of the Q and sends them to the hardware, then puts it on
- * the Q to wait for completion.
- */
-static void start_io( ctlr_info_t *h)
+/*
+ * Takes jobs of the Q and sends them to the hardware, then puts it on
+ * the Q to wait for completion.
+ */
+static void start_io(ctlr_info_t *h)
{
CommandList_struct *c;
-
- while(( c = h->reqQ) != NULL )
- {
+
+ while ((c = h->reqQ) != NULL) {
/* can't do anything if fifo is full */
if ((h->access.fifo_full(h))) {
printk(KERN_WARNING "cciss: fifo full\n");
break;
}
- /* Get the first entry from the Request Q */
+ /* Get the first entry from the Request Q */
removeQ(&(h->reqQ), c);
h->Qdepth--;
-
- /* Tell the controller execute command */
+
+ /* Tell the controller execute command */
h->access.submit_command(h, c);
-
- /* Put job onto the completed Q */
- addQ (&(h->cmpQ), c);
+
+ /* Put job onto the completed Q */
+ addQ(&(h->cmpQ), c);
}
}
+
/* Assumes that CCISS_LOCK(h->ctlr) is held. */
/* Zeros out the error record and then resends the command back */
/* to the controller */
-static inline void resend_cciss_cmd( ctlr_info_t *h, CommandList_struct *c)
+static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c)
{
/* erase the old error information */
memset(c->err_info, 0, sizeof(ErrorInfo_struct));
/* add it to software queue and then send it to the controller */
- addQ(&(h->reqQ),c);
+ addQ(&(h->reqQ), c);
h->Qdepth++;
- if(h->Qdepth > h->maxQsinceinit)
+ if (h->Qdepth > h->maxQsinceinit)
h->maxQsinceinit = h->Qdepth;
start_io(h);
}
-/* checks the status of the job and calls complete buffers to mark all
+/* checks the status of the job and calls complete buffers to mark all
* buffers for the completed job. Note that this function does not need
* to hold the hba/queue lock.
- */
-static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd,
- int timeout)
+ */
+static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
+ int timeout)
{
int status = 1;
int retry_cmd = 0;
-
+
if (timeout)
- status = 0;
+ status = 0;
- if(cmd->err_info->CommandStatus != 0)
- { /* an error has occurred */
- switch(cmd->err_info->CommandStatus)
- {
+ if (cmd->err_info->CommandStatus != 0) { /* an error has occurred */
+ switch (cmd->err_info->CommandStatus) {
unsigned char sense_key;
- case CMD_TARGET_STATUS:
- status = 0;
-
- if( cmd->err_info->ScsiStatus == 0x02)
- {
- printk(KERN_WARNING "cciss: cmd %p "
- "has CHECK CONDITION "
- " byte 2 = 0x%x\n", cmd,
- cmd->err_info->SenseInfo[2]
- );
- /* check the sense key */
- sense_key = 0xf &
- cmd->err_info->SenseInfo[2];
- /* no status or recovered error */
- if((sense_key == 0x0) ||
- (sense_key == 0x1))
- {
- status = 1;
- }
- } else
- {
- printk(KERN_WARNING "cciss: cmd %p "
- "has SCSI Status 0x%x\n",
- cmd, cmd->err_info->ScsiStatus);
+ case CMD_TARGET_STATUS:
+ status = 0;
+
+ if (cmd->err_info->ScsiStatus == 0x02) {
+ printk(KERN_WARNING "cciss: cmd %p "
+ "has CHECK CONDITION "
+ " byte 2 = 0x%x\n", cmd,
+ cmd->err_info->SenseInfo[2]
+ );
+ /* check the sense key */
+ sense_key = 0xf & cmd->err_info->SenseInfo[2];
+ /* no status or recovered error */
+ if ((sense_key == 0x0) || (sense_key == 0x1)) {
+ status = 1;
}
+ } else {
+ printk(KERN_WARNING "cciss: cmd %p "
+ "has SCSI Status 0x%x\n",
+ cmd, cmd->err_info->ScsiStatus);
+ }
break;
- case CMD_DATA_UNDERRUN:
- printk(KERN_WARNING "cciss: cmd %p has"
- " completed with data underrun "
- "reported\n", cmd);
+ case CMD_DATA_UNDERRUN:
+ printk(KERN_WARNING "cciss: cmd %p has"
+ " completed with data underrun "
+ "reported\n", cmd);
break;
- case CMD_DATA_OVERRUN:
- printk(KERN_WARNING "cciss: cmd %p has"
- " completed with data overrun "
- "reported\n", cmd);
+ case CMD_DATA_OVERRUN:
+ printk(KERN_WARNING "cciss: cmd %p has"
+ " completed with data overrun "
+ "reported\n", cmd);
break;
- case CMD_INVALID:
- printk(KERN_WARNING "cciss: cmd %p is "
- "reported invalid\n", cmd);
- status = 0;
+ case CMD_INVALID:
+ printk(KERN_WARNING "cciss: cmd %p is "
+ "reported invalid\n", cmd);
+ status = 0;
break;
- case CMD_PROTOCOL_ERR:
- printk(KERN_WARNING "cciss: cmd %p has "
- "protocol error \n", cmd);
- status = 0;
- break;
- case CMD_HARDWARE_ERR:
- printk(KERN_WARNING "cciss: cmd %p had "
- " hardware error\n", cmd);
- status = 0;
- break;
- case CMD_CONNECTION_LOST:
- printk(KERN_WARNING "cciss: cmd %p had "
- "connection lost\n", cmd);
- status=0;
+ case CMD_PROTOCOL_ERR:
+ printk(KERN_WARNING "cciss: cmd %p has "
+ "protocol error \n", cmd);
+ status = 0;
break;
- case CMD_ABORTED:
- printk(KERN_WARNING "cciss: cmd %p was "
- "aborted\n", cmd);
- status=0;
+ case CMD_HARDWARE_ERR:
+ printk(KERN_WARNING "cciss: cmd %p had "
+ " hardware error\n", cmd);
+ status = 0;
break;
- case CMD_ABORT_FAILED:
- printk(KERN_WARNING "cciss: cmd %p reports "
- "abort failed\n", cmd);
- status=0;
+ case CMD_CONNECTION_LOST:
+ printk(KERN_WARNING "cciss: cmd %p had "
+ "connection lost\n", cmd);
+ status = 0;
break;
- case CMD_UNSOLICITED_ABORT:
- printk(KERN_WARNING "cciss%d: unsolicited "
- "abort %p\n", h->ctlr, cmd);
- if (cmd->retry_count < MAX_CMD_RETRIES) {
- retry_cmd=1;
- printk(KERN_WARNING
- "cciss%d: retrying %p\n",
- h->ctlr, cmd);
- cmd->retry_count++;
- } else
- printk(KERN_WARNING
- "cciss%d: %p retried too "
- "many times\n", h->ctlr, cmd);
- status=0;
+ case CMD_ABORTED:
+ printk(KERN_WARNING "cciss: cmd %p was "
+ "aborted\n", cmd);
+ status = 0;
+ break;
+ case CMD_ABORT_FAILED:
+ printk(KERN_WARNING "cciss: cmd %p reports "
+ "abort failed\n", cmd);
+ status = 0;
+ break;
+ case CMD_UNSOLICITED_ABORT:
+ printk(KERN_WARNING "cciss%d: unsolicited "
+ "abort %p\n", h->ctlr, cmd);
+ if (cmd->retry_count < MAX_CMD_RETRIES) {
+ retry_cmd = 1;
+ printk(KERN_WARNING
+ "cciss%d: retrying %p\n", h->ctlr, cmd);
+ cmd->retry_count++;
+ } else
+ printk(KERN_WARNING
+ "cciss%d: %p retried too "
+ "many times\n", h->ctlr, cmd);
+ status = 0;
break;
- case CMD_TIMEOUT:
- printk(KERN_WARNING "cciss: cmd %p timedout\n",
- cmd);
- status=0;
+ case CMD_TIMEOUT:
+ printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd);
+ status = 0;
break;
- default:
- printk(KERN_WARNING "cciss: cmd %p returned "
- "unknown status %x\n", cmd,
- cmd->err_info->CommandStatus);
- status=0;
+ default:
+ printk(KERN_WARNING "cciss: cmd %p returned "
+ "unknown status %x\n", cmd,
+ cmd->err_info->CommandStatus);
+ status = 0;
}
}
/* We need to return this command */
- if(retry_cmd) {
- resend_cciss_cmd(h,cmd);
+ if (retry_cmd) {
+ resend_cciss_cmd(h, cmd);
return;
- }
+ }
cmd->rq->completion_data = cmd;
cmd->rq->errors = status;
@@ -2336,12 +2365,12 @@ static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd,
blk_complete_request(cmd->rq);
}
-/*
- * Get a request and submit it to the controller.
+/*
+ * Get a request and submit it to the controller.
*/
static void do_cciss_request(request_queue_t *q)
{
- ctlr_info_t *h= q->queuedata;
+ ctlr_info_t *h = q->queuedata;
CommandList_struct *c;
int start_blk, seg;
struct request *creq;
@@ -2352,18 +2381,18 @@ static void do_cciss_request(request_queue_t *q)
/* We call start_io here in case there is a command waiting on the
* queue that has not been sent.
- */
+ */
if (blk_queue_plugged(q))
goto startio;
-queue:
+ queue:
creq = elv_next_request(q);
if (!creq)
goto startio;
BUG_ON(creq->nr_phys_segments > MAXSGENTRIES);
- if (( c = cmd_alloc(h, 1)) == NULL)
+ if ((c = cmd_alloc(h, 1)) == NULL)
goto full;
blkdev_dequeue_request(creq);
@@ -2372,81 +2401,82 @@ queue:
c->cmd_type = CMD_RWREQ;
c->rq = creq;
-
- /* fill in the request */
+
+ /* fill in the request */
drv = creq->rq_disk->private_data;
- c->Header.ReplyQueue = 0; // unused in simple mode
+ c->Header.ReplyQueue = 0; // unused in simple mode
/* got command from pool, so use the command block index instead */
/* for direct lookups. */
/* The first 2 bits are reserved for controller error reporting. */
c->Header.Tag.lower = (c->cmdindex << 3);
- c->Header.Tag.lower |= 0x04; /* flag for direct lookup. */
- c->Header.LUN.LogDev.VolId= drv->LunID;
+ c->Header.Tag.lower |= 0x04; /* flag for direct lookup. */
+ c->Header.LUN.LogDev.VolId = drv->LunID;
c->Header.LUN.LogDev.Mode = 1;
- c->Request.CDBLen = 10; // 12 byte commands not in FW yet;
- c->Request.Type.Type = TYPE_CMD; // It is a command.
- c->Request.Type.Attribute = ATTR_SIMPLE;
- c->Request.Type.Direction =
- (rq_data_dir(creq) == READ) ? XFER_READ: XFER_WRITE;
- c->Request.Timeout = 0; // Don't time out
- c->Request.CDB[0] = (rq_data_dir(creq) == READ) ? CCISS_READ : CCISS_WRITE;
+ c->Request.CDBLen = 10; // 12 byte commands not in FW yet;
+ c->Request.Type.Type = TYPE_CMD; // It is a command.
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Direction =
+ (rq_data_dir(creq) == READ) ? XFER_READ : XFER_WRITE;
+ c->Request.Timeout = 0; // Don't time out
+ c->Request.CDB[0] =
+ (rq_data_dir(creq) == READ) ? CCISS_READ : CCISS_WRITE;
start_blk = creq->sector;
#ifdef CCISS_DEBUG
- printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n",(int) creq->sector,
- (int) creq->nr_sectors);
-#endif /* CCISS_DEBUG */
+ printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n", (int)creq->sector,
+ (int)creq->nr_sectors);
+#endif /* CCISS_DEBUG */
seg = blk_rq_map_sg(q, creq, tmp_sg);
- /* get the DMA records for the setup */
+ /* get the DMA records for the setup */
if (c->Request.Type.Direction == XFER_READ)
dir = PCI_DMA_FROMDEVICE;
else
dir = PCI_DMA_TODEVICE;
- for (i=0; i<seg; i++)
- {
+ for (i = 0; i < seg; i++) {
c->SG[i].Len = tmp_sg[i].length;
temp64.val = (__u64) pci_map_page(h->pdev, tmp_sg[i].page,
- tmp_sg[i].offset, tmp_sg[i].length,
- dir);
+ tmp_sg[i].offset,
+ tmp_sg[i].length, dir);
c->SG[i].Addr.lower = temp64.val32.lower;
- c->SG[i].Addr.upper = temp64.val32.upper;
- c->SG[i].Ext = 0; // we are not chaining
+ c->SG[i].Addr.upper = temp64.val32.upper;
+ c->SG[i].Ext = 0; // we are not chaining
}
- /* track how many SG entries we are using */
- if( seg > h->maxSG)
- h->maxSG = seg;
+ /* track how many SG entries we are using */
+ if (seg > h->maxSG)
+ h->maxSG = seg;
#ifdef CCISS_DEBUG
- printk(KERN_DEBUG "cciss: Submitting %d sectors in %d segments\n", creq->nr_sectors, seg);
-#endif /* CCISS_DEBUG */
+ printk(KERN_DEBUG "cciss: Submitting %d sectors in %d segments\n",
+ creq->nr_sectors, seg);
+#endif /* CCISS_DEBUG */
c->Header.SGList = c->Header.SGTotal = seg;
- c->Request.CDB[1]= 0;
- c->Request.CDB[2]= (start_blk >> 24) & 0xff; //MSB
- c->Request.CDB[3]= (start_blk >> 16) & 0xff;
- c->Request.CDB[4]= (start_blk >> 8) & 0xff;
- c->Request.CDB[5]= start_blk & 0xff;
- c->Request.CDB[6]= 0; // (sect >> 24) & 0xff; MSB
- c->Request.CDB[7]= (creq->nr_sectors >> 8) & 0xff;
- c->Request.CDB[8]= creq->nr_sectors & 0xff;
+ c->Request.CDB[1] = 0;
+ c->Request.CDB[2] = (start_blk >> 24) & 0xff; //MSB
+ c->Request.CDB[3] = (start_blk >> 16) & 0xff;
+ c->Request.CDB[4] = (start_blk >> 8) & 0xff;
+ c->Request.CDB[5] = start_blk & 0xff;
+ c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB
+ c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff;
+ c->Request.CDB[8] = creq->nr_sectors & 0xff;
c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
spin_lock_irq(q->queue_lock);
- addQ(&(h->reqQ),c);
+ addQ(&(h->reqQ), c);
h->Qdepth++;
- if(h->Qdepth > h->maxQsinceinit)
- h->maxQsinceinit = h->Qdepth;
+ if (h->Qdepth > h->maxQsinceinit)
+ h->maxQsinceinit = h->Qdepth;
goto queue;
-full:
+ full:
blk_stop_queue(q);
-startio:
+ startio:
/* We will already have the driver lock here so not need
* to lock it.
- */
+ */
start_io(h);
}
@@ -2473,7 +2503,7 @@ static inline unsigned long get_next_completion(ctlr_info_t *h)
static inline int interrupt_pending(ctlr_info_t *h)
{
#ifdef CONFIG_CISS_SCSI_TAPE
- return ( h->access.intr_pending(h)
+ return (h->access.intr_pending(h)
|| (h->scsi_rejects.ncompletions > 0));
#else
return h->access.intr_pending(h);
@@ -2483,11 +2513,11 @@ static inline int interrupt_pending(ctlr_info_t *h)
static inline long interrupt_not_for_us(ctlr_info_t *h)
{
#ifdef CONFIG_CISS_SCSI_TAPE
- return (((h->access.intr_pending(h) == 0) ||
- (h->interrupts_enabled == 0))
- && (h->scsi_rejects.ncompletions == 0));
+ return (((h->access.intr_pending(h) == 0) ||
+ (h->interrupts_enabled == 0))
+ && (h->scsi_rejects.ncompletions == 0));
#else
- return (((h->access.intr_pending(h) == 0) ||
+ return (((h->access.intr_pending(h) == 0) ||
(h->interrupts_enabled == 0)));
#endif
}
@@ -2509,12 +2539,14 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
*/
spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
while (interrupt_pending(h)) {
- while((a = get_next_completion(h)) != FIFO_EMPTY) {
+ while ((a = get_next_completion(h)) != FIFO_EMPTY) {
a1 = a;
if ((a & 0x04)) {
a2 = (a >> 3);
if (a2 >= NR_CMDS) {
- printk(KERN_WARNING "cciss: controller cciss%d failed, stopping.\n", h->ctlr);
+ printk(KERN_WARNING
+ "cciss: controller cciss%d failed, stopping.\n",
+ h->ctlr);
fail_all_cmds(h->ctlr);
return IRQ_HANDLED;
}
@@ -2523,22 +2555,24 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
a = c->busaddr;
} else {
- a &= ~3;
+ a &= ~3;
if ((c = h->cmpQ) == NULL) {
- printk(KERN_WARNING "cciss: Completion of %08x ignored\n", a1);
- continue;
- }
- while(c->busaddr != a) {
- c = c->next;
- if (c == h->cmpQ)
- break;
- }
+ printk(KERN_WARNING
+ "cciss: Completion of %08x ignored\n",
+ a1);
+ continue;
+ }
+ while (c->busaddr != a) {
+ c = c->next;
+ if (c == h->cmpQ)
+ break;
+ }
}
/*
* If we've found the command, take it off the
* completion Q and free it
*/
- if (c->busaddr == a) {
+ if (c->busaddr == a) {
removeQ(&h->cmpQ, c);
if (c->cmd_type == CMD_RWREQ) {
complete_command(h, c, 0);
@@ -2554,130 +2588,118 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
}
}
- /* check to see if we have maxed out the number of commands that can
- * be placed on the queue. If so then exit. We do this check here
- * in case the interrupt we serviced was from an ioctl and did not
- * free any new commands.
+ /* check to see if we have maxed out the number of commands that can
+ * be placed on the queue. If so then exit. We do this check here
+ * in case the interrupt we serviced was from an ioctl and did not
+ * free any new commands.
+ */
+ if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS)
+ goto cleanup;
+
+ /* We have room on the queue for more commands. Now we need to queue
+ * them up. We will also keep track of the next queue to run so
+ * that every queue gets a chance to be started first.
*/
- if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS)
- goto cleanup;
-
- /* We have room on the queue for more commands. Now we need to queue
- * them up. We will also keep track of the next queue to run so
- * that every queue gets a chance to be started first.
- */
- for (j=0; j < h->highest_lun + 1; j++){
+ for (j = 0; j < h->highest_lun + 1; j++) {
int curr_queue = (start_queue + j) % (h->highest_lun + 1);
- /* make sure the disk has been added and the drive is real
- * because this can be called from the middle of init_one.
- */
- if(!(h->drv[curr_queue].queue) ||
- !(h->drv[curr_queue].heads))
- continue;
- blk_start_queue(h->gendisk[curr_queue]->queue);
-
- /* check to see if we have maxed out the number of commands
- * that can be placed on the queue.
- */
- if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS)
- {
- if (curr_queue == start_queue){
- h->next_to_run = (start_queue + 1) % (h->highest_lun + 1);
- goto cleanup;
- } else {
- h->next_to_run = curr_queue;
- goto cleanup;
- }
- } else {
+ /* make sure the disk has been added and the drive is real
+ * because this can be called from the middle of init_one.
+ */
+ if (!(h->drv[curr_queue].queue) || !(h->drv[curr_queue].heads))
+ continue;
+ blk_start_queue(h->gendisk[curr_queue]->queue);
+
+ /* check to see if we have maxed out the number of commands
+ * that can be placed on the queue.
+ */
+ if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS) {
+ if (curr_queue == start_queue) {
+ h->next_to_run =
+ (start_queue + 1) % (h->highest_lun + 1);
+ goto cleanup;
+ } else {
+ h->next_to_run = curr_queue;
+ goto cleanup;
+ }
+ } else {
curr_queue = (curr_queue + 1) % (h->highest_lun + 1);
- }
- }
+ }
+ }
-cleanup:
+ cleanup:
spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
return IRQ_HANDLED;
}
-/*
- * We cannot read the structure directly, for portablity we must use
+
+/*
+ * We cannot read the structure directly, for portability we must use
* the io functions.
- * This is for debug only.
+ * This is for debug only.
*/
#ifdef CCISS_DEBUG
-static void print_cfg_table( CfgTable_struct *tb)
+static void print_cfg_table(CfgTable_struct *tb)
{
int i;
char temp_name[17];
printk("Controller Configuration information\n");
printk("------------------------------------\n");
- for(i=0;i<4;i++)
+ for (i = 0; i < 4; i++)
temp_name[i] = readb(&(tb->Signature[i]));
- temp_name[4]='\0';
- printk(" Signature = %s\n", temp_name);
+ temp_name[4] = '\0';
+ printk(" Signature = %s\n", temp_name);
printk(" Spec Number = %d\n", readl(&(tb->SpecValence)));
- printk(" Transport methods supported = 0x%x\n",
- readl(&(tb-> TransportSupport)));
- printk(" Transport methods active = 0x%x\n",
- readl(&(tb->TransportActive)));
- printk(" Requested transport Method = 0x%x\n",
- readl(&(tb->HostWrite.TransportRequest)));
- printk(" Coalese Interrupt Delay = 0x%x\n",
- readl(&(tb->HostWrite.CoalIntDelay)));
- printk(" Coalese Interrupt Count = 0x%x\n",
- readl(&(tb->HostWrite.CoalIntCount)));
- printk(" Max outstanding commands = 0x%d\n",
- readl(&(tb->CmdsOutMax)));
- printk(" Bus Types = 0x%x\n", readl(&(tb-> BusTypes)));
- for(i=0;i<16;i++)
+ printk(" Transport methods supported = 0x%x\n",
+ readl(&(tb->TransportSupport)));
+ printk(" Transport methods active = 0x%x\n",
+ readl(&(tb->TransportActive)));
+ printk(" Requested transport Method = 0x%x\n",
+ readl(&(tb->HostWrite.TransportRequest)));
+ printk(" Coalesce Interrupt Delay = 0x%x\n",
+ readl(&(tb->HostWrite.CoalIntDelay)));
+ printk(" Coalesce Interrupt Count = 0x%x\n",
+ readl(&(tb->HostWrite.CoalIntCount)));
+ printk(" Max outstanding commands = 0x%d\n",
+ readl(&(tb->CmdsOutMax)));
+ printk(" Bus Types = 0x%x\n", readl(&(tb->BusTypes)));
+ for (i = 0; i < 16; i++)
temp_name[i] = readb(&(tb->ServerName[i]));
temp_name[16] = '\0';
printk(" Server Name = %s\n", temp_name);
- printk(" Heartbeat Counter = 0x%x\n\n\n",
- readl(&(tb->HeartBeat)));
-}
-#endif /* CCISS_DEBUG */
-
-static void release_io_mem(ctlr_info_t *c)
-{
- /* if IO mem was not protected do nothing */
- if( c->io_mem_addr == 0)
- return;
- release_region(c->io_mem_addr, c->io_mem_length);
- c->io_mem_addr = 0;
- c->io_mem_length = 0;
+ printk(" Heartbeat Counter = 0x%x\n\n\n", readl(&(tb->HeartBeat)));
}
+#endif /* CCISS_DEBUG */
-static int find_PCI_BAR_index(struct pci_dev *pdev,
- unsigned long pci_bar_addr)
+static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
{
int i, offset, mem_type, bar_type;
- if (pci_bar_addr == PCI_BASE_ADDRESS_0) /* looking for BAR zero? */
+ if (pci_bar_addr == PCI_BASE_ADDRESS_0) /* looking for BAR zero? */
return 0;
offset = 0;
- for (i=0; i<DEVICE_COUNT_RESOURCE; i++) {
- bar_type = pci_resource_flags(pdev, i) &
- PCI_BASE_ADDRESS_SPACE;
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ bar_type = pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE;
if (bar_type == PCI_BASE_ADDRESS_SPACE_IO)
offset += 4;
else {
mem_type = pci_resource_flags(pdev, i) &
- PCI_BASE_ADDRESS_MEM_TYPE_MASK;
+ PCI_BASE_ADDRESS_MEM_TYPE_MASK;
switch (mem_type) {
- case PCI_BASE_ADDRESS_MEM_TYPE_32:
- case PCI_BASE_ADDRESS_MEM_TYPE_1M:
- offset += 4; /* 32 bit */
- break;
- case PCI_BASE_ADDRESS_MEM_TYPE_64:
- offset += 8;
- break;
- default: /* reserved in PCI 2.2 */
- printk(KERN_WARNING "Base address is invalid\n");
- return -1;
+ case PCI_BASE_ADDRESS_MEM_TYPE_32:
+ case PCI_BASE_ADDRESS_MEM_TYPE_1M:
+ offset += 4; /* 32 bit */
+ break;
+ case PCI_BASE_ADDRESS_MEM_TYPE_64:
+ offset += 8;
+ break;
+ default: /* reserved in PCI 2.2 */
+ printk(KERN_WARNING
+ "Base address is invalid\n");
+ return -1;
break;
}
}
- if (offset == pci_bar_addr - PCI_BASE_ADDRESS_0)
- return i+1;
+ if (offset == pci_bar_addr - PCI_BASE_ADDRESS_0)
+ return i + 1;
}
return -1;
}
@@ -2686,53 +2708,54 @@ static int find_PCI_BAR_index(struct pci_dev *pdev,
* controllers that are capable. If not, we use IO-APIC mode.
*/
-static void __devinit cciss_interrupt_mode(ctlr_info_t *c, struct pci_dev *pdev, __u32 board_id)
+static void __devinit cciss_interrupt_mode(ctlr_info_t *c,
+ struct pci_dev *pdev, __u32 board_id)
{
#ifdef CONFIG_PCI_MSI
- int err;
- struct msix_entry cciss_msix_entries[4] = {{0,0}, {0,1},
- {0,2}, {0,3}};
+ int err;
+ struct msix_entry cciss_msix_entries[4] = { {0, 0}, {0, 1},
+ {0, 2}, {0, 3}
+ };
/* Some boards advertise MSI but don't really support it */
if ((board_id == 0x40700E11) ||
- (board_id == 0x40800E11) ||
- (board_id == 0x40820E11) ||
- (board_id == 0x40830E11))
+ (board_id == 0x40800E11) ||
+ (board_id == 0x40820E11) || (board_id == 0x40830E11))
goto default_int_mode;
- if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
- err = pci_enable_msix(pdev, cciss_msix_entries, 4);
- if (!err) {
- c->intr[0] = cciss_msix_entries[0].vector;
- c->intr[1] = cciss_msix_entries[1].vector;
- c->intr[2] = cciss_msix_entries[2].vector;
- c->intr[3] = cciss_msix_entries[3].vector;
- c->msix_vector = 1;
- return;
- }
- if (err > 0) {
- printk(KERN_WARNING "cciss: only %d MSI-X vectors "
- "available\n", err);
- } else {
- printk(KERN_WARNING "cciss: MSI-X init failed %d\n",
- err);
- }
- }
- if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) {
- if (!pci_enable_msi(pdev)) {
- c->intr[SIMPLE_MODE_INT] = pdev->irq;
- c->msi_vector = 1;
- return;
- } else {
- printk(KERN_WARNING "cciss: MSI init failed\n");
- c->intr[SIMPLE_MODE_INT] = pdev->irq;
- return;
- }
- }
-default_int_mode:
-#endif /* CONFIG_PCI_MSI */
+ if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
+ err = pci_enable_msix(pdev, cciss_msix_entries, 4);
+ if (!err) {
+ c->intr[0] = cciss_msix_entries[0].vector;
+ c->intr[1] = cciss_msix_entries[1].vector;
+ c->intr[2] = cciss_msix_entries[2].vector;
+ c->intr[3] = cciss_msix_entries[3].vector;
+ c->msix_vector = 1;
+ return;
+ }
+ if (err > 0) {
+ printk(KERN_WARNING "cciss: only %d MSI-X vectors "
+ "available\n", err);
+ } else {
+ printk(KERN_WARNING "cciss: MSI-X init failed %d\n",
+ err);
+ }
+ }
+ if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) {
+ if (!pci_enable_msi(pdev)) {
+ c->intr[SIMPLE_MODE_INT] = pdev->irq;
+ c->msi_vector = 1;
+ return;
+ } else {
+ printk(KERN_WARNING "cciss: MSI init failed\n");
+ c->intr[SIMPLE_MODE_INT] = pdev->irq;
+ return;
+ }
+ }
+ default_int_mode:
+#endif /* CONFIG_PCI_MSI */
/* if we get here we're going to use the default interrupt mode */
- c->intr[SIMPLE_MODE_INT] = pdev->irq;
+ c->intr[SIMPLE_MODE_INT] = pdev->irq;
return;
}
@@ -2743,58 +2766,40 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
__u64 cfg_offset;
__u32 cfg_base_addr;
__u64 cfg_base_addr_index;
- int i;
+ int i, err;
/* check to see if controller has been disabled */
/* BEFORE trying to enable it */
- (void) pci_read_config_word(pdev, PCI_COMMAND,&command);
- if(!(command & 0x02))
- {
- printk(KERN_WARNING "cciss: controller appears to be disabled\n");
- return(-1);
+ (void)pci_read_config_word(pdev, PCI_COMMAND, &command);
+ if (!(command & 0x02)) {
+ printk(KERN_WARNING
+ "cciss: controller appears to be disabled\n");
+ return -ENODEV;
}
- if (pci_enable_device(pdev))
- {
+ err = pci_enable_device(pdev);
+ if (err) {
printk(KERN_ERR "cciss: Unable to Enable PCI device\n");
- return( -1);
+ return err;
+ }
+
+ err = pci_request_regions(pdev, "cciss");
+ if (err) {
+ printk(KERN_ERR "cciss: Cannot obtain PCI resources, "
+ "aborting\n");
+ goto err_out_disable_pdev;
}
subsystem_vendor_id = pdev->subsystem_vendor;
subsystem_device_id = pdev->subsystem_device;
board_id = (((__u32) (subsystem_device_id << 16) & 0xffff0000) |
- subsystem_vendor_id);
-
- /* search for our IO range so we can protect it */
- for(i=0; i<DEVICE_COUNT_RESOURCE; i++)
- {
- /* is this an IO range */
- if( pci_resource_flags(pdev, i) & 0x01 ) {
- c->io_mem_addr = pci_resource_start(pdev, i);
- c->io_mem_length = pci_resource_end(pdev, i) -
- pci_resource_start(pdev, i) +1;
-#ifdef CCISS_DEBUG
- printk("IO value found base_addr[%d] %lx %lx\n", i,
- c->io_mem_addr, c->io_mem_length);
-#endif /* CCISS_DEBUG */
- /* register the IO range */
- if(!request_region( c->io_mem_addr,
- c->io_mem_length, "cciss"))
- {
- printk(KERN_WARNING "cciss I/O memory range already in use addr=%lx length=%ld\n",
- c->io_mem_addr, c->io_mem_length);
- c->io_mem_addr= 0;
- c->io_mem_length = 0;
- }
- break;
- }
- }
+ subsystem_vendor_id);
#ifdef CCISS_DEBUG
printk("command = %x\n", command);
printk("irq = %x\n", pdev->irq);
printk("board_id = %x\n", board_id);
-#endif /* CCISS_DEBUG */
+#endif /* CCISS_DEBUG */
/* If the kernel supports MSI/MSI-X we will try to enable that functionality,
* else we use the IO-APIC interrupt assigned to us by system ROM.
@@ -2803,27 +2808,28 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
/*
* Memory base addr is first addr , the second points to the config
- * table
+ * table
*/
- c->paddr = pci_resource_start(pdev, 0); /* addressing mode bits already removed */
+ c->paddr = pci_resource_start(pdev, 0); /* addressing mode bits already removed */
#ifdef CCISS_DEBUG
printk("address 0 = %x\n", c->paddr);
-#endif /* CCISS_DEBUG */
+#endif /* CCISS_DEBUG */
c->vaddr = remap_pci_mem(c->paddr, 200);
/* Wait for the board to become ready. (PCI hotplug needs this.)
* We poll for up to 120 secs, once per 100ms. */
- for (i=0; i < 1200; i++) {
+ for (i = 0; i < 1200; i++) {
scratchpad = readl(c->vaddr + SA5_SCRATCHPAD_OFFSET);
if (scratchpad == CCISS_FIRMWARE_READY)
break;
set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ / 10); /* wait 100ms */
+ schedule_timeout(HZ / 10); /* wait 100ms */
}
if (scratchpad != CCISS_FIRMWARE_READY) {
printk(KERN_WARNING "cciss: Board not ready. Timed out.\n");
- return -1;
+ err = -ENODEV;
+ goto err_out_free_res;
}
/* get the address index number */
@@ -2831,103 +2837,108 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
cfg_base_addr &= (__u32) 0x0000ffff;
#ifdef CCISS_DEBUG
printk("cfg base address = %x\n", cfg_base_addr);
-#endif /* CCISS_DEBUG */
- cfg_base_addr_index =
- find_PCI_BAR_index(pdev, cfg_base_addr);
+#endif /* CCISS_DEBUG */
+ cfg_base_addr_index = find_PCI_BAR_index(pdev, cfg_base_addr);
#ifdef CCISS_DEBUG
printk("cfg base address index = %x\n", cfg_base_addr_index);
-#endif /* CCISS_DEBUG */
+#endif /* CCISS_DEBUG */
if (cfg_base_addr_index == -1) {
printk(KERN_WARNING "cciss: Cannot find cfg_base_addr_index\n");
- release_io_mem(c);
- return -1;
+ err = -ENODEV;
+ goto err_out_free_res;
}
cfg_offset = readl(c->vaddr + SA5_CTMEM_OFFSET);
#ifdef CCISS_DEBUG
printk("cfg offset = %x\n", cfg_offset);
-#endif /* CCISS_DEBUG */
- c->cfgtable = remap_pci_mem(pci_resource_start(pdev,
- cfg_base_addr_index) + cfg_offset,
- sizeof(CfgTable_struct));
+#endif /* CCISS_DEBUG */
+ c->cfgtable = remap_pci_mem(pci_resource_start(pdev,
+ cfg_base_addr_index) +
+ cfg_offset, sizeof(CfgTable_struct));
c->board_id = board_id;
#ifdef CCISS_DEBUG
print_cfg_table(c->cfgtable);
-#endif /* CCISS_DEBUG */
+#endif /* CCISS_DEBUG */
- for(i=0; i<NR_PRODUCTS; i++) {
+ for (i = 0; i < ARRAY_SIZE(products); i++) {
if (board_id == products[i].board_id) {
c->product_name = products[i].product_name;
c->access = *(products[i].access);
break;
}
}
- if (i == NR_PRODUCTS) {
+ if (i == ARRAY_SIZE(products)) {
printk(KERN_WARNING "cciss: Sorry, I don't know how"
- " to access the Smart Array controller %08lx\n",
- (unsigned long)board_id);
- return -1;
- }
- if ( (readb(&c->cfgtable->Signature[0]) != 'C') ||
- (readb(&c->cfgtable->Signature[1]) != 'I') ||
- (readb(&c->cfgtable->Signature[2]) != 'S') ||
- (readb(&c->cfgtable->Signature[3]) != 'S') )
- {
+ " to access the Smart Array controller %08lx\n",
+ (unsigned long)board_id);
+ err = -ENODEV;
+ goto err_out_free_res;
+ }
+ if ((readb(&c->cfgtable->Signature[0]) != 'C') ||
+ (readb(&c->cfgtable->Signature[1]) != 'I') ||
+ (readb(&c->cfgtable->Signature[2]) != 'S') ||
+ (readb(&c->cfgtable->Signature[3]) != 'S')) {
printk("Does not appear to be a valid CISS config table\n");
- return -1;
+ err = -ENODEV;
+ goto err_out_free_res;
}
-
#ifdef CONFIG_X86
-{
- /* Need to enable prefetch in the SCSI core for 6400 in x86 */
- __u32 prefetch;
- prefetch = readl(&(c->cfgtable->SCSI_Prefetch));
- prefetch |= 0x100;
- writel(prefetch, &(c->cfgtable->SCSI_Prefetch));
-}
+ {
+ /* Need to enable prefetch in the SCSI core for 6400 in x86 */
+ __u32 prefetch;
+ prefetch = readl(&(c->cfgtable->SCSI_Prefetch));
+ prefetch |= 0x100;
+ writel(prefetch, &(c->cfgtable->SCSI_Prefetch));
+ }
#endif
#ifdef CCISS_DEBUG
printk("Trying to put board into Simple mode\n");
-#endif /* CCISS_DEBUG */
+#endif /* CCISS_DEBUG */
c->max_commands = readl(&(c->cfgtable->CmdsOutMax));
- /* Update the field, and then ring the doorbell */
- writel( CFGTBL_Trans_Simple,
- &(c->cfgtable->HostWrite.TransportRequest));
- writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
+ /* Update the field, and then ring the doorbell */
+ writel(CFGTBL_Trans_Simple, &(c->cfgtable->HostWrite.TransportRequest));
+ writel(CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
/* under certain very rare conditions, this can take awhile.
* (e.g.: hot replace a failed 144GB drive in a RAID 5 set right
* as we enter this code.) */
- for(i=0;i<MAX_CONFIG_WAIT;i++) {
+ for (i = 0; i < MAX_CONFIG_WAIT; i++) {
if (!(readl(c->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
break;
/* delay and try again */
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(10);
- }
+ }
#ifdef CCISS_DEBUG
- printk(KERN_DEBUG "I counter got to %d %x\n", i, readl(c->vaddr + SA5_DOORBELL));
-#endif /* CCISS_DEBUG */
+ printk(KERN_DEBUG "I counter got to %d %x\n", i,
+ readl(c->vaddr + SA5_DOORBELL));
+#endif /* CCISS_DEBUG */
#ifdef CCISS_DEBUG
- print_cfg_table(c->cfgtable);
-#endif /* CCISS_DEBUG */
+ print_cfg_table(c->cfgtable);
+#endif /* CCISS_DEBUG */
- if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple))
- {
+ if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) {
printk(KERN_WARNING "cciss: unable to get board into"
- " simple mode\n");
- return -1;
+ " simple mode\n");
+ err = -ENODEV;
+ goto err_out_free_res;
}
return 0;
+ err_out_free_res:
+ pci_release_regions(pdev);
+
+ err_out_disable_pdev:
+ pci_disable_device(pdev);
+ return err;
}
-/*
- * Gets information about the local volumes attached to the controller.
- */
+/*
+ * Gets information about the local volumes attached to the controller.
+ */
static void cciss_getgeometry(int cntl_num)
{
ReportLunData_struct *ld_buff;
@@ -2938,102 +2949,102 @@ static void cciss_getgeometry(int cntl_num)
int listlength = 0;
__u32 lunid = 0;
int block_size;
- int total_size;
+ int total_size;
ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
- if (ld_buff == NULL)
- {
+ if (ld_buff == NULL) {
+ printk(KERN_ERR "cciss: out of memory\n");
+ return;
+ }
+ size_buff = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
+ if (size_buff == NULL) {
printk(KERN_ERR "cciss: out of memory\n");
+ kfree(ld_buff);
return;
}
- size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
- if (size_buff == NULL)
- {
- printk(KERN_ERR "cciss: out of memory\n");
+ inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
+ if (inq_buff == NULL) {
+ printk(KERN_ERR "cciss: out of memory\n");
kfree(ld_buff);
- return;
- }
- inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
- if (inq_buff == NULL)
- {
- printk(KERN_ERR "cciss: out of memory\n");
- kfree(ld_buff);
kfree(size_buff);
- return;
- }
- /* Get the firmware version */
- return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff,
- sizeof(InquiryData_struct), 0, 0 ,0, NULL, TYPE_CMD);
- if (return_code == IO_OK)
- {
+ return;
+ }
+ /* Get the firmware version */
+ return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff,
+ sizeof(InquiryData_struct), 0, 0, 0, NULL,
+ TYPE_CMD);
+ if (return_code == IO_OK) {
hba[cntl_num]->firm_ver[0] = inq_buff->data_byte[32];
hba[cntl_num]->firm_ver[1] = inq_buff->data_byte[33];
hba[cntl_num]->firm_ver[2] = inq_buff->data_byte[34];
hba[cntl_num]->firm_ver[3] = inq_buff->data_byte[35];
- } else /* send command failed */
- {
+ } else { /* send command failed */
+
printk(KERN_WARNING "cciss: unable to determine firmware"
- " version of controller\n");
+ " version of controller\n");
}
- /* Get the number of logical volumes */
- return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff,
- sizeof(ReportLunData_struct), 0, 0, 0, NULL, TYPE_CMD);
+ /* Get the number of logical volumes */
+ return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff,
+ sizeof(ReportLunData_struct), 0, 0, 0, NULL,
+ TYPE_CMD);
- if( return_code == IO_OK)
- {
+ if (return_code == IO_OK) {
#ifdef CCISS_DEBUG
printk("LUN Data\n--------------------------\n");
-#endif /* CCISS_DEBUG */
-
- listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
- listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
- listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;
+#endif /* CCISS_DEBUG */
+
+ listlength |=
+ (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
+ listlength |=
+ (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
+ listlength |=
+ (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;
listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
- } else /* reading number of logical volumes failed */
- {
+ } else { /* reading number of logical volumes failed */
+
printk(KERN_WARNING "cciss: report logical volume"
- " command failed\n");
+ " command failed\n");
listlength = 0;
}
- hba[cntl_num]->num_luns = listlength / 8; // 8 bytes pre entry
- if (hba[cntl_num]->num_luns > CISS_MAX_LUN)
- {
- printk(KERN_ERR "ciss: only %d number of logical volumes supported\n",
- CISS_MAX_LUN);
+ hba[cntl_num]->num_luns = listlength / 8; // 8 bytes pre entry
+ if (hba[cntl_num]->num_luns > CISS_MAX_LUN) {
+ printk(KERN_ERR
+ "ciss: only %d number of logical volumes supported\n",
+ CISS_MAX_LUN);
hba[cntl_num]->num_luns = CISS_MAX_LUN;
}
#ifdef CCISS_DEBUG
- printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", ld_buff->LUNListLength[0],
- ld_buff->LUNListLength[1], ld_buff->LUNListLength[2],
- ld_buff->LUNListLength[3], hba[cntl_num]->num_luns);
-#endif /* CCISS_DEBUG */
-
- hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns-1;
-// for(i=0; i< hba[cntl_num]->num_luns; i++)
- for(i=0; i < CISS_MAX_LUN; i++)
- {
- if (i < hba[cntl_num]->num_luns){
- lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3]))
- << 24;
- lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2]))
- << 16;
- lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1]))
- << 8;
- lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
-
- hba[cntl_num]->drv[i].LunID = lunid;
-
+ printk(KERN_DEBUG "Length = %x %x %x %x = %d\n",
+ ld_buff->LUNListLength[0], ld_buff->LUNListLength[1],
+ ld_buff->LUNListLength[2], ld_buff->LUNListLength[3],
+ hba[cntl_num]->num_luns);
+#endif /* CCISS_DEBUG */
+
+ hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns - 1;
+// for(i=0; i< hba[cntl_num]->num_luns; i++)
+ for (i = 0; i < CISS_MAX_LUN; i++) {
+ if (i < hba[cntl_num]->num_luns) {
+ lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3]))
+ << 24;
+ lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2]))
+ << 16;
+ lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1]))
+ << 8;
+ lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
+
+ hba[cntl_num]->drv[i].LunID = lunid;
#ifdef CCISS_DEBUG
- printk(KERN_DEBUG "LUN[%d]: %x %x %x %x = %x\n", i,
- ld_buff->LUN[i][0], ld_buff->LUN[i][1],
- ld_buff->LUN[i][2], ld_buff->LUN[i][3],
- hba[cntl_num]->drv[i].LunID);
-#endif /* CCISS_DEBUG */
- cciss_read_capacity(cntl_num, i, size_buff, 0,
- &total_size, &block_size);
+ printk(KERN_DEBUG "LUN[%d]: %x %x %x %x = %x\n", i,
+ ld_buff->LUN[i][0], ld_buff->LUN[i][1],
+ ld_buff->LUN[i][2], ld_buff->LUN[i][3],
+ hba[cntl_num]->drv[i].LunID);
+#endif /* CCISS_DEBUG */
+ cciss_read_capacity(cntl_num, i, size_buff, 0,
+ &total_size, &block_size);
cciss_geometry_inquiry(cntl_num, i, 0, total_size,
- block_size, inq_buff, &hba[cntl_num]->drv[i]);
+ block_size, inq_buff,
+ &hba[cntl_num]->drv[i]);
} else {
/* initialize raid_level to indicate a free space */
hba[cntl_num]->drv[i].raid_level = -1;
@@ -3042,7 +3053,7 @@ static void cciss_getgeometry(int cntl_num)
kfree(ld_buff);
kfree(size_buff);
kfree(inq_buff);
-}
+}
/* Function to find the first free pointer into our hba[] array */
/* Returns -1 if no free entries are left. */
@@ -3056,7 +3067,7 @@ static int alloc_cciss_hba(void)
goto out;
}
- for(i=0; i< MAX_CTLR; i++) {
+ for (i = 0; i < MAX_CTLR; i++) {
if (!hba[i]) {
ctlr_info_t *p;
p = kzalloc(sizeof(ctlr_info_t), GFP_KERNEL);
@@ -3069,11 +3080,11 @@ static int alloc_cciss_hba(void)
}
}
printk(KERN_WARNING "cciss: This driver supports a maximum"
- " of %d controllers.\n", MAX_CTLR);
+ " of %d controllers.\n", MAX_CTLR);
goto out;
-Enomem:
+ Enomem:
printk(KERN_ERR "cciss: out of memory.\n");
-out:
+ out:
while (n--)
put_disk(disk[n]);
return -1;
@@ -3096,20 +3107,17 @@ static void free_hba(int i)
* returns the number of block devices registered.
*/
static int __devinit cciss_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
request_queue_t *q;
int i;
int j;
int rc;
+ int dac;
- printk(KERN_DEBUG "cciss: Device 0x%x has been found at"
- " bus %d dev %d func %d\n",
- pdev->device, pdev->bus->number, PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn));
i = alloc_cciss_hba();
- if(i < 0)
- return (-1);
+ if (i < 0)
+ return -1;
hba[i]->busy_initializing = 1;
@@ -3122,11 +3130,11 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
/* configure PCI DMA stuff */
if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK))
- printk("cciss: using DAC cycles\n");
+ dac = 1;
else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK))
- printk("cciss: not using DAC cycles\n");
+ dac = 0;
else {
- printk("cciss: no suitable DMA available\n");
+ printk(KERN_ERR "cciss: no suitable DMA available\n");
goto clean1;
}
@@ -3138,60 +3146,69 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
if (i < MAX_CTLR_ORIG)
hba[i]->major = COMPAQ_CISS_MAJOR + i;
rc = register_blkdev(hba[i]->major, hba[i]->devname);
- if(rc == -EBUSY || rc == -EINVAL) {
+ if (rc == -EBUSY || rc == -EINVAL) {
printk(KERN_ERR
- "cciss: Unable to get major number %d for %s "
- "on hba %d\n", hba[i]->major, hba[i]->devname, i);
+ "cciss: Unable to get major number %d for %s "
+ "on hba %d\n", hba[i]->major, hba[i]->devname, i);
goto clean1;
- }
- else {
+ } else {
if (i >= MAX_CTLR_ORIG)
hba[i]->major = rc;
}
/* make sure the board interrupts are off */
hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
- if( request_irq(hba[i]->intr[SIMPLE_MODE_INT], do_cciss_intr,
- SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
- hba[i]->devname, hba[i])) {
+ if (request_irq(hba[i]->intr[SIMPLE_MODE_INT], do_cciss_intr,
+ SA_INTERRUPT | SA_SHIRQ, hba[i]->devname, hba[i])) {
printk(KERN_ERR "cciss: Unable to get irq %d for %s\n",
- hba[i]->intr[SIMPLE_MODE_INT], hba[i]->devname);
+ hba[i]->intr[SIMPLE_MODE_INT], hba[i]->devname);
goto clean2;
}
- hba[i]->cmd_pool_bits = kmalloc(((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long), GFP_KERNEL);
- hba[i]->cmd_pool = (CommandList_struct *)pci_alloc_consistent(
- hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct),
- &(hba[i]->cmd_pool_dhandle));
- hba[i]->errinfo_pool = (ErrorInfo_struct *)pci_alloc_consistent(
- hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct),
- &(hba[i]->errinfo_pool_dhandle));
- if((hba[i]->cmd_pool_bits == NULL)
- || (hba[i]->cmd_pool == NULL)
- || (hba[i]->errinfo_pool == NULL)) {
- printk( KERN_ERR "cciss: out of memory");
+
+ printk(KERN_INFO "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n",
+ hba[i]->devname, pdev->device, pci_name(pdev),
+ hba[i]->intr[SIMPLE_MODE_INT], dac ? "" : " not");
+
+ hba[i]->cmd_pool_bits =
+ kmalloc(((NR_CMDS + BITS_PER_LONG -
+ 1) / BITS_PER_LONG) * sizeof(unsigned long), GFP_KERNEL);
+ hba[i]->cmd_pool = (CommandList_struct *)
+ pci_alloc_consistent(hba[i]->pdev,
+ NR_CMDS * sizeof(CommandList_struct),
+ &(hba[i]->cmd_pool_dhandle));
+ hba[i]->errinfo_pool = (ErrorInfo_struct *)
+ pci_alloc_consistent(hba[i]->pdev,
+ NR_CMDS * sizeof(ErrorInfo_struct),
+ &(hba[i]->errinfo_pool_dhandle));
+ if ((hba[i]->cmd_pool_bits == NULL)
+ || (hba[i]->cmd_pool == NULL)
+ || (hba[i]->errinfo_pool == NULL)) {
+ printk(KERN_ERR "cciss: out of memory");
goto clean4;
}
#ifdef CONFIG_CISS_SCSI_TAPE
- hba[i]->scsi_rejects.complete =
- kmalloc(sizeof(hba[i]->scsi_rejects.complete[0]) *
- (NR_CMDS + 5), GFP_KERNEL);
+ hba[i]->scsi_rejects.complete =
+ kmalloc(sizeof(hba[i]->scsi_rejects.complete[0]) *
+ (NR_CMDS + 5), GFP_KERNEL);
if (hba[i]->scsi_rejects.complete == NULL) {
- printk( KERN_ERR "cciss: out of memory");
+ printk(KERN_ERR "cciss: out of memory");
goto clean4;
}
#endif
spin_lock_init(&hba[i]->lock);
- /* Initialize the pdev driver private data.
- have it point to hba[i]. */
+ /* Initialize the pdev driver private data.
+ have it point to hba[i]. */
pci_set_drvdata(pdev, hba[i]);
- /* command and error info recs zeroed out before
- they are used */
- memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long));
+ /* command and error info recs zeroed out before
+ they are used */
+ memset(hba[i]->cmd_pool_bits, 0,
+ ((NR_CMDS + BITS_PER_LONG -
+ 1) / BITS_PER_LONG) * sizeof(unsigned long));
-#ifdef CCISS_DEBUG
- printk(KERN_DEBUG "Scanning for drives on controller cciss%d\n",i);
-#endif /* CCISS_DEBUG */
+#ifdef CCISS_DEBUG
+ printk(KERN_DEBUG "Scanning for drives on controller cciss%d\n", i);
+#endif /* CCISS_DEBUG */
cciss_getgeometry(i);
@@ -3203,15 +3220,15 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
cciss_procinit(i);
hba[i]->busy_initializing = 0;
- for(j=0; j < NWD; j++) { /* mfm */
+ for (j = 0; j < NWD; j++) { /* mfm */
drive_info_struct *drv = &(hba[i]->drv[j]);
struct gendisk *disk = hba[i]->gendisk[j];
q = blk_init_queue(do_cciss_request, &hba[i]->lock);
if (!q) {
printk(KERN_ERR
- "cciss: unable to allocate queue for disk %d\n",
- j);
+ "cciss: unable to allocate queue for disk %d\n",
+ j);
break;
}
drv->queue = q;
@@ -3240,92 +3257,87 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
disk->driverfs_dev = &pdev->dev;
/* we must register the controller even if no disks exist */
/* this is for the online array utilities */
- if(!drv->heads && j)
+ if (!drv->heads && j)
continue;
blk_queue_hardsect_size(q, drv->block_size);
set_capacity(disk, drv->nr_blocks);
add_disk(disk);
}
- return(1);
+ return 1;
-clean4:
+ clean4:
#ifdef CONFIG_CISS_SCSI_TAPE
kfree(hba[i]->scsi_rejects.complete);
#endif
kfree(hba[i]->cmd_pool_bits);
- if(hba[i]->cmd_pool)
+ if (hba[i]->cmd_pool)
pci_free_consistent(hba[i]->pdev,
- NR_CMDS * sizeof(CommandList_struct),
- hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);
- if(hba[i]->errinfo_pool)
+ NR_CMDS * sizeof(CommandList_struct),
+ hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);
+ if (hba[i]->errinfo_pool)
pci_free_consistent(hba[i]->pdev,
- NR_CMDS * sizeof( ErrorInfo_struct),
- hba[i]->errinfo_pool,
- hba[i]->errinfo_pool_dhandle);
+ NR_CMDS * sizeof(ErrorInfo_struct),
+ hba[i]->errinfo_pool,
+ hba[i]->errinfo_pool_dhandle);
free_irq(hba[i]->intr[SIMPLE_MODE_INT], hba[i]);
-clean2:
+ clean2:
unregister_blkdev(hba[i]->major, hba[i]->devname);
-clean1:
- release_io_mem(hba[i]);
+ clean1:
hba[i]->busy_initializing = 0;
free_hba(i);
- return(-1);
+ return -1;
}
-static void __devexit cciss_remove_one (struct pci_dev *pdev)
+static void __devexit cciss_remove_one(struct pci_dev *pdev)
{
ctlr_info_t *tmp_ptr;
int i, j;
char flush_buf[4];
- int return_code;
+ int return_code;
- if (pci_get_drvdata(pdev) == NULL)
- {
- printk( KERN_ERR "cciss: Unable to remove device \n");
+ if (pci_get_drvdata(pdev) == NULL) {
+ printk(KERN_ERR "cciss: Unable to remove device \n");
return;
}
tmp_ptr = pci_get_drvdata(pdev);
i = tmp_ptr->ctlr;
- if (hba[i] == NULL)
- {
+ if (hba[i] == NULL) {
printk(KERN_ERR "cciss: device appears to "
- "already be removed \n");
+ "already be removed \n");
return;
}
/* Turn board interrupts off and send the flush cache command */
/* sendcmd will turn off interrupt, and send the flush...
- * To write all data in the battery backed cache to disks */
+ * To write all data in the battery backed cache to disks */
memset(flush_buf, 0, 4);
return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL,
- TYPE_CMD);
- if(return_code != IO_OK)
- {
- printk(KERN_WARNING "Error Flushing cache on controller %d\n",
- i);
+ TYPE_CMD);
+ if (return_code != IO_OK) {
+ printk(KERN_WARNING "Error Flushing cache on controller %d\n",
+ i);
}
free_irq(hba[i]->intr[2], hba[i]);
#ifdef CONFIG_PCI_MSI
- if (hba[i]->msix_vector)
- pci_disable_msix(hba[i]->pdev);
- else if (hba[i]->msi_vector)
- pci_disable_msi(hba[i]->pdev);
-#endif /* CONFIG_PCI_MSI */
+ if (hba[i]->msix_vector)
+ pci_disable_msix(hba[i]->pdev);
+ else if (hba[i]->msi_vector)
+ pci_disable_msi(hba[i]->pdev);
+#endif /* CONFIG_PCI_MSI */
- pci_set_drvdata(pdev, NULL);
iounmap(hba[i]->vaddr);
- cciss_unregister_scsi(i); /* unhook from SCSI subsystem */
+ cciss_unregister_scsi(i); /* unhook from SCSI subsystem */
unregister_blkdev(hba[i]->major, hba[i]->devname);
- remove_proc_entry(hba[i]->devname, proc_cciss);
-
+ remove_proc_entry(hba[i]->devname, proc_cciss);
+
/* remove it from the disk list */
for (j = 0; j < NWD; j++) {
struct gendisk *disk = hba[i]->gendisk[j];
if (disk) {
request_queue_t *q = disk->queue;
- if (disk->flags & GENHD_FL_UP)
+ if (disk->flags & GENHD_FL_UP)
del_gendisk(disk);
if (q)
blk_cleanup_queue(q);
@@ -3334,26 +3346,28 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev)
pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct),
hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);
- pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct),
- hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle);
+ pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof(ErrorInfo_struct),
+ hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle);
kfree(hba[i]->cmd_pool_bits);
#ifdef CONFIG_CISS_SCSI_TAPE
kfree(hba[i]->scsi_rejects.complete);
#endif
- release_io_mem(hba[i]);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
free_hba(i);
-}
+}
static struct pci_driver cciss_pci_driver = {
- .name = "cciss",
- .probe = cciss_init_one,
- .remove = __devexit_p(cciss_remove_one),
- .id_table = cciss_pci_device_id, /* id_table */
+ .name = "cciss",
+ .probe = cciss_init_one,
+ .remove = __devexit_p(cciss_remove_one),
+ .id_table = cciss_pci_device_id, /* id_table */
};
/*
* This is it. Register the PCI driver information for the cards we control
- * the OS will call our registered routines when it finds one of our cards.
+ * the OS will call our registered routines when it finds one of our cards.
*/
static int __init cciss_init(void)
{
@@ -3369,12 +3383,10 @@ static void __exit cciss_cleanup(void)
pci_unregister_driver(&cciss_pci_driver);
/* double check that all controller entrys have been removed */
- for (i=0; i< MAX_CTLR; i++)
- {
- if (hba[i] != NULL)
- {
+ for (i = 0; i < MAX_CTLR; i++) {
+ if (hba[i] != NULL) {
printk(KERN_WARNING "cciss: had to remove"
- " controller %d\n", i);
+ " controller %d\n", i);
cciss_remove_one(hba[i]->pdev);
}
}
@@ -3389,21 +3401,21 @@ static void fail_all_cmds(unsigned long ctlr)
unsigned long flags;
printk(KERN_WARNING "cciss%d: controller not responding.\n", h->ctlr);
- h->alive = 0; /* the controller apparently died... */
+ h->alive = 0; /* the controller apparently died... */
spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
- pci_disable_device(h->pdev); /* Make sure it is really dead. */
+ pci_disable_device(h->pdev); /* Make sure it is really dead. */
/* move everything off the request queue onto the completed queue */
- while( (c = h->reqQ) != NULL ) {
+ while ((c = h->reqQ) != NULL) {
removeQ(&(h->reqQ), c);
h->Qdepth--;
- addQ (&(h->cmpQ), c);
+ addQ(&(h->cmpQ), c);
}
/* Now, fail everything on the completed queue with a HW error */
- while( (c = h->cmpQ) != NULL ) {
+ while ((c = h->cmpQ) != NULL) {
removeQ(&h->cmpQ, c);
c->err_info->CommandStatus = CMD_HARDWARE_ERR;
if (c->cmd_type == CMD_RWREQ) {
@@ -3411,8 +3423,8 @@ static void fail_all_cmds(unsigned long ctlr)
} else if (c->cmd_type == CMD_IOCTL_PEND)
complete(c->waiting);
#ifdef CONFIG_CISS_SCSI_TAPE
- else if (c->cmd_type == CMD_SCSI)
- complete_scsi_command(c, 0, 0);
+ else if (c->cmd_type == CMD_SCSI)
+ complete_scsi_command(c, 0, 0);
#endif
}
spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h
index b24fc05..868e0d8 100644
--- a/drivers/block/cciss.h
+++ b/drivers/block/cciss.h
@@ -60,8 +60,6 @@ struct ctlr_info
__u32 board_id;
void __iomem *vaddr;
unsigned long paddr;
- unsigned long io_mem_addr;
- unsigned long io_mem_length;
CfgTable_struct __iomem *cfgtable;
int interrupts_enabled;
int major;
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index b6ea2f0..5eb6fb7 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -392,7 +392,7 @@ static void __devexit cpqarray_remove_one_eisa (int i)
}
/* pdev is NULL for eisa */
-static int cpqarray_register_ctlr( int i, struct pci_dev *pdev)
+static int __init cpqarray_register_ctlr( int i, struct pci_dev *pdev)
{
request_queue_t *q;
int j;
@@ -410,8 +410,7 @@ static int cpqarray_register_ctlr( int i, struct pci_dev *pdev)
}
hba[i]->access.set_intr_mask(hba[i], 0);
if (request_irq(hba[i]->intr, do_ida_intr,
- SA_INTERRUPT|SA_SHIRQ|SA_SAMPLE_RANDOM,
- hba[i]->devname, hba[i]))
+ SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i]))
{
printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n",
hba[i]->intr, hba[i]->devname);
@@ -745,7 +744,7 @@ __setup("smart2=", cpqarray_setup);
/*
* Find an EISA controller's signature. Set up an hba if we find it.
*/
-static int cpqarray_eisa_detect(void)
+static int __init cpqarray_eisa_detect(void)
{
int i=0, j;
__u32 board_id;
@@ -1036,6 +1035,8 @@ static inline void complete_command(cmdlist_t *cmd, int timeout)
complete_buffers(cmd->rq->bio, ok);
+ add_disk_randomness(cmd->rq->rq_disk);
+
DBGPX(printk("Done with %p\n", cmd->rq););
end_that_request_last(cmd->rq, ok ? 1 : -EIO);
}
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 9c3b94e..9dc294a 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -74,6 +74,7 @@
#include <linux/completion.h>
#include <linux/highmem.h>
#include <linux/gfp.h>
+#include <linux/kthread.h>
#include <asm/uaccess.h>
@@ -578,8 +579,6 @@ static int loop_thread(void *data)
struct loop_device *lo = data;
struct bio *bio;
- daemonize("loop%d", lo->lo_number);
-
/*
* loop can be used in an encrypted device,
* hence, it mustn't be stopped at all
@@ -592,11 +591,6 @@ static int loop_thread(void *data)
lo->lo_state = Lo_bound;
lo->lo_pending = 1;
- /*
- * complete it, we are running
- */
- complete(&lo->lo_done);
-
for (;;) {
int pending;
@@ -629,7 +623,6 @@ static int loop_thread(void *data)
break;
}
- complete(&lo->lo_done);
return 0;
}
@@ -746,6 +739,7 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
unsigned lo_blocksize;
int lo_flags = 0;
int error;
+ struct task_struct *tsk;
loff_t size;
/* This is safe, since we have a reference from open(). */
@@ -818,7 +812,7 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
lo->lo_device = bdev;
lo->lo_flags = lo_flags;
lo->lo_backing_file = file;
- lo->transfer = NULL;
+ lo->transfer = transfer_none;
lo->ioctl = NULL;
lo->lo_sizelimit = 0;
lo->old_gfp_mask = mapping_gfp_mask(mapping);
@@ -839,10 +833,11 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
set_blocksize(bdev, lo_blocksize);
- error = kernel_thread(loop_thread, lo, CLONE_KERNEL);
- if (error < 0)
+ tsk = kthread_run(loop_thread, lo, "loop%d", lo->lo_number);
+ if (IS_ERR(tsk)) {
+ error = PTR_ERR(tsk);
goto out_putf;
- wait_for_completion(&lo->lo_done);
+ }
return 0;
out_putf:
@@ -898,6 +893,9 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
if (lo->lo_state != Lo_bound)
return -ENXIO;
+ if (!lo->lo_thread)
+ return -EINVAL;
+
if (lo->lo_refcnt > 1) /* we needed one fd for the ioctl */
return -EBUSY;
@@ -911,7 +909,7 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
complete(&lo->lo_bh_done);
spin_unlock_irq(&lo->lo_lock);
- wait_for_completion(&lo->lo_done);
+ kthread_stop(lo->lo_thread);
lo->lo_backing_file = NULL;
@@ -924,6 +922,7 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
lo->lo_sizelimit = 0;
lo->lo_encrypt_key_size = 0;
lo->lo_flags = 0;
+ lo->lo_thread = NULL;
memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE);
memset(lo->lo_crypt_name, 0, LO_NAME_SIZE);
memset(lo->lo_file_name, 0, LO_NAME_SIZE);
@@ -1288,7 +1287,6 @@ static int __init loop_init(void)
if (!lo->lo_queue)
goto out_mem4;
mutex_init(&lo->lo_ctl_mutex);
- init_completion(&lo->lo_done);
init_completion(&lo->lo_bh_done);
lo->lo_number = i;
spin_lock_init(&lo->lo_lock);
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 8bca490..7f554f2 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -7,39 +7,9 @@
* Copyright 1997-2000 Pavel Machek <pavel@ucw.cz>
* Parts copyright 2001 Steven Whitehouse <steve@chygwyn.com>
*
- * (part of code stolen from loop.c)
+ * This file is released under GPLv2 or later.
*
- * 97-3-25 compiled 0-th version, not yet tested it
- * (it did not work, BTW) (later that day) HEY! it works!
- * (bit later) hmm, not that much... 2:00am next day:
- * yes, it works, but it gives something like 50kB/sec
- * 97-4-01 complete rewrite to make it possible for many requests at
- * once to be processed
- * 97-4-11 Making protocol independent of endianity etc.
- * 97-9-13 Cosmetic changes
- * 98-5-13 Attempt to make 64-bit-clean on 64-bit machines
- * 99-1-11 Attempt to make 64-bit-clean on 32-bit machines <ankry@mif.pg.gda.pl>
- * 01-2-27 Fix to store proper blockcount for kernel (calculated using
- * BLOCK_SIZE_BITS, not device blocksize) <aga@permonline.ru>
- * 01-3-11 Make nbd work with new Linux block layer code. It now supports
- * plugging like all the other block devices. Also added in MSG_MORE to
- * reduce number of partial TCP segments sent. <steve@chygwyn.com>
- * 01-12-6 Fix deadlock condition by making queue locks independent of
- * the transmit lock. <steve@chygwyn.com>
- * 02-10-11 Allow hung xmit to be aborted via SIGKILL & various fixes.
- * <Paul.Clements@SteelEye.com> <James.Bottomley@SteelEye.com>
- * 03-06-22 Make nbd work with new linux 2.5 block layer design. This fixes
- * memory corruption from module removal and possible memory corruption
- * from sending/receiving disk data. <ldl@aros.net>
- * 03-06-23 Cosmetic changes. <ldl@aros.net>
- * 03-06-23 Enhance diagnostics support. <ldl@aros.net>
- * 03-06-24 Remove unneeded blksize_bits field from nbd_device struct.
- * <ldl@aros.net>
- * 03-06-24 Cleanup PARANOIA usage & code. <ldl@aros.net>
- * 04-02-19 Remove PARANOIA, plus various cleanups (Paul Clements)
- * possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall
- * why not: would need access_ok and friends, would share yet another
- * structure with userland
+ * (part of code stolen from loop.c)
*/
#include <linux/major.h>
diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c
index f63e07b..b0df4f5 100644
--- a/drivers/block/viodasd.c
+++ b/drivers/block/viodasd.c
@@ -747,7 +747,7 @@ static int viodasd_remove(struct vio_dev *vdev)
* support.
*/
static struct vio_device_id viodasd_device_table[] __devinitdata = {
- { "viodasd", "" },
+ { "block", "IBM,iSeries-viodasd" },
{ "", "" }
};
MODULE_DEVICE_TABLE(vio, viodasd_device_table);
diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c
index a0b580c..0f6e7aa 100644
--- a/drivers/cdrom/mcdx.c
+++ b/drivers/cdrom/mcdx.c
@@ -1006,7 +1006,7 @@ static int mcdx_talk(struct s_drive_stuff *stuffp,
/* MODULE STUFF ***********************************************************/
-int __mcdx_init(void)
+static int __init __mcdx_init(void)
{
int i;
int drives = 0;
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
index c0f817b..af6b3bf 100644
--- a/drivers/cdrom/viocd.c
+++ b/drivers/cdrom/viocd.c
@@ -731,7 +731,7 @@ static int viocd_remove(struct vio_dev *vdev)
* support.
*/
static struct vio_device_id viocd_device_table[] __devinitdata = {
- { "viocd", "" },
+ { "block", "IBM,iSeries-viocd" },
{ "", "" }
};
MODULE_DEVICE_TABLE(vio, viocd_device_table);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 78d928f..63f28d1 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -865,6 +865,7 @@ config SONYPI
config TANBAC_TB0219
tristate "TANBAC TB0219 base board support"
depends TANBAC_TB022X
+ select GPIO_VR41XX
menu "Ftape, the floppy tape device driver"
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
index 7c88c06..46685a5 100644
--- a/drivers/char/agp/Kconfig
+++ b/drivers/char/agp/Kconfig
@@ -1,7 +1,6 @@
config AGP
- tristate "/dev/agpgart (AGP Support)" if !GART_IOMMU
+ tristate "/dev/agpgart (AGP Support)"
depends on ALPHA || IA64 || PPC || X86
- default y if GART_IOMMU
---help---
AGP (Accelerated Graphics Port) is a bus system mainly used to
connect graphics cards to the rest of the system.
diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c
index 8c4c6ef..907fb66 100644
--- a/drivers/char/agp/hp-agp.c
+++ b/drivers/char/agp/hp-agp.c
@@ -497,7 +497,7 @@ zx1_gart_probe (acpi_handle obj, u32 depth, void *context, void **ret)
info = buffer.pointer;
info->hardware_id.value[sizeof(info->hardware_id)-1] = '\0';
match = (strcmp(info->hardware_id.value, "HWP0001") == 0);
- ACPI_MEM_FREE(info);
+ kfree(info);
if (match) {
status = hp_acpi_csr_space(handle, &sba_hpa, &length);
if (ACPI_SUCCESS(status))
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index a370e7a..9275d5e 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -166,11 +166,7 @@ static int ac_register_board(unsigned long physloc, void __iomem *loc,
return boardno + 1;
}
-#ifdef MODULE
-
-#define applicom_init init_module
-
-void cleanup_module(void)
+static void __exit applicom_exit(void)
{
unsigned int i;
@@ -188,9 +184,7 @@ void cleanup_module(void)
}
}
-#endif /* MODULE */
-
-int __init applicom_init(void)
+static int __init applicom_init(void)
{
int i, numisa = 0;
struct pci_dev *dev = NULL;
@@ -355,10 +349,9 @@ out:
return ret;
}
+module_init(applicom_init);
+module_exit(applicom_exit);
-#ifndef MODULE
-__initcall(applicom_init);
-#endif
static ssize_t ac_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
@@ -851,28 +844,3 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
return 0;
}
-#ifndef MODULE
-static int __init applicom_setup(char *str)
-{
- int ints[4];
-
- (void) get_options(str, 4, ints);
-
- if (ints[0] > 2) {
- printk(KERN_WARNING "Too many arguments to 'applicom=', expected mem,irq only.\n");
- }
-
- if (ints[0] < 2) {
- printk(KERN_INFO"applicom numargs: %d\n", ints[0]);
- return 0;
- }
-
- mem = ints[1];
- irq = ints[2];
- return 1;
-}
-
-__setup("applicom=", applicom_setup);
-
-#endif /* MODULE */
-
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index cc7acf8..122e7a7 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -2833,9 +2833,8 @@ cy_write(struct tty_struct * tty, const unsigned char *buf, int count)
return 0;
}
- if (!tty || !info->xmit_buf || !tmp_buf){
- return 0;
- }
+ if (!info->xmit_buf || !tmp_buf)
+ return 0;
CY_LOCK(info, flags);
while (1) {
@@ -2884,7 +2883,7 @@ cy_put_char(struct tty_struct *tty, unsigned char ch)
if (serial_paranoia_check(info, tty->name, "cy_put_char"))
return;
- if (!tty || !info->xmit_buf)
+ if (!info->xmit_buf)
return;
CY_LOCK(info, flags);
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index 9f4b8ce..a94233b 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -758,7 +758,9 @@ drm_ioctl_desc_t i915_ioctls[] = {
[DRM_IOCTL_NR(DRM_I915_FREE)] = {i915_mem_free, DRM_AUTH},
[DRM_IOCTL_NR(DRM_I915_INIT_HEAP)] = {i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }
+ [DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY },
+ [DRM_IOCTL_NR(DRM_I915_SET_VBLANK_PIPE)] = { i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY },
+ [DRM_IOCTL_NR(DRM_I915_GET_VBLANK_PIPE)] = { i915_vblank_pipe_get, DRM_AUTH },
};
int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h
index 4cb3da5..5aa3e0e 100644
--- a/drivers/char/drm/i915_drm.h
+++ b/drivers/char/drm/i915_drm.h
@@ -124,6 +124,8 @@ typedef struct _drm_i915_sarea {
#define DRM_I915_INIT_HEAP 0x0a
#define DRM_I915_CMDBUFFER 0x0b
#define DRM_I915_DESTROY_HEAP 0x0c
+#define DRM_I915_SET_VBLANK_PIPE 0x0d
+#define DRM_I915_GET_VBLANK_PIPE 0x0e
#define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
#define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -138,6 +140,8 @@ typedef struct _drm_i915_sarea {
#define DRM_IOCTL_I915_INIT_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT_HEAP, drm_i915_mem_init_heap_t)
#define DRM_IOCTL_I915_CMDBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_CMDBUFFER, drm_i915_cmdbuffer_t)
#define DRM_IOCTL_I915_DESTROY_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_DESTROY_HEAP, drm_i915_mem_destroy_heap_t)
+#define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
+#define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
/* Allow drivers to submit batchbuffers directly to hardware, relying
* on the security mechanisms provided by hardware.
@@ -224,4 +228,13 @@ typedef struct drm_i915_mem_destroy_heap {
int region;
} drm_i915_mem_destroy_heap_t;
+/* Allow X server to configure which pipes to monitor for vblank signals
+ */
+#define DRM_I915_VBLANK_PIPE_A 1
+#define DRM_I915_VBLANK_PIPE_B 2
+
+typedef struct drm_i915_vblank_pipe {
+ int pipe;
+} drm_i915_vblank_pipe_t;
+
#endif /* _I915_DRM_H_ */
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
index 7a65666..2d56503 100644
--- a/drivers/char/drm/i915_drv.h
+++ b/drivers/char/drm/i915_drv.h
@@ -45,9 +45,10 @@
* 1.2: Add Power Management
* 1.3: Add vblank support
* 1.4: Fix cmdbuffer path, add heap destroy
+ * 1.5: Add vblank pipe configuration
*/
#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 4
+#define DRIVER_MINOR 5
#define DRIVER_PATCHLEVEL 0
typedef struct _drm_i915_ring_buffer {
@@ -96,6 +97,7 @@ typedef struct drm_i915_private {
int allow_batchbuffer;
struct mem_block *agp_heap;
unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
+ int vblank_pipe;
} drm_i915_private_t;
extern drm_ioctl_desc_t i915_ioctls[];
@@ -119,6 +121,8 @@ extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
extern void i915_driver_irq_preinstall(drm_device_t * dev);
extern void i915_driver_irq_postinstall(drm_device_t * dev);
extern void i915_driver_irq_uninstall(drm_device_t * dev);
+extern int i915_vblank_pipe_set(DRM_IOCTL_ARGS);
+extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS);
/* i915_mem.c */
extern int i915_mem_alloc(DRM_IOCTL_ARGS);
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
index a752afd..cd96cfa 100644
--- a/drivers/char/drm/i915_irq.c
+++ b/drivers/char/drm/i915_irq.c
@@ -44,7 +44,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
u16 temp;
temp = I915_READ16(I915REG_INT_IDENTITY_R);
- temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG);
+
+ temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG);
DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
@@ -58,7 +59,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
if (temp & USER_INT_FLAG)
DRM_WAKEUP(&dev_priv->irq_queue);
- if (temp & VSYNC_PIPEA_FLAG) {
+ if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
atomic_inc(&dev->vbl_received);
DRM_WAKEUP(&dev->vbl_queue);
drm_vbl_send_signals(dev);
@@ -182,6 +183,68 @@ int i915_irq_wait(DRM_IOCTL_ARGS)
return i915_wait_irq(dev, irqwait.irq_seq);
}
+static int i915_enable_interrupt (drm_device_t *dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ u16 flag;
+
+ flag = 0;
+ if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)
+ flag |= VSYNC_PIPEA_FLAG;
+ if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
+ flag |= VSYNC_PIPEB_FLAG;
+ if (dev_priv->vblank_pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
+ DRM_ERROR("%s called with invalid pipe 0x%x\n",
+ __FUNCTION__, dev_priv->vblank_pipe);
+ return DRM_ERR(EINVAL);
+ }
+ I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag);
+ return 0;
+}
+
+/* Set the vblank monitor pipe
+ */
+int i915_vblank_pipe_set(DRM_IOCTL_ARGS)
+{
+ DRM_DEVICE;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_vblank_pipe_t pipe;
+
+ if (!dev_priv) {
+ DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ return DRM_ERR(EINVAL);
+ }
+
+ DRM_COPY_FROM_USER_IOCTL(pipe, (drm_i915_vblank_pipe_t __user *) data,
+ sizeof(pipe));
+
+ dev_priv->vblank_pipe = pipe.pipe;
+ return i915_enable_interrupt (dev);
+}
+
+int i915_vblank_pipe_get(DRM_IOCTL_ARGS)
+{
+ DRM_DEVICE;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_vblank_pipe_t pipe;
+ u16 flag;
+
+ if (!dev_priv) {
+ DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ return DRM_ERR(EINVAL);
+ }
+
+ flag = I915_READ(I915REG_INT_ENABLE_R);
+ pipe.pipe = 0;
+ if (flag & VSYNC_PIPEA_FLAG)
+ pipe.pipe |= DRM_I915_VBLANK_PIPE_A;
+ if (flag & VSYNC_PIPEB_FLAG)
+ pipe.pipe |= DRM_I915_VBLANK_PIPE_B;
+ DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_pipe_t __user *) data, pipe,
+ sizeof(pipe));
+ return 0;
+}
+
/* drm_dma.h hooks
*/
void i915_driver_irq_preinstall(drm_device_t * dev)
@@ -197,7 +260,7 @@ void i915_driver_irq_postinstall(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | VSYNC_PIPEA_FLAG);
+ i915_enable_interrupt(dev);
DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
}
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index 7f949c9..5ad43ba 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -39,7 +39,7 @@
static int radeon_do_cleanup_cp(drm_device_t * dev);
/* CP microcode (from ATI) */
-static u32 R200_cp_microcode[][2] = {
+static const u32 R200_cp_microcode[][2] = {
{0x21007000, 0000000000},
{0x20007000, 0000000000},
{0x000000ab, 0x00000004},
@@ -298,7 +298,7 @@ static u32 R200_cp_microcode[][2] = {
{0000000000, 0000000000},
};
-static u32 radeon_cp_microcode[][2] = {
+static const u32 radeon_cp_microcode[][2] = {
{0x21007000, 0000000000},
{0x20007000, 0000000000},
{0x000000b4, 0x00000004},
@@ -557,7 +557,7 @@ static u32 radeon_cp_microcode[][2] = {
{0000000000, 0000000000},
};
-static u32 R300_cp_microcode[][2] = {
+static const u32 R300_cp_microcode[][2] = {
{0x4200e000, 0000000000},
{0x4000e000, 0000000000},
{0x000000af, 0x00000008},
diff --git a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h
index c8e279e..8d6350d 100644
--- a/drivers/char/drm/radeon_drm.h
+++ b/drivers/char/drm/radeon_drm.h
@@ -161,7 +161,8 @@
#define R200_EMIT_PP_TXCTLALL_3 91
#define R200_EMIT_PP_TXCTLALL_4 92
#define R200_EMIT_PP_TXCTLALL_5 93
-#define RADEON_MAX_STATE_PACKETS 94
+#define R200_EMIT_VAP_PVS_CNTL 94
+#define RADEON_MAX_STATE_PACKETS 95
/* Commands understood by cmd_buffer ioctl. More can be added but
* obviously these can't be removed or changed:
@@ -176,6 +177,7 @@
#define RADEON_CMD_WAIT 8 /* emit hw wait commands -- note:
* doesn't make the cpu wait, just
* the graphics hardware */
+#define RADEON_CMD_VECLINEAR 9 /* another r200 stopgap */
typedef union {
int i;
@@ -192,6 +194,9 @@ typedef union {
unsigned char cmd_type, offset, stride, count;
} vectors;
struct {
+ unsigned char cmd_type, addr_lo, addr_hi, count;
+ } veclinear;
+ struct {
unsigned char cmd_type, buf_idx, pad0, pad1;
} dma;
struct {
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
index 78345ce..e5a256f 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -38,7 +38,7 @@
#define DRIVER_NAME "radeon"
#define DRIVER_DESC "ATI Radeon"
-#define DRIVER_DATE "20060225"
+#define DRIVER_DATE "20060524"
/* Interface history:
*
@@ -93,9 +93,11 @@
* 1.22- Add support for texture cache flushes (R300_TX_CNTL)
* 1.23- Add new radeon memory map work from benh
* 1.24- Add general-purpose packet for manipulating scratch registers (r300)
+ * 1.25- Add support for r200 vertex programs (R200_EMIT_VAP_PVS_CNTL,
+ * new packet type)
*/
#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 24
+#define DRIVER_MINOR 25
#define DRIVER_PATCHLEVEL 0
/*
@@ -884,6 +886,8 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
#define RADEON_PP_CUBIC_OFFSET_T1_0 0x1e00
#define RADEON_PP_CUBIC_OFFSET_T2_0 0x1e14
+#define RADEON_SE_TCL_STATE_FLUSH 0x2284
+
#define SE_VAP_CNTL__TCL_ENA_MASK 0x00000001
#define SE_VAP_CNTL__FORCE_W_TO_ONE_MASK 0x00010000
#define SE_VAP_CNTL__VF_MAX_VTX_NUM__SHIFT 0x00000012
@@ -905,6 +909,8 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
#define R200_PP_AFS_0 0x2f80
#define R200_PP_AFS_1 0x2f00 /* same as txcblend_0 */
+#define R200_VAP_PVS_CNTL_1 0x22D0
+
/* Constants */
#define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */
diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c
index c5b8f77..5bb2234 100644
--- a/drivers/char/drm/radeon_state.c
+++ b/drivers/char/drm/radeon_state.c
@@ -249,6 +249,7 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
case R200_EMIT_PP_TXCTLALL_3:
case R200_EMIT_PP_TXCTLALL_4:
case R200_EMIT_PP_TXCTLALL_5:
+ case R200_EMIT_VAP_PVS_CNTL:
/* These packets don't contain memory offsets */
break;
@@ -626,6 +627,7 @@ static struct {
{R200_PP_TXFILTER_3, 8, "R200_PP_TXCTLALL_3"},
{R200_PP_TXFILTER_4, 8, "R200_PP_TXCTLALL_4"},
{R200_PP_TXFILTER_5, 8, "R200_PP_TXCTLALL_5"},
+ {R200_VAP_PVS_CNTL_1, 2, "R200_VAP_PVS_CNTL"},
};
/* ================================================================
@@ -2595,7 +2597,8 @@ static __inline__ int radeon_emit_vectors(drm_radeon_private_t *dev_priv,
int stride = header.vectors.stride;
RING_LOCALS;
- BEGIN_RING(3 + sz);
+ BEGIN_RING(5 + sz);
+ OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
OUT_RING(start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
@@ -2607,6 +2610,32 @@ static __inline__ int radeon_emit_vectors(drm_radeon_private_t *dev_priv,
return 0;
}
+static __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv,
+ drm_radeon_cmd_header_t header,
+ drm_radeon_kcmd_buffer_t *cmdbuf)
+{
+ int sz = header.veclinear.count * 4;
+ int start = header.veclinear.addr_lo | (header.veclinear.addr_hi << 8);
+ RING_LOCALS;
+
+ if (!sz)
+ return 0;
+ if (sz * 4 > cmdbuf->bufsz)
+ return DRM_ERR(EINVAL);
+
+ BEGIN_RING(5 + sz);
+ OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
+ OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
+ OUT_RING(start | (1 << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
+ OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
+ OUT_RING_TABLE(cmdbuf->buf, sz);
+ ADVANCE_RING();
+
+ cmdbuf->buf += sz * sizeof(int);
+ cmdbuf->bufsz -= sz * sizeof(int);
+ return 0;
+}
+
static int radeon_emit_packet3(drm_device_t * dev,
drm_file_t * filp_priv,
drm_radeon_kcmd_buffer_t *cmdbuf)
@@ -2865,6 +2894,14 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
goto err;
}
break;
+ case RADEON_CMD_VECLINEAR:
+ DRM_DEBUG("RADEON_CMD_VECLINEAR\n");
+ if (radeon_emit_veclinear(dev_priv, header, &cmdbuf)) {
+ DRM_ERROR("radeon_emit_veclinear failed\n");
+ goto err;
+ }
+ break;
+
default:
DRM_ERROR("bad cmd_type %d at %p\n",
header.header.cmd_type,
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index 09dc4b0..922174d 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -1212,7 +1212,7 @@ static void rs_put_char(struct tty_struct *tty, unsigned char ch)
if (serial_paranoia_check(info, tty->name, "rs_put_char"))
return;
- if (!tty || !info->xmit_buf)
+ if (!info->xmit_buf)
return;
spin_lock_irqsave(&info->lock, flags);
@@ -1256,7 +1256,7 @@ static int rs_write(struct tty_struct * tty,
if (serial_paranoia_check(info, tty->name, "rs_write"))
return 0;
- if (!tty || !info->xmit_buf)
+ if (!info->xmit_buf)
return 0;
while (1) {
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index ef140eb..07473cd 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -925,11 +925,8 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
status = acpi_resource_to_address64(res, &addr);
if (ACPI_SUCCESS(status)) {
- unsigned long size;
-
- size = addr.maximum - addr.minimum + 1;
hdp->hd_phys_address = addr.minimum;
- hdp->hd_address = ioremap(addr.minimum, size);
+ hdp->hd_address = ioremap(addr.minimum, addr.address_length);
if (hpet_is_known(hdp)) {
printk(KERN_DEBUG "%s: 0x%lx is busy\n",
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index 2b6a56b..a5c6a9d 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -553,7 +553,6 @@ static int hvc_chars_in_buffer(struct tty_struct *tty)
#define HVC_POLL_READ 0x00000001
#define HVC_POLL_WRITE 0x00000002
-#define HVC_POLL_QUICK 0x00000004
static int hvc_poll(struct hvc_struct *hp)
{
@@ -568,6 +567,7 @@ static int hvc_poll(struct hvc_struct *hp)
/* Push pending writes */
if (hp->n_outbuf > 0)
hvc_push(hp);
+
/* Reschedule us if still some write pending */
if (hp->n_outbuf > 0)
poll_mask |= HVC_POLL_WRITE;
@@ -680,7 +680,7 @@ int khvcd(void *unused)
poll_mask |= HVC_POLL_READ;
if (hvc_kicked)
continue;
- if (poll_mask & HVC_POLL_QUICK) {
+ if (poll_mask & HVC_POLL_WRITE) {
yield();
continue;
}
diff --git a/drivers/char/hvc_rtas.c b/drivers/char/hvc_rtas.c
index 83364ea..57106e02 100644
--- a/drivers/char/hvc_rtas.c
+++ b/drivers/char/hvc_rtas.c
@@ -41,37 +41,28 @@
#define hvc_rtas_cookie 0x67781e15
struct hvc_struct *hvc_rtas_dev;
-#define RTASCONS_PUT_ATTEMPTS 16
-
static int rtascons_put_char_token = RTAS_UNKNOWN_SERVICE;
static int rtascons_get_char_token = RTAS_UNKNOWN_SERVICE;
-static int rtascons_put_delay = 100;
-module_param_named(put_delay, rtascons_put_delay, int, 0644);
-static inline int hvc_rtas_write_console(uint32_t vtermno, const char *buf, int count)
+static inline int hvc_rtas_write_console(uint32_t vtermno, const char *buf,
+ int count)
{
- int done;
+ int i;
- /* if there is more than one character to be displayed, wait a bit */
- for (done = 0; done < count; done++) {
- int result;
- result = rtas_call(rtascons_put_char_token, 1, 1, NULL, buf[done]);
- if (result)
+ for (i = 0; i < count; i++) {
+ if (rtas_call(rtascons_put_char_token, 1, 1, NULL, buf[i]))
break;
}
- /* the calling routine expects to receive the number of bytes sent */
- return done;
+
+ return i;
}
static int hvc_rtas_read_console(uint32_t vtermno, char *buf, int count)
{
- int i;
+ int i, c;
for (i = 0; i < count; i++) {
- int c, err;
-
- err = rtas_call(rtascons_get_char_token, 0, 2, &c);
- if (err)
+ if (rtas_call(rtascons_get_char_token, 0, 2, &c))
break;
buf[i] = c;
@@ -106,7 +97,9 @@ static int hvc_rtas_init(void)
hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops);
if (IS_ERR(hp))
return PTR_ERR(hp);
+
hvc_rtas_dev = hp;
+
return 0;
}
module_init(hvc_rtas_init);
@@ -114,8 +107,8 @@ module_init(hvc_rtas_init);
/* This will tear down the tty portion of the driver */
static void __exit hvc_rtas_exit(void)
{
- /* Really the fun isn't over until the worker thread breaks down and the
- * tty cleans up */
+ /* Really the fun isn't over until the worker thread breaks down and
+ * the tty cleans up */
if (hvc_rtas_dev)
hvc_remove(hvc_rtas_dev);
}
@@ -127,12 +120,14 @@ static int hvc_rtas_console_init(void)
rtascons_put_char_token = rtas_token("put-term-char");
if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE)
return -EIO;
+
rtascons_get_char_token = rtas_token("get-term-char");
if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE)
return -EIO;
- hvc_instantiate(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops );
+ hvc_instantiate(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops);
add_preferred_console("hvc", 0, NULL);
+
return 0;
}
console_initcall(hvc_rtas_console_init);
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
index a952218..a0370ed 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -1179,7 +1179,7 @@ static int __init hvsi_init(void)
if (tty_register_driver(hvsi_driver))
panic("Couldn't register hvsi console driver\n");
- printk(KERN_INFO "HVSI: registered %i devices\n", hvsi_count);
+ printk(KERN_DEBUG "HVSI: registered %i devices\n", hvsi_count);
return 0;
}
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index 03db1cb..9ab33c3 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -305,7 +305,7 @@ static struct class *ip2_class;
// Some functions to keep track of what irq's we have
-static int __init
+static int
is_valid_irq(int irq)
{
int *i = Valid_Irqs;
@@ -316,14 +316,14 @@ is_valid_irq(int irq)
return (*i);
}
-static void __init
+static void
mark_requested_irq( char irq )
{
rirqs[iindx++] = irq;
}
#ifdef MODULE
-static int __init
+static int
clear_requested_irq( char irq )
{
int i;
@@ -337,7 +337,7 @@ clear_requested_irq( char irq )
}
#endif
-static int __init
+static int
have_requested_irq( char irq )
{
// array init to zeros so 0 irq will not be requested as a side effect
@@ -818,7 +818,7 @@ EXPORT_SYMBOL(ip2_loadmain);
/* the board, the channel structures are initialized, and the board details */
/* are reported on the console. */
/******************************************************************************/
-static void __init
+static void
ip2_init_board( int boardnum )
{
int i;
@@ -961,7 +961,7 @@ err_initialize:
/* EISA motherboard, or no valid board ID is selected it returns 0. Otherwise */
/* it returns the base address of the controller. */
/******************************************************************************/
-static unsigned short __init
+static unsigned short
find_eisa_board( int start_slot )
{
int i, j;
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 2d11ddd..8f88671 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -212,24 +212,16 @@ static int set_param_str(const char *val, struct kernel_param *kp)
{
action_fn fn = (action_fn) kp->arg;
int rv = 0;
- const char *end;
- char valcp[16];
- int len;
-
- /* Truncate leading and trailing spaces. */
- while (isspace(*val))
- val++;
- end = val + strlen(val) - 1;
- while ((end >= val) && isspace(*end))
- end--;
- len = end - val + 1;
- if (len > sizeof(valcp) - 1)
- return -EINVAL;
- memcpy(valcp, val, len);
- valcp[len] = '\0';
+ char *dup, *s;
+
+ dup = kstrdup(val, GFP_KERNEL);
+ if (!dup)
+ return -ENOMEM;
+
+ s = strstrip(dup);
down_read(&register_sem);
- rv = fn(valcp, NULL);
+ rv = fn(s, NULL);
if (rv)
goto out_unlock;
@@ -239,6 +231,7 @@ static int set_param_str(const char *val, struct kernel_param *kp)
out_unlock:
up_read(&register_sem);
+ kfree(dup);
return rv;
}
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index e9ebaba..efaaa19 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -1145,7 +1145,7 @@ static int isicom_write(struct tty_struct *tty, const unsigned char *buf,
if (isicom_paranoia_check(port, tty->name, "isicom_write"))
return 0;
- if (!tty || !port->xmit_buf)
+ if (!port->xmit_buf)
return 0;
spin_lock_irqsave(&card->card_lock, flags);
@@ -1180,7 +1180,7 @@ static void isicom_put_char(struct tty_struct *tty, unsigned char ch)
if (isicom_paranoia_check(port, tty->name, "isicom_put_char"))
return;
- if (!tty || !port->xmit_buf)
+ if (!port->xmit_buf)
return;
spin_lock_irqsave(&card->card_lock, flags);
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 5755b7e..edd996f 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -39,6 +39,7 @@
#include <linux/vt_kern.h>
#include <linux/sysrq.h>
#include <linux/input.h>
+#include <linux/reboot.h>
static void kbd_disconnect(struct input_handle *handle);
extern void ctrl_alt_del(void);
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c
index 1b05fa6..d65b310 100644
--- a/drivers/char/mmtimer.c
+++ b/drivers/char/mmtimer.c
@@ -329,7 +329,6 @@ static int mmtimer_mmap(struct file *file, struct vm_area_struct *vma)
if (PAGE_SIZE > (1 << 16))
return -ENOSYS;
- vma->vm_flags |= (VM_IO | VM_SHM | VM_LOCKED );
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
mmtimer_addr = __pa(RTC_COUNTER_ADDR);
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 0fb2fb9..645d9d7 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -9,7 +9,7 @@
* 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.
+ * (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
@@ -71,8 +71,8 @@
#define MXSERMAJOR 174
#define MXSERCUMAJOR 175
-#define MXSER_EVENT_TXLOW 1
-#define MXSER_EVENT_HANGUP 2
+#define MXSER_EVENT_TXLOW 1
+#define MXSER_EVENT_HANGUP 2
#define MXSER_BOARDS 4 /* Max. boards */
#define MXSER_PORTS 32 /* Max. ports */
@@ -92,7 +92,8 @@
#define UART_MCR_AFE 0x20
#define UART_LSR_SPECIAL 0x1E
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|IXON|IXOFF))
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|\
+ IXON|IXOFF))
#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
@@ -152,27 +153,27 @@ static char *mxser_brdname[] = {
};
static int mxser_numports[] = {
- 8, // C168-ISA
- 4, // C104-ISA
- 4, // CI104J
- 8, // C168-PCI
- 4, // C104-PCI
- 2, // C102-ISA
- 2, // CI132
- 4, // CI134
- 2, // CP132
- 4, // CP114
- 4, // CT114
- 2, // CP102
- 4, // CP104U
- 8, // CP168U
- 2, // CP132U
- 4, // CP134U
- 4, // CP104JU
- 8, // RC7000
- 8, // CP118U
- 2, // CP102UL
- 2, // CP102U
+ 8, /* C168-ISA */
+ 4, /* C104-ISA */
+ 4, /* CI104J */
+ 8, /* C168-PCI */
+ 4, /* C104-PCI */
+ 2, /* C102-ISA */
+ 2, /* CI132 */
+ 4, /* CI134 */
+ 2, /* CP132 */
+ 4, /* CP114 */
+ 4, /* CT114 */
+ 2, /* CP102 */
+ 4, /* CP104U */
+ 8, /* CP168U */
+ 2, /* CP132U */
+ 4, /* CP134U */
+ 4, /* CP104JU */
+ 8, /* RC7000 */
+ 8, /* CP118U */
+ 2, /* CP102UL */
+ 2, /* CP102U */
};
#define UART_TYPE_NUM 2
@@ -182,7 +183,7 @@ static const unsigned int Gmoxa_uart_id[UART_TYPE_NUM] = {
MOXA_MUST_MU860_HWID
};
-// This is only for PCI
+/* This is only for PCI */
#define UART_INFO_NUM 3
struct mxpciuart_info {
int type;
@@ -231,7 +232,7 @@ MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
typedef struct _moxa_pci_info {
unsigned short busNum;
unsigned short devNum;
- struct pci_dev *pdev; // add by Victor Yu. 06-23-2003
+ struct pci_dev *pdev; /* add by Victor Yu. 06-23-2003 */
} moxa_pci_info;
static int ioaddr[MXSER_BOARDS] = { 0, 0, 0, 0 };
@@ -280,6 +281,7 @@ struct mxser_mon_ext {
int fifo[32];
int iftype[32];
};
+
struct mxser_hwconf {
int board_type;
int ports;
@@ -290,9 +292,9 @@ struct mxser_hwconf {
int ioaddr[MXSER_PORTS_PER_BOARD];
int baud_base[MXSER_PORTS_PER_BOARD];
moxa_pci_info pciInfo;
- int IsMoxaMustChipFlag; // add by Victor Yu. 08-30-2002
- int MaxCanSetBaudRate[MXSER_PORTS_PER_BOARD]; // add by Victor Yu. 09-04-2002
- int opmode_ioaddr[MXSER_PORTS_PER_BOARD]; // add by Victor Yu. 01-05-2004
+ int IsMoxaMustChipFlag; /* add by Victor Yu. 08-30-2002 */
+ int MaxCanSetBaudRate[MXSER_PORTS_PER_BOARD]; /* add by Victor Yu. 09-04-2002 */
+ int opmode_ioaddr[MXSER_PORTS_PER_BOARD]; /* add by Victor Yu. 01-05-2004 */
};
struct mxser_struct {
@@ -334,9 +336,9 @@ struct mxser_struct {
wait_queue_head_t delta_msr_wait;
struct async_icount icount; /* kernel counters for the 4 input interrupts */
int timeout;
- int IsMoxaMustChipFlag; // add by Victor Yu. 08-30-2002
- int MaxCanSetBaudRate; // add by Victor Yu. 09-04-2002
- int opmode_ioaddr; // add by Victor Yu. 01-05-2004
+ int IsMoxaMustChipFlag; /* add by Victor Yu. 08-30-2002 */
+ int MaxCanSetBaudRate; /* add by Victor Yu. 09-04-2002 */
+ int opmode_ioaddr; /* add by Victor Yu. 01-05-2004 */
unsigned char stop_rx;
unsigned char ldisc_stop_rx;
long realbaud;
@@ -345,7 +347,6 @@ struct mxser_struct {
spinlock_t slock;
};
-
struct mxser_mstatus {
tcflag_t cflag;
int cts;
@@ -358,7 +359,7 @@ static struct mxser_mstatus GMStatus[MXSER_PORTS];
static int mxserBoardCAP[MXSER_BOARDS] = {
0, 0, 0, 0
- /* 0x180, 0x280, 0x200, 0x320 */
+ /* 0x180, 0x280, 0x200, 0x320 */
};
static struct tty_driver *mxvar_sdriver;
@@ -386,7 +387,7 @@ static struct mxser_hwconf mxsercfg[MXSER_BOARDS];
static void mxser_getcfg(int board, struct mxser_hwconf *hwconf);
static int mxser_init(void);
-//static void mxser_poll(unsigned long);
+/* static void mxser_poll(unsigned long); */
static int mxser_get_ISA_conf(int, struct mxser_hwconf *);
static int mxser_get_PCI_conf(int, int, int, struct mxser_hwconf *);
static void mxser_do_softint(void *);
@@ -440,18 +441,18 @@ static int CheckIsMoxaMust(int io)
SET_MOXA_MUST_XON1_VALUE(io, 0x11);
if ((hwid = inb(io + UART_MCR)) != 0) {
outb(oldmcr, io + UART_MCR);
- return (MOXA_OTHER_UART);
+ return MOXA_OTHER_UART;
}
GET_MOXA_MUST_HARDWARE_ID(io, &hwid);
for (i = 0; i < UART_TYPE_NUM; i++) {
if (hwid == Gmoxa_uart_id[i])
- return (int) hwid;
+ return (int)hwid;
}
return MOXA_OTHER_UART;
}
-// above is modified by Victor Yu. 08-15-2002
+/* above is modified by Victor Yu. 08-15-2002 */
static struct tty_operations mxser_ops = {
.open = mxser_open,
@@ -504,7 +505,6 @@ static void __exit mxser_module_exit(void)
else
printk(KERN_ERR "Couldn't unregister MOXA Smartio/Industio family serial driver\n");
-
for (i = 0; i < MXSER_BOARDS; i++) {
struct pci_dev *pdev;
@@ -513,7 +513,7 @@ static void __exit mxser_module_exit(void)
else {
pdev = mxsercfg[i].pciInfo.pdev;
free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]);
- if (pdev != NULL) { //PCI
+ if (pdev != NULL) { /* PCI */
release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2));
release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3));
} else {
@@ -524,7 +524,6 @@ static void __exit mxser_module_exit(void)
}
if (verbose)
printk(KERN_DEBUG "Done.\n");
-
}
static void process_txrx_fifo(struct mxser_struct *info)
@@ -558,8 +557,10 @@ static int mxser_initbrd(int board, struct mxser_hwconf *hwconf)
n = board * MXSER_PORTS_PER_BOARD;
info = &mxvar_table[n];
/*if (verbose) */ {
- printk(KERN_DEBUG " ttyM%d - ttyM%d ", n, n + hwconf->ports - 1);
- printk(" max. baud rate = %d bps.\n", hwconf->MaxCanSetBaudRate[0]);
+ printk(KERN_DEBUG " ttyM%d - ttyM%d ",
+ n, n + hwconf->ports - 1);
+ printk(" max. baud rate = %d bps.\n",
+ hwconf->MaxCanSetBaudRate[0]);
}
for (i = 0; i < hwconf->ports; i++, n++, info++) {
@@ -568,12 +569,12 @@ static int mxser_initbrd(int board, struct mxser_hwconf *hwconf)
info->irq = hwconf->irq;
info->vector = hwconf->vector;
info->vectormask = hwconf->vector_mask;
- info->opmode_ioaddr = hwconf->opmode_ioaddr[i]; // add by Victor Yu. 01-05-2004
+ info->opmode_ioaddr = hwconf->opmode_ioaddr[i]; /* add by Victor Yu. 01-05-2004 */
info->stop_rx = 0;
info->ldisc_stop_rx = 0;
info->IsMoxaMustChipFlag = hwconf->IsMoxaMustChipFlag;
- //Enhance mode enabled here
+ /* Enhance mode enabled here */
if (info->IsMoxaMustChipFlag != MOXA_OTHER_UART) {
ENABLE_MOXA_MUST_ENCHANCE_MODE(info->base);
}
@@ -606,22 +607,25 @@ static int mxser_initbrd(int board, struct mxser_hwconf *hwconf)
/* before set INT ISR, disable all int */
for (i = 0; i < hwconf->ports; i++) {
- outb(inb(hwconf->ioaddr[i] + UART_IER) & 0xf0, hwconf->ioaddr[i] + UART_IER);
+ outb(inb(hwconf->ioaddr[i] + UART_IER) & 0xf0,
+ hwconf->ioaddr[i] + UART_IER);
}
n = board * MXSER_PORTS_PER_BOARD;
info = &mxvar_table[n];
- retval = request_irq(hwconf->irq, mxser_interrupt, IRQ_T(info), "mxser", info);
+ retval = request_irq(hwconf->irq, mxser_interrupt, IRQ_T(info),
+ "mxser", info);
if (retval) {
- printk(KERN_ERR "Board %d: %s", board, mxser_brdname[hwconf->board_type - 1]);
- printk(" Request irq fail,IRQ (%d) may be conflit with another device.\n", info->irq);
+ printk(KERN_ERR "Board %d: %s",
+ board, mxser_brdname[hwconf->board_type - 1]);
+ printk(" Request irq failed, IRQ (%d) may conflict with"
+ " another device.\n", info->irq);
return retval;
}
return 0;
}
-
static void mxser_getcfg(int board, struct mxser_hwconf *hwconf)
{
mxsercfg[board] = *hwconf;
@@ -631,26 +635,27 @@ static void mxser_getcfg(int board, struct mxser_hwconf *hwconf)
static int mxser_get_PCI_conf(int busnum, int devnum, int board_type, struct mxser_hwconf *hwconf)
{
int i, j;
-// unsigned int val;
+ /* unsigned int val; */
unsigned int ioaddress;
struct pci_dev *pdev = hwconf->pciInfo.pdev;
- //io address
+ /* io address */
hwconf->board_type = board_type;
hwconf->ports = mxser_numports[board_type - 1];
ioaddress = pci_resource_start(pdev, 2);
- request_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2), "mxser(IO)");
+ request_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2),
+ "mxser(IO)");
- for (i = 0; i < hwconf->ports; i++) {
+ for (i = 0; i < hwconf->ports; i++)
hwconf->ioaddr[i] = ioaddress + 8 * i;
- }
- //vector
+ /* vector */
ioaddress = pci_resource_start(pdev, 3);
- request_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3), "mxser(vector)");
+ request_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3),
+ "mxser(vector)");
hwconf->vector = ioaddress;
- //irq
+ /* irq */
hwconf->irq = hwconf->pciInfo.pdev->irq;
hwconf->IsMoxaMustChipFlag = CheckIsMoxaMust(hwconf->ioaddr[0]);
@@ -663,7 +668,7 @@ static int mxser_get_PCI_conf(int busnum, int devnum, int board_type, struct mxs
if (Gpci_uart_info[j].type == hwconf->IsMoxaMustChipFlag) {
hwconf->MaxCanSetBaudRate[i] = Gpci_uart_info[j].max_baud;
- //exception....CP-102
+ /* exception....CP-102 */
if (board_type == MXSER_BOARD_CP102)
hwconf->MaxCanSetBaudRate[i] = 921600;
break;
@@ -678,15 +683,15 @@ static int mxser_get_PCI_conf(int busnum, int devnum, int board_type, struct mxs
else
hwconf->opmode_ioaddr[i] = ioaddress + 0x0c;
}
- outb(0, ioaddress + 4); // default set to RS232 mode
- outb(0, ioaddress + 0x0c); //default set to RS232 mode
+ outb(0, ioaddress + 4); /* default set to RS232 mode */
+ outb(0, ioaddress + 0x0c); /* default set to RS232 mode */
}
for (i = 0; i < hwconf->ports; i++) {
hwconf->vector_mask |= (1 << i);
hwconf->baud_base[i] = 921600;
}
- return (0);
+ return 0;
}
#endif
@@ -707,7 +712,8 @@ static int mxser_init(void)
mxsercfg[i].board_type = -1;
}
- printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n", MXSER_VERSION);
+ printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n",
+ MXSER_VERSION);
/* Initialize the tty_driver structure */
memset(mxvar_sdriver, 0, sizeof(struct tty_driver));
@@ -719,7 +725,7 @@ static int mxser_init(void)
mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL;
mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
mxvar_sdriver->init_termios = tty_std_termios;
- mxvar_sdriver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(mxvar_sdriver, &mxser_ops);
mxvar_sdriver->ttys = mxvar_tty;
@@ -739,23 +745,29 @@ static int mxser_init(void)
/* Start finding ISA boards here */
for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
int cap;
+
if (!(cap = mxserBoardCAP[b]))
continue;
retval = mxser_get_ISA_conf(cap, &hwconf);
if (retval != 0)
- printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n", mxser_brdname[hwconf.board_type - 1], ioaddr[b]);
+ printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n",
+ mxser_brdname[hwconf.board_type - 1], ioaddr[b]);
if (retval <= 0) {
if (retval == MXSER_ERR_IRQ)
- printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+ printk(KERN_ERR "Invalid interrupt number, "
+ "board not configured\n");
else if (retval == MXSER_ERR_IRQ_CONFLIT)
- printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+ printk(KERN_ERR "Invalid interrupt number, "
+ "board not configured\n");
else if (retval == MXSER_ERR_VECTOR)
- printk(KERN_ERR "Invalid interrupt vector,board not configured\n");
+ printk(KERN_ERR "Invalid interrupt vector, "
+ "board not configured\n");
else if (retval == MXSER_ERR_IOADDR)
- printk(KERN_ERR "Invalid I/O address,board not configured\n");
+ printk(KERN_ERR "Invalid I/O address, "
+ "board not configured\n");
continue;
}
@@ -765,35 +777,43 @@ static int mxser_init(void)
hwconf.pciInfo.pdev = NULL;
mxser_getcfg(m, &hwconf);
- //init mxsercfg first, or mxsercfg data is not correct on ISR.
- //mxser_initbrd will hook ISR.
+ /*
+ * init mxsercfg first,
+ * or mxsercfg data is not correct on ISR.
+ */
+ /* mxser_initbrd will hook ISR. */
if (mxser_initbrd(m, &hwconf) < 0)
continue;
-
m++;
}
/* Start finding ISA boards from module arg */
for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
int cap;
+
if (!(cap = ioaddr[b]))
continue;
retval = mxser_get_ISA_conf(cap, &hwconf);
if (retval != 0)
- printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n", mxser_brdname[hwconf.board_type - 1], ioaddr[b]);
+ printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n",
+ mxser_brdname[hwconf.board_type - 1], ioaddr[b]);
if (retval <= 0) {
if (retval == MXSER_ERR_IRQ)
- printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+ printk(KERN_ERR "Invalid interrupt number, "
+ "board not configured\n");
else if (retval == MXSER_ERR_IRQ_CONFLIT)
- printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+ printk(KERN_ERR "Invalid interrupt number, "
+ "board not configured\n");
else if (retval == MXSER_ERR_VECTOR)
- printk(KERN_ERR "Invalid interrupt vector,board not configured\n");
+ printk(KERN_ERR "Invalid interrupt vector, "
+ "board not configured\n");
else if (retval == MXSER_ERR_IOADDR)
- printk(KERN_ERR "Invalid I/O address,board not configured\n");
+ printk(KERN_ERR "Invalid I/O address, "
+ "board not configured\n");
continue;
}
@@ -803,8 +823,11 @@ static int mxser_init(void)
hwconf.pciInfo.pdev = NULL;
mxser_getcfg(m, &hwconf);
- //init mxsercfg first, or mxsercfg data is not correct on ISR.
- //mxser_initbrd will hook ISR.
+ /*
+ * init mxsercfg first,
+ * or mxsercfg data is not correct on ISR.
+ */
+ /* mxser_initbrd will hook ISR. */
if (mxser_initbrd(m, &hwconf) < 0)
continue;
@@ -817,7 +840,8 @@ static int mxser_init(void)
index = 0;
b = 0;
while (b < n) {
- pdev = pci_find_device(mxser_pcibrds[b].vendor, mxser_pcibrds[b].device, pdev);
+ pdev = pci_find_device(mxser_pcibrds[b].vendor,
+ mxser_pcibrds[b].device, pdev);
if (pdev == NULL) {
b++;
continue;
@@ -825,30 +849,48 @@ static int mxser_init(void)
hwconf.pciInfo.busNum = busnum = pdev->bus->number;
hwconf.pciInfo.devNum = devnum = PCI_SLOT(pdev->devfn) << 3;
hwconf.pciInfo.pdev = pdev;
- printk(KERN_INFO "Found MOXA %s board(BusNo=%d,DevNo=%d)\n", mxser_brdname[(int) (mxser_pcibrds[b].driver_data) - 1], busnum, devnum >> 3);
+ printk(KERN_INFO "Found MOXA %s board(BusNo=%d,DevNo=%d)\n",
+ mxser_brdname[(int) (mxser_pcibrds[b].driver_data) - 1],
+ busnum, devnum >> 3);
index++;
- if (m >= MXSER_BOARDS) {
- printk(KERN_ERR "Too many Smartio/Industio family boards find (maximum %d),board not configured\n", MXSER_BOARDS);
- } else {
+ if (m >= MXSER_BOARDS)
+ printk(KERN_ERR
+ "Too many Smartio/Industio family boards find "
+ "(maximum %d), board not configured\n",
+ MXSER_BOARDS);
+ else {
if (pci_enable_device(pdev)) {
- printk(KERN_ERR "Moxa SmartI/O PCI enable fail !\n");
+ printk(KERN_ERR "Moxa SmartI/O PCI enable "
+ "fail !\n");
continue;
}
- retval = mxser_get_PCI_conf(busnum, devnum, (int) mxser_pcibrds[b].driver_data, &hwconf);
+ retval = mxser_get_PCI_conf(busnum, devnum,
+ (int)mxser_pcibrds[b].driver_data,
+ &hwconf);
if (retval < 0) {
if (retval == MXSER_ERR_IRQ)
- printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+ printk(KERN_ERR
+ "Invalid interrupt number, "
+ "board not configured\n");
else if (retval == MXSER_ERR_IRQ_CONFLIT)
- printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+ printk(KERN_ERR
+ "Invalid interrupt number, "
+ "board not configured\n");
else if (retval == MXSER_ERR_VECTOR)
- printk(KERN_ERR "Invalid interrupt vector,board not configured\n");
+ printk(KERN_ERR
+ "Invalid interrupt vector, "
+ "board not configured\n");
else if (retval == MXSER_ERR_IOADDR)
- printk(KERN_ERR "Invalid I/O address,board not configured\n");
+ printk(KERN_ERR
+ "Invalid I/O address, "
+ "board not configured\n");
continue;
}
mxser_getcfg(m, &hwconf);
- //init mxsercfg first, or mxsercfg data is not correct on ISR.
- //mxser_initbrd will hook ISR.
+ /* init mxsercfg first,
+ * or mxsercfg data is not correct on ISR.
+ */
+ /* mxser_initbrd will hook ISR. */
if (mxser_initbrd(m, &hwconf) < 0)
continue;
m++;
@@ -858,7 +900,8 @@ static int mxser_init(void)
retval = tty_register_driver(mxvar_sdriver);
if (retval) {
- printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family driver !\n");
+ printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family"
+ " driver !\n");
put_tty_driver(mxvar_sdriver);
for (i = 0; i < MXSER_BOARDS; i++) {
@@ -866,7 +909,7 @@ static int mxser_init(void)
continue;
else {
free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]);
- //todo: release io, vector
+ /* todo: release io, vector */
}
}
return retval;
@@ -877,7 +920,7 @@ static int mxser_init(void)
static void mxser_do_softint(void *private_)
{
- struct mxser_struct *info = (struct mxser_struct *) private_;
+ struct mxser_struct *info = private_;
struct tty_struct *tty;
tty = info->tty;
@@ -926,7 +969,7 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
return -ENODEV;
info = mxvar_table + line;
if (!info->base)
- return (-ENODEV);
+ return -ENODEV;
tty->driver_data = info;
info->tty = tty;
@@ -935,11 +978,11 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
*/
retval = mxser_startup(info);
if (retval)
- return (retval);
+ return retval;
retval = mxser_block_til_ready(tty, filp, info);
if (retval)
- return (retval);
+ return retval;
info->count++;
@@ -955,11 +998,12 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
info->pgrp = process_group(current);
clear_bit(TTY_DONT_FLIP, &tty->flags);
- //status = mxser_get_msr(info->base, 0, info->port);
- //mxser_check_modem_status(info, status);
+ /*
+ status = mxser_get_msr(info->base, 0, info->port);
+ mxser_check_modem_status(info, status);
+ */
-/* unmark here for very high baud rate (ex. 921600 bps) used
-*/
+/* unmark here for very high baud rate (ex. 921600 bps) used */
tty->low_latency = 1;
return 0;
}
@@ -972,7 +1016,7 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
*/
static void mxser_close(struct tty_struct *tty, struct file *filp)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long timeout;
unsigned long flags;
@@ -997,11 +1041,13 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
* one, we've got real problems, since it means the
* serial port won't be shutdown.
*/
- printk(KERN_ERR "mxser_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count);
+ printk(KERN_ERR "mxser_close: bad serial port count; "
+ "tty->count is 1, info->count is %d\n", info->count);
info->count = 1;
}
if (--info->count < 0) {
- printk(KERN_ERR "mxser_close: bad serial port count for ttys%d: %d\n", info->port, info->count);
+ printk(KERN_ERR "mxser_close: bad serial port count for "
+ "ttys%d: %d\n", info->port, info->count);
info->count = 0;
}
if (info->count) {
@@ -1056,7 +1102,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
ld = tty_ldisc_ref(tty);
if (ld) {
- if(ld->flush_buffer)
+ if (ld->flush_buffer)
ld->flush_buffer(tty);
tty_ldisc_deref(ld);
}
@@ -1078,31 +1124,34 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
int c, total = 0;
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long flags;
- if (!tty || !info->xmit_buf)
- return (0);
+ if (!info->xmit_buf)
+ return 0;
while (1) {
- c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head));
+ c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
if (c <= 0)
break;
memcpy(info->xmit_buf + info->xmit_head, buf, c);
spin_lock_irqsave(&info->slock, flags);
- info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1);
+ info->xmit_head = (info->xmit_head + c) &
+ (SERIAL_XMIT_SIZE - 1);
info->xmit_cnt += c;
spin_unlock_irqrestore(&info->slock, flags);
buf += c;
count -= c;
total += c;
-
}
if (info->xmit_cnt && !tty->stopped && !(info->IER & UART_IER_THRI)) {
- if (!tty->hw_stopped || (info->type == PORT_16550A) || (info->IsMoxaMustChipFlag)) {
+ if (!tty->hw_stopped ||
+ (info->type == PORT_16550A) ||
+ (info->IsMoxaMustChipFlag)) {
spin_lock_irqsave(&info->slock, flags);
info->IER |= UART_IER_THRI;
outb(info->IER, info->base + UART_IER);
@@ -1114,10 +1163,10 @@ static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int cou
static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long flags;
- if (!tty || !info->xmit_buf)
+ if (!info->xmit_buf)
return;
if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
@@ -1129,7 +1178,9 @@ static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
info->xmit_cnt++;
spin_unlock_irqrestore(&info->slock, flags);
if (!tty->stopped && !(info->IER & UART_IER_THRI)) {
- if (!tty->hw_stopped || (info->type == PORT_16550A) || info->IsMoxaMustChipFlag) {
+ if (!tty->hw_stopped ||
+ (info->type == PORT_16550A) ||
+ info->IsMoxaMustChipFlag) {
spin_lock_irqsave(&info->slock, flags);
info->IER |= UART_IER_THRI;
outb(info->IER, info->base + UART_IER);
@@ -1141,10 +1192,16 @@ static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
static void mxser_flush_chars(struct tty_struct *tty)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long flags;
- if (info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf || (tty->hw_stopped && (info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)))
+ if (info->xmit_cnt <= 0 ||
+ tty->stopped ||
+ !info->xmit_buf ||
+ (tty->hw_stopped &&
+ (info->type != PORT_16550A) &&
+ (!info->IsMoxaMustChipFlag)
+ ))
return;
spin_lock_irqsave(&info->slock, flags);
@@ -1157,24 +1214,24 @@ static void mxser_flush_chars(struct tty_struct *tty)
static int mxser_write_room(struct tty_struct *tty)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
int ret;
ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
if (ret < 0)
ret = 0;
- return (ret);
+ return ret;
}
static int mxser_chars_in_buffer(struct tty_struct *tty)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
return info->xmit_cnt;
}
static void mxser_flush_buffer(struct tty_struct *tty)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
char fcr;
unsigned long flags;
@@ -1184,7 +1241,8 @@ static void mxser_flush_buffer(struct tty_struct *tty)
/* below added by shinhay */
fcr = inb(info->base + UART_FCR);
- outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), info->base + UART_FCR);
+ outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+ info->base + UART_FCR);
outb(fcr, info->base + UART_FCR);
spin_unlock_irqrestore(&info->slock, flags);
@@ -1197,7 +1255,7 @@ static void mxser_flush_buffer(struct tty_struct *tty)
static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
int retval;
struct async_icount cprev, cnow; /* kernel counter temps */
struct serial_icounter_struct __user *p_cuser;
@@ -1206,9 +1264,9 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
void __user *argp = (void __user *)arg;
if (tty->index == MXSER_PORTS)
- return (mxser_ioctl_special(cmd, argp));
+ return mxser_ioctl_special(cmd, argp);
- // following add by Victor Yu. 01-05-2004
+ /* following add by Victor Yu. 01-05-2004 */
if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) {
int opmode, p;
static unsigned char ModeMask[] = { 0xfc, 0xf3, 0xcf, 0x3f };
@@ -1219,7 +1277,10 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
if (cmd == MOXA_SET_OP_MODE) {
if (get_user(opmode, (int __user *) argp))
return -EFAULT;
- if (opmode != RS232_MODE && opmode != RS485_2WIRE_MODE && opmode != RS422_MODE && opmode != RS485_4WIRE_MODE)
+ if (opmode != RS232_MODE &&
+ opmode != RS485_2WIRE_MODE &&
+ opmode != RS422_MODE &&
+ opmode != RS485_4WIRE_MODE)
return -EFAULT;
mask = ModeMask[p];
shiftbit = p * 2;
@@ -1236,36 +1297,36 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
}
return 0;
}
- // above add by Victor Yu. 01-05-2004
+ /* above add by Victor Yu. 01-05-2004 */
if ((cmd != TIOCGSERIAL) && (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
if (tty->flags & (1 << TTY_IO_ERROR))
- return (-EIO);
+ return -EIO;
}
switch (cmd) {
case TCSBRK: /* SVID version: non-zero arg --> no break */
retval = tty_check_change(tty);
if (retval)
- return (retval);
+ return retval;
tty_wait_until_sent(tty, 0);
if (!arg)
mxser_send_break(info, HZ / 4); /* 1/4 second */
- return (0);
+ return 0;
case TCSBRKP: /* support for POSIX tcsendbreak() */
retval = tty_check_change(tty);
if (retval)
- return (retval);
+ return retval;
tty_wait_until_sent(tty, 0);
mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
- return (0);
+ return 0;
case TIOCGSOFTCAR:
- return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) argp);
+ return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);
case TIOCSSOFTCAR:
if (get_user(templ, (unsigned long __user *) argp))
return -EFAULT;
arg = templ;
tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
- return (0);
+ return 0;
case TIOCGSERIAL:
return mxser_get_serial_info(info, argp);
case TIOCSSERIAL:
@@ -1278,7 +1339,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
* (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
* Caller should use TIOCGICOUNT to see which one it was
*/
- case TIOCMIWAIT:{
+ case TIOCMIWAIT: {
DECLARE_WAITQUEUE(wait, current);
int ret;
spin_lock_irqsave(&info->slock, flags);
@@ -1292,7 +1353,14 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
spin_unlock_irqrestore(&info->slock, flags);
set_current_state(TASK_INTERRUPTIBLE);
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
+ if (((arg & TIOCM_RNG) &&
+ (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) &&
+ (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) &&
+ (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) &&
+ (cnow.cts != cprev.cts))) {
ret = 0;
break;
}
@@ -1338,21 +1406,18 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
put_user(cnow.dsr, &p_cuser->dsr);
put_user(cnow.rng, &p_cuser->rng);
put_user(cnow.dcd, &p_cuser->dcd);
-
-/* */
return 0;
case MOXA_HighSpeedOn:
- return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *) argp);
-
- case MOXA_SDS_RSTICOUNTER:{
+ return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
+ case MOXA_SDS_RSTICOUNTER: {
info->mon_data.rxcnt = 0;
info->mon_data.txcnt = 0;
return 0;
}
-// (above) added by James.
+/* (above) added by James. */
case MOXA_ASPP_SETBAUD:{
long baud;
- if (get_user(baud, (long __user *) argp))
+ if (get_user(baud, (long __user *)argp))
return -EFAULT;
mxser_set_baud(info, baud);
return 0;
@@ -1377,9 +1442,10 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
return 0;
}
- case MOXA_ASPP_MON:{
+ case MOXA_ASPP_MON: {
int mcr, status;
-// info->mon_data.ser_param = tty->termios->c_cflag;
+
+ /* info->mon_data.ser_param = tty->termios->c_cflag; */
status = mxser_get_msr(info->base, 1, info->port, info);
mxser_check_modem_status(info, status);
@@ -1400,25 +1466,25 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
else
info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
-
- if (copy_to_user(argp, &info->mon_data, sizeof(struct mxser_mon)))
+ if (copy_to_user(argp, &info->mon_data,
+ sizeof(struct mxser_mon)))
return -EFAULT;
return 0;
-
}
- case MOXA_ASPP_LSTATUS:{
- if (copy_to_user(argp, &info->err_shadow, sizeof(unsigned char)))
+ case MOXA_ASPP_LSTATUS: {
+ if (copy_to_user(argp, &info->err_shadow,
+ sizeof(unsigned char)))
return -EFAULT;
info->err_shadow = 0;
return 0;
-
}
- case MOXA_SET_BAUD_METHOD:{
+ case MOXA_SET_BAUD_METHOD: {
int method;
- if (get_user(method, (int __user *) argp))
+
+ if (get_user(method, (int __user *)argp))
return -EFAULT;
mxser_set_baud_method[info->port] = method;
if (copy_to_user(argp, &method, sizeof(int)))
@@ -1442,7 +1508,8 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
switch (cmd) {
case MOXA_GET_CONF:
- if (copy_to_user(argp, mxsercfg, sizeof(struct mxser_hwconf) * 4))
+ if (copy_to_user(argp, mxsercfg,
+ sizeof(struct mxser_hwconf) * 4))
return -EFAULT;
return 0;
case MOXA_GET_MAJOR:
@@ -1461,11 +1528,11 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
if (mxvar_table[i].base)
result |= (1 << i);
}
- return put_user(result, (unsigned long __user *) argp);
+ return put_user(result, (unsigned long __user *)argp);
case MOXA_GETDATACOUNT:
if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
return -EFAULT;
- return (0);
+ return 0;
case MOXA_GETMSTATUS:
for (i = 0; i < MXSER_PORTS; i++) {
GMStatus[i].ri = 0;
@@ -1498,22 +1565,26 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
else
GMStatus[i].cts = 0;
}
- if (copy_to_user(argp, GMStatus, sizeof(struct mxser_mstatus) * MXSER_PORTS))
+ if (copy_to_user(argp, GMStatus,
+ sizeof(struct mxser_mstatus) * MXSER_PORTS))
return -EFAULT;
return 0;
- case MOXA_ASPP_MON_EXT:{
+ case MOXA_ASPP_MON_EXT: {
int status;
int opmode, p;
int shiftbit;
unsigned cflag, iflag;
for (i = 0; i < MXSER_PORTS; i++) {
-
if (!mxvar_table[i].base)
continue;
- status = mxser_get_msr(mxvar_table[i].base, 0, i, &(mxvar_table[i]));
-// mxser_check_modem_status(&mxvar_table[i], status);
+ status = mxser_get_msr(mxvar_table[i].base, 0,
+ i, &(mxvar_table[i]));
+ /*
+ mxser_check_modem_status(&mxvar_table[i],
+ status);
+ */
if (status & UART_MSR_TERI)
mxvar_table[i].icount.rng++;
if (status & UART_MSR_DDSR)
@@ -1578,75 +1649,76 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
return 0;
}
-
static void mxser_stoprx(struct tty_struct *tty)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
- //unsigned long flags;
-
+ struct mxser_struct *info = tty->driver_data;
+ /* unsigned long flags; */
info->ldisc_stop_rx = 1;
if (I_IXOFF(tty)) {
-
- //MX_LOCK(&info->slock);
- // following add by Victor Yu. 09-02-2002
+ /* MX_LOCK(&info->slock); */
+ /* following add by Victor Yu. 09-02-2002 */
if (info->IsMoxaMustChipFlag) {
info->IER &= ~MOXA_MUST_RECV_ISR;
outb(info->IER, info->base + UART_IER);
} else {
- // above add by Victor Yu. 09-02-2002
-
+ /* above add by Victor Yu. 09-02-2002 */
info->x_char = STOP_CHAR(tty);
- // outb(info->IER, 0); // mask by Victor Yu. 09-02-2002
+ /* mask by Victor Yu. 09-02-2002 */
+ /* outb(info->IER, 0); */
outb(0, info->base + UART_IER);
info->IER |= UART_IER_THRI;
- outb(info->IER, info->base + UART_IER); /* force Tx interrupt */
- } // add by Victor Yu. 09-02-2002
- //MX_UNLOCK(&info->slock);
+ /* force Tx interrupt */
+ outb(info->IER, info->base + UART_IER);
+ } /* add by Victor Yu. 09-02-2002 */
+ /* MX_UNLOCK(&info->slock); */
}
if (info->tty->termios->c_cflag & CRTSCTS) {
- //MX_LOCK(&info->slock);
+ /* MX_LOCK(&info->slock); */
info->MCR &= ~UART_MCR_RTS;
outb(info->MCR, info->base + UART_MCR);
- //MX_UNLOCK(&info->slock);
+ /* MX_UNLOCK(&info->slock); */
}
}
static void mxser_startrx(struct tty_struct *tty)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
- //unsigned long flags;
+ struct mxser_struct *info = tty->driver_data;
+ /* unsigned long flags; */
info->ldisc_stop_rx = 0;
if (I_IXOFF(tty)) {
if (info->x_char)
info->x_char = 0;
else {
- //MX_LOCK(&info->slock);
+ /* MX_LOCK(&info->slock); */
- // following add by Victor Yu. 09-02-2002
+ /* following add by Victor Yu. 09-02-2002 */
if (info->IsMoxaMustChipFlag) {
info->IER |= MOXA_MUST_RECV_ISR;
outb(info->IER, info->base + UART_IER);
} else {
- // above add by Victor Yu. 09-02-2002
+ /* above add by Victor Yu. 09-02-2002 */
info->x_char = START_CHAR(tty);
- // outb(info->IER, 0); // mask by Victor Yu. 09-02-2002
- outb(0, info->base + UART_IER); // add by Victor Yu. 09-02-2002
- info->IER |= UART_IER_THRI; /* force Tx interrupt */
+ /* mask by Victor Yu. 09-02-2002 */
+ /* outb(info->IER, 0); */
+ /* add by Victor Yu. 09-02-2002 */
+ outb(0, info->base + UART_IER);
+ /* force Tx interrupt */
+ info->IER |= UART_IER_THRI;
outb(info->IER, info->base + UART_IER);
- } // add by Victor Yu. 09-02-2002
- //MX_UNLOCK(&info->slock);
+ } /* add by Victor Yu. 09-02-2002 */
+ /* MX_UNLOCK(&info->slock); */
}
}
if (info->tty->termios->c_cflag & CRTSCTS) {
- //MX_LOCK(&info->slock);
+ /* MX_LOCK(&info->slock); */
info->MCR |= UART_MCR_RTS;
outb(info->MCR, info->base + UART_MCR);
- //MX_UNLOCK(&info->slock);
+ /* MX_UNLOCK(&info->slock); */
}
}
@@ -1656,48 +1728,53 @@ static void mxser_startrx(struct tty_struct *tty)
*/
static void mxser_throttle(struct tty_struct *tty)
{
- //struct mxser_struct *info = (struct mxser_struct *)tty->driver_data;
- //unsigned long flags;
- //MX_LOCK(&info->slock);
+ /* struct mxser_struct *info = tty->driver_data; */
+ /* unsigned long flags; */
+
+ /* MX_LOCK(&info->slock); */
mxser_stoprx(tty);
- //MX_UNLOCK(&info->slock);
+ /* MX_UNLOCK(&info->slock); */
}
static void mxser_unthrottle(struct tty_struct *tty)
{
- //struct mxser_struct *info = (struct mxser_struct *)tty->driver_data;
- //unsigned long flags;
- //MX_LOCK(&info->slock);
+ /* struct mxser_struct *info = tty->driver_data; */
+ /* unsigned long flags; */
+
+ /* MX_LOCK(&info->slock); */
mxser_startrx(tty);
- //MX_UNLOCK(&info->slock);
+ /* MX_UNLOCK(&info->slock); */
}
static void mxser_set_termios(struct tty_struct *tty, struct termios *old_termios)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long flags;
- if ((tty->termios->c_cflag != old_termios->c_cflag) || (RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) {
+ if ((tty->termios->c_cflag != old_termios->c_cflag) ||
+ (RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) {
mxser_change_speed(info, old_termios);
- if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) {
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
mxser_start(tty);
}
}
/* Handle sw stopped */
- if ((old_termios->c_iflag & IXON) && !(tty->termios->c_iflag & IXON)) {
+ if ((old_termios->c_iflag & IXON) &&
+ !(tty->termios->c_iflag & IXON)) {
tty->stopped = 0;
- // following add by Victor Yu. 09-02-2002
+ /* following add by Victor Yu. 09-02-2002 */
if (info->IsMoxaMustChipFlag) {
spin_lock_irqsave(&info->slock, flags);
DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->base);
spin_unlock_irqrestore(&info->slock, flags);
}
- // above add by Victor Yu. 09-02-2002
+ /* above add by Victor Yu. 09-02-2002 */
mxser_start(tty);
}
@@ -1711,7 +1788,7 @@ static void mxser_set_termios(struct tty_struct *tty, struct termios *old_termio
*/
static void mxser_stop(struct tty_struct *tty)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long flags;
spin_lock_irqsave(&info->slock, flags);
@@ -1724,7 +1801,7 @@ static void mxser_stop(struct tty_struct *tty)
static void mxser_start(struct tty_struct *tty)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long flags;
spin_lock_irqsave(&info->slock, flags);
@@ -1740,7 +1817,7 @@ static void mxser_start(struct tty_struct *tty)
*/
static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long orig_jiffies, char_time;
int lsr;
@@ -1777,7 +1854,8 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
if (!timeout || timeout > 2 * info->timeout)
timeout = 2 * info->timeout;
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
- printk(KERN_DEBUG "In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
+ printk(KERN_DEBUG "In rs_wait_until_sent(%d) check=%lu...",
+ timeout, char_time);
printk("jiff=%lu...", jiffies);
#endif
while (!((lsr = inb(info->base + UART_LSR)) & UART_LSR_TEMT)) {
@@ -1803,7 +1881,7 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
*/
void mxser_hangup(struct tty_struct *tty)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
mxser_flush_buffer(tty);
mxser_shutdown(info);
@@ -1815,24 +1893,26 @@ void mxser_hangup(struct tty_struct *tty)
}
-// added by James 03-12-2004.
+/* added by James 03-12-2004. */
/*
* mxser_rs_break() --- routine which turns the break handling on or off
*/
static void mxser_rs_break(struct tty_struct *tty, int break_state)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long flags;
spin_lock_irqsave(&info->slock, flags);
if (break_state == -1)
- outb(inb(info->base + UART_LCR) | UART_LCR_SBC, info->base + UART_LCR);
+ outb(inb(info->base + UART_LCR) | UART_LCR_SBC,
+ info->base + UART_LCR);
else
- outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC, info->base + UART_LCR);
+ outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC,
+ info->base + UART_LCR);
spin_unlock_irqrestore(&info->slock, flags);
}
-// (above) added by James.
+/* (above) added by James. */
/*
@@ -1848,7 +1928,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
int handled = IRQ_NONE;
port = NULL;
- //spin_lock(&gm_lock);
+ /* spin_lock(&gm_lock); */
for (i = 0; i < MXSER_BOARDS; i++) {
if (dev_id == &(mxvar_table[i * MXSER_PORTS_PER_BOARD])) {
@@ -1857,29 +1937,25 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
}
- if (i == MXSER_BOARDS) {
+ if (i == MXSER_BOARDS)
goto irq_stop;
- }
- if (port == 0) {
+ if (port == 0)
goto irq_stop;
- }
max = mxser_numports[mxsercfg[i].board_type - 1];
while (1) {
irqbits = inb(port->vector) & port->vectormask;
- if (irqbits == port->vectormask) {
+ if (irqbits == port->vectormask)
break;
- }
handled = IRQ_HANDLED;
for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) {
- if (irqbits == port->vectormask) {
+ if (irqbits == port->vectormask)
break;
- }
if (bits & irqbits)
continue;
info = port + i;
- // following add by Victor Yu. 09-13-2002
+ /* following add by Victor Yu. 09-13-2002 */
iir = inb(info->base + UART_IIR);
if (iir & UART_IIR_NO_INT)
continue;
@@ -1890,9 +1966,9 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
inb(info->base + UART_MSR);
continue;
}
- // above add by Victor Yu. 09-13-2002
+ /* above add by Victor Yu. 09-13-2002 */
/*
- if ( info->tty->flip.count < TTY_FLIPBUF_SIZE/4 ){
+ if (info->tty->flip.count < TTY_FLIPBUF_SIZE / 4) {
info->IER |= MOXA_MUST_RECV_ISR;
outb(info->IER, info->base + UART_IER);
}
@@ -1908,18 +1984,15 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
status = inb(info->base + UART_LSR) & info->read_status_mask;
*/
- // following add by Victor Yu. 09-02-2002
+ /* following add by Victor Yu. 09-02-2002 */
status = inb(info->base + UART_LSR);
- if (status & UART_LSR_PE) {
+ if (status & UART_LSR_PE)
info->err_shadow |= NPPI_NOTIFY_PARITY;
- }
- if (status & UART_LSR_FE) {
+ if (status & UART_LSR_FE)
info->err_shadow |= NPPI_NOTIFY_FRAMING;
- }
- if (status & UART_LSR_OE) {
+ if (status & UART_LSR_OE)
info->err_shadow |= NPPI_NOTIFY_HW_OVERRUN;
- }
if (status & UART_LSR_BI)
info->err_shadow |= NPPI_NOTIFY_BREAK;
@@ -1930,11 +2003,14 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
continue;
}
*/
- if (iir == MOXA_MUST_IIR_GDA || iir == MOXA_MUST_IIR_RDA || iir == MOXA_MUST_IIR_RTO || iir == MOXA_MUST_IIR_LSR)
+ if (iir == MOXA_MUST_IIR_GDA ||
+ iir == MOXA_MUST_IIR_RDA ||
+ iir == MOXA_MUST_IIR_RTO ||
+ iir == MOXA_MUST_IIR_LSR)
mxser_receive_chars(info, &status);
} else {
- // above add by Victor Yu. 09-02-2002
+ /* above add by Victor Yu. 09-02-2002 */
status &= info->read_status_mask;
if (status & UART_LSR_DR)
@@ -1944,13 +2020,13 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (msr & UART_MSR_ANY_DELTA) {
mxser_check_modem_status(info, msr);
}
- // following add by Victor Yu. 09-13-2002
+ /* following add by Victor Yu. 09-13-2002 */
if (info->IsMoxaMustChipFlag) {
if ((iir == 0x02) && (status & UART_LSR_THRE)) {
mxser_transmit_chars(info);
}
} else {
- // above add by Victor Yu. 09-13-2002
+ /* above add by Victor Yu. 09-13-2002 */
if (status & UART_LSR_THRE) {
/* 8-2-99 by William
@@ -1966,7 +2042,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
irq_stop:
- //spin_unlock(&gm_lock);
+ /* spin_unlock(&gm_lock); */
return handled;
}
@@ -1984,56 +2060,58 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status)
recv_room = tty->receive_room;
if ((recv_room == 0) && (!info->ldisc_stop_rx)) {
- //mxser_throttle(tty);
+ /* mxser_throttle(tty); */
mxser_stoprx(tty);
- //return;
+ /* return; */
}
- // following add by Victor Yu. 09-02-2002
+ /* following add by Victor Yu. 09-02-2002 */
if (info->IsMoxaMustChipFlag != MOXA_OTHER_UART) {
if (*status & UART_LSR_SPECIAL) {
goto intr_old;
}
- // following add by Victor Yu. 02-11-2004
- if (info->IsMoxaMustChipFlag == MOXA_MUST_MU860_HWID && (*status & MOXA_MUST_LSR_RERR))
+ /* following add by Victor Yu. 02-11-2004 */
+ if (info->IsMoxaMustChipFlag == MOXA_MUST_MU860_HWID &&
+ (*status & MOXA_MUST_LSR_RERR))
goto intr_old;
- // above add by Victor Yu. 02-14-2004
+ /* above add by Victor Yu. 02-14-2004 */
if (*status & MOXA_MUST_LSR_RERR)
goto intr_old;
gdl = inb(info->base + MOXA_MUST_GDL_REGISTER);
- if (info->IsMoxaMustChipFlag == MOXA_MUST_MU150_HWID) // add by Victor Yu. 02-11-2004
+ /* add by Victor Yu. 02-11-2004 */
+ if (info->IsMoxaMustChipFlag == MOXA_MUST_MU150_HWID)
gdl &= MOXA_MUST_GDL_MASK;
if (gdl >= recv_room) {
if (!info->ldisc_stop_rx) {
- //mxser_throttle(tty);
+ /* mxser_throttle(tty); */
mxser_stoprx(tty);
}
- //return;
+ /* return; */
}
while (gdl--) {
ch = inb(info->base + UART_RX);
tty_insert_flip_char(tty, ch, 0);
cnt++;
/*
- if((cnt>=HI_WATER) && (info->stop_rx==0)){
+ if ((cnt >= HI_WATER) && (info->stop_rx == 0)) {
mxser_stoprx(tty);
- info->stop_rx=1;
+ info->stop_rx = 1;
break;
} */
}
goto end_intr;
}
-intr_old:
- // above add by Victor Yu. 09-02-2002
+ intr_old:
+ /* above add by Victor Yu. 09-02-2002 */
do {
if (max-- < 0)
break;
/*
- if((cnt>=HI_WATER) && (info->stop_rx==0)){
+ if ((cnt >= HI_WATER) && (info->stop_rx == 0)) {
mxser_stoprx(tty);
info->stop_rx=1;
break;
@@ -2041,11 +2119,11 @@ intr_old:
*/
ch = inb(info->base + UART_RX);
- // following add by Victor Yu. 09-02-2002
+ /* following add by Victor Yu. 09-02-2002 */
if (info->IsMoxaMustChipFlag && (*status & UART_LSR_OE) /*&& !(*status&UART_LSR_DR) */ )
outb(0x23, info->base + UART_FCR);
*status &= info->read_status_mask;
- // above add by Victor Yu. 09-02-2002
+ /* above add by Victor Yu. 09-02-2002 */
if (*status & info->ignore_status_mask) {
if (++ignored > 100)
break;
@@ -2080,7 +2158,7 @@ intr_old:
cnt++;
if (cnt >= recv_room) {
if (!info->ldisc_stop_rx) {
- //mxser_throttle(tty);
+ /* mxser_throttle(tty); */
mxser_stoprx(tty);
}
break;
@@ -2088,21 +2166,20 @@ intr_old:
}
- // following add by Victor Yu. 09-02-2002
+ /* following add by Victor Yu. 09-02-2002 */
if (info->IsMoxaMustChipFlag)
break;
- // above add by Victor Yu. 09-02-2002
+ /* above add by Victor Yu. 09-02-2002 */
/* mask by Victor Yu. 09-02-2002
*status = inb(info->base + UART_LSR) & info->read_status_mask;
*/
- // following add by Victor Yu. 09-02-2002
+ /* following add by Victor Yu. 09-02-2002 */
*status = inb(info->base + UART_LSR);
- // above add by Victor Yu. 09-02-2002
+ /* above add by Victor Yu. 09-02-2002 */
} while (*status & UART_LSR_DR);
-end_intr: // add by Victor Yu. 09-02-2002
-
+end_intr: /* add by Victor Yu. 09-02-2002 */
mxvar_log.rxcnt[info->port] += cnt;
info->mon_data.rxcnt += cnt;
info->mon_data.up_rxcnt += cnt;
@@ -2137,7 +2214,10 @@ static void mxser_transmit_chars(struct mxser_struct *info)
return;
}
- if ((info->xmit_cnt <= 0) || info->tty->stopped || (info->tty->hw_stopped && (info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag))) {
+ if ((info->xmit_cnt <= 0) || info->tty->stopped ||
+ (info->tty->hw_stopped &&
+ (info->type != PORT_16550A) &&
+ (!info->IsMoxaMustChipFlag))) {
info->IER &= ~UART_IER_THRI;
outb(info->IER, info->base + UART_IER);
spin_unlock_irqrestore(&info->slock, flags);
@@ -2147,17 +2227,18 @@ static void mxser_transmit_chars(struct mxser_struct *info)
cnt = info->xmit_cnt;
count = info->xmit_fifo_size;
do {
- outb(info->xmit_buf[info->xmit_tail++], info->base + UART_TX);
+ outb(info->xmit_buf[info->xmit_tail++],
+ info->base + UART_TX);
info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE - 1);
if (--info->xmit_cnt <= 0)
break;
} while (--count > 0);
mxvar_log.txcnt[info->port] += (cnt - info->xmit_cnt);
-// added by James 03-12-2004.
+/* added by James 03-12-2004. */
info->mon_data.txcnt += (cnt - info->xmit_cnt);
info->mon_data.up_txcnt += (cnt - info->xmit_cnt);
-// (above) added by James.
+/* (above) added by James. */
/* added by casper 1/11/2000 */
info->icount.tx += (cnt - info->xmit_cnt);
@@ -2188,7 +2269,6 @@ static void mxser_check_modem_status(struct mxser_struct *info, int status)
info->mon_data.modem_status = status;
wake_up_interruptible(&info->delta_msr_wait);
-
if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
if (status & UART_MSR_DCD)
wake_up_interruptible(&info->open_wait);
@@ -2200,7 +2280,8 @@ static void mxser_check_modem_status(struct mxser_struct *info, int status)
if (status & UART_MSR_CTS) {
info->tty->hw_stopped = 0;
- if ((info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)) {
+ if ((info->type != PORT_16550A) &&
+ (!info->IsMoxaMustChipFlag)) {
info->IER |= UART_IER_THRI;
outb(info->IER, info->base + UART_IER);
}
@@ -2209,7 +2290,8 @@ static void mxser_check_modem_status(struct mxser_struct *info, int status)
} else {
if (!(status & UART_MSR_CTS)) {
info->tty->hw_stopped = 1;
- if ((info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)) {
+ if ((info->type != PORT_16550A) &&
+ (!info->IsMoxaMustChipFlag)) {
info->IER &= ~UART_IER_THRI;
outb(info->IER, info->base + UART_IER);
}
@@ -2231,7 +2313,7 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, stru
*/
if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
info->flags |= ASYNC_NORMAL_ACTIVE;
- return (0);
+ return 0;
}
if (tty->termios->c_cflag & CLOCAL)
@@ -2254,7 +2336,8 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, stru
info->blocked_open++;
while (1) {
spin_lock_irqsave(&info->slock, flags);
- outb(inb(info->base + UART_MCR) | UART_MCR_DTR | UART_MCR_RTS, info->base + UART_MCR);
+ outb(inb(info->base + UART_MCR) |
+ UART_MCR_DTR | UART_MCR_RTS, info->base + UART_MCR);
spin_unlock_irqrestore(&info->slock, flags);
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) {
@@ -2264,7 +2347,9 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, stru
retval = -ERESTARTSYS;
break;
}
- if (!(info->flags & ASYNC_CLOSING) && (do_clocal || (inb(info->base + UART_MSR) & UART_MSR_DCD)))
+ if (!(info->flags & ASYNC_CLOSING) &&
+ (do_clocal ||
+ (inb(info->base + UART_MSR) & UART_MSR_DCD)))
break;
if (signal_pending(current)) {
retval = -ERESTARTSYS;
@@ -2278,27 +2363,26 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, stru
info->count++;
info->blocked_open--;
if (retval)
- return (retval);
+ return retval;
info->flags |= ASYNC_NORMAL_ACTIVE;
- return (0);
+ return 0;
}
static int mxser_startup(struct mxser_struct *info)
{
-
unsigned long page;
unsigned long flags;
page = __get_free_page(GFP_KERNEL);
if (!page)
- return (-ENOMEM);
+ return -ENOMEM;
spin_lock_irqsave(&info->slock, flags);
if (info->flags & ASYNC_INITIALIZED) {
free_page(page);
spin_unlock_irqrestore(&info->slock, flags);
- return (0);
+ return 0;
}
if (!info->base || !info->type) {
@@ -2306,7 +2390,7 @@ static int mxser_startup(struct mxser_struct *info)
set_bit(TTY_IO_ERROR, &info->tty->flags);
free_page(page);
spin_unlock_irqrestore(&info->slock, flags);
- return (0);
+ return 0;
}
if (info->xmit_buf)
free_page(page);
@@ -2318,9 +2402,12 @@ static int mxser_startup(struct mxser_struct *info)
* (they will be reenabled in mxser_change_speed())
*/
if (info->IsMoxaMustChipFlag)
- outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
+ outb((UART_FCR_CLEAR_RCVR |
+ UART_FCR_CLEAR_XMIT |
+ MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
else
- outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), info->base + UART_FCR);
+ outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+ info->base + UART_FCR);
/*
* At this point there's no way the LSR could still be 0xFF;
@@ -2332,9 +2419,9 @@ static int mxser_startup(struct mxser_struct *info)
if (capable(CAP_SYS_ADMIN)) {
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
- return (0);
+ return 0;
} else
- return (-ENODEV);
+ return -ENODEV;
}
/*
@@ -2356,12 +2443,12 @@ static int mxser_startup(struct mxser_struct *info)
* Finally, enable interrupts
*/
info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
-// info->IER = UART_IER_RLSI | UART_IER_RDI;
+ /* info->IER = UART_IER_RLSI | UART_IER_RDI; */
- // following add by Victor Yu. 08-30-2002
+ /* following add by Victor Yu. 08-30-2002 */
if (info->IsMoxaMustChipFlag)
info->IER |= MOXA_MUST_IER_EGDAI;
- // above add by Victor Yu. 08-30-2002
+ /* above add by Victor Yu. 08-30-2002 */
outb(info->IER, info->base + UART_IER); /* enable interrupts */
/*
@@ -2383,7 +2470,7 @@ static int mxser_startup(struct mxser_struct *info)
mxser_change_speed(info, NULL);
info->flags |= ASYNC_INITIALIZED;
- return (0);
+ return 0;
}
/*
@@ -2421,12 +2508,15 @@ static void mxser_shutdown(struct mxser_struct *info)
outb(info->MCR, info->base + UART_MCR);
/* clear Rx/Tx FIFO's */
- // following add by Victor Yu. 08-30-2002
+ /* following add by Victor Yu. 08-30-2002 */
if (info->IsMoxaMustChipFlag)
- outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
+ outb((UART_FCR_CLEAR_RCVR |
+ UART_FCR_CLEAR_XMIT |
+ MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
else
- // above add by Victor Yu. 08-30-2002
- outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), info->base + UART_FCR);
+ /* above add by Victor Yu. 08-30-2002 */
+ outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+ info->base + UART_FCR);
/* read data port to reset things */
(void) inb(info->base + UART_RX);
@@ -2436,11 +2526,10 @@ static void mxser_shutdown(struct mxser_struct *info)
info->flags &= ~ASYNC_INITIALIZED;
- // following add by Victor Yu. 09-23-2002
- if (info->IsMoxaMustChipFlag) {
+ /* following add by Victor Yu. 09-23-2002 */
+ if (info->IsMoxaMustChipFlag)
SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->base);
- }
- // above add by Victor Yu. 09-23-2002
+ /* above add by Victor Yu. 09-23-2002 */
spin_unlock_irqrestore(&info->slock, flags);
}
@@ -2457,14 +2546,12 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
long baud;
unsigned long flags;
-
if (!info->tty || !info->tty->termios)
return ret;
cflag = info->tty->termios->c_cflag;
if (!(info->base))
return ret;
-
#ifndef B921600
#define B921600 (B460800 +1)
#endif
@@ -2559,9 +2646,8 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
cval |= 0x04;
if (cflag & PARENB)
cval |= UART_LCR_PARITY;
- if (!(cflag & PARODD)) {
+ if (!(cflag & PARODD))
cval |= UART_LCR_EPAR;
- }
if (cflag & CMSPAR)
cval |= UART_LCR_SPAR;
@@ -2574,13 +2660,12 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
fcr = 0;
} else {
fcr = UART_FCR_ENABLE_FIFO;
- // following add by Victor Yu. 08-30-2002
+ /* following add by Victor Yu. 08-30-2002 */
if (info->IsMoxaMustChipFlag) {
fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
SET_MOXA_MUST_FIFO_VALUE(info);
} else {
- // above add by Victor Yu. 08-30-2002
-
+ /* above add by Victor Yu. 08-30-2002 */
switch (info->rx_trigger) {
case 1:
fcr |= UART_FCR_TRIGGER_1;
@@ -2606,22 +2691,24 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
info->IER |= UART_IER_MSI;
if ((info->type == PORT_16550A) || (info->IsMoxaMustChipFlag)) {
info->MCR |= UART_MCR_AFE;
- //status = mxser_get_msr(info->base, 0, info->port);
-/* save_flags(flags);
+ /* status = mxser_get_msr(info->base, 0, info->port); */
+/*
+ save_flags(flags);
cli();
status = inb(baseaddr + UART_MSR);
- restore_flags(flags);*/
- //mxser_check_modem_status(info, status);
+ restore_flags(flags);
+*/
+ /* mxser_check_modem_status(info, status); */
} else {
- //status = mxser_get_msr(info->base, 0, info->port);
-
- //MX_LOCK(&info->slock);
+ /* status = mxser_get_msr(info->base, 0, info->port); */
+ /* MX_LOCK(&info->slock); */
status = inb(info->base + UART_MSR);
- //MX_UNLOCK(&info->slock);
+ /* MX_UNLOCK(&info->slock); */
if (info->tty->hw_stopped) {
if (status & UART_MSR_CTS) {
info->tty->hw_stopped = 0;
- if ((info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)) {
+ if ((info->type != PORT_16550A) &&
+ (!info->IsMoxaMustChipFlag)) {
info->IER |= UART_IER_THRI;
outb(info->IER, info->base + UART_IER);
}
@@ -2630,7 +2717,8 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
} else {
if (!(status & UART_MSR_CTS)) {
info->tty->hw_stopped = 1;
- if ((info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)) {
+ if ((info->type != PORT_16550A) &&
+ (!info->IsMoxaMustChipFlag)) {
info->IER &= ~UART_IER_THRI;
outb(info->IER, info->base + UART_IER);
}
@@ -2668,11 +2756,17 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
* overruns too. (For real raw support).
*/
if (I_IGNPAR(info->tty)) {
- info->ignore_status_mask |= UART_LSR_OE | UART_LSR_PE | UART_LSR_FE;
- info->read_status_mask |= UART_LSR_OE | UART_LSR_PE | UART_LSR_FE;
+ info->ignore_status_mask |=
+ UART_LSR_OE |
+ UART_LSR_PE |
+ UART_LSR_FE;
+ info->read_status_mask |=
+ UART_LSR_OE |
+ UART_LSR_PE |
+ UART_LSR_FE;
}
}
- // following add by Victor Yu. 09-02-2002
+ /* following add by Victor Yu. 09-02-2002 */
if (info->IsMoxaMustChipFlag) {
spin_lock_irqsave(&info->slock, flags);
SET_MOXA_MUST_XON1_VALUE(info->base, START_CHAR(info->tty));
@@ -2698,7 +2792,7 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
*/
spin_unlock_irqrestore(&info->slock, flags);
}
- // above add by Victor Yu. 09-02-2002
+ /* above add by Victor Yu. 09-02-2002 */
outb(fcr, info->base + UART_FCR); /* set fcr */
@@ -2729,10 +2823,8 @@ static int mxser_set_baud(struct mxser_struct *info, long newspd)
quot = (2 * info->baud_base / 269);
} else if (newspd) {
quot = info->baud_base / newspd;
-
if (quot == 0)
quot = 1;
-
} else {
quot = 0;
}
@@ -2765,8 +2857,6 @@ static int mxser_set_baud(struct mxser_struct *info, long newspd)
return ret;
}
-
-
/*
* ------------------------------------------------------------
* friends of mxser_ioctl()
@@ -2777,7 +2867,7 @@ static int mxser_get_serial_info(struct mxser_struct *info, struct serial_struct
struct serial_struct tmp;
if (!retinfo)
- return (-EFAULT);
+ return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
tmp.type = info->type;
tmp.line = info->port;
@@ -2791,7 +2881,7 @@ static int mxser_get_serial_info(struct mxser_struct *info, struct serial_struct
tmp.hub6 = 0;
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT;
- return (0);
+ return 0;
}
static int mxser_set_serial_info(struct mxser_struct *info, struct serial_struct __user *new_info)
@@ -2801,29 +2891,37 @@ static int mxser_set_serial_info(struct mxser_struct *info, struct serial_struct
int retval = 0;
if (!new_info || !info->base)
- return (-EFAULT);
+ return -EFAULT;
if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
return -EFAULT;
- if ((new_serial.irq != info->irq) || (new_serial.port != info->base) || (new_serial.custom_divisor != info->custom_divisor) || (new_serial.baud_base != info->baud_base))
- return (-EPERM);
+ if ((new_serial.irq != info->irq) ||
+ (new_serial.port != info->base) ||
+ (new_serial.custom_divisor != info->custom_divisor) ||
+ (new_serial.baud_base != info->baud_base))
+ return -EPERM;
flags = info->flags & ASYNC_SPD_MASK;
if (!capable(CAP_SYS_ADMIN)) {
- if ((new_serial.baud_base != info->baud_base) || (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));
+ if ((new_serial.baud_base != info->baud_base) ||
+ (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));
} else {
/*
* OK, past this point, all the error checking has been done.
* At this point, we start making changes.....
*/
- info->flags = ((info->flags & ~ASYNC_FLAGS) | (new_serial.flags & ASYNC_FLAGS));
+ info->flags = ((info->flags & ~ASYNC_FLAGS) |
+ (new_serial.flags & ASYNC_FLAGS));
info->close_delay = new_serial.close_delay * HZ / 100;
info->closing_wait = new_serial.closing_wait * HZ / 100;
- info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
- info->tty->low_latency = 0; //(info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+ info->tty->low_latency =
+ (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+ info->tty->low_latency = 0; /* (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; */
}
/* added by casper, 3/17/2000, for mouse */
@@ -2831,7 +2929,6 @@ static int mxser_set_serial_info(struct mxser_struct *info, struct serial_struct
process_txrx_fifo(info);
- /* */
if (info->flags & ASYNC_INITIALIZED) {
if (flags != (info->flags & ASYNC_SPD_MASK)) {
mxser_change_speed(info, NULL);
@@ -2839,7 +2936,7 @@ static int mxser_set_serial_info(struct mxser_struct *info, struct serial_struct
} else {
retval = mxser_startup(info);
}
- return (retval);
+ return retval;
}
/*
@@ -2876,25 +2973,27 @@ static void mxser_send_break(struct mxser_struct *info, int duration)
return;
set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&info->slock, flags);
- outb(inb(info->base + UART_LCR) | UART_LCR_SBC, info->base + UART_LCR);
+ outb(inb(info->base + UART_LCR) | UART_LCR_SBC,
+ info->base + UART_LCR);
spin_unlock_irqrestore(&info->slock, flags);
schedule_timeout(duration);
spin_lock_irqsave(&info->slock, flags);
- outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC, info->base + UART_LCR);
+ outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC,
+ info->base + UART_LCR);
spin_unlock_irqrestore(&info->slock, flags);
}
static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned char control, status;
unsigned long flags;
if (tty->index == MXSER_PORTS)
- return (-ENOIOCTLCMD);
+ return -ENOIOCTLCMD;
if (tty->flags & (1 << TTY_IO_ERROR))
- return (-EIO);
+ return -EIO;
control = info->MCR;
@@ -2904,12 +3003,16 @@ static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
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) | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
+ ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
+ ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) |
+ ((status & UART_MSR_RI) ? TIOCM_RNG : 0) |
+ ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) |
+ ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
}
static int mxser_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long flags;
@@ -2968,38 +3071,36 @@ static int mxser_get_ISA_conf(int cap, struct mxser_hwconf *hwconf)
hwconf->board_type = MXSER_BOARD_CI104J;
hwconf->ports = 4;
} else
- return (0);
+ return 0;
irq = 0;
if (hwconf->ports == 2) {
irq = regs[9] & 0xF000;
irq = irq | (irq >> 4);
if (irq != (regs[9] & 0xFF00))
- return (MXSER_ERR_IRQ_CONFLIT);
+ return MXSER_ERR_IRQ_CONFLIT;
} else if (hwconf->ports == 4) {
irq = regs[9] & 0xF000;
irq = irq | (irq >> 4);
irq = irq | (irq >> 8);
if (irq != regs[9])
- return (MXSER_ERR_IRQ_CONFLIT);
+ return MXSER_ERR_IRQ_CONFLIT;
} else if (hwconf->ports == 8) {
irq = regs[9] & 0xF000;
irq = irq | (irq >> 4);
irq = irq | (irq >> 8);
if ((irq != regs[9]) || (irq != regs[10]))
- return (MXSER_ERR_IRQ_CONFLIT);
+ return MXSER_ERR_IRQ_CONFLIT;
}
- if (!irq) {
- return (MXSER_ERR_IRQ);
- }
- hwconf->irq = ((int) (irq & 0xF000) >> 12);
+ if (!irq)
+ return MXSER_ERR_IRQ;
+ hwconf->irq = ((int)(irq & 0xF000) >> 12);
for (i = 0; i < 8; i++)
hwconf->ioaddr[i] = (int) regs[i + 1] & 0xFFF8;
- if ((regs[12] & 0x80) == 0) {
- return (MXSER_ERR_VECTOR);
- }
- hwconf->vector = (int) regs[11]; /* interrupt vector */
+ if ((regs[12] & 0x80) == 0)
+ return MXSER_ERR_VECTOR;
+ hwconf->vector = (int)regs[11]; /* interrupt vector */
if (id == 1)
hwconf->vector_mask = 0x00FF;
else
@@ -3007,10 +3108,10 @@ static int mxser_get_ISA_conf(int cap, struct mxser_hwconf *hwconf)
for (i = 7, bits = 0x0100; i >= 0; i--, bits <<= 1) {
if (regs[12] & bits) {
hwconf->baud_base[i] = 921600;
- hwconf->MaxCanSetBaudRate[i] = 921600; // add by Victor Yu. 09-04-2002
+ hwconf->MaxCanSetBaudRate[i] = 921600; /* add by Victor Yu. 09-04-2002 */
} else {
hwconf->baud_base[i] = 115200;
- hwconf->MaxCanSetBaudRate[i] = 115200; // add by Victor Yu. 09-04-2002
+ hwconf->MaxCanSetBaudRate[i] = 115200; /* add by Victor Yu. 09-04-2002 */
}
}
scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB);
@@ -3030,7 +3131,7 @@ static int mxser_get_ISA_conf(int cap, struct mxser_hwconf *hwconf)
hwconf->ports = 4;
request_region(hwconf->ioaddr[0], 8 * hwconf->ports, "mxser(IO)");
request_region(hwconf->vector, 1, "mxser(vector)");
- return (hwconf->ports);
+ return hwconf->ports;
}
#define CHIP_SK 0x01 /* Serial Data Clock in Eprom */
@@ -3053,7 +3154,7 @@ static int mxser_read_register(int port, unsigned short *regs)
id = mxser_program_mode(port);
if (id < 0)
- return (id);
+ return id;
for (i = 0; i < 14; i++) {
k = (i & 0x3F) | 0x180;
for (j = 0x100; j > 0; j >>= 1) {
@@ -3066,7 +3167,7 @@ static int mxser_read_register(int port, unsigned short *regs)
outb(CHIP_CS | CHIP_SK, port); /* A? bit of read */
}
}
- (void) inb(port);
+ (void)inb(port);
value = 0;
for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) {
outb(CHIP_CS, port);
@@ -3078,28 +3179,33 @@ static int mxser_read_register(int port, unsigned short *regs)
outb(0, port);
}
mxser_normal_mode(port);
- return (id);
+ return id;
}
static int mxser_program_mode(int port)
{
int id, i, j, n;
- //unsigned long flags;
+ /* unsigned long flags; */
spin_lock(&gm_lock);
outb(0, port);
outb(0, port);
outb(0, port);
- (void) inb(port);
- (void) inb(port);
+ (void)inb(port);
+ (void)inb(port);
outb(0, port);
- (void) inb(port);
- //restore_flags(flags);
+ (void)inb(port);
+ /* restore_flags(flags); */
spin_unlock(&gm_lock);
id = inb(port + 1) & 0x1F;
- if ((id != C168_ASIC_ID) && (id != C104_ASIC_ID) && (id != C102_ASIC_ID) && (id != CI132_ASIC_ID) && (id != CI134_ASIC_ID) && (id != CI104J_ASIC_ID))
- return (-1);
+ if ((id != C168_ASIC_ID) &&
+ (id != C104_ASIC_ID) &&
+ (id != C102_ASIC_ID) &&
+ (id != CI132_ASIC_ID) &&
+ (id != CI134_ASIC_ID) &&
+ (id != CI104J_ASIC_ID))
+ return -1;
for (i = 0, j = 0; i < 4; i++) {
n = inb(port + 2);
if (n == 'M') {
@@ -3112,7 +3218,7 @@ static int mxser_program_mode(int port)
}
if (j != 2)
id = -2;
- return (id);
+ return id;
}
static void mxser_normal_mode(int port)
@@ -3130,7 +3236,7 @@ static void mxser_normal_mode(int port)
if ((n & 0x61) == 0x60)
break;
if ((n & 1) == 1)
- (void) inb(port);
+ (void)inb(port);
}
outb(0x00, port + 4);
}
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index c48de09..203dc2b 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -951,7 +951,8 @@ static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
{
queue_the_message:
- pMsg = kmalloc(sizeof(struct r3964_message), GFP_KERNEL);
+ pMsg = kmalloc(sizeof(struct r3964_message),
+ error_code?GFP_ATOMIC:GFP_KERNEL);
TRACE_M("add_msg - kmalloc %p",pMsg);
if(pMsg==NULL) {
return;
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 0721345..17bc8ab 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -844,7 +844,7 @@ static int bh_action(MGSLPC_INFO *info)
return rc;
}
-void bh_handler(void* Context)
+static void bh_handler(void* Context)
{
MGSLPC_INFO *info = (MGSLPC_INFO*)Context;
int action;
@@ -888,7 +888,7 @@ void bh_handler(void* Context)
__FILE__,__LINE__,info->device_name);
}
-void bh_transmit(MGSLPC_INFO *info)
+static void bh_transmit(MGSLPC_INFO *info)
{
struct tty_struct *tty = info->tty;
if (debug_level >= DEBUG_LEVEL_BH)
@@ -900,7 +900,7 @@ void bh_transmit(MGSLPC_INFO *info)
}
}
-void bh_status(MGSLPC_INFO *info)
+static void bh_status(MGSLPC_INFO *info)
{
info->ri_chkcount = 0;
info->dsr_chkcount = 0;
@@ -1582,7 +1582,7 @@ static void mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_put_char"))
return;
- if (!tty || !info->tx_buf)
+ if (!info->tx_buf)
return;
spin_lock_irqsave(&info->lock,flags);
@@ -1649,7 +1649,7 @@ static int mgslpc_write(struct tty_struct * tty,
__FILE__,__LINE__,info->device_name,count);
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_write") ||
- !tty || !info->tx_buf)
+ !info->tx_buf)
goto cleanup;
if (info->params.mode == MGSL_MODE_HDLC) {
@@ -2305,7 +2305,7 @@ static int mgslpc_ioctl(struct tty_struct *tty, struct file * file,
return ioctl_common(info, cmd, arg);
}
-int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg)
+static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg)
{
int error;
struct mgsl_icount cnow; /* kernel counter temps */
@@ -2877,7 +2877,7 @@ done:
return ((count < begin+len-off) ? count : begin+len-off);
}
-int rx_alloc_buffers(MGSLPC_INFO *info)
+static int rx_alloc_buffers(MGSLPC_INFO *info)
{
/* each buffer has header and data */
info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
@@ -2900,13 +2900,13 @@ int rx_alloc_buffers(MGSLPC_INFO *info)
return 0;
}
-void rx_free_buffers(MGSLPC_INFO *info)
+static void rx_free_buffers(MGSLPC_INFO *info)
{
kfree(info->rx_buf);
info->rx_buf = NULL;
}
-int claim_resources(MGSLPC_INFO *info)
+static int claim_resources(MGSLPC_INFO *info)
{
if (rx_alloc_buffers(info) < 0 ) {
printk( "Cant allocate rx buffer %s\n", info->device_name);
@@ -2916,7 +2916,7 @@ int claim_resources(MGSLPC_INFO *info)
return 0;
}
-void release_resources(MGSLPC_INFO *info)
+static void release_resources(MGSLPC_INFO *info)
{
if (debug_level >= DEBUG_LEVEL_INFO)
printk("release_resources(%s)\n", info->device_name);
@@ -2928,7 +2928,7 @@ void release_resources(MGSLPC_INFO *info)
*
* Arguments: info pointer to device instance data
*/
-void mgslpc_add_device(MGSLPC_INFO *info)
+static void mgslpc_add_device(MGSLPC_INFO *info)
{
info->next_device = NULL;
info->line = mgslpc_device_count;
@@ -2964,7 +2964,7 @@ void mgslpc_add_device(MGSLPC_INFO *info)
#endif
}
-void mgslpc_remove_device(MGSLPC_INFO *remove_info)
+static void mgslpc_remove_device(MGSLPC_INFO *remove_info)
{
MGSLPC_INFO *info = mgslpc_device_list;
MGSLPC_INFO *last = NULL;
@@ -3257,7 +3257,7 @@ static void loopback_enable(MGSLPC_INFO *info)
write_reg(info, CHA + MODE, val);
}
-void hdlc_mode(MGSLPC_INFO *info)
+static void hdlc_mode(MGSLPC_INFO *info)
{
unsigned char val;
unsigned char clkmode, clksubmode;
@@ -3497,7 +3497,7 @@ void hdlc_mode(MGSLPC_INFO *info)
rx_stop(info);
}
-void rx_stop(MGSLPC_INFO *info)
+static void rx_stop(MGSLPC_INFO *info)
{
if (debug_level >= DEBUG_LEVEL_ISR)
printk("%s(%d):rx_stop(%s)\n",
@@ -3510,7 +3510,7 @@ void rx_stop(MGSLPC_INFO *info)
info->rx_overflow = 0;
}
-void rx_start(MGSLPC_INFO *info)
+static void rx_start(MGSLPC_INFO *info)
{
if (debug_level >= DEBUG_LEVEL_ISR)
printk("%s(%d):rx_start(%s)\n",
@@ -3526,7 +3526,7 @@ void rx_start(MGSLPC_INFO *info)
info->rx_enabled = 1;
}
-void tx_start(MGSLPC_INFO *info)
+static void tx_start(MGSLPC_INFO *info)
{
if (debug_level >= DEBUG_LEVEL_ISR)
printk("%s(%d):tx_start(%s)\n",
@@ -3564,7 +3564,7 @@ void tx_start(MGSLPC_INFO *info)
info->tx_enabled = 1;
}
-void tx_stop(MGSLPC_INFO *info)
+static void tx_stop(MGSLPC_INFO *info)
{
if (debug_level >= DEBUG_LEVEL_ISR)
printk("%s(%d):tx_stop(%s)\n",
@@ -3578,7 +3578,7 @@ void tx_stop(MGSLPC_INFO *info)
/* Reset the adapter to a known state and prepare it for further use.
*/
-void reset_device(MGSLPC_INFO *info)
+static void reset_device(MGSLPC_INFO *info)
{
/* power up both channels (set BIT7) */
write_reg(info, CHA + CCR0, 0x80);
@@ -3628,7 +3628,7 @@ void reset_device(MGSLPC_INFO *info)
write_reg(info, IPC, 0x05);
}
-void async_mode(MGSLPC_INFO *info)
+static void async_mode(MGSLPC_INFO *info)
{
unsigned char val;
@@ -3799,7 +3799,7 @@ void async_mode(MGSLPC_INFO *info)
/* Set the HDLC idle mode for the transmitter.
*/
-void tx_set_idle(MGSLPC_INFO *info)
+static void tx_set_idle(MGSLPC_INFO *info)
{
/* Note: ESCC2 only supports flags and one idle modes */
if (info->idle_mode == HDLC_TXIDLE_FLAGS)
@@ -3810,7 +3810,7 @@ void tx_set_idle(MGSLPC_INFO *info)
/* get state of the V24 status (input) signals.
*/
-void get_signals(MGSLPC_INFO *info)
+static void get_signals(MGSLPC_INFO *info)
{
unsigned char status = 0;
@@ -3832,7 +3832,7 @@ void get_signals(MGSLPC_INFO *info)
/* Set the state of DTR and RTS based on contents of
* serial_signals member of device extension.
*/
-void set_signals(MGSLPC_INFO *info)
+static void set_signals(MGSLPC_INFO *info)
{
unsigned char val;
@@ -3856,7 +3856,7 @@ void set_signals(MGSLPC_INFO *info)
set_reg_bits(info, CHA + PVR, PVR_DTR);
}
-void rx_reset_buffers(MGSLPC_INFO *info)
+static void rx_reset_buffers(MGSLPC_INFO *info)
{
RXBUF *buf;
int i;
@@ -3875,7 +3875,7 @@ void rx_reset_buffers(MGSLPC_INFO *info)
*
* Returns 1 if frame returned, otherwise 0
*/
-int rx_get_frame(MGSLPC_INFO *info)
+static int rx_get_frame(MGSLPC_INFO *info)
{
unsigned short status;
RXBUF *buf;
@@ -3961,7 +3961,7 @@ int rx_get_frame(MGSLPC_INFO *info)
return 1;
}
-BOOLEAN register_test(MGSLPC_INFO *info)
+static BOOLEAN register_test(MGSLPC_INFO *info)
{
static unsigned char patterns[] =
{ 0x00, 0xff, 0xaa, 0x55, 0x69, 0x96, 0x0f };
@@ -3987,7 +3987,7 @@ BOOLEAN register_test(MGSLPC_INFO *info)
return rc;
}
-BOOLEAN irq_test(MGSLPC_INFO *info)
+static BOOLEAN irq_test(MGSLPC_INFO *info)
{
unsigned long end_time;
unsigned long flags;
@@ -4022,7 +4022,7 @@ BOOLEAN irq_test(MGSLPC_INFO *info)
return info->irq_occurred ? TRUE : FALSE;
}
-int adapter_test(MGSLPC_INFO *info)
+static int adapter_test(MGSLPC_INFO *info)
{
if (!register_test(info)) {
info->init_error = DiagStatus_AddressFailure;
@@ -4044,7 +4044,7 @@ int adapter_test(MGSLPC_INFO *info)
return 0;
}
-void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit)
+static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit)
{
int i;
int linecount;
@@ -4079,7 +4079,7 @@ void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit)
/* HDLC frame time out
* update stats and do tx completion processing
*/
-void tx_timeout(unsigned long context)
+static void tx_timeout(unsigned long context)
{
MGSLPC_INFO *info = (MGSLPC_INFO*)context;
unsigned long flags;
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 7edc6a4..0708c51 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -324,35 +324,15 @@ static void rp_do_receive(struct r_port *info,
CHANNEL_t * cp, unsigned int ChanStatus)
{
unsigned int CharNStat;
- int ToRecv, wRecv, space = 0, count;
- unsigned char *cbuf, *chead;
- char *fbuf, *fhead;
- struct tty_ldisc *ld;
-
- ld = tty_ldisc_ref(tty);
+ int ToRecv, wRecv, space;
+ unsigned char *cbuf;
ToRecv = sGetRxCnt(cp);
- space = tty->receive_room;
- if (space > 2 * TTY_FLIPBUF_SIZE)
- space = 2 * TTY_FLIPBUF_SIZE;
- count = 0;
#ifdef ROCKET_DEBUG_INTR
- printk(KERN_INFO "rp_do_receive(%d, %d)...", ToRecv, space);
+ printk(KERN_INFO "rp_do_receive(%d)...", ToRecv);
#endif
-
- /*
- * determine how many we can actually read in. If we can't
- * read any in then we have a software overrun condition.
- */
- if (ToRecv > space)
- ToRecv = space;
-
- ToRecv = tty_prepare_flip_string_flags(tty, &chead, &fhead, ToRecv);
- if (ToRecv <= 0)
- goto done;
-
- cbuf = chead;
- fbuf = fhead;
+ if (ToRecv == 0)
+ return;
/*
* if status indicates there are errored characters in the
@@ -380,6 +360,8 @@ static void rp_do_receive(struct r_port *info,
info->read_status_mask);
#endif
while (ToRecv) {
+ char flag;
+
CharNStat = sInW(sGetTxRxDataIO(cp));
#ifdef ROCKET_DEBUG_RECEIVE
printk(KERN_INFO "%x...", CharNStat);
@@ -392,17 +374,16 @@ static void rp_do_receive(struct r_port *info,
}
CharNStat &= info->read_status_mask;
if (CharNStat & STMBREAKH)
- *fbuf++ = TTY_BREAK;
+ flag = TTY_BREAK;
else if (CharNStat & STMPARITYH)
- *fbuf++ = TTY_PARITY;
+ flag = TTY_PARITY;
else if (CharNStat & STMFRAMEH)
- *fbuf++ = TTY_FRAME;
+ flag = TTY_FRAME;
else if (CharNStat & STMRCVROVRH)
- *fbuf++ = TTY_OVERRUN;
+ flag = TTY_OVERRUN;
else
- *fbuf++ = TTY_NORMAL;
- *cbuf++ = CharNStat & 0xff;
- count++;
+ flag = TTY_NORMAL;
+ tty_insert_flip_char(tty, CharNStat & 0xff, flag);
ToRecv--;
}
@@ -422,20 +403,23 @@ static void rp_do_receive(struct r_port *info,
* characters at time by doing repeated word IO
* transfer.
*/
+ space = tty_prepare_flip_string(tty, &cbuf, ToRecv);
+ if (space < ToRecv) {
+#ifdef ROCKET_DEBUG_RECEIVE
+ printk(KERN_INFO "rp_do_receive:insufficient space ToRecv=%d space=%d\n", ToRecv, space);
+#endif
+ if (space <= 0)
+ return;
+ ToRecv = space;
+ }
wRecv = ToRecv >> 1;
if (wRecv)
sInStrW(sGetTxRxDataIO(cp), (unsigned short *) cbuf, wRecv);
if (ToRecv & 1)
cbuf[ToRecv - 1] = sInB(sGetTxRxDataIO(cp));
- memset(fbuf, TTY_NORMAL, ToRecv);
- cbuf += ToRecv;
- fbuf += ToRecv;
- count += ToRecv;
}
/* Push the data up to the tty layer */
- ld->receive_buf(tty, chead, fhead, count);
-done:
- tty_ldisc_deref(ld);
+ tty_flip_buffer_push(tty);
}
/*
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index f6686fc..0897b0c 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -928,7 +928,7 @@ static int __init rtc_init(void)
#ifdef __sparc__
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if(strcmp(edev->prom_name, "rtc") == 0) {
+ if(strcmp(edev->prom_node->name, "rtc") == 0) {
rtc_port = edev->resource[0].start;
rtc_irq = edev->irqs[0];
goto found;
@@ -938,7 +938,7 @@ static int __init rtc_init(void)
#ifdef __sparc_v9__
for_each_isa(isa_br) {
for_each_isadev(isa_dev, isa_br) {
- if (strcmp(isa_dev->prom_name, "rtc") == 0) {
+ if (strcmp(isa_dev->prom_node->name, "rtc") == 0) {
rtc_port = isa_dev->resource.start;
rtc_irq = isa_dev->irq;
goto found;
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index a90f5d9..43dfd86 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -512,7 +512,7 @@ static struct sonypi_device {
#ifdef CONFIG_ACPI
static struct acpi_device *sonypi_acpi_device;
-static int acpi_enabled;
+static int acpi_driver_registered;
#endif
static int sonypi_ec_write(u8 addr, u8 value)
@@ -869,7 +869,7 @@ found:
sonypi_report_input_event(event);
#ifdef CONFIG_ACPI
- if (acpi_enabled)
+ if (sonypi_acpi_device)
acpi_bus_generate_event(sonypi_acpi_device, 1, event);
#endif
@@ -1551,8 +1551,8 @@ static int __init sonypi_init(void)
goto err_free_device;
#ifdef CONFIG_ACPI
- if (acpi_bus_register_driver(&sonypi_acpi_driver) > 0)
- acpi_enabled = 1;
+ if (acpi_bus_register_driver(&sonypi_acpi_driver) >= 0)
+ acpi_driver_registered = 1;
#endif
return 0;
@@ -1567,7 +1567,7 @@ static int __init sonypi_init(void)
static void __exit sonypi_exit(void)
{
#ifdef CONFIG_ACPI
- if (acpi_enabled)
+ if (acpi_driver_registered)
acpi_bus_unregister_driver(&sonypi_acpi_driver);
#endif
platform_device_unregister(sonypi_platform_device);
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index 5343e9f..1b53302 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -1683,7 +1683,7 @@ static int sx_write(struct tty_struct * tty,
bp = port_Board(port);
- if (!tty || !port->xmit_buf || !tmp_buf) {
+ if (!port->xmit_buf || !tmp_buf) {
func_exit();
return 0;
}
@@ -1733,7 +1733,7 @@ static void sx_put_char(struct tty_struct * tty, unsigned char ch)
return;
}
dprintk (SX_DEBUG_TX, "check tty: %p %p\n", tty, port->xmit_buf);
- if (!tty || !port->xmit_buf) {
+ if (!port->xmit_buf) {
func_exit();
return;
}
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index b4d1f4e..4e35d41 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -101,6 +101,7 @@ MODULE_LICENSE("GPL");
static struct pci_device_id pci_table[] = {
{PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+ {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT2_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
{PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT4_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
{PCI_VENDOR_ID_MICROGATE, SYNCLINK_AC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
{0,}, /* terminate list */
@@ -870,7 +871,7 @@ static int write(struct tty_struct *tty,
goto cleanup;
DBGINFO(("%s write count=%d\n", info->device_name, count));
- if (!tty || !info->tx_buf)
+ if (!info->tx_buf)
goto cleanup;
if (count > info->max_frame_size) {
@@ -924,7 +925,7 @@ static void put_char(struct tty_struct *tty, unsigned char ch)
if (sanity_check(info, tty->name, "put_char"))
return;
DBGINFO(("%s put_char(%d)\n", info->device_name, ch));
- if (!tty || !info->tx_buf)
+ if (!info->tx_buf)
return;
spin_lock_irqsave(&info->lock,flags);
if (!info->tx_active && (info->tx_count < info->max_frame_size))
@@ -2515,7 +2516,8 @@ static int set_txidle(struct slgt_info *info, int idle_mode)
DBGINFO(("%s set_txidle(%d)\n", info->device_name, idle_mode));
spin_lock_irqsave(&info->lock,flags);
info->idle_mode = idle_mode;
- tx_set_idle(info);
+ if (info->params.mode != MGSL_MODE_ASYNC)
+ tx_set_idle(info);
spin_unlock_irqrestore(&info->lock,flags);
return 0;
}
@@ -3076,7 +3078,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
static int alloc_tmp_rbuf(struct slgt_info *info)
{
- info->tmp_rbuf = kmalloc(info->max_frame_size, GFP_KERNEL);
+ info->tmp_rbuf = kmalloc(info->max_frame_size + 5, GFP_KERNEL);
if (info->tmp_rbuf == NULL)
return -ENOMEM;
return 0;
@@ -3276,6 +3278,9 @@ static void add_device(struct slgt_info *info)
case SYNCLINK_GT_DEVICE_ID:
devstr = "GT";
break;
+ case SYNCLINK_GT2_DEVICE_ID:
+ devstr = "GT2";
+ break;
case SYNCLINK_GT4_DEVICE_ID:
devstr = "GT4";
break;
@@ -3353,7 +3358,9 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
int i;
int port_count = 1;
- if (pdev->device == SYNCLINK_GT4_DEVICE_ID)
+ if (pdev->device == SYNCLINK_GT2_DEVICE_ID)
+ port_count = 2;
+ else if (pdev->device == SYNCLINK_GT4_DEVICE_ID)
port_count = 4;
/* allocate device instances for all ports */
@@ -3940,8 +3947,6 @@ static void async_mode(struct slgt_info *info)
msc_set_vcr(info);
- tx_set_idle(info);
-
/* SCR (serial control)
*
* 15 1=tx req on FIFO half empty
@@ -4012,7 +4017,7 @@ static void hdlc_mode(struct slgt_info *info)
case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break;
}
- switch (info->params.crc_type)
+ switch (info->params.crc_type & HDLC_CRC_MASK)
{
case HDLC_CRC_16_CCITT: val |= BIT9; break;
case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break;
@@ -4073,7 +4078,7 @@ static void hdlc_mode(struct slgt_info *info)
case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break;
}
- switch (info->params.crc_type)
+ switch (info->params.crc_type & HDLC_CRC_MASK)
{
case HDLC_CRC_16_CCITT: val |= BIT9; break;
case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break;
@@ -4175,17 +4180,38 @@ static void hdlc_mode(struct slgt_info *info)
*/
static void tx_set_idle(struct slgt_info *info)
{
- unsigned char val = 0xff;
+ unsigned char val;
+ unsigned short tcr;
- switch(info->idle_mode)
- {
- case HDLC_TXIDLE_FLAGS: val = 0x7e; break;
- case HDLC_TXIDLE_ALT_ZEROS_ONES: val = 0xaa; break;
- case HDLC_TXIDLE_ZEROS: val = 0x00; break;
- case HDLC_TXIDLE_ONES: val = 0xff; break;
- case HDLC_TXIDLE_ALT_MARK_SPACE: val = 0xaa; break;
- case HDLC_TXIDLE_SPACE: val = 0x00; break;
- case HDLC_TXIDLE_MARK: val = 0xff; break;
+ /* if preamble enabled (tcr[6] == 1) then tx idle size = 8 bits
+ * else tcr[5:4] = tx idle size: 00 = 8 bits, 01 = 16 bits
+ */
+ tcr = rd_reg16(info, TCR);
+ if (info->idle_mode & HDLC_TXIDLE_CUSTOM_16) {
+ /* disable preamble, set idle size to 16 bits */
+ tcr = (tcr & ~(BIT6 + BIT5)) | BIT4;
+ /* MSB of 16 bit idle specified in tx preamble register (TPR) */
+ wr_reg8(info, TPR, (unsigned char)((info->idle_mode >> 8) & 0xff));
+ } else if (!(tcr & BIT6)) {
+ /* preamble is disabled, set idle size to 8 bits */
+ tcr &= ~(BIT5 + BIT4);
+ }
+ wr_reg16(info, TCR, tcr);
+
+ if (info->idle_mode & (HDLC_TXIDLE_CUSTOM_8 | HDLC_TXIDLE_CUSTOM_16)) {
+ /* LSB of custom tx idle specified in tx idle register */
+ val = (unsigned char)(info->idle_mode & 0xff);
+ } else {
+ /* standard 8 bit idle patterns */
+ switch(info->idle_mode)
+ {
+ case HDLC_TXIDLE_FLAGS: val = 0x7e; break;
+ case HDLC_TXIDLE_ALT_ZEROS_ONES:
+ case HDLC_TXIDLE_ALT_MARK_SPACE: val = 0xaa; break;
+ case HDLC_TXIDLE_ZEROS:
+ case HDLC_TXIDLE_SPACE: val = 0x00; break;
+ default: val = 0xff;
+ }
}
wr_reg8(info, TIR, val);
@@ -4313,6 +4339,12 @@ static int rx_get_frame(struct slgt_info *info)
unsigned long flags;
struct tty_struct *tty = info->tty;
unsigned char addr_field = 0xff;
+ unsigned int crc_size = 0;
+
+ switch (info->params.crc_type & HDLC_CRC_MASK) {
+ case HDLC_CRC_16_CCITT: crc_size = 2; break;
+ case HDLC_CRC_32_CCITT: crc_size = 4; break;
+ }
check_again:
@@ -4357,7 +4389,7 @@ check_again:
status = desc_status(info->rbufs[end]);
/* ignore CRC bit if not using CRC (bit is undefined) */
- if (info->params.crc_type == HDLC_CRC_NONE)
+ if ((info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_NONE)
status &= ~BIT1;
if (framesize == 0 ||
@@ -4366,34 +4398,34 @@ check_again:
goto check_again;
}
- if (framesize < 2 || status & (BIT1+BIT0)) {
- if (framesize < 2 || (status & BIT0))
- info->icount.rxshort++;
- else
- info->icount.rxcrc++;
+ if (framesize < (2 + crc_size) || status & BIT0) {
+ info->icount.rxshort++;
framesize = 0;
+ } else if (status & BIT1) {
+ info->icount.rxcrc++;
+ if (!(info->params.crc_type & HDLC_CRC_RETURN_EX))
+ framesize = 0;
+ }
#ifdef CONFIG_HDLC
- {
- struct net_device_stats *stats = hdlc_stats(info->netdev);
- stats->rx_errors++;
- stats->rx_frame_errors++;
- }
-#endif
- } else {
- /* adjust frame size for CRC, if any */
- if (info->params.crc_type == HDLC_CRC_16_CCITT)
- framesize -= 2;
- else if (info->params.crc_type == HDLC_CRC_32_CCITT)
- framesize -= 4;
+ if (framesize == 0) {
+ struct net_device_stats *stats = hdlc_stats(info->netdev);
+ stats->rx_errors++;
+ stats->rx_frame_errors++;
}
+#endif
DBGBH(("%s rx frame status=%04X size=%d\n",
info->device_name, status, framesize));
DBGDATA(info, info->rbufs[start].buf, min_t(int, framesize, DMABUFSIZE), "rx");
if (framesize) {
- if (framesize > info->max_frame_size)
+ if (!(info->params.crc_type & HDLC_CRC_RETURN_EX)) {
+ framesize -= crc_size;
+ crc_size = 0;
+ }
+
+ if (framesize > info->max_frame_size + crc_size)
info->icount.rxlong++;
else {
/* copy dma buffer(s) to contiguous temp buffer */
@@ -4413,6 +4445,11 @@ check_again:
i = 0;
}
+ if (info->params.crc_type & HDLC_CRC_RETURN_EX) {
+ *p = (status & BIT1) ? RX_CRC_ERROR : RX_OK;
+ framesize++;
+ }
+
#ifdef CONFIG_HDLC
if (info->netcount)
hdlcdev_rx(info,info->tmp_rbuf, framesize);
@@ -4671,13 +4708,13 @@ static int loopback_test(struct slgt_info *info)
static int adapter_test(struct slgt_info *info)
{
DBGINFO(("testing %s\n", info->device_name));
- if ((info->init_error = register_test(info)) < 0) {
+ if (register_test(info) < 0) {
printk("register test failure %s addr=%08X\n",
info->device_name, info->phys_reg_addr);
- } else if ((info->init_error = irq_test(info)) < 0) {
+ } else if (irq_test(info) < 0) {
printk("IRQ test failure %s IRQ=%d\n",
info->device_name, info->irq_level);
- } else if ((info->init_error = loopback_test(info)) < 0) {
+ } else if (loopback_test(info) < 0) {
printk("loopback test failure %s\n", info->device_name);
}
return info->init_error;
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index 8587401..21bf15a 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -988,7 +988,7 @@ static int write(struct tty_struct *tty,
if (sanity_check(info, tty->name, "write"))
goto cleanup;
- if (!tty || !info->tx_buf)
+ if (!info->tx_buf)
goto cleanup;
if (info->params.mode == MGSL_MODE_HDLC) {
@@ -1067,7 +1067,7 @@ static void put_char(struct tty_struct *tty, unsigned char ch)
if (sanity_check(info, tty->name, "put_char"))
return;
- if (!tty || !info->tx_buf)
+ if (!info->tx_buf)
return;
spin_lock_irqsave(&info->lock,flags);
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
index 60aabdb..11c7e9d 100644
--- a/drivers/char/viotape.c
+++ b/drivers/char/viotape.c
@@ -989,7 +989,7 @@ static int viotape_remove(struct vio_dev *vdev)
* support.
*/
static struct vio_device_id viotape_device_table[] __devinitdata = {
- { "viotape", "" },
+ { "byte", "IBM,iSeries-viotape" },
{ "", "" }
};
MODULE_DEVICE_TABLE(vio, viotape_device_table);
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
index 4b4d7db..498aa37 100644
--- a/drivers/connector/cn_proc.c
+++ b/drivers/connector/cn_proc.c
@@ -26,6 +26,7 @@
#include <linux/kernel.h>
#include <linux/ktime.h>
#include <linux/init.h>
+#include <linux/connector.h>
#include <asm/atomic.h>
#include <linux/cn_proc.h>
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index 79d581c..b49bacf 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -121,6 +121,7 @@ nlmsg_failure:
kfree_skb(skb);
return -EINVAL;
}
+EXPORT_SYMBOL_GPL(cn_netlink_send);
/*
* Callback helper - queues work and setup destructor for given data.
@@ -319,6 +320,7 @@ int cn_add_callback(struct cb_id *id, char *name, void (*callback)(void *))
return 0;
}
+EXPORT_SYMBOL_GPL(cn_add_callback);
/*
* Callback remove routing - removes callback
@@ -335,6 +337,7 @@ void cn_del_callback(struct cb_id *id)
cn_queue_del_callback(dev->cbdev, id);
cn_notify(id, 1);
}
+EXPORT_SYMBOL_GPL(cn_del_callback);
/*
* Checks two connector's control messages to be the same.
@@ -488,7 +491,3 @@ static void __devexit cn_fini(void)
subsys_initcall(cn_init);
module_exit(cn_fini);
-
-EXPORT_SYMBOL_GPL(cn_add_callback);
-EXPORT_SYMBOL_GPL(cn_del_callback);
-EXPORT_SYMBOL_GPL(cn_netlink_send);
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index e07a354..b3ebc8f 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -22,6 +22,7 @@
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/sysfs.h>
+#include <linux/cpu.h>
#include <linux/sched.h>
#include <linux/kmod.h>
#include <linux/workqueue.h>
@@ -72,6 +73,14 @@ static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
static unsigned int dbs_enable; /* number of CPUs using this policy */
+/*
+ * DEADLOCK ALERT! There is a ordering requirement between cpu_hotplug
+ * lock and dbs_mutex. cpu_hotplug lock should always be held before
+ * dbs_mutex. If any function that can potentially take cpu_hotplug lock
+ * (like __cpufreq_driver_target()) is being called with dbs_mutex taken, then
+ * cpu_hotplug lock should be taken before that. Note that cpu_hotplug lock
+ * is recursive for the same process. -Venki
+ */
static DEFINE_MUTEX (dbs_mutex);
static DECLARE_WORK (dbs_work, do_dbs_timer, NULL);
@@ -414,12 +423,14 @@ static void dbs_check_cpu(int cpu)
static void do_dbs_timer(void *data)
{
int i;
+ lock_cpu_hotplug();
mutex_lock(&dbs_mutex);
for_each_online_cpu(i)
dbs_check_cpu(i);
schedule_delayed_work(&dbs_work,
usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
mutex_unlock(&dbs_mutex);
+ unlock_cpu_hotplug();
}
static inline void dbs_timer_init(void)
@@ -514,6 +525,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
break;
case CPUFREQ_GOV_LIMITS:
+ lock_cpu_hotplug();
mutex_lock(&dbs_mutex);
if (policy->max < this_dbs_info->cur_policy->cur)
__cpufreq_driver_target(
@@ -524,6 +536,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
this_dbs_info->cur_policy,
policy->min, CPUFREQ_RELATION_L);
mutex_unlock(&dbs_mutex);
+ unlock_cpu_hotplug();
break;
}
return 0;
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 3e6ffca..693e540 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -21,6 +21,7 @@
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/sysfs.h>
+#include <linux/cpu.h>
#include <linux/sched.h>
#include <linux/kmod.h>
#include <linux/workqueue.h>
@@ -71,6 +72,14 @@ static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
static unsigned int dbs_enable; /* number of CPUs using this policy */
+/*
+ * DEADLOCK ALERT! There is a ordering requirement between cpu_hotplug
+ * lock and dbs_mutex. cpu_hotplug lock should always be held before
+ * dbs_mutex. If any function that can potentially take cpu_hotplug lock
+ * (like __cpufreq_driver_target()) is being called with dbs_mutex taken, then
+ * cpu_hotplug lock should be taken before that. Note that cpu_hotplug lock
+ * is recursive for the same process. -Venki
+ */
static DEFINE_MUTEX (dbs_mutex);
static DECLARE_WORK (dbs_work, do_dbs_timer, NULL);
@@ -363,12 +372,14 @@ static void dbs_check_cpu(int cpu)
static void do_dbs_timer(void *data)
{
int i;
+ lock_cpu_hotplug();
mutex_lock(&dbs_mutex);
for_each_online_cpu(i)
dbs_check_cpu(i);
queue_delayed_work(dbs_workq, &dbs_work,
usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
mutex_unlock(&dbs_mutex);
+ unlock_cpu_hotplug();
}
static inline void dbs_timer_init(void)
@@ -469,6 +480,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
break;
case CPUFREQ_GOV_LIMITS:
+ lock_cpu_hotplug();
mutex_lock(&dbs_mutex);
if (policy->max < this_dbs_info->cur_policy->cur)
__cpufreq_driver_target(
@@ -479,6 +491,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
this_dbs_info->cur_policy,
policy->min, CPUFREQ_RELATION_L);
mutex_unlock(&dbs_mutex);
+ unlock_cpu_hotplug();
break;
}
return 0;
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 1e371a5..731c3d5 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -6,8 +6,7 @@
menu "Firmware Drivers"
config EDD
- tristate "BIOS Enhanced Disk Drive calls determine boot disk (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ tristate "BIOS Enhanced Disk Drive calls determine boot disk"
depends on !IA64
help
Say Y or M here if you want to enable BIOS Enhanced Disk Drive
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 948bd7e..b9e3886 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -255,10 +255,15 @@ void __init dmi_scan_machine(void)
/**
* dmi_check_system - check system DMI data
* @list: array of dmi_system_id structures to match against
+ * All non-null elements of the list must match
+ * their slot's (field index's) data (i.e., each
+ * list string must be a substring of the specified
+ * DMI slot's string data) to be considered a
+ * successful match.
*
* Walk the blacklist table running matching functions until someone
* returns non zero or we hit the end. Callback function is called for
- * each successfull match. Returns the number of matches.
+ * each successful match. Returns the number of matches.
*/
int dmi_check_system(struct dmi_system_id *list)
{
@@ -287,7 +292,7 @@ EXPORT_SYMBOL(dmi_check_system);
/**
* dmi_get_system_info - return DMI data value
- * @field: data index (see enum dmi_filed)
+ * @field: data index (see enum dmi_field)
*
* Returns one DMI data value, can be used to perform
* complex DMI data checks.
@@ -301,13 +306,13 @@ EXPORT_SYMBOL(dmi_get_system_info);
/**
* dmi_find_device - find onboard device by type/name
* @type: device type or %DMI_DEV_TYPE_ANY to match all device types
- * @desc: device name string or %NULL to match all
+ * @name: device name string or %NULL to match all
* @from: previous device found in search, or %NULL for new search.
*
* Iterates through the list of known onboard devices. If a device is
* found with a matching @vendor and @device, a pointer to its device
* structure is returned. Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL to the @from argument.
+ * A new search is initiated by passing %NULL as the @from argument.
* If @from is not %NULL, searches continue from next device.
*/
struct dmi_device * dmi_find_device(int type, const char *name,
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 99cdc61..0e31a0c 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1,5 +1,5 @@
#
-# I2C Sensor chip drivers configuration
+# Hardware monitoring chip drivers configuration
#
menu "Hardware Monitoring support"
@@ -16,6 +16,10 @@ config HWMON
should say Y here and also to the specific driver(s) for your
sensors chip(s) below.
+ To find out which specific driver(s) you need, use the
+ sensors-detect script from the lm_sensors package. Read
+ <file:Documentation/hwmon/userspace-tools> for details.
+
This support can also be built as a module. If so, the module
will be called hwmon.
@@ -23,6 +27,18 @@ config HWMON_VID
tristate
default n
+config SENSORS_ABITUGURU
+ tristate "Abit uGuru"
+ depends on HWMON && EXPERIMENTAL
+ help
+ If you say yes here you get support for the Abit uGuru chips
+ sensor part. The voltage and frequency control parts of the Abit
+ uGuru are not supported. The Abit uGuru chip can be found on Abit
+ uGuru featuring motherboards (most modern Abit motherboards).
+
+ This driver can also be built as a module. If so, the module
+ will be called abituguru.
+
config SENSORS_ADM1021
tristate "Analog Devices ADM1021 and compatibles"
depends on HWMON && I2C
@@ -188,6 +204,16 @@ config SENSORS_LM63
This driver can also be built as a module. If so, the module
will be called lm63.
+config SENSORS_LM70
+ tristate "National Semiconductor LM70"
+ depends on HWMON && SPI_MASTER && EXPERIMENTAL
+ help
+ If you say yes here you get support for the National Semiconductor
+ LM70 digital temperature sensor chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called lm70.
+
config SENSORS_LM75
tristate "National Semiconductor LM75 and compatibles"
depends on HWMON && I2C
@@ -236,11 +262,11 @@ config SENSORS_LM80
will be called lm80.
config SENSORS_LM83
- tristate "National Semiconductor LM83"
+ tristate "National Semiconductor LM83 and compatibles"
depends on HWMON && I2C
help
If you say yes here you get support for National Semiconductor
- LM83 sensor chips.
+ LM82 and LM83 sensor chips.
This driver can also be built as a module. If so, the module
will be called lm83.
@@ -333,11 +359,32 @@ config SENSORS_SMSC47M1
help
If you say yes here you get support for the integrated fan
monitoring and control capabilities of the SMSC LPC47B27x,
- LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192 chips.
+ LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x, LPC47M192 and
+ LPC47M997 chips.
+
+ The temperature and voltage sensor features of the LPC47M192
+ and LPC47M997 are supported by another driver, select also
+ "SMSC LPC47M192 and compatibles" below for those.
This driver can also be built as a module. If so, the module
will be called smsc47m1.
+config SENSORS_SMSC47M192
+ tristate "SMSC LPC47M192 and compatibles"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select HWMON_VID
+ help
+ If you say yes here you get support for the temperature and
+ voltage sensors of the SMSC LPC47M192 and LPC47M997 chips.
+
+ The fan monitoring and control capabilities of these chips
+ are supported by another driver, select
+ "SMSC LPC47M10x and compatibles" above. You need both drivers
+ if you want fan control and voltage/temperature sensor support.
+
+ This driver can also be built as a module. If so, the module
+ will be called smsc47m192.
+
config SENSORS_SMSC47B397
tristate "SMSC LPC47B397-NC"
depends on HWMON && I2C && EXPERIMENTAL
@@ -385,6 +432,16 @@ config SENSORS_W83781D
This driver can also be built as a module. If so, the module
will be called w83781d.
+config SENSORS_W83791D
+ tristate "Winbond W83791D"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select HWMON_VID
+ help
+ If you say yes here you get support for the Winbond W83791D chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called w83791d.
+
config SENSORS_W83792D
tristate "Winbond W83792D"
depends on HWMON && I2C && EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index fbdb8d9..3141584 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -10,7 +10,9 @@ obj-$(CONFIG_SENSORS_ASB100) += asb100.o
obj-$(CONFIG_SENSORS_W83627HF) += w83627hf.o
obj-$(CONFIG_SENSORS_W83792D) += w83792d.o
obj-$(CONFIG_SENSORS_W83781D) += w83781d.o
+obj-$(CONFIG_SENSORS_W83791D) += w83791d.o
+obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o
obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
@@ -26,6 +28,7 @@ obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
obj-$(CONFIG_SENSORS_IT87) += it87.o
obj-$(CONFIG_SENSORS_LM63) += lm63.o
+obj-$(CONFIG_SENSORS_LM70) += lm70.o
obj-$(CONFIG_SENSORS_LM75) += lm75.o
obj-$(CONFIG_SENSORS_LM77) += lm77.o
obj-$(CONFIG_SENSORS_LM78) += lm78.o
@@ -40,6 +43,7 @@ obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
+obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
obj-$(CONFIG_SENSORS_VT8231) += vt8231.o
obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c
new file mode 100644
index 0000000..59122cc
--- /dev/null
+++ b/drivers/hwmon/abituguru.c
@@ -0,0 +1,1415 @@
+/*
+ abituguru.c Copyright (c) 2005-2006 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+/*
+ This driver supports the sensor part of the custom Abit uGuru chip found
+ on Abit uGuru motherboards. Note: because of lack of specs the CPU / RAM /
+ etc voltage & frequency control is not supported!
+*/
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <asm/io.h>
+
+/* Banks */
+#define ABIT_UGURU_ALARM_BANK 0x20 /* 1x 3 bytes */
+#define ABIT_UGURU_SENSOR_BANK1 0x21 /* 16x volt and temp */
+#define ABIT_UGURU_FAN_PWM 0x24 /* 3x 5 bytes */
+#define ABIT_UGURU_SENSOR_BANK2 0x26 /* fans */
+/* max nr of sensors in bank1, a bank1 sensor can be in, temp or nc */
+#define ABIT_UGURU_MAX_BANK1_SENSORS 16
+/* Warning if you increase one of the 2 MAX defines below to 10 or higher you
+ should adjust the belonging _NAMES_LENGTH macro for the 2 digit number! */
+/* max nr of sensors in bank2, currently mb's with max 6 fans are known */
+#define ABIT_UGURU_MAX_BANK2_SENSORS 6
+/* max nr of pwm outputs, currently mb's with max 5 pwm outputs are known */
+#define ABIT_UGURU_MAX_PWMS 5
+/* uGuru sensor bank 1 flags */ /* Alarm if: */
+#define ABIT_UGURU_TEMP_HIGH_ALARM_ENABLE 0x01 /* temp over warn */
+#define ABIT_UGURU_VOLT_HIGH_ALARM_ENABLE 0x02 /* volt over max */
+#define ABIT_UGURU_VOLT_LOW_ALARM_ENABLE 0x04 /* volt under min */
+#define ABIT_UGURU_TEMP_HIGH_ALARM_FLAG 0x10 /* temp is over warn */
+#define ABIT_UGURU_VOLT_HIGH_ALARM_FLAG 0x20 /* volt is over max */
+#define ABIT_UGURU_VOLT_LOW_ALARM_FLAG 0x40 /* volt is under min */
+/* uGuru sensor bank 2 flags */ /* Alarm if: */
+#define ABIT_UGURU_FAN_LOW_ALARM_ENABLE 0x01 /* fan under min */
+/* uGuru sensor bank common flags */
+#define ABIT_UGURU_BEEP_ENABLE 0x08 /* beep if alarm */
+#define ABIT_UGURU_SHUTDOWN_ENABLE 0x80 /* shutdown if alarm */
+/* uGuru fan PWM (speed control) flags */
+#define ABIT_UGURU_FAN_PWM_ENABLE 0x80 /* enable speed control */
+/* Values used for conversion */
+#define ABIT_UGURU_FAN_MAX 15300 /* RPM */
+/* Bank1 sensor types */
+#define ABIT_UGURU_IN_SENSOR 0
+#define ABIT_UGURU_TEMP_SENSOR 1
+#define ABIT_UGURU_NC 2
+/* Timeouts / Retries, if these turn out to need a lot of fiddling we could
+ convert them to params. */
+/* 250 was determined by trial and error, 200 works most of the time, but not
+ always. I assume this is cpu-speed independent, since the ISA-bus and not
+ the CPU should be the bottleneck. Note that 250 sometimes is still not
+ enough (only reported on AN7 mb) this is handled by a higher layer. */
+#define ABIT_UGURU_WAIT_TIMEOUT 250
+/* Normally all expected status in abituguru_ready, are reported after the
+ first read, but sometimes not and we need to poll, 5 polls was not enough
+ 50 sofar is. */
+#define ABIT_UGURU_READY_TIMEOUT 50
+/* Maximum 3 retries on timedout reads/writes, delay 200 ms before retrying */
+#define ABIT_UGURU_MAX_RETRIES 3
+#define ABIT_UGURU_RETRY_DELAY (HZ/5)
+/* Maximum 2 timeouts in abituguru_update_device, iow 3 in a row is an error */
+#define ABIT_UGURU_MAX_TIMEOUTS 2
+/* utility macros */
+#define ABIT_UGURU_NAME "abituguru"
+#define ABIT_UGURU_DEBUG(level, format, arg...) \
+ if (level <= verbose) \
+ printk(KERN_DEBUG ABIT_UGURU_NAME ": " format , ## arg)
+/* Macros to help calculate the sysfs_names array length */
+/* sum of strlen of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0,
+ in??_{min,max}_alarm_enable\0, in??_beep\0, in??_shutdown\0 */
+#define ABITUGURU_IN_NAMES_LENGTH (11 + 2 * 9 + 2 * 15 + 2 * 22 + 10 + 14)
+/* sum of strlen of: temp??_input\0, temp??_max\0, temp??_crit\0,
+ temp??_alarm\0, temp??_alarm_enable\0, temp??_beep\0, temp??_shutdown\0 */
+#define ABITUGURU_TEMP_NAMES_LENGTH (13 + 11 + 12 + 13 + 20 + 12 + 16)
+/* sum of strlen of: fan?_input\0, fan?_min\0, fan?_alarm\0,
+ fan?_alarm_enable\0, fan?_beep\0, fan?_shutdown\0 */
+#define ABITUGURU_FAN_NAMES_LENGTH (11 + 9 + 11 + 18 + 10 + 14)
+/* sum of strlen of: pwm?_enable\0, pwm?_auto_channels_temp\0,
+ pwm?_auto_point{1,2}_pwm\0, pwm?_auto_point{1,2}_temp\0 */
+#define ABITUGURU_PWM_NAMES_LENGTH (12 + 24 + 2 * 21 + 2 * 22)
+/* IN_NAMES_LENGTH > TEMP_NAMES_LENGTH so assume all bank1 sensors are in */
+#define ABITUGURU_SYSFS_NAMES_LENGTH ( \
+ ABIT_UGURU_MAX_BANK1_SENSORS * ABITUGURU_IN_NAMES_LENGTH + \
+ ABIT_UGURU_MAX_BANK2_SENSORS * ABITUGURU_FAN_NAMES_LENGTH + \
+ ABIT_UGURU_MAX_PWMS * ABITUGURU_PWM_NAMES_LENGTH)
+
+/* All the macros below are named identical to the oguru and oguru2 programs
+ reverse engineered by Olle Sandberg, hence the names might not be 100%
+ logical. I could come up with better names, but I prefer keeping the names
+ identical so that this driver can be compared with his work more easily. */
+/* Two i/o-ports are used by uGuru */
+#define ABIT_UGURU_BASE 0x00E0
+/* Used to tell uGuru what to read and to read the actual data */
+#define ABIT_UGURU_CMD 0x00
+/* Mostly used to check if uGuru is busy */
+#define ABIT_UGURU_DATA 0x04
+#define ABIT_UGURU_REGION_LENGTH 5
+/* uGuru status' */
+#define ABIT_UGURU_STATUS_WRITE 0x00 /* Ready to be written */
+#define ABIT_UGURU_STATUS_READ 0x01 /* Ready to be read */
+#define ABIT_UGURU_STATUS_INPUT 0x08 /* More input */
+#define ABIT_UGURU_STATUS_READY 0x09 /* Ready to be written */
+
+/* Constants */
+/* in (Volt) sensors go up to 3494 mV, temp to 255000 millidegrees Celsius */
+static const int abituguru_bank1_max_value[2] = { 3494, 255000 };
+/* Min / Max allowed values for sensor2 (fan) alarm threshold, these values
+ correspond to 300-3000 RPM */
+static const u8 abituguru_bank2_min_threshold = 5;
+static const u8 abituguru_bank2_max_threshold = 50;
+/* Register 0 is a bitfield, 1 and 2 are pwm settings (255 = 100%), 3 and 4
+ are temperature trip points. */
+static const int abituguru_pwm_settings_multiplier[5] = { 0, 1, 1, 1000, 1000 };
+/* Min / Max allowed values for pwm_settings. Note: pwm1 (CPU fan) is a
+ special case the minium allowed pwm% setting for this is 30% (77) on
+ some MB's this special case is handled in the code! */
+static const u8 abituguru_pwm_min[5] = { 0, 170, 170, 25, 25 };
+static const u8 abituguru_pwm_max[5] = { 0, 255, 255, 75, 75 };
+
+
+/* Insmod parameters */
+static int force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Set to one to force detection.");
+static int fan_sensors;
+module_param(fan_sensors, int, 0);
+MODULE_PARM_DESC(fan_sensors, "Number of fan sensors on the uGuru "
+ "(0 = autodetect)");
+static int pwms;
+module_param(pwms, int, 0);
+MODULE_PARM_DESC(pwms, "Number of PWMs on the uGuru "
+ "(0 = autodetect)");
+
+/* Default verbose is 2, since this driver is still in the testing phase */
+static int verbose = 2;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "How verbose should the driver be? (0-3):\n"
+ " 0 normal output\n"
+ " 1 + verbose error reporting\n"
+ " 2 + sensors type probing info\n"
+ " 3 + retryable error reporting");
+
+
+/* For the Abit uGuru, we need to keep some data in memory.
+ The structure is dynamically allocated, at the same time when a new
+ abituguru device is allocated. */
+struct abituguru_data {
+ struct class_device *class_dev; /* hwmon registered device */
+ struct mutex update_lock; /* protect access to data and uGuru */
+ unsigned long last_updated; /* In jiffies */
+ unsigned short addr; /* uguru base address */
+ char uguru_ready; /* is the uguru in ready state? */
+ unsigned char update_timeouts; /* number of update timeouts since last
+ successful update */
+
+ /* The sysfs attr and their names are generated automatically, for bank1
+ we cannot use a predefined array because we don't know beforehand
+ of a sensor is a volt or a temp sensor, for bank2 and the pwms its
+ easier todo things the same way. For in sensors we have 9 (temp 7)
+ sysfs entries per sensor, for bank2 and pwms 6. */
+ struct sensor_device_attribute_2 sysfs_attr[
+ ABIT_UGURU_MAX_BANK1_SENSORS * 9 +
+ ABIT_UGURU_MAX_BANK2_SENSORS * 6 + ABIT_UGURU_MAX_PWMS * 6];
+ /* Buffer to store the dynamically generated sysfs names */
+ char sysfs_names[ABITUGURU_SYSFS_NAMES_LENGTH];
+
+ /* Bank 1 data */
+ /* number of and addresses of [0] in, [1] temp sensors */
+ u8 bank1_sensors[2];
+ u8 bank1_address[2][ABIT_UGURU_MAX_BANK1_SENSORS];
+ u8 bank1_value[ABIT_UGURU_MAX_BANK1_SENSORS];
+ /* This array holds 3 entries per sensor for the bank 1 sensor settings
+ (flags, min, max for voltage / flags, warn, shutdown for temp). */
+ u8 bank1_settings[ABIT_UGURU_MAX_BANK1_SENSORS][3];
+ /* Maximum value for each sensor used for scaling in mV/millidegrees
+ Celsius. */
+ int bank1_max_value[ABIT_UGURU_MAX_BANK1_SENSORS];
+
+ /* Bank 2 data, ABIT_UGURU_MAX_BANK2_SENSORS entries for bank2 */
+ u8 bank2_sensors; /* actual number of bank2 sensors found */
+ u8 bank2_value[ABIT_UGURU_MAX_BANK2_SENSORS];
+ u8 bank2_settings[ABIT_UGURU_MAX_BANK2_SENSORS][2]; /* flags, min */
+
+ /* Alarms 2 bytes for bank1, 1 byte for bank2 */
+ u8 alarms[3];
+
+ /* Fan PWM (speed control) 5 bytes per PWM */
+ u8 pwms; /* actual number of pwms found */
+ u8 pwm_settings[ABIT_UGURU_MAX_PWMS][5];
+};
+
+/* wait till the uguru is in the specified state */
+static int abituguru_wait(struct abituguru_data *data, u8 state)
+{
+ int timeout = ABIT_UGURU_WAIT_TIMEOUT;
+
+ while (inb_p(data->addr + ABIT_UGURU_DATA) != state) {
+ timeout--;
+ if (timeout == 0)
+ return -EBUSY;
+ }
+ return 0;
+}
+
+/* Put the uguru in ready for input state */
+static int abituguru_ready(struct abituguru_data *data)
+{
+ int timeout = ABIT_UGURU_READY_TIMEOUT;
+
+ if (data->uguru_ready)
+ return 0;
+
+ /* Reset? / Prepare for next read/write cycle */
+ outb(0x00, data->addr + ABIT_UGURU_DATA);
+
+ /* Wait till the uguru is ready */
+ if (abituguru_wait(data, ABIT_UGURU_STATUS_READY)) {
+ ABIT_UGURU_DEBUG(1,
+ "timeout exceeded waiting for ready state\n");
+ return -EIO;
+ }
+
+ /* Cmd port MUST be read now and should contain 0xAC */
+ while (inb_p(data->addr + ABIT_UGURU_CMD) != 0xAC) {
+ timeout--;
+ if (timeout == 0) {
+ ABIT_UGURU_DEBUG(1,
+ "CMD reg does not hold 0xAC after ready command\n");
+ return -EIO;
+ }
+ }
+
+ /* After this the ABIT_UGURU_DATA port should contain
+ ABIT_UGURU_STATUS_INPUT */
+ timeout = ABIT_UGURU_READY_TIMEOUT;
+ while (inb_p(data->addr + ABIT_UGURU_DATA) != ABIT_UGURU_STATUS_INPUT) {
+ timeout--;
+ if (timeout == 0) {
+ ABIT_UGURU_DEBUG(1,
+ "state != more input after ready command\n");
+ return -EIO;
+ }
+ }
+
+ data->uguru_ready = 1;
+ return 0;
+}
+
+/* Send the bank and then sensor address to the uGuru for the next read/write
+ cycle. This function gets called as the first part of a read/write by
+ abituguru_read and abituguru_write. This function should never be
+ called by any other function. */
+static int abituguru_send_address(struct abituguru_data *data,
+ u8 bank_addr, u8 sensor_addr, int retries)
+{
+ /* assume the caller does error handling itself if it has not requested
+ any retries, and thus be quiet. */
+ int report_errors = retries;
+
+ for (;;) {
+ /* Make sure the uguru is ready and then send the bank address,
+ after this the uguru is no longer "ready". */
+ if (abituguru_ready(data) != 0)
+ return -EIO;
+ outb(bank_addr, data->addr + ABIT_UGURU_DATA);
+ data->uguru_ready = 0;
+
+ /* Wait till the uguru is ABIT_UGURU_STATUS_INPUT state again
+ and send the sensor addr */
+ if (abituguru_wait(data, ABIT_UGURU_STATUS_INPUT)) {
+ if (retries) {
+ ABIT_UGURU_DEBUG(3, "timeout exceeded "
+ "waiting for more input state, %d "
+ "tries remaining\n", retries);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(ABIT_UGURU_RETRY_DELAY);
+ retries--;
+ continue;
+ }
+ if (report_errors)
+ ABIT_UGURU_DEBUG(1, "timeout exceeded "
+ "waiting for more input state "
+ "(bank: %d)\n", (int)bank_addr);
+ return -EBUSY;
+ }
+ outb(sensor_addr, data->addr + ABIT_UGURU_CMD);
+ return 0;
+ }
+}
+
+/* Read count bytes from sensor sensor_addr in bank bank_addr and store the
+ result in buf, retry the send address part of the read retries times. */
+static int abituguru_read(struct abituguru_data *data,
+ u8 bank_addr, u8 sensor_addr, u8 *buf, int count, int retries)
+{
+ int i;
+
+ /* Send the address */
+ i = abituguru_send_address(data, bank_addr, sensor_addr, retries);
+ if (i)
+ return i;
+
+ /* And read the data */
+ for (i = 0; i < count; i++) {
+ if (abituguru_wait(data, ABIT_UGURU_STATUS_READ)) {
+ ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for "
+ "read state (bank: %d, sensor: %d)\n",
+ (int)bank_addr, (int)sensor_addr);
+ break;
+ }
+ buf[i] = inb(data->addr + ABIT_UGURU_CMD);
+ }
+
+ /* Last put the chip back in ready state */
+ abituguru_ready(data);
+
+ return i;
+}
+
+/* Write count bytes from buf to sensor sensor_addr in bank bank_addr, the send
+ address part of the write is always retried ABIT_UGURU_MAX_RETRIES times. */
+static int abituguru_write(struct abituguru_data *data,
+ u8 bank_addr, u8 sensor_addr, u8 *buf, int count)
+{
+ int i;
+
+ /* Send the address */
+ i = abituguru_send_address(data, bank_addr, sensor_addr,
+ ABIT_UGURU_MAX_RETRIES);
+ if (i)
+ return i;
+
+ /* And write the data */
+ for (i = 0; i < count; i++) {
+ if (abituguru_wait(data, ABIT_UGURU_STATUS_WRITE)) {
+ ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for "
+ "write state (bank: %d, sensor: %d)\n",
+ (int)bank_addr, (int)sensor_addr);
+ break;
+ }
+ outb(buf[i], data->addr + ABIT_UGURU_CMD);
+ }
+
+ /* Now we need to wait till the chip is ready to be read again,
+ don't ask why */
+ if (abituguru_wait(data, ABIT_UGURU_STATUS_READ)) {
+ ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for read state "
+ "after write (bank: %d, sensor: %d)\n", (int)bank_addr,
+ (int)sensor_addr);
+ return -EIO;
+ }
+
+ /* Cmd port MUST be read now and should contain 0xAC */
+ if (inb_p(data->addr + ABIT_UGURU_CMD) != 0xAC) {
+ ABIT_UGURU_DEBUG(1, "CMD reg does not hold 0xAC after write "
+ "(bank: %d, sensor: %d)\n", (int)bank_addr,
+ (int)sensor_addr);
+ return -EIO;
+ }
+
+ /* Last put the chip back in ready state */
+ abituguru_ready(data);
+
+ return i;
+}
+
+/* Detect sensor type. Temp and Volt sensors are enabled with
+ different masks and will ignore enable masks not meant for them.
+ This enables us to test what kind of sensor we're dealing with.
+ By setting the alarm thresholds so that we will always get an
+ alarm for sensor type X and then enabling the sensor as sensor type
+ X, if we then get an alarm it is a sensor of type X. */
+static int __devinit
+abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
+ u8 sensor_addr)
+{
+ u8 val, buf[3];
+ int ret = ABIT_UGURU_NC;
+
+ /* First read the sensor and the current settings */
+ if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1, sensor_addr, &val,
+ 1, ABIT_UGURU_MAX_RETRIES) != 1)
+ return -ENODEV;
+
+ /* Test val is sane / usable for sensor type detection. */
+ if ((val < 10u) || (val > 240u)) {
+ printk(KERN_WARNING ABIT_UGURU_NAME
+ ": bank1-sensor: %d reading (%d) too close to limits, "
+ "unable to determine sensor type, skipping sensor\n",
+ (int)sensor_addr, (int)val);
+ /* assume no sensor is there for sensors for which we can't
+ determine the sensor type because their reading is too close
+ to their limits, this usually means no sensor is there. */
+ return ABIT_UGURU_NC;
+ }
+
+ ABIT_UGURU_DEBUG(2, "testing bank1 sensor %d\n", (int)sensor_addr);
+ /* Volt sensor test, enable volt low alarm, set min value ridicously
+ high. If its a volt sensor this should always give us an alarm. */
+ buf[0] = ABIT_UGURU_VOLT_LOW_ALARM_ENABLE;
+ buf[1] = 245;
+ buf[2] = 250;
+ if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
+ buf, 3) != 3)
+ return -ENODEV;
+ /* Now we need 20 ms to give the uguru time to read the sensors
+ and raise a voltage alarm */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ/50);
+ /* Check for alarm and check the alarm is a volt low alarm. */
+ if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, buf, 3,
+ ABIT_UGURU_MAX_RETRIES) != 3)
+ return -ENODEV;
+ if (buf[sensor_addr/8] & (0x01 << (sensor_addr % 8))) {
+ if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1,
+ sensor_addr, buf, 3,
+ ABIT_UGURU_MAX_RETRIES) != 3)
+ return -ENODEV;
+ if (buf[0] & ABIT_UGURU_VOLT_LOW_ALARM_FLAG) {
+ /* Restore original settings */
+ if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2,
+ sensor_addr,
+ data->bank1_settings[sensor_addr],
+ 3) != 3)
+ return -ENODEV;
+ ABIT_UGURU_DEBUG(2, " found volt sensor\n");
+ return ABIT_UGURU_IN_SENSOR;
+ } else
+ ABIT_UGURU_DEBUG(2, " alarm raised during volt "
+ "sensor test, but volt low flag not set\n");
+ } else
+ ABIT_UGURU_DEBUG(2, " alarm not raised during volt sensor "
+ "test\n");
+
+ /* Temp sensor test, enable sensor as a temp sensor, set beep value
+ ridicously low (but not too low, otherwise uguru ignores it).
+ If its a temp sensor this should always give us an alarm. */
+ buf[0] = ABIT_UGURU_TEMP_HIGH_ALARM_ENABLE;
+ buf[1] = 5;
+ buf[2] = 10;
+ if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
+ buf, 3) != 3)
+ return -ENODEV;
+ /* Now we need 50 ms to give the uguru time to read the sensors
+ and raise a temp alarm */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ/20);
+ /* Check for alarm and check the alarm is a temp high alarm. */
+ if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, buf, 3,
+ ABIT_UGURU_MAX_RETRIES) != 3)
+ return -ENODEV;
+ if (buf[sensor_addr/8] & (0x01 << (sensor_addr % 8))) {
+ if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1,
+ sensor_addr, buf, 3,
+ ABIT_UGURU_MAX_RETRIES) != 3)
+ return -ENODEV;
+ if (buf[0] & ABIT_UGURU_TEMP_HIGH_ALARM_FLAG) {
+ ret = ABIT_UGURU_TEMP_SENSOR;
+ ABIT_UGURU_DEBUG(2, " found temp sensor\n");
+ } else
+ ABIT_UGURU_DEBUG(2, " alarm raised during temp "
+ "sensor test, but temp high flag not set\n");
+ } else
+ ABIT_UGURU_DEBUG(2, " alarm not raised during temp sensor "
+ "test\n");
+
+ /* Restore original settings */
+ if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
+ data->bank1_settings[sensor_addr], 3) != 3)
+ return -ENODEV;
+
+ return ret;
+}
+
+/* These functions try to find out how many sensors there are in bank2 and how
+ many pwms there are. The purpose of this is to make sure that we don't give
+ the user the possibility to change settings for non-existent sensors / pwm.
+ The uGuru will happily read / write whatever memory happens to be after the
+ memory storing the PWM settings when reading/writing to a PWM which is not
+ there. Notice even if we detect a PWM which doesn't exist we normally won't
+ write to it, unless the user tries to change the settings.
+
+ Although the uGuru allows reading (settings) from non existing bank2
+ sensors, my version of the uGuru does seem to stop writing to them, the
+ write function above aborts in this case with:
+ "CMD reg does not hold 0xAC after write"
+
+ Notice these 2 tests are non destructive iow read-only tests, otherwise
+ they would defeat their purpose. Although for the bank2_sensors detection a
+ read/write test would be feasible because of the reaction above, I've
+ however opted to stay on the safe side. */
+static void __devinit
+abituguru_detect_no_bank2_sensors(struct abituguru_data *data)
+{
+ int i;
+
+ if (fan_sensors) {
+ data->bank2_sensors = fan_sensors;
+ ABIT_UGURU_DEBUG(2, "assuming %d fan sensors because of "
+ "\"fan_sensors\" module param\n",
+ (int)data->bank2_sensors);
+ return;
+ }
+
+ ABIT_UGURU_DEBUG(2, "detecting number of fan sensors\n");
+ for (i = 0; i < ABIT_UGURU_MAX_BANK2_SENSORS; i++) {
+ /* 0x89 are the known used bits:
+ -0x80 enable shutdown
+ -0x08 enable beep
+ -0x01 enable alarm
+ All other bits should be 0, but on some motherboards
+ 0x40 (bit 6) is also high for some of the fans?? */
+ if (data->bank2_settings[i][0] & ~0xC9) {
+ ABIT_UGURU_DEBUG(2, " bank2 sensor %d does not seem "
+ "to be a fan sensor: settings[0] = %02X\n",
+ i, (unsigned int)data->bank2_settings[i][0]);
+ break;
+ }
+
+ /* check if the threshold is within the allowed range */
+ if (data->bank2_settings[i][1] <
+ abituguru_bank2_min_threshold) {
+ ABIT_UGURU_DEBUG(2, " bank2 sensor %d does not seem "
+ "to be a fan sensor: the threshold (%d) is "
+ "below the minimum (%d)\n", i,
+ (int)data->bank2_settings[i][1],
+ (int)abituguru_bank2_min_threshold);
+ break;
+ }
+ if (data->bank2_settings[i][1] >
+ abituguru_bank2_max_threshold) {
+ ABIT_UGURU_DEBUG(2, " bank2 sensor %d does not seem "
+ "to be a fan sensor: the threshold (%d) is "
+ "above the maximum (%d)\n", i,
+ (int)data->bank2_settings[i][1],
+ (int)abituguru_bank2_max_threshold);
+ break;
+ }
+ }
+
+ data->bank2_sensors = i;
+ ABIT_UGURU_DEBUG(2, " found: %d fan sensors\n",
+ (int)data->bank2_sensors);
+}
+
+static void __devinit
+abituguru_detect_no_pwms(struct abituguru_data *data)
+{
+ int i, j;
+
+ if (pwms) {
+ data->pwms = pwms;
+ ABIT_UGURU_DEBUG(2, "assuming %d PWM outputs because of "
+ "\"pwms\" module param\n", (int)data->pwms);
+ return;
+ }
+
+ ABIT_UGURU_DEBUG(2, "detecting number of PWM outputs\n");
+ for (i = 0; i < ABIT_UGURU_MAX_PWMS; i++) {
+ /* 0x80 is the enable bit and the low
+ nibble is which temp sensor to use,
+ the other bits should be 0 */
+ if (data->pwm_settings[i][0] & ~0x8F) {
+ ABIT_UGURU_DEBUG(2, " pwm channel %d does not seem "
+ "to be a pwm channel: settings[0] = %02X\n",
+ i, (unsigned int)data->pwm_settings[i][0]);
+ break;
+ }
+
+ /* the low nibble must correspond to one of the temp sensors
+ we've found */
+ for (j = 0; j < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR];
+ j++) {
+ if (data->bank1_address[ABIT_UGURU_TEMP_SENSOR][j] ==
+ (data->pwm_settings[i][0] & 0x0F))
+ break;
+ }
+ if (j == data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]) {
+ ABIT_UGURU_DEBUG(2, " pwm channel %d does not seem "
+ "to be a pwm channel: %d is not a valid temp "
+ "sensor address\n", i,
+ data->pwm_settings[i][0] & 0x0F);
+ break;
+ }
+
+ /* check if all other settings are within the allowed range */
+ for (j = 1; j < 5; j++) {
+ u8 min;
+ /* special case pwm1 min pwm% */
+ if ((i == 0) && ((j == 1) || (j == 2)))
+ min = 77;
+ else
+ min = abituguru_pwm_min[j];
+ if (data->pwm_settings[i][j] < min) {
+ ABIT_UGURU_DEBUG(2, " pwm channel %d does "
+ "not seem to be a pwm channel: "
+ "setting %d (%d) is below the minimum "
+ "value (%d)\n", i, j,
+ (int)data->pwm_settings[i][j],
+ (int)min);
+ goto abituguru_detect_no_pwms_exit;
+ }
+ if (data->pwm_settings[i][j] > abituguru_pwm_max[j]) {
+ ABIT_UGURU_DEBUG(2, " pwm channel %d does "
+ "not seem to be a pwm channel: "
+ "setting %d (%d) is above the maximum "
+ "value (%d)\n", i, j,
+ (int)data->pwm_settings[i][j],
+ (int)abituguru_pwm_max[j]);
+ goto abituguru_detect_no_pwms_exit;
+ }
+ }
+
+ /* check that min temp < max temp and min pwm < max pwm */
+ if (data->pwm_settings[i][1] >= data->pwm_settings[i][2]) {
+ ABIT_UGURU_DEBUG(2, " pwm channel %d does not seem "
+ "to be a pwm channel: min pwm (%d) >= "
+ "max pwm (%d)\n", i,
+ (int)data->pwm_settings[i][1],
+ (int)data->pwm_settings[i][2]);
+ break;
+ }
+ if (data->pwm_settings[i][3] >= data->pwm_settings[i][4]) {
+ ABIT_UGURU_DEBUG(2, " pwm channel %d does not seem "
+ "to be a pwm channel: min temp (%d) >= "
+ "max temp (%d)\n", i,
+ (int)data->pwm_settings[i][3],
+ (int)data->pwm_settings[i][4]);
+ break;
+ }
+ }
+
+abituguru_detect_no_pwms_exit:
+ data->pwms = i;
+ ABIT_UGURU_DEBUG(2, " found: %d PWM outputs\n", (int)data->pwms);
+}
+
+/* Following are the sysfs callback functions. These functions expect:
+ sensor_device_attribute_2->index: sensor address/offset in the bank
+ sensor_device_attribute_2->nr: register offset, bitmask or NA. */
+static struct abituguru_data *abituguru_update_device(struct device *dev);
+
+static ssize_t show_bank1_value(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru_data *data = abituguru_update_device(dev);
+ if (!data)
+ return -EIO;
+ return sprintf(buf, "%d\n", (data->bank1_value[attr->index] *
+ data->bank1_max_value[attr->index] + 128) / 255);
+}
+
+static ssize_t show_bank1_setting(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n",
+ (data->bank1_settings[attr->index][attr->nr] *
+ data->bank1_max_value[attr->index] + 128) / 255);
+}
+
+static ssize_t show_bank2_value(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru_data *data = abituguru_update_device(dev);
+ if (!data)
+ return -EIO;
+ return sprintf(buf, "%d\n", (data->bank2_value[attr->index] *
+ ABIT_UGURU_FAN_MAX + 128) / 255);
+}
+
+static ssize_t show_bank2_setting(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n",
+ (data->bank2_settings[attr->index][attr->nr] *
+ ABIT_UGURU_FAN_MAX + 128) / 255);
+}
+
+static ssize_t store_bank1_setting(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru_data *data = dev_get_drvdata(dev);
+ u8 val = (simple_strtoul(buf, NULL, 10) * 255 +
+ data->bank1_max_value[attr->index]/2) /
+ data->bank1_max_value[attr->index];
+ ssize_t ret = count;
+
+ mutex_lock(&data->update_lock);
+ if (data->bank1_settings[attr->index][attr->nr] != val) {
+ u8 orig_val = data->bank1_settings[attr->index][attr->nr];
+ data->bank1_settings[attr->index][attr->nr] = val;
+ if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2,
+ attr->index, data->bank1_settings[attr->index],
+ 3) <= attr->nr) {
+ data->bank1_settings[attr->index][attr->nr] = orig_val;
+ ret = -EIO;
+ }
+ }
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+static ssize_t store_bank2_setting(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru_data *data = dev_get_drvdata(dev);
+ u8 val = (simple_strtoul(buf, NULL, 10)*255 + ABIT_UGURU_FAN_MAX/2) /
+ ABIT_UGURU_FAN_MAX;
+ ssize_t ret = count;
+
+ /* this check can be done before taking the lock */
+ if ((val < abituguru_bank2_min_threshold) ||
+ (val > abituguru_bank2_max_threshold))
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ if (data->bank2_settings[attr->index][attr->nr] != val) {
+ u8 orig_val = data->bank2_settings[attr->index][attr->nr];
+ data->bank2_settings[attr->index][attr->nr] = val;
+ if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK2 + 2,
+ attr->index, data->bank2_settings[attr->index],
+ 2) <= attr->nr) {
+ data->bank2_settings[attr->index][attr->nr] = orig_val;
+ ret = -EIO;
+ }
+ }
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+static ssize_t show_bank1_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru_data *data = abituguru_update_device(dev);
+ if (!data)
+ return -EIO;
+ /* See if the alarm bit for this sensor is set, and if the
+ alarm matches the type of alarm we're looking for (for volt
+ it can be either low or high). The type is stored in a few
+ readonly bits in the settings part of the relevant sensor.
+ The bitmask of the type is passed to us in attr->nr. */
+ if ((data->alarms[attr->index / 8] & (0x01 << (attr->index % 8))) &&
+ (data->bank1_settings[attr->index][0] & attr->nr))
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t show_bank2_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru_data *data = abituguru_update_device(dev);
+ if (!data)
+ return -EIO;
+ if (data->alarms[2] & (0x01 << attr->index))
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t show_bank1_mask(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru_data *data = dev_get_drvdata(dev);
+ if (data->bank1_settings[attr->index][0] & attr->nr)
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t show_bank2_mask(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru_data *data = dev_get_drvdata(dev);
+ if (data->bank2_settings[attr->index][0] & attr->nr)
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t store_bank1_mask(struct device *dev,
+ struct device_attribute *devattr, const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru_data *data = dev_get_drvdata(dev);
+ int mask = simple_strtoul(buf, NULL, 10);
+ ssize_t ret = count;
+ u8 orig_val;
+
+ mutex_lock(&data->update_lock);
+ orig_val = data->bank1_settings[attr->index][0];
+
+ if (mask)
+ data->bank1_settings[attr->index][0] |= attr->nr;
+ else
+ data->bank1_settings[attr->index][0] &= ~attr->nr;
+
+ if ((data->bank1_settings[attr->index][0] != orig_val) &&
+ (abituguru_write(data,
+ ABIT_UGURU_SENSOR_BANK1 + 2, attr->index,
+ data->bank1_settings[attr->index], 3) < 1)) {
+ data->bank1_settings[attr->index][0] = orig_val;
+ ret = -EIO;
+ }
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+static ssize_t store_bank2_mask(struct device *dev,
+ struct device_attribute *devattr, const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru_data *data = dev_get_drvdata(dev);
+ int mask = simple_strtoul(buf, NULL, 10);
+ ssize_t ret = count;
+ u8 orig_val;
+
+ mutex_lock(&data->update_lock);
+ orig_val = data->bank2_settings[attr->index][0];
+
+ if (mask)
+ data->bank2_settings[attr->index][0] |= attr->nr;
+ else
+ data->bank2_settings[attr->index][0] &= ~attr->nr;
+
+ if ((data->bank2_settings[attr->index][0] != orig_val) &&
+ (abituguru_write(data,
+ ABIT_UGURU_SENSOR_BANK2 + 2, attr->index,
+ data->bank2_settings[attr->index], 2) < 1)) {
+ data->bank2_settings[attr->index][0] = orig_val;
+ ret = -EIO;
+ }
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+/* Fan PWM (speed control) */
+static ssize_t show_pwm_setting(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", data->pwm_settings[attr->index][attr->nr] *
+ abituguru_pwm_settings_multiplier[attr->nr]);
+}
+
+static ssize_t store_pwm_setting(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru_data *data = dev_get_drvdata(dev);
+ u8 min, val = (simple_strtoul(buf, NULL, 10) +
+ abituguru_pwm_settings_multiplier[attr->nr]/2) /
+ abituguru_pwm_settings_multiplier[attr->nr];
+ ssize_t ret = count;
+
+ /* special case pwm1 min pwm% */
+ if ((attr->index == 0) && ((attr->nr == 1) || (attr->nr == 2)))
+ min = 77;
+ else
+ min = abituguru_pwm_min[attr->nr];
+
+ /* this check can be done before taking the lock */
+ if ((val < min) || (val > abituguru_pwm_max[attr->nr]))
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ /* this check needs to be done after taking the lock */
+ if ((attr->nr & 1) &&
+ (val >= data->pwm_settings[attr->index][attr->nr + 1]))
+ ret = -EINVAL;
+ else if (!(attr->nr & 1) &&
+ (val <= data->pwm_settings[attr->index][attr->nr - 1]))
+ ret = -EINVAL;
+ else if (data->pwm_settings[attr->index][attr->nr] != val) {
+ u8 orig_val = data->pwm_settings[attr->index][attr->nr];
+ data->pwm_settings[attr->index][attr->nr] = val;
+ if (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1,
+ attr->index, data->pwm_settings[attr->index],
+ 5) <= attr->nr) {
+ data->pwm_settings[attr->index][attr->nr] =
+ orig_val;
+ ret = -EIO;
+ }
+ }
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+static ssize_t show_pwm_sensor(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru_data *data = dev_get_drvdata(dev);
+ int i;
+ /* We need to walk to the temp sensor addresses to find what
+ the userspace id of the configured temp sensor is. */
+ for (i = 0; i < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]; i++)
+ if (data->bank1_address[ABIT_UGURU_TEMP_SENSOR][i] ==
+ (data->pwm_settings[attr->index][0] & 0x0F))
+ return sprintf(buf, "%d\n", i+1);
+
+ return -ENXIO;
+}
+
+static ssize_t store_pwm_sensor(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru_data *data = dev_get_drvdata(dev);
+ unsigned long val = simple_strtoul(buf, NULL, 10) - 1;
+ ssize_t ret = count;
+
+ mutex_lock(&data->update_lock);
+ if (val < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]) {
+ u8 orig_val = data->pwm_settings[attr->index][0];
+ u8 address = data->bank1_address[ABIT_UGURU_TEMP_SENSOR][val];
+ data->pwm_settings[attr->index][0] &= 0xF0;
+ data->pwm_settings[attr->index][0] |= address;
+ if (data->pwm_settings[attr->index][0] != orig_val) {
+ if (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1,
+ attr->index,
+ data->pwm_settings[attr->index],
+ 5) < 1) {
+ data->pwm_settings[attr->index][0] = orig_val;
+ ret = -EIO;
+ }
+ }
+ }
+ else
+ ret = -EINVAL;
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+static ssize_t show_pwm_enable(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru_data *data = dev_get_drvdata(dev);
+ int res = 0;
+ if (data->pwm_settings[attr->index][0] & ABIT_UGURU_FAN_PWM_ENABLE)
+ res = 2;
+ return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru_data *data = dev_get_drvdata(dev);
+ u8 orig_val, user_val = simple_strtoul(buf, NULL, 10);
+ ssize_t ret = count;
+
+ mutex_lock(&data->update_lock);
+ orig_val = data->pwm_settings[attr->index][0];
+ switch (user_val) {
+ case 0:
+ data->pwm_settings[attr->index][0] &=
+ ~ABIT_UGURU_FAN_PWM_ENABLE;
+ break;
+ case 2:
+ data->pwm_settings[attr->index][0] |=
+ ABIT_UGURU_FAN_PWM_ENABLE;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ if ((data->pwm_settings[attr->index][0] != orig_val) &&
+ (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1,
+ attr->index, data->pwm_settings[attr->index],
+ 5) < 1)) {
+ data->pwm_settings[attr->index][0] = orig_val;
+ ret = -EIO;
+ }
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+static ssize_t show_name(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ return sprintf(buf, "%s\n", ABIT_UGURU_NAME);
+}
+
+/* Sysfs attr templates, the real entries are generated automatically. */
+static const
+struct sensor_device_attribute_2 abituguru_sysfs_bank1_templ[2][9] = {
+ {
+ SENSOR_ATTR_2(in%d_input, 0444, show_bank1_value, NULL, 0, 0),
+ SENSOR_ATTR_2(in%d_min, 0644, show_bank1_setting,
+ store_bank1_setting, 1, 0),
+ SENSOR_ATTR_2(in%d_min_alarm, 0444, show_bank1_alarm, NULL,
+ ABIT_UGURU_VOLT_LOW_ALARM_FLAG, 0),
+ SENSOR_ATTR_2(in%d_max, 0644, show_bank1_setting,
+ store_bank1_setting, 2, 0),
+ SENSOR_ATTR_2(in%d_max_alarm, 0444, show_bank1_alarm, NULL,
+ ABIT_UGURU_VOLT_HIGH_ALARM_FLAG, 0),
+ SENSOR_ATTR_2(in%d_beep, 0644, show_bank1_mask,
+ store_bank1_mask, ABIT_UGURU_BEEP_ENABLE, 0),
+ SENSOR_ATTR_2(in%d_shutdown, 0644, show_bank1_mask,
+ store_bank1_mask, ABIT_UGURU_SHUTDOWN_ENABLE, 0),
+ SENSOR_ATTR_2(in%d_min_alarm_enable, 0644, show_bank1_mask,
+ store_bank1_mask, ABIT_UGURU_VOLT_LOW_ALARM_ENABLE, 0),
+ SENSOR_ATTR_2(in%d_max_alarm_enable, 0644, show_bank1_mask,
+ store_bank1_mask, ABIT_UGURU_VOLT_HIGH_ALARM_ENABLE, 0),
+ }, {
+ SENSOR_ATTR_2(temp%d_input, 0444, show_bank1_value, NULL, 0, 0),
+ SENSOR_ATTR_2(temp%d_alarm, 0444, show_bank1_alarm, NULL,
+ ABIT_UGURU_TEMP_HIGH_ALARM_FLAG, 0),
+ SENSOR_ATTR_2(temp%d_max, 0644, show_bank1_setting,
+ store_bank1_setting, 1, 0),
+ SENSOR_ATTR_2(temp%d_crit, 0644, show_bank1_setting,
+ store_bank1_setting, 2, 0),
+ SENSOR_ATTR_2(temp%d_beep, 0644, show_bank1_mask,
+ store_bank1_mask, ABIT_UGURU_BEEP_ENABLE, 0),
+ SENSOR_ATTR_2(temp%d_shutdown, 0644, show_bank1_mask,
+ store_bank1_mask, ABIT_UGURU_SHUTDOWN_ENABLE, 0),
+ SENSOR_ATTR_2(temp%d_alarm_enable, 0644, show_bank1_mask,
+ store_bank1_mask, ABIT_UGURU_TEMP_HIGH_ALARM_ENABLE, 0),
+ }
+};
+
+static const struct sensor_device_attribute_2 abituguru_sysfs_fan_templ[6] = {
+ SENSOR_ATTR_2(fan%d_input, 0444, show_bank2_value, NULL, 0, 0),
+ SENSOR_ATTR_2(fan%d_alarm, 0444, show_bank2_alarm, NULL, 0, 0),
+ SENSOR_ATTR_2(fan%d_min, 0644, show_bank2_setting,
+ store_bank2_setting, 1, 0),
+ SENSOR_ATTR_2(fan%d_beep, 0644, show_bank2_mask,
+ store_bank2_mask, ABIT_UGURU_BEEP_ENABLE, 0),
+ SENSOR_ATTR_2(fan%d_shutdown, 0644, show_bank2_mask,
+ store_bank2_mask, ABIT_UGURU_SHUTDOWN_ENABLE, 0),
+ SENSOR_ATTR_2(fan%d_alarm_enable, 0644, show_bank2_mask,
+ store_bank2_mask, ABIT_UGURU_FAN_LOW_ALARM_ENABLE, 0),
+};
+
+static const struct sensor_device_attribute_2 abituguru_sysfs_pwm_templ[6] = {
+ SENSOR_ATTR_2(pwm%d_enable, 0644, show_pwm_enable,
+ store_pwm_enable, 0, 0),
+ SENSOR_ATTR_2(pwm%d_auto_channels_temp, 0644, show_pwm_sensor,
+ store_pwm_sensor, 0, 0),
+ SENSOR_ATTR_2(pwm%d_auto_point1_pwm, 0644, show_pwm_setting,
+ store_pwm_setting, 1, 0),
+ SENSOR_ATTR_2(pwm%d_auto_point2_pwm, 0644, show_pwm_setting,
+ store_pwm_setting, 2, 0),
+ SENSOR_ATTR_2(pwm%d_auto_point1_temp, 0644, show_pwm_setting,
+ store_pwm_setting, 3, 0),
+ SENSOR_ATTR_2(pwm%d_auto_point2_temp, 0644, show_pwm_setting,
+ store_pwm_setting, 4, 0),
+};
+
+static struct sensor_device_attribute_2 abituguru_sysfs_attr[] = {
+ SENSOR_ATTR_2(name, 0444, show_name, NULL, 0, 0),
+};
+
+static int __devinit abituguru_probe(struct platform_device *pdev)
+{
+ struct abituguru_data *data;
+ int i, j, used, sysfs_names_free, sysfs_attr_i, res = -ENODEV;
+ char *sysfs_filename;
+
+ /* El weirdo probe order, to keep the sysfs order identical to the
+ BIOS and window-appliction listing order. */
+ const u8 probe_order[ABIT_UGURU_MAX_BANK1_SENSORS] = {
+ 0x00, 0x01, 0x03, 0x04, 0x0A, 0x08, 0x0E, 0x02,
+ 0x09, 0x06, 0x05, 0x0B, 0x0F, 0x0D, 0x07, 0x0C };
+
+ if (!(data = kzalloc(sizeof(struct abituguru_data), GFP_KERNEL)))
+ return -ENOMEM;
+
+ data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
+ mutex_init(&data->update_lock);
+ platform_set_drvdata(pdev, data);
+
+ /* See if the uGuru is ready */
+ if (inb_p(data->addr + ABIT_UGURU_DATA) == ABIT_UGURU_STATUS_INPUT)
+ data->uguru_ready = 1;
+
+ /* Completely read the uGuru this has 2 purposes:
+ - testread / see if one really is there.
+ - make an in memory copy of all the uguru settings for future use. */
+ if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0,
+ data->alarms, 3, ABIT_UGURU_MAX_RETRIES) != 3)
+ goto abituguru_probe_error;
+
+ for (i = 0; i < ABIT_UGURU_MAX_BANK1_SENSORS; i++) {
+ if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1, i,
+ &data->bank1_value[i], 1,
+ ABIT_UGURU_MAX_RETRIES) != 1)
+ goto abituguru_probe_error;
+ if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1+1, i,
+ data->bank1_settings[i], 3,
+ ABIT_UGURU_MAX_RETRIES) != 3)
+ goto abituguru_probe_error;
+ }
+ /* Note: We don't know how many bank2 sensors / pwms there really are,
+ but in order to "detect" this we need to read the maximum amount
+ anyways. If we read sensors/pwms not there we'll just read crap
+ this can't hurt. We need the detection because we don't want
+ unwanted writes, which will hurt! */
+ for (i = 0; i < ABIT_UGURU_MAX_BANK2_SENSORS; i++) {
+ if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK2, i,
+ &data->bank2_value[i], 1,
+ ABIT_UGURU_MAX_RETRIES) != 1)
+ goto abituguru_probe_error;
+ if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK2+1, i,
+ data->bank2_settings[i], 2,
+ ABIT_UGURU_MAX_RETRIES) != 2)
+ goto abituguru_probe_error;
+ }
+ for (i = 0; i < ABIT_UGURU_MAX_PWMS; i++) {
+ if (abituguru_read(data, ABIT_UGURU_FAN_PWM, i,
+ data->pwm_settings[i], 5,
+ ABIT_UGURU_MAX_RETRIES) != 5)
+ goto abituguru_probe_error;
+ }
+ data->last_updated = jiffies;
+
+ /* Detect sensor types and fill the sysfs attr for bank1 */
+ sysfs_attr_i = 0;
+ sysfs_filename = data->sysfs_names;
+ sysfs_names_free = ABITUGURU_SYSFS_NAMES_LENGTH;
+ for (i = 0; i < ABIT_UGURU_MAX_BANK1_SENSORS; i++) {
+ res = abituguru_detect_bank1_sensor_type(data, probe_order[i]);
+ if (res < 0)
+ goto abituguru_probe_error;
+ if (res == ABIT_UGURU_NC)
+ continue;
+
+ /* res 1 (temp) sensors have 7 sysfs entries, 0 (in) 9 */
+ for (j = 0; j < (res ? 7 : 9); j++) {
+ used = snprintf(sysfs_filename, sysfs_names_free,
+ abituguru_sysfs_bank1_templ[res][j].dev_attr.
+ attr.name, data->bank1_sensors[res] + res)
+ + 1;
+ data->sysfs_attr[sysfs_attr_i] =
+ abituguru_sysfs_bank1_templ[res][j];
+ data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
+ sysfs_filename;
+ data->sysfs_attr[sysfs_attr_i].index = probe_order[i];
+ sysfs_filename += used;
+ sysfs_names_free -= used;
+ sysfs_attr_i++;
+ }
+ data->bank1_max_value[probe_order[i]] =
+ abituguru_bank1_max_value[res];
+ data->bank1_address[res][data->bank1_sensors[res]] =
+ probe_order[i];
+ data->bank1_sensors[res]++;
+ }
+ /* Detect number of sensors and fill the sysfs attr for bank2 (fans) */
+ abituguru_detect_no_bank2_sensors(data);
+ for (i = 0; i < data->bank2_sensors; i++) {
+ for (j = 0; j < ARRAY_SIZE(abituguru_sysfs_fan_templ); j++) {
+ used = snprintf(sysfs_filename, sysfs_names_free,
+ abituguru_sysfs_fan_templ[j].dev_attr.attr.name,
+ i + 1) + 1;
+ data->sysfs_attr[sysfs_attr_i] =
+ abituguru_sysfs_fan_templ[j];
+ data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
+ sysfs_filename;
+ data->sysfs_attr[sysfs_attr_i].index = i;
+ sysfs_filename += used;
+ sysfs_names_free -= used;
+ sysfs_attr_i++;
+ }
+ }
+ /* Detect number of sensors and fill the sysfs attr for pwms */
+ abituguru_detect_no_pwms(data);
+ for (i = 0; i < data->pwms; i++) {
+ for (j = 0; j < ARRAY_SIZE(abituguru_sysfs_pwm_templ); j++) {
+ used = snprintf(sysfs_filename, sysfs_names_free,
+ abituguru_sysfs_pwm_templ[j].dev_attr.attr.name,
+ i + 1) + 1;
+ data->sysfs_attr[sysfs_attr_i] =
+ abituguru_sysfs_pwm_templ[j];
+ data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
+ sysfs_filename;
+ data->sysfs_attr[sysfs_attr_i].index = i;
+ sysfs_filename += used;
+ sysfs_names_free -= used;
+ sysfs_attr_i++;
+ }
+ }
+ /* Fail safe check, this should never happen! */
+ if (sysfs_names_free < 0) {
+ printk(KERN_ERR ABIT_UGURU_NAME ": Fatal error ran out of "
+ "space for sysfs attr names. This should never "
+ "happen please report to the abituguru maintainer "
+ "(see MAINTAINERS)\n");
+ res = -ENAMETOOLONG;
+ goto abituguru_probe_error;
+ }
+ printk(KERN_INFO ABIT_UGURU_NAME ": found Abit uGuru\n");
+
+ /* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->class_dev)) {
+ res = PTR_ERR(data->class_dev);
+ goto abituguru_probe_error;
+ }
+ for (i = 0; i < sysfs_attr_i; i++)
+ device_create_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
+ for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
+ device_create_file(&pdev->dev,
+ &abituguru_sysfs_attr[i].dev_attr);
+
+ return 0;
+
+abituguru_probe_error:
+ kfree(data);
+ return res;
+}
+
+static int __devexit abituguru_remove(struct platform_device *pdev)
+{
+ struct abituguru_data *data = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ hwmon_device_unregister(data->class_dev);
+ kfree(data);
+
+ return 0;
+}
+
+static struct abituguru_data *abituguru_update_device(struct device *dev)
+{
+ int i, err;
+ struct abituguru_data *data = dev_get_drvdata(dev);
+ /* fake a complete successful read if no update necessary. */
+ char success = 1;
+
+ mutex_lock(&data->update_lock);
+ if (time_after(jiffies, data->last_updated + HZ)) {
+ success = 0;
+ if ((err = abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0,
+ data->alarms, 3, 0)) != 3)
+ goto LEAVE_UPDATE;
+ for (i = 0; i < ABIT_UGURU_MAX_BANK1_SENSORS; i++) {
+ if ((err = abituguru_read(data,
+ ABIT_UGURU_SENSOR_BANK1, i,
+ &data->bank1_value[i], 1, 0)) != 1)
+ goto LEAVE_UPDATE;
+ if ((err = abituguru_read(data,
+ ABIT_UGURU_SENSOR_BANK1 + 1, i,
+ data->bank1_settings[i], 3, 0)) != 3)
+ goto LEAVE_UPDATE;
+ }
+ for (i = 0; i < data->bank2_sensors; i++)
+ if ((err = abituguru_read(data,
+ ABIT_UGURU_SENSOR_BANK2, i,
+ &data->bank2_value[i], 1, 0)) != 1)
+ goto LEAVE_UPDATE;
+ /* success! */
+ success = 1;
+ data->update_timeouts = 0;
+LEAVE_UPDATE:
+ /* handle timeout condition */
+ if (err == -EBUSY) {
+ /* No overflow please */
+ if (data->update_timeouts < 255u)
+ data->update_timeouts++;
+ if (data->update_timeouts <= ABIT_UGURU_MAX_TIMEOUTS) {
+ ABIT_UGURU_DEBUG(3, "timeout exceeded, will "
+ "try again next update\n");
+ /* Just a timeout, fake a successful read */
+ success = 1;
+ } else
+ ABIT_UGURU_DEBUG(1, "timeout exceeded %d "
+ "times waiting for more input state\n",
+ (int)data->update_timeouts);
+ }
+ /* On success set last_updated */
+ if (success)
+ data->last_updated = jiffies;
+ }
+ mutex_unlock(&data->update_lock);
+
+ if (success)
+ return data;
+ else
+ return NULL;
+}
+
+static struct platform_driver abituguru_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = ABIT_UGURU_NAME,
+ },
+ .probe = abituguru_probe,
+ .remove = __devexit_p(abituguru_remove),
+};
+
+static int __init abituguru_detect(void)
+{
+ /* See if there is an uguru there. After a reboot uGuru will hold 0x00
+ at DATA and 0xAC, when this driver has already been loaded once
+ DATA will hold 0x08. For most uGuru's CMD will hold 0xAC in either
+ scenario but some will hold 0x00.
+ Some uGuru's initally hold 0x09 at DATA and will only hold 0x08
+ after reading CMD first, so CMD must be read first! */
+ u8 cmd_val = inb_p(ABIT_UGURU_BASE + ABIT_UGURU_CMD);
+ u8 data_val = inb_p(ABIT_UGURU_BASE + ABIT_UGURU_DATA);
+ if (((data_val == 0x00) || (data_val == 0x08)) &&
+ ((cmd_val == 0x00) || (cmd_val == 0xAC)))
+ return ABIT_UGURU_BASE;
+
+ ABIT_UGURU_DEBUG(2, "no Abit uGuru found, data = 0x%02X, cmd = "
+ "0x%02X\n", (unsigned int)data_val, (unsigned int)cmd_val);
+
+ if (force) {
+ printk(KERN_INFO ABIT_UGURU_NAME ": Assuming Abit uGuru is "
+ "present because of \"force\" parameter\n");
+ return ABIT_UGURU_BASE;
+ }
+
+ /* No uGuru found */
+ return -ENODEV;
+}
+
+static struct platform_device *abituguru_pdev;
+
+static int __init abituguru_init(void)
+{
+ int address, err;
+ struct resource res = { .flags = IORESOURCE_IO };
+
+ address = abituguru_detect();
+ if (address < 0)
+ return address;
+
+ err = platform_driver_register(&abituguru_driver);
+ if (err)
+ goto exit;
+
+ abituguru_pdev = platform_device_alloc(ABIT_UGURU_NAME, address);
+ if (!abituguru_pdev) {
+ printk(KERN_ERR ABIT_UGURU_NAME
+ ": Device allocation failed\n");
+ err = -ENOMEM;
+ goto exit_driver_unregister;
+ }
+
+ res.start = address;
+ res.end = address + ABIT_UGURU_REGION_LENGTH - 1;
+ res.name = ABIT_UGURU_NAME;
+
+ err = platform_device_add_resources(abituguru_pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR ABIT_UGURU_NAME
+ ": Device resource addition failed (%d)\n", err);
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(abituguru_pdev);
+ if (err) {
+ printk(KERN_ERR ABIT_UGURU_NAME
+ ": Device addition failed (%d)\n", err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(abituguru_pdev);
+exit_driver_unregister:
+ platform_driver_unregister(&abituguru_driver);
+exit:
+ return err;
+}
+
+static void __exit abituguru_exit(void)
+{
+ platform_device_unregister(abituguru_pdev);
+ platform_driver_unregister(&abituguru_driver);
+}
+
+MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
+MODULE_DESCRIPTION("Abit uGuru Sensor device");
+MODULE_LICENSE("GPL");
+
+module_init(abituguru_init);
+module_exit(abituguru_exit);
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index 885465d..fd72440 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -99,10 +99,6 @@ superio_exit(int base)
#define ADDR_REG_OFFSET 0
#define DATA_REG_OFFSET 1
-static struct resource f71805f_resource __initdata = {
- .flags = IORESOURCE_IO,
-};
-
/*
* Registers
*/
@@ -782,6 +778,11 @@ static struct platform_driver f71805f_driver = {
static int __init f71805f_device_add(unsigned short address)
{
+ struct resource res = {
+ .start = address,
+ .end = address + REGION_LENGTH - 1,
+ .flags = IORESOURCE_IO,
+ };
int err;
pdev = platform_device_alloc(DRVNAME, address);
@@ -791,10 +792,8 @@ static int __init f71805f_device_add(unsigned short address)
goto exit;
}
- f71805f_resource.start = address;
- f71805f_resource.end = address + REGION_LENGTH - 1;
- f71805f_resource.name = pdev->name;
- err = platform_device_add_resources(pdev, &f71805f_resource, 1);
+ res.name = pdev->name;
+ err = platform_device_add_resources(pdev, &res, 1);
if (err) {
printk(KERN_ERR DRVNAME ": Device resource addition failed "
"(%d)\n", err);
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
index 1659f6c..42b6328 100644
--- a/drivers/hwmon/hdaps.c
+++ b/drivers/hwmon/hdaps.c
@@ -41,7 +41,7 @@
#define HDAPS_PORT_STATE 0x1611 /* device state */
#define HDAPS_PORT_YPOS 0x1612 /* y-axis position */
#define HDAPS_PORT_XPOS 0x1614 /* x-axis position */
-#define HDAPS_PORT_TEMP1 0x1616 /* device temperature, in celcius */
+#define HDAPS_PORT_TEMP1 0x1616 /* device temperature, in Celsius */
#define HDAPS_PORT_YVAR 0x1617 /* y-axis variance (what is this?) */
#define HDAPS_PORT_XVAR 0x1619 /* x-axis variance (what is this?) */
#define HDAPS_PORT_TEMP2 0x161b /* device temperature (again?) */
@@ -522,13 +522,15 @@ static int __init hdaps_init(void)
{
int ret;
- /* Note that DMI_MATCH(...,"ThinkPad T42") will match "ThinkPad T42p" */
+ /* Note that HDAPS_DMI_MATCH_NORMAL("ThinkPad T42") would match
+ "ThinkPad T42p", so the order of the entries matters */
struct dmi_system_id hdaps_whitelist[] = {
HDAPS_DMI_MATCH_NORMAL("ThinkPad H"),
HDAPS_DMI_MATCH_INVERT("ThinkPad R50p"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad R50"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad R51"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad R52"),
+ HDAPS_DMI_MATCH_NORMAL("ThinkPad H"), /* R52 (1846AQG) */
HDAPS_DMI_MATCH_INVERT("ThinkPad T41p"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad T41"),
HDAPS_DMI_MATCH_INVERT("ThinkPad T42p"),
@@ -536,9 +538,9 @@ static int __init hdaps_init(void)
HDAPS_DMI_MATCH_NORMAL("ThinkPad T43"),
HDAPS_DMI_MATCH_LENOVO("ThinkPad T60p"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad X40"),
- HDAPS_DMI_MATCH_NORMAL("ThinkPad X41 Tablet"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad X41"),
HDAPS_DMI_MATCH_LENOVO("ThinkPad X60"),
+ HDAPS_DMI_MATCH_NORMAL("ThinkPad Z60m"),
{ .ident = NULL }
};
diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c
index a74a44f..a6764ff 100644
--- a/drivers/hwmon/hwmon-vid.c
+++ b/drivers/hwmon/hwmon-vid.c
@@ -58,11 +58,20 @@
doesn't seem to be any named specification for these. The conversion
tables are detailed directly in the various Pentium M datasheets:
http://www.intel.com/design/intarch/pentiumm/docs_pentiumm.htm
+
+ The 14 specification corresponds to Intel Core series. There
+ doesn't seem to be any named specification for these. The conversion
+ tables are detailed directly in the various Pentium Core datasheets:
+ http://www.intel.com/design/mobile/datashts/309221.htm
+
+ The 110 (VRM 11) specification corresponds to Intel Conroe based series.
+ http://www.intel.com/design/processor/applnots/313214.htm
*/
/* vrm is the VRM/VRD document version multiplied by 10.
- val is the 4-, 5- or 6-bit VID code.
- Returned value is in mV to avoid floating point in the kernel. */
+ val is the 4-bit or more VID code.
+ Returned value is in mV to avoid floating point in the kernel.
+ Some VID have some bits in uV scale, this is rounded to mV */
int vid_from_reg(int val, u8 vrm)
{
int vid;
@@ -70,26 +79,36 @@ int vid_from_reg(int val, u8 vrm)
switch(vrm) {
case 100: /* VRD 10.0 */
+ /* compute in uV, round to mV */
+ val &= 0x3f;
if((val & 0x1f) == 0x1f)
return 0;
if((val & 0x1f) <= 0x09 || val == 0x0a)
- vid = 10875 - (val & 0x1f) * 250;
+ vid = 1087500 - (val & 0x1f) * 25000;
else
- vid = 18625 - (val & 0x1f) * 250;
+ vid = 1862500 - (val & 0x1f) * 25000;
if(val & 0x20)
- vid -= 125;
- vid /= 10; /* only return 3 dec. places for now */
- return vid;
+ vid -= 12500;
+ return((vid + 500) / 1000);
+ case 110: /* Intel Conroe */
+ /* compute in uV, round to mV */
+ val &= 0xff;
+ if(((val & 0x7e) == 0xfe) || (!(val & 0x7e)))
+ return 0;
+ return((1600000 - (val - 2) * 6250 + 500) / 1000);
case 24: /* Opteron processor */
+ val &= 0x1f;
return(val == 0x1f ? 0 : 1550 - val * 25);
case 91: /* VRM 9.1 */
case 90: /* VRM 9.0 */
+ val &= 0x1f;
return(val == 0x1f ? 0 :
1850 - val * 25);
case 85: /* VRM 8.5 */
+ val &= 0x1f;
return((val & 0x10 ? 25 : 0) +
((val & 0x0f) > 0x04 ? 2050 : 1250) -
((val & 0x0f) * 50));
@@ -98,14 +117,21 @@ int vid_from_reg(int val, u8 vrm)
val &= 0x0f;
/* fall through */
case 82: /* VRM 8.2 */
+ val &= 0x1f;
return(val == 0x1f ? 0 :
val & 0x10 ? 5100 - (val) * 100 :
2050 - (val) * 50);
case 17: /* Intel IMVP-II */
+ val &= 0x1f;
return(val & 0x10 ? 975 - (val & 0xF) * 25 :
1750 - val * 50);
case 13:
- return(1708 - (val & 0x3f) * 16);
+ val &= 0x3f;
+ return(1708 - val * 16);
+ case 14: /* Intel Core */
+ /* compute in uV, round to mV */
+ val &= 0x7f;
+ return(val > 0x77 ? 0 : (1500000 - (val * 12500) + 500) / 1000);
default: /* report 0 for unknown */
printk(KERN_INFO "hwmon-vid: requested unknown VRM version\n");
return 0;
@@ -138,6 +164,8 @@ static struct vrm_model vrm_models[] = {
{X86_VENDOR_INTEL, 0x6, 0x9, ANY, 13}, /* Pentium M (130 nm) */
{X86_VENDOR_INTEL, 0x6, 0xB, ANY, 85}, /* Tualatin */
{X86_VENDOR_INTEL, 0x6, 0xD, ANY, 13}, /* Pentium M (90 nm) */
+ {X86_VENDOR_INTEL, 0x6, 0xE, ANY, 14}, /* Intel Core (65 nm) */
+ {X86_VENDOR_INTEL, 0x6, 0xF, ANY, 110}, /* Intel Conroe */
{X86_VENDOR_INTEL, 0x6, ANY, ANY, 82}, /* any P6 */
{X86_VENDOR_INTEL, 0x7, ANY, ANY, 0}, /* Itanium */
{X86_VENDOR_INTEL, 0xF, 0x0, ANY, 90}, /* P4 */
diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c
new file mode 100644
index 0000000..6ba8473
--- /dev/null
+++ b/drivers/hwmon/lm70.c
@@ -0,0 +1,165 @@
+/*
+ * lm70.c
+ *
+ * The LM70 is a temperature sensor chip from National Semiconductor (NS).
+ * Copyright (C) 2006 Kaiwan N Billimoria <kaiwan@designergraphix.com>
+ *
+ * The LM70 communicates with a host processor via an SPI/Microwire Bus
+ * interface. The complete datasheet is available at National's website
+ * here:
+ * http://www.national.com/pf/LM/LM70.html
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/spi/spi.h>
+#include <asm/semaphore.h>
+
+#define DRVNAME "lm70"
+
+struct lm70 {
+ struct class_device *cdev;
+ struct semaphore sem;
+};
+
+/* sysfs hook function */
+static ssize_t lm70_sense_temp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ int status, val;
+ u8 rxbuf[2];
+ s16 raw=0;
+ struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev);
+
+ if (down_interruptible(&p_lm70->sem))
+ return -ERESTARTSYS;
+
+ /*
+ * spi_read() requires a DMA-safe buffer; so we use
+ * spi_write_then_read(), transmitting 0 bytes.
+ */
+ status = spi_write_then_read(spi, NULL, 0, &rxbuf[0], 2);
+ if (status < 0) {
+ printk(KERN_WARNING
+ "spi_write_then_read failed with status %d\n", status);
+ goto out;
+ }
+ dev_dbg(dev, "rxbuf[1] : 0x%x rxbuf[0] : 0x%x\n", rxbuf[1], rxbuf[0]);
+
+ raw = (rxbuf[1] << 8) + rxbuf[0];
+ dev_dbg(dev, "raw=0x%x\n", raw);
+
+ /*
+ * The "raw" temperature read into rxbuf[] is a 16-bit signed 2's
+ * complement value. Only the MSB 11 bits (1 sign + 10 temperature
+ * bits) are meaningful; the LSB 5 bits are to be discarded.
+ * See the datasheet.
+ *
+ * Further, each bit represents 0.25 degrees Celsius; so, multiply
+ * by 0.25. Also multiply by 1000 to represent in millidegrees
+ * Celsius.
+ * So it's equivalent to multiplying by 0.25 * 1000 = 250.
+ */
+ val = ((int)raw/32) * 250;
+ status = sprintf(buf, "%+d\n", val); /* millidegrees Celsius */
+out:
+ up(&p_lm70->sem);
+ return status;
+}
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, lm70_sense_temp, NULL);
+
+/*----------------------------------------------------------------------*/
+
+static int __devinit lm70_probe(struct spi_device *spi)
+{
+ struct lm70 *p_lm70;
+ int status;
+
+ p_lm70 = kzalloc(sizeof *p_lm70, GFP_KERNEL);
+ if (!p_lm70)
+ return -ENOMEM;
+
+ init_MUTEX(&p_lm70->sem);
+
+ /* sysfs hook */
+ p_lm70->cdev = hwmon_device_register(&spi->dev);
+ if (IS_ERR(p_lm70->cdev)) {
+ dev_dbg(&spi->dev, "hwmon_device_register failed.\n");
+ status = PTR_ERR(p_lm70->cdev);
+ goto out_dev_reg_failed;
+ }
+ dev_set_drvdata(&spi->dev, p_lm70);
+
+ if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input))) {
+ dev_dbg(&spi->dev, "device_create_file failure.\n");
+ goto out_dev_create_file_failed;
+ }
+
+ return 0;
+
+out_dev_create_file_failed:
+ hwmon_device_unregister(p_lm70->cdev);
+out_dev_reg_failed:
+ dev_set_drvdata(&spi->dev, NULL);
+ kfree(p_lm70);
+ return status;
+}
+
+static int __exit lm70_remove(struct spi_device *spi)
+{
+ struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev);
+
+ device_remove_file(&spi->dev, &dev_attr_temp1_input);
+ hwmon_device_unregister(p_lm70->cdev);
+ dev_set_drvdata(&spi->dev, NULL);
+ kfree(p_lm70);
+
+ return 0;
+}
+
+static struct spi_driver lm70_driver = {
+ .driver = {
+ .name = "lm70",
+ .owner = THIS_MODULE,
+ },
+ .probe = lm70_probe,
+ .remove = __devexit_p(lm70_remove),
+};
+
+static int __init init_lm70(void)
+{
+ return spi_register_driver(&lm70_driver);
+}
+
+static void __exit cleanup_lm70(void)
+{
+ spi_unregister_driver(&lm70_driver);
+}
+
+module_init(init_lm70);
+module_exit(cleanup_lm70);
+
+MODULE_AUTHOR("Kaiwan N Billimoria");
+MODULE_DESCRIPTION("National Semiconductor LM70 Linux driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c
index aac4ec2..2137d78 100644
--- a/drivers/hwmon/lm83.c
+++ b/drivers/hwmon/lm83.c
@@ -12,6 +12,10 @@
* Since the datasheet omits to give the chip stepping code, I give it
* here: 0x03 (at register 0xff).
*
+ * Also supports the LM82 temp sensor, which is basically a stripped down
+ * model of the LM83. Datasheet is here:
+ * http://www.national.com/pf/LM/LM82.html
+ *
* 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
@@ -52,7 +56,7 @@ static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
* Insmod parameters
*/
-I2C_CLIENT_INSMOD_1(lm83);
+I2C_CLIENT_INSMOD_2(lm83, lm82);
/*
* The LM83 registers
@@ -283,6 +287,9 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
if (man_id == 0x01) { /* National Semiconductor */
if (chip_id == 0x03) {
kind = lm83;
+ } else
+ if (chip_id == 0x01) {
+ kind = lm82;
}
}
@@ -296,6 +303,9 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
if (kind == lm83) {
name = "lm83";
+ } else
+ if (kind == lm82) {
+ name = "lm82";
}
/* We can fill in the remaining client fields */
@@ -319,32 +329,46 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_detach;
}
+ /*
+ * The LM82 can only monitor one external diode which is
+ * at the same register as the LM83 temp3 entry - so we
+ * declare 1 and 3 common, and then 2 and 4 only for the LM83.
+ */
+
device_create_file(&new_client->dev,
&sensor_dev_attr_temp1_input.dev_attr);
device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_input.dev_attr);
- device_create_file(&new_client->dev,
&sensor_dev_attr_temp3_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp4_input.dev_attr);
+
device_create_file(&new_client->dev,
&sensor_dev_attr_temp1_max.dev_attr);
device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_max.dev_attr);
- device_create_file(&new_client->dev,
&sensor_dev_attr_temp3_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp4_max.dev_attr);
+
device_create_file(&new_client->dev,
&sensor_dev_attr_temp1_crit.dev_attr);
device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_crit.dev_attr);
- device_create_file(&new_client->dev,
&sensor_dev_attr_temp3_crit.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp4_crit.dev_attr);
+
device_create_file(&new_client->dev, &dev_attr_alarms);
+ if (kind == lm83) {
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp2_input.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp4_input.dev_attr);
+
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp2_max.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp4_max.dev_attr);
+
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp2_crit.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp4_crit.dev_attr);
+ }
+
return 0;
exit_detach:
diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c
new file mode 100644
index 0000000..bdc4570
--- /dev/null
+++ b/drivers/hwmon/smsc47m192.c
@@ -0,0 +1,648 @@
+/*
+ smsc47m192.c - Support for hardware monitoring block of
+ SMSC LPC47M192 and LPC47M997 Super I/O chips
+
+ Copyright (C) 2006 Hartmut Rick <linux@rick.claranet.de>
+
+ Derived from lm78.c and other chip drivers.
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(smsc47m192);
+
+/* SMSC47M192 registers */
+#define SMSC47M192_REG_IN(nr) ((nr)<6 ? (0x20 + (nr)) : \
+ (0x50 + (nr) - 6))
+#define SMSC47M192_REG_IN_MAX(nr) ((nr)<6 ? (0x2b + (nr) * 2) : \
+ (0x54 + (((nr) - 6) * 2)))
+#define SMSC47M192_REG_IN_MIN(nr) ((nr)<6 ? (0x2c + (nr) * 2) : \
+ (0x55 + (((nr) - 6) * 2)))
+static u8 SMSC47M192_REG_TEMP[3] = { 0x27, 0x26, 0x52 };
+static u8 SMSC47M192_REG_TEMP_MAX[3] = { 0x39, 0x37, 0x58 };
+static u8 SMSC47M192_REG_TEMP_MIN[3] = { 0x3A, 0x38, 0x59 };
+#define SMSC47M192_REG_TEMP_OFFSET(nr) ((nr)==2 ? 0x1e : 0x1f)
+#define SMSC47M192_REG_ALARM1 0x41
+#define SMSC47M192_REG_ALARM2 0x42
+#define SMSC47M192_REG_VID 0x47
+#define SMSC47M192_REG_VID4 0x49
+#define SMSC47M192_REG_CONFIG 0x40
+#define SMSC47M192_REG_SFR 0x4f
+#define SMSC47M192_REG_COMPANY_ID 0x3e
+#define SMSC47M192_REG_VERSION 0x3f
+
+/* generalised scaling with integer rounding */
+static inline int SCALE(long val, int mul, int div)
+{
+ if (val < 0)
+ return (val * mul - div / 2) / div;
+ else
+ return (val * mul + div / 2) / div;
+}
+
+/* Conversions */
+
+/* smsc47m192 internally scales voltage measurements */
+static const u16 nom_mv[] = { 2500, 2250, 3300, 5000, 12000, 3300, 1500, 1800 };
+
+static inline unsigned int IN_FROM_REG(u8 reg, int n)
+{
+ return SCALE(reg, nom_mv[n], 192);
+}
+
+static inline u8 IN_TO_REG(unsigned long val, int n)
+{
+ return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255);
+}
+
+/* TEMP: 0.001 degC units (-128C to +127C)
+ REG: 1C/bit, two's complement */
+static inline s8 TEMP_TO_REG(int val)
+{
+ return SENSORS_LIMIT(SCALE(val, 1, 1000), -128000, 127000);
+}
+
+static inline int TEMP_FROM_REG(s8 val)
+{
+ return val * 1000;
+}
+
+struct smsc47m192_data {
+ struct i2c_client client;
+ struct class_device *class_dev;
+ struct semaphore update_lock;
+ char valid; /* !=0 if following fields are valid */
+ unsigned long last_updated; /* In jiffies */
+
+ u8 in[8]; /* Register value */
+ u8 in_max[8]; /* Register value */
+ u8 in_min[8]; /* Register value */
+ s8 temp[3]; /* Register value */
+ s8 temp_max[3]; /* Register value */
+ s8 temp_min[3]; /* Register value */
+ s8 temp_offset[3]; /* Register value */
+ u16 alarms; /* Register encoding, combined */
+ u8 vid; /* Register encoding, combined */
+ u8 vrm;
+};
+
+static int smsc47m192_attach_adapter(struct i2c_adapter *adapter);
+static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
+ int kind);
+static int smsc47m192_detach_client(struct i2c_client *client);
+static struct smsc47m192_data *smsc47m192_update_device(struct device *dev);
+
+static struct i2c_driver smsc47m192_driver = {
+ .driver = {
+ .name = "smsc47m192",
+ },
+ .attach_adapter = smsc47m192_attach_adapter,
+ .detach_client = smsc47m192_detach_client,
+};
+
+/* Voltages */
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct smsc47m192_data *data = smsc47m192_update_device(dev);
+ return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], nr));
+}
+
+static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct smsc47m192_data *data = smsc47m192_update_device(dev);
+ return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr], nr));
+}
+
+static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct smsc47m192_data *data = smsc47m192_update_device(dev);
+ return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr], nr));
+}
+
+static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct smsc47m192_data *data = i2c_get_clientdata(client);
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->in_min[nr] = IN_TO_REG(val, nr);
+ i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MIN(nr),
+ data->in_min[nr]);
+ up(&data->update_lock);
+ return count;
+}
+
+static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct smsc47m192_data *data = i2c_get_clientdata(client);
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->in_max[nr] = IN_TO_REG(val, nr);
+ i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MAX(nr),
+ data->in_max[nr]);
+ up(&data->update_lock);
+ return count;
+}
+
+#define show_in_offset(offset) \
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+ show_in, NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+ show_in_min, set_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+ show_in_max, set_in_max, offset);
+
+show_in_offset(0)
+show_in_offset(1)
+show_in_offset(2)
+show_in_offset(3)
+show_in_offset(4)
+show_in_offset(5)
+show_in_offset(6)
+show_in_offset(7)
+
+/* Temperatures */
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct smsc47m192_data *data = smsc47m192_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));
+}
+
+static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct smsc47m192_data *data = smsc47m192_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr]));
+}
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct smsc47m192_data *data = smsc47m192_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr]));
+}
+
+static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct smsc47m192_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->temp_min[nr] = TEMP_TO_REG(val);
+ i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MIN[nr],
+ data->temp_min[nr]);
+ up(&data->update_lock);
+ return count;
+}
+
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct smsc47m192_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->temp_max[nr] = TEMP_TO_REG(val);
+ i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MAX[nr],
+ data->temp_max[nr]);
+ up(&data->update_lock);
+ return count;
+}
+
+static ssize_t show_temp_offset(struct device *dev, struct device_attribute
+ *attr, char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct smsc47m192_data *data = smsc47m192_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_offset[nr]));
+}
+
+static ssize_t set_temp_offset(struct device *dev, struct device_attribute
+ *attr, const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct smsc47m192_data *data = i2c_get_clientdata(client);
+ u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->temp_offset[nr] = TEMP_TO_REG(val);
+ if (nr>1)
+ i2c_smbus_write_byte_data(client,
+ SMSC47M192_REG_TEMP_OFFSET(nr), data->temp_offset[nr]);
+ else if (data->temp_offset[nr] != 0) {
+ /* offset[0] and offset[1] share the same register,
+ SFR bit 4 activates offset[0] */
+ i2c_smbus_write_byte_data(client, SMSC47M192_REG_SFR,
+ (sfr & 0xef) | (nr==0 ? 0x10 : 0));
+ data->temp_offset[1-nr] = 0;
+ i2c_smbus_write_byte_data(client,
+ SMSC47M192_REG_TEMP_OFFSET(nr), data->temp_offset[nr]);
+ } else if ((sfr & 0x10) == (nr==0 ? 0x10 : 0))
+ i2c_smbus_write_byte_data(client,
+ SMSC47M192_REG_TEMP_OFFSET(nr), 0);
+ up(&data->update_lock);
+ return count;
+}
+
+#define show_temp_index(index) \
+static SENSOR_DEVICE_ATTR(temp##index##_input, S_IRUGO, \
+ show_temp, NULL, index-1); \
+static SENSOR_DEVICE_ATTR(temp##index##_min, S_IRUGO | S_IWUSR, \
+ show_temp_min, set_temp_min, index-1); \
+static SENSOR_DEVICE_ATTR(temp##index##_max, S_IRUGO | S_IWUSR, \
+ show_temp_max, set_temp_max, index-1); \
+static SENSOR_DEVICE_ATTR(temp##index##_offset, S_IRUGO | S_IWUSR, \
+ show_temp_offset, set_temp_offset, index-1);
+
+show_temp_index(1)
+show_temp_index(2)
+show_temp_index(3)
+
+/* VID */
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct smsc47m192_data *data = smsc47m192_update_device(dev);
+ return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct smsc47m192_data *data = smsc47m192_update_device(dev);
+ return sprintf(buf, "%d\n", data->vrm);
+}
+
+static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct smsc47m192_data *data = i2c_get_clientdata(client);
+ data->vrm = simple_strtoul(buf, NULL, 10);
+ return count;
+}
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
+
+/* Alarms */
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct smsc47m192_data *data = smsc47m192_update_device(dev);
+ return sprintf(buf, "%u\n", (data->alarms & nr) ? 1 : 0);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0x0010);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 0x0020);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 0x0040);
+static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 0x4000);
+static SENSOR_DEVICE_ATTR(temp3_input_fault, S_IRUGO, show_alarm, NULL, 0x8000);
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0x0001);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 0x0002);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 0x0004);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 0x0008);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 0x0100);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 0x0200);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 0x0400);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 0x0800);
+
+/* This function is called when:
+ * smsc47m192_driver is inserted (when this module is loaded), for each
+ available adapter
+ * when a new adapter is inserted (and smsc47m192_driver is still present) */
+static int smsc47m192_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON))
+ return 0;
+ return i2c_probe(adapter, &addr_data, smsc47m192_detect);
+}
+
+static void smsc47m192_init_client(struct i2c_client *client)
+{
+ int i;
+ u8 config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG);
+ u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
+
+ /* select cycle mode (pause 1 sec between updates) */
+ i2c_smbus_write_byte_data(client, SMSC47M192_REG_SFR,
+ (sfr & 0xfd) | 0x02);
+ if (!(config & 0x01)) {
+ /* initialize alarm limits */
+ for (i=0; i<8; i++) {
+ i2c_smbus_write_byte_data(client,
+ SMSC47M192_REG_IN_MIN(i), 0);
+ i2c_smbus_write_byte_data(client,
+ SMSC47M192_REG_IN_MAX(i), 0xff);
+ }
+ for (i=0; i<3; i++) {
+ i2c_smbus_write_byte_data(client,
+ SMSC47M192_REG_TEMP_MIN[i], 0x80);
+ i2c_smbus_write_byte_data(client,
+ SMSC47M192_REG_TEMP_MAX[i], 0x7f);
+ }
+
+ /* start monitoring */
+ i2c_smbus_write_byte_data(client, SMSC47M192_REG_CONFIG,
+ (config & 0xf7) | 0x01);
+ }
+}
+
+/* This function is called by i2c_probe */
+static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
+ int kind)
+{
+ struct i2c_client *client;
+ struct smsc47m192_data *data;
+ int err = 0;
+ int version, config;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ goto exit;
+
+ if (!(data = kzalloc(sizeof(struct smsc47m192_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &smsc47m192_driver;
+
+ if (kind == 0)
+ kind = smsc47m192;
+
+ /* Detection criteria from sensors_detect script */
+ if (kind < 0) {
+ if (i2c_smbus_read_byte_data(client,
+ SMSC47M192_REG_COMPANY_ID) == 0x55
+ && ((version = i2c_smbus_read_byte_data(client,
+ SMSC47M192_REG_VERSION)) & 0xf0) == 0x20
+ && (i2c_smbus_read_byte_data(client,
+ SMSC47M192_REG_VID) & 0x70) == 0x00
+ && (i2c_smbus_read_byte_data(client,
+ SMSC47M192_REG_VID4) & 0xfe) == 0x80) {
+ dev_info(&adapter->dev,
+ "found SMSC47M192 or SMSC47M997, "
+ "version 2, stepping A%d\n", version & 0x0f);
+ } else {
+ dev_dbg(&adapter->dev,
+ "SMSC47M192 detection failed at 0x%02x\n",
+ address);
+ goto exit_free;
+ }
+ }
+
+ /* Fill in the remaining client fields and put into the global list */
+ strlcpy(client->name, "smsc47m192", I2C_NAME_SIZE);
+ data->vrm = vid_which_vrm();
+ init_MUTEX(&data->update_lock);
+
+ /* Tell the I2C layer a new client has arrived */
+ if ((err = i2c_attach_client(client)))
+ goto exit_free;
+
+ /* Initialize the SMSC47M192 chip */
+ smsc47m192_init_client(client);
+
+ /* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
+ device_create_file(&client->dev, &sensor_dev_attr_in0_input.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in0_min.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in0_max.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in0_alarm.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in1_input.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in1_min.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in1_max.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in1_alarm.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in2_input.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in2_min.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in2_max.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in2_alarm.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in3_input.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in3_min.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in3_max.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in3_alarm.dev_attr);
+
+ /* Pin 110 is either in4 (+12V) or VID4 */
+ config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG);
+ if (!(config & 0x20)) {
+ device_create_file(&client->dev,
+ &sensor_dev_attr_in4_input.dev_attr);
+ device_create_file(&client->dev,
+ &sensor_dev_attr_in4_min.dev_attr);
+ device_create_file(&client->dev,
+ &sensor_dev_attr_in4_max.dev_attr);
+ device_create_file(&client->dev,
+ &sensor_dev_attr_in4_alarm.dev_attr);
+ }
+ device_create_file(&client->dev, &sensor_dev_attr_in5_input.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in5_min.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in5_max.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in5_alarm.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in6_input.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in6_min.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in6_max.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in6_alarm.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in7_input.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in7_min.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in7_max.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_in7_alarm.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_temp1_input.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_temp1_max.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_temp1_min.dev_attr);
+ device_create_file(&client->dev,
+ &sensor_dev_attr_temp1_offset.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_temp1_alarm.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_temp2_input.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_temp2_max.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_temp2_min.dev_attr);
+ device_create_file(&client->dev,
+ &sensor_dev_attr_temp2_offset.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_temp2_alarm.dev_attr);
+ device_create_file(&client->dev,
+ &sensor_dev_attr_temp2_input_fault.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_temp3_input.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_temp3_max.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_temp3_min.dev_attr);
+ device_create_file(&client->dev,
+ &sensor_dev_attr_temp3_offset.dev_attr);
+ device_create_file(&client->dev, &sensor_dev_attr_temp3_alarm.dev_attr);
+ device_create_file(&client->dev,
+ &sensor_dev_attr_temp3_input_fault.dev_attr);
+ device_create_file(&client->dev, &dev_attr_cpu0_vid);
+ device_create_file(&client->dev, &dev_attr_vrm);
+
+ return 0;
+
+exit_detach:
+ i2c_detach_client(client);
+exit_free:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int smsc47m192_detach_client(struct i2c_client *client)
+{
+ struct smsc47m192_data *data = i2c_get_clientdata(client);
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(data);
+
+ return 0;
+}
+
+static struct smsc47m192_data *smsc47m192_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct smsc47m192_data *data = i2c_get_clientdata(client);
+ int i, config;
+
+ down(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+ || !data->valid) {
+ u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
+
+ dev_dbg(&client->dev, "Starting smsc47m192 update\n");
+
+ for (i = 0; i <= 7; i++) {
+ data->in[i] = i2c_smbus_read_byte_data(client,
+ SMSC47M192_REG_IN(i));
+ data->in_min[i] = i2c_smbus_read_byte_data(client,
+ SMSC47M192_REG_IN_MIN(i));
+ data->in_max[i] = i2c_smbus_read_byte_data(client,
+ SMSC47M192_REG_IN_MAX(i));
+ }
+ for (i = 0; i < 3; i++) {
+ data->temp[i] = i2c_smbus_read_byte_data(client,
+ SMSC47M192_REG_TEMP[i]);
+ data->temp_max[i] = i2c_smbus_read_byte_data(client,
+ SMSC47M192_REG_TEMP_MAX[i]);
+ data->temp_min[i] = i2c_smbus_read_byte_data(client,
+ SMSC47M192_REG_TEMP_MIN[i]);
+ }
+ for (i = 1; i < 3; i++)
+ data->temp_offset[i] = i2c_smbus_read_byte_data(client,
+ SMSC47M192_REG_TEMP_OFFSET(i));
+ /* first offset is temp_offset[0] if SFR bit 4 is set,
+ temp_offset[1] otherwise */
+ if (sfr & 0x10) {
+ data->temp_offset[0] = data->temp_offset[1];
+ data->temp_offset[1] = 0;
+ } else
+ data->temp_offset[0] = 0;
+
+ data->vid = i2c_smbus_read_byte_data(client, SMSC47M192_REG_VID)
+ & 0x0f;
+ config = i2c_smbus_read_byte_data(client,
+ SMSC47M192_REG_CONFIG);
+ if (config & 0x20)
+ data->vid |= (i2c_smbus_read_byte_data(client,
+ SMSC47M192_REG_VID4) & 0x01) << 4;
+ data->alarms = i2c_smbus_read_byte_data(client,
+ SMSC47M192_REG_ALARM1) |
+ (i2c_smbus_read_byte_data(client,
+ SMSC47M192_REG_ALARM2) << 8);
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ up(&data->update_lock);
+
+ return data;
+}
+
+static int __init smsc47m192_init(void)
+{
+ return i2c_add_driver(&smsc47m192_driver);
+}
+
+static void __exit smsc47m192_exit(void)
+{
+ i2c_del_driver(&smsc47m192_driver);
+}
+
+MODULE_AUTHOR("Hartmut Rick <linux@rick.claranet.de>");
+MODULE_DESCRIPTION("SMSC47M192 driver");
+MODULE_LICENSE("GPL");
+
+module_init(smsc47m192_init);
+module_exit(smsc47m192_exit);
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index b6bd568..40301bc 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -30,10 +30,7 @@
Supports the following chips:
Chip #vin #fan #pwm #temp chip_id man_id
- w83627ehf - 5 - 3 0x88 0x5ca3
-
- This is a preliminary version of the driver, only supporting the
- fan and temperature inputs. The chip does much more than that.
+ w83627ehf 10 5 - 3 0x88 0x5ca3
*/
#include <linux/module.h>
@@ -121,6 +118,14 @@ superio_exit(void)
static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
+/* The W83627EHF registers for nr=7,8,9 are in bank 5 */
+#define W83627EHF_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
+ (0x554 + (((nr) - 7) * 2)))
+#define W83627EHF_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
+ (0x555 + (((nr) - 7) * 2)))
+#define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
+ (0x550 + (nr) - 7))
+
#define W83627EHF_REG_TEMP1 0x27
#define W83627EHF_REG_TEMP1_HYST 0x3a
#define W83627EHF_REG_TEMP1_OVER 0x39
@@ -136,6 +141,10 @@ static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 };
#define W83627EHF_REG_DIODE 0x59
#define W83627EHF_REG_SMI_OVT 0x4C
+#define W83627EHF_REG_ALARM1 0x459
+#define W83627EHF_REG_ALARM2 0x45A
+#define W83627EHF_REG_ALARM3 0x45B
+
/*
* Conversions
*/
@@ -172,6 +181,20 @@ temp1_to_reg(int temp)
return (temp + 500) / 1000;
}
+/* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */
+
+static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 };
+
+static inline long in_from_reg(u8 reg, u8 nr)
+{
+ return reg * scale_in[nr];
+}
+
+static inline u8 in_to_reg(u32 val, u8 nr)
+{
+ return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0, 255);
+}
+
/*
* Data structures and manipulation thereof
*/
@@ -186,6 +209,9 @@ struct w83627ehf_data {
unsigned long last_updated; /* In jiffies */
/* Register values */
+ u8 in[10]; /* Register value */
+ u8 in_max[10]; /* Register value */
+ u8 in_min[10]; /* Register value */
u8 fan[5];
u8 fan_min[5];
u8 fan_div[5];
@@ -196,6 +222,7 @@ struct w83627ehf_data {
s16 temp[2];
s16 temp_max[2];
s16 temp_max_hyst[2];
+ u32 alarms;
};
static inline int is_word_sized(u16 reg)
@@ -349,6 +376,16 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
data->fan_div[3] |= (i >> 5) & 0x04;
}
+ /* Measured voltages and limits */
+ for (i = 0; i < 10; i++) {
+ data->in[i] = w83627ehf_read_value(client,
+ W83627EHF_REG_IN(i));
+ data->in_min[i] = w83627ehf_read_value(client,
+ W83627EHF_REG_IN_MIN(i));
+ data->in_max[i] = w83627ehf_read_value(client,
+ W83627EHF_REG_IN_MAX(i));
+ }
+
/* Measured fan speeds and limits */
for (i = 0; i < 5; i++) {
if (!(data->has_fan & (1 << i)))
@@ -395,6 +432,13 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
W83627EHF_REG_TEMP_HYST[i]);
}
+ data->alarms = w83627ehf_read_value(client,
+ W83627EHF_REG_ALARM1) |
+ (w83627ehf_read_value(client,
+ W83627EHF_REG_ALARM2) << 8) |
+ (w83627ehf_read_value(client,
+ W83627EHF_REG_ALARM3) << 16);
+
data->last_updated = jiffies;
data->valid = 1;
}
@@ -406,6 +450,109 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
/*
* Sysfs callback functions
*/
+#define show_in_reg(reg) \
+static ssize_t \
+show_##reg(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct w83627ehf_data *data = w83627ehf_update_device(dev); \
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ int nr = sensor_attr->index; \
+ return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \
+}
+show_in_reg(in)
+show_in_reg(in_min)
+show_in_reg(in_max)
+
+#define store_in_reg(REG, reg) \
+static ssize_t \
+store_in_##reg (struct device *dev, struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct i2c_client *client = to_i2c_client(dev); \
+ struct w83627ehf_data *data = i2c_get_clientdata(client); \
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ int nr = sensor_attr->index; \
+ u32 val = simple_strtoul(buf, NULL, 10); \
+ \
+ mutex_lock(&data->update_lock); \
+ data->in_##reg[nr] = in_to_reg(val, nr); \
+ w83627ehf_write_value(client, W83627EHF_REG_IN_##REG(nr), \
+ data->in_##reg[nr]); \
+ mutex_unlock(&data->update_lock); \
+ return count; \
+}
+
+store_in_reg(MIN, min)
+store_in_reg(MAX, max)
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w83627ehf_data *data = w83627ehf_update_device(dev);
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ return sprintf(buf, "%u\n", (data->alarms >> nr) & 0x01);
+}
+
+static struct sensor_device_attribute sda_in_input[] = {
+ SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
+ SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
+ SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
+ SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
+ SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
+ SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
+ SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
+ SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
+ SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
+ SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9),
+};
+
+static struct sensor_device_attribute sda_in_alarm[] = {
+ SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
+ SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
+ SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
+ SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
+ SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
+ SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 21),
+ SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 20),
+ SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16),
+ SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17),
+ SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 19),
+};
+
+static struct sensor_device_attribute sda_in_min[] = {
+ SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
+ SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
+ SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
+ SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
+ SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
+ SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
+ SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
+ SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
+ SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
+ SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
+};
+
+static struct sensor_device_attribute sda_in_max[] = {
+ SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
+ SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
+ SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
+ SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
+ SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
+ SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
+ SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
+ SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
+ SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
+ SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
+};
+
+static void device_create_file_in(struct device *dev, int i)
+{
+ device_create_file(dev, &sda_in_input[i].dev_attr);
+ device_create_file(dev, &sda_in_alarm[i].dev_attr);
+ device_create_file(dev, &sda_in_min[i].dev_attr);
+ device_create_file(dev, &sda_in_max[i].dev_attr);
+}
#define show_fan_reg(reg) \
static ssize_t \
@@ -505,6 +652,14 @@ static struct sensor_device_attribute sda_fan_input[] = {
SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
};
+static struct sensor_device_attribute sda_fan_alarm[] = {
+ SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
+ SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
+ SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
+ SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 10),
+ SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 23),
+};
+
static struct sensor_device_attribute sda_fan_min[] = {
SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
store_fan_min, 0),
@@ -529,6 +684,7 @@ static struct sensor_device_attribute sda_fan_div[] = {
static void device_create_file_fan(struct device *dev, int i)
{
device_create_file(dev, &sda_fan_input[i].dev_attr);
+ device_create_file(dev, &sda_fan_alarm[i].dev_attr);
device_create_file(dev, &sda_fan_div[i].dev_attr);
device_create_file(dev, &sda_fan_min[i].dev_attr);
}
@@ -616,6 +772,9 @@ static struct sensor_device_attribute sda_temp[] = {
store_temp_max_hyst, 0),
SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
store_temp_max_hyst, 1),
+ SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
+ SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
+ SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
};
/*
@@ -705,6 +864,9 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
goto exit_detach;
}
+ for (i = 0; i < 10; i++)
+ device_create_file_in(dev, i);
+
for (i = 0; i < 5; i++) {
if (data->has_fan & (1 << i))
device_create_file_fan(dev, i);
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
new file mode 100644
index 0000000..eec43ab
--- /dev/null
+++ b/drivers/hwmon/w83791d.c
@@ -0,0 +1,1255 @@
+/*
+ w83791d.c - Part of lm_sensors, Linux kernel modules for hardware
+ monitoring
+
+ Copyright (C) 2006 Charles Spirakis <bezaur@gmail.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ Supports following chips:
+
+ Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA
+ w83791d 10 5 3 3 0x71 0x5ca3 yes no
+
+ The w83791d chip appears to be part way between the 83781d and the
+ 83792d. Thus, this file is derived from both the w83792d.c and
+ w83781d.c files, but its output is more along the lines of the
+ 83781d (which means there are no changes to the user-mode sensors
+ program which treats the 83791d as an 83781d).
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+#define NUMBER_OF_VIN 10
+#define NUMBER_OF_FANIN 5
+#define NUMBER_OF_TEMPIN 3
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(w83791d);
+I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
+ "{bus, clientaddr, subclientaddr1, subclientaddr2}");
+
+static int reset;
+module_param(reset, bool, 0);
+MODULE_PARM_DESC(reset, "Set to one to force a hardware chip reset");
+
+static int init;
+module_param(init, bool, 0);
+MODULE_PARM_DESC(init, "Set to one to force extra software initialization");
+
+/* The W83791D registers */
+static const u8 W83791D_REG_IN[NUMBER_OF_VIN] = {
+ 0x20, /* VCOREA in DataSheet */
+ 0x21, /* VINR0 in DataSheet */
+ 0x22, /* +3.3VIN in DataSheet */
+ 0x23, /* VDD5V in DataSheet */
+ 0x24, /* +12VIN in DataSheet */
+ 0x25, /* -12VIN in DataSheet */
+ 0x26, /* -5VIN in DataSheet */
+ 0xB0, /* 5VSB in DataSheet */
+ 0xB1, /* VBAT in DataSheet */
+ 0xB2 /* VINR1 in DataSheet */
+};
+
+static const u8 W83791D_REG_IN_MAX[NUMBER_OF_VIN] = {
+ 0x2B, /* VCOREA High Limit in DataSheet */
+ 0x2D, /* VINR0 High Limit in DataSheet */
+ 0x2F, /* +3.3VIN High Limit in DataSheet */
+ 0x31, /* VDD5V High Limit in DataSheet */
+ 0x33, /* +12VIN High Limit in DataSheet */
+ 0x35, /* -12VIN High Limit in DataSheet */
+ 0x37, /* -5VIN High Limit in DataSheet */
+ 0xB4, /* 5VSB High Limit in DataSheet */
+ 0xB6, /* VBAT High Limit in DataSheet */
+ 0xB8 /* VINR1 High Limit in DataSheet */
+};
+static const u8 W83791D_REG_IN_MIN[NUMBER_OF_VIN] = {
+ 0x2C, /* VCOREA Low Limit in DataSheet */
+ 0x2E, /* VINR0 Low Limit in DataSheet */
+ 0x30, /* +3.3VIN Low Limit in DataSheet */
+ 0x32, /* VDD5V Low Limit in DataSheet */
+ 0x34, /* +12VIN Low Limit in DataSheet */
+ 0x36, /* -12VIN Low Limit in DataSheet */
+ 0x38, /* -5VIN Low Limit in DataSheet */
+ 0xB5, /* 5VSB Low Limit in DataSheet */
+ 0xB7, /* VBAT Low Limit in DataSheet */
+ 0xB9 /* VINR1 Low Limit in DataSheet */
+};
+static const u8 W83791D_REG_FAN[NUMBER_OF_FANIN] = {
+ 0x28, /* FAN 1 Count in DataSheet */
+ 0x29, /* FAN 2 Count in DataSheet */
+ 0x2A, /* FAN 3 Count in DataSheet */
+ 0xBA, /* FAN 4 Count in DataSheet */
+ 0xBB, /* FAN 5 Count in DataSheet */
+};
+static const u8 W83791D_REG_FAN_MIN[NUMBER_OF_FANIN] = {
+ 0x3B, /* FAN 1 Count Low Limit in DataSheet */
+ 0x3C, /* FAN 2 Count Low Limit in DataSheet */
+ 0x3D, /* FAN 3 Count Low Limit in DataSheet */
+ 0xBC, /* FAN 4 Count Low Limit in DataSheet */
+ 0xBD, /* FAN 5 Count Low Limit in DataSheet */
+};
+
+static const u8 W83791D_REG_FAN_CFG[2] = {
+ 0x84, /* FAN 1/2 configuration */
+ 0x95, /* FAN 3 configuration */
+};
+
+static const u8 W83791D_REG_FAN_DIV[3] = {
+ 0x47, /* contains FAN1 and FAN2 Divisor */
+ 0x4b, /* contains FAN3 Divisor */
+ 0x5C, /* contains FAN4 and FAN5 Divisor */
+};
+
+#define W83791D_REG_BANK 0x4E
+#define W83791D_REG_TEMP2_CONFIG 0xC2
+#define W83791D_REG_TEMP3_CONFIG 0xCA
+
+static const u8 W83791D_REG_TEMP1[3] = {
+ 0x27, /* TEMP 1 in DataSheet */
+ 0x39, /* TEMP 1 Over in DataSheet */
+ 0x3A, /* TEMP 1 Hyst in DataSheet */
+};
+
+static const u8 W83791D_REG_TEMP_ADD[2][6] = {
+ {0xC0, /* TEMP 2 in DataSheet */
+ 0xC1, /* TEMP 2(0.5 deg) in DataSheet */
+ 0xC5, /* TEMP 2 Over High part in DataSheet */
+ 0xC6, /* TEMP 2 Over Low part in DataSheet */
+ 0xC3, /* TEMP 2 Thyst High part in DataSheet */
+ 0xC4}, /* TEMP 2 Thyst Low part in DataSheet */
+ {0xC8, /* TEMP 3 in DataSheet */
+ 0xC9, /* TEMP 3(0.5 deg) in DataSheet */
+ 0xCD, /* TEMP 3 Over High part in DataSheet */
+ 0xCE, /* TEMP 3 Over Low part in DataSheet */
+ 0xCB, /* TEMP 3 Thyst High part in DataSheet */
+ 0xCC} /* TEMP 3 Thyst Low part in DataSheet */
+};
+
+#define W83791D_REG_BEEP_CONFIG 0x4D
+
+static const u8 W83791D_REG_BEEP_CTRL[3] = {
+ 0x56, /* BEEP Control Register 1 */
+ 0x57, /* BEEP Control Register 2 */
+ 0xA3, /* BEEP Control Register 3 */
+};
+
+#define W83791D_REG_CONFIG 0x40
+#define W83791D_REG_VID_FANDIV 0x47
+#define W83791D_REG_DID_VID4 0x49
+#define W83791D_REG_WCHIPID 0x58
+#define W83791D_REG_CHIPMAN 0x4F
+#define W83791D_REG_PIN 0x4B
+#define W83791D_REG_I2C_SUBADDR 0x4A
+
+#define W83791D_REG_ALARM1 0xA9 /* realtime status register1 */
+#define W83791D_REG_ALARM2 0xAA /* realtime status register2 */
+#define W83791D_REG_ALARM3 0xAB /* realtime status register3 */
+
+#define W83791D_REG_VBAT 0x5D
+#define W83791D_REG_I2C_ADDR 0x48
+
+/* The SMBus locks itself. The Winbond W83791D has a bank select register
+ (index 0x4e), but the driver only accesses registers in bank 0. Since
+ we don't switch banks, we don't need any special code to handle
+ locking access between bank switches */
+static inline int w83791d_read(struct i2c_client *client, u8 reg)
+{
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+static inline int w83791d_write(struct i2c_client *client, u8 reg, u8 value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+/* The analog voltage inputs have 16mV LSB. Since the sysfs output is
+ in mV as would be measured on the chip input pin, need to just
+ multiply/divide by 16 to translate from/to register values. */
+#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8) / 16), 0, 255))
+#define IN_FROM_REG(val) ((val) * 16)
+
+static u8 fan_to_reg(long rpm, int div)
+{
+ if (rpm == 0)
+ return 255;
+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
+ return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+}
+
+#define FAN_FROM_REG(val,div) ((val) == 0 ? -1 : \
+ ((val) == 255 ? 0 : \
+ 1350000 / ((val) * (div))))
+
+/* for temp1 which is 8-bit resolution, LSB = 1 degree Celsius */
+#define TEMP1_FROM_REG(val) ((val) * 1000)
+#define TEMP1_TO_REG(val) ((val) <= -128000 ? -128 : \
+ (val) >= 127000 ? 127 : \
+ (val) < 0 ? ((val) - 500) / 1000 : \
+ ((val) + 500) / 1000)
+
+/* for temp2 and temp3 which are 9-bit resolution, LSB = 0.5 degree Celsius
+ Assumes the top 8 bits are the integral amount and the bottom 8 bits
+ are the fractional amount. Since we only have 0.5 degree resolution,
+ the bottom 7 bits will always be zero */
+#define TEMP23_FROM_REG(val) ((val) / 128 * 500)
+#define TEMP23_TO_REG(val) ((val) <= -128000 ? 0x8000 : \
+ (val) >= 127500 ? 0x7F80 : \
+ (val) < 0 ? ((val) - 250) / 500 * 128 : \
+ ((val) + 250) / 500 * 128)
+
+
+#define BEEP_MASK_TO_REG(val) ((val) & 0xffffff)
+#define BEEP_MASK_FROM_REG(val) ((val) & 0xffffff)
+
+#define DIV_FROM_REG(val) (1 << (val))
+
+static u8 div_to_reg(int nr, long val)
+{
+ int i;
+ int max;
+
+ /* first three fan's divisor max out at 8, rest max out at 128 */
+ max = (nr < 3) ? 8 : 128;
+ val = SENSORS_LIMIT(val, 1, max) >> 1;
+ for (i = 0; i < 7; i++) {
+ if (val == 0)
+ break;
+ val >>= 1;
+ }
+ return (u8) i;
+}
+
+struct w83791d_data {
+ struct i2c_client client;
+ struct class_device *class_dev;
+ struct mutex update_lock;
+
+ char valid; /* !=0 if following fields are valid */
+ unsigned long last_updated; /* In jiffies */
+
+ /* array of 2 pointers to subclients */
+ struct i2c_client *lm75[2];
+
+ /* volts */
+ u8 in[NUMBER_OF_VIN]; /* Register value */
+ u8 in_max[NUMBER_OF_VIN]; /* Register value */
+ u8 in_min[NUMBER_OF_VIN]; /* Register value */
+
+ /* fans */
+ u8 fan[NUMBER_OF_FANIN]; /* Register value */
+ u8 fan_min[NUMBER_OF_FANIN]; /* Register value */
+ u8 fan_div[NUMBER_OF_FANIN]; /* Register encoding, shifted right */
+
+ /* Temperature sensors */
+
+ s8 temp1[3]; /* current, over, thyst */
+ s16 temp_add[2][3]; /* fixed point value. Top 8 bits are the
+ integral part, bottom 8 bits are the
+ fractional part. We only use the top
+ 9 bits as the resolution is only
+ to the 0.5 degree C...
+ two sensors with three values
+ (cur, over, hyst) */
+
+ /* Misc */
+ u32 alarms; /* realtime status register encoding,combined */
+ u8 beep_enable; /* Global beep enable */
+ u32 beep_mask; /* Mask off specific beeps */
+ u8 vid; /* Register encoding, combined */
+ u8 vrm; /* hwmon-vid */
+};
+
+static int w83791d_attach_adapter(struct i2c_adapter *adapter);
+static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind);
+static int w83791d_detach_client(struct i2c_client *client);
+
+static int w83791d_read(struct i2c_client *client, u8 register);
+static int w83791d_write(struct i2c_client *client, u8 register, u8 value);
+static struct w83791d_data *w83791d_update_device(struct device *dev);
+
+#ifdef DEBUG
+static void w83791d_print_debug(struct w83791d_data *data, struct device *dev);
+#endif
+
+static void w83791d_init_client(struct i2c_client *client);
+
+static struct i2c_driver w83791d_driver = {
+ .driver = {
+ .name = "w83791d",
+ },
+ .attach_adapter = w83791d_attach_adapter,
+ .detach_client = w83791d_detach_client,
+};
+
+/* following are the sysfs callback functions */
+#define show_in_reg(reg) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct sensor_device_attribute *sensor_attr = \
+ to_sensor_dev_attr(attr); \
+ struct w83791d_data *data = w83791d_update_device(dev); \
+ int nr = sensor_attr->index; \
+ return sprintf(buf,"%d\n", IN_FROM_REG(data->reg[nr])); \
+}
+
+show_in_reg(in);
+show_in_reg(in_min);
+show_in_reg(in_max);
+
+#define store_in_reg(REG, reg) \
+static ssize_t store_in_##reg(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct sensor_device_attribute *sensor_attr = \
+ to_sensor_dev_attr(attr); \
+ struct i2c_client *client = to_i2c_client(dev); \
+ struct w83791d_data *data = i2c_get_clientdata(client); \
+ unsigned long val = simple_strtoul(buf, NULL, 10); \
+ int nr = sensor_attr->index; \
+ \
+ mutex_lock(&data->update_lock); \
+ data->in_##reg[nr] = IN_TO_REG(val); \
+ w83791d_write(client, W83791D_REG_IN_##REG[nr], data->in_##reg[nr]); \
+ mutex_unlock(&data->update_lock); \
+ \
+ return count; \
+}
+store_in_reg(MIN, min);
+store_in_reg(MAX, max);
+
+static struct sensor_device_attribute sda_in_input[] = {
+ SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
+ SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
+ SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
+ SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
+ SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
+ SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
+ SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
+ SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
+ SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
+ SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9),
+};
+
+static struct sensor_device_attribute sda_in_min[] = {
+ SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
+ SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
+ SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
+ SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
+ SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
+ SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
+ SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
+ SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
+ SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
+ SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
+};
+
+static struct sensor_device_attribute sda_in_max[] = {
+ SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
+ SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
+ SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
+ SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
+ SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
+ SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
+ SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
+ SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
+ SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
+ SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
+};
+
+#define show_fan_reg(reg) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct sensor_device_attribute *sensor_attr = \
+ to_sensor_dev_attr(attr); \
+ struct w83791d_data *data = w83791d_update_device(dev); \
+ int nr = sensor_attr->index; \
+ return sprintf(buf,"%d\n", \
+ FAN_FROM_REG(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \
+}
+
+show_fan_reg(fan);
+show_fan_reg(fan_min);
+
+static ssize_t store_fan_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83791d_data *data = i2c_get_clientdata(client);
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+ int nr = sensor_attr->index;
+
+ mutex_lock(&data->update_lock);
+ data->fan_min[nr] = fan_to_reg(val, DIV_FROM_REG(data->fan_div[nr]));
+ w83791d_write(client, W83791D_REG_FAN_MIN[nr], data->fan_min[nr]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct w83791d_data *data = w83791d_update_device(dev);
+ return sprintf(buf, "%u\n", DIV_FROM_REG(data->fan_div[nr]));
+}
+
+/* Note: we save and restore the fan minimum here, because its value is
+ determined in part by the fan divisor. This follows the principle of
+ least suprise; the user doesn't expect the fan minimum to change just
+ because the divisor changed. */
+static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83791d_data *data = i2c_get_clientdata(client);
+ int nr = sensor_attr->index;
+ unsigned long min;
+ u8 tmp_fan_div;
+ u8 fan_div_reg;
+ int indx = 0;
+ u8 keep_mask = 0;
+ u8 new_shift = 0;
+
+ /* Save fan_min */
+ min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]));
+
+ mutex_lock(&data->update_lock);
+ data->fan_div[nr] = div_to_reg(nr, simple_strtoul(buf, NULL, 10));
+
+ switch (nr) {
+ case 0:
+ indx = 0;
+ keep_mask = 0xcf;
+ new_shift = 4;
+ break;
+ case 1:
+ indx = 0;
+ keep_mask = 0x3f;
+ new_shift = 6;
+ break;
+ case 2:
+ indx = 1;
+ keep_mask = 0x3f;
+ new_shift = 6;
+ break;
+ case 3:
+ indx = 2;
+ keep_mask = 0xf8;
+ new_shift = 0;
+ break;
+ case 4:
+ indx = 2;
+ keep_mask = 0x8f;
+ new_shift = 4;
+ break;
+#ifdef DEBUG
+ default:
+ dev_warn(dev, "store_fan_div: Unexpected nr seen: %d\n", nr);
+ count = -EINVAL;
+ goto err_exit;
+#endif
+ }
+
+ fan_div_reg = w83791d_read(client, W83791D_REG_FAN_DIV[indx])
+ & keep_mask;
+ tmp_fan_div = (data->fan_div[nr] << new_shift) & ~keep_mask;
+
+ w83791d_write(client, W83791D_REG_FAN_DIV[indx],
+ fan_div_reg | tmp_fan_div);
+
+ /* Restore fan_min */
+ data->fan_min[nr] = fan_to_reg(min, DIV_FROM_REG(data->fan_div[nr]));
+ w83791d_write(client, W83791D_REG_FAN_MIN[nr], data->fan_min[nr]);
+
+#ifdef DEBUG
+err_exit:
+#endif
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static struct sensor_device_attribute sda_fan_input[] = {
+ SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
+ SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
+ SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
+ SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
+ SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
+};
+
+static struct sensor_device_attribute sda_fan_min[] = {
+ SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 0),
+ SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 1),
+ SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 2),
+ SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 3),
+ SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 4),
+};
+
+static struct sensor_device_attribute sda_fan_div[] = {
+ SENSOR_ATTR(fan1_div, S_IWUSR | S_IRUGO,
+ show_fan_div, store_fan_div, 0),
+ SENSOR_ATTR(fan2_div, S_IWUSR | S_IRUGO,
+ show_fan_div, store_fan_div, 1),
+ SENSOR_ATTR(fan3_div, S_IWUSR | S_IRUGO,
+ show_fan_div, store_fan_div, 2),
+ SENSOR_ATTR(fan4_div, S_IWUSR | S_IRUGO,
+ show_fan_div, store_fan_div, 3),
+ SENSOR_ATTR(fan5_div, S_IWUSR | S_IRUGO,
+ show_fan_div, store_fan_div, 4),
+};
+
+/* read/write the temperature1, includes measured value and limits */
+static ssize_t show_temp1(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct w83791d_data *data = w83791d_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp1[attr->index]));
+}
+
+static ssize_t store_temp1(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83791d_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+ int nr = attr->index;
+
+ mutex_lock(&data->update_lock);
+ data->temp1[nr] = TEMP1_TO_REG(val);
+ w83791d_write(client, W83791D_REG_TEMP1[nr], data->temp1[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+/* read/write temperature2-3, includes measured value and limits */
+static ssize_t show_temp23(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct w83791d_data *data = w83791d_update_device(dev);
+ int nr = attr->nr;
+ int index = attr->index;
+ return sprintf(buf, "%d\n", TEMP23_FROM_REG(data->temp_add[nr][index]));
+}
+
+static ssize_t store_temp23(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83791d_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+ int nr = attr->nr;
+ int index = attr->index;
+
+ mutex_lock(&data->update_lock);
+ data->temp_add[nr][index] = TEMP23_TO_REG(val);
+ w83791d_write(client, W83791D_REG_TEMP_ADD[nr][index * 2],
+ data->temp_add[nr][index] >> 8);
+ w83791d_write(client, W83791D_REG_TEMP_ADD[nr][index * 2 + 1],
+ data->temp_add[nr][index] & 0x80);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static struct sensor_device_attribute_2 sda_temp_input[] = {
+ SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp1, NULL, 0, 0),
+ SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp23, NULL, 0, 0),
+ SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp23, NULL, 1, 0),
+};
+
+static struct sensor_device_attribute_2 sda_temp_max[] = {
+ SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR,
+ show_temp1, store_temp1, 0, 1),
+ SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR,
+ show_temp23, store_temp23, 0, 1),
+ SENSOR_ATTR_2(temp3_max, S_IRUGO | S_IWUSR,
+ show_temp23, store_temp23, 1, 1),
+};
+
+static struct sensor_device_attribute_2 sda_temp_max_hyst[] = {
+ SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR,
+ show_temp1, store_temp1, 0, 2),
+ SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR,
+ show_temp23, store_temp23, 0, 2),
+ SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR,
+ show_temp23, store_temp23, 1, 2),
+};
+
+
+/* get reatime status of all sensors items: voltage, temp, fan */
+static ssize_t show_alarms_reg(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct w83791d_data *data = w83791d_update_device(dev);
+ return sprintf(buf, "%u\n", data->alarms);
+}
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+
+/* Beep control */
+
+#define GLOBAL_BEEP_ENABLE_SHIFT 15
+#define GLOBAL_BEEP_ENABLE_MASK (1 << GLOBAL_BEEP_ENABLE_SHIFT)
+
+static ssize_t show_beep_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct w83791d_data *data = w83791d_update_device(dev);
+ return sprintf(buf, "%d\n", data->beep_enable);
+}
+
+static ssize_t show_beep_mask(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct w83791d_data *data = w83791d_update_device(dev);
+ return sprintf(buf, "%d\n", BEEP_MASK_FROM_REG(data->beep_mask));
+}
+
+
+static ssize_t store_beep_mask(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83791d_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+ int i;
+
+ mutex_lock(&data->update_lock);
+
+ /* The beep_enable state overrides any enabling request from
+ the masks */
+ data->beep_mask = BEEP_MASK_TO_REG(val) & ~GLOBAL_BEEP_ENABLE_MASK;
+ data->beep_mask |= (data->beep_enable << GLOBAL_BEEP_ENABLE_SHIFT);
+
+ val = data->beep_mask;
+
+ for (i = 0; i < 3; i++) {
+ w83791d_write(client, W83791D_REG_BEEP_CTRL[i], (val & 0xff));
+ val >>= 8;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t store_beep_enable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83791d_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+
+ data->beep_enable = val ? 1 : 0;
+
+ /* Keep the full mask value in sync with the current enable */
+ data->beep_mask &= ~GLOBAL_BEEP_ENABLE_MASK;
+ data->beep_mask |= (data->beep_enable << GLOBAL_BEEP_ENABLE_SHIFT);
+
+ /* The global control is in the second beep control register
+ so only need to update that register */
+ val = (data->beep_mask >> 8) & 0xff;
+
+ w83791d_write(client, W83791D_REG_BEEP_CTRL[1], val);
+
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static struct sensor_device_attribute sda_beep_ctrl[] = {
+ SENSOR_ATTR(beep_enable, S_IRUGO | S_IWUSR,
+ show_beep_enable, store_beep_enable, 0),
+ SENSOR_ATTR(beep_mask, S_IRUGO | S_IWUSR,
+ show_beep_mask, store_beep_mask, 1)
+};
+
+/* cpu voltage regulation information */
+static ssize_t show_vid_reg(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct w83791d_data *data = w83791d_update_device(dev);
+ return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
+
+static ssize_t show_vrm_reg(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct w83791d_data *data = w83791d_update_device(dev);
+ return sprintf(buf, "%d\n", data->vrm);
+}
+
+static ssize_t store_vrm_reg(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83791d_data *data = i2c_get_clientdata(client);
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+
+ /* No lock needed as vrm is internal to the driver
+ (not read from a chip register) and so is not
+ updated in w83791d_update_device() */
+ data->vrm = val;
+
+ return count;
+}
+
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
+
+/* This function is called when:
+ * w83791d_driver is inserted (when this module is loaded), for each
+ available adapter
+ * when a new adapter is inserted (and w83791d_driver is still present) */
+static int w83791d_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON))
+ return 0;
+ return i2c_probe(adapter, &addr_data, w83791d_detect);
+}
+
+
+static int w83791d_create_subclient(struct i2c_adapter *adapter,
+ struct i2c_client *client, int addr,
+ struct i2c_client **sub_cli)
+{
+ int err;
+ struct i2c_client *sub_client;
+
+ (*sub_cli) = sub_client =
+ kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (!(sub_client)) {
+ return -ENOMEM;
+ }
+ sub_client->addr = 0x48 + addr;
+ i2c_set_clientdata(sub_client, NULL);
+ sub_client->adapter = adapter;
+ sub_client->driver = &w83791d_driver;
+ strlcpy(sub_client->name, "w83791d subclient", I2C_NAME_SIZE);
+ if ((err = i2c_attach_client(sub_client))) {
+ dev_err(&client->dev, "subclient registration "
+ "at address 0x%x failed\n", sub_client->addr);
+ kfree(sub_client);
+ return err;
+ }
+ return 0;
+}
+
+
+static int w83791d_detect_subclients(struct i2c_adapter *adapter, int address,
+ int kind, struct i2c_client *client)
+{
+ struct w83791d_data *data = i2c_get_clientdata(client);
+ int i, id, err;
+ u8 val;
+
+ id = i2c_adapter_id(adapter);
+ if (force_subclients[0] == id && force_subclients[1] == address) {
+ for (i = 2; i <= 3; i++) {
+ if (force_subclients[i] < 0x48 ||
+ force_subclients[i] > 0x4f) {
+ dev_err(&client->dev,
+ "invalid subclient "
+ "address %d; must be 0x48-0x4f\n",
+ force_subclients[i]);
+ err = -ENODEV;
+ goto error_sc_0;
+ }
+ }
+ w83791d_write(client, W83791D_REG_I2C_SUBADDR,
+ (force_subclients[2] & 0x07) |
+ ((force_subclients[3] & 0x07) << 4));
+ }
+
+ val = w83791d_read(client, W83791D_REG_I2C_SUBADDR);
+ if (!(val & 0x08)) {
+ err = w83791d_create_subclient(adapter, client,
+ val & 0x7, &data->lm75[0]);
+ if (err < 0)
+ goto error_sc_0;
+ }
+ if (!(val & 0x80)) {
+ if ((data->lm75[0] != NULL) &&
+ ((val & 0x7) == ((val >> 4) & 0x7))) {
+ dev_err(&client->dev,
+ "duplicate addresses 0x%x, "
+ "use force_subclient\n",
+ data->lm75[0]->addr);
+ err = -ENODEV;
+ goto error_sc_1;
+ }
+ err = w83791d_create_subclient(adapter, client,
+ (val >> 4) & 0x7, &data->lm75[1]);
+ if (err < 0)
+ goto error_sc_1;
+ }
+
+ return 0;
+
+/* Undo inits in case of errors */
+
+error_sc_1:
+ if (data->lm75[0] != NULL) {
+ i2c_detach_client(data->lm75[0]);
+ kfree(data->lm75[0]);
+ }
+error_sc_0:
+ return err;
+}
+
+
+static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct device *dev;
+ struct w83791d_data *data;
+ int i, val1, val2;
+ int err = 0;
+ const char *client_name = "";
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ goto error0;
+ }
+
+ /* OK. For now, we presume we have a valid client. We now create the
+ client structure, even though we cannot fill it completely yet.
+ But it allows us to access w83791d_{read,write}_value. */
+ if (!(data = kzalloc(sizeof(struct w83791d_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto error0;
+ }
+
+ client = &data->client;
+ dev = &client->dev;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &w83791d_driver;
+ mutex_init(&data->update_lock);
+
+ /* Now, we do the remaining detection. */
+
+ /* The w83791d may be stuck in some other bank than bank 0. This may
+ make reading other information impossible. Specify a force=...
+ parameter, and the Winbond will be reset to the right bank. */
+ if (kind < 0) {
+ if (w83791d_read(client, W83791D_REG_CONFIG) & 0x80) {
+ dev_dbg(dev, "Detection failed at step 1\n");
+ goto error1;
+ }
+ val1 = w83791d_read(client, W83791D_REG_BANK);
+ val2 = w83791d_read(client, W83791D_REG_CHIPMAN);
+ /* Check for Winbond ID if in bank 0 */
+ if (!(val1 & 0x07)) {
+ /* yes it is Bank0 */
+ if (((!(val1 & 0x80)) && (val2 != 0xa3)) ||
+ ((val1 & 0x80) && (val2 != 0x5c))) {
+ dev_dbg(dev, "Detection failed at step 2\n");
+ goto error1;
+ }
+ }
+ /* If Winbond chip, address of chip and W83791D_REG_I2C_ADDR
+ should match */
+ if (w83791d_read(client, W83791D_REG_I2C_ADDR) != address) {
+ dev_dbg(dev, "Detection failed at step 3\n");
+ goto error1;
+ }
+ }
+
+ /* We either have a force parameter or we have reason to
+ believe it is a Winbond chip. Either way, we want bank 0 and
+ Vendor ID high byte */
+ val1 = w83791d_read(client, W83791D_REG_BANK) & 0x78;
+ w83791d_write(client, W83791D_REG_BANK, val1 | 0x80);
+
+ /* Verify it is a Winbond w83791d */
+ if (kind <= 0) {
+ /* get vendor ID */
+ val2 = w83791d_read(client, W83791D_REG_CHIPMAN);
+ if (val2 != 0x5c) { /* the vendor is NOT Winbond */
+ dev_dbg(dev, "Detection failed at step 4\n");
+ goto error1;
+ }
+ val1 = w83791d_read(client, W83791D_REG_WCHIPID);
+ if (val1 == 0x71) {
+ kind = w83791d;
+ } else {
+ if (kind == 0)
+ dev_warn(dev,
+ "w83791d: Ignoring 'force' parameter "
+ "for unknown chip at adapter %d, "
+ "address 0x%02x\n",
+ i2c_adapter_id(adapter), address);
+ goto error1;
+ }
+ }
+
+ if (kind == w83791d) {
+ client_name = "w83791d";
+ } else {
+ dev_err(dev, "w83791d: Internal error: unknown kind (%d)?!?",
+ kind);
+ goto error1;
+ }
+
+#ifdef DEBUG
+ val1 = w83791d_read(client, W83791D_REG_DID_VID4);
+ dev_dbg(dev, "Device ID version: %d.%d (0x%02x)\n",
+ (val1 >> 5) & 0x07, (val1 >> 1) & 0x0f, val1);
+#endif
+
+ /* Fill in the remaining client fields and put into the global list */
+ strlcpy(client->name, client_name, I2C_NAME_SIZE);
+
+ /* Tell the I2C layer a new client has arrived */
+ if ((err = i2c_attach_client(client)))
+ goto error1;
+
+ if ((err = w83791d_detect_subclients(adapter, address, kind, client)))
+ goto error2;
+
+ /* Initialize the chip */
+ w83791d_init_client(client);
+
+ /* If the fan_div is changed, make sure there is a rational
+ fan_min in place */
+ for (i = 0; i < NUMBER_OF_FANIN; i++) {
+ data->fan_min[i] = w83791d_read(client, W83791D_REG_FAN_MIN[i]);
+ }
+
+ /* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto error3;
+ }
+
+ for (i = 0; i < NUMBER_OF_VIN; i++) {
+ device_create_file(dev, &sda_in_input[i].dev_attr);
+ device_create_file(dev, &sda_in_min[i].dev_attr);
+ device_create_file(dev, &sda_in_max[i].dev_attr);
+ }
+
+ for (i = 0; i < NUMBER_OF_FANIN; i++) {
+ device_create_file(dev, &sda_fan_input[i].dev_attr);
+ device_create_file(dev, &sda_fan_div[i].dev_attr);
+ device_create_file(dev, &sda_fan_min[i].dev_attr);
+ }
+
+ for (i = 0; i < NUMBER_OF_TEMPIN; i++) {
+ device_create_file(dev, &sda_temp_input[i].dev_attr);
+ device_create_file(dev, &sda_temp_max[i].dev_attr);
+ device_create_file(dev, &sda_temp_max_hyst[i].dev_attr);
+ }
+
+ device_create_file(dev, &dev_attr_alarms);
+
+ for (i = 0; i < ARRAY_SIZE(sda_beep_ctrl); i++) {
+ device_create_file(dev, &sda_beep_ctrl[i].dev_attr);
+ }
+
+ device_create_file(dev, &dev_attr_cpu0_vid);
+ device_create_file(dev, &dev_attr_vrm);
+
+ return 0;
+
+error3:
+ if (data->lm75[0] != NULL) {
+ i2c_detach_client(data->lm75[0]);
+ kfree(data->lm75[0]);
+ }
+ if (data->lm75[1] != NULL) {
+ i2c_detach_client(data->lm75[1]);
+ kfree(data->lm75[1]);
+ }
+error2:
+ i2c_detach_client(client);
+error1:
+ kfree(data);
+error0:
+ return err;
+}
+
+static int w83791d_detach_client(struct i2c_client *client)
+{
+ struct w83791d_data *data = i2c_get_clientdata(client);
+ int err;
+
+ /* main client */
+ if (data)
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ /* main client */
+ if (data)
+ kfree(data);
+ /* subclient */
+ else
+ kfree(client);
+
+ return 0;
+}
+
+static void w83791d_init_client(struct i2c_client *client)
+{
+ struct w83791d_data *data = i2c_get_clientdata(client);
+ u8 tmp;
+ u8 old_beep;
+
+ /* The difference between reset and init is that reset
+ does a hard reset of the chip via index 0x40, bit 7,
+ but init simply forces certain registers to have "sane"
+ values. The hope is that the BIOS has done the right
+ thing (which is why the default is reset=0, init=0),
+ but if not, reset is the hard hammer and init
+ is the soft mallet both of which are trying to whack
+ things into place...
+ NOTE: The data sheet makes a distinction between
+ "power on defaults" and "reset by MR". As far as I can tell,
+ the hard reset puts everything into a power-on state so I'm
+ not sure what "reset by MR" means or how it can happen.
+ */
+ if (reset || init) {
+ /* keep some BIOS settings when we... */
+ old_beep = w83791d_read(client, W83791D_REG_BEEP_CONFIG);
+
+ if (reset) {
+ /* ... reset the chip and ... */
+ w83791d_write(client, W83791D_REG_CONFIG, 0x80);
+ }
+
+ /* ... disable power-on abnormal beep */
+ w83791d_write(client, W83791D_REG_BEEP_CONFIG, old_beep | 0x80);
+
+ /* disable the global beep (not done by hard reset) */
+ tmp = w83791d_read(client, W83791D_REG_BEEP_CTRL[1]);
+ w83791d_write(client, W83791D_REG_BEEP_CTRL[1], tmp & 0xef);
+
+ if (init) {
+ /* Make sure monitoring is turned on for add-ons */
+ tmp = w83791d_read(client, W83791D_REG_TEMP2_CONFIG);
+ if (tmp & 1) {
+ w83791d_write(client, W83791D_REG_TEMP2_CONFIG,
+ tmp & 0xfe);
+ }
+
+ tmp = w83791d_read(client, W83791D_REG_TEMP3_CONFIG);
+ if (tmp & 1) {
+ w83791d_write(client, W83791D_REG_TEMP3_CONFIG,
+ tmp & 0xfe);
+ }
+
+ /* Start monitoring */
+ tmp = w83791d_read(client, W83791D_REG_CONFIG) & 0xf7;
+ w83791d_write(client, W83791D_REG_CONFIG, tmp | 0x01);
+ }
+ }
+
+ data->vrm = vid_which_vrm();
+}
+
+static struct w83791d_data *w83791d_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83791d_data *data = i2c_get_clientdata(client);
+ int i, j;
+ u8 reg_array_tmp[3];
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + (HZ * 3))
+ || !data->valid) {
+ dev_dbg(dev, "Starting w83791d device update\n");
+
+ /* Update the voltages measured value and limits */
+ for (i = 0; i < NUMBER_OF_VIN; i++) {
+ data->in[i] = w83791d_read(client,
+ W83791D_REG_IN[i]);
+ data->in_max[i] = w83791d_read(client,
+ W83791D_REG_IN_MAX[i]);
+ data->in_min[i] = w83791d_read(client,
+ W83791D_REG_IN_MIN[i]);
+ }
+
+ /* Update the fan counts and limits */
+ for (i = 0; i < NUMBER_OF_FANIN; i++) {
+ /* Update the Fan measured value and limits */
+ data->fan[i] = w83791d_read(client,
+ W83791D_REG_FAN[i]);
+ data->fan_min[i] = w83791d_read(client,
+ W83791D_REG_FAN_MIN[i]);
+ }
+
+ /* Update the fan divisor */
+ for (i = 0; i < 3; i++) {
+ reg_array_tmp[i] = w83791d_read(client,
+ W83791D_REG_FAN_DIV[i]);
+ }
+ data->fan_div[0] = (reg_array_tmp[0] >> 4) & 0x03;
+ data->fan_div[1] = (reg_array_tmp[0] >> 6) & 0x03;
+ data->fan_div[2] = (reg_array_tmp[1] >> 6) & 0x03;
+ data->fan_div[3] = reg_array_tmp[2] & 0x07;
+ data->fan_div[4] = (reg_array_tmp[2] >> 4) & 0x07;
+
+ /* Update the first temperature sensor */
+ for (i = 0; i < 3; i++) {
+ data->temp1[i] = w83791d_read(client,
+ W83791D_REG_TEMP1[i]);
+ }
+
+ /* Update the rest of the temperature sensors */
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 3; j++) {
+ data->temp_add[i][j] =
+ (w83791d_read(client,
+ W83791D_REG_TEMP_ADD[i][j * 2]) << 8) |
+ w83791d_read(client,
+ W83791D_REG_TEMP_ADD[i][j * 2 + 1]);
+ }
+ }
+
+ /* Update the realtime status */
+ data->alarms =
+ w83791d_read(client, W83791D_REG_ALARM1) +
+ (w83791d_read(client, W83791D_REG_ALARM2) << 8) +
+ (w83791d_read(client, W83791D_REG_ALARM3) << 16);
+
+ /* Update the beep configuration information */
+ data->beep_mask =
+ w83791d_read(client, W83791D_REG_BEEP_CTRL[0]) +
+ (w83791d_read(client, W83791D_REG_BEEP_CTRL[1]) << 8) +
+ (w83791d_read(client, W83791D_REG_BEEP_CTRL[2]) << 16);
+
+ data->beep_enable =
+ (data->beep_mask >> GLOBAL_BEEP_ENABLE_SHIFT) & 0x01;
+
+ /* Update the cpu voltage information */
+ i = w83791d_read(client, W83791D_REG_VID_FANDIV);
+ data->vid = i & 0x0f;
+ data->vid |= (w83791d_read(client, W83791D_REG_DID_VID4) & 0x01)
+ << 4;
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+#ifdef DEBUG
+ w83791d_print_debug(data, dev);
+#endif
+
+ return data;
+}
+
+#ifdef DEBUG
+static void w83791d_print_debug(struct w83791d_data *data, struct device *dev)
+{
+ int i = 0, j = 0;
+
+ dev_dbg(dev, "======Start of w83791d debug values======\n");
+ dev_dbg(dev, "%d set of Voltages: ===>\n", NUMBER_OF_VIN);
+ for (i = 0; i < NUMBER_OF_VIN; i++) {
+ dev_dbg(dev, "vin[%d] is: 0x%02x\n", i, data->in[i]);
+ dev_dbg(dev, "vin[%d] min is: 0x%02x\n", i, data->in_min[i]);
+ dev_dbg(dev, "vin[%d] max is: 0x%02x\n", i, data->in_max[i]);
+ }
+ dev_dbg(dev, "%d set of Fan Counts/Divisors: ===>\n", NUMBER_OF_FANIN);
+ for (i = 0; i < NUMBER_OF_FANIN; i++) {
+ dev_dbg(dev, "fan[%d] is: 0x%02x\n", i, data->fan[i]);
+ dev_dbg(dev, "fan[%d] min is: 0x%02x\n", i, data->fan_min[i]);
+ dev_dbg(dev, "fan_div[%d] is: 0x%02x\n", i, data->fan_div[i]);
+ }
+
+ /* temperature math is signed, but only print out the
+ bits that matter */
+ dev_dbg(dev, "%d set of Temperatures: ===>\n", NUMBER_OF_TEMPIN);
+ for (i = 0; i < 3; i++) {
+ dev_dbg(dev, "temp1[%d] is: 0x%02x\n", i, (u8) data->temp1[i]);
+ }
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 3; j++) {
+ dev_dbg(dev, "temp_add[%d][%d] is: 0x%04x\n", i, j,
+ (u16) data->temp_add[i][j]);
+ }
+ }
+
+ dev_dbg(dev, "Misc Information: ===>\n");
+ dev_dbg(dev, "alarm is: 0x%08x\n", data->alarms);
+ dev_dbg(dev, "beep_mask is: 0x%08x\n", data->beep_mask);
+ dev_dbg(dev, "beep_enable is: %d\n", data->beep_enable);
+ dev_dbg(dev, "vid is: 0x%02x\n", data->vid);
+ dev_dbg(dev, "vrm is: 0x%02x\n", data->vrm);
+ dev_dbg(dev, "=======End of w83791d debug values========\n");
+ dev_dbg(dev, "\n");
+}
+#endif
+
+static int __init sensors_w83791d_init(void)
+{
+ return i2c_add_driver(&w83791d_driver);
+}
+
+static void __exit sensors_w83791d_exit(void)
+{
+ i2c_del_driver(&w83791d_driver);
+}
+
+MODULE_AUTHOR("Charles Spirakis <bezaur@gmail.com>");
+MODULE_DESCRIPTION("W83791D driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_w83791d_init);
+module_exit(sensors_w83791d_exit);
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
index 958602e..4ef884c 100644
--- a/drivers/hwmon/w83792d.c
+++ b/drivers/hwmon/w83792d.c
@@ -250,8 +250,6 @@ FAN_TO_REG(long rpm, int div)
: (val)) / 1000, 0, 0xff))
#define TEMP_ADD_TO_REG_LOW(val) ((val%1000) ? 0x80 : 0x00)
-#define PWM_FROM_REG(val) (val)
-#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
#define DIV_FROM_REG(val) (1 << (val))
static inline u8
@@ -291,7 +289,6 @@ struct w83792d_data {
u8 pwm[7]; /* We only consider the first 3 set of pwm,
although 792 chip has 7 set of pwm. */
u8 pwmenable[3];
- u8 pwm_mode[7]; /* indicates PWM or DC mode: 1->PWM; 0->DC */
u32 alarms; /* realtime status register encoding,combined */
u8 chassis; /* Chassis status */
u8 chassis_clear; /* CLR_CHS, clear chassis intrusion detection */
@@ -375,8 +372,10 @@ static ssize_t store_in_##reg (struct device *dev, \
u32 val; \
\
val = simple_strtoul(buf, NULL, 10); \
+ mutex_lock(&data->update_lock); \
data->in_##reg[nr] = SENSORS_LIMIT(IN_TO_REG(nr, val)/4, 0, 255); \
w83792d_write_value(client, W83792D_REG_IN_##REG[nr], data->in_##reg[nr]); \
+ mutex_unlock(&data->update_lock); \
\
return count; \
}
@@ -443,9 +442,11 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
u32 val;
val = simple_strtoul(buf, NULL, 10);
+ mutex_lock(&data->update_lock);
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
w83792d_write_value(client, W83792D_REG_FAN_MIN[nr],
data->fan_min[nr]);
+ mutex_unlock(&data->update_lock);
return count;
}
@@ -478,6 +479,7 @@ store_fan_div(struct device *dev, struct device_attribute *attr,
u8 tmp_fan_div;
/* Save fan_min */
+ mutex_lock(&data->update_lock);
min = FAN_FROM_REG(data->fan_min[nr],
DIV_FROM_REG(data->fan_div[nr]));
@@ -493,6 +495,7 @@ store_fan_div(struct device *dev, struct device_attribute *attr,
/* Restore fan_min */
data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
w83792d_write_value(client, W83792D_REG_FAN_MIN[nr], data->fan_min[nr]);
+ mutex_unlock(&data->update_lock);
return count;
}
@@ -547,10 +550,11 @@ static ssize_t store_temp1(struct device *dev, struct device_attribute *attr,
s32 val;
val = simple_strtol(buf, NULL, 10);
-
+ mutex_lock(&data->update_lock);
data->temp1[nr] = TEMP1_TO_REG(val);
w83792d_write_value(client, W83792D_REG_TEMP1[nr],
data->temp1[nr]);
+ mutex_unlock(&data->update_lock);
return count;
}
@@ -580,13 +584,14 @@ static ssize_t store_temp23(struct device *dev, struct device_attribute *attr,
s32 val;
val = simple_strtol(buf, NULL, 10);
-
+ mutex_lock(&data->update_lock);
data->temp_add[nr][index] = TEMP_ADD_TO_REG_HIGH(val);
data->temp_add[nr][index+1] = TEMP_ADD_TO_REG_LOW(val);
w83792d_write_value(client, W83792D_REG_TEMP_ADD[nr][index],
data->temp_add[nr][index]);
w83792d_write_value(client, W83792D_REG_TEMP_ADD[nr][index+1],
data->temp_add[nr][index+1]);
+ mutex_unlock(&data->update_lock);
return count;
}
@@ -627,7 +632,7 @@ show_pwm(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct w83792d_data *data = w83792d_update_device(dev);
- return sprintf(buf, "%ld\n", (long) PWM_FROM_REG(data->pwm[nr-1]));
+ return sprintf(buf, "%d\n", (data->pwm[nr] & 0x0f) << 4);
}
static ssize_t
@@ -659,14 +664,16 @@ store_pwm(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
- int nr = sensor_attr->index - 1;
+ int nr = sensor_attr->index;
struct i2c_client *client = to_i2c_client(dev);
struct w83792d_data *data = i2c_get_clientdata(client);
- u32 val;
+ u8 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255) >> 4;
- val = simple_strtoul(buf, NULL, 10);
- data->pwm[nr] = PWM_TO_REG(val);
+ mutex_lock(&data->update_lock);
+ val |= w83792d_read_value(client, W83792D_REG_PWM[nr]) & 0xf0;
+ data->pwm[nr] = val;
w83792d_write_value(client, W83792D_REG_PWM[nr], data->pwm[nr]);
+ mutex_unlock(&data->update_lock);
return count;
}
@@ -683,6 +690,10 @@ store_pwmenable(struct device *dev, struct device_attribute *attr,
u8 fan_cfg_tmp, cfg1_tmp, cfg2_tmp, cfg3_tmp, cfg4_tmp;
val = simple_strtoul(buf, NULL, 10);
+ if (val < 1 || val > 3)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
switch (val) {
case 1:
data->pwmenable[nr] = 0; /* manual mode */
@@ -693,8 +704,6 @@ store_pwmenable(struct device *dev, struct device_attribute *attr,
case 3:
data->pwmenable[nr] = 1; /* thermal cruise/Smart Fan I */
break;
- default:
- return -EINVAL;
}
cfg1_tmp = data->pwmenable[0];
cfg2_tmp = (data->pwmenable[1]) << 2;
@@ -702,14 +711,15 @@ store_pwmenable(struct device *dev, struct device_attribute *attr,
cfg4_tmp = w83792d_read_value(client,W83792D_REG_FAN_CFG) & 0xc0;
fan_cfg_tmp = ((cfg4_tmp | cfg3_tmp) | cfg2_tmp) | cfg1_tmp;
w83792d_write_value(client, W83792D_REG_FAN_CFG, fan_cfg_tmp);
+ mutex_unlock(&data->update_lock);
return count;
}
static struct sensor_device_attribute sda_pwm[] = {
- SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
- SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
- SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
+ SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
+ SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
+ SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
};
static struct sensor_device_attribute sda_pwm_enable[] = {
SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
@@ -728,7 +738,7 @@ show_pwm_mode(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct w83792d_data *data = w83792d_update_device(dev);
- return sprintf(buf, "%d\n", data->pwm_mode[nr-1]);
+ return sprintf(buf, "%d\n", data->pwm[nr] >> 7);
}
static ssize_t
@@ -736,29 +746,35 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
- int nr = sensor_attr->index - 1;
+ int nr = sensor_attr->index;
struct i2c_client *client = to_i2c_client(dev);
struct w83792d_data *data = i2c_get_clientdata(client);
u32 val;
- u8 pwm_mode_mask = 0;
val = simple_strtoul(buf, NULL, 10);
- data->pwm_mode[nr] = SENSORS_LIMIT(val, 0, 1);
- pwm_mode_mask = w83792d_read_value(client,
- W83792D_REG_PWM[nr]) & 0x7f;
- w83792d_write_value(client, W83792D_REG_PWM[nr],
- ((data->pwm_mode[nr]) << 7) | pwm_mode_mask);
+ if (val != 0 && val != 1)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ data->pwm[nr] = w83792d_read_value(client, W83792D_REG_PWM[nr]);
+ if (val) { /* PWM mode */
+ data->pwm[nr] |= 0x80;
+ } else { /* DC mode */
+ data->pwm[nr] &= 0x7f;
+ }
+ w83792d_write_value(client, W83792D_REG_PWM[nr], data->pwm[nr]);
+ mutex_unlock(&data->update_lock);
return count;
}
static struct sensor_device_attribute sda_pwm_mode[] = {
SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO,
- show_pwm_mode, store_pwm_mode, 1),
+ show_pwm_mode, store_pwm_mode, 0),
SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO,
- show_pwm_mode, store_pwm_mode, 2),
+ show_pwm_mode, store_pwm_mode, 1),
SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO,
- show_pwm_mode, store_pwm_mode, 3),
+ show_pwm_mode, store_pwm_mode, 2),
};
@@ -789,12 +805,13 @@ store_chassis_clear(struct device *dev, struct device_attribute *attr,
u8 temp1 = 0, temp2 = 0;
val = simple_strtoul(buf, NULL, 10);
-
+ mutex_lock(&data->update_lock);
data->chassis_clear = SENSORS_LIMIT(val, 0 ,1);
temp1 = ((data->chassis_clear) << 7) & 0x80;
temp2 = w83792d_read_value(client,
W83792D_REG_CHASSIS_CLR) & 0x7f;
w83792d_write_value(client, W83792D_REG_CHASSIS_CLR, temp1 | temp2);
+ mutex_unlock(&data->update_lock);
return count;
}
@@ -827,10 +844,12 @@ store_thermal_cruise(struct device *dev, struct device_attribute *attr,
val = simple_strtoul(buf, NULL, 10);
target_tmp = val;
target_tmp = target_tmp & 0x7f;
+ mutex_lock(&data->update_lock);
target_mask = w83792d_read_value(client, W83792D_REG_THERMAL[nr]) & 0x80;
data->thermal_cruise[nr] = SENSORS_LIMIT(target_tmp, 0, 255);
w83792d_write_value(client, W83792D_REG_THERMAL[nr],
(data->thermal_cruise[nr]) | target_mask);
+ mutex_unlock(&data->update_lock);
return count;
}
@@ -867,6 +886,7 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
u8 tol_tmp, tol_mask;
val = simple_strtoul(buf, NULL, 10);
+ mutex_lock(&data->update_lock);
tol_mask = w83792d_read_value(client,
W83792D_REG_TOLERANCE[nr]) & ((nr == 1) ? 0x0f : 0xf0);
tol_tmp = SENSORS_LIMIT(val, 0, 15);
@@ -877,6 +897,7 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
}
w83792d_write_value(client, W83792D_REG_TOLERANCE[nr],
tol_mask | tol_tmp);
+ mutex_unlock(&data->update_lock);
return count;
}
@@ -915,11 +936,13 @@ store_sf2_point(struct device *dev, struct device_attribute *attr,
u8 mask_tmp = 0;
val = simple_strtoul(buf, NULL, 10);
+ mutex_lock(&data->update_lock);
data->sf2_points[index][nr] = SENSORS_LIMIT(val, 0, 127);
mask_tmp = w83792d_read_value(client,
W83792D_REG_POINTS[index][nr]) & 0x80;
w83792d_write_value(client, W83792D_REG_POINTS[index][nr],
mask_tmp|data->sf2_points[index][nr]);
+ mutex_unlock(&data->update_lock);
return count;
}
@@ -979,6 +1002,7 @@ store_sf2_level(struct device *dev, struct device_attribute *attr,
u8 mask_tmp=0, level_tmp=0;
val = simple_strtoul(buf, NULL, 10);
+ mutex_lock(&data->update_lock);
data->sf2_levels[index][nr] = SENSORS_LIMIT((val * 15) / 100, 0, 15);
mask_tmp = w83792d_read_value(client, W83792D_REG_LEVELS[index][nr])
& ((nr==3) ? 0xf0 : 0x0f);
@@ -988,6 +1012,7 @@ store_sf2_level(struct device *dev, struct device_attribute *attr,
level_tmp = data->sf2_levels[index][nr] << 4;
}
w83792d_write_value(client, W83792D_REG_LEVELS[index][nr], level_tmp | mask_tmp);
+ mutex_unlock(&data->update_lock);
return count;
}
@@ -1373,7 +1398,7 @@ static struct w83792d_data *w83792d_update_device(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct w83792d_data *data = i2c_get_clientdata(client);
int i, j;
- u8 reg_array_tmp[4], pwm_array_tmp[7], reg_tmp;
+ u8 reg_array_tmp[4], reg_tmp;
mutex_lock(&data->update_lock);
@@ -1402,10 +1427,8 @@ static struct w83792d_data *w83792d_update_device(struct device *dev)
data->fan_min[i] = w83792d_read_value(client,
W83792D_REG_FAN_MIN[i]);
/* Update the PWM/DC Value and PWM/DC flag */
- pwm_array_tmp[i] = w83792d_read_value(client,
+ data->pwm[i] = w83792d_read_value(client,
W83792D_REG_PWM[i]);
- data->pwm[i] = pwm_array_tmp[i] & 0x0f;
- data->pwm_mode[i] = pwm_array_tmp[i] >> 7;
}
reg_tmp = w83792d_read_value(client, W83792D_REG_FAN_CFG);
@@ -1513,7 +1536,6 @@ static void w83792d_print_debug(struct w83792d_data *data, struct device *dev)
dev_dbg(dev, "fan[%d] is: 0x%x\n", i, data->fan[i]);
dev_dbg(dev, "fan[%d] min is: 0x%x\n", i, data->fan_min[i]);
dev_dbg(dev, "pwm[%d] is: 0x%x\n", i, data->pwm[i]);
- dev_dbg(dev, "pwm_mode[%d] is: 0x%x\n", i, data->pwm_mode[i]);
}
dev_dbg(dev, "3 set of Temperatures: =====>\n");
for (i=0; i<3; i++) {
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index d6d4494..884320e 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -163,7 +163,7 @@ config I2C_PXA_SLAVE
I2C bus.
config I2C_PIIX4
- tristate "Intel PIIX4"
+ tristate "Intel PIIX4 and compatible (ATI/Serverworks/Broadcom/SMSC)"
depends on I2C && PCI
help
If you say yes to this option, support will be included for the Intel
@@ -172,6 +172,9 @@ config I2C_PIIX4
of Broadcom):
Intel PIIX4
Intel 440MX
+ ATI IXP200
+ ATI IXP300
+ ATI IXP400
Serverworks OSB4
Serverworks CSB5
Serverworks CSB6
@@ -252,12 +255,12 @@ config I2C_POWERMAC
will be called i2c-powermac.
config I2C_MPC
- tristate "MPC107/824x/85xx/52xx"
+ tristate "MPC107/824x/85xx/52xx/86xx"
depends on I2C && PPC32
help
If you say yes to this option, support will be included for the
built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and
- MPC85xx family processors. The driver may also work on 52xx
+ MPC85xx/MPC8641 family processors. The driver may also work on 52xx
family processors, though interrupts are known not to work.
This driver can also be built as a module. If so, the module
@@ -273,6 +276,17 @@ config I2C_NFORCE2
This driver can also be built as a module. If so, the module
will be called i2c-nforce2.
+config I2C_OCORES
+ tristate "OpenCores I2C Controller"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes to this option, support will be included for the
+ OpenCores I2C controller. For details see
+ http://www.opencores.org/projects.cgi/web/i2c/overview
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-ocores.
+
config I2C_PARPORT
tristate "Parallel port adapter"
depends on I2C && PARPORT
@@ -500,6 +514,7 @@ config I2C_PCA_ISA
tristate "PCA9564 on an ISA bus"
depends on I2C
select I2C_ALGOPCA
+ default n
help
This driver supports ISA boards using the Philips PCA 9564
Parallel bus to I2C bus controller
@@ -507,6 +522,11 @@ config I2C_PCA_ISA
This driver can also be built as a module. If so, the module
will be called i2c-pca-isa.
+ This device is almost undetectable and using this driver on a
+ system which doesn't have this device will result in long
+ delays when I2C/SMBus chip drivers are loaded (e.g. at boot
+ time). If unsure, say N.
+
config I2C_MV64XXX
tristate "Marvell mv64xxx I2C Controller"
depends on I2C && MV64X60 && EXPERIMENTAL
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index b44831d..ac56df5 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
+obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index dfca749..3e0d04d 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -1,5 +1,5 @@
/*
- i801.c - Part of lm_sensors, Linux kernel modules for hardware
+ i2c-i801.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
@@ -36,7 +36,7 @@
This driver supports several versions of Intel's I/O Controller Hubs (ICH).
For SMBus support, they are similar to the PIIX4 and are part
of Intel's '810' and other chipsets.
- See the doc/busses/i2c-i801 file for details.
+ See the file Documentation/i2c/busses/i2c-i801 for details.
I2C Block Read and Process Call are not supported.
*/
@@ -66,9 +66,8 @@
#define SMBAUXCTL (13 + i801_smba) /* ICH4 only */
/* PCI Address Constants */
-#define SMBBA 0x020
+#define SMBBAR 4
#define SMBHSTCFG 0x040
-#define SMBREV 0x008
/* Host configuration bits for SMBHSTCFG */
#define SMBHSTCFG_HST_EN 1
@@ -92,92 +91,16 @@
#define I801_START 0x40
#define I801_PEC_EN 0x80 /* ICH4 only */
-/* insmod parameters */
-
-/* If force_addr is set to anything different from 0, we forcibly enable
- the I801 at the given address. VERY DANGEROUS! */
-static u16 force_addr;
-module_param(force_addr, ushort, 0);
-MODULE_PARM_DESC(force_addr,
- "Forcibly enable the I801 at the given address. "
- "EXTREMELY DANGEROUS!");
static int i801_transaction(void);
static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
int command, int hwpec);
-static unsigned short i801_smba;
+static unsigned long i801_smba;
static struct pci_driver i801_driver;
static struct pci_dev *I801_dev;
static int isich4;
-static int i801_setup(struct pci_dev *dev)
-{
- int error_return = 0;
- unsigned char temp;
-
- /* Note: we keep on searching until we have found 'function 3' */
- if(PCI_FUNC(dev->devfn) != 3)
- return -ENODEV;
-
- I801_dev = dev;
- if ((dev->device == PCI_DEVICE_ID_INTEL_82801DB_3) ||
- (dev->device == PCI_DEVICE_ID_INTEL_82801EB_3) ||
- (dev->device == PCI_DEVICE_ID_INTEL_ESB_4))
- isich4 = 1;
- else
- isich4 = 0;
-
- /* Determine the address of the SMBus areas */
- if (force_addr) {
- i801_smba = force_addr & 0xfff0;
- } else {
- pci_read_config_word(I801_dev, SMBBA, &i801_smba);
- i801_smba &= 0xfff0;
- if(i801_smba == 0) {
- dev_err(&dev->dev, "SMB base address uninitialized "
- "- upgrade BIOS or use force_addr=0xaddr\n");
- return -ENODEV;
- }
- }
-
- if (!request_region(i801_smba, (isich4 ? 16 : 8), i801_driver.name)) {
- dev_err(&dev->dev, "I801_smb region 0x%x already in use!\n",
- i801_smba);
- error_return = -EBUSY;
- goto END;
- }
-
- pci_read_config_byte(I801_dev, SMBHSTCFG, &temp);
- temp &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */
- pci_write_config_byte(I801_dev, SMBHSTCFG, temp);
-
- /* If force_addr is set, we program the new address here. Just to make
- sure, we disable the device first. */
- if (force_addr) {
- pci_write_config_byte(I801_dev, SMBHSTCFG, temp & 0xfe);
- pci_write_config_word(I801_dev, SMBBA, i801_smba);
- pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 0x01);
- dev_warn(&dev->dev, "WARNING: I801 SMBus interface set to "
- "new address %04x!\n", i801_smba);
- } else if ((temp & 1) == 0) {
- pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 1);
- dev_warn(&dev->dev, "enabling SMBus device\n");
- }
-
- if (temp & 0x02)
- dev_dbg(&dev->dev, "I801 using Interrupt SMI# for SMBus.\n");
- else
- dev_dbg(&dev->dev, "I801 using PCI Interrupt for SMBus.\n");
-
- pci_read_config_byte(I801_dev, SMBREV, &temp);
- dev_dbg(&dev->dev, "SMBREV = 0x%X\n", temp);
- dev_dbg(&dev->dev, "I801_smba = 0x%X\n", i801_smba);
-
-END:
- return error_return;
-}
-
static int i801_transaction(void)
{
int temp;
@@ -334,8 +257,8 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
/* We will always wait for a fraction of a second! */
timeout = 0;
do {
- temp = inb_p(SMBHSTSTS);
msleep(1);
+ temp = inb_p(SMBHSTSTS);
}
while ((!(temp & 0x80))
&& (timeout++ < MAX_TIMEOUT));
@@ -393,8 +316,8 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
/* wait for INTR bit as advised by Intel */
timeout = 0;
do {
- temp = inb_p(SMBHSTSTS);
msleep(1);
+ temp = inb_p(SMBHSTSTS);
} while ((!(temp & 0x02))
&& (timeout++ < MAX_TIMEOUT));
@@ -541,25 +464,76 @@ MODULE_DEVICE_TABLE (pci, i801_ids);
static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
+ unsigned char temp;
+ int err;
+
+ I801_dev = dev;
+ if ((dev->device == PCI_DEVICE_ID_INTEL_82801DB_3) ||
+ (dev->device == PCI_DEVICE_ID_INTEL_82801EB_3) ||
+ (dev->device == PCI_DEVICE_ID_INTEL_ESB_4))
+ isich4 = 1;
+ else
+ isich4 = 0;
+
+ err = pci_enable_device(dev);
+ if (err) {
+ dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n",
+ err);
+ goto exit;
+ }
+
+ /* Determine the address of the SMBus area */
+ i801_smba = pci_resource_start(dev, SMBBAR);
+ if (!i801_smba) {
+ dev_err(&dev->dev, "SMBus base address uninitialized, "
+ "upgrade BIOS\n");
+ err = -ENODEV;
+ goto exit_disable;
+ }
+
+ err = pci_request_region(dev, SMBBAR, i801_driver.name);
+ if (err) {
+ dev_err(&dev->dev, "Failed to request SMBus region "
+ "0x%lx-0x%lx\n", i801_smba,
+ pci_resource_end(dev, SMBBAR));
+ goto exit_disable;
+ }
- if (i801_setup(dev)) {
- dev_warn(&dev->dev,
- "I801 not detected, module not inserted.\n");
- return -ENODEV;
+ pci_read_config_byte(I801_dev, SMBHSTCFG, &temp);
+ temp &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */
+ if (!(temp & SMBHSTCFG_HST_EN)) {
+ dev_info(&dev->dev, "Enabling SMBus device\n");
+ temp |= SMBHSTCFG_HST_EN;
}
+ pci_write_config_byte(I801_dev, SMBHSTCFG, temp);
+
+ if (temp & SMBHSTCFG_SMB_SMI_EN)
+ dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n");
+ else
+ dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n");
/* set up the driverfs linkage to our parent device */
i801_adapter.dev.parent = &dev->dev;
snprintf(i801_adapter.name, I2C_NAME_SIZE,
- "SMBus I801 adapter at %04x", i801_smba);
- return i2c_add_adapter(&i801_adapter);
+ "SMBus I801 adapter at %04lx", i801_smba);
+ err = i2c_add_adapter(&i801_adapter);
+ if (err) {
+ dev_err(&dev->dev, "Failed to add SMBus adapter\n");
+ goto exit_disable;
+ }
+
+exit_disable:
+ pci_disable_device(dev);
+exit:
+ return err;
}
static void __devexit i801_remove(struct pci_dev *dev)
{
i2c_del_adapter(&i801_adapter);
- release_region(i801_smba, (isich4 ? 16 : 8));
+ pci_release_region(dev, SMBBAR);
+ pci_disable_device(dev);
}
static struct pci_driver i801_driver = {
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index 2d80eb2..604b49e 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -31,6 +31,8 @@
nForce3 250Gb MCP 00E4
nForce4 MCP 0052
nForce4 MCP-04 0034
+ nForce4 MCP51 0264
+ nForce4 MCP55 0368
This driver supports the 2 SMBuses that are included in the MCP of the
nForce2/3/4 chipsets.
@@ -64,6 +66,7 @@ struct nforce2_smbus {
/*
* nVidia nForce2 SMBus control register definitions
+ * (Newer incarnations use standard BARs 4 and 5 instead)
*/
#define NFORCE_PCI_SMB1 0x50
#define NFORCE_PCI_SMB2 0x54
@@ -259,6 +262,8 @@ static struct pci_device_id nforce2_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS) },
{ 0 }
};
@@ -266,19 +271,29 @@ static struct pci_device_id nforce2_ids[] = {
MODULE_DEVICE_TABLE (pci, nforce2_ids);
-static int __devinit nforce2_probe_smb (struct pci_dev *dev, int reg,
- struct nforce2_smbus *smbus, char *name)
+static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar,
+ int alt_reg, struct nforce2_smbus *smbus, const char *name)
{
- u16 iobase;
int error;
- if (pci_read_config_word(dev, reg, &iobase) != PCIBIOS_SUCCESSFUL) {
- dev_err(&smbus->adapter.dev, "Error reading PCI config for %s\n", name);
- return -1;
+ smbus->base = pci_resource_start(dev, bar);
+ if (smbus->base) {
+ smbus->size = pci_resource_len(dev, bar);
+ } else {
+ /* Older incarnations of the device used non-standard BARs */
+ u16 iobase;
+
+ if (pci_read_config_word(dev, alt_reg, &iobase)
+ != PCIBIOS_SUCCESSFUL) {
+ dev_err(&dev->dev, "Error reading PCI config for %s\n",
+ name);
+ return -1;
+ }
+
+ smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK;
+ smbus->size = 8;
}
- smbus->dev = dev;
- smbus->base = iobase & 0xfffc;
- smbus->size = 8;
+ smbus->dev = dev;
if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) {
dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n",
@@ -313,12 +328,13 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_
pci_set_drvdata(dev, smbuses);
/* SMBus adapter 1 */
- res1 = nforce2_probe_smb (dev, NFORCE_PCI_SMB1, &smbuses[0], "SMB1");
+ res1 = nforce2_probe_smb(dev, 4, NFORCE_PCI_SMB1, &smbuses[0], "SMB1");
if (res1 < 0) {
dev_err(&dev->dev, "Error probing SMB1.\n");
smbuses[0].base = 0; /* to have a check value */
}
- res2 = nforce2_probe_smb (dev, NFORCE_PCI_SMB2, &smbuses[1], "SMB2");
+ /* SMBus adapter 2 */
+ res2 = nforce2_probe_smb(dev, 5, NFORCE_PCI_SMB2, &smbuses[1], "SMB2");
if (res2 < 0) {
dev_err(&dev->dev, "Error probing SMB2.\n");
smbuses[1].base = 0; /* to have a check value */
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
new file mode 100644
index 0000000..5928240
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -0,0 +1,341 @@
+/*
+ * i2c-ocores.c: I2C bus driver for OpenCores I2C controller
+ * (http://www.opencores.org/projects.cgi/web/i2c/overview).
+ *
+ * Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/i2c-ocores.h>
+#include <asm/io.h>
+
+struct ocores_i2c {
+ void __iomem *base;
+ int regstep;
+ wait_queue_head_t wait;
+ struct i2c_adapter adap;
+ struct i2c_msg *msg;
+ int pos;
+ int nmsgs;
+ int state; /* see STATE_ */
+};
+
+/* registers */
+#define OCI2C_PRELOW 0
+#define OCI2C_PREHIGH 1
+#define OCI2C_CONTROL 2
+#define OCI2C_DATA 3
+#define OCI2C_CMD 4 /* write only */
+#define OCI2C_STATUS 4 /* read only, same address as OCI2C_CMD */
+
+#define OCI2C_CTRL_IEN 0x40
+#define OCI2C_CTRL_EN 0x80
+
+#define OCI2C_CMD_START 0x91
+#define OCI2C_CMD_STOP 0x41
+#define OCI2C_CMD_READ 0x21
+#define OCI2C_CMD_WRITE 0x11
+#define OCI2C_CMD_READ_ACK 0x21
+#define OCI2C_CMD_READ_NACK 0x29
+#define OCI2C_CMD_IACK 0x01
+
+#define OCI2C_STAT_IF 0x01
+#define OCI2C_STAT_TIP 0x02
+#define OCI2C_STAT_ARBLOST 0x20
+#define OCI2C_STAT_BUSY 0x40
+#define OCI2C_STAT_NACK 0x80
+
+#define STATE_DONE 0
+#define STATE_START 1
+#define STATE_WRITE 2
+#define STATE_READ 3
+#define STATE_ERROR 4
+
+static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value)
+{
+ iowrite8(value, i2c->base + reg * i2c->regstep);
+}
+
+static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg)
+{
+ return ioread8(i2c->base + reg * i2c->regstep);
+}
+
+static void ocores_process(struct ocores_i2c *i2c)
+{
+ struct i2c_msg *msg = i2c->msg;
+ u8 stat = oc_getreg(i2c, OCI2C_STATUS);
+
+ if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) {
+ /* stop has been sent */
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
+ wake_up(&i2c->wait);
+ return;
+ }
+
+ /* error? */
+ if (stat & OCI2C_STAT_ARBLOST) {
+ i2c->state = STATE_ERROR;
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ return;
+ }
+
+ if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) {
+ i2c->state =
+ (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
+
+ if (stat & OCI2C_STAT_NACK) {
+ i2c->state = STATE_ERROR;
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ return;
+ }
+ } else
+ msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA);
+
+ /* end of msg? */
+ if (i2c->pos == msg->len) {
+ i2c->nmsgs--;
+ i2c->msg++;
+ i2c->pos = 0;
+ msg = i2c->msg;
+
+ if (i2c->nmsgs) { /* end? */
+ /* send start? */
+ if (!(msg->flags & I2C_M_NOSTART)) {
+ u8 addr = (msg->addr << 1);
+
+ if (msg->flags & I2C_M_RD)
+ addr |= 1;
+
+ i2c->state = STATE_START;
+
+ oc_setreg(i2c, OCI2C_DATA, addr);
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
+ return;
+ } else
+ i2c->state = (msg->flags & I2C_M_RD)
+ ? STATE_READ : STATE_WRITE;
+ } else {
+ i2c->state = STATE_DONE;
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ return;
+ }
+ }
+
+ if (i2c->state == STATE_READ) {
+ oc_setreg(i2c, OCI2C_CMD, i2c->pos == (msg->len-1) ?
+ OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK);
+ } else {
+ oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]);
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE);
+ }
+}
+
+static irqreturn_t ocores_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct ocores_i2c *i2c = dev_id;
+
+ ocores_process(i2c);
+
+ return IRQ_HANDLED;
+}
+
+static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct ocores_i2c *i2c = i2c_get_adapdata(adap);
+
+ i2c->msg = msgs;
+ i2c->pos = 0;
+ i2c->nmsgs = num;
+ i2c->state = STATE_START;
+
+ oc_setreg(i2c, OCI2C_DATA,
+ (i2c->msg->addr << 1) |
+ ((i2c->msg->flags & I2C_M_RD) ? 1:0));
+
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
+
+ if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
+ (i2c->state == STATE_DONE), HZ))
+ return (i2c->state == STATE_DONE) ? num : -EIO;
+ else
+ return -ETIMEDOUT;
+}
+
+static void ocores_init(struct ocores_i2c *i2c,
+ struct ocores_i2c_platform_data *pdata)
+{
+ int prescale;
+ u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);
+
+ /* make sure the device is disabled */
+ oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
+
+ prescale = (pdata->clock_khz / (5*100)) - 1;
+ oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff);
+ oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8);
+
+ /* Init the device */
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
+ oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN | OCI2C_CTRL_EN);
+}
+
+
+static u32 ocores_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm ocores_algorithm = {
+ .master_xfer = ocores_xfer,
+ .functionality = ocores_func,
+};
+
+static struct i2c_adapter ocores_adapter = {
+ .owner = THIS_MODULE,
+ .name = "i2c-ocores",
+ .class = I2C_CLASS_HWMON,
+ .algo = &ocores_algorithm,
+};
+
+
+static int __devinit ocores_i2c_probe(struct platform_device *pdev)
+{
+ struct ocores_i2c *i2c;
+ struct ocores_i2c_platform_data *pdata;
+ struct resource *res, *res2;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res2)
+ return -ENODEV;
+
+ pdata = (struct ocores_i2c_platform_data*) pdev->dev.platform_data;
+ if (!pdata)
+ return -ENODEV;
+
+ i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ if (!request_mem_region(res->start, res->end - res->start + 1,
+ pdev->name)) {
+ dev_err(&pdev->dev, "Memory region busy\n");
+ ret = -EBUSY;
+ goto request_mem_failed;
+ }
+
+ i2c->base = ioremap(res->start, res->end - res->start + 1);
+ if (!i2c->base) {
+ dev_err(&pdev->dev, "Unable to map registers\n");
+ ret = -EIO;
+ goto map_failed;
+ }
+
+ i2c->regstep = pdata->regstep;
+ ocores_init(i2c, pdata);
+
+ init_waitqueue_head(&i2c->wait);
+ ret = request_irq(res2->start, ocores_isr, 0, pdev->name, i2c);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot claim IRQ\n");
+ goto request_irq_failed;
+ }
+
+ /* hook up driver to tree */
+ platform_set_drvdata(pdev, i2c);
+ i2c->adap = ocores_adapter;
+ i2c_set_adapdata(&i2c->adap, i2c);
+ i2c->adap.dev.parent = &pdev->dev;
+
+ /* add i2c adapter to i2c tree */
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add adapter\n");
+ goto add_adapter_failed;
+ }
+
+ return 0;
+
+add_adapter_failed:
+ free_irq(res2->start, i2c);
+request_irq_failed:
+ iounmap(i2c->base);
+map_failed:
+ release_mem_region(res->start, res->end - res->start + 1);
+request_mem_failed:
+ kfree(i2c);
+
+ return ret;
+}
+
+static int __devexit ocores_i2c_remove(struct platform_device* pdev)
+{
+ struct ocores_i2c *i2c = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ /* disable i2c logic */
+ oc_setreg(i2c, OCI2C_CONTROL, oc_getreg(i2c, OCI2C_CONTROL)
+ & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
+
+ /* remove adapter & data */
+ i2c_del_adapter(&i2c->adap);
+ platform_set_drvdata(pdev, NULL);
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res)
+ free_irq(res->start, i2c);
+
+ iounmap(i2c->base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ kfree(i2c);
+
+ return 0;
+}
+
+static struct platform_driver ocores_i2c_driver = {
+ .probe = ocores_i2c_probe,
+ .remove = __devexit_p(ocores_i2c_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ocores-i2c",
+ },
+};
+
+static int __init ocores_i2c_init(void)
+{
+ return platform_driver_register(&ocores_i2c_driver);
+}
+
+static void __exit ocores_i2c_exit(void)
+{
+ platform_driver_unregister(&ocores_i2c_driver);
+}
+
+module_init(ocores_i2c_init);
+module_exit(ocores_i2c_exit);
+
+MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
+MODULE_DESCRIPTION("OpenCores I2C bus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index d9c7c00..8f2f65b 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -102,13 +102,6 @@ MODULE_PARM_DESC(force_addr,
"Forcibly enable the PIIX4 at the given address. "
"EXTREMELY DANGEROUS!");
-/* If fix_hstcfg is set to anything different from 0, we reset one of the
- registers to be a valid value. */
-static int fix_hstcfg;
-module_param (fix_hstcfg, int, 0);
-MODULE_PARM_DESC(fix_hstcfg,
- "Fix config register. Needed on some boards (Force CPCI735).");
-
static int piix4_transaction(void);
static unsigned short piix4_smba;
@@ -137,7 +130,7 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
/* Don't access SMBus on IBM systems which get corrupted eeproms */
if (dmi_check_system(piix4_dmi_table) &&
PIIX4_dev->vendor == PCI_VENDOR_ID_INTEL) {
- dev_err(&PIIX4_dev->dev, "IBM Laptop detected; this module "
+ dev_err(&PIIX4_dev->dev, "IBM system detected; this module "
"may corrupt your serial eeprom! Refusing to load "
"module!\n");
return -EPERM;
@@ -166,22 +159,6 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
pci_read_config_byte(PIIX4_dev, SMBHSTCFG, &temp);
- /* Some BIOS will set up the chipset incorrectly and leave a register
- in an undefined state (causing I2C to act very strangely). */
- if (temp & 0x02) {
- if (fix_hstcfg) {
- dev_info(&PIIX4_dev->dev, "Working around buggy BIOS "
- "(I2C)\n");
- temp &= 0xfd;
- pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp);
- } else {
- dev_info(&PIIX4_dev->dev, "Unusual config register "
- "value\n");
- dev_info(&PIIX4_dev->dev, "Try using fix_hstcfg=1 if "
- "you experience problems\n");
- }
- }
-
/* If force_addr is set, we program the new address here. Just to make
sure, we disable the PIIX4 first. */
if (force_addr) {
@@ -214,7 +191,7 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
}
}
- if ((temp & 0x0E) == 8)
+ if (((temp & 0x0E) == 8) || ((temp & 0x0E) == 2))
dev_dbg(&PIIX4_dev->dev, "Using Interrupt 9 for SMBus.\n");
else if ((temp & 0x0E) == 0)
dev_dbg(&PIIX4_dev->dev, "Using Interrupt SMI# for SMBus.\n");
@@ -413,6 +390,12 @@ static struct i2c_adapter piix4_adapter = {
static struct pci_device_id piix4_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3),
.driver_data = 3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_SMBUS),
+ .driver_data = 0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS),
+ .driver_data = 0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS),
+ .driver_data = 0 },
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4),
.driver_data = 0 },
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5),
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index 766cc96..22a3eda 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -33,7 +33,6 @@
#include <linux/delay.h>
#include <linux/mutex.h>
#include <asm/io.h>
-#include <asm/msr.h>
#include <linux/scx200.h>
@@ -85,6 +84,10 @@ struct scx200_acb_iface {
u8 *ptr;
char needs_reset;
unsigned len;
+
+ /* PCI device info */
+ struct pci_dev *pdev;
+ int bar;
};
/* Register Definitions */
@@ -381,7 +384,7 @@ static struct i2c_algorithm scx200_acb_algorithm = {
static struct scx200_acb_iface *scx200_acb_list;
static DECLARE_MUTEX(scx200_acb_list_mutex);
-static int scx200_acb_probe(struct scx200_acb_iface *iface)
+static __init int scx200_acb_probe(struct scx200_acb_iface *iface)
{
u8 val;
@@ -417,17 +420,16 @@ static int scx200_acb_probe(struct scx200_acb_iface *iface)
return 0;
}
-static int __init scx200_acb_create(const char *text, int base, int index)
+static __init struct scx200_acb_iface *scx200_create_iface(const char *text,
+ int index)
{
struct scx200_acb_iface *iface;
struct i2c_adapter *adapter;
- int rc;
iface = kzalloc(sizeof(*iface), GFP_KERNEL);
if (!iface) {
printk(KERN_ERR NAME ": can't allocate memory\n");
- rc = -ENOMEM;
- goto errout;
+ return NULL;
}
adapter = &iface->adapter;
@@ -440,26 +442,27 @@ static int __init scx200_acb_create(const char *text, int base, int index)
mutex_init(&iface->mutex);
- if (!request_region(base, 8, adapter->name)) {
- printk(KERN_ERR NAME ": can't allocate io 0x%x-0x%x\n",
- base, base + 8-1);
- rc = -EBUSY;
- goto errout_free;
- }
- iface->base = base;
+ return iface;
+}
+
+static int __init scx200_acb_create(struct scx200_acb_iface *iface)
+{
+ struct i2c_adapter *adapter;
+ int rc;
+
+ adapter = &iface->adapter;
rc = scx200_acb_probe(iface);
if (rc) {
printk(KERN_WARNING NAME ": probe failed\n");
- goto errout_release;
+ return rc;
}
scx200_acb_reset(iface);
if (i2c_add_adapter(adapter) < 0) {
printk(KERN_ERR NAME ": failed to register\n");
- rc = -ENODEV;
- goto errout_release;
+ return -ENODEV;
}
down(&scx200_acb_list_mutex);
@@ -468,64 +471,148 @@ static int __init scx200_acb_create(const char *text, int base, int index)
up(&scx200_acb_list_mutex);
return 0;
+}
- errout_release:
- release_region(iface->base, 8);
+static __init int scx200_create_pci(const char *text, struct pci_dev *pdev,
+ int bar)
+{
+ struct scx200_acb_iface *iface;
+ int rc;
+
+ iface = scx200_create_iface(text, 0);
+
+ if (iface == NULL)
+ return -ENOMEM;
+
+ iface->pdev = pdev;
+ iface->bar = bar;
+
+ pci_enable_device_bars(iface->pdev, 1 << iface->bar);
+
+ rc = pci_request_region(iface->pdev, iface->bar, iface->adapter.name);
+
+ if (rc != 0) {
+ printk(KERN_ERR NAME ": can't allocate PCI BAR %d\n",
+ iface->bar);
+ goto errout_free;
+ }
+
+ iface->base = pci_resource_start(iface->pdev, iface->bar);
+ rc = scx200_acb_create(iface);
+
+ if (rc == 0)
+ return 0;
+
+ pci_release_region(iface->pdev, iface->bar);
+ pci_dev_put(iface->pdev);
errout_free:
kfree(iface);
- errout:
return rc;
}
-static struct pci_device_id scx200[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
- { },
-};
+static int __init scx200_create_isa(const char *text, unsigned long base,
+ int index)
+{
+ struct scx200_acb_iface *iface;
+ int rc;
+
+ iface = scx200_create_iface(text, index);
+
+ if (iface == NULL)
+ return -ENOMEM;
+
+ if (request_region(base, 8, iface->adapter.name) == 0) {
+ printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n",
+ base, base + 8 - 1);
+ rc = -EBUSY;
+ goto errout_free;
+ }
+
+ iface->base = base;
+ rc = scx200_acb_create(iface);
+
+ if (rc == 0)
+ return 0;
-static struct pci_device_id divil_pci[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
- { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
- { } /* NULL entry */
+ release_region(base, 8);
+ errout_free:
+ kfree(iface);
+ return rc;
+}
+
+/* Driver data is an index into the scx200_data array that indicates
+ * the name and the BAR where the I/O address resource is located. ISA
+ * devices are flagged with a bar value of -1 */
+
+static struct pci_device_id scx200_pci[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE),
+ .driver_data = 0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE),
+ .driver_data = 0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA),
+ .driver_data = 1 },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA),
+ .driver_data = 2 }
};
-#define MSR_LBAR_SMB 0x5140000B
+static struct {
+ const char *name;
+ int bar;
+} scx200_data[] = {
+ { "SCx200", -1 },
+ { "CS5535", 0 },
+ { "CS5536", 0 }
+};
-static __init int scx200_add_cs553x(void)
+static __init int scx200_scan_pci(void)
{
- u32 low, hi;
- u32 smb_base;
-
- /* Grab & reserve the SMB I/O range */
- rdmsr(MSR_LBAR_SMB, low, hi);
+ int data, dev;
+ int rc = -ENODEV;
+ struct pci_dev *pdev;
+
+ for(dev = 0; dev < ARRAY_SIZE(scx200_pci); dev++) {
+ pdev = pci_get_device(scx200_pci[dev].vendor,
+ scx200_pci[dev].device, NULL);
+
+ if (pdev == NULL)
+ continue;
+
+ data = scx200_pci[dev].driver_data;
+
+ /* if .bar is greater or equal to zero, this is a
+ * PCI device - otherwise, we assume
+ that the ports are ISA based
+ */
+
+ if (scx200_data[data].bar >= 0)
+ rc = scx200_create_pci(scx200_data[data].name, pdev,
+ scx200_data[data].bar);
+ else {
+ int i;
+
+ for (i = 0; i < MAX_DEVICES; ++i) {
+ if (base[i] == 0)
+ continue;
+
+ rc = scx200_create_isa(scx200_data[data].name,
+ base[i],
+ i);
+ }
+ }
- /* Check the IO mask and whether SMB is enabled */
- if (hi != 0x0000F001) {
- printk(KERN_WARNING NAME ": SMBus not enabled\n");
- return -ENODEV;
+ break;
}
- /* SMBus IO size is 8 bytes */
- smb_base = low & 0x0000FFF8;
-
- return scx200_acb_create("CS5535", smb_base, 0);
+ return rc;
}
static int __init scx200_acb_init(void)
{
- int i;
- int rc = -ENODEV;
+ int rc;
pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
- /* Verify that this really is a SCx200 processor */
- if (pci_dev_present(scx200)) {
- for (i = 0; i < MAX_DEVICES; ++i) {
- if (base[i] > 0)
- rc = scx200_acb_create("SCx200", base[i], i);
- }
- } else if (pci_dev_present(divil_pci))
- rc = scx200_add_cs553x();
+ rc = scx200_scan_pci();
/* If at least one bus was created, init must succeed */
if (scx200_acb_list)
@@ -543,7 +630,14 @@ static void __exit scx200_acb_cleanup(void)
up(&scx200_acb_list_mutex);
i2c_del_adapter(&iface->adapter);
- release_region(iface->base, 8);
+
+ if (iface->pdev) {
+ pci_release_region(iface->pdev, iface->bar);
+ pci_dev_put(iface->pdev);
+ }
+ else
+ release_region(iface->base, 8);
+
kfree(iface);
down(&scx200_acb_list_mutex);
}
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index 7aa5c38..87ee3ce 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -39,6 +39,7 @@ config SENSORS_EEPROM
config SENSORS_PCF8574
tristate "Philips PCF8574 and PCF8574A"
depends on I2C && EXPERIMENTAL
+ default n
help
If you say yes here you get support for Philips PCF8574 and
PCF8574A chips.
@@ -46,6 +47,9 @@ config SENSORS_PCF8574
This driver can also be built as a module. If so, the module
will be called pcf8574.
+ These devices are hard to detect and rarely found on mainstream
+ hardware. If unsure, say N.
+
config SENSORS_PCA9539
tristate "Philips PCA9539 16-bit I/O port"
depends on I2C && EXPERIMENTAL
@@ -59,12 +63,16 @@ config SENSORS_PCA9539
config SENSORS_PCF8591
tristate "Philips PCF8591"
depends on I2C && EXPERIMENTAL
+ default n
help
If you say yes here you get support for Philips PCF8591 chips.
This driver can also be built as a module. If so, the module
will be called pcf8591.
+ These devices are hard to detect and rarely found on mainstream
+ hardware. If unsure, say N.
+
config ISP1301_OMAP
tristate "Philips ISP1301 with OMAP OTG"
depends on I2C && ARCH_OMAP_OTG
diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c
index 99ab4ec..2dd0a34 100644
--- a/drivers/i2c/chips/m41t00.c
+++ b/drivers/i2c/chips/m41t00.c
@@ -1,11 +1,9 @@
/*
- * drivers/i2c/chips/m41t00.c
- *
- * I2C client/driver for the ST M41T00 Real-Time Clock chip.
+ * I2C client/driver for the ST M41T00 family of i2c rtc chips.
*
* Author: Mark A. Greer <mgreer@mvista.com>
*
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * 2005, 2006 (c) MontaVista Software, Inc. This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
@@ -13,9 +11,6 @@
/*
* This i2c client/driver wedges between the drivers/char/genrtc.c RTC
* interface and the SMBus interface of the i2c subsystem.
- * It would be more efficient to use i2c msgs/i2c_transfer directly but, as
- * recommened in .../Documentation/i2c/writing-clients section
- * "Sending and receiving", using SMBus level communication is preferred.
*/
#include <linux/kernel.h>
@@ -24,56 +19,110 @@
#include <linux/i2c.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
-#include <linux/mutex.h>
#include <linux/workqueue.h>
-
+#include <linux/platform_device.h>
+#include <linux/m41t00.h>
#include <asm/time.h>
#include <asm/rtc.h>
-#define M41T00_DRV_NAME "m41t00"
-
-static DEFINE_MUTEX(m41t00_mutex);
-
static struct i2c_driver m41t00_driver;
static struct i2c_client *save_client;
static unsigned short ignore[] = { I2C_CLIENT_END };
-static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END };
+static unsigned short normal_addr[] = { I2C_CLIENT_END, I2C_CLIENT_END };
static struct i2c_client_address_data addr_data = {
- .normal_i2c = normal_addr,
- .probe = ignore,
- .ignore = ignore,
+ .normal_i2c = normal_addr,
+ .probe = ignore,
+ .ignore = ignore,
+};
+
+struct m41t00_chip_info {
+ u8 type;
+ char *name;
+ u8 read_limit;
+ u8 sec; /* Offsets for chip regs */
+ u8 min;
+ u8 hour;
+ u8 day;
+ u8 mon;
+ u8 year;
+ u8 alarm_mon;
+ u8 alarm_hour;
+ u8 sqw;
+ u8 sqw_freq;
};
+static struct m41t00_chip_info m41t00_chip_info_tbl[] = {
+ {
+ .type = M41T00_TYPE_M41T00,
+ .name = "m41t00",
+ .read_limit = 5,
+ .sec = 0,
+ .min = 1,
+ .hour = 2,
+ .day = 4,
+ .mon = 5,
+ .year = 6,
+ },
+ {
+ .type = M41T00_TYPE_M41T81,
+ .name = "m41t81",
+ .read_limit = 1,
+ .sec = 1,
+ .min = 2,
+ .hour = 3,
+ .day = 5,
+ .mon = 6,
+ .year = 7,
+ .alarm_mon = 0xa,
+ .alarm_hour = 0xc,
+ .sqw = 0x13,
+ },
+ {
+ .type = M41T00_TYPE_M41T85,
+ .name = "m41t85",
+ .read_limit = 1,
+ .sec = 1,
+ .min = 2,
+ .hour = 3,
+ .day = 5,
+ .mon = 6,
+ .year = 7,
+ .alarm_mon = 0xa,
+ .alarm_hour = 0xc,
+ .sqw = 0x13,
+ },
+};
+static struct m41t00_chip_info *m41t00_chip;
+
ulong
m41t00_get_rtc_time(void)
{
- s32 sec, min, hour, day, mon, year;
- s32 sec1, min1, hour1, day1, mon1, year1;
- ulong limit = 10;
+ s32 sec, min, hour, day, mon, year;
+ s32 sec1, min1, hour1, day1, mon1, year1;
+ u8 reads = 0;
+ u8 buf[8], msgbuf[1] = { 0 }; /* offset into rtc's regs */
+ struct i2c_msg msgs[] = {
+ {
+ .addr = save_client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = msgbuf,
+ },
+ {
+ .addr = save_client->addr,
+ .flags = I2C_M_RD,
+ .len = 8,
+ .buf = buf,
+ },
+ };
sec = min = hour = day = mon = year = 0;
- sec1 = min1 = hour1 = day1 = mon1 = year1 = 0;
- mutex_lock(&m41t00_mutex);
do {
- if (((sec = i2c_smbus_read_byte_data(save_client, 0)) >= 0)
- && ((min = i2c_smbus_read_byte_data(save_client, 1))
- >= 0)
- && ((hour = i2c_smbus_read_byte_data(save_client, 2))
- >= 0)
- && ((day = i2c_smbus_read_byte_data(save_client, 4))
- >= 0)
- && ((mon = i2c_smbus_read_byte_data(save_client, 5))
- >= 0)
- && ((year = i2c_smbus_read_byte_data(save_client, 6))
- >= 0)
- && ((sec == sec1) && (min == min1) && (hour == hour1)
- && (day == day1) && (mon == mon1)
- && (year == year1)))
-
- break;
+ if (i2c_transfer(save_client->adapter, msgs, 2) < 0)
+ goto read_err;
sec1 = sec;
min1 = min;
@@ -81,69 +130,88 @@ m41t00_get_rtc_time(void)
day1 = day;
mon1 = mon;
year1 = year;
- } while (--limit > 0);
- mutex_unlock(&m41t00_mutex);
-
- if (limit == 0) {
- dev_warn(&save_client->dev,
- "m41t00: can't read rtc chip\n");
- sec = min = hour = day = mon = year = 0;
- }
-
- sec &= 0x7f;
- min &= 0x7f;
- hour &= 0x3f;
- day &= 0x3f;
- mon &= 0x1f;
- year &= 0xff;
- BCD_TO_BIN(sec);
- BCD_TO_BIN(min);
- BCD_TO_BIN(hour);
- BCD_TO_BIN(day);
- BCD_TO_BIN(mon);
- BCD_TO_BIN(year);
+ sec = buf[m41t00_chip->sec] & 0x7f;
+ min = buf[m41t00_chip->min] & 0x7f;
+ hour = buf[m41t00_chip->hour] & 0x3f;
+ day = buf[m41t00_chip->day] & 0x3f;
+ mon = buf[m41t00_chip->mon] & 0x1f;
+ year = buf[m41t00_chip->year];
+ } while ((++reads < m41t00_chip->read_limit) && ((sec != sec1)
+ || (min != min1) || (hour != hour1) || (day != day1)
+ || (mon != mon1) || (year != year1)));
+
+ if ((m41t00_chip->read_limit > 1) && ((sec != sec1) || (min != min1)
+ || (hour != hour1) || (day != day1) || (mon != mon1)
+ || (year != year1)))
+ goto read_err;
+
+ sec = BCD2BIN(sec);
+ min = BCD2BIN(min);
+ hour = BCD2BIN(hour);
+ day = BCD2BIN(day);
+ mon = BCD2BIN(mon);
+ year = BCD2BIN(year);
year += 1900;
if (year < 1970)
year += 100;
return mktime(year, mon, day, hour, min, sec);
+
+read_err:
+ dev_err(&save_client->dev, "m41t00_get_rtc_time: Read error\n");
+ return 0;
}
+EXPORT_SYMBOL_GPL(m41t00_get_rtc_time);
static void
m41t00_set(void *arg)
{
struct rtc_time tm;
- ulong nowtime = *(ulong *)arg;
+ int nowtime = *(int *)arg;
+ s32 sec, min, hour, day, mon, year;
+ u8 wbuf[9], *buf = &wbuf[1], msgbuf[1] = { 0 };
+ struct i2c_msg msgs[] = {
+ {
+ .addr = save_client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = msgbuf,
+ },
+ {
+ .addr = save_client->addr,
+ .flags = I2C_M_RD,
+ .len = 8,
+ .buf = buf,
+ },
+ };
to_tm(nowtime, &tm);
tm.tm_year = (tm.tm_year - 1900) % 100;
- BIN_TO_BCD(tm.tm_sec);
- BIN_TO_BCD(tm.tm_min);
- BIN_TO_BCD(tm.tm_hour);
- BIN_TO_BCD(tm.tm_mon);
- BIN_TO_BCD(tm.tm_mday);
- BIN_TO_BCD(tm.tm_year);
-
- mutex_lock(&m41t00_mutex);
- if ((i2c_smbus_write_byte_data(save_client, 0, tm.tm_sec & 0x7f) < 0)
- || (i2c_smbus_write_byte_data(save_client, 1, tm.tm_min & 0x7f)
- < 0)
- || (i2c_smbus_write_byte_data(save_client, 2, tm.tm_hour & 0x3f)
- < 0)
- || (i2c_smbus_write_byte_data(save_client, 4, tm.tm_mday & 0x3f)
- < 0)
- || (i2c_smbus_write_byte_data(save_client, 5, tm.tm_mon & 0x1f)
- < 0)
- || (i2c_smbus_write_byte_data(save_client, 6, tm.tm_year & 0xff)
- < 0))
-
- dev_warn(&save_client->dev,"m41t00: can't write to rtc chip\n");
-
- mutex_unlock(&m41t00_mutex);
- return;
+ sec = BIN2BCD(tm.tm_sec);
+ min = BIN2BCD(tm.tm_min);
+ hour = BIN2BCD(tm.tm_hour);
+ day = BIN2BCD(tm.tm_mday);
+ mon = BIN2BCD(tm.tm_mon);
+ year = BIN2BCD(tm.tm_year);
+
+ /* Read reg values into buf[0..7]/wbuf[1..8] */
+ if (i2c_transfer(save_client->adapter, msgs, 2) < 0) {
+ dev_err(&save_client->dev, "m41t00_set: Read error\n");
+ return;
+ }
+
+ wbuf[0] = 0; /* offset into rtc's regs */
+ buf[m41t00_chip->sec] = (buf[m41t00_chip->sec] & ~0x7f) | (sec & 0x7f);
+ buf[m41t00_chip->min] = (buf[m41t00_chip->min] & ~0x7f) | (min & 0x7f);
+ buf[m41t00_chip->hour] = (buf[m41t00_chip->hour] & ~0x3f) | (hour& 0x3f);
+ buf[m41t00_chip->day] = (buf[m41t00_chip->day] & ~0x3f) | (day & 0x3f);
+ buf[m41t00_chip->mon] = (buf[m41t00_chip->mon] & ~0x1f) | (mon & 0x1f);
+
+ if (i2c_master_send(save_client, wbuf, 9) < 0)
+ dev_err(&save_client->dev, "m41t00_set: Write error\n");
}
static ulong new_time;
@@ -162,6 +230,48 @@ m41t00_set_rtc_time(ulong nowtime)
return 0;
}
+EXPORT_SYMBOL_GPL(m41t00_set_rtc_time);
+
+/*
+ *****************************************************************************
+ *
+ * platform_data Driver Interface
+ *
+ *****************************************************************************
+ */
+static int __init
+m41t00_platform_probe(struct platform_device *pdev)
+{
+ struct m41t00_platform_data *pdata;
+ int i;
+
+ if (pdev && (pdata = pdev->dev.platform_data)) {
+ normal_addr[0] = pdata->i2c_addr;
+
+ for (i=0; i<ARRAY_SIZE(m41t00_chip_info_tbl); i++)
+ if (m41t00_chip_info_tbl[i].type == pdata->type) {
+ m41t00_chip = &m41t00_chip_info_tbl[i];
+ m41t00_chip->sqw_freq = pdata->sqw_freq;
+ return 0;
+ }
+ }
+ return -ENODEV;
+}
+
+static int __exit
+m41t00_platform_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver m41t00_platform_driver = {
+ .probe = m41t00_platform_probe,
+ .remove = m41t00_platform_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = M41T00_DRV_NAME,
+ },
+};
/*
*****************************************************************************
@@ -176,23 +286,71 @@ m41t00_probe(struct i2c_adapter *adap, int addr, int kind)
struct i2c_client *client;
int rc;
+ if (!i2c_check_functionality(adap, I2C_FUNC_I2C
+ | I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
if (!client)
return -ENOMEM;
- strncpy(client->name, M41T00_DRV_NAME, I2C_NAME_SIZE);
+ strlcpy(client->name, m41t00_chip->name, I2C_NAME_SIZE);
client->addr = addr;
client->adapter = adap;
client->driver = &m41t00_driver;
- if ((rc = i2c_attach_client(client)) != 0) {
- kfree(client);
- return rc;
+ if ((rc = i2c_attach_client(client)))
+ goto attach_err;
+
+ if (m41t00_chip->type != M41T00_TYPE_M41T00) {
+ /* If asked, disable SQW, set SQW frequency & re-enable */
+ if (m41t00_chip->sqw_freq)
+ if (((rc = i2c_smbus_read_byte_data(client,
+ m41t00_chip->alarm_mon)) < 0)
+ || ((rc = i2c_smbus_write_byte_data(client,
+ m41t00_chip->alarm_mon, rc & ~0x40)) <0)
+ || ((rc = i2c_smbus_write_byte_data(client,
+ m41t00_chip->sqw,
+ m41t00_chip->sqw_freq)) < 0)
+ || ((rc = i2c_smbus_write_byte_data(client,
+ m41t00_chip->alarm_mon, rc | 0x40)) <0))
+ goto sqw_err;
+
+ /* Make sure HT (Halt Update) bit is cleared */
+ if ((rc = i2c_smbus_read_byte_data(client,
+ m41t00_chip->alarm_hour)) < 0)
+ goto ht_err;
+
+ if (rc & 0x40)
+ if ((rc = i2c_smbus_write_byte_data(client,
+ m41t00_chip->alarm_hour, rc & ~0x40))<0)
+ goto ht_err;
}
- m41t00_wq = create_singlethread_workqueue("m41t00");
+ /* Make sure ST (stop) bit is cleared */
+ if ((rc = i2c_smbus_read_byte_data(client, m41t00_chip->sec)) < 0)
+ goto st_err;
+
+ if (rc & 0x80)
+ if ((rc = i2c_smbus_write_byte_data(client, m41t00_chip->sec,
+ rc & ~0x80)) < 0)
+ goto st_err;
+
+ m41t00_wq = create_singlethread_workqueue(m41t00_chip->name);
save_client = client;
return 0;
+
+st_err:
+ dev_err(&client->dev, "m41t00_probe: Can't clear ST bit\n");
+ goto attach_err;
+ht_err:
+ dev_err(&client->dev, "m41t00_probe: Can't clear HT bit\n");
+ goto attach_err;
+sqw_err:
+ dev_err(&client->dev, "m41t00_probe: Can't set SQW Frequency\n");
+attach_err:
+ kfree(client);
+ return rc;
}
static int
@@ -204,7 +362,7 @@ m41t00_attach(struct i2c_adapter *adap)
static int
m41t00_detach(struct i2c_client *client)
{
- int rc;
+ int rc;
if ((rc = i2c_detach_client(client)) == 0) {
kfree(client);
@@ -225,14 +383,18 @@ static struct i2c_driver m41t00_driver = {
static int __init
m41t00_init(void)
{
- return i2c_add_driver(&m41t00_driver);
+ int rc;
+
+ if (!(rc = platform_driver_register(&m41t00_platform_driver)))
+ rc = i2c_add_driver(&m41t00_driver);
+ return rc;
}
static void __exit
m41t00_exit(void)
{
i2c_del_driver(&m41t00_driver);
- return;
+ platform_driver_unregister(&m41t00_platform_driver);
}
module_init(m41t00_init);
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 45e2cdf..a45155f 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -916,7 +916,7 @@ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
}
s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command,
- u8 length, u8 *values)
+ u8 length, const u8 *values)
{
union i2c_smbus_data data;
@@ -944,7 +944,7 @@ s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *val
}
s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command,
- u8 length, u8 *values)
+ u8 length, const u8 *values)
{
union i2c_smbus_data data;
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index ed7eed3..58ccddd 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -426,10 +426,7 @@ static int i2cdev_attach_adapter(struct i2c_adapter *adap)
/* register this i2c device with the driver core */
i2c_dev->adap = adap;
- if (adap->dev.parent == &platform_bus)
- dev = &adap->dev;
- else
- dev = adap->dev.parent;
+ dev = &adap->dev;
i2c_dev->class_dev = class_device_create(i2c_dev_class, NULL,
MKDEV(I2C_MAJOR, i2c_dev->minor),
dev, "i2c-%d", i2c_dev->minor);
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index b4a41d6..99fa424 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -395,7 +395,8 @@ static int cdrom_log_sense(ide_drive_t *drive, struct request *rq,
* we cannot reliably check if drive can auto-close
*/
if (rq->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24)
- log = 0;
+ break;
+ log = 1;
break;
case UNIT_ATTENTION:
/*
@@ -417,6 +418,11 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
struct request *failed_command,
struct request_sense *sense)
{
+ unsigned long sector;
+ unsigned long bio_sectors;
+ unsigned long valid;
+ struct cdrom_info *info = drive->driver_data;
+
if (!cdrom_log_sense(drive, failed_command, sense))
return;
@@ -429,6 +435,37 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
if (sense->sense_key == 0x05 && sense->asc == 0x24)
return;
+ if (sense->error_code == 0x70) { /* Current Error */
+ switch(sense->sense_key) {
+ case MEDIUM_ERROR:
+ case VOLUME_OVERFLOW:
+ case ILLEGAL_REQUEST:
+ if (!sense->valid)
+ break;
+ if (failed_command == NULL ||
+ !blk_fs_request(failed_command))
+ break;
+ sector = (sense->information[0] << 24) |
+ (sense->information[1] << 16) |
+ (sense->information[2] << 8) |
+ (sense->information[3]);
+
+ bio_sectors = bio_sectors(failed_command->bio);
+ if (bio_sectors < 4)
+ bio_sectors = 4;
+ if (drive->queue->hardsect_size == 2048)
+ sector <<= 2; /* Device sector size is 2K */
+ sector &= ~(bio_sectors -1);
+ valid = (sector - failed_command->sector) << 9;
+
+ if (valid < 0)
+ valid = 0;
+ if (sector < get_capacity(info->disk) &&
+ drive->probed_capacity - sector < 4 * 75) {
+ set_capacity(info->disk, sector);
+ }
+ }
+ }
#if VERBOSE_IDE_CD_ERRORS
{
int i;
@@ -609,17 +646,23 @@ static void cdrom_end_request (ide_drive_t *drive, int uptodate)
sense = failed->sense;
failed->sense_len = rq->sense_len;
}
-
+ cdrom_analyze_sense_data(drive, failed, sense);
/*
* now end failed request
*/
- spin_lock_irqsave(&ide_lock, flags);
- end_that_request_chunk(failed, 0, failed->data_len);
- end_that_request_last(failed, 0);
- spin_unlock_irqrestore(&ide_lock, flags);
- }
-
- cdrom_analyze_sense_data(drive, failed, sense);
+ if (blk_fs_request(failed)) {
+ if (ide_end_dequeued_request(drive, failed, 0,
+ failed->hard_nr_sectors))
+ BUG();
+ } else {
+ spin_lock_irqsave(&ide_lock, flags);
+ end_that_request_chunk(failed, 0,
+ failed->data_len);
+ end_that_request_last(failed, 0);
+ spin_unlock_irqrestore(&ide_lock, flags);
+ }
+ } else
+ cdrom_analyze_sense_data(drive, NULL, sense);
}
if (!rq->current_nr_sectors && blk_fs_request(rq))
@@ -633,6 +676,13 @@ static void cdrom_end_request (ide_drive_t *drive, int uptodate)
ide_end_request(drive, uptodate, nsectors);
}
+static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 stat)
+{
+ if (stat & 0x80)
+ return;
+ ide_dump_status(drive, msg, stat);
+}
+
/* Returns 0 if the request should be continued.
Returns 1 if the request was ended. */
static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
@@ -761,16 +811,16 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
sense_key == DATA_PROTECT) {
/* No point in retrying after an illegal
request or data protect error.*/
- ide_dump_status (drive, "command error", stat);
+ ide_dump_status_no_sense (drive, "command error", stat);
do_end_request = 1;
} else if (sense_key == MEDIUM_ERROR) {
/* No point in re-trying a zillion times on a bad
* sector... If we got here the error is not correctable */
- ide_dump_status (drive, "media error (bad sector)", stat);
+ ide_dump_status_no_sense (drive, "media error (bad sector)", stat);
do_end_request = 1;
} else if (sense_key == BLANK_CHECK) {
/* Disk appears blank ?? */
- ide_dump_status (drive, "media error (blank)", stat);
+ ide_dump_status_no_sense (drive, "media error (blank)", stat);
do_end_request = 1;
} else if ((err & ~ABRT_ERR) != 0) {
/* Go to the default handler
@@ -782,13 +832,27 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
do_end_request = 1;
}
- if (do_end_request)
- cdrom_end_request(drive, 0);
-
- /* If we got a CHECK_CONDITION status,
- queue a request sense command. */
- if ((stat & ERR_STAT) != 0)
- cdrom_queue_request_sense(drive, NULL, NULL);
+ /* End a request through request sense analysis when we have
+ sense data. We need this in order to perform end of media
+ processing */
+
+ if (do_end_request) {
+ if (stat & ERR_STAT) {
+ unsigned long flags;
+ spin_lock_irqsave(&ide_lock, flags);
+ blkdev_dequeue_request(rq);
+ HWGROUP(drive)->rq = NULL;
+ spin_unlock_irqrestore(&ide_lock, flags);
+
+ cdrom_queue_request_sense(drive, rq->sense, rq);
+ } else
+ cdrom_end_request(drive, 0);
+ } else {
+ /* If we got a CHECK_CONDITION status,
+ queue a request sense command. */
+ if (stat & ERR_STAT)
+ cdrom_queue_request_sense(drive, NULL, NULL);
+ }
} else {
blk_dump_rq_flags(rq, "ide-cd: bad rq");
cdrom_end_request(drive, 0);
@@ -1451,9 +1515,12 @@ static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
} else {
confused:
printk (KERN_ERR "%s: cdrom_pc_intr: The drive "
- "appears confused (ireason = 0x%02x)\n",
+ "appears confused (ireason = 0x%02x). "
+ "Trying to recover by ending request.\n",
drive->name, ireason);
rq->flags |= REQ_FAILED;
+ cdrom_end_request(drive, 0);
+ return ide_stopped;
}
/* Now we wait for another interrupt. */
@@ -1488,8 +1555,7 @@ static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive)
}
-static
-int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
+static int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
{
struct request_sense sense;
int retries = 10;
@@ -1722,8 +1788,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
}
}
- if (HWGROUP(drive)->handler != NULL)
- BUG();
+ BUG_ON(HWGROUP(drive)->handler != NULL);
ide_set_handler(drive, cdrom_newpc_intr, rq->timeout, NULL);
return ide_started;
@@ -2218,6 +2283,9 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
toc->capacity = 0x1fffff;
set_capacity(info->disk, toc->capacity * sectors_per_frame);
+ /* Save a private copy of te TOC capacity for error handling */
+ drive->probed_capacity = toc->capacity * sectors_per_frame;
+
blk_queue_hardsect_size(drive->queue,
sectors_per_frame << SECTOR_BITS);
@@ -2340,6 +2408,7 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
if (!stat && (last_written > toc->capacity)) {
toc->capacity = last_written;
set_capacity(info->disk, toc->capacity * sectors_per_frame);
+ drive->probed_capacity = toc->capacity * sectors_per_frame;
}
/* Remember that we've read this stuff. */
@@ -2696,14 +2765,11 @@ int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr)
* any other way to detect this...
*/
if (sense.sense_key == NOT_READY) {
- if (sense.asc == 0x3a) {
- if (sense.ascq == 1)
- return CDS_NO_DISC;
- else if (sense.ascq == 0 || sense.ascq == 2)
- return CDS_TRAY_OPEN;
- }
+ if (sense.asc == 0x3a && sense.ascq == 1)
+ return CDS_NO_DISC;
+ else
+ return CDS_TRAY_OPEN;
}
-
return CDS_DRIVE_NOT_READY;
}
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index c481be8..783a247 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -206,8 +206,7 @@ int ide_build_sglist(ide_drive_t *drive, struct request *rq)
ide_hwif_t *hwif = HWIF(drive);
struct scatterlist *sg = hwif->sg_table;
- if ((rq->flags & REQ_DRIVE_TASKFILE) && rq->nr_sectors > 256)
- BUG();
+ BUG_ON((rq->flags & REQ_DRIVE_TASKFILE) && rq->nr_sectors > 256);
ide_map_sg(drive, rq);
@@ -947,8 +946,7 @@ void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_p
}
printk("\n");
- if (!(hwif->dma_master))
- BUG();
+ BUG_ON(!hwif->dma_master);
}
EXPORT_SYMBOL_GPL(ide_setup_dma);
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index a53e3ce..4656587 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -898,8 +898,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
"to send us more data than expected "
"- discarding data\n");
idefloppy_discard_data(drive,bcount.all);
- if (HWGROUP(drive)->handler != NULL)
- BUG();
+ BUG_ON(HWGROUP(drive)->handler != NULL);
ide_set_handler(drive,
&idefloppy_pc_intr,
IDEFLOPPY_WAIT_CMD,
@@ -932,8 +931,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
pc->actually_transferred += bcount.all;
pc->current_position += bcount.all;
- if (HWGROUP(drive)->handler != NULL)
- BUG();
+ BUG_ON(HWGROUP(drive)->handler != NULL);
ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); /* And set the interrupt handler again */
return ide_started;
}
@@ -960,8 +958,7 @@ static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
"issuing a packet command\n");
return ide_do_reset(drive);
}
- if (HWGROUP(drive)->handler != NULL)
- BUG();
+ BUG_ON(HWGROUP(drive)->handler != NULL);
/* Set the interrupt routine */
ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);
/* Send the actual packet */
@@ -1017,8 +1014,7 @@ static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
* 40 and 50msec work well. idefloppy_pc_intr will not be actually
* used until after the packet is moved in about 50 msec.
*/
- if (HWGROUP(drive)->handler != NULL)
- BUG();
+ BUG_ON(HWGROUP(drive)->handler != NULL);
ide_set_handler(drive,
&idefloppy_pc_intr, /* service routine for packet command */
floppy->ticks, /* wait this long before "failing" */
@@ -1288,7 +1284,7 @@ static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request
debug_log(KERN_INFO "rq_status: %d, dev: %s, flags: %lx, errors: %d\n",
rq->rq_status,
- rq->rq_disk ? rq->rq_disk->disk_name ? "?",
+ rq->rq_disk ? rq->rq_disk->disk_name : "?",
rq->flags, rq->errors);
debug_log(KERN_INFO "sector: %ld, nr_sectors: %ld, "
"current_nr_sectors: %d\n", (long)rq->sector,
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index c01615d..622a55c 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -142,38 +142,41 @@ enum {
static void ide_complete_power_step(ide_drive_t *drive, struct request *rq, u8 stat, u8 error)
{
+ struct request_pm_state *pm = rq->end_io_data;
+
if (drive->media != ide_disk)
return;
- switch (rq->pm->pm_step) {
+ switch (pm->pm_step) {
case ide_pm_flush_cache: /* Suspend step 1 (flush cache) complete */
- if (rq->pm->pm_state == PM_EVENT_FREEZE)
- rq->pm->pm_step = ide_pm_state_completed;
+ if (pm->pm_state == PM_EVENT_FREEZE)
+ pm->pm_step = ide_pm_state_completed;
else
- rq->pm->pm_step = idedisk_pm_standby;
+ pm->pm_step = idedisk_pm_standby;
break;
case idedisk_pm_standby: /* Suspend step 2 (standby) complete */
- rq->pm->pm_step = ide_pm_state_completed;
+ pm->pm_step = ide_pm_state_completed;
break;
case idedisk_pm_idle: /* Resume step 1 (idle) complete */
- rq->pm->pm_step = ide_pm_restore_dma;
+ pm->pm_step = ide_pm_restore_dma;
break;
}
}
static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
{
+ struct request_pm_state *pm = rq->end_io_data;
ide_task_t *args = rq->special;
memset(args, 0, sizeof(*args));
if (drive->media != ide_disk) {
/* skip idedisk_pm_idle for ATAPI devices */
- if (rq->pm->pm_step == idedisk_pm_idle)
- rq->pm->pm_step = ide_pm_restore_dma;
+ if (pm->pm_step == idedisk_pm_idle)
+ pm->pm_step = ide_pm_restore_dma;
}
- switch (rq->pm->pm_step) {
+ switch (pm->pm_step) {
case ide_pm_flush_cache: /* Suspend step 1 (flush cache) */
if (drive->media != ide_disk)
break;
@@ -215,11 +218,68 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
drive->hwif->ide_dma_check(drive);
break;
}
- rq->pm->pm_step = ide_pm_state_completed;
+ pm->pm_step = ide_pm_state_completed;
return ide_stopped;
}
/**
+ * ide_end_dequeued_request - complete an IDE I/O
+ * @drive: IDE device for the I/O
+ * @uptodate:
+ * @nr_sectors: number of sectors completed
+ *
+ * Complete an I/O that is no longer on the request queue. This
+ * typically occurs when we pull the request and issue a REQUEST_SENSE.
+ * We must still finish the old request but we must not tamper with the
+ * queue in the meantime.
+ *
+ * NOTE: This path does not handle barrier, but barrier is not supported
+ * on ide-cd anyway.
+ */
+
+int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq,
+ int uptodate, int nr_sectors)
+{
+ unsigned long flags;
+ int ret = 1;
+
+ spin_lock_irqsave(&ide_lock, flags);
+
+ BUG_ON(!(rq->flags & REQ_STARTED));
+
+ /*
+ * if failfast is set on a request, override number of sectors and
+ * complete the whole request right now
+ */
+ if (blk_noretry_request(rq) && end_io_error(uptodate))
+ nr_sectors = rq->hard_nr_sectors;
+
+ if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors)
+ rq->errors = -EIO;
+
+ /*
+ * decide whether to reenable DMA -- 3 is a random magic for now,
+ * if we DMA timeout more than 3 times, just stay in PIO
+ */
+ if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+ drive->state = 0;
+ HWGROUP(drive)->hwif->ide_dma_on(drive);
+ }
+
+ if (!end_that_request_first(rq, uptodate, nr_sectors)) {
+ add_disk_randomness(rq->rq_disk);
+ if (blk_rq_tagged(rq))
+ blk_queue_end_tag(drive->queue, rq);
+ end_that_request_last(rq, uptodate);
+ ret = 0;
+ }
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ide_end_dequeued_request);
+
+
+/**
* ide_complete_pm_request - end the current Power Management request
* @drive: target drive
* @rq: request
@@ -362,12 +422,13 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
}
}
} else if (blk_pm_request(rq)) {
+ struct request_pm_state *pm = rq->end_io_data;
#ifdef DEBUG_PM
printk("%s: complete_power_step(step: %d, stat: %x, err: %x)\n",
drive->name, rq->pm->pm_step, stat, err);
#endif
ide_complete_power_step(drive, rq, stat, err);
- if (rq->pm->pm_step == ide_pm_state_completed)
+ if (pm->pm_step == ide_pm_state_completed)
ide_complete_pm_request(drive, rq);
return;
}
@@ -871,6 +932,39 @@ done:
return ide_stopped;
}
+static void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
+{
+ struct request_pm_state *pm = rq->end_io_data;
+
+ if (blk_pm_suspend_request(rq) &&
+ pm->pm_step == ide_pm_state_start_suspend)
+ /* Mark drive blocked when starting the suspend sequence. */
+ drive->blocked = 1;
+ else if (blk_pm_resume_request(rq) &&
+ pm->pm_step == ide_pm_state_start_resume) {
+ /*
+ * The first thing we do on wakeup is to wait for BSY bit to
+ * go away (with a looong timeout) as a drive on this hwif may
+ * just be POSTing itself.
+ * We do that before even selecting as the "other" device on
+ * the bus may be broken enough to walk on our toes at this
+ * point.
+ */
+ int rc;
+#ifdef DEBUG_PM
+ printk("%s: Wakeup request inited, waiting for !BSY...\n", drive->name);
+#endif
+ rc = ide_wait_not_busy(HWIF(drive), 35000);
+ if (rc)
+ printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name);
+ SELECT_DRIVE(drive);
+ HWIF(drive)->OUTB(8, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]);
+ rc = ide_wait_not_busy(HWIF(drive), 10000);
+ if (rc)
+ printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name);
+ }
+}
+
/**
* start_request - start of I/O and command issuing for IDE
*
@@ -909,33 +1003,8 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
if (block == 0 && drive->remap_0_to_1 == 1)
block = 1; /* redirect MBR access to EZ-Drive partn table */
- if (blk_pm_suspend_request(rq) &&
- rq->pm->pm_step == ide_pm_state_start_suspend)
- /* Mark drive blocked when starting the suspend sequence. */
- drive->blocked = 1;
- else if (blk_pm_resume_request(rq) &&
- rq->pm->pm_step == ide_pm_state_start_resume) {
- /*
- * The first thing we do on wakeup is to wait for BSY bit to
- * go away (with a looong timeout) as a drive on this hwif may
- * just be POSTing itself.
- * We do that before even selecting as the "other" device on
- * the bus may be broken enough to walk on our toes at this
- * point.
- */
- int rc;
-#ifdef DEBUG_PM
- printk("%s: Wakeup request inited, waiting for !BSY...\n", drive->name);
-#endif
- rc = ide_wait_not_busy(HWIF(drive), 35000);
- if (rc)
- printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name);
- SELECT_DRIVE(drive);
- HWIF(drive)->OUTB(8, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]);
- rc = ide_wait_not_busy(HWIF(drive), 10000);
- if (rc)
- printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name);
- }
+ if (blk_pm_request(rq))
+ ide_check_pm_state(drive, rq);
SELECT_DRIVE(drive);
if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
@@ -950,13 +1019,14 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
else if (rq->flags & REQ_DRIVE_TASKFILE)
return execute_drive_cmd(drive, rq);
else if (blk_pm_request(rq)) {
+ struct request_pm_state *pm = rq->end_io_data;
#ifdef DEBUG_PM
printk("%s: start_power_step(step: %d)\n",
drive->name, rq->pm->pm_step);
#endif
startstop = ide_start_power_step(drive, rq);
if (startstop == ide_stopped &&
- rq->pm->pm_step == ide_pm_state_completed)
+ pm->pm_step == ide_pm_state_completed)
ide_complete_pm_request(drive, rq);
return startstop;
}
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index b72dde7..97a49e7 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -939,8 +939,7 @@ void ide_execute_command(ide_drive_t *drive, task_ioreg_t cmd, ide_handler_t *ha
spin_lock_irqsave(&ide_lock, flags);
- if(hwgroup->handler)
- BUG();
+ BUG_ON(hwgroup->handler);
hwgroup->handler = handler;
hwgroup->expiry = expiry;
hwgroup->timer.expires = jiffies + timeout;
@@ -981,8 +980,7 @@ static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
printk("%s: ATAPI reset complete\n", drive->name);
} else {
if (time_before(jiffies, hwgroup->poll_timeout)) {
- if (HWGROUP(drive)->handler != NULL)
- BUG();
+ BUG_ON(HWGROUP(drive)->handler != NULL);
ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
/* continue polling */
return ide_started;
@@ -1021,8 +1019,7 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
if (!OK_STAT(tmp = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) {
if (time_before(jiffies, hwgroup->poll_timeout)) {
- if (HWGROUP(drive)->handler != NULL)
- BUG();
+ BUG_ON(HWGROUP(drive)->handler != NULL);
ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
/* continue polling */
return ide_started;
@@ -1138,8 +1135,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
hwgroup = HWGROUP(drive);
/* We must not reset with running handlers */
- if(hwgroup->handler != NULL)
- BUG();
+ BUG_ON(hwgroup->handler != NULL);
/* For an ATAPI device, first try an ATAPI SRST. */
if (drive->media != ide_disk && !do_not_try_atapi) {
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
index 41d46db..16a1431 100644
--- a/drivers/ide/ide-lib.c
+++ b/drivers/ide/ide-lib.c
@@ -164,8 +164,7 @@ u8 ide_rate_filter (u8 mode, u8 speed)
// printk("%s: mode 0x%02x, speed 0x%02x\n", __FUNCTION__, mode, speed);
/* So that we remember to update this if new modes appear */
- if (mode > 4)
- BUG();
+ BUG_ON(mode > 4);
return min(speed, speed_max[mode]);
#else /* !CONFIG_BLK_DEV_IDEDMA */
return min(speed, (u8)XFER_PIO_4);
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index f04791a..09f3a7d 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -2646,21 +2646,23 @@ static idetape_stage_t *idetape_kmalloc_stage (idetape_tape_t *tape)
return __idetape_kmalloc_stage(tape, 0, 0);
}
-static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char __user *buf, int n)
+static int idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char __user *buf, int n)
{
struct idetape_bh *bh = tape->bh;
int count;
+ int ret = 0;
while (n) {
#if IDETAPE_DEBUG_BUGS
if (bh == NULL) {
printk(KERN_ERR "ide-tape: bh == NULL in "
"idetape_copy_stage_from_user\n");
- return;
+ return 1;
}
#endif /* IDETAPE_DEBUG_BUGS */
count = min((unsigned int)(bh->b_size - atomic_read(&bh->b_count)), (unsigned int)n);
- copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count);
+ if (copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count))
+ ret = 1;
n -= count;
atomic_add(count, &bh->b_count);
buf += count;
@@ -2671,23 +2673,26 @@ static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t
}
}
tape->bh = bh;
+ return ret;
}
-static void idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, idetape_stage_t *stage, int n)
+static int idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, idetape_stage_t *stage, int n)
{
struct idetape_bh *bh = tape->bh;
int count;
+ int ret = 0;
while (n) {
#if IDETAPE_DEBUG_BUGS
if (bh == NULL) {
printk(KERN_ERR "ide-tape: bh == NULL in "
"idetape_copy_stage_to_user\n");
- return;
+ return 1;
}
#endif /* IDETAPE_DEBUG_BUGS */
count = min(tape->b_count, n);
- copy_to_user(buf, tape->b_data, count);
+ if (copy_to_user(buf, tape->b_data, count))
+ ret = 1;
n -= count;
tape->b_data += count;
tape->b_count -= count;
@@ -2700,6 +2705,7 @@ static void idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf,
}
}
}
+ return ret;
}
static void idetape_init_merge_stage (idetape_tape_t *tape)
@@ -3719,6 +3725,7 @@ static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
struct ide_tape_obj *tape = ide_tape_f(file);
ide_drive_t *drive = tape->drive;
ssize_t bytes_read,temp, actually_read = 0, rc;
+ ssize_t ret = 0;
#if IDETAPE_DEBUG_LOG
if (tape->debug_level >= 3)
@@ -3737,7 +3744,8 @@ static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
return (0);
if (tape->merge_stage_size) {
actually_read = min((unsigned int)(tape->merge_stage_size), (unsigned int)count);
- idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read);
+ if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read))
+ ret = -EFAULT;
buf += actually_read;
tape->merge_stage_size -= actually_read;
count -= actually_read;
@@ -3746,7 +3754,8 @@ static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
bytes_read = idetape_add_chrdev_read_request(drive, tape->capabilities.ctl);
if (bytes_read <= 0)
goto finish;
- idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read);
+ if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read))
+ ret = -EFAULT;
buf += bytes_read;
count -= bytes_read;
actually_read += bytes_read;
@@ -3756,7 +3765,8 @@ static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
if (bytes_read <= 0)
goto finish;
temp = min((unsigned long)count, (unsigned long)bytes_read);
- idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp);
+ if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp))
+ ret = -EFAULT;
actually_read += temp;
tape->merge_stage_size = bytes_read-temp;
}
@@ -3769,7 +3779,8 @@ finish:
idetape_space_over_filemarks(drive, MTFSF, 1);
return 0;
}
- return actually_read;
+
+ return (ret) ? ret : actually_read;
}
static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
@@ -3777,7 +3788,8 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
{
struct ide_tape_obj *tape = ide_tape_f(file);
ide_drive_t *drive = tape->drive;
- ssize_t retval, actually_written = 0;
+ ssize_t actually_written = 0;
+ ssize_t ret = 0;
/* The drive is write protected. */
if (tape->write_prot)
@@ -3813,7 +3825,7 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
* some drives (Seagate STT3401A) will return an error.
*/
if (drive->dsc_overlap) {
- retval = idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 0, tape->merge_stage->bh);
+ ssize_t retval = idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 0, tape->merge_stage->bh);
if (retval < 0) {
__idetape_kfree_stage(tape->merge_stage);
tape->merge_stage = NULL;
@@ -3834,12 +3846,14 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
}
#endif /* IDETAPE_DEBUG_BUGS */
actually_written = min((unsigned int)(tape->stage_size - tape->merge_stage_size), (unsigned int)count);
- idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written);
+ if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written))
+ ret = -EFAULT;
buf += actually_written;
tape->merge_stage_size += actually_written;
count -= actually_written;
if (tape->merge_stage_size == tape->stage_size) {
+ ssize_t retval;
tape->merge_stage_size = 0;
retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
if (retval <= 0)
@@ -3847,7 +3861,9 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
}
}
while (count >= tape->stage_size) {
- idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size);
+ ssize_t retval;
+ if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size))
+ ret = -EFAULT;
buf += tape->stage_size;
count -= tape->stage_size;
retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
@@ -3857,10 +3873,11 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
}
if (count) {
actually_written += count;
- idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count);
+ if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count))
+ ret = -EFAULT;
tape->merge_stage_size += count;
}
- return (actually_written);
+ return (ret) ? ret : actually_written;
}
static int idetape_write_filemark (ide_drive_t *drive)
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 9233b81..a839b2a 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -196,8 +196,7 @@ ide_startstop_t set_geometry_intr (ide_drive_t *drive)
if (stat & (ERR_STAT|DRQ_STAT))
return ide_error(drive, "set_geometry_intr", stat);
- if (HWGROUP(drive)->handler != NULL)
- BUG();
+ BUG_ON(HWGROUP(drive)->handler != NULL);
ide_set_handler(drive, &set_geometry_intr, WAIT_WORSTCASE, NULL);
return ide_started;
}
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 3fdab56..59fe358 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -726,6 +726,7 @@ void ide_setup_ports ( hw_regs_t *hw,
{
int i;
+ memset(hw, 0, sizeof(hw_regs_t));
for (i = 0; i < IDE_NR_PORTS; i++) {
if (offsets[i] == -1) {
switch(i) {
@@ -1225,7 +1226,7 @@ static int generic_ide_suspend(struct device *dev, pm_message_t state)
memset(&args, 0, sizeof(args));
rq.flags = REQ_PM_SUSPEND;
rq.special = &args;
- rq.pm = &rqpm;
+ rq.end_io_data = &rqpm;
rqpm.pm_step = ide_pm_state_start_suspend;
rqpm.pm_state = state.event;
@@ -1244,7 +1245,7 @@ static int generic_ide_resume(struct device *dev)
memset(&args, 0, sizeof(args));
rq.flags = REQ_PM_RESUME;
rq.special = &args;
- rq.pm = &rqpm;
+ rq.end_io_data = &rqpm;
rqpm.pm_step = ide_pm_state_start_resume;
rqpm.pm_state = PM_EVENT_ON;
@@ -1366,8 +1367,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
ide_abort(drive, "drive reset");
- if(HWGROUP(drive)->handler)
- BUG();
+ BUG_ON(HWGROUP(drive)->handler);
/* Ensure nothing gets queued after we
drop the lock. Reset will clear the busy */
diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c
index 2a78b79..434a94f 100644
--- a/drivers/ide/legacy/q40ide.c
+++ b/drivers/ide/legacy/q40ide.c
@@ -80,6 +80,7 @@ void q40_ide_setup_ports ( hw_regs_t *hw,
{
int i;
+ memset(hw, 0, sizeof(hw_regs_t));
for (i = 0; i < IDE_NR_PORTS; i++) {
/* BIG FAT WARNING:
assumption: only DATA port is ever used in 16 bit mode */
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
index b22ee54..6e9dbf4 100644
--- a/drivers/ide/pci/amd74xx.c
+++ b/drivers/ide/pci/amd74xx.c
@@ -74,6 +74,7 @@ static struct amd_ide_chip {
{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, 0x50, AMD_UDMA_133 },
+ { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_AMD_CS5536_IDE, 0x40, AMD_UDMA_100 },
{ 0 }
};
@@ -488,7 +489,8 @@ static ide_pci_device_t amd74xx_chipsets[] __devinitdata = {
/* 14 */ DECLARE_NV_DEV("NFORCE-MCP04"),
/* 15 */ DECLARE_NV_DEV("NFORCE-MCP51"),
/* 16 */ DECLARE_NV_DEV("NFORCE-MCP55"),
- /* 17 */ DECLARE_AMD_DEV("AMD5536"),
+ /* 17 */ DECLARE_NV_DEV("NFORCE-MCP61"),
+ /* 18 */ DECLARE_AMD_DEV("AMD5536"),
};
static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
@@ -525,7 +527,8 @@ static struct pci_device_id amd74xx_pci_tbl[] = {
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 },
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17 },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
index 27c9eb9..e125032 100644
--- a/drivers/ide/pci/sgiioc4.c
+++ b/drivers/ide/pci/sgiioc4.c
@@ -723,6 +723,12 @@ static ide_pci_device_t sgiioc4_chipsets[] __devinitdata = {
int
ioc4_ide_attach_one(struct ioc4_driver_data *idd)
{
+ /* PCI-RT does not bring out IDE connection.
+ * Do not attach to this particular IOC4.
+ */
+ if (idd->idd_variant == IOC4_VARIANT_PCI_RT)
+ return 0;
+
return pci_init_sgiioc4(idd->idd_pdev,
&sgiioc4_chipsets[idd->idd_pci_id->driver_data]);
}
diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c
index c26c8ca..fe80295 100644
--- a/drivers/ide/pci/trm290.c
+++ b/drivers/ide/pci/trm290.c
@@ -183,8 +183,7 @@ static void trm290_ide_dma_exec_cmd(ide_drive_t *drive, u8 command)
{
ide_hwif_t *hwif = HWIF(drive);
- if (HWGROUP(drive)->handler != NULL) /* paranoia check */
- BUG();
+ BUG_ON(HWGROUP(drive)->handler != NULL); /* paranoia check */
ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
/* issue cmd to drive */
hwif->OUTB(command, IDE_COMMAND_REG);
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 948f1b8..50c71e1 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -8,6 +8,7 @@
* directory of the kernel sources for details.
*/
+#include <linux/bitmap.h>
#include <linux/kernel.h>
#include <linux/config.h>
#include <linux/list.h>
@@ -334,10 +335,12 @@ static ssize_t fw_show_ne_bus_options(struct device *dev, struct device_attribut
static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL);
+/* tlabels_free, tlabels_allocations, tlabels_mask are read non-atomically
+ * here, therefore displayed values may be occasionally wrong. */
static ssize_t fw_show_ne_tlabels_free(struct device *dev, struct device_attribute *attr, char *buf)
{
struct node_entry *ne = container_of(dev, struct node_entry, device);
- return sprintf(buf, "%d\n", atomic_read(&ne->tpool->count.count) + 1);
+ return sprintf(buf, "%d\n", 64 - bitmap_weight(ne->tpool->pool, 64));
}
static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL);
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index dc1f4de..e725ccc 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -815,11 +815,12 @@ static void ib_uverbs_remove_one(struct ib_device *device)
kref_put(&uverbs_dev->ref, ib_uverbs_release_dev);
}
-static struct super_block *uverbs_event_get_sb(struct file_system_type *fs_type, int flags,
- const char *dev_name, void *data)
+static int uverbs_event_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data,
+ struct vfsmount *mnt)
{
return get_sb_pseudo(fs_type, "infinibandevent:", NULL,
- INFINIBANDEVENTFS_MAGIC);
+ INFINIBANDEVENTFS_MAGIC, mnt);
}
static struct file_system_type uverbs_event_fs = {
diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
index e274120..63de304 100644
--- a/drivers/infiniband/hw/ipath/ipath_fs.c
+++ b/drivers/infiniband/hw/ipath/ipath_fs.c
@@ -542,13 +542,14 @@ bail:
return ret;
}
-static struct super_block *ipathfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data)
+static int ipathfs_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data, struct vfsmount *mnt)
{
- ipath_super = get_sb_single(fs_type, flags, data,
- ipathfs_fill_super);
- return ipath_super;
+ int ret = get_sb_single(fs_type, flags, data,
+ ipathfs_fill_super, mnt);
+ if (ret >= 0)
+ ipath_super = mnt->mnt_sb;
+ return ret;
}
static void ipathfs_kill_super(struct super_block *s)
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index ba325f1..5f561fc 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -82,7 +82,7 @@ static int evdev_fasync(int fd, struct file *file, int on)
return retval < 0 ? retval : 0;
}
-static int evdev_flush(struct file * file)
+static int evdev_flush(struct file * file, fl_owner_t id)
{
struct evdev_list *list = file->private_data;
if (!list->evdev->exist) return -ENODEV;
diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c
index 4c8fb1f..f1f9db9 100644
--- a/drivers/input/keyboard/amikbd.c
+++ b/drivers/input/keyboard/amikbd.c
@@ -36,6 +36,7 @@
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/keyboard.h>
#include <asm/amigaints.h>
#include <asm/amigahw.h>
@@ -45,7 +46,7 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Amiga keyboard driver");
MODULE_LICENSE("GPL");
-static unsigned char amikbd_keycode[0x78] = {
+static unsigned char amikbd_keycode[0x78] __initdata = {
[0] = KEY_GRAVE,
[1] = KEY_1,
[2] = KEY_2,
@@ -170,12 +171,9 @@ static irqreturn_t amikbd_interrupt(int irq, void *dummy, struct pt_regs *fp)
scancode >>= 1;
if (scancode < 0x78) { /* scancodes < 0x78 are keys */
-
- scancode = amikbd_keycode[scancode];
-
input_regs(amikbd_dev, fp);
- if (scancode == KEY_CAPSLOCK) { /* CapsLock is a toggle switch key on Amiga */
+ if (scancode == 98) { /* CapsLock is a toggle switch key on Amiga */
input_report_key(amikbd_dev, scancode, 1);
input_report_key(amikbd_dev, scancode, 0);
} else {
@@ -191,7 +189,7 @@ static irqreturn_t amikbd_interrupt(int irq, void *dummy, struct pt_regs *fp)
static int __init amikbd_init(void)
{
- int i;
+ int i, j;
if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
return -EIO;
@@ -214,14 +212,26 @@ static int __init amikbd_init(void)
amikbd_dev->id.version = 0x0100;
amikbd_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
- amikbd_dev->keycode = amikbd_keycode;
- amikbd_dev->keycodesize = sizeof(unsigned char);
- amikbd_dev->keycodemax = ARRAY_SIZE(amikbd_keycode);
for (i = 0; i < 0x78; i++)
- if (amikbd_keycode[i])
- set_bit(amikbd_keycode[i], amikbd_dev->keybit);
-
+ set_bit(i, amikbd_dev->keybit);
+
+ for (i = 0; i < MAX_NR_KEYMAPS; i++) {
+ static u_short temp_map[NR_KEYS] __initdata;
+ if (!key_maps[i])
+ continue;
+ memset(temp_map, 0, sizeof(temp_map));
+ for (j = 0; j < 0x78; j++) {
+ if (!amikbd_keycode[j])
+ continue;
+ temp_map[j] = key_maps[i][amikbd_keycode[j]];
+ }
+ for (j = 0; j < NR_KEYS; j++) {
+ if (!temp_map[j])
+ temp_map[j] = 0xf200;
+ }
+ memcpy(key_maps[i], temp_map, sizeof(temp_map));
+ }
ciaa.cra &= ~0x41; /* serial data in, turn off TA */
request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd", amikbd_interrupt);
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 4bad588..a6dfc74 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -26,7 +26,7 @@ config INPUT_PCSPKR
config INPUT_SPARCSPKR
tristate "SPARC Speaker support"
- depends on PCI && SPARC
+ depends on PCI && SPARC64
help
Say Y here if you want the standard Speaker on Sparc PCI systems
to be used for bells and whistles.
diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c
index f0fd2c4..42c11fb 100644
--- a/drivers/input/misc/sparcspkr.c
+++ b/drivers/input/misc/sparcspkr.c
@@ -2,7 +2,7 @@
* Driver for PC-speaker like devices found on various Sparc systems.
*
* Copyright (c) 2002 Vojtech Pavlik
- * Copyright (c) 2002 David S. Miller (davem@redhat.com)
+ * Copyright (c) 2002, 2006 David S. Miller (davem@davemloft.net)
*/
#include <linux/config.h>
#include <linux/kernel.h>
@@ -13,21 +13,23 @@
#include <asm/io.h>
#include <asm/ebus.h>
-#ifdef CONFIG_SPARC64
#include <asm/isa.h>
-#endif
-MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
MODULE_DESCRIPTION("Sparc Speaker beeper driver");
MODULE_LICENSE("GPL");
-const char *beep_name;
-static unsigned long beep_iobase;
-static int (*beep_event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
-static DEFINE_SPINLOCK(beep_lock);
+struct sparcspkr_state {
+ const char *name;
+ unsigned long iobase;
+ int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
+ spinlock_t lock;
+ struct input_dev *input_dev;
+};
static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
+ struct sparcspkr_state *state = dev_get_drvdata(dev->cdev.dev);
unsigned int count = 0;
unsigned long flags;
@@ -43,24 +45,24 @@ static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned in
if (value > 20 && value < 32767)
count = 1193182 / value;
- spin_lock_irqsave(&beep_lock, flags);
+ spin_lock_irqsave(&state->lock, flags);
/* EBUS speaker only has on/off state, the frequency does not
* appear to be programmable.
*/
- if (beep_iobase & 0x2UL)
- outb(!!count, beep_iobase);
+ if (state->iobase & 0x2UL)
+ outb(!!count, state->iobase);
else
- outl(!!count, beep_iobase);
+ outl(!!count, state->iobase);
- spin_unlock_irqrestore(&beep_lock, flags);
+ spin_unlock_irqrestore(&state->lock, flags);
return 0;
}
-#ifdef CONFIG_SPARC64
static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
+ struct sparcspkr_state *state = dev_get_drvdata(dev->cdev.dev);
unsigned int count = 0;
unsigned long flags;
@@ -76,29 +78,29 @@ static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int
if (value > 20 && value < 32767)
count = 1193182 / value;
- spin_lock_irqsave(&beep_lock, flags);
+ spin_lock_irqsave(&state->lock, flags);
if (count) {
/* enable counter 2 */
- outb(inb(beep_iobase + 0x61) | 3, beep_iobase + 0x61);
+ outb(inb(state->iobase + 0x61) | 3, state->iobase + 0x61);
/* set command for counter 2, 2 byte write */
- outb(0xB6, beep_iobase + 0x43);
+ outb(0xB6, state->iobase + 0x43);
/* select desired HZ */
- outb(count & 0xff, beep_iobase + 0x42);
- outb((count >> 8) & 0xff, beep_iobase + 0x42);
+ outb(count & 0xff, state->iobase + 0x42);
+ outb((count >> 8) & 0xff, state->iobase + 0x42);
} else {
/* disable counter 2 */
- outb(inb_p(beep_iobase + 0x61) & 0xFC, beep_iobase + 0x61);
+ outb(inb_p(state->iobase + 0x61) & 0xFC, state->iobase + 0x61);
}
- spin_unlock_irqrestore(&beep_lock, flags);
+ spin_unlock_irqrestore(&state->lock, flags);
return 0;
}
-#endif
-static int __devinit sparcspkr_probe(struct platform_device *dev)
+static int __devinit sparcspkr_probe(struct device *dev)
{
+ struct sparcspkr_state *state = dev_get_drvdata(dev);
struct input_dev *input_dev;
int error;
@@ -106,18 +108,18 @@ static int __devinit sparcspkr_probe(struct platform_device *dev)
if (!input_dev)
return -ENOMEM;
- input_dev->name = beep_name;
+ input_dev->name = state->name;
input_dev->phys = "sparc/input0";
input_dev->id.bustype = BUS_ISA;
input_dev->id.vendor = 0x001f;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &dev->dev;
+ input_dev->cdev.dev = dev;
input_dev->evbit[0] = BIT(EV_SND);
input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
- input_dev->event = beep_event;
+ input_dev->event = state->event;
error = input_register_device(input_dev);
if (error) {
@@ -125,111 +127,137 @@ static int __devinit sparcspkr_probe(struct platform_device *dev)
return error;
}
- platform_set_drvdata(dev, input_dev);
+ state->input_dev = input_dev;
return 0;
}
-static int __devexit sparcspkr_remove(struct platform_device *dev)
+static int __devexit sparcspkr_remove(struct of_device *dev)
{
- struct input_dev *input_dev = platform_get_drvdata(dev);
+ struct sparcspkr_state *state = dev_get_drvdata(&dev->dev);
+ struct input_dev *input_dev = state->input_dev;
- input_unregister_device(input_dev);
- platform_set_drvdata(dev, NULL);
/* turn off the speaker */
- beep_event(NULL, EV_SND, SND_BELL, 0);
+ state->event(input_dev, EV_SND, SND_BELL, 0);
+
+ input_unregister_device(input_dev);
+
+ dev_set_drvdata(&dev->dev, NULL);
+ kfree(state);
return 0;
}
-static void sparcspkr_shutdown(struct platform_device *dev)
+static int sparcspkr_shutdown(struct of_device *dev)
{
+ struct sparcspkr_state *state = dev_get_drvdata(&dev->dev);
+ struct input_dev *input_dev = state->input_dev;
+
/* turn off the speaker */
- beep_event(NULL, EV_SND, SND_BELL, 0);
+ state->event(input_dev, EV_SND, SND_BELL, 0);
+
+ return 0;
+}
+
+static int __devinit ebus_beep_probe(struct of_device *dev, const struct of_device_id *match)
+{
+ struct linux_ebus_device *edev = to_ebus_device(&dev->dev);
+ struct sparcspkr_state *state;
+ int err;
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+
+ state->name = "Sparc EBUS Speaker";
+ state->iobase = edev->resource[0].start;
+ state->event = ebus_spkr_event;
+ spin_lock_init(&state->lock);
+
+ dev_set_drvdata(&dev->dev, state);
+
+ err = sparcspkr_probe(&dev->dev);
+ if (err) {
+ dev_set_drvdata(&dev->dev, NULL);
+ kfree(state);
+ }
+
+ return 0;
}
-static struct platform_driver sparcspkr_platform_driver = {
- .driver = {
- .name = "sparcspkr",
- .owner = THIS_MODULE,
+static struct of_device_id ebus_beep_match[] = {
+ {
+ .name = "beep",
},
- .probe = sparcspkr_probe,
- .remove = __devexit_p(sparcspkr_remove),
- .shutdown = sparcspkr_shutdown,
+ {},
};
-static struct platform_device *sparcspkr_platform_device;
+static struct of_platform_driver ebus_beep_driver = {
+ .name = "beep",
+ .match_table = ebus_beep_match,
+ .probe = ebus_beep_probe,
+ .remove = sparcspkr_remove,
+ .shutdown = sparcspkr_shutdown,
+};
-static int __init sparcspkr_drv_init(void)
+static int __devinit isa_beep_probe(struct of_device *dev, const struct of_device_id *match)
{
- int error;
+ struct sparc_isa_device *idev = to_isa_device(&dev->dev);
+ struct sparcspkr_state *state;
+ int err;
- error = platform_driver_register(&sparcspkr_platform_driver);
- if (error)
- return error;
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
- sparcspkr_platform_device = platform_device_alloc("sparcspkr", -1);
- if (!sparcspkr_platform_device) {
- error = -ENOMEM;
- goto err_unregister_driver;
- }
+ state->name = "Sparc ISA Speaker";
+ state->iobase = idev->resource.start;
+ state->event = isa_spkr_event;
+ spin_lock_init(&state->lock);
+
+ dev_set_drvdata(&dev->dev, state);
- error = platform_device_add(sparcspkr_platform_device);
- if (error)
- goto err_free_device;
+ err = sparcspkr_probe(&dev->dev);
+ if (err) {
+ dev_set_drvdata(&dev->dev, NULL);
+ kfree(state);
+ }
return 0;
+}
- err_free_device:
- platform_device_put(sparcspkr_platform_device);
- err_unregister_driver:
- platform_driver_unregister(&sparcspkr_platform_driver);
+static struct of_device_id isa_beep_match[] = {
+ {
+ .name = "dma",
+ },
+ {},
+};
- return error;
-}
+static struct of_platform_driver isa_beep_driver = {
+ .name = "beep",
+ .match_table = isa_beep_match,
+ .probe = isa_beep_probe,
+ .remove = sparcspkr_remove,
+ .shutdown = sparcspkr_shutdown,
+};
static int __init sparcspkr_init(void)
{
- struct linux_ebus *ebus;
- struct linux_ebus_device *edev;
-#ifdef CONFIG_SPARC64
- struct sparc_isa_bridge *isa_br;
- struct sparc_isa_device *isa_dev;
-#endif
-
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "beep")) {
- beep_name = "Sparc EBUS Speaker";
- beep_event = ebus_spkr_event;
- beep_iobase = edev->resource[0].start;
- return sparcspkr_drv_init();
- }
- }
- }
-#ifdef CONFIG_SPARC64
- for_each_isa(isa_br) {
- for_each_isadev(isa_dev, isa_br) {
- /* A hack, the beep device's base lives in
- * the DMA isa node.
- */
- if (!strcmp(isa_dev->prom_name, "dma")) {
- beep_name = "Sparc ISA Speaker";
- beep_event = isa_spkr_event,
- beep_iobase = isa_dev->resource.start;
- return sparcspkr_drv_init();
- }
- }
+ int err = of_register_driver(&ebus_beep_driver, &ebus_bus_type);
+
+ if (!err) {
+ err = of_register_driver(&isa_beep_driver, &isa_bus_type);
+ if (err)
+ of_unregister_driver(&ebus_beep_driver);
}
-#endif
- return -ENODEV;
+ return err;
}
static void __exit sparcspkr_exit(void)
{
- platform_device_unregister(sparcspkr_platform_device);
- platform_driver_unregister(&sparcspkr_platform_driver);
+ of_unregister_driver(&ebus_beep_driver);
+ of_unregister_driver(&isa_beep_driver);
}
module_init(sparcspkr_init);
diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h
index ed9446f..6d66351 100644
--- a/drivers/input/serio/i8042-sparcio.h
+++ b/drivers/input/serio/i8042-sparcio.h
@@ -74,7 +74,7 @@ static int __init i8042_platform_init(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "8042"))
+ if (!strcmp(edev->prom_node->name, "8042"))
goto edev_found;
}
}
@@ -82,14 +82,14 @@ static int __init i8042_platform_init(void)
edev_found:
for_each_edevchild(edev, child) {
- if (!strcmp(child->prom_name, OBP_PS2KBD_NAME1) ||
- !strcmp(child->prom_name, OBP_PS2KBD_NAME2)) {
+ if (!strcmp(child->prom_node->name, OBP_PS2KBD_NAME1) ||
+ !strcmp(child->prom_node->name, OBP_PS2KBD_NAME2)) {
i8042_kbd_irq = child->irqs[0];
kbd_iobase =
ioremap(child->resource[0].start, 8);
}
- if (!strcmp(child->prom_name, OBP_PS2MS_NAME1) ||
- !strcmp(child->prom_name, OBP_PS2MS_NAME2))
+ if (!strcmp(child->prom_node->name, OBP_PS2MS_NAME1) ||
+ !strcmp(child->prom_node->name, OBP_PS2MS_NAME2))
i8042_aux_irq = child->irqs[0];
}
if (i8042_kbd_irq == -1 ||
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 161afdd..386023c 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -773,8 +773,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ts->last_msg = m;
- if (request_irq(spi->irq, ads7846_irq,
- SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING,
+ if (request_irq(spi->irq, ads7846_irq, SA_TRIGGER_FALLING,
spi->dev.driver->name, ts)) {
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
err = -EBUSY;
diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
index a18d56b..a595d386 100644
--- a/drivers/input/touchscreen/h3600_ts_input.c
+++ b/drivers/input/touchscreen/h3600_ts_input.c
@@ -399,16 +399,14 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
- SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
- "h3600_action", &ts->dev)) {
+ SA_SHIRQ | SA_INTERRUPT, "h3600_action", &ts->dev)) {
printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
err = -EBUSY;
goto fail2;
}
if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
- SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
- "h3600_suspend", &ts->dev)) {
+ SA_SHIRQ | SA_INTERRUPT, "h3600_suspend", &ts->dev)) {
printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n");
err = -EBUSY;
goto fail3;
diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c
index 0a37ade..9ea6bd0 100644
--- a/drivers/isdn/capi/capifs.c
+++ b/drivers/isdn/capi/capifs.c
@@ -121,10 +121,10 @@ fail:
return -ENOMEM;
}
-static struct super_block *capifs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int capifs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, capifs_fill_super);
+ return get_sb_single(fs_type, flags, data, capifs_fill_super, mnt);
}
static struct file_system_type capifs_fs_type = {
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index 22759c0..81accdf 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -1177,9 +1177,8 @@ isdn_write(struct file *file, const char __user *buf, size_t count, loff_t * off
goto out;
}
chidx = isdn_minor2chan(minor);
- while (isdn_writebuf_stub(drvidx, chidx, buf, count) != count)
+ while ((retval = isdn_writebuf_stub(drvidx, chidx, buf, count)) == 0)
interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]);
- retval = count;
goto out;
}
if (minor <= ISDN_MINOR_CTRLMAX) {
@@ -1951,9 +1950,10 @@ isdn_writebuf_stub(int drvidx, int chan, const u_char __user * buf, int len)
struct sk_buff *skb = alloc_skb(hl + len, GFP_ATOMIC);
if (!skb)
- return 0;
+ return -ENOMEM;
skb_reserve(skb, hl);
- copy_from_user(skb_put(skb, len), buf, len);
+ if (copy_from_user(skb_put(skb, len), buf, len))
+ return -EFAULT;
ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb);
if (ret <= 0)
dev_kfree_skb(skb);
diff --git a/drivers/isdn/sc/ioctl.c b/drivers/isdn/sc/ioctl.c
index f4f7122..57c4ab9 100644
--- a/drivers/isdn/sc/ioctl.c
+++ b/drivers/isdn/sc/ioctl.c
@@ -97,6 +97,7 @@ int sc_ioctl(int card, scs_ioctl *data)
case SCIOCSTART:
{
+ kfree(rcvmsg);
pr_debug("%s: SCIOSTART: ioctl received\n",
sc_adapter[card]->devicename);
if(sc_adapter[card]->EngineUp) {
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 6265062..9650998 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -63,6 +63,12 @@ config LEDS_S3C24XX
This option enables support for LEDs connected to GPIO lines
on Samsung S3C24XX series CPUs, such as the S3C2410 and S3C2440.
+config LEDS_AMS_DELTA
+ tristate "LED Support for the Amstrad Delta (E3)"
+ depends LEDS_CLASS && MACH_AMS_DELTA
+ help
+ This option enables support for the LEDs on Amstrad Delta (E3).
+
comment "LED Triggers"
config LEDS_TRIGGERS
@@ -87,5 +93,14 @@ config LEDS_TRIGGER_IDE_DISK
This allows LEDs to be controlled by IDE disk activity.
If unsure, say Y.
+config LEDS_TRIGGER_HEARTBEAT
+ tristate "LED Heartbeat Trigger"
+ depends LEDS_TRIGGERS
+ help
+ This allows LEDs to be controlled by a CPU load average.
+ The flash frequency is a hyperbolic function of the 1-minute
+ load average.
+ If unsure, say Y.
+
endmenu
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 40f0426..88d3b6e 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -11,7 +11,9 @@ obj-$(CONFIG_LEDS_SPITZ) += leds-spitz.o
obj-$(CONFIG_LEDS_IXP4XX) += leds-ixp4xx-gpio.o
obj-$(CONFIG_LEDS_TOSA) += leds-tosa.o
obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
+obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o
# LED Triggers
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o
+obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
diff --git a/drivers/leds/leds-ams-delta.c b/drivers/leds/leds-ams-delta.c
new file mode 100644
index 0000000..e9f0611
--- /dev/null
+++ b/drivers/leds/leds-ams-delta.c
@@ -0,0 +1,162 @@
+/*
+ * LEDs driver for Amstrad Delta (E3)
+ *
+ * Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <asm/arch/board-ams-delta.h>
+
+/*
+ * Our context
+ */
+struct ams_delta_led {
+ struct led_classdev cdev;
+ u8 bitmask;
+};
+
+static void ams_delta_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct ams_delta_led *led_dev =
+ container_of(led_cdev, struct ams_delta_led, cdev);
+
+ if (value)
+ ams_delta_latch1_write(led_dev->bitmask, led_dev->bitmask);
+ else
+ ams_delta_latch1_write(led_dev->bitmask, 0);
+}
+
+static struct ams_delta_led ams_delta_leds[] = {
+ {
+ .cdev = {
+ .name = "ams-delta:camera",
+ .brightness_set = ams_delta_led_set,
+ },
+ .bitmask = AMS_DELTA_LATCH1_LED_CAMERA,
+ },
+ {
+ .cdev = {
+ .name = "ams-delta:advert",
+ .brightness_set = ams_delta_led_set,
+ },
+ .bitmask = AMS_DELTA_LATCH1_LED_ADVERT,
+ },
+ {
+ .cdev = {
+ .name = "ams-delta:email",
+ .brightness_set = ams_delta_led_set,
+ },
+ .bitmask = AMS_DELTA_LATCH1_LED_EMAIL,
+ },
+ {
+ .cdev = {
+ .name = "ams-delta:handsfree",
+ .brightness_set = ams_delta_led_set,
+ },
+ .bitmask = AMS_DELTA_LATCH1_LED_HANDSFREE,
+ },
+ {
+ .cdev = {
+ .name = "ams-delta:voicemail",
+ .brightness_set = ams_delta_led_set,
+ },
+ .bitmask = AMS_DELTA_LATCH1_LED_VOICEMAIL,
+ },
+ {
+ .cdev = {
+ .name = "ams-delta:voice",
+ .brightness_set = ams_delta_led_set,
+ },
+ .bitmask = AMS_DELTA_LATCH1_LED_VOICE,
+ },
+};
+
+#ifdef CONFIG_PM
+static int ams_delta_led_suspend(struct platform_device *dev,
+ pm_message_t state)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ams_delta_leds); i++)
+ led_classdev_suspend(&ams_delta_leds[i].cdev);
+
+ return 0;
+}
+
+static int ams_delta_led_resume(struct platform_device *dev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ams_delta_leds); i++)
+ led_classdev_resume(&ams_delta_leds[i].cdev);
+
+ return 0;
+}
+#else
+#define ams_delta_led_suspend NULL
+#define ams_delta_led_resume NULL
+#endif
+
+static int ams_delta_led_probe(struct platform_device *pdev)
+{
+ int i;
+ int ret;
+
+ for (i = ret = 0; ret >= 0 && i < ARRAY_SIZE(ams_delta_leds); i++) {
+ ret = led_classdev_register(&pdev->dev,
+ &ams_delta_leds[i].cdev);
+ }
+
+ if (ret < 0 && i > 1) {
+ for (i = i - 2; i >= 0; i--)
+ led_classdev_unregister(&ams_delta_leds[i].cdev);
+ }
+
+ return ret;
+}
+
+static int ams_delta_led_remove(struct platform_device *pdev)
+{
+ int i;
+
+ for (i = ARRAY_SIZE(ams_delta_leds) - 1; i >= 0; i--)
+ led_classdev_unregister(&ams_delta_leds[i].cdev);
+
+ return 0;
+}
+
+static struct platform_driver ams_delta_led_driver = {
+ .probe = ams_delta_led_probe,
+ .remove = ams_delta_led_remove,
+ .suspend = ams_delta_led_suspend,
+ .resume = ams_delta_led_resume,
+ .driver = {
+ .name = "ams-delta-led",
+ },
+};
+
+static int __init ams_delta_led_init(void)
+{
+ return platform_driver_register(&ams_delta_led_driver);
+}
+
+static void __exit ams_delta_led_exit(void)
+{
+ return platform_driver_unregister(&ams_delta_led_driver);
+}
+
+module_init(ams_delta_led_init);
+module_exit(ams_delta_led_exit);
+
+MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>");
+MODULE_DESCRIPTION("Amstrad Delta LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/ledtrig-heartbeat.c b/drivers/leds/ledtrig-heartbeat.c
new file mode 100644
index 0000000..4bf8cec
--- /dev/null
+++ b/drivers/leds/ledtrig-heartbeat.c
@@ -0,0 +1,118 @@
+/*
+ * LED Heartbeat Trigger
+ *
+ * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * Based on Richard Purdie's ledtrig-timer.c and some arch's
+ * CONFIG_HEARTBEAT code.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/leds.h>
+#include "leds.h"
+
+struct heartbeat_trig_data {
+ unsigned int phase;
+ unsigned int period;
+ struct timer_list timer;
+};
+
+static void led_heartbeat_function(unsigned long data)
+{
+ struct led_classdev *led_cdev = (struct led_classdev *) data;
+ struct heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data;
+ unsigned long brightness = LED_OFF;
+ unsigned long delay = 0;
+
+ /* acts like an actual heart beat -- ie thump-thump-pause... */
+ switch (heartbeat_data->phase) {
+ case 0:
+ /*
+ * The hyperbolic function below modifies the
+ * heartbeat period length in dependency of the
+ * current (1min) load. It goes through the points
+ * f(0)=1260, f(1)=860, f(5)=510, f(inf)->300.
+ */
+ heartbeat_data->period = 300 +
+ (6720 << FSHIFT) / (5 * avenrun[0] + (7 << FSHIFT));
+ heartbeat_data->period =
+ msecs_to_jiffies(heartbeat_data->period);
+ delay = msecs_to_jiffies(70);
+ heartbeat_data->phase++;
+ brightness = LED_FULL;
+ break;
+ case 1:
+ delay = heartbeat_data->period / 4 - msecs_to_jiffies(70);
+ heartbeat_data->phase++;
+ break;
+ case 2:
+ delay = msecs_to_jiffies(70);
+ heartbeat_data->phase++;
+ brightness = LED_FULL;
+ break;
+ default:
+ delay = heartbeat_data->period - heartbeat_data->period / 4 -
+ msecs_to_jiffies(70);
+ heartbeat_data->phase = 0;
+ break;
+ }
+
+ led_set_brightness(led_cdev, brightness);
+ mod_timer(&heartbeat_data->timer, jiffies + delay);
+}
+
+static void heartbeat_trig_activate(struct led_classdev *led_cdev)
+{
+ struct heartbeat_trig_data *heartbeat_data;
+
+ heartbeat_data = kzalloc(sizeof(*heartbeat_data), GFP_KERNEL);
+ if (!heartbeat_data)
+ return;
+
+ led_cdev->trigger_data = heartbeat_data;
+ setup_timer(&heartbeat_data->timer,
+ led_heartbeat_function, (unsigned long) led_cdev);
+ heartbeat_data->phase = 0;
+ led_heartbeat_function(heartbeat_data->timer.data);
+}
+
+static void heartbeat_trig_deactivate(struct led_classdev *led_cdev)
+{
+ struct heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data;
+
+ if (heartbeat_data) {
+ del_timer_sync(&heartbeat_data->timer);
+ kfree(heartbeat_data);
+ }
+}
+
+static struct led_trigger heartbeat_led_trigger = {
+ .name = "heartbeat",
+ .activate = heartbeat_trig_activate,
+ .deactivate = heartbeat_trig_deactivate,
+};
+
+static int __init heartbeat_trig_init(void)
+{
+ return led_trigger_register(&heartbeat_led_trigger);
+}
+
+static void __exit heartbeat_trig_exit(void)
+{
+ led_trigger_unregister(&heartbeat_led_trigger);
+}
+
+module_init(heartbeat_trig_init);
+module_exit(heartbeat_trig_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("Heartbeat LED trigger");
+MODULE_LICENSE("GPL");
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index 12ad462..37cd6ee 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -99,17 +99,22 @@ config PMAC_MEDIABAY
devices are not fully supported in the bay as I never had one to
try with
-# made a separate option since backlight may end up beeing used
-# on non-powerbook machines (but only on PMU based ones AFAIK)
config PMAC_BACKLIGHT
bool "Backlight control for LCD screens"
depends on ADB_PMU && (BROKEN || !PPC64)
help
- Say Y here to build in code to manage the LCD backlight on a
- Macintosh PowerBook. With this code, the backlight will be turned
- on and off appropriately on power-management and lid-open/lid-closed
- events; also, the PowerBook button device will be enabled so you can
- change the screen brightness.
+ Say Y here to enable Macintosh specific extensions of the generic
+ backlight code. With this enabled, the brightness keys on older
+ PowerBooks will be enabled so you can change the screen brightness.
+ Newer models should use an userspace daemon like pbbuttonsd.
+
+config PMAC_BACKLIGHT_LEGACY
+ bool "Provide legacy ioctl's on /dev/pmu for the backlight"
+ depends on PMAC_BACKLIGHT && (BROKEN || !PPC64)
+ help
+ Say Y if you want to enable legacy ioctl's on /dev/pmu. This is for
+ programs which use this old interface. New and updated programs
+ should use the backlight classes in sysfs.
config ADB_MACIO
bool "Include MacIO (CHRP) ADB driver"
@@ -171,6 +176,7 @@ config THERM_PM72
config WINDFARM
tristate "New PowerMac thermal control infrastructure"
+ depends on PPC
config WINDFARM_PM81
tristate "Support for thermal management on iMac G5"
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index 6081acd..8972e53 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_INPUT_ADBHID) += adbhid.o
obj-$(CONFIG_ANSLCD) += ans-lcd.o
obj-$(CONFIG_ADB_PMU) += via-pmu.o
+obj-$(CONFIG_PMAC_BACKLIGHT) += via-pmu-backlight.o
obj-$(CONFIG_ADB_CUDA) += via-cuda.o
obj-$(CONFIG_PMAC_APM_EMU) += apm_emu.o
obj-$(CONFIG_PMAC_SMU) += smu.o
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
index 394334e..c26e123 100644
--- a/drivers/macintosh/adbhid.c
+++ b/drivers/macintosh/adbhid.c
@@ -503,9 +503,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
case 0x1f: /* Powerbook button device */
{
int down = (data[1] == (data[1] & 0xf));
-#ifdef CONFIG_PMAC_BACKLIGHT
- int backlight = get_backlight_level();
-#endif
+
/*
* XXX: Where is the contrast control for the passive?
* -- Cort
@@ -530,29 +528,17 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
case 0xa: /* brightness decrease */
#ifdef CONFIG_PMAC_BACKLIGHT
- if (!disable_kernel_backlight) {
- if (down && backlight >= 0) {
- if (backlight > BACKLIGHT_OFF)
- set_backlight_level(backlight-1);
- else
- set_backlight_level(BACKLIGHT_OFF);
- }
- }
-#endif /* CONFIG_PMAC_BACKLIGHT */
+ if (!disable_kernel_backlight && down)
+ pmac_backlight_key_down();
+#endif
input_report_key(adbhid[id]->input, KEY_BRIGHTNESSDOWN, down);
break;
case 0x9: /* brightness increase */
#ifdef CONFIG_PMAC_BACKLIGHT
- if (!disable_kernel_backlight) {
- if (down && backlight >= 0) {
- if (backlight < BACKLIGHT_MAX)
- set_backlight_level(backlight+1);
- else
- set_backlight_level(BACKLIGHT_MAX);
- }
- }
-#endif /* CONFIG_PMAC_BACKLIGHT */
+ if (!disable_kernel_backlight && down)
+ pmac_backlight_key_up();
+#endif
input_report_key(adbhid[id]->input, KEY_BRIGHTNESSUP, down);
break;
diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c
new file mode 100644
index 0000000..b42d05f
--- /dev/null
+++ b/drivers/macintosh/via-pmu-backlight.c
@@ -0,0 +1,150 @@
+/*
+ * Backlight code for via-pmu
+ *
+ * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
+ * Copyright (C) 2001-2002 Benjamin Herrenschmidt
+ * Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
+ *
+ */
+
+#include <asm/ptrace.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <asm/backlight.h>
+#include <asm/prom.h>
+
+#define MAX_PMU_LEVEL 0xFF
+
+static struct device_node *vias;
+static struct backlight_properties pmu_backlight_data;
+
+static int pmu_backlight_get_level_brightness(struct fb_info *info,
+ int level)
+{
+ int pmulevel;
+
+ /* Get and convert the value */
+ mutex_lock(&info->bl_mutex);
+ pmulevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_PMU_LEVEL;
+ mutex_unlock(&info->bl_mutex);
+
+ if (pmulevel < 0)
+ pmulevel = 0;
+ else if (pmulevel > MAX_PMU_LEVEL)
+ pmulevel = MAX_PMU_LEVEL;
+
+ return pmulevel;
+}
+
+static int pmu_backlight_update_status(struct backlight_device *bd)
+{
+ struct fb_info *info = class_get_devdata(&bd->class_dev);
+ struct adb_request req;
+ int pmulevel, level = bd->props->brightness;
+
+ if (vias == NULL)
+ return -ENODEV;
+
+ if (bd->props->power != FB_BLANK_UNBLANK ||
+ bd->props->fb_blank != FB_BLANK_UNBLANK)
+ level = 0;
+
+ pmulevel = pmu_backlight_get_level_brightness(info, level);
+
+ pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel);
+ pmu_wait_complete(&req);
+
+ pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
+ PMU_POW_BACKLIGHT | (level > 0 ? PMU_POW_ON : PMU_POW_OFF));
+ pmu_wait_complete(&req);
+
+ return 0;
+}
+
+static int pmu_backlight_get_brightness(struct backlight_device *bd)
+{
+ return bd->props->brightness;
+}
+
+static struct backlight_properties pmu_backlight_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = pmu_backlight_get_brightness,
+ .update_status = pmu_backlight_update_status,
+ .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
+};
+
+void __init pmu_backlight_init(struct device_node *in_vias)
+{
+ struct backlight_device *bd;
+ struct fb_info *info;
+ char name[10];
+ int level, autosave;
+
+ vias = in_vias;
+
+ /* Special case for the old PowerBook since I can't test on it */
+ autosave =
+ machine_is_compatible("AAPL,3400/2400") ||
+ machine_is_compatible("AAPL,3500");
+
+ if (!autosave &&
+ !pmac_has_backlight_type("pmu") &&
+ !machine_is_compatible("AAPL,PowerBook1998") &&
+ !machine_is_compatible("PowerBook1,1"))
+ return;
+
+ /* Actually, this is a hack, but I don't know of a better way
+ * to get the first framebuffer device.
+ */
+ info = registered_fb[0];
+ if (!info) {
+ printk("pmubl: No framebuffer found\n");
+ goto error;
+ }
+
+ snprintf(name, sizeof(name), "pmubl%d", info->node);
+
+ bd = backlight_device_register(name, info, &pmu_backlight_data);
+ if (IS_ERR(bd)) {
+ printk("pmubl: Backlight registration failed\n");
+ goto error;
+ }
+
+ mutex_lock(&info->bl_mutex);
+ info->bl_dev = bd;
+ fb_bl_default_curve(info, 0x7F, 0x46, 0x0E);
+ mutex_unlock(&info->bl_mutex);
+
+ level = pmu_backlight_data.max_brightness;
+
+ if (autosave) {
+ /* read autosaved value if available */
+ struct adb_request req;
+ pmu_request(&req, NULL, 2, 0xd9, 0);
+ pmu_wait_complete(&req);
+
+ mutex_lock(&info->bl_mutex);
+ level = pmac_backlight_curve_lookup(info,
+ (req.reply[0] >> 4) *
+ pmu_backlight_data.max_brightness / 15);
+ mutex_unlock(&info->bl_mutex);
+ }
+
+ up(&bd->sem);
+ bd->props->brightness = level;
+ bd->props->power = FB_BLANK_UNBLANK;
+ bd->props->update_status(bd);
+ down(&bd->sem);
+
+ mutex_lock(&pmac_backlight_mutex);
+ if (!pmac_backlight)
+ pmac_backlight = bd;
+ mutex_unlock(&pmac_backlight_mutex);
+
+ printk("pmubl: Backlight initialized (%s)\n", name);
+
+ return;
+
+error:
+ return;
+}
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 0b5ff55..2a355ae5 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -144,7 +144,6 @@ static int data_index;
static int data_len;
static volatile int adb_int_pending;
static volatile int disable_poll;
-static struct adb_request bright_req_1, bright_req_2;
static struct device_node *vias;
static int pmu_kind = PMU_UNKNOWN;
static int pmu_fully_inited = 0;
@@ -161,7 +160,7 @@ static int drop_interrupts;
#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
static int option_lid_wakeup = 1;
#endif /* CONFIG_PM && CONFIG_PPC32 */
-#if (defined(CONFIG_PM)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT)
+#if (defined(CONFIG_PM)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT_LEGACY)
static int sleep_in_progress;
#endif
static unsigned long async_req_locks;
@@ -208,10 +207,6 @@ static int proc_get_info(char *page, char **start, off_t off,
int count, int *eof, void *data);
static int proc_get_irqstats(char *page, char **start, off_t off,
int count, int *eof, void *data);
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int pmu_set_backlight_level(int level, void* data);
-static int pmu_set_backlight_enable(int on, int level, void* data);
-#endif /* CONFIG_PMAC_BACKLIGHT */
static void pmu_pass_intr(unsigned char *data, int len);
static int proc_get_batt(char *page, char **start, off_t off,
int count, int *eof, void *data);
@@ -292,13 +287,6 @@ static char *pbook_type[] = {
"Core99"
};
-#ifdef CONFIG_PMAC_BACKLIGHT
-static struct backlight_controller pmu_backlight_controller = {
- pmu_set_backlight_enable,
- pmu_set_backlight_level
-};
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
int __init find_via_pmu(void)
{
u64 taddr;
@@ -417,8 +405,6 @@ static int __init via_pmu_start(void)
if (vias == NULL)
return -ENODEV;
- bright_req_1.complete = 1;
- bright_req_2.complete = 1;
batt_req.complete = 1;
#ifndef CONFIG_PPC_MERGE
@@ -483,9 +469,9 @@ static int __init via_pmu_dev_init(void)
return -ENODEV;
#ifdef CONFIG_PMAC_BACKLIGHT
- /* Enable backlight */
- register_backlight_controller(&pmu_backlight_controller, NULL, "pmu");
-#endif /* CONFIG_PMAC_BACKLIGHT */
+ /* Initialize backlight */
+ pmu_backlight_init(vias);
+#endif
#ifdef CONFIG_PPC32
if (machine_is_compatible("AAPL,3400/2400") ||
@@ -1424,7 +1410,7 @@ next:
#ifdef CONFIG_INPUT_ADBHID
if (!disable_kernel_backlight)
#endif /* CONFIG_INPUT_ADBHID */
- set_backlight_level(data[1] >> 4);
+ pmac_backlight_set_legacy_brightness(data[1] >> 4);
#endif /* CONFIG_PMAC_BACKLIGHT */
}
/* Tick interrupt */
@@ -1674,61 +1660,6 @@ gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
return IRQ_NONE;
}
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int backlight_to_bright[] = {
- 0x7f, 0x46, 0x42, 0x3e, 0x3a, 0x36, 0x32, 0x2e,
- 0x2a, 0x26, 0x22, 0x1e, 0x1a, 0x16, 0x12, 0x0e
-};
-
-static int
-pmu_set_backlight_enable(int on, int level, void* data)
-{
- struct adb_request req;
-
- if (vias == NULL)
- return -ENODEV;
-
- if (on) {
- pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
- backlight_to_bright[level]);
- pmu_wait_complete(&req);
- }
- pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
- PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF));
- pmu_wait_complete(&req);
-
- return 0;
-}
-
-static void
-pmu_bright_complete(struct adb_request *req)
-{
- if (req == &bright_req_1)
- clear_bit(1, &async_req_locks);
- if (req == &bright_req_2)
- clear_bit(2, &async_req_locks);
-}
-
-static int
-pmu_set_backlight_level(int level, void* data)
-{
- if (vias == NULL)
- return -ENODEV;
-
- if (test_and_set_bit(1, &async_req_locks))
- return -EAGAIN;
- pmu_request(&bright_req_1, pmu_bright_complete, 2, PMU_BACKLIGHT_BRIGHT,
- backlight_to_bright[level]);
- if (test_and_set_bit(2, &async_req_locks))
- return -EAGAIN;
- pmu_request(&bright_req_2, pmu_bright_complete, 2, PMU_POWER_CTRL,
- PMU_POW_BACKLIGHT | (level > BACKLIGHT_OFF ?
- PMU_POW_ON : PMU_POW_OFF));
-
- return 0;
-}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
void
pmu_enable_irled(int on)
{
@@ -2145,9 +2076,8 @@ pmac_suspend_devices(void)
return -EBUSY;
}
- /* Wait for completion of async backlight requests */
- while (!bright_req_1.complete || !bright_req_2.complete ||
- !batt_req.complete)
+ /* Wait for completion of async requests */
+ while (!batt_req.complete)
pmu_poll();
/* Giveup the lazy FPU & vec so we don't have to back them
@@ -2268,7 +2198,7 @@ static int powerbook_sleep_grackle(void)
_set_L2CR(save_l2cr);
/* Restore userland MMU context */
- set_context(current->active_mm->context, current->active_mm->pgd);
+ set_context(current->active_mm->context.id, current->active_mm->pgd);
/* Power things up */
pmu_unlock();
@@ -2366,7 +2296,7 @@ powerbook_sleep_Core99(void)
_set_L3CR(save_l3cr);
/* Restore userland MMU context */
- set_context(current->active_mm->context, current->active_mm->pgd);
+ set_context(current->active_mm->context.id, current->active_mm->pgd);
/* Tell PMU we are ready */
pmu_unlock();
@@ -2678,26 +2608,34 @@ pmu_ioctl(struct inode * inode, struct file *filp,
return put_user(1, argp);
#endif /* CONFIG_PM && CONFIG_PPC32 */
-#ifdef CONFIG_PMAC_BACKLIGHT
- /* Backlight should have its own device or go via
- * the fbdev
- */
+#ifdef CONFIG_PMAC_BACKLIGHT_LEGACY
+ /* Compatibility ioctl's for backlight */
case PMU_IOC_GET_BACKLIGHT:
+ {
+ int brightness;
+
if (sleep_in_progress)
return -EBUSY;
- error = get_backlight_level();
- if (error < 0)
- return error;
- return put_user(error, argp);
+
+ brightness = pmac_backlight_get_legacy_brightness();
+ if (brightness < 0)
+ return brightness;
+ else
+ return put_user(brightness, argp);
+
+ }
case PMU_IOC_SET_BACKLIGHT:
{
- __u32 value;
+ int brightness;
+
if (sleep_in_progress)
return -EBUSY;
- error = get_user(value, argp);
- if (!error)
- error = set_backlight_level(value);
- break;
+
+ error = get_user(brightness, argp);
+ if (error)
+ return error;
+
+ return pmac_backlight_set_legacy_brightness(brightness);
}
#ifdef CONFIG_INPUT_ADBHID
case PMU_IOC_GRAB_BACKLIGHT: {
@@ -2713,7 +2651,7 @@ pmu_ioctl(struct inode * inode, struct file *filp,
return 0;
}
#endif /* CONFIG_INPUT_ADBHID */
-#endif /* CONFIG_PMAC_BACKLIGHT */
+#endif /* CONFIG_PMAC_BACKLIGHT_LEGACY */
case PMU_IOC_GET_MODEL:
return put_user(pmu_kind, argp);
case PMU_IOC_HAS_ADB:
diff --git a/drivers/md/raid6algos.c b/drivers/md/raid6algos.c
index 51c63c0..9265761 100644
--- a/drivers/md/raid6algos.c
+++ b/drivers/md/raid6algos.c
@@ -139,15 +139,14 @@ int __init raid6_select_algo(void)
}
}
- if ( best )
+ if (best) {
printk("raid6: using algorithm %s (%ld MB/s)\n",
best->name,
(bestperf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2));
- else
+ raid6_call = *best;
+ } else
printk("raid6: Yikes! No algorithm found!\n");
- raid6_call = *best;
-
free_pages((unsigned long)syndromes, 1);
return best ? 0 : -EINVAL;
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 344d83a..583d151 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -25,7 +25,7 @@ config VIDEO_DEV
module will be called videodev.
config VIDEO_V4L1
- boolean "Enable Video For Linux API 1 (DEPRECATED)"
+ bool "Enable Video For Linux API 1 (DEPRECATED)"
depends on VIDEO_DEV
select VIDEO_V4L1_COMPAT
default y
@@ -36,7 +36,7 @@ config VIDEO_V4L1
If you are unsure as to whether this is required, answer Y.
config VIDEO_V4L1_COMPAT
- boolean "Enable Video For Linux API 1 compatible Layer"
+ bool "Enable Video For Linux API 1 compatible Layer"
depends on VIDEO_DEV
default y
---help---
@@ -82,6 +82,9 @@ config VIDEO_IR
config VIDEO_TVEEPROM
tristate
+config VIDEO_CX2341X
+ tristate
+
config USB_DABUSB
tristate "DABUSB driver"
depends on USB
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
index 61b8961..8e74482 100644
--- a/drivers/media/common/Makefile
+++ b/drivers/media/common/Makefile
@@ -1,5 +1,5 @@
saa7146-objs := saa7146_i2c.o saa7146_core.o
-saa7146_vv-objs := saa7146_vv_ksyms.o saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
+saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
ir-common-objs := ir-functions.o ir-keymaps.o
obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
index 397cff8..8eaa88f 100644
--- a/drivers/media/common/ir-functions.c
+++ b/drivers/media/common/ir-functions.c
@@ -269,4 +269,3 @@ EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
* c-basic-offset: 8
* End:
*/
-
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index a294d5c..ca98d94 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -618,7 +618,7 @@ IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE] = {
EXPORT_SYMBOL_GPL(ir_codes_em_terratec);
-IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE] = {
+IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE] = {
[ 0x3a ] = KEY_0,
[ 0x31 ] = KEY_1,
[ 0x32 ] = KEY_2,
@@ -670,7 +670,7 @@ IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE] = {
[ 0x27 ] = KEY_RECORD,
};
-EXPORT_SYMBOL_GPL(ir_codes_em_pinnacle_usb);
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle_grey);
IR_KEYTAB_TYPE ir_codes_flyvideo[IR_KEYTAB_SIZE] = {
[ 0x0f ] = KEY_0,
@@ -1263,34 +1263,51 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
[ 0x0f ] = KEY_9,
[ 0x00 ] = KEY_POWER,
- [ 0x02 ] = KEY_TUNER, /* TV/FM */
- [ 0x1e ] = KEY_VIDEO,
+ [ 0x1b ] = KEY_AUDIO, /* Audio Source */
+ [ 0x02 ] = KEY_TUNER, /* TV/FM, not on Y0400052 */
+ [ 0x1e ] = KEY_VIDEO, /* Video Source */
+ [ 0x16 ] = KEY_INFO, /* Display information */
[ 0x04 ] = KEY_VOLUMEUP,
[ 0x08 ] = KEY_VOLUMEDOWN,
[ 0x0c ] = KEY_CHANNELUP,
[ 0x10 ] = KEY_CHANNELDOWN,
[ 0x03 ] = KEY_ZOOM, /* fullscreen */
- [ 0x1f ] = KEY_SUBTITLE, /* closed caption/teletext */
+ [ 0x1f ] = KEY_TEXT, /* closed caption/teletext */
[ 0x20 ] = KEY_SLEEP,
+ [ 0x29 ] = KEY_CLEAR, /* boss key */
[ 0x14 ] = KEY_MUTE,
[ 0x2b ] = KEY_RED,
[ 0x2c ] = KEY_GREEN,
[ 0x2d ] = KEY_YELLOW,
[ 0x2e ] = KEY_BLUE,
- [ 0x18 ] = KEY_KPPLUS, /* fine tune + */
- [ 0x19 ] = KEY_KPMINUS, /* fine tune - */
+ [ 0x18 ] = KEY_KPPLUS, /* fine tune + , not on Y040052 */
+ [ 0x19 ] = KEY_KPMINUS, /* fine tune - , not on Y040052 */
+ [ 0x2a ] = KEY_MEDIA, /* PIP (Picture in picture */
[ 0x21 ] = KEY_DOT,
[ 0x13 ] = KEY_ENTER,
- [ 0x22 ] = KEY_BACK,
+ [ 0x11 ] = KEY_LAST, /* Recall (last channel */
+ [ 0x22 ] = KEY_PREVIOUS,
[ 0x23 ] = KEY_PLAYPAUSE,
[ 0x24 ] = KEY_NEXT,
+ [ 0x25 ] = KEY_ARCHIVE, /* Time Shifting */
[ 0x26 ] = KEY_STOP,
- [ 0x27 ] = KEY_RECORD
+ [ 0x27 ] = KEY_RECORD,
+ [ 0x28 ] = KEY_SAVE, /* Screenshot */
+ [ 0x2f ] = KEY_MENU,
+ [ 0x30 ] = KEY_CANCEL,
+ [ 0x31 ] = KEY_CHANNEL, /* Channel Surf */
+ [ 0x32 ] = KEY_SUBTITLE,
+ [ 0x33 ] = KEY_LANGUAGE,
+ [ 0x34 ] = KEY_REWIND,
+ [ 0x35 ] = KEY_FASTFORWARD,
+ [ 0x36 ] = KEY_TV,
+ [ 0x37 ] = KEY_RADIO, /* FM */
+ [ 0x38 ] = KEY_DVD
};
EXPORT_SYMBOL_GPL(ir_codes_winfast);
-IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
+IR_KEYTAB_TYPE ir_codes_pinnacle_color[IR_KEYTAB_SIZE] = {
[ 0x59 ] = KEY_MUTE,
[ 0x4a ] = KEY_POWER,
@@ -1348,7 +1365,7 @@ IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
[ 0x0a ] = KEY_BACKSPACE,
};
-EXPORT_SYMBOL_GPL(ir_codes_pinnacle);
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle_color);
/* Hauppauge: the newer, gray remotes (seems there are multiple
* slightly different versions), shipped with cx88+ivtv cards.
@@ -1413,3 +1430,46 @@ IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE] = {
EXPORT_SYMBOL_GPL(ir_codes_hauppauge_new);
+IR_KEYTAB_TYPE ir_codes_npgtech[IR_KEYTAB_SIZE] = {
+ [ 0x1d ] = KEY_SWITCHVIDEOMODE, /* switch inputs */
+ [ 0x2a ] = KEY_FRONT,
+
+ [ 0x3e ] = KEY_1,
+ [ 0x02 ] = KEY_2,
+ [ 0x06 ] = KEY_3,
+ [ 0x0a ] = KEY_4,
+ [ 0x0e ] = KEY_5,
+ [ 0x12 ] = KEY_6,
+ [ 0x16 ] = KEY_7,
+ [ 0x1a ] = KEY_8,
+ [ 0x1e ] = KEY_9,
+ [ 0x3a ] = KEY_0,
+ [ 0x22 ] = KEY_NUMLOCK, /* -/-- */
+ [ 0x20 ] = KEY_REFRESH,
+
+ [ 0x03 ] = KEY_BRIGHTNESSDOWN,
+ [ 0x28 ] = KEY_AUDIO,
+ [ 0x3c ] = KEY_UP,
+ [ 0x3f ] = KEY_LEFT,
+ [ 0x2e ] = KEY_MUTE,
+ [ 0x3b ] = KEY_RIGHT,
+ [ 0x00 ] = KEY_DOWN,
+ [ 0x07 ] = KEY_BRIGHTNESSUP,
+ [ 0x2c ] = KEY_TEXT,
+
+ [ 0x37 ] = KEY_RECORD,
+ [ 0x17 ] = KEY_PLAY,
+ [ 0x13 ] = KEY_PAUSE,
+ [ 0x26 ] = KEY_STOP,
+ [ 0x18 ] = KEY_FASTFORWARD,
+ [ 0x14 ] = KEY_REWIND,
+ [ 0x33 ] = KEY_ZOOM,
+ [ 0x32 ] = KEY_KEYBOARD,
+ [ 0x30 ] = KEY_GOTO, /* Pointing arrow */
+ [ 0x36 ] = KEY_MACRO, /* Maximize/Minimize (yellow) */
+ [ 0x0b ] = KEY_RADIO,
+ [ 0x10 ] = KEY_POWER,
+
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_npgtech);
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index 523ab38..0027acc 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -501,6 +501,7 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
return 0;
}
+EXPORT_SYMBOL_GPL(saa7146_vv_init);
int saa7146_vv_release(struct saa7146_dev* dev)
{
@@ -515,6 +516,7 @@ int saa7146_vv_release(struct saa7146_dev* dev)
return 0;
}
+EXPORT_SYMBOL_GPL(saa7146_vv_release);
int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
char *name, int type)
@@ -553,6 +555,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
*vid = vfd;
return 0;
}
+EXPORT_SYMBOL_GPL(saa7146_register_device);
int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev)
{
@@ -571,6 +574,7 @@ int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev
return 0;
}
+EXPORT_SYMBOL_GPL(saa7146_unregister_device);
static int __init saa7146_vv_init_module(void)
{
diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c
index 33bec8a..2092e6c 100644
--- a/drivers/media/common/saa7146_hlp.c
+++ b/drivers/media/common/saa7146_hlp.c
@@ -641,6 +641,7 @@ void saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sy
vv->current_hps_source = source;
vv->current_hps_sync = sync;
}
+EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync);
int saa7146_enable_overlay(struct saa7146_fh *fh)
{
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index e7079d1..8393d47 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -318,6 +318,7 @@ int saa7146_start_preview(struct saa7146_fh *fh)
return 0;
}
+EXPORT_SYMBOL_GPL(saa7146_start_preview);
int saa7146_stop_preview(struct saa7146_fh *fh)
{
@@ -352,6 +353,7 @@ int saa7146_stop_preview(struct saa7146_fh *fh)
return 0;
}
+EXPORT_SYMBOL_GPL(saa7146_stop_preview);
static int s_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
{
diff --git a/drivers/media/common/saa7146_vv_ksyms.c b/drivers/media/common/saa7146_vv_ksyms.c
deleted file mode 100644
index 62226eb4..0000000
--- a/drivers/media/common/saa7146_vv_ksyms.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <linux/module.h>
-#include <media/saa7146_vv.h>
-
-EXPORT_SYMBOL_GPL(saa7146_start_preview);
-EXPORT_SYMBOL_GPL(saa7146_stop_preview);
-
-EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync);
-EXPORT_SYMBOL_GPL(saa7146_register_device);
-EXPORT_SYMBOL_GPL(saa7146_unregister_device);
-
-EXPORT_SYMBOL_GPL(saa7146_vv_init);
-EXPORT_SYMBOL_GPL(saa7146_vv_release);
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index 9c7f122..3be87c7 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -14,6 +14,7 @@
#include "stv0297.h"
#include "mt312.h"
#include "lgdt330x.h"
+#include "lg_h06xf.h"
#include "dvb-pll.h"
/* lnb control */
@@ -166,11 +167,12 @@ static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate,
return 0;
}
-static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
+static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
u8 buf[4];
u32 div;
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ struct flexcop_device *fc = fe->dvb->priv;
div = params->frequency / 125;
@@ -181,8 +183,11 @@ static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct i2c_adapter
if (params->frequency < 1500000) buf[3] |= 0x10;
- if (i2c_transfer(i2c, &msg, 1) != 1)
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) {
return -EIO;
+ }
return 0;
}
@@ -241,7 +246,6 @@ static struct stv0299_config samsung_tbmu24112_config = {
.volt13_op0_op1 = STV0299_VOLT13_OP1,
.min_delay_ms = 100,
.set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
- .pll_set = samsung_tbmu24112_pll_set,
};
/* dvb-t mt352 */
@@ -264,11 +268,14 @@ static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
return 0;
}
-static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
{
u32 div;
unsigned char bs = 0;
+ if (buf_len < 5)
+ return -EINVAL;
+
#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
@@ -276,19 +283,18 @@ static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_front
if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
- pllbuf[0] = 0xc2; /* Note: non-linux standard PLL i2c address */
+ pllbuf[0] = 0x61;
pllbuf[1] = div >> 8;
pllbuf[2] = div & 0xff;
pllbuf[3] = 0xcc;
pllbuf[4] = bs;
- return 0;
+ return 5;
}
static struct mt352_config samsung_tdtc9251dh0_config = {
.demod_address = 0x0f,
.demod_init = samsung_tdtc9251dh0_demod_init,
- .pll_set = samsung_tdtc9251dh0_pll_set,
};
static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
@@ -297,56 +303,21 @@ static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct fir
return request_firmware(fw, name, fc->dev);
}
-static int lgdt3303_pll_set(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params)
+static int lgdt3303_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct flexcop_device *fc = fe->dvb->priv;
- u8 buf[4];
- struct i2c_msg msg =
- { .addr = 0x61, .flags = 0, .buf = buf, .len = 4 };
- int err;
-
- dvb_pll_configure(&dvb_pll_tdvs_tua6034,buf, params->frequency, 0);
- dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
- __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
- if ((err = i2c_transfer(&fc->i2c_adap, &msg, 1)) != 1) {
- printk(KERN_WARNING "lgdt3303: %s error "
- "(addr %02x <- %02x, err = %i)\n",
- __FUNCTION__, buf[0], buf[1], err);
- if (err < 0)
- return err;
- else
- return -EREMOTEIO;
- }
-
- buf[0] = 0x86 | 0x18;
- buf[1] = 0x50;
- msg.len = 2;
- if ((err = i2c_transfer(&fc->i2c_adap, &msg, 1)) != 1) {
- printk(KERN_WARNING "lgdt3303: %s error "
- "(addr %02x <- %02x, err = %i)\n",
- __FUNCTION__, buf[0], buf[1], err);
- if (err < 0)
- return err;
- else
- return -EREMOTEIO;
- }
-
- return 0;
+ return lg_h06xf_pll_set(fe, &fc->i2c_adap, params);
}
static struct lgdt330x_config air2pc_atsc_hd5000_config = {
.demod_address = 0x59,
.demod_chip = LGDT3303,
.serial_mpeg = 0x04,
- .pll_set = lgdt3303_pll_set,
.clock_polarity_flip = 1,
};
static struct nxt200x_config samsung_tbmv_config = {
.demod_address = 0x0a,
- .pll_address = 0xc2,
- .pll_desc = &dvb_pll_samsung_tbmv,
};
static struct bcm3510_config air2pc_atsc_first_gen_config = {
@@ -354,7 +325,7 @@ static struct bcm3510_config air2pc_atsc_first_gen_config = {
.request_firmware = flexcop_fe_request_firmware,
};
-static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
u8 buf[4];
u32 div;
@@ -371,6 +342,8 @@ static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct d
if (params->frequency < 1550000)
buf[3] |= 0x02;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
@@ -379,9 +352,52 @@ static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct d
static struct mt312_config skystar23_samsung_tbdu18132_config = {
.demod_address = 0x0e,
- .pll_set = skystar23_samsung_tbdu18132_pll_set,
};
+static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct flexcop_device *fc = fe->dvb->priv;
+ u8 buf[4];
+ u16 div;
+ int ret;
+
+/* 62.5 kHz * 10 */
+#define REF_FREQ 625
+#define FREQ_OFFSET 36125
+
+ div = ((fep->frequency/1000 + FREQ_OFFSET ) * 10) / REF_FREQ; // 4 MHz = 4000 KHz
+
+ buf[0] = (u8)( div >> 8) & 0x7f;
+ buf[1] = (u8) div & 0xff;
+
+/* F(osc) = N * Reference Freq. (62.5 kHz)
+ * byte 2 : 0 N14 N13 N12 N11 N10 N9 N8
+ * byte 3 : N7 N6 N5 N4 N3 N2 N1 N0
+ * byte 4 : 1 * * AGD R3 R2 R1 R0
+ * byte 5 : C1 * RE RTS BS4 BS3 BS2 BS1
+ * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */
+ buf[2] = 0x95;
+
+// Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5
+// 47 - 153 0 * 0 0 0 0 0 1 0x01
+// 153 - 430 0 * 0 0 0 0 1 0 0x02
+// 430 - 822 0 * 0 0 1 0 0 0 0x08
+// 822 - 862 1 * 0 0 1 0 0 0 0x88
+
+ if (fep->frequency <= 153000000) buf[3] = 0x01;
+ else if (fep->frequency <= 430000000) buf[3] = 0x02;
+ else if (fep->frequency <= 822000000) buf[3] = 0x08;
+ else buf[3] = 0x88;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]);
+ ret = fc->i2c_request(fc,FC_WRITE,FC_I2C_PORT_TUNER,0x61,buf[0],&buf[1],3);
+ deb_tuner("tuner write returned: %d\n",ret);
+
+ return 0;
+}
static u8 alps_tdee4_stv0297_inittab[] = {
0x80, 0x01,
@@ -490,7 +506,9 @@ int flexcop_frontend_init(struct flexcop_device *fc)
/* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
- ops = fc->fe->ops;
+ ops = &fc->fe->ops;
+
+ ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
ops->set_voltage = flexcop_set_voltage;
@@ -503,16 +521,19 @@ int flexcop_frontend_init(struct flexcop_device *fc)
/* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
if ((fc->fe = mt352_attach(&samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
fc->dev_type = FC_AIR_DVB;
+ fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
} else
/* try the air atsc 2nd generation (nxt2002) */
if ((fc->fe = nxt200x_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
fc->dev_type = FC_AIR_ATSC2;
+ dvb_pll_attach(fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_samsung_tbmv);
info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
} else
/* try the air atsc 3nd generation (lgdt3303) */
if ((fc->fe = lgdt330x_attach(&air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
fc->dev_type = FC_AIR_ATSC3;
+ fc->fe->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
} else
/* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
@@ -523,11 +544,14 @@ int flexcop_frontend_init(struct flexcop_device *fc)
/* try the cable dvb (stv0297) */
if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) {
fc->dev_type = FC_CABLE;
+ fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address);
} else
/* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
if ((fc->fe = vp310_mt312_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
- ops = fc->fe->ops;
+ ops = &fc->fe->ops;
+
+ ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params;
ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
ops->diseqc_send_burst = flexcop_diseqc_send_burst;
@@ -547,7 +571,7 @@ int flexcop_frontend_init(struct flexcop_device *fc)
} else {
if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
err("frontend registration failed!");
- ops = fc->fe->ops;
+ ops = &fc->fe->ops;
if (ops->release != NULL)
ops->release(fc->fe);
fc->fe = NULL;
diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c
index 9bc40bd..f0404170 100644
--- a/drivers/media/dvb/b2c2/flexcop-pci.c
+++ b/drivers/media/dvb/b2c2/flexcop-pci.c
@@ -242,19 +242,16 @@ static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci)
if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[0],FC_DEFAULT_DMA1_BUFSIZE)) != 0)
return ret;
- if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[1],FC_DEFAULT_DMA2_BUFSIZE)) != 0)
- goto dma1_free;
+ if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[1],FC_DEFAULT_DMA2_BUFSIZE)) != 0) {
+ flexcop_dma_free(&fc_pci->dma[0]);
+ return ret;
+ }
flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_MEDIA | FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1);
flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2);
fc_pci->init_state |= FC_PCI_DMA_INIT;
- goto success;
-dma1_free:
- flexcop_dma_free(&fc_pci->dma[0]);
-
-success:
return ret;
}
@@ -303,7 +300,7 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci)
spin_lock_init(&fc_pci->irq_lock);
fc_pci->init_state |= FC_PCI_INIT;
- goto success;
+ return ret;
err_pci_iounmap:
pci_iounmap(fc_pci->pdev, fc_pci->io_mem);
@@ -312,8 +309,6 @@ err_pci_release_regions:
pci_release_regions(fc_pci->pdev);
err_pci_disable_device:
pci_disable_device(fc_pci->pdev);
-
-success:
return ret;
}
@@ -378,14 +373,14 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
INIT_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work, fc_pci);
- goto success;
+ return ret;
+
err_fc_exit:
flexcop_device_exit(fc);
err_pci_exit:
flexcop_pci_exit(fc_pci);
err_kfree:
flexcop_device_kfree(fc);
-success:
return ret;
}
diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c
index 06ec9fff..515954f 100644
--- a/drivers/media/dvb/b2c2/flexcop-usb.c
+++ b/drivers/media/dvb/b2c2/flexcop-usb.c
@@ -433,11 +433,10 @@ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
flexcop_wan_set_speed(fc_usb->fc_dev,FC_WAN_SPEED_8MBITS);
flexcop_sram_ctrl(fc_usb->fc_dev,1,1,1);
- ret = 0;
- goto success;
+ return 0;
+
urb_error:
flexcop_usb_transfer_exit(fc_usb);
-success:
return ret;
}
@@ -515,15 +514,14 @@ static int flexcop_usb_probe(struct usb_interface *intf,
goto err_fc_exit;
info("%s successfully initialized and connected.",DRIVER_NAME);
- ret = 0;
- goto success;
+ return 0;
+
err_fc_exit:
flexcop_device_exit(fc);
err_usb_exit:
flexcop_usb_exit(fc_usb);
err_kfree:
flexcop_device_kfree(fc);
-success:
return ret;
}
diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c
index 56ba524..29ec418 100644
--- a/drivers/media/dvb/b2c2/flexcop.c
+++ b/drivers/media/dvb/b2c2/flexcop.c
@@ -67,7 +67,7 @@ static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
static int flexcop_dvb_init(struct flexcop_device *fc)
{
int ret;
- if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",fc->owner)) < 0) {
+ if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",fc->owner,fc->dev)) < 0) {
err("error registering DVB adapter");
return ret;
}
@@ -116,7 +116,7 @@ static int flexcop_dvb_init(struct flexcop_device *fc)
dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx);
fc->init_state |= FC_STATE_DVB_INIT;
- goto success;
+ return 0;
err_connect_frontend:
fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->mem_frontend);
@@ -129,9 +129,6 @@ err_dmx_dev:
err_dmx:
dvb_unregister_adapter(&fc->dvb_adapter);
return ret;
-
-success:
- return 0;
}
static void flexcop_dvb_exit(struct flexcop_device *fc)
@@ -279,11 +276,10 @@ int flexcop_device_initialize(struct flexcop_device *fc)
flexcop_device_name(fc,"initialization of","complete");
- ret = 0;
- goto success;
+ return 0;
+
error:
flexcop_device_exit(fc);
-success:
return ret;
}
EXPORT_SYMBOL(flexcop_device_initialize);
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
index 5500f8a..761fa6e 100644
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ b/drivers/media/dvb/bt8xx/bt878.c
@@ -63,8 +63,6 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging, default is 0 (off).");
int bt878_num;
struct bt878 bt878[BT878_MAX];
-EXPORT_SYMBOL(bt878_debug);
-EXPORT_SYMBOL(bt878_verbose);
EXPORT_SYMBOL(bt878_num);
EXPORT_SYMBOL(bt878);
@@ -393,7 +391,9 @@ static struct cards card_list[] __devinitdata = {
{ 0x07711461, BTTV_BOARD_AVDVBT_771, "AVermedia AverTV DVB-T 771" },
{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" },
{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
- { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV"},
+ { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV" },
+ { 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini" },
+
{ 0, -1, NULL }
};
@@ -417,6 +417,11 @@ static int __devinit bt878_probe(struct pci_dev *dev,
printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n",
bt878_num);
+ if (bt878_num >= BT878_MAX) {
+ printk(KERN_ERR "bt878: Too many devices inserted\n");
+ result = -ENOMEM;
+ goto fail0;
+ }
if (pci_enable_device(dev))
return -EIO;
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 1cfa5e5..d687a14 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -38,6 +38,10 @@ static unsigned int dst_addons;
module_param(dst_addons, int, 0644);
MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)");
+static unsigned int dst_algo;
+module_param(dst_algo, int, 0644);
+MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)");
+
#define HAS_LOCK 1
#define ATTEMPT_TUNE 2
#define HAS_POWER 4
@@ -47,20 +51,24 @@ MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)");
#define DST_INFO 2
#define DST_DEBUG 3
-#define dprintk(x, y, z, format, arg...) do { \
- if (z) { \
- if ((x > DST_ERROR) && (x > y)) \
- printk(KERN_ERR "%s: " format "\n", __FUNCTION__ , ##arg); \
- else if ((x > DST_NOTICE) && (x > y)) \
- printk(KERN_NOTICE "%s: " format "\n", __FUNCTION__ , ##arg); \
- else if ((x > DST_INFO) && (x > y)) \
- printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ##arg); \
- else if ((x > DST_DEBUG) && (x > y)) \
- printk(KERN_DEBUG "%s: " format "\n", __FUNCTION__ , ##arg); \
- } else { \
- if (x > y) \
- printk(format, ##arg); \
- } \
+#define dprintk(x, y, z, format, arg...) do { \
+ if (z) { \
+ if ((x > DST_ERROR) && (x > y)) \
+ printk(KERN_ERR "dst(%d) %s: " format "\n", \
+ state->bt->nr, __func__ , ##arg); \
+ else if ((x > DST_NOTICE) && (x > y)) \
+ printk(KERN_NOTICE "dst(%d) %s: " format "\n", \
+ state->bt->nr, __func__ , ##arg); \
+ else if ((x > DST_INFO) && (x > y)) \
+ printk(KERN_INFO "dst(%d) %s: " format "\n", \
+ state->bt->nr, __func__ , ##arg); \
+ else if ((x > DST_DEBUG) && (x > y)) \
+ printk(KERN_DEBUG "dst(%d) %s: " format "\n", \
+ state->bt->nr, __func__ , ##arg); \
+ } else { \
+ if (x > y) \
+ printk(format, ##arg); \
+ } \
} while(0)
@@ -110,7 +118,7 @@ int dst_gpio_inb(struct dst_state *state, u8 *result)
*result = 0;
if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) {
- dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)\n", err);
+ dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)", err);
return -EREMOTEIO;
}
*result = (u8) rd_packet.rd.value;
@@ -363,6 +371,17 @@ static int dst_set_freq(struct dst_state *state, u32 freq)
state->tx_tuna[2] = (freq >> 16) & 0xff;
state->tx_tuna[3] = (freq >> 8) & 0xff;
state->tx_tuna[4] = (u8) freq;
+ } else if (state->dst_type == DST_TYPE_IS_ATSC) {
+ freq = freq / 1000;
+ if (freq < 51000 || freq > 858000)
+ return -EINVAL;
+ state->tx_tuna[2] = (freq >> 16) & 0xff;
+ state->tx_tuna[3] = (freq >> 8) & 0xff;
+ state->tx_tuna[4] = (u8) freq;
+ state->tx_tuna[5] = 0x00; /* ATSC */
+ state->tx_tuna[6] = 0x00;
+ if (state->dst_hw_cap & DST_TYPE_HAS_ANALOG)
+ state->tx_tuna[7] = 0x00; /* Digital */
} else
return -EINVAL;
@@ -447,29 +466,41 @@ static int dst_set_symbolrate(struct dst_state *state, u32 srate)
}
dprintk(verbose, DST_INFO, 1, "set symrate %u", srate);
srate /= 1000;
- if (state->type_flags & DST_TYPE_HAS_SYMDIV) {
- sval = srate;
- sval <<= 20;
- do_div(sval, 88000);
- symcalc = (u32) sval;
- dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc);
- state->tx_tuna[5] = (u8) (symcalc >> 12);
- state->tx_tuna[6] = (u8) (symcalc >> 4);
- state->tx_tuna[7] = (u8) (symcalc << 4);
- } else {
- state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f;
- state->tx_tuna[6] = (u8) (srate >> 8);
- state->tx_tuna[7] = (u8) srate;
- }
- state->tx_tuna[8] &= ~0x20;
- if (state->type_flags & DST_TYPE_HAS_OBS_REGS) {
- if (srate > 8000)
- state->tx_tuna[8] |= 0x20;
+ if (state->dst_type == DST_TYPE_IS_SAT) {
+ if (state->type_flags & DST_TYPE_HAS_SYMDIV) {
+ sval = srate;
+ sval <<= 20;
+ do_div(sval, 88000);
+ symcalc = (u32) sval;
+ dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc);
+ state->tx_tuna[5] = (u8) (symcalc >> 12);
+ state->tx_tuna[6] = (u8) (symcalc >> 4);
+ state->tx_tuna[7] = (u8) (symcalc << 4);
+ } else {
+ state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f;
+ state->tx_tuna[6] = (u8) (srate >> 8);
+ state->tx_tuna[7] = (u8) srate;
+ }
+ state->tx_tuna[8] &= ~0x20;
+ if (state->type_flags & DST_TYPE_HAS_OBS_REGS) {
+ if (srate > 8000)
+ state->tx_tuna[8] |= 0x20;
+ }
+ } else if (state->dst_type == DST_TYPE_IS_CABLE) {
+ dprintk(verbose, DST_DEBUG, 1, "%s", state->fw_name);
+ if (!strncmp(state->fw_name, "DCTNEW", 6)) {
+ state->tx_tuna[5] = (u8) (srate >> 8);
+ state->tx_tuna[6] = (u8) srate;
+ state->tx_tuna[7] = 0x00;
+ } else if (!strncmp(state->fw_name, "DCT-CI", 6)) {
+ state->tx_tuna[5] = 0x00;
+ state->tx_tuna[6] = (u8) (srate >> 8);
+ state->tx_tuna[7] = (u8) srate;
+ }
}
return 0;
}
-
static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation)
{
if (state->dst_type != DST_TYPE_IS_CABLE)
@@ -490,7 +521,10 @@ static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulatio
state->tx_tuna[8] = 0x80;
break;
case QAM_256:
- state->tx_tuna[8] = 0x00;
+ if (!strncmp(state->fw_name, "DCTNEW", 6))
+ state->tx_tuna[8] = 0xff;
+ else if (!strncmp(state->fw_name, "DCT-CI", 6))
+ state->tx_tuna[8] = 0x00;
break;
case QPSK:
case QAM_AUTO:
@@ -523,13 +557,19 @@ u8 dst_check_sum(u8 *buf, u32 len)
}
EXPORT_SYMBOL(dst_check_sum);
-static void dst_type_flags_print(u32 type_flags)
+static void dst_type_flags_print(struct dst_state *state)
{
+ u32 type_flags = state->type_flags;
+
dprintk(verbose, DST_ERROR, 0, "DST type flags :");
- if (type_flags & DST_TYPE_HAS_NEWTUNE)
- dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_NEWTUNE);
+ if (type_flags & DST_TYPE_HAS_TS188)
+ dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_TS188);
+ if (type_flags & DST_TYPE_HAS_NEWTUNE_2)
+ dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner 2", DST_TYPE_HAS_NEWTUNE_2);
if (type_flags & DST_TYPE_HAS_TS204)
dprintk(verbose, DST_ERROR, 0, " 0x%x ts204", DST_TYPE_HAS_TS204);
+ if (type_flags & DST_TYPE_HAS_VLF)
+ dprintk(verbose, DST_ERROR, 0, " 0x%x VLF", DST_TYPE_HAS_VLF);
if (type_flags & DST_TYPE_HAS_SYMDIV)
dprintk(verbose, DST_ERROR, 0, " 0x%x symdiv", DST_TYPE_HAS_SYMDIV);
if (type_flags & DST_TYPE_HAS_FW_1)
@@ -542,7 +582,7 @@ static void dst_type_flags_print(u32 type_flags)
}
-static int dst_type_print(u8 type)
+static int dst_type_print(struct dst_state *state, u8 type)
{
char *otype;
switch (type) {
@@ -558,6 +598,10 @@ static int dst_type_print(u8 type)
otype = "cable";
break;
+ case DST_TYPE_IS_ATSC:
+ otype = "atsc";
+ break;
+
default:
dprintk(verbose, DST_INFO, 1, "invalid dst type %d", type);
return -EINVAL;
@@ -567,6 +611,127 @@ static int dst_type_print(u8 type)
return 0;
}
+struct tuner_types tuner_list[] = {
+ {
+ .tuner_type = TUNER_TYPE_L64724,
+ .tuner_name = "L 64724",
+ .board_name = "UNKNOWN",
+ .fw_name = "UNKNOWN"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_STV0299,
+ .tuner_name = "STV 0299",
+ .board_name = "VP1020",
+ .fw_name = "DST-MOT"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_STV0299,
+ .tuner_name = "STV 0299",
+ .board_name = "VP1020",
+ .fw_name = "DST-03T"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_MB86A15,
+ .tuner_name = "MB 86A15",
+ .board_name = "VP1022",
+ .fw_name = "DST-03T"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_MB86A15,
+ .tuner_name = "MB 86A15",
+ .board_name = "VP1025",
+ .fw_name = "DST-03T"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_STV0299,
+ .tuner_name = "STV 0299",
+ .board_name = "VP1030",
+ .fw_name = "DST-CI"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_STV0299,
+ .tuner_name = "STV 0299",
+ .board_name = "VP1030",
+ .fw_name = "DSTMCI"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_UNKNOWN,
+ .tuner_name = "UNKNOWN",
+ .board_name = "VP2021",
+ .fw_name = "DCTNEW"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_UNKNOWN,
+ .tuner_name = "UNKNOWN",
+ .board_name = "VP2030",
+ .fw_name = "DCT-CI"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_UNKNOWN,
+ .tuner_name = "UNKNOWN",
+ .board_name = "VP2031",
+ .fw_name = "DCT-CI"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_UNKNOWN,
+ .tuner_name = "UNKNOWN",
+ .board_name = "VP2040",
+ .fw_name = "DCT-CI"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_UNKNOWN,
+ .tuner_name = "UNKNOWN",
+ .board_name = "VP3020",
+ .fw_name = "DTTFTA"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_UNKNOWN,
+ .tuner_name = "UNKNOWN",
+ .board_name = "VP3021",
+ .fw_name = "DTTFTA"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_TDA10046,
+ .tuner_name = "TDA10046",
+ .board_name = "VP3040",
+ .fw_name = "DTT-CI"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_UNKNOWN,
+ .tuner_name = "UNKNOWN",
+ .board_name = "VP3051",
+ .fw_name = "DTTNXT"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_NXT200x,
+ .tuner_name = "NXT200x",
+ .board_name = "VP3220",
+ .fw_name = "ATSCDI"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_NXT200x,
+ .tuner_name = "NXT200x",
+ .board_name = "VP3250",
+ .fw_name = "ATSCAD"
+ },
+};
+
/*
Known cards list
Satellite
@@ -608,7 +773,8 @@ static struct dst_types dst_tlist[] = {
.offset = 0,
.dst_type = DST_TYPE_IS_SAT,
.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS,
- .dst_feature = 0
+ .dst_feature = 0,
+ .tuner_type = 0
}, /* obsolete */
{
@@ -616,15 +782,17 @@ static struct dst_types dst_tlist[] = {
.offset = 0,
.dst_type = DST_TYPE_IS_SAT,
.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
- .dst_feature = 0
+ .dst_feature = 0,
+ .tuner_type = 0
}, /* obsolete */
{
.device_id = "DST-030",
.offset = 0,
.dst_type = DST_TYPE_IS_SAT,
- .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1,
- .dst_feature = 0
+ .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1,
+ .dst_feature = 0,
+ .tuner_type = 0
}, /* obsolete */
{
@@ -633,7 +801,8 @@ static struct dst_types dst_tlist[] = {
.dst_type = DST_TYPE_IS_SAT,
.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2,
.dst_feature = DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_DISEQC5
- | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO
+ | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO,
+ .tuner_type = TUNER_TYPE_MULTI
},
{
@@ -641,57 +810,63 @@ static struct dst_types dst_tlist[] = {
.offset = 0,
.dst_type = DST_TYPE_IS_SAT,
.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
- .dst_feature = 0
+ .dst_feature = 0,
+ .tuner_type = 0
}, /* obsolete */
{
.device_id = "DST-CI",
.offset = 1,
.dst_type = DST_TYPE_IS_SAT,
- .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1,
- .dst_feature = DST_TYPE_HAS_CA
+ .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_1,
+ .dst_feature = DST_TYPE_HAS_CA,
+ .tuner_type = 0
}, /* An OEM board */
{
.device_id = "DSTMCI",
.offset = 1,
.dst_type = DST_TYPE_IS_SAT,
- .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT,
+ .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT | DST_TYPE_HAS_VLF,
.dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4
- | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC
+ | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC,
+ .tuner_type = TUNER_TYPE_MULTI
},
{
.device_id = "DSTFCI",
.offset = 1,
.dst_type = DST_TYPE_IS_SAT,
- .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1,
- .dst_feature = 0
+ .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1,
+ .dst_feature = 0,
+ .tuner_type = 0
}, /* unknown to vendor */
{
.device_id = "DCT-CI",
.offset = 1,
.dst_type = DST_TYPE_IS_CABLE,
- .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1
- | DST_TYPE_HAS_FW_2,
- .dst_feature = DST_TYPE_HAS_CA
+ .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_VLF,
+ .dst_feature = DST_TYPE_HAS_CA,
+ .tuner_type = 0
},
{
.device_id = "DCTNEW",
.offset = 1,
.dst_type = DST_TYPE_IS_CABLE,
- .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD,
- .dst_feature = 0
+ .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_MULTI_FE,
+ .dst_feature = 0,
+ .tuner_type = 0
},
{
.device_id = "DTT-CI",
.offset = 1,
.dst_type = DST_TYPE_IS_TERR,
- .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE,
- .dst_feature = DST_TYPE_HAS_CA
+ .type_flags = DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_VLF,
+ .dst_feature = DST_TYPE_HAS_CA,
+ .tuner_type = 0
},
{
@@ -699,7 +874,8 @@ static struct dst_types dst_tlist[] = {
.offset = 1,
.dst_type = DST_TYPE_IS_TERR,
.type_flags = DST_TYPE_HAS_FW_2,
- .dst_feature = 0
+ .dst_feature = 0,
+ .tuner_type = 0
},
{
@@ -707,7 +883,8 @@ static struct dst_types dst_tlist[] = {
.offset = 1,
.dst_type = DST_TYPE_IS_TERR,
.type_flags = DST_TYPE_HAS_FW_2,
- .dst_feature = DST_TYPE_HAS_ANALOG
+ .dst_feature = DST_TYPE_HAS_ANALOG,
+ .tuner_type = 0
},
{
@@ -715,15 +892,17 @@ static struct dst_types dst_tlist[] = {
.offset = 1,
.dst_type = DST_TYPE_IS_ATSC,
.type_flags = DST_TYPE_HAS_FW_2,
- .dst_feature = 0
+ .dst_feature = 0,
+ .tuner_type = 0
},
{
.device_id = "ATSCAD",
.offset = 1,
.dst_type = DST_TYPE_IS_ATSC,
- .type_flags = DST_TYPE_HAS_FW_2,
- .dst_feature = 0
+ .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD,
+ .dst_feature = DST_TYPE_HAS_MAC | DST_TYPE_HAS_ANALOG,
+ .tuner_type = 0
},
{ }
@@ -768,6 +947,9 @@ static int dst_fw_ver(struct dst_state *state)
static int dst_card_type(struct dst_state *state)
{
+ int j;
+ struct tuner_types *p_tuner_list = NULL;
+
u8 get_type[] = { 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
get_type[7] = dst_check_sum(get_type, 7);
if (dst_command(state, get_type, 8) < 0) {
@@ -775,9 +957,17 @@ static int dst_card_type(struct dst_state *state)
return -1;
}
memset(&state->card_info, '\0', 8);
- memcpy(&state->card_info, &state->rxbuffer, 8);
+ memcpy(&state->card_info, &state->rxbuffer, 7);
dprintk(verbose, DST_ERROR, 1, "Device Model=[%s]", &state->card_info[0]);
+ for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) {
+ if (!strcmp(&state->card_info[0], p_tuner_list->board_name)) {
+ state->tuner_type = p_tuner_list->tuner_type;
+ dprintk(verbose, DST_ERROR, 1, "DST has [%s] tuner, tuner type=[%d]",
+ p_tuner_list->tuner_name, p_tuner_list->tuner_type);
+ }
+ }
+
return 0;
}
@@ -790,12 +980,64 @@ static int dst_get_vendor(struct dst_state *state)
return -1;
}
memset(&state->vendor, '\0', 8);
- memcpy(&state->vendor, &state->rxbuffer, 8);
+ memcpy(&state->vendor, &state->rxbuffer, 7);
dprintk(verbose, DST_ERROR, 1, "Vendor=[%s]", &state->vendor[0]);
return 0;
}
+static void debug_dst_buffer(struct dst_state *state)
+{
+ int i;
+
+ if (verbose > 2) {
+ printk("%s: [", __func__);
+ for (i = 0; i < 8; i++)
+ printk(" %02x", state->rxbuffer[i]);
+ printk("]\n");
+ }
+}
+
+static int dst_check_stv0299(struct dst_state *state)
+{
+ u8 check_stv0299[] = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ check_stv0299[7] = dst_check_sum(check_stv0299, 7);
+ if (dst_command(state, check_stv0299, 8) < 0) {
+ dprintk(verbose, DST_ERROR, 1, "Cmd=[0x04] failed");
+ return -1;
+ }
+ debug_dst_buffer(state);
+
+ if (memcmp(&check_stv0299, &state->rxbuffer, 8)) {
+ dprintk(verbose, DST_ERROR, 1, "Found a STV0299 NIM");
+ state->tuner_type = TUNER_TYPE_STV0299;
+ return 0;
+ }
+
+ return -1;
+}
+
+static int dst_check_mb86a15(struct dst_state *state)
+{
+ u8 check_mb86a15[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ check_mb86a15[7] = dst_check_sum(check_mb86a15, 7);
+ if (dst_command(state, check_mb86a15, 8) < 0) {
+ dprintk(verbose, DST_ERROR, 1, "Cmd=[0x10], failed");
+ return -1;
+ }
+ debug_dst_buffer(state);
+
+ if (memcmp(&check_mb86a15, &state->rxbuffer, 8) < 0) {
+ dprintk(verbose, DST_ERROR, 1, "Found a MB86A15 NIM");
+ state->tuner_type = TUNER_TYPE_MB86A15;
+ return 0;
+ }
+
+ return -1;
+}
+
static int dst_get_tuner_info(struct dst_state *state)
{
u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
@@ -803,60 +1045,59 @@ static int dst_get_tuner_info(struct dst_state *state)
get_tuner_1[7] = dst_check_sum(get_tuner_1, 7);
get_tuner_2[7] = dst_check_sum(get_tuner_2, 7);
+ dprintk(verbose, DST_ERROR, 1, "DST TYpe = MULTI FE");
if (state->type_flags & DST_TYPE_HAS_MULTI_FE) {
- if (dst_command(state, get_tuner_2, 8) < 0) {
- dprintk(verbose, DST_INFO, 1, "Unsupported Command");
- return -1;
+ if (dst_command(state, get_tuner_1, 8) < 0) {
+ dprintk(verbose, DST_INFO, 1, "Cmd=[0x13], Unsupported");
+ goto force;
}
} else {
- if (dst_command(state, get_tuner_1, 8) < 0) {
- dprintk(verbose, DST_INFO, 1, "Unsupported Command");
- return -1;
+ if (dst_command(state, get_tuner_2, 8) < 0) {
+ dprintk(verbose, DST_INFO, 1, "Cmd=[0xb], Unsupported");
+ goto force;
}
}
memset(&state->board_info, '\0', 8);
memcpy(&state->board_info, &state->rxbuffer, 8);
if (state->type_flags & DST_TYPE_HAS_MULTI_FE) {
- if (state->board_info[1] == 0x0b) {
- if (state->type_flags & DST_TYPE_HAS_TS204)
- state->type_flags &= ~DST_TYPE_HAS_TS204;
- state->type_flags |= DST_TYPE_HAS_NEWTUNE;
- dprintk(verbose, DST_INFO, 1, "DST type has TS=188");
- } else {
- if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
- state->type_flags &= ~DST_TYPE_HAS_NEWTUNE;
- state->type_flags |= DST_TYPE_HAS_TS204;
- dprintk(verbose, DST_INFO, 1, "DST type has TS=204");
- }
- } else {
- if (state->board_info[0] == 0xbc) {
- if (state->type_flags & DST_TYPE_HAS_TS204)
- state->type_flags &= ~DST_TYPE_HAS_TS204;
- state->type_flags |= DST_TYPE_HAS_NEWTUNE;
- dprintk(verbose, DST_INFO, 1, "DST type has TS=188, Daughterboard=[%d]", state->board_info[1]);
-
- } else if (state->board_info[0] == 0xcc) {
- if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
- state->type_flags &= ~DST_TYPE_HAS_NEWTUNE;
- state->type_flags |= DST_TYPE_HAS_TS204;
- dprintk(verbose, DST_INFO, 1, "DST type has TS=204 Daughterboard=[%d]", state->board_info[1]);
+ dprintk(verbose, DST_ERROR, 1, "DST type has TS=188");
+ }
+ if (state->board_info[0] == 0xbc) {
+ if (state->type_flags != DST_TYPE_IS_ATSC)
+ state->type_flags |= DST_TYPE_HAS_TS188;
+ else
+ state->type_flags |= DST_TYPE_HAS_NEWTUNE_2;
+
+ if (state->board_info[1] == 0x01) {
+ state->dst_hw_cap |= DST_TYPE_HAS_DBOARD;
+ dprintk(verbose, DST_ERROR, 1, "DST has Daughterboard");
}
}
return 0;
+force:
+ if (!strncmp(state->fw_name, "DCT-CI", 6)) {
+ state->type_flags |= DST_TYPE_HAS_TS204;
+ dprintk(verbose, DST_ERROR, 1, "Forcing [%s] to TS188", state->fw_name);
+ }
+
+ return -1;
}
static int dst_get_device_id(struct dst_state *state)
{
u8 reply;
- int i;
- struct dst_types *p_dst_type;
+ int i, j;
+ struct dst_types *p_dst_type = NULL;
+ struct tuner_types *p_tuner_list = NULL;
+
u8 use_dst_type = 0;
u32 use_type_flags = 0;
static u8 device_type[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
+ state->tuner_type = 0;
device_type[7] = dst_check_sum(device_type, 7);
if (write_dst(state, device_type, FIXED_COMM))
@@ -888,8 +1129,34 @@ static int dst_get_device_id(struct dst_state *state)
/* Card capabilities */
state->dst_hw_cap = p_dst_type->dst_feature;
- dprintk(verbose, DST_ERROR, 1, "Recognise [%s]\n", p_dst_type->device_id);
-
+ dprintk(verbose, DST_ERROR, 1, "Recognise [%s]", p_dst_type->device_id);
+ strncpy(&state->fw_name[0], p_dst_type->device_id, 6);
+ /* Multiple tuners */
+ if (p_dst_type->tuner_type & TUNER_TYPE_MULTI) {
+ switch (use_dst_type) {
+ case DST_TYPE_IS_SAT:
+ /* STV0299 check */
+ if (dst_check_stv0299(state) < 0) {
+ dprintk(verbose, DST_ERROR, 1, "Unsupported");
+ state->tuner_type = TUNER_TYPE_MB86A15;
+ }
+ break;
+ default:
+ break;
+ }
+ if (dst_check_mb86a15(state) < 0)
+ dprintk(verbose, DST_ERROR, 1, "Unsupported");
+ /* Single tuner */
+ } else {
+ state->tuner_type = p_dst_type->tuner_type;
+ }
+ for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) {
+ if (!(strncmp(p_dst_type->device_id, p_tuner_list->fw_name, 7)) &&
+ p_tuner_list->tuner_type == state->tuner_type) {
+ dprintk(verbose, DST_ERROR, 1, "[%s] has a [%s]",
+ p_dst_type->device_id, p_tuner_list->tuner_name);
+ }
+ }
break;
}
}
@@ -900,10 +1167,10 @@ static int dst_get_device_id(struct dst_state *state)
use_dst_type = DST_TYPE_IS_SAT;
use_type_flags = DST_TYPE_HAS_SYMDIV;
}
- dst_type_print(use_dst_type);
+ dst_type_print(state, use_dst_type);
state->type_flags = use_type_flags;
state->dst_type = use_dst_type;
- dst_type_flags_print(state->type_flags);
+ dst_type_flags_print(state);
return 0;
}
@@ -911,15 +1178,15 @@ static int dst_get_device_id(struct dst_state *state)
static int dst_probe(struct dst_state *state)
{
mutex_init(&state->dst_mutex);
- if ((rdc_8820_reset(state)) < 0) {
- dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed.");
- return -1;
- }
- if (dst_addons & DST_TYPE_HAS_CA)
+ if (dst_addons & DST_TYPE_HAS_CA) {
+ if ((rdc_8820_reset(state)) < 0) {
+ dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed.");
+ return -1;
+ }
msleep(4000);
- else
+ } else {
msleep(100);
-
+ }
if ((dst_comm_init(state)) < 0) {
dprintk(verbose, DST_ERROR, 1, "DST Initialization Failed.");
return -1;
@@ -931,7 +1198,6 @@ static int dst_probe(struct dst_state *state)
}
if (dst_get_mac(state) < 0) {
dprintk(verbose, DST_INFO, 1, "MAC: Unsupported command");
- return 0;
}
if ((state->type_flags & DST_TYPE_HAS_MULTI_FE) || (state->type_flags & DST_TYPE_HAS_FW_BUILD)) {
if (dst_get_tuner_info(state) < 0)
@@ -1048,6 +1314,10 @@ static int dst_get_signal(struct dst_state *state)
state->decode_lock = (state->rxbuffer[1]) ? 1 : 0;
state->decode_strength = state->rxbuffer[4] << 8;
state->decode_snr = state->rxbuffer[3] << 8;
+ } else if (state->dst_type == DST_TYPE_IS_ATSC) {
+ state->decode_lock = (state->rxbuffer[6] == 0x00) ? 1 : 0;
+ state->decode_strength = state->rxbuffer[4] << 8;
+ state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3];
}
state->cur_jiff = jiffies;
}
@@ -1078,8 +1348,9 @@ static int dst_get_tuna(struct dst_state *state)
state->diseq_flags &= ~(HAS_LOCK);
if (!dst_wait_dst_ready(state, NO_DELAY))
return -EIO;
- if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
- /* how to get variable length reply ???? */
+ if ((state->type_flags & DST_TYPE_HAS_VLF) &&
+ !(state->dst_type == DST_TYPE_IS_ATSC))
+
retval = read_dst(state, state->rx_tuna, 10);
else
retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM);
@@ -1087,7 +1358,10 @@ static int dst_get_tuna(struct dst_state *state)
dprintk(verbose, DST_DEBUG, 1, "read not successful");
return retval;
}
- if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+ if ((state->type_flags & DST_TYPE_HAS_VLF) &&
+ !(state->dst_type == DST_TYPE_IS_CABLE) &&
+ !(state->dst_type == DST_TYPE_IS_ATSC)) {
+
if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) {
dprintk(verbose, DST_INFO, 1, "checksum failure ? ");
return -EIO;
@@ -1133,7 +1407,10 @@ static int dst_write_tuna(struct dvb_frontend *fe)
dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed.");
goto error;
}
- if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+// if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+ if ((state->type_flags & DST_TYPE_HAS_VLF) &&
+ (!(state->dst_type == DST_TYPE_IS_ATSC))) {
+
state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9);
retval = write_dst(state, &state->tx_tuna[0], 10);
} else {
@@ -1189,9 +1466,12 @@ static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd
if (state->dst_type != DST_TYPE_IS_SAT)
return 0;
- if (cmd->msg_len == 0 || cmd->msg_len > 4)
+ if (cmd->msg_len > 0 && cmd->msg_len < 5)
+ memcpy(&paket[3], cmd->msg, cmd->msg_len);
+ else if (cmd->msg_len == 5 && state->dst_hw_cap & DST_TYPE_HAS_DISEQC5)
+ memcpy(&paket[2], cmd->msg, cmd->msg_len);
+ else
return -EINVAL;
- memcpy(&paket[3], cmd->msg, cmd->msg_len);
paket[7] = dst_check_sum(&paket[0], 7);
dst_command(state, paket, 8);
return 0;
@@ -1287,8 +1567,9 @@ static int dst_init(struct dvb_frontend *fe)
static u8 sat_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x55, 0xbd, 0x50, 0x00, 0x00 };
static u8 ter_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
static u8 ter_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
- static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
static u8 cab_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
+ static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
+ static u8 atsc_tuner[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
state->inversion = INVERSION_OFF;
state->voltage = SEC_VOLTAGE_13;
@@ -1298,11 +1579,13 @@ static int dst_init(struct dvb_frontend *fe)
state->bandwidth = BANDWIDTH_7_MHZ;
state->cur_jiff = jiffies;
if (state->dst_type == DST_TYPE_IS_SAT)
- memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204));
+ memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204));
else if (state->dst_type == DST_TYPE_IS_TERR)
- memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204));
+ memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204));
else if (state->dst_type == DST_TYPE_IS_CABLE)
- memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204));
+ memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204));
+ else if (state->dst_type == DST_TYPE_IS_ATSC)
+ memcpy(state->tx_tuna, atsc_tuner, sizeof (atsc_tuner));
return 0;
}
@@ -1341,7 +1624,36 @@ static int dst_read_snr(struct dvb_frontend *fe, u16 *snr)
return 0;
}
-static int dst_set_frontend(struct dvb_frontend* fe,
+static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+{
+ struct dst_state *state = fe->demodulator_priv;
+
+ if (p != NULL) {
+ dst_set_freq(state, p->frequency);
+ dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
+
+ if (state->dst_type == DST_TYPE_IS_SAT) {
+ if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
+ dst_set_inversion(state, p->inversion);
+ dst_set_fec(state, p->u.qpsk.fec_inner);
+ dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
+ dst_set_polarization(state);
+ dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate);
+
+ } else if (state->dst_type == DST_TYPE_IS_TERR)
+ dst_set_bandwidth(state, p->u.ofdm.bandwidth);
+ else if (state->dst_type == DST_TYPE_IS_CABLE) {
+ dst_set_fec(state, p->u.qam.fec_inner);
+ dst_set_symbolrate(state, p->u.qam.symbol_rate);
+ dst_set_modulation(state, p->u.qam.modulation);
+ }
+ dst_write_tuna(fe);
+ }
+
+ return 0;
+}
+
+static int dst_tune_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters* p,
unsigned int mode_flags,
int *delay,
@@ -1378,6 +1690,11 @@ static int dst_set_frontend(struct dvb_frontend* fe,
return 0;
}
+static int dst_get_tuning_algo(struct dvb_frontend *fe)
+{
+ return dst_algo;
+}
+
static int dst_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
{
struct dst_state *state = fe->demodulator_priv;
@@ -1408,6 +1725,7 @@ static void dst_release(struct dvb_frontend *fe)
static struct dvb_frontend_ops dst_dvbt_ops;
static struct dvb_frontend_ops dst_dvbs_ops;
static struct dvb_frontend_ops dst_dvbc_ops;
+static struct dvb_frontend_ops dst_atsc_ops;
struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter)
{
@@ -1417,24 +1735,25 @@ struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_ad
return NULL;
}
/* determine settings based on type */
+ /* create dvb_frontend */
switch (state->dst_type) {
case DST_TYPE_IS_TERR:
- memcpy(&state->ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops));
+ memcpy(&state->frontend.ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops));
break;
case DST_TYPE_IS_CABLE:
- memcpy(&state->ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops));
+ memcpy(&state->frontend.ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops));
break;
case DST_TYPE_IS_SAT:
- memcpy(&state->ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops));
+ memcpy(&state->frontend.ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops));
+ break;
+ case DST_TYPE_IS_ATSC:
+ memcpy(&state->frontend.ops, &dst_atsc_ops, sizeof(struct dvb_frontend_ops));
break;
default:
dprintk(verbose, DST_ERROR, 1, "unknown DST type. please report to the LinuxTV.org DVB mailinglist.");
kfree(state);
return NULL;
}
-
- /* create dvb_frontend */
- state->frontend.ops = &state->ops;
state->frontend.demodulator_priv = state;
return state; /* Manu (DST is a card not a frontend) */
@@ -1455,8 +1774,10 @@ static struct dvb_frontend_ops dst_dvbt_ops = {
.release = dst_release,
.init = dst_init,
- .tune = dst_set_frontend,
+ .tune = dst_tune_frontend,
+ .set_frontend = dst_set_frontend,
.get_frontend = dst_get_frontend,
+ .get_frontend_algo = dst_get_tuning_algo,
.read_status = dst_read_status,
.read_signal_strength = dst_read_signal_strength,
.read_snr = dst_read_snr,
@@ -1479,8 +1800,10 @@ static struct dvb_frontend_ops dst_dvbs_ops = {
.release = dst_release,
.init = dst_init,
- .tune = dst_set_frontend,
+ .tune = dst_tune_frontend,
+ .set_frontend = dst_set_frontend,
.get_frontend = dst_get_frontend,
+ .get_frontend_algo = dst_get_tuning_algo,
.read_status = dst_read_status,
.read_signal_strength = dst_read_signal_strength,
.read_snr = dst_read_snr,
@@ -1506,13 +1829,38 @@ static struct dvb_frontend_ops dst_dvbc_ops = {
.release = dst_release,
.init = dst_init,
- .tune = dst_set_frontend,
+ .tune = dst_tune_frontend,
+ .set_frontend = dst_set_frontend,
+ .get_frontend = dst_get_frontend,
+ .get_frontend_algo = dst_get_tuning_algo,
+ .read_status = dst_read_status,
+ .read_signal_strength = dst_read_signal_strength,
+ .read_snr = dst_read_snr,
+};
+
+static struct dvb_frontend_ops dst_atsc_ops = {
+ .info = {
+ .name = "DST ATSC",
+ .type = FE_ATSC,
+ .frequency_stepsize = 62500,
+ .frequency_min = 510000000,
+ .frequency_max = 858000000,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+ },
+
+ .release = dst_release,
+ .init = dst_init,
+ .tune = dst_tune_frontend,
+ .set_frontend = dst_set_frontend,
.get_frontend = dst_get_frontend,
+ .get_frontend_algo = dst_get_tuning_algo,
.read_status = dst_read_status,
.read_signal_strength = dst_read_signal_strength,
.read_snr = dst_read_snr,
};
-MODULE_DESCRIPTION("DST DVB-S/T/C Combo Frontend driver");
+MODULE_DESCRIPTION("DST DVB-S/T/C/ATSC Combo Frontend driver");
MODULE_AUTHOR("Jamie Honan, Manu Abraham");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
index f6b49a8..fa923b9 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -68,6 +68,13 @@ static int ca_set_pid(void)
return -EOPNOTSUPP;
}
+static void put_command_and_length(u8 *data, int command, int length)
+{
+ data[0] = (command >> 16) & 0xff;
+ data[1] = (command >> 8) & 0xff;
+ data[2] = command & 0xff;
+ data[3] = length;
+}
static void put_checksum(u8 *check_string, int length)
{
@@ -124,15 +131,18 @@ static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string,
u8 dst_ca_comm_err = 0;
while (dst_ca_comm_err < RETRIES) {
- dst_comm_init(state);
dprintk(verbose, DST_CA_NOTICE, 1, " Put Command");
if (dst_ci_command(state, data, ca_string, len, read)) { // If error
dst_error_recovery(state);
dst_ca_comm_err++; // work required here.
+ } else {
+ break;
}
- break;
}
+ if(dst_ca_comm_err == RETRIES)
+ return -1;
+
return 0;
}
@@ -140,6 +150,7 @@ static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string,
static int ca_get_app_info(struct dst_state *state)
{
+ int length, str_length;
static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff};
put_checksum(&command[0], command[0]);
@@ -154,6 +165,68 @@ static int ca_get_app_info(struct dst_state *state)
(state->messages[10] << 8) | state->messages[11], __FUNCTION__, (char *)(&state->messages[12]));
dprintk(verbose, DST_CA_INFO, 1, " ==================================================================================================");
+ // Transform dst message to correct application_info message
+ length = state->messages[5];
+ str_length = length - 6;
+ if (str_length < 0) {
+ str_length = 0;
+ dprintk(verbose, DST_CA_ERROR, 1, "Invalid string length returned in ca_get_app_info(). Recovering.");
+ }
+
+ // First, the command and length fields
+ put_command_and_length(&state->messages[0], CA_APP_INFO, length);
+
+ // Copy application_type, application_manufacturer and manufacturer_code
+ memcpy(&state->messages[4], &state->messages[7], 5);
+
+ // Set string length and copy string
+ state->messages[9] = str_length;
+ memcpy(&state->messages[10], &state->messages[12], str_length);
+
+ return 0;
+}
+
+static int ca_get_ca_info(struct dst_state *state)
+{
+ int srcPtr, dstPtr, i, num_ids;
+ static u8 slot_command[8] = {0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff};
+ const int in_system_id_pos = 8, out_system_id_pos = 4, in_num_ids_pos = 7;
+
+ put_checksum(&slot_command[0], slot_command[0]);
+ if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
+ return -1;
+ }
+ dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
+
+ // Print raw data
+ dprintk(verbose, DST_CA_INFO, 0, " DST data = [");
+ for (i = 0; i < state->messages[0] + 1; i++) {
+ dprintk(verbose, DST_CA_INFO, 0, " 0x%02x", state->messages[i]);
+ }
+ dprintk(verbose, DST_CA_INFO, 0, "]\n");
+
+ // Set the command and length of the output
+ num_ids = state->messages[in_num_ids_pos];
+ if (num_ids >= 100) {
+ num_ids = 100;
+ dprintk(verbose, DST_CA_ERROR, 1, "Invalid number of ids (>100). Recovering.");
+ }
+ put_command_and_length(&state->messages[0], CA_INFO, num_ids * 2);
+
+ dprintk(verbose, DST_CA_INFO, 0, " CA_INFO = [");
+ srcPtr = in_system_id_pos;
+ dstPtr = out_system_id_pos;
+ for(i = 0; i < num_ids; i++) {
+ dprintk(verbose, DST_CA_INFO, 0, " 0x%02x%02x", state->messages[srcPtr + 0], state->messages[srcPtr + 1]);
+ // Append to output
+ state->messages[dstPtr + 0] = state->messages[srcPtr + 0];
+ state->messages[dstPtr + 1] = state->messages[srcPtr + 1];
+ srcPtr += 2;
+ dstPtr += 2;
+ }
+ dprintk(verbose, DST_CA_INFO, 0, "]\n");
+
return 0;
}
@@ -174,7 +247,7 @@ static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps,
dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]);
dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
- for (i = 0; i < 8; i++)
+ for (i = 0; i < slot_cap[0] + 1; i++)
dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]);
dprintk(verbose, DST_CA_INFO, 0, "\n");
@@ -260,6 +333,11 @@ static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message,
if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
return -EFAULT;
break;
+ case CA_INFO:
+ memcpy(p_ca_message->msg, state->messages, 128);
+ if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
+ return -EFAULT;
+ break;
}
}
@@ -302,7 +380,7 @@ static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 l
rdc_reset_state(state);
return -1;
}
- dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command succes.");
+ dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success.");
return 0;
}
@@ -340,6 +418,7 @@ static int debug_string(u8 *msg, u32 length, u32 offset)
return 0;
}
+
static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
{
u32 length = 0;
@@ -455,6 +534,16 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message,
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !");
break;
+ case CA_INFO_ENQUIRY:
+ dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information");
+
+ if ((ca_get_ca_info(state)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !");
+ result = -1;
+ goto free_mem_and_exit;
+ }
+ dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !");
+ break;
}
}
free_mem_and_exit:
@@ -473,18 +562,15 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd
void __user *arg = (void __user *)ioctl_arg;
int result = 0;
- if ((p_ca_message = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
- dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
- return -ENOMEM;
- }
- if ((p_ca_slot_info = (struct ca_slot_info *) kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL)) == NULL) {
+ p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL);
+ p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL);
+ p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL);
+ if (!p_ca_message || !p_ca_slot_info || !p_ca_caps) {
dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
- return -ENOMEM;
- }
- if ((p_ca_caps = (struct ca_caps *) kmalloc(sizeof (struct ca_caps), GFP_KERNEL)) == NULL) {
- dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
- return -ENOMEM;
+ result = -ENOMEM;
+ goto free_mem_and_exit;
}
+
/* We have now only the standard ioctl's, the driver is upposed to handle internals. */
switch (cmd) {
case CA_SEND_MSG:
@@ -582,7 +668,7 @@ static int dst_ca_release(struct inode *inode, struct file *file)
static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
{
- int bytes_read = 0;
+ ssize_t bytes_read = 0;
dprintk(verbose, DST_CA_DEBUG, 1, " Device read.");
diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h
index 51d4e04..0677b04 100644
--- a/drivers/media/dvb/bt8xx/dst_common.h
+++ b/drivers/media/dvb/bt8xx/dst_common.h
@@ -42,7 +42,7 @@
#define DST_TYPE_IS_CABLE 2
#define DST_TYPE_IS_ATSC 3
-#define DST_TYPE_HAS_NEWTUNE 1
+#define DST_TYPE_HAS_TS188 1
#define DST_TYPE_HAS_TS204 2
#define DST_TYPE_HAS_SYMDIV 4
#define DST_TYPE_HAS_FW_1 8
@@ -52,6 +52,9 @@
#define DST_TYPE_HAS_OBS_REGS 128
#define DST_TYPE_HAS_INC_COUNT 256
#define DST_TYPE_HAS_MULTI_FE 512
+#define DST_TYPE_HAS_NEWTUNE_2 1024
+#define DST_TYPE_HAS_DBOARD 2048
+#define DST_TYPE_HAS_VLF 4096
/* Card capability list */
@@ -64,6 +67,20 @@
#define DST_TYPE_HAS_ANALOG 64 /* Analog inputs */
#define DST_TYPE_HAS_SESSION 128
+#define TUNER_TYPE_MULTI 1
+#define TUNER_TYPE_UNKNOWN 2
+/* DVB-S */
+#define TUNER_TYPE_L64724 4
+#define TUNER_TYPE_STV0299 8
+#define TUNER_TYPE_MB86A15 16
+
+/* DVB-T */
+#define TUNER_TYPE_TDA10046 32
+
+/* ATSC */
+#define TUNER_TYPE_NXT200x 64
+
+
#define RDC_8820_PIO_0_DISABLE 0
#define RDC_8820_PIO_0_ENABLE 1
#define RDC_8820_INT 2
@@ -84,8 +101,6 @@ struct dst_state {
struct bt878* bt;
- struct dvb_frontend_ops ops;
-
/* configuration settings */
const struct dst_config* config;
@@ -121,8 +136,17 @@ struct dst_state {
u8 card_info[8];
u8 vendor[8];
u8 board_info[8];
-
+ u32 tuner_type;
+ char *tuner_name;
struct mutex dst_mutex;
+ u8 fw_name[8];
+};
+
+struct tuner_types {
+ u32 tuner_type;
+ char *tuner_name;
+ char *board_name;
+ char *fw_name;
};
struct dst_types {
@@ -131,6 +155,7 @@ struct dst_types {
u8 dst_type;
u32 type_flags;
u32 dst_feature;
+ u32 tuner_type;
};
struct dst_config
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index ccc7b2e..b715b97 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -147,12 +147,15 @@ static int thomson_dtt7579_demod_init(struct dvb_frontend* fe)
return 0;
}
-static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
{
u32 div;
unsigned char bs = 0;
unsigned char cp = 0;
+ if (buf_len < 5)
+ return -EINVAL;
+
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
if (params->frequency < 542000000)
@@ -169,22 +172,25 @@ static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_
else
bs = 0x08;
- pllbuf[0] = 0xc0; // Note: non-linux standard PLL i2c address
+ pllbuf[0] = 0x60;
pllbuf[1] = div >> 8;
pllbuf[2] = div & 0xff;
pllbuf[3] = cp;
pllbuf[4] = bs;
- return 0;
+ return 5;
}
static struct mt352_config thomson_dtt7579_config = {
.demod_address = 0x0f,
.demod_init = thomson_dtt7579_demod_init,
- .pll_set = thomson_dtt7579_pll_set,
};
-static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static struct zl10353_config thomson_dtt7579_zl10353_config = {
+ .demod_address = 0x0f,
+};
+
+static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
u32 freq = params->frequency;
@@ -237,7 +243,7 @@ static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_paramete
return 0;
}
-static int pinnsat_pll_init(struct dvb_frontend* fe)
+static int pinnsat_tuner_init(struct dvb_frontend* fe)
{
struct dvb_bt8xx_card *card = fe->dvb->priv;
@@ -247,7 +253,7 @@ static int pinnsat_pll_init(struct dvb_frontend* fe)
return 0;
}
-static int pinnsat_pll_sleep(struct dvb_frontend* fe)
+static int pinnsat_tuner_sleep(struct dvb_frontend* fe)
{
struct dvb_bt8xx_card *card = fe->dvb->priv;
@@ -258,12 +264,9 @@ static int pinnsat_pll_sleep(struct dvb_frontend* fe)
static struct cx24110_config pctvsat_config = {
.demod_address = 0x55,
- .pll_init = pinnsat_pll_init,
- .pll_set = cx24108_pll_set,
- .pll_sleep = pinnsat_pll_sleep,
};
-static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
u8 cfg, cpump, band_select;
@@ -297,6 +300,8 @@ static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_front
data[2] = ((div >> 10) & 0x60) | cfg;
data[3] = (cpump << 6) | band_select;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(card->i2c_adapter, &msg, 1);
return (div * 166666 - 36000000);
}
@@ -310,7 +315,6 @@ static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const s
static struct sp887x_config microtune_mt7202dtf_config = {
.demod_address = 0x70,
- .pll_set = microtune_mt7202dtf_pll_set,
.request_firmware = microtune_mt7202dtf_request_firmware,
};
@@ -337,12 +341,14 @@ static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
return 0;
}
-static int advbt771_samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
{
u32 div;
unsigned char bs = 0;
unsigned char cp = 0;
+ if (buf_len < 5) return -EINVAL;
+
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
if (params->frequency < 150000000)
@@ -383,19 +389,18 @@ static int advbt771_samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct
else
bs = 0x08;
- pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address
+ pllbuf[0] = 0x61;
pllbuf[1] = div >> 8;
pllbuf[2] = div & 0xff;
pllbuf[3] = cp;
pllbuf[4] = bs;
- return 0;
+ return 5;
}
static struct mt352_config advbt771_samsung_tdtc9251dh0_config = {
.demod_address = 0x0f,
.demod_init = advbt771_samsung_tdtc9251dh0_demod_init,
- .pll_set = advbt771_samsung_tdtc9251dh0_pll_set,
};
static struct dst_config dst_config = {
@@ -455,7 +460,7 @@ static struct or51211_config or51211_config = {
.sleep = or51211_sleep,
};
-static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
u8 buf[4];
@@ -478,6 +483,8 @@ static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_fronten
else
return -EINVAL;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(card->i2c_adapter, &msg, 1);
return 0;
}
@@ -485,7 +492,6 @@ static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_fronten
static struct nxt6000_config vp3021_alps_tded4_config = {
.demod_address = 0x0a,
.clock_inversion = 1,
- .pll_set = vp3021_alps_tded4_pll_set,
};
static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe)
@@ -506,14 +512,17 @@ static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe)
return 0;
}
-static int digitv_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
{
u32 div;
struct dvb_ofdm_parameters *op = &params->u.ofdm;
+ if (buf_len < 5)
+ return -EINVAL;
+
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
- pllbuf[0] = 0xc2;
+ pllbuf[0] = 0x61;
pllbuf[1] = (div >> 8) & 0x7F;
pllbuf[2] = div & 0xFF;
pllbuf[3] = 0x85;
@@ -530,7 +539,7 @@ static int digitv_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_fronten
if (op->bandwidth == 8)
pllbuf[4] |= 0x04;
- return 0;
+ return 5;
}
static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt)
@@ -557,43 +566,18 @@ static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt)
static struct mt352_config digitv_alps_tded4_config = {
.demod_address = 0x0a,
.demod_init = digitv_alps_tded4_demod_init,
- .pll_set = digitv_alps_tded4_pll_set,
};
-static int tdvs_tua6034_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int tdvs_tua6034_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
- u8 buf[4];
- struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
- int err;
-
- dvb_pll_configure(&dvb_pll_tdvs_tua6034, buf, params->frequency, 0);
- dprintk("%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
- __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
- if ((err = i2c_transfer(card->i2c_adapter, &msg, 1)) != 1) {
- printk(KERN_WARNING "dvb-bt8xx: %s error "
- "(addr %02x <- %02x, err = %i)\n",
- __FUNCTION__, buf[0], buf[1], err);
- if (err < 0)
- return err;
- else
- return -EREMOTEIO;
- }
-
- /* Set the Auxiliary Byte. */
- buf[2] &= ~0x20;
- buf[2] |= 0x18;
- buf[3] = 0x50;
- i2c_transfer(card->i2c_adapter, &msg, 1);
-
- return 0;
+ return lg_h06xf_pll_set(fe, card->i2c_adapter, params);
}
static struct lgdt330x_config tdvs_tua6034_config = {
.demod_address = 0x0e,
.demod_chip = LGDT3303,
.serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
- .pll_set = tdvs_tua6034_pll_set,
};
static void lgdt330x_reset(struct dvb_bt8xx_card *bt)
@@ -617,17 +601,25 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
switch(type) {
case BTTV_BOARD_DVICO_DVBT_LITE:
card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter);
+
+ if (card->fe == NULL)
+ card->fe = zl10353_attach(&thomson_dtt7579_zl10353_config,
+ card->i2c_adapter);
+
if (card->fe != NULL) {
- card->fe->ops->info.frequency_min = 174000000;
- card->fe->ops->info.frequency_max = 862000000;
+ card->fe->ops.tuner_ops.calc_regs = thomson_dtt7579_tuner_calc_regs;
+ card->fe->ops.info.frequency_min = 174000000;
+ card->fe->ops.info.frequency_max = 862000000;
}
break;
case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
lgdt330x_reset(card);
card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter);
- if (card->fe != NULL)
+ if (card->fe != NULL) {
+ card->fe->ops.tuner_ops.set_params = tdvs_tua6034_tuner_set_params;
dprintk ("dvb_bt8xx: lgdt330x detected\n");
+ }
break;
case BTTV_BOARD_NEBULA_DIGITV:
@@ -640,6 +632,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
digitv_alps_tded4_reset(card);
card->fe = nxt6000_attach(&vp3021_alps_tded4_config, card->i2c_adapter);
if (card->fe != NULL) {
+ card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params;
dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n");
break;
}
@@ -648,19 +641,25 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
digitv_alps_tded4_reset(card);
card->fe = mt352_attach(&digitv_alps_tded4_config, card->i2c_adapter);
- if (card->fe != NULL)
+ if (card->fe != NULL) {
+ card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs;
dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n");
+ }
break;
case BTTV_BOARD_AVDVBT_761:
card->fe = sp887x_attach(&microtune_mt7202dtf_config, card->i2c_adapter);
+ if (card->fe) {
+ card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params;
+ }
break;
case BTTV_BOARD_AVDVBT_771:
card->fe = mt352_attach(&advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter);
if (card->fe != NULL) {
- card->fe->ops->info.frequency_min = 174000000;
- card->fe->ops->info.frequency_max = 862000000;
+ card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs;
+ card->fe->ops.info.frequency_min = 174000000;
+ card->fe->ops.info.frequency_max = 862000000;
}
break;
@@ -687,6 +686,11 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
case BTTV_BOARD_PINNACLESAT:
card->fe = cx24110_attach(&pctvsat_config, card->i2c_adapter);
+ if (card->fe) {
+ card->fe->ops.tuner_ops.init = pinnsat_tuner_init;
+ card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep;
+ card->fe->ops.tuner_ops.set_params = cx24108_tuner_set_params;
+ }
break;
case BTTV_BOARD_PC_HDTV:
@@ -703,8 +707,8 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
else
if (dvb_register_frontend(&card->dvb_adapter, card->fe)) {
printk("dvb-bt8xx: Frontend registration failed!\n");
- if (card->fe->ops->release)
- card->fe->ops->release(card->fe);
+ if (card->fe->ops.release)
+ card->fe->ops.release(card->fe);
card->fe = NULL;
}
}
@@ -713,7 +717,7 @@ static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
{
int result;
- if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, THIS_MODULE)) < 0) {
+ if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, THIS_MODULE, &card->bt->dev->dev)) < 0) {
printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result);
return result;
}
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
index 00dd9fa..4745a90 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
@@ -37,6 +37,8 @@
#include "cx24110.h"
#include "or51211.h"
#include "lgdt330x.h"
+#include "lg_h06xf.h"
+#include "zl10353.h"
struct dvb_bt8xx_card {
struct mutex lock;
diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig
index 6018fcd..b5cdd57 100644
--- a/drivers/media/dvb/cinergyT2/Kconfig
+++ b/drivers/media/dvb/cinergyT2/Kconfig
@@ -64,7 +64,7 @@ config DVB_CINERGYT2_QUERY_INTERVAL
config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
bool "Register the onboard IR Remote Control Receiver as Input Device"
depends on DVB_CINERGYT2_TUNING
- default "yes"
+ default y
help
Enable this option if you want to use the onboard Infrared Remote
Control Receiver as Linux-Input device.
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index 9325d03..1b89536 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -544,15 +544,19 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct
{
struct dvb_device *dvbdev = file->private_data;
struct cinergyt2 *cinergyt2 = dvbdev->priv;
+ unsigned int mask = 0;
if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
poll_wait(file, &cinergyt2->poll_wq, wait);
+ if (cinergyt2->pending_fe_events != 0)
+ mask |= (POLLIN | POLLRDNORM | POLLPRI);
+
mutex_unlock(&cinergyt2->sem);
- return (POLLIN | POLLRDNORM | POLLPRI);
+ return mask;
}
@@ -902,7 +906,7 @@ static int cinergyt2_probe (struct usb_interface *intf,
return -ENOMEM;
}
- if ((err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, THIS_MODULE)) < 0) {
+ if ((err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, THIS_MODULE, &cinergyt2->udev->dev)) < 0) {
kfree(cinergyt2);
return err;
}
diff --git a/drivers/media/dvb/dvb-core/Makefile b/drivers/media/dvb/dvb-core/Makefile
index 7adb50c..1105465 100644
--- a/drivers/media/dvb/dvb-core/Makefile
+++ b/drivers/media/dvb/dvb-core/Makefile
@@ -2,8 +2,8 @@
# Makefile for the kernel DVB device drivers.
#
-dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
- dvb_ca_en50221.o dvb_frontend.o \
- dvb_net.o dvb_ringbuffer.o
+dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
+ dvb_ca_en50221.o dvb_frontend.o \
+ dvb_net.o dvb_ringbuffer.o dvb_math.o
obj-$(CONFIG_DVB_CORE) += dvb-core.o
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 04578df..988499d 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -872,9 +872,6 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
mutex_unlock(&dmxdevfilter->mutex);
break;
- case DMX_GET_EVENT:
- break;
-
case DMX_GET_PES_PIDS:
if (!dmxdev->demux->get_pes_pids) {
ret = -EINVAL;
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index 00347a7..2a03bf5 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -1060,8 +1060,18 @@ static int dvb_ca_en50221_thread(void *data)
break;
case DVB_CA_SLOTSTATE_VALIDATE:
- if (dvb_ca_en50221_parse_attributes(ca, slot)
- != 0) {
+ if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) {
+ /* we need this extra check for annoying interfaces like the budget-av */
+ if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
+ (ca->pub->poll_slot_status)) {
+ int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+ if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+ }
+
printk("dvb_ca adapter %d: Invalid PC card inserted :(\n",
ca->dvbdev->adapter->num);
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
@@ -1108,6 +1118,17 @@ static int dvb_ca_en50221_thread(void *data)
case DVB_CA_SLOTSTATE_LINKINIT:
if (dvb_ca_en50221_link_init(ca, slot) != 0) {
+ /* we need this extra check for annoying interfaces like the budget-av */
+ if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
+ (ca->pub->poll_slot_status)) {
+ int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+ if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+ }
+
printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num);
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
dvb_ca_en50221_thread_update_delay(ca);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 83ec5e0..fcff5ea 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -473,7 +473,7 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
goto bailout;
}
memcpy(&demux->tsbuf[i], buf, j);
- if ((demux->tsbuf[0] == 0x47) | (demux->tsbuf[0] == 0xB8)) {
+ if ((demux->tsbuf[0] == 0x47) || (demux->tsbuf[0] == 0xB8)) {
memcpy(tmppack, demux->tsbuf, 188);
if (tmppack[0] == 0xB8)
tmppack[0] = 0x47;
@@ -484,7 +484,7 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
}
while (p < count) {
- if ((buf[p] == 0x47) | (buf[p] == 0xB8)) {
+ if ((buf[p] == 0x47) || (buf[p] == 0xB8)) {
if (count - p >= 204) {
memcpy(tmppack, &buf[p], 188);
if (tmppack[0] == 0xB8)
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index a051790..3152a54 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -56,7 +56,7 @@ MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AU
module_param(dvb_override_tune_delay, int, 0644);
MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
module_param(dvb_powerdown_on_sleep, int, 0644);
-MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB volatage off on sleep (default)");
+MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)");
#define dprintk if (dvb_frontend_debug) printk
@@ -72,6 +72,8 @@ MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB vola
#define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST)
#define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW)
#define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW)
+
+#define FE_ALGO_HW 1
/*
* FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling.
* FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune.
@@ -151,8 +153,8 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
sizeof (struct dvb_frontend_parameters));
if (status & FE_HAS_LOCK)
- if (fe->ops->get_frontend)
- fe->ops->get_frontend(fe, &e->parameters);
+ if (fe->ops.get_frontend)
+ fe->ops.get_frontend(fe, &e->parameters);
events->eventw = wp;
@@ -211,10 +213,15 @@ static void dvb_frontend_init(struct dvb_frontend *fe)
{
dprintk ("DVB: initialising frontend %i (%s)...\n",
fe->dvb->num,
- fe->ops->info.name);
-
- if (fe->ops->init)
- fe->ops->init(fe);
+ fe->ops.info.name);
+
+ if (fe->ops.init)
+ fe->ops.init(fe);
+ if (fe->ops.tuner_ops.init) {
+ fe->ops.tuner_ops.init(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
}
void dvb_frontend_reinitialise(struct dvb_frontend *fe)
@@ -259,7 +266,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
u32 original_frequency = fepriv->parameters.frequency;
/* are we using autoinversion? */
- autoinversion = ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
+ autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
(fepriv->parameters.inversion == INVERSION_AUTO));
/* setup parameters correctly */
@@ -329,8 +336,8 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
fepriv->parameters.frequency += fepriv->lnb_drift;
if (autoinversion)
fepriv->parameters.inversion = fepriv->inversion;
- if (fe->ops->set_frontend)
- fe->ops->set_frontend(fe, &fepriv->parameters);
+ if (fe->ops.set_frontend)
+ fe->ops.set_frontend(fe, &fepriv->parameters);
fepriv->parameters.frequency = original_frequency;
fepriv->parameters.inversion = original_inversion;
@@ -354,8 +361,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
/* in SCAN mode, we just set the frontend when asked and leave it alone */
if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {
if (fepriv->state & FESTATE_RETUNE) {
- if (fe->ops->set_frontend)
- fe->ops->set_frontend(fe, &fepriv->parameters);
+ if (fe->ops.set_frontend)
+ fe->ops.set_frontend(fe, &fepriv->parameters);
fepriv->state = FESTATE_TUNED;
}
fepriv->delay = 3*HZ;
@@ -367,8 +374,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
if (fepriv->state & FESTATE_RETUNE) {
s = 0;
} else {
- if (fe->ops->read_status)
- fe->ops->read_status(fe, &s);
+ if (fe->ops.read_status)
+ fe->ops.read_status(fe, &s);
if (s != fepriv->status) {
dvb_frontend_add_event(fe, s);
fepriv->status = s;
@@ -381,7 +388,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
fepriv->state = FESTATE_TUNED;
/* if we're tuned, then we have determined the correct inversion */
- if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
+ if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
(fepriv->parameters.inversion == INVERSION_AUTO)) {
fepriv->parameters.inversion = fepriv->inversion;
}
@@ -405,7 +412,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
/* don't actually do anything if we're in the LOSTLOCK state,
* the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
if ((fepriv->state & FESTATE_LOSTLOCK) &&
- (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
+ (fe->ops.info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
return;
}
@@ -540,16 +547,16 @@ static int dvb_frontend_thread(void *data)
if (fepriv->reinitialise) {
dvb_frontend_init(fe);
if (fepriv->tone != -1) {
- fe->ops->set_tone(fe, fepriv->tone);
+ fe->ops.set_tone(fe, fepriv->tone);
}
if (fepriv->voltage != -1) {
- fe->ops->set_voltage(fe, fepriv->voltage);
+ fe->ops.set_voltage(fe, fepriv->voltage);
}
fepriv->reinitialise = 0;
}
/* do an iteration of the tuning loop */
- if (fe->ops->tune) {
+ if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) {
/* have we been asked to retune? */
params = NULL;
if (fepriv->state & FESTATE_RETUNE) {
@@ -557,7 +564,7 @@ static int dvb_frontend_thread(void *data)
fepriv->state = FESTATE_TUNED;
}
- fe->ops->tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
+ fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
if (s != fepriv->status) {
dvb_frontend_add_event(fe, s);
fepriv->status = s;
@@ -569,10 +576,15 @@ static int dvb_frontend_thread(void *data)
if (dvb_shutdown_timeout) {
if (dvb_powerdown_on_sleep)
- if (fe->ops->set_voltage)
- fe->ops->set_voltage(fe, SEC_VOLTAGE_OFF);
- if (fe->ops->sleep)
- fe->ops->sleep(fe);
+ if (fe->ops.set_voltage)
+ fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
+ if (fe->ops.tuner_ops.sleep) {
+ fe->ops.tuner_ops.sleep(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ if (fe->ops.sleep)
+ fe->ops.sleep(fe);
}
fepriv->thread_pid = 0;
@@ -724,7 +736,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
case FE_GET_INFO: {
struct dvb_frontend_info* info = parg;
- memcpy(info, &fe->ops->info, sizeof(struct dvb_frontend_info));
+ memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));
/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
* do it, it is done for it. */
@@ -744,58 +756,58 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
break;
}
- if (fe->ops->read_status)
- err = fe->ops->read_status(fe, status);
+ if (fe->ops.read_status)
+ err = fe->ops.read_status(fe, status);
break;
}
case FE_READ_BER:
- if (fe->ops->read_ber)
- err = fe->ops->read_ber(fe, (__u32*) parg);
+ if (fe->ops.read_ber)
+ err = fe->ops.read_ber(fe, (__u32*) parg);
break;
case FE_READ_SIGNAL_STRENGTH:
- if (fe->ops->read_signal_strength)
- err = fe->ops->read_signal_strength(fe, (__u16*) parg);
+ if (fe->ops.read_signal_strength)
+ err = fe->ops.read_signal_strength(fe, (__u16*) parg);
break;
case FE_READ_SNR:
- if (fe->ops->read_snr)
- err = fe->ops->read_snr(fe, (__u16*) parg);
+ if (fe->ops.read_snr)
+ err = fe->ops.read_snr(fe, (__u16*) parg);
break;
case FE_READ_UNCORRECTED_BLOCKS:
- if (fe->ops->read_ucblocks)
- err = fe->ops->read_ucblocks(fe, (__u32*) parg);
+ if (fe->ops.read_ucblocks)
+ err = fe->ops.read_ucblocks(fe, (__u32*) parg);
break;
case FE_DISEQC_RESET_OVERLOAD:
- if (fe->ops->diseqc_reset_overload) {
- err = fe->ops->diseqc_reset_overload(fe);
+ if (fe->ops.diseqc_reset_overload) {
+ err = fe->ops.diseqc_reset_overload(fe);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
}
break;
case FE_DISEQC_SEND_MASTER_CMD:
- if (fe->ops->diseqc_send_master_cmd) {
- err = fe->ops->diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
+ if (fe->ops.diseqc_send_master_cmd) {
+ err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
}
break;
case FE_DISEQC_SEND_BURST:
- if (fe->ops->diseqc_send_burst) {
- err = fe->ops->diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
+ if (fe->ops.diseqc_send_burst) {
+ err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
}
break;
case FE_SET_TONE:
- if (fe->ops->set_tone) {
- err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg);
+ if (fe->ops.set_tone) {
+ err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg);
fepriv->tone = (fe_sec_tone_mode_t) parg;
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
@@ -803,8 +815,8 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
break;
case FE_SET_VOLTAGE:
- if (fe->ops->set_voltage) {
- err = fe->ops->set_voltage(fe, (fe_sec_voltage_t) parg);
+ if (fe->ops.set_voltage) {
+ err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg);
fepriv->voltage = (fe_sec_voltage_t) parg;
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
@@ -812,11 +824,11 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
break;
case FE_DISHNETWORK_SEND_LEGACY_CMD:
- if (fe->ops->dishnetwork_send_legacy_command) {
- err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned long) parg);
+ if (fe->ops.dishnetwork_send_legacy_command) {
+ err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
- } else if (fe->ops->set_voltage) {
+ } else if (fe->ops.set_voltage) {
/*
* NOTE: This is a fallback condition. Some frontends
* (stv0299 for instance) take longer than 8msec to
@@ -846,7 +858,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
/* before sending a command, initialize by sending
* a 32ms 18V to the switch
*/
- fe->ops->set_voltage(fe, SEC_VOLTAGE_18);
+ fe->ops.set_voltage(fe, SEC_VOLTAGE_18);
dvb_frontend_sleep_until(&nexttime, 32000);
for (i = 0; i < 9; i++) {
@@ -854,7 +866,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
do_gettimeofday(&tv[i + 1]);
if ((cmd & 0x01) != last) {
/* set voltage to (last ? 13V : 18V) */
- fe->ops->set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
+ fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
last = (last) ? 0 : 1;
}
cmd = cmd >> 1;
@@ -874,13 +886,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
break;
case FE_DISEQC_RECV_SLAVE_REPLY:
- if (fe->ops->diseqc_recv_slave_reply)
- err = fe->ops->diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
+ if (fe->ops.diseqc_recv_slave_reply)
+ err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
break;
case FE_ENABLE_HIGH_LNB_VOLTAGE:
- if (fe->ops->enable_high_lnb_voltage)
- err = fe->ops->enable_high_lnb_voltage(fe, (long) parg);
+ if (fe->ops.enable_high_lnb_voltage)
+ err = fe->ops.enable_high_lnb_voltage(fe, (long) parg);
break;
case FE_SET_FRONTEND: {
@@ -898,7 +910,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
fepriv->parameters.inversion = INVERSION_AUTO;
fetunesettings.parameters.inversion = INVERSION_AUTO;
}
- if (fe->ops->info.type == FE_OFDM) {
+ if (fe->ops.info.type == FE_OFDM) {
/* without hierachical coding code_rate_LP is irrelevant,
* so we tolerate the otherwise invalid FEC_NONE setting */
if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
@@ -907,13 +919,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
}
/* get frontend-specific tuning settings */
- if (fe->ops->get_tune_settings && (fe->ops->get_tune_settings(fe, &fetunesettings) == 0)) {
+ if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) {
fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
fepriv->max_drift = fetunesettings.max_drift;
fepriv->step_size = fetunesettings.step_size;
} else {
/* default values */
- switch(fe->ops->info.type) {
+ switch(fe->ops.info.type) {
case FE_QPSK:
fepriv->min_delay = HZ/20;
fepriv->step_size = fepriv->parameters.u.qpsk.symbol_rate / 16000;
@@ -928,11 +940,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
case FE_OFDM:
fepriv->min_delay = HZ/20;
- fepriv->step_size = fe->ops->info.frequency_stepsize * 2;
- fepriv->max_drift = (fe->ops->info.frequency_stepsize * 2) + 1;
+ fepriv->step_size = fe->ops.info.frequency_stepsize * 2;
+ fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
break;
case FE_ATSC:
- printk("dvb-core: FE_ATSC not handled yet.\n");
+ fepriv->min_delay = HZ/20;
+ fepriv->step_size = 0;
+ fepriv->max_drift = 0;
break;
}
}
@@ -952,9 +966,9 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
break;
case FE_GET_FRONTEND:
- if (fe->ops->get_frontend) {
+ if (fe->ops.get_frontend) {
memcpy (parg, &fepriv->parameters, sizeof (struct dvb_frontend_parameters));
- err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg);
+ err = fe->ops.get_frontend(fe, (struct dvb_frontend_parameters*) parg);
}
break;
@@ -1067,7 +1081,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
printk ("DVB: registering frontend %i (%s)...\n",
fe->dvb->num,
- fe->ops->info.name);
+ fe->ops.info.name);
dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
fe, DVB_DEVICE_FRONTEND);
@@ -1085,10 +1099,15 @@ int dvb_unregister_frontend(struct dvb_frontend* fe)
mutex_lock(&frontend_mutex);
dvb_unregister_device (fepriv->dvbdev);
dvb_frontend_stop (fe);
- if (fe->ops->release)
- fe->ops->release(fe);
+ if (fe->ops.tuner_ops.release) {
+ fe->ops.tuner_ops.release(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ if (fe->ops.release)
+ fe->ops.release(fe);
else
- printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops->info.name);
+ printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops.info.name);
/* fe is invalid now */
kfree(fepriv);
mutex_unlock(&frontend_mutex);
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index 5926a3b..2887e2b 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -49,6 +49,44 @@ struct dvb_frontend_tune_settings {
struct dvb_frontend;
+struct dvb_tuner_info {
+ char name[128];
+
+ u32 frequency_min;
+ u32 frequency_max;
+ u32 frequency_step;
+
+ u32 bandwidth_min;
+ u32 bandwidth_max;
+ u32 bandwidth_step;
+};
+
+struct dvb_tuner_ops {
+
+ struct dvb_tuner_info info;
+
+ int (*release)(struct dvb_frontend *fe);
+ int (*init)(struct dvb_frontend *fe);
+ int (*sleep)(struct dvb_frontend *fe);
+
+ /** This is for simple PLLs - set all parameters in one go. */
+ int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
+
+ /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
+ int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len);
+
+ int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
+ int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
+
+#define TUNER_STATUS_LOCKED 1
+ int (*get_status)(struct dvb_frontend *fe, u32 *status);
+
+ /** These are provided seperately from set_params in order to facilitate silicon
+ * tuners which require sophisticated tuning loops, controlling each parameter seperately. */
+ int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
+ int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
+};
+
struct dvb_frontend_ops {
struct dvb_frontend_info info;
@@ -64,6 +102,8 @@ struct dvb_frontend_ops {
unsigned int mode_flags,
int *delay,
fe_status_t *status);
+ /* get frontend tuning algorithm from the module */
+ int (*get_frontend_algo)(struct dvb_frontend *fe);
/* these two are only used for the swzigzag code */
int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
@@ -86,6 +126,8 @@ struct dvb_frontend_ops {
int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
+
+ struct dvb_tuner_ops tuner_ops;
};
#define MAX_EVENT 8
@@ -100,9 +142,10 @@ struct dvb_fe_events {
};
struct dvb_frontend {
- struct dvb_frontend_ops* ops;
+ struct dvb_frontend_ops ops;
struct dvb_adapter *dvb;
void* demodulator_priv;
+ void* tuner_priv;
void* frontend_priv;
void* misc_priv;
};
diff --git a/drivers/media/dvb/dvb-core/dvb_math.c b/drivers/media/dvb/dvb-core/dvb_math.c
new file mode 100644
index 0000000..beb7c93
--- /dev/null
+++ b/drivers/media/dvb/dvb-core/dvb_math.c
@@ -0,0 +1,145 @@
+/*
+ * dvb-math provides some complex fixed-point math
+ * operations shared between the dvb related stuff
+ *
+ * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/bug.h>
+#include "dvb_math.h"
+
+static const unsigned short logtable[256] = {
+ 0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
+ 0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508,
+ 0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6,
+ 0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37,
+ 0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f,
+ 0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41,
+ 0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1,
+ 0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142,
+ 0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68,
+ 0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355,
+ 0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c,
+ 0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490,
+ 0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3,
+ 0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507,
+ 0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe,
+ 0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca,
+ 0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c,
+ 0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7,
+ 0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c,
+ 0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c,
+ 0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a,
+ 0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065,
+ 0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730,
+ 0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc,
+ 0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469,
+ 0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9,
+ 0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c,
+ 0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765,
+ 0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83,
+ 0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387,
+ 0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973,
+ 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47
+};
+
+unsigned int intlog2(u32 value)
+{
+ /**
+ * returns: log2(value) * 2^24
+ * wrong result if value = 0 (log2(0) is undefined)
+ */
+ unsigned int msb;
+ unsigned int logentry;
+ unsigned int significand;
+ unsigned int interpolation;
+
+ if (unlikely(value == 0)) {
+ WARN_ON(1);
+ return 0;
+ }
+
+ /* first detect the msb (count begins at 0) */
+ msb = fls(value) - 1;
+
+ /**
+ * now we use a logtable after the following method:
+ *
+ * log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24
+ * where x = msb and therefore 1 <= y < 2
+ * first y is determined by shifting the value left
+ * so that msb is bit 31
+ * 0x00231f56 -> 0x8C7D5800
+ * the result is y * 2^31 -> "significand"
+ * then the highest 9 bits are used for a table lookup
+ * the highest bit is discarded because it's always set
+ * the highest nine bits in our example are 100011000
+ * so we would use the entry 0x18
+ */
+ significand = value << (31 - msb);
+ logentry = (significand >> 23) & 0xff;
+
+ /**
+ * last step we do is interpolation because of the
+ * limitations of the log table the error is that part of
+ * the significand which isn't used for lookup then we
+ * compute the ratio between the error and the next table entry
+ * and interpolate it between the log table entry used and the
+ * next one the biggest error possible is 0x7fffff
+ * (in our example it's 0x7D5800)
+ * needed value for next table entry is 0x800000
+ * so the interpolation is
+ * (error / 0x800000) * (logtable_next - logtable_current)
+ * in the implementation the division is moved to the end for
+ * better accuracy there is also an overflow correction if
+ * logtable_next is 256
+ */
+ interpolation = ((significand & 0x7fffff) *
+ ((logtable[(logentry + 1) & 0xff] -
+ logtable[logentry]) & 0xffff)) >> 15;
+
+ /* now we return the result */
+ return ((msb << 24) + (logtable[logentry] << 8) + interpolation);
+}
+EXPORT_SYMBOL(intlog2);
+
+unsigned int intlog10(u32 value)
+{
+ /**
+ * returns: log10(value) * 2^24
+ * wrong result if value = 0 (log10(0) is undefined)
+ */
+ u64 log;
+
+ if (unlikely(value == 0)) {
+ WARN_ON(1);
+ return 0;
+ }
+
+ log = intlog2(value);
+
+ /**
+ * we use the following method:
+ * log10(x) = log2(x) * log10(2)
+ */
+
+ return (log * 646456993) >> 31;
+}
+EXPORT_SYMBOL(intlog10);
diff --git a/drivers/media/dvb/dvb-core/dvb_math.h b/drivers/media/dvb/dvb-core/dvb_math.h
new file mode 100644
index 0000000..aecc867
--- /dev/null
+++ b/drivers/media/dvb/dvb-core/dvb_math.h
@@ -0,0 +1,58 @@
+/*
+ * dvb-math provides some complex fixed-point math
+ * operations shared between the dvb related stuff
+ *
+ * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __DVB_MATH_H
+#define __DVB_MATH_H
+
+#include <linux/types.h>
+
+/**
+ * computes log2 of a value; the result is shifted left by 24 bits
+ *
+ * to use rational values you can use the following method:
+ * intlog2(value) = intlog2(value * 2^x) - x * 2^24
+ *
+ * example: intlog2(8) will give 3 << 24 = 3 * 2^24
+ * example: intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24
+ * example: intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24
+ *
+ * @param value The value (must be != 0)
+ * @return log2(value) * 2^24
+ */
+extern unsigned int intlog2(u32 value);
+
+/**
+ * computes log10 of a value; the result is shifted left by 24 bits
+ *
+ * to use rational values you can use the following method:
+ * intlog10(value) = intlog10(value * 10^x) - x * 2^24
+ *
+ * example: intlog10(1000) will give 3 << 24 = 3 * 2^24
+ * due to the implementation intlog10(1000) might be not exactly 3 * 2^24
+ *
+ * look at intlog2 for similar examples
+ *
+ * @param value The value (must be != 0)
+ * @return log10(value) * 2^24
+ */
+extern unsigned int intlog10(u32 value);
+
+#endif
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 9fd8752..8859ab7 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -12,7 +12,7 @@
* Hilmar Linder <hlinder@cosy.sbg.ac.at>
* and Wolfram Stering <wstering@cosy.sbg.ac.at>
*
- * ULE Decaps according to draft-ietf-ipdvb-ule-03.txt.
+ * ULE Decaps according to RFC 4326.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -42,6 +42,9 @@
* Bugfixes and robustness improvements.
* Filtering on dest MAC addresses, if present (D-Bit = 0)
* ULE_DEBUG compile-time option.
+ * Apr 2006: cp v3: Bugfixes and compliency with RFC 4326 (ULE) by
+ * Christian Praehauser <cpraehaus@cosy.sbg.ac.at>,
+ * Paris Lodron University of Salzburg.
*/
/*
@@ -49,9 +52,6 @@
*
* Unloading does not work for 2.6.9 kernels: a refcount doesn't go to zero.
*
- * TS_FEED callback is called once for every single TS cell although it is
- * registered (in dvb_net_feed_start()) for 100 TS cells (used for dvb_net_ule()).
- *
*/
#include <linux/module.h>
@@ -89,6 +89,9 @@ static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt )
#ifdef ULE_DEBUG
+#define MAC_ADDR_PRINTFMT "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"
+#define MAX_ADDR_PRINTFMT_ARGS(macap) (macap)[0],(macap)[1],(macap)[2],(macap)[3],(macap)[4],(macap)[5]
+
#define isprint(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
static void hexdump( const unsigned char *buf, unsigned short len )
@@ -214,6 +217,8 @@ static unsigned short dvb_net_eth_type_trans(struct sk_buff *skb,
#define ULE_TEST 0
#define ULE_BRIDGED 1
+#define ULE_OPTEXTHDR_PADDING 0
+
static int ule_test_sndu( struct dvb_net_priv *p )
{
return -1;
@@ -221,14 +226,28 @@ static int ule_test_sndu( struct dvb_net_priv *p )
static int ule_bridged_sndu( struct dvb_net_priv *p )
{
- /* BRIDGE SNDU handling sucks in draft-ietf-ipdvb-ule-03.txt.
- * This has to be the last extension header, otherwise it won't work.
- * Blame the authors!
+ struct ethhdr *hdr = (struct ethhdr*) p->ule_next_hdr;
+ if(ntohs(hdr->h_proto) < 1536) {
+ int framelen = p->ule_sndu_len - ((p->ule_next_hdr+sizeof(struct ethhdr)) - p->ule_skb->data);
+ /* A frame Type < 1536 for a bridged frame, introduces a LLC Length field. */
+ if(framelen != ntohs(hdr->h_proto)) {
+ return -1;
+ }
+ }
+ /* Note:
+ * From RFC4326:
+ * "A bridged SNDU is a Mandatory Extension Header of Type 1.
+ * It must be the final (or only) extension header specified in the header chain of a SNDU."
+ * The 'ule_bridged' flag will cause the extension header processing loop to terminate.
*/
p->ule_bridged = 1;
return 0;
}
+static int ule_exthdr_padding(struct dvb_net_priv *p)
+{
+ return 0;
+}
/** Handle ULE extension headers.
* Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding.
@@ -242,7 +261,8 @@ static int handle_one_ule_extension( struct dvb_net_priv *p )
{ [0] = ule_test_sndu, [1] = ule_bridged_sndu, [2] = NULL, };
/* Table of optional extension header handlers. The header type is the index. */
- static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) = { NULL, };
+ static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) =
+ { [0] = ule_exthdr_padding, [1] = NULL, };
int ext_len = 0;
unsigned char hlen = (p->ule_sndu_type & 0x0700) >> 8;
@@ -253,25 +273,31 @@ static int handle_one_ule_extension( struct dvb_net_priv *p )
/* Mandatory extension header */
if (ule_mandatory_ext_handlers[htype]) {
ext_len = ule_mandatory_ext_handlers[htype]( p );
- p->ule_next_hdr += ext_len;
- if (! p->ule_bridged) {
- p->ule_sndu_type = ntohs( *(unsigned short *)p->ule_next_hdr );
- p->ule_next_hdr += 2;
- } else {
- p->ule_sndu_type = ntohs( *(unsigned short *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN)) );
- /* This assures the extension handling loop will terminate. */
+ if(ext_len >= 0) {
+ p->ule_next_hdr += ext_len;
+ if (!p->ule_bridged) {
+ p->ule_sndu_type = ntohs(*(unsigned short *)p->ule_next_hdr);
+ p->ule_next_hdr += 2;
+ } else {
+ p->ule_sndu_type = ntohs(*(unsigned short *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN)));
+ /* This assures the extension handling loop will terminate. */
+ }
}
+ // else: extension handler failed or SNDU should be discarded
} else
ext_len = -1; /* SNDU has to be discarded. */
} else {
/* Optional extension header. Calculate the length. */
- ext_len = hlen << 2;
+ ext_len = hlen << 1;
/* Process the optional extension header according to its type. */
if (ule_optional_ext_handlers[htype])
(void)ule_optional_ext_handlers[htype]( p );
p->ule_next_hdr += ext_len;
- p->ule_sndu_type = ntohs( *(unsigned short *)p->ule_next_hdr );
- p->ule_next_hdr += 2;
+ p->ule_sndu_type = ntohs( *(unsigned short *)(p->ule_next_hdr-2) );
+ /*
+ * note: the length of the next header type is included in the
+ * length of THIS optional extension header
+ */
}
return ext_len;
@@ -284,8 +310,14 @@ static int handle_ule_extensions( struct dvb_net_priv *p )
p->ule_next_hdr = p->ule_skb->data;
do {
l = handle_one_ule_extension( p );
- if (l == -1) return -1; /* Stop extension header processing and discard SNDU. */
+ if (l < 0)
+ return l; /* Stop extension header processing and discard SNDU. */
total_ext_len += l;
+#ifdef ULE_DEBUG
+ dprintk("handle_ule_extensions: ule_next_hdr=%p, ule_sndu_type=%i, "
+ "l=%i, total_ext_len=%i\n", p->ule_next_hdr,
+ (int) p->ule_sndu_type, l, total_ext_len);
+#endif
} while (p->ule_sndu_type < 1536);
@@ -355,8 +387,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
if (priv->ule_skb) {
dev_kfree_skb( priv->ule_skb );
/* Prepare for next SNDU. */
- ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
- ((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++;
+ priv->stats.rx_errors++;
+ priv->stats.rx_frame_errors++;
}
reset_ule(priv);
priv->need_pusi = 1;
@@ -396,27 +428,25 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
}
}
- /* Check continuity counter. */
if (new_ts) {
+ /* Check continuity counter. */
if ((ts[3] & 0x0F) == priv->tscc)
priv->tscc = (priv->tscc + 1) & 0x0F;
else {
/* TS discontinuity handling: */
printk(KERN_WARNING "%lu: TS discontinuity: got %#x, "
- "exptected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc);
+ "expected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc);
/* Drop partly decoded SNDU, reset state, resync on PUSI. */
if (priv->ule_skb) {
dev_kfree_skb( priv->ule_skb );
/* Prepare for next SNDU. */
// reset_ule(priv); moved to below.
- ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
- ((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++;
+ priv->stats.rx_errors++;
+ priv->stats.rx_frame_errors++;
}
reset_ule(priv);
/* skip to next PUSI. */
priv->need_pusi = 1;
- ts += TS_SZ;
- priv->ts_count++;
continue;
}
/* If we still have an incomplete payload, but PUSI is
@@ -425,7 +455,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
* cells (continuity counter wrap). */
if (ts[1] & TS_PUSI) {
if (! priv->need_pusi) {
- if (*from_where > 181) {
+ if (!(*from_where < (ts_remain-1)) || *from_where != priv->ule_sndu_remain) {
/* Pointer field is invalid. Drop this TS cell and any started ULE SNDU. */
printk(KERN_WARNING "%lu: Invalid pointer "
"field: %u.\n", priv->ts_count, *from_where);
@@ -438,8 +468,6 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
}
reset_ule(priv);
priv->need_pusi = 1;
- ts += TS_SZ;
- priv->ts_count++;
continue;
}
/* Skip pointer field (we're processing a
@@ -452,8 +480,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
if (priv->ule_sndu_remain > 183) {
/* Current SNDU lacks more data than there could be available in the
* current TS cell. */
- ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
- ((struct dvb_net_priv *) dev->priv)->stats.rx_length_errors++;
+ priv->stats.rx_errors++;
+ priv->stats.rx_length_errors++;
printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but "
"got PUSI (pf %d, ts_remain %d). Flushing incomplete payload.\n",
priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain);
@@ -492,9 +520,11 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
} else
priv->ule_dbit = 0;
- if (priv->ule_sndu_len > 32763) {
+ if (priv->ule_sndu_len < 5) {
printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. "
"Resyncing.\n", priv->ts_count, priv->ule_sndu_len);
+ priv->stats.rx_errors++;
+ priv->stats.rx_length_errors++;
priv->ule_sndu_len = 0;
priv->need_pusi = 1;
new_ts = 1;
@@ -608,58 +638,103 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
ule_dump = 1;
#endif
- ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
- ((struct dvb_net_priv *) dev->priv)->stats.rx_crc_errors++;
+ priv->stats.rx_errors++;
+ priv->stats.rx_crc_errors++;
dev_kfree_skb(priv->ule_skb);
} else {
/* CRC32 verified OK. */
+ u8 dest_addr[ETH_ALEN];
+ static const u8 bc_addr[ETH_ALEN] =
+ { [ 0 ... ETH_ALEN-1] = 0xff };
+
+ /* CRC32 was OK. Remove it from skb. */
+ priv->ule_skb->tail -= 4;
+ priv->ule_skb->len -= 4;
+
+ if (!priv->ule_dbit) {
+ /*
+ * The destination MAC address is the
+ * next data in the skb. It comes
+ * before any extension headers.
+ *
+ * Check if the payload of this SNDU
+ * should be passed up the stack.
+ */
+ register int drop = 0;
+ if (priv->rx_mode != RX_MODE_PROMISC) {
+ if (priv->ule_skb->data[0] & 0x01) {
+ /* multicast or broadcast */
+ if (memcmp(priv->ule_skb->data, bc_addr, ETH_ALEN)) {
+ /* multicast */
+ if (priv->rx_mode == RX_MODE_MULTI) {
+ int i;
+ for(i = 0; i < priv->multi_num && memcmp(priv->ule_skb->data, priv->multi_macs[i], ETH_ALEN); i++)
+ ;
+ if (i == priv->multi_num)
+ drop = 1;
+ } else if (priv->rx_mode != RX_MODE_ALL_MULTI)
+ drop = 1; /* no broadcast; */
+ /* else: all multicast mode: accept all multicast packets */
+ }
+ /* else: broadcast */
+ }
+ else if (memcmp(priv->ule_skb->data, dev->dev_addr, ETH_ALEN))
+ drop = 1;
+ /* else: destination address matches the MAC address of our receiver device */
+ }
+ /* else: promiscious mode; pass everything up the stack */
+
+ if (drop) {
+#ifdef ULE_DEBUG
+ dprintk("Dropping SNDU: MAC destination address does not match: dest addr: "MAC_ADDR_PRINTFMT", dev addr: "MAC_ADDR_PRINTFMT"\n",
+ MAX_ADDR_PRINTFMT_ARGS(priv->ule_skb->data), MAX_ADDR_PRINTFMT_ARGS(dev->dev_addr));
+#endif
+ dev_kfree_skb(priv->ule_skb);
+ goto sndu_done;
+ }
+ else
+ {
+ memcpy(dest_addr, priv->ule_skb->data, ETH_ALEN);
+ skb_pull(priv->ule_skb, ETH_ALEN);
+ }
+ }
+
/* Handle ULE Extension Headers. */
if (priv->ule_sndu_type < 1536) {
/* There is an extension header. Handle it accordingly. */
- int l = handle_ule_extensions( priv );
+ int l = handle_ule_extensions(priv);
if (l < 0) {
/* Mandatory extension header unknown or TEST SNDU. Drop it. */
// printk( KERN_WARNING "Dropping SNDU, extension headers.\n" );
- dev_kfree_skb( priv->ule_skb );
+ dev_kfree_skb(priv->ule_skb);
goto sndu_done;
}
- skb_pull( priv->ule_skb, l );
+ skb_pull(priv->ule_skb, l);
}
- /* CRC32 was OK. Remove it from skb. */
- priv->ule_skb->tail -= 4;
- priv->ule_skb->len -= 4;
-
- /* Filter on receiver's destination MAC address, if present. */
- if (!priv->ule_dbit) {
- /* The destination MAC address is the next data in the skb. */
- if (memcmp( priv->ule_skb->data, dev->dev_addr, ETH_ALEN )) {
- /* MAC addresses don't match. Drop SNDU. */
- // printk( KERN_WARNING "Dropping SNDU, MAC address.\n" );
- dev_kfree_skb( priv->ule_skb );
- goto sndu_done;
- }
- if (! priv->ule_bridged) {
- skb_push( priv->ule_skb, ETH_ALEN + 2 );
- ethh = (struct ethhdr *)priv->ule_skb->data;
- memcpy( ethh->h_dest, ethh->h_source, ETH_ALEN );
- memset( ethh->h_source, 0, ETH_ALEN );
- ethh->h_proto = htons( priv->ule_sndu_type );
- } else {
- /* Skip the Receiver destination MAC address. */
- skb_pull( priv->ule_skb, ETH_ALEN );
- }
- } else {
- if (! priv->ule_bridged) {
- skb_push( priv->ule_skb, ETH_HLEN );
- ethh = (struct ethhdr *)priv->ule_skb->data;
- memcpy( ethh->h_dest, dev->dev_addr, ETH_ALEN );
- memset( ethh->h_source, 0, ETH_ALEN );
- ethh->h_proto = htons( priv->ule_sndu_type );
- } else {
- /* skb is in correct state; nothing to do. */
+ /*
+ * Construct/assure correct ethernet header.
+ * Note: in bridged mode (priv->ule_bridged !=
+ * 0) we already have the (original) ethernet
+ * header at the start of the payload (after
+ * optional dest. address and any extension
+ * headers).
+ */
+
+ if (!priv->ule_bridged) {
+ skb_push(priv->ule_skb, ETH_HLEN);
+ ethh = (struct ethhdr *)priv->ule_skb->data;
+ if (!priv->ule_dbit) {
+ /* dest_addr buffer is only valid if priv->ule_dbit == 0 */
+ memcpy(ethh->h_dest, dest_addr, ETH_ALEN);
+ memset(ethh->h_source, 0, ETH_ALEN);
}
+ else /* zeroize source and dest */
+ memset( ethh, 0, ETH_ALEN*2 );
+
+ ethh->h_proto = htons(priv->ule_sndu_type);
}
+ /* else: skb is in correct state; nothing to do. */
priv->ule_bridged = 0;
/* Stuff into kernel's protocol stack. */
@@ -668,8 +743,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
* receive the packet anyhow. */
/* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST)
priv->ule_skb->pkt_type = PACKET_HOST; */
- ((struct dvb_net_priv *) dev->priv)->stats.rx_packets++;
- ((struct dvb_net_priv *) dev->priv)->stats.rx_bytes += priv->ule_skb->len;
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += priv->ule_skb->len;
netif_rx(priv->ule_skb);
}
sndu_done:
@@ -944,7 +1019,7 @@ static int dvb_net_feed_start(struct net_device *dev)
dprintk("%s: start filtering\n", __FUNCTION__);
priv->secfeed->start_filtering(priv->secfeed);
} else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
- struct timespec timeout = { 0, 30000000 }; // 30 msec
+ struct timespec timeout = { 0, 10000000 }; // 10 msec
/* we have payloads encapsulated in TS */
dprintk("%s: alloc tsfeed\n", __FUNCTION__);
@@ -956,10 +1031,13 @@ static int dvb_net_feed_start(struct net_device *dev)
/* Set netdevice pointer for ts decaps callback. */
priv->tsfeed->priv = (void *)dev;
- ret = priv->tsfeed->set(priv->tsfeed, priv->pid,
- TS_PACKET, DMX_TS_PES_OTHER,
+ ret = priv->tsfeed->set(priv->tsfeed,
+ priv->pid, /* pid */
+ TS_PACKET, /* type */
+ DMX_TS_PES_OTHER, /* pes type */
32768, /* circular buffer size */
- timeout);
+ timeout /* timeout */
+ );
if (ret < 0) {
printk("%s: could not set ts feed\n", dev->name);
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index 3852430..134c2bb 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -236,7 +236,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
"dvb/adapter%d/%s%d", adap->num, dnames[type], id);
class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
- NULL, "dvb%d.%s%d", adap->num, dnames[type], id);
+ adap->device, "dvb%d.%s%d", adap->num, dnames[type], id);
dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
adap->num, dnames[type], id, nums2minor(adap->num, type, id),
@@ -285,7 +285,7 @@ skip:
}
-int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module)
+int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module, struct device *device)
{
int num;
@@ -306,6 +306,7 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct modu
adap->num = num;
adap->name = name;
adap->module = module;
+ adap->device = device;
list_add_tail (&adap->list_head, &dvb_adapter_list);
diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h
index 74ed585..d7a976d 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.h
+++ b/drivers/media/dvb/dvb-core/dvbdev.h
@@ -51,6 +51,8 @@ struct dvb_adapter {
u8 proposed_mac [6];
void* priv;
+ struct device *device;
+
struct module *module;
};
@@ -76,7 +78,7 @@ struct dvb_device {
};
-extern int dvb_register_adapter (struct dvb_adapter *adap, const char *name, struct module *module);
+extern int dvb_register_adapter (struct dvb_adapter *adap, const char *name, struct module *module, struct device *device);
extern int dvb_unregister_adapter (struct dvb_adapter *adap);
extern int dvb_register_device (struct dvb_adapter *adap,
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index e388fb1..3bc6722 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -88,6 +88,7 @@ config DVB_USB_CXUSB
select DVB_CX22702
select DVB_LGDT330X
select DVB_MT352
+ select DVB_ZL10353
help
Say Y here to support the Conexant USB2.0 hybrid reference design.
Currently, only DVB and ATSC modes are supported, analog mode
@@ -130,6 +131,15 @@ config DVB_USB_VP702X
DVB-S USB2.0 receivers.
+config DVB_USB_GP8PSK
+ tristate "GENPIX 8PSK->USB module support"
+ depends on DVB_USB
+ help
+ Say Y here to support the
+ GENPIX 8psk module
+
+ DVB-S USB2.0 receivers.
+
config DVB_USB_NOVA_T_USB2
tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
depends on DVB_USB
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 2dc9aad..9643f56 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -7,6 +7,9 @@ obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o
dvb-usb-vp702x-objs = vp702x.o vp702x-fe.o
obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o
+dvb-usb-gp8psk-objs = gp8psk.o gp8psk-fe.o
+obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.o
+
dvb-usb-dtt200u-objs = dtt200u.o dtt200u-fe.o
obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 1f0d3e9..ae23bdd 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -27,8 +27,10 @@
#include "cx22702.h"
#include "lgdt330x.h"
+#include "lg_h06xf.h"
#include "mt352.h"
#include "mt352_priv.h"
+#include "zl10353.h"
/* debug */
int dvb_usb_cxusb_debug;
@@ -322,32 +324,37 @@ static int cxusb_mt352_demod_init(struct dvb_frontend* fe)
return 0;
}
+static int cxusb_lgh064f_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct dvb_usb_device *d = fe->dvb->priv;
+ return lg_h06xf_pll_set(fe, &d->i2c_adap, fep);
+}
+
static struct cx22702_config cxusb_cx22702_config = {
.demod_address = 0x63,
.output_mode = CX22702_PARALLEL_OUTPUT,
-
- .pll_init = dvb_usb_pll_init_i2c,
- .pll_set = dvb_usb_pll_set_i2c,
};
static struct lgdt330x_config cxusb_lgdt3303_config = {
.demod_address = 0x0e,
.demod_chip = LGDT3303,
- .pll_set = dvb_usb_pll_set_i2c,
};
static struct mt352_config cxusb_dee1601_config = {
.demod_address = 0x0f,
.demod_init = cxusb_dee1601_demod_init,
- .pll_set = dvb_usb_pll_set,
};
-struct mt352_config cxusb_mt352_config = {
+static struct zl10353_config cxusb_zl10353_dee1601_config = {
+ .demod_address = 0x0f,
+};
+
+static struct mt352_config cxusb_mt352_config = {
/* used in both lgz201 and th7579 */
.demod_address = 0x0f,
.demod_init = cxusb_mt352_demod_init,
- .pll_set = dvb_usb_pll_set,
};
/* Callbacks for DVB USB */
@@ -357,17 +364,10 @@ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_device *d)
d->pll_addr = 0x61;
memcpy(d->pll_init, bpll, 4);
d->pll_desc = &dvb_pll_fmd1216me;
- return 0;
-}
-static int cxusb_lgh064f_tuner_attach(struct dvb_usb_device *d)
-{
- u8 bpll[4] = { 0x00, 0x00, 0x18, 0x50 };
- /* bpll[2] : unset bit 3, set bits 4&5
- bpll[3] : 0x50 - digital, 0x20 - analog */
- d->pll_addr = 0x61;
- memcpy(d->pll_init, bpll, 4);
- d->pll_desc = &dvb_pll_tdvs_tua6034;
+ d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+ d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
+
return 0;
}
@@ -375,6 +375,7 @@ static int cxusb_dee1601_tuner_attach(struct dvb_usb_device *d)
{
d->pll_addr = 0x61;
d->pll_desc = &dvb_pll_thomson_dtt7579;
+ d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
return 0;
}
@@ -382,6 +383,7 @@ static int cxusb_lgz201_tuner_attach(struct dvb_usb_device *d)
{
d->pll_addr = 0x61;
d->pll_desc = &dvb_pll_lg_z201;
+ d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
return 0;
}
@@ -389,6 +391,13 @@ static int cxusb_dtt7579_tuner_attach(struct dvb_usb_device *d)
{
d->pll_addr = 0x60;
d->pll_desc = &dvb_pll_thomson_dtt7579;
+ d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ return 0;
+}
+
+static int cxusb_lgdt3303_tuner_attach(struct dvb_usb_device *d)
+{
+ d->fe->ops.tuner_ops.set_params = cxusb_lgh064f_tuner_set_params;
return 0;
}
@@ -439,7 +448,8 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_device *d)
cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
- if ((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL)
+ if (((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL) ||
+ ((d->fe = zl10353_attach(&cxusb_zl10353_dee1601_config, &d->i2c_adap)) != NULL))
return 0;
return -EIO;
@@ -555,7 +565,7 @@ static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = {
.streaming_ctrl = cxusb_streaming_ctrl,
.power_ctrl = cxusb_bluebird_power_ctrl,
.frontend_attach = cxusb_lgdt3303_frontend_attach,
- .tuner_attach = cxusb_lgh064f_tuner_attach,
+ .tuner_attach = cxusb_lgdt3303_tuner_attach,
.i2c_algo = &cxusb_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
index 2d52b76..abd75b4 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-common.c
@@ -173,11 +173,10 @@ int dibusb_dib3000mc_frontend_attach(struct dvb_usb_device *d)
struct dib3000_config demod_cfg;
struct dibusb_state *st = d->priv;
- demod_cfg.pll_set = dvb_usb_pll_set_i2c;
- demod_cfg.pll_init = dvb_usb_pll_init_i2c;
-
for (demod_cfg.demod_address = 0x8; demod_cfg.demod_address < 0xd; demod_cfg.demod_address++)
if ((d->fe = dib3000mc_attach(&demod_cfg,&d->i2c_adap,&st->ops)) != NULL) {
+ d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+ d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
return 0;
}
@@ -190,6 +189,10 @@ int dibusb_dib3000mc_tuner_attach (struct dvb_usb_device *d)
{
d->pll_addr = 0x60;
d->pll_desc = &dvb_pll_env57h1xd5;
+
+ d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+ d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
+
return 0;
}
EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index dd5a131..f4c45f3 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -20,11 +20,12 @@ static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_device *d)
struct dibusb_state *st = d->priv;
demod_cfg.demod_address = 0x8;
- demod_cfg.pll_set = dvb_usb_pll_set_i2c;
- demod_cfg.pll_init = dvb_usb_pll_init_i2c;
- if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL)
+ if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL) {
+ d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+ d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
return -ENODEV;
+ }
d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index 91136c0..c14d9ef 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -112,27 +112,30 @@ static int digitv_mt352_demod_init(struct dvb_frontend *fe)
static struct mt352_config digitv_mt352_config = {
.demod_init = digitv_mt352_demod_init,
- .pll_set = dvb_usb_pll_set,
};
-static int digitv_nxt6000_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
{
struct dvb_usb_device *d = fe->dvb->priv;
u8 b[5];
- dvb_usb_pll_set(fe,fep,b);
+ dvb_usb_tuner_calc_regs(fe,fep,b, 5);
return digitv_ctrl_msg(d,USB_WRITE_TUNER,0,&b[1],4,NULL,0);
}
static struct nxt6000_config digitv_nxt6000_config = {
.clock_inversion = 1,
- .pll_set = digitv_nxt6000_pll_set,
};
static int digitv_frontend_attach(struct dvb_usb_device *d)
{
- if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL ||
- (d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL)
+ if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL) {
+ d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
return 0;
+ }
+ if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL) {
+ d->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+ return 0;
+ }
return -EIO;
}
diff --git a/drivers/media/dvb/dvb-usb/dtt200u-fe.c b/drivers/media/dvb/dvb-usb/dtt200u-fe.c
index cd21ddb..17413ad 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u-fe.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u-fe.c
@@ -18,7 +18,6 @@ struct dtt200u_fe_state {
struct dvb_frontend_parameters fep;
struct dvb_frontend frontend;
- struct dvb_frontend_ops ops;
};
static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat)
@@ -163,16 +162,13 @@ struct dvb_frontend* dtt200u_fe_attach(struct dvb_usb_device *d)
deb_info("attaching frontend dtt200u\n");
state->d = d;
- memcpy(&state->ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops));
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
- goto success;
+ return &state->frontend;
error:
return NULL;
-success:
- return &state->frontend;
}
static struct dvb_frontend_ops dtt200u_fe_ops = {
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
index 6fa9210..ec63170 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
@@ -82,7 +82,7 @@ int dvb_usb_dvb_init(struct dvb_usb_device *d)
int ret;
if ((ret = dvb_register_adapter(&d->dvb_adap, d->desc->name,
- d->owner)) < 0) {
+ d->owner, &d->udev->dev)) < 0) {
deb_info("dvb_register_adapter failed: error %d", ret);
goto err;
}
@@ -121,16 +121,15 @@ int dvb_usb_dvb_init(struct dvb_usb_device *d)
dvb_net_init(&d->dvb_adap, &d->dvb_net, &d->demux.dmx);
- goto success;
+ d->state |= DVB_USB_STATE_DVB;
+ return 0;
+
err_dmx_dev:
dvb_dmx_release(&d->demux);
err_dmx:
dvb_unregister_adapter(&d->dvb_adap);
err:
return ret;
-success:
- d->state |= DVB_USB_STATE_DVB;
- return 0;
}
int dvb_usb_dvb_exit(struct dvb_usb_device *d)
@@ -184,13 +183,13 @@ int dvb_usb_fe_init(struct dvb_usb_device* d)
/* re-assign sleep and wakeup functions */
if (d->fe != NULL) {
- d->fe_init = d->fe->ops->init; d->fe->ops->init = dvb_usb_fe_wakeup;
- d->fe_sleep = d->fe->ops->sleep; d->fe->ops->sleep = dvb_usb_fe_sleep;
+ d->fe_init = d->fe->ops.init; d->fe->ops.init = dvb_usb_fe_wakeup;
+ d->fe_sleep = d->fe->ops.sleep; d->fe->ops.sleep = dvb_usb_fe_sleep;
if (dvb_register_frontend(&d->dvb_adap, d->fe)) {
err("Frontend registration failed.");
- if (d->fe->ops->release)
- d->fe->ops->release(d->fe);
+ if (d->fe->ops.release)
+ d->fe->ops.release(d->fe);
d->fe = NULL;
return -ENODEV;
}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
index 9b25453..6b611a7 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
@@ -46,7 +46,7 @@ int dvb_usb_i2c_exit(struct dvb_usb_device *d)
return 0;
}
-int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
+int dvb_usb_tuner_init_i2c(struct dvb_frontend *fe)
{
struct dvb_usb_device *d = fe->dvb->priv;
struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = d->pll_init, .len = 4 };
@@ -63,6 +63,8 @@ int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
deb_pll("pll-buf: %x %x %x %x\n",d->pll_init[0],d->pll_init[1],
d->pll_init[2],d->pll_init[3]);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
err("tuner i2c write failed for pll_init.");
ret = -EREMOTEIO;
@@ -73,38 +75,42 @@ int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
d->tuner_pass_ctrl(fe,0,d->pll_addr);
return ret;
}
-EXPORT_SYMBOL(dvb_usb_pll_init_i2c);
+EXPORT_SYMBOL(dvb_usb_tuner_init_i2c);
-int dvb_usb_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 b[5])
+int dvb_usb_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 *b, int buf_len)
{
struct dvb_usb_device *d = fe->dvb->priv;
+ if (buf_len != 5)
+ return -EINVAL;
if (d->pll_desc == NULL)
return 0;
deb_pll("pll addr: %x, freq: %d %p\n",d->pll_addr,fep->frequency,d->pll_desc);
- b[0] = d->pll_addr << 1;
+ b[0] = d->pll_addr;
dvb_pll_configure(d->pll_desc,&b[1],fep->frequency,fep->u.ofdm.bandwidth);
deb_pll("pll-buf: %x %x %x %x %x\n",b[0],b[1],b[2],b[3],b[4]);
- return 0;
+ return 5;
}
-EXPORT_SYMBOL(dvb_usb_pll_set);
+EXPORT_SYMBOL(dvb_usb_tuner_calc_regs);
-int dvb_usb_pll_set_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
{
struct dvb_usb_device *d = fe->dvb->priv;
int ret = 0;
u8 b[5];
struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = &b[1], .len = 4 };
- dvb_usb_pll_set(fe,fep,b);
+ dvb_usb_tuner_calc_regs(fe,fep,b,5);
if (d->tuner_pass_ctrl)
d->tuner_pass_ctrl(fe,1,d->pll_addr);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
err("tuner i2c write failed for pll_set.");
ret = -EREMOTEIO;
@@ -116,4 +122,4 @@ int dvb_usb_pll_set_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters
return ret;
}
-EXPORT_SYMBOL(dvb_usb_pll_set_i2c);
+EXPORT_SYMBOL(dvb_usb_tuner_set_params_i2c);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index cb23904..9569891 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -31,6 +31,7 @@
#define USB_VID_VISIONPLUS 0x13d3
#define USB_VID_TWINHAN 0x1822
#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
+#define USB_VID_GENPIX 0x09c0
/* Product IDs */
#define USB_PID_ADSTECH_USB2_COLD 0xa333
@@ -104,5 +105,6 @@
#define USB_PID_KYE_DVB_T_WARM 0x701f
#define USB_PID_PCTV_200E 0x020e
#define USB_PID_PCTV_400E 0x020f
-
+#define USB_PID_GENPIX_8PSK_COLD 0x0200
+#define USB_PID_GENPIX_8PSK_WARM 0x0201
#endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index fead958..4cf9f89 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -330,9 +330,9 @@ extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16);
extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
/* commonly used pll init and set functions */
-extern int dvb_usb_pll_init_i2c(struct dvb_frontend *);
-extern int dvb_usb_pll_set(struct dvb_frontend *, struct dvb_frontend_parameters *, u8[]);
-extern int dvb_usb_pll_set_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
+extern int dvb_usb_tuner_init_i2c(struct dvb_frontend *);
+extern int dvb_usb_tuner_calc_regs(struct dvb_frontend *, struct dvb_frontend_parameters *, u8 *buf, int buf_len);
+extern int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
/* commonly used firmware download types and function */
struct hexline {
diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
new file mode 100644
index 0000000..6ccbdc9
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
@@ -0,0 +1,272 @@
+/* DVB USB compliant Linux driver for the
+ * - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *
+ * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ *
+ * Thanks to GENPIX for the sample code used to implement this module.
+ *
+ * This module is based off the vp7045 and vp702x modules
+ *
+ * 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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "gp8psk.h"
+
+struct gp8psk_fe_state {
+ struct dvb_frontend fe;
+
+ struct dvb_usb_device *d;
+
+ u16 snr;
+
+ unsigned long next_snr_check;
+};
+
+static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
+{
+ struct gp8psk_fe_state *st = fe->demodulator_priv;
+ u8 lock;
+
+ if (gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0, 0, &lock,1))
+ return -EINVAL;
+
+ if (lock)
+ *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
+ else
+ *status = 0;
+
+ return 0;
+}
+
+/* not supported by this Frontend */
+static int gp8psk_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
+{
+ (void) fe;
+ *ber = 0;
+ return 0;
+}
+
+/* not supported by this Frontend */
+static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
+{
+ (void) fe;
+ *unc = 0;
+ return 0;
+}
+
+static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+ struct gp8psk_fe_state *st = fe->demodulator_priv;
+ u8 buf[2];
+
+ if (time_after(jiffies,st->next_snr_check)) {
+ gp8psk_usb_in_op(st->d,GET_SIGNAL_STRENGTH,0,0,buf,2);
+ *snr = (int)(buf[1]) << 8 | buf[0];
+ /* snr is reported in dBu*256 */
+ /* snr / 38.4 ~= 100% strength */
+ /* snr * 17 returns 100% strength as 65535 */
+ if (*snr <= 3855)
+ *snr = (*snr<<4) + *snr; // snr * 17
+ else
+ *snr = 65535;
+ st->next_snr_check = jiffies + (10*HZ)/1000;
+ } else {
+ *snr = st->snr;
+ }
+ return 0;
+}
+
+static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
+{
+ return gp8psk_fe_read_snr(fe, strength);
+}
+
+static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+ tune->min_delay_ms = 800;
+ return 0;
+}
+
+static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct gp8psk_fe_state *state = fe->demodulator_priv;
+ u8 cmd[10];
+ u32 freq = fep->frequency * 1000;
+
+ cmd[4] = freq & 0xff;
+ cmd[5] = (freq >> 8) & 0xff;
+ cmd[6] = (freq >> 16) & 0xff;
+ cmd[7] = (freq >> 24) & 0xff;
+
+ switch(fe->ops.info.type) {
+ case FE_QPSK:
+ cmd[0] = fep->u.qpsk.symbol_rate & 0xff;
+ cmd[1] = (fep->u.qpsk.symbol_rate >> 8) & 0xff;
+ cmd[2] = (fep->u.qpsk.symbol_rate >> 16) & 0xff;
+ cmd[3] = (fep->u.qpsk.symbol_rate >> 24) & 0xff;
+ cmd[8] = ADV_MOD_DVB_QPSK;
+ cmd[9] = 0x03; /*ADV_MOD_FEC_XXX*/
+ break;
+ default:
+ // other modes are unsuported right now
+ cmd[0] = 0;
+ cmd[1] = 0;
+ cmd[2] = 0;
+ cmd[3] = 0;
+ cmd[8] = 0;
+ cmd[9] = 0;
+ break;
+ }
+
+ gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10);
+
+ state->next_snr_check = jiffies;
+
+ return 0;
+}
+
+static int gp8psk_fe_get_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep)
+{
+ return 0;
+}
+
+
+static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe,
+ struct dvb_diseqc_master_cmd *m)
+{
+ struct gp8psk_fe_state *st = fe->demodulator_priv;
+
+ deb_fe("%s\n",__FUNCTION__);
+
+ if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0,
+ m->msg, m->msg_len)) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int gp8psk_fe_send_diseqc_burst (struct dvb_frontend* fe,
+ fe_sec_mini_cmd_t burst)
+{
+ struct gp8psk_fe_state *st = fe->demodulator_priv;
+ u8 cmd;
+
+ deb_fe("%s\n",__FUNCTION__);
+
+ /* These commands are certainly wrong */
+ cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01;
+
+ if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, cmd, 0,
+ &cmd, 0)) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int gp8psk_fe_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ struct gp8psk_fe_state* state = fe->demodulator_priv;
+
+ if (gp8psk_usb_out_op(state->d,SET_22KHZ_TONE,
+ (tone == SEC_TONE_ON), 0, NULL, 0)) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+ struct gp8psk_fe_state* state = fe->demodulator_priv;
+
+ if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE,
+ voltage == SEC_VOLTAGE_18, 0, NULL, 0)) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd)
+{
+ struct gp8psk_fe_state* state = fe->demodulator_priv;
+ u8 cmd = sw_cmd & 0x7f;
+
+ if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0,
+ NULL, 0)) {
+ return -EINVAL;
+ }
+ if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80),
+ 0, NULL, 0)) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void gp8psk_fe_release(struct dvb_frontend* fe)
+{
+ struct gp8psk_fe_state *state = fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops gp8psk_fe_ops;
+
+struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d)
+{
+ struct gp8psk_fe_state *s = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL);
+ if (s == NULL)
+ goto error;
+
+ s->d = d;
+ memcpy(&s->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops));
+ s->fe.demodulator_priv = s;
+
+ goto success;
+error:
+ return NULL;
+success:
+ return &s->fe;
+}
+
+
+static struct dvb_frontend_ops gp8psk_fe_ops = {
+ .info = {
+ .name = "Genpix 8psk-USB DVB-S",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 100,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ .symbol_rate_tolerance = 500, /* ppm */
+ .caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK
+ },
+
+ .release = gp8psk_fe_release,
+
+ .init = NULL,
+ .sleep = NULL,
+
+ .set_frontend = gp8psk_fe_set_frontend,
+ .get_frontend = gp8psk_fe_get_frontend,
+ .get_tune_settings = gp8psk_fe_get_tune_settings,
+
+ .read_status = gp8psk_fe_read_status,
+ .read_ber = gp8psk_fe_read_ber,
+ .read_signal_strength = gp8psk_fe_read_signal_strength,
+ .read_snr = gp8psk_fe_read_snr,
+ .read_ucblocks = gp8psk_fe_read_unc_blocks,
+
+ .diseqc_send_master_cmd = gp8psk_fe_send_diseqc_msg,
+ .diseqc_send_burst = gp8psk_fe_send_diseqc_burst,
+ .set_tone = gp8psk_fe_set_tone,
+ .set_voltage = gp8psk_fe_set_voltage,
+ .dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd,
+};
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c
new file mode 100644
index 0000000..9a98f3f
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/gp8psk.c
@@ -0,0 +1,256 @@
+/* DVB USB compliant Linux driver for the
+ * - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *
+ * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ *
+ * Thanks to GENPIX for the sample code used to implement this module.
+ *
+ * This module is based off the vp7045 and vp702x modules
+ *
+ * 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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "gp8psk.h"
+
+/* debug */
+static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw";
+int dvb_usb_gp8psk_debug;
+module_param_named(debug,dvb_usb_gp8psk_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
+
+int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
+{
+ int ret = 0,try = 0;
+
+ if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+ return ret;
+
+ while (ret >= 0 && ret != blen && try < 3) {
+ ret = usb_control_msg(d->udev,
+ usb_rcvctrlpipe(d->udev,0),
+ req,
+ USB_TYPE_VENDOR | USB_DIR_IN,
+ value,index,b,blen,
+ 2000);
+ deb_info("reading number %d (ret: %d)\n",try,ret);
+ try++;
+ }
+
+ if (ret < 0 || ret != blen) {
+ warn("usb in operation failed.");
+ ret = -EIO;
+ } else
+ ret = 0;
+
+ deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
+ debug_dump(b,blen,deb_xfer);
+
+ mutex_unlock(&d->usb_mutex);
+
+ return ret;
+}
+
+int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+ u16 index, u8 *b, int blen)
+{
+ int ret;
+
+ deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
+ debug_dump(b,blen,deb_xfer);
+
+ if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+ return ret;
+
+ if (usb_control_msg(d->udev,
+ usb_sndctrlpipe(d->udev,0),
+ req,
+ USB_TYPE_VENDOR | USB_DIR_OUT,
+ value,index,b,blen,
+ 2000) != blen) {
+ warn("usb out operation failed.");
+ ret = -EIO;
+ } else
+ ret = 0;
+ mutex_unlock(&d->usb_mutex);
+
+ return ret;
+}
+
+static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d)
+{
+ int ret;
+ const struct firmware *fw = NULL;
+ u8 *ptr, *buf;
+ if ((ret = request_firmware(&fw, bcm4500_firmware,
+ &d->udev->dev)) != 0) {
+ err("did not find the bcm4500 firmware file. (%s) "
+ "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
+ bcm4500_firmware,ret);
+ return ret;
+ }
+
+ ret = -EINVAL;
+
+ if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0))
+ goto out_rel_fw;
+
+ info("downloaidng bcm4500 firmware from file '%s'",bcm4500_firmware);
+
+ ptr = fw->data;
+ buf = kmalloc(512, GFP_KERNEL | GFP_DMA);
+
+ while (ptr[0] != 0xff) {
+ u16 buflen = ptr[0] + 4;
+ if (ptr + buflen >= fw->data + fw->size) {
+ err("failed to load bcm4500 firmware.");
+ goto out_free;
+ }
+ memcpy(buf, ptr, buflen);
+ if (dvb_usb_generic_write(d, buf, buflen)) {
+ err("failed to load bcm4500 firmware.");
+ goto out_free;
+ }
+ ptr += buflen;
+ }
+
+ ret = 0;
+
+out_free:
+ kfree(buf);
+out_rel_fw:
+ release_firmware(fw);
+
+ return ret;
+}
+
+static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ u8 status, buf;
+ if (onoff) {
+ gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
+ if (! (status & 0x01)) /* started */
+ if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
+ return -EINVAL;
+
+ if (! (status & 0x02)) /* BCM4500 firmware loaded */
+ if(gp8psk_load_bcm4500fw(d))
+ return EINVAL;
+
+ if (! (status & 0x04)) /* LNB Power */
+ if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0,
+ &buf, 1))
+ return EINVAL;
+
+ /* Set DVB mode */
+ if(gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0))
+ return -EINVAL;
+ gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
+ } else {
+ /* Turn off LNB power */
+ if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1))
+ return EINVAL;
+ /* Turn off 8psk power */
+ if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
+ return -EINVAL;
+
+ }
+ return 0;
+}
+
+
+static int gp8psk_streaming_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ return gp8psk_usb_out_op(d, ARM_TRANSFER, onoff, 0 , NULL, 0);
+}
+
+static int gp8psk_frontend_attach(struct dvb_usb_device *d)
+{
+ d->fe = gp8psk_fe_attach(d);
+
+ return 0;
+}
+
+static struct dvb_usb_properties gp8psk_properties;
+
+static int gp8psk_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL);
+}
+
+static struct usb_device_id gp8psk_usb_table [] = {
+ { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_COLD) },
+ { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_WARM) },
+ { 0 },
+};
+MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
+
+static struct dvb_usb_properties gp8psk_properties = {
+ .caps = 0,
+
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-gp8psk-01.fw",
+
+ .streaming_ctrl = gp8psk_streaming_ctrl,
+ .power_ctrl = gp8psk_power_ctrl,
+ .frontend_attach = gp8psk_frontend_attach,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+ .urb = {
+ .type = DVB_USB_BULK,
+ .count = 7,
+ .endpoint = 0x82,
+ .u = {
+ .bulk = {
+ .buffersize = 8192,
+ }
+ }
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ { .name = "Genpix 8PSK-USB DVB-S USB2.0 receiver",
+ .cold_ids = { &gp8psk_usb_table[0], NULL },
+ .warm_ids = { &gp8psk_usb_table[1], NULL },
+ },
+ { 0 },
+ }
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver gp8psk_usb_driver = {
+ .name = "dvb_usb_gp8psk",
+ .probe = gp8psk_usb_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = gp8psk_usb_table,
+};
+
+/* module stuff */
+static int __init gp8psk_usb_module_init(void)
+{
+ int result;
+ if ((result = usb_register(&gp8psk_usb_driver))) {
+ err("usb_register failed. (%d)",result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void __exit gp8psk_usb_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&gp8psk_usb_driver);
+}
+
+module_init(gp8psk_usb_module_init);
+module_exit(gp8psk_usb_module_exit);
+
+MODULE_AUTHOR("Alan Nisota <alannisota@gamil.com>");
+MODULE_DESCRIPTION("Driver for Genpix 8psk-USB DVB-S USB2.0");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h
new file mode 100644
index 0000000..3eba706
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/gp8psk.h
@@ -0,0 +1,79 @@
+/* DVB USB compliant Linux driver for the
+ * - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *
+ * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ *
+ * Thanks to GENPIX for the sample code used to implement this module.
+ *
+ * This module is based off the vp7045 and vp702x modules
+ *
+ * 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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_GP8PSK_H_
+#define _DVB_USB_GP8PSK_H_
+
+#define DVB_USB_LOG_PREFIX "gp8psk"
+#include "dvb-usb.h"
+
+extern int dvb_usb_gp8psk_debug;
+#define deb_info(args...) dprintk(dvb_usb_gp8psk_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_gp8psk_debug,0x02,args)
+#define deb_rc(args...) dprintk(dvb_usb_gp8psk_debug,0x04,args)
+#define deb_fe(args...) dprintk(dvb_usb_gp8psk_debug,0x08,args)
+/* gp8psk commands */
+
+/* Twinhan Vendor requests */
+#define TH_COMMAND_IN 0xC0
+#define TH_COMMAND_OUT 0xC1
+
+/* command bytes */
+#define GET_8PSK_CONFIG 0x80
+#define SET_8PSK_CONFIG 0x81
+#define ARM_TRANSFER 0x85
+#define TUNE_8PSK 0x86
+#define GET_SIGNAL_STRENGTH 0x87
+#define LOAD_BCM4500 0x88
+#define BOOT_8PSK 0x89
+#define START_INTERSIL 0x8A
+#define SET_LNB_VOLTAGE 0x8B
+#define SET_22KHZ_TONE 0x8C
+#define SEND_DISEQC_COMMAND 0x8D
+#define SET_DVB_MODE 0x8E
+#define SET_DN_SWITCH 0x8F
+#define GET_SIGNAL_LOCK 0x90
+
+/* Satellite modulation modes */
+#define ADV_MOD_DVB_QPSK 0 /* DVB-S QPSK */
+#define ADV_MOD_TURBO_QPSK 1 /* Turbo QPSK */
+#define ADV_MOD_TURBO_8PSK 2 /* Turbo 8PSK (also used for Trellis 8PSK) */
+#define ADV_MOD_TURBO_16QAM 3 /* Turbo 16QAM (also used for Trellis 8PSK) */
+
+#define ADV_MOD_DCII_C_QPSK 4 /* Digicipher II Combo */
+#define ADV_MOD_DCII_I_QPSK 5 /* Digicipher II I-stream */
+#define ADV_MOD_DCII_Q_QPSK 6 /* Digicipher II Q-stream */
+#define ADV_MOD_DCII_C_OQPSK 7 /* Digicipher II offset QPSK */
+#define ADV_MOD_DSS_QPSK 8 /* DSS (DIRECTV) QPSK */
+#define ADV_MOD_DVB_BPSK 9 /* DVB-S BPSK */
+
+#define GET_USB_SPEED 0x07
+ #define USB_SPEED_LOW 0
+ #define USB_SPEED_FULL 1
+ #define USB_SPEED_HIGH 2
+
+#define RESET_FX2 0x13
+
+#define FW_VERSION_READ 0x0B
+#define VENDOR_STRING_READ 0x0C
+#define PRODUCT_STRING_READ 0x0D
+#define FW_BCD_VERSION_READ 0x14
+
+extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
+extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
+extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+ u16 index, u8 *b, int blen);
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c
index 14f1911..97d74da 100644
--- a/drivers/media/dvb/dvb-usb/umt-010.c
+++ b/drivers/media/dvb/dvb-usb/umt-010.c
@@ -57,7 +57,6 @@ static int umt_mt352_frontend_attach(struct dvb_usb_device *d)
memset(&umt_config,0,sizeof(struct mt352_config));
umt_config.demod_init = umt_mt352_demod_init;
umt_config.demod_address = 0xf;
- umt_config.pll_set = dvb_usb_pll_set;
d->fe = mt352_attach(&umt_config, &d->i2c_adap);
@@ -68,6 +67,7 @@ static int umt_tuner_attach (struct dvb_usb_device *d)
{
d->pll_addr = 0x61;
d->pll_desc = &dvb_pll_tua6034;
+ d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
return 0;
}
diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c
index 2a89f8c..d4da494 100644
--- a/drivers/media/dvb/dvb-usb/vp702x-fe.c
+++ b/drivers/media/dvb/dvb-usb/vp702x-fe.c
@@ -287,17 +287,16 @@ struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d)
goto error;
s->d = d;
- s->fe.ops = &vp702x_fe_ops;
+
+ memcpy(&s->fe.ops,&vp702x_fe_ops,sizeof(struct dvb_frontend_ops));
s->fe.demodulator_priv = s;
s->lnb_buf[1] = SET_LNB_POWER;
s->lnb_buf[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */
- goto success;
+ return &s->fe;
error:
return NULL;
-success:
- return &s->fe;
}
diff --git a/drivers/media/dvb/dvb-usb/vp7045-fe.c b/drivers/media/dvb/dvb-usb/vp7045-fe.c
index 9999336..8452eef 100644
--- a/drivers/media/dvb/dvb-usb/vp7045-fe.c
+++ b/drivers/media/dvb/dvb-usb/vp7045-fe.c
@@ -23,8 +23,6 @@
struct vp7045_fe_state {
struct dvb_frontend fe;
- struct dvb_frontend_ops ops;
-
struct dvb_usb_device *d;
};
@@ -151,15 +149,12 @@ struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d)
goto error;
s->d = d;
- memcpy(&s->ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops));
- s->fe.ops = &s->ops;
+ memcpy(&s->fe.ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops));
s->fe.demodulator_priv = s;
- goto success;
+ return &s->fe;
error:
return NULL;
-success:
- return &s->fe;
}
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 37d5e0a..0ef361f 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -157,7 +157,7 @@ config DVB_STV0297
help
A DVB-C tuner module. Say Y when you want to support this frontend.
-comment "ATSC (North American/Korean Terresterial DTV) frontends"
+comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends"
depends on DVB_CORE
config DVB_NXT200X
@@ -216,4 +216,20 @@ config DVB_LGDT330X
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
+
+comment "Miscellaneous devices"
+ depends on DVB_CORE
+
+config DVB_LNBP21
+ tristate "LNBP21 SEC controller"
+ depends on DVB_CORE
+ help
+ An SEC control chip.
+
+config DVB_ISL6421
+ tristate "ISL6421 SEC controller"
+ depends on DVB_CORE
+ help
+ An SEC control chip.
+
endmenu
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index d09b607..5222245 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -31,3 +31,5 @@ obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
obj-$(CONFIG_DVB_CX24123) += cx24123.o
+obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
+obj-$(CONFIG_DVB_ISL6421) += isl6421.o
diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c
index 1708a1d..baeb311d 100644
--- a/drivers/media/dvb/frontends/bcm3510.c
+++ b/drivers/media/dvb/frontends/bcm3510.c
@@ -48,7 +48,6 @@
struct bcm3510_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct bcm3510_config* config;
struct dvb_frontend frontend;
@@ -791,10 +790,9 @@ struct dvb_frontend* bcm3510_attach(const struct bcm3510_config *config,
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops));
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
mutex_init(&state->hab_mutex);
diff --git a/drivers/media/dvb/frontends/bsbe1.h b/drivers/media/dvb/frontends/bsbe1.h
index 78573b2..d8f6573 100644
--- a/drivers/media/dvb/frontends/bsbe1.h
+++ b/drivers/media/dvb/frontends/bsbe1.h
@@ -89,12 +89,13 @@ static int alps_bsbe1_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ra
return 0;
}
-static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
+static int alps_bsbe1_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
int ret;
u8 data[4];
u32 div;
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+ struct i2c_adapter *i2c = fe->tuner_priv;
if ((params->frequency < 950000) || (params->frequency > 2150000))
return -EINVAL;
@@ -105,6 +106,8 @@ static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c,
data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
ret = i2c_transfer(i2c, &msg, 1);
return (ret != 1) ? -EIO : 0;
}
@@ -117,7 +120,6 @@ static struct stv0299_config alps_bsbe1_config = {
.skip_reinit = 0,
.min_delay_ms = 100,
.set_symbol_rate = alps_bsbe1_set_symbol_rate,
- .pll_set = alps_bsbe1_pll_set,
};
#endif
diff --git a/drivers/media/dvb/frontends/bsru6.h b/drivers/media/dvb/frontends/bsru6.h
index 2a5366c..e231cd8 100644
--- a/drivers/media/dvb/frontends/bsru6.h
+++ b/drivers/media/dvb/frontends/bsru6.h
@@ -101,11 +101,12 @@ static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ra
return 0;
}
-static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params)
+static int alps_bsru6_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
u8 buf[4];
u32 div;
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ struct i2c_adapter *i2c = fe->tuner_priv;
if ((params->frequency < 950000) || (params->frequency > 2150000))
return -EINVAL;
@@ -119,6 +120,8 @@ static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c,
if (params->frequency > 1530000)
buf[3] = 0xc0;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(i2c, &msg, 1) != 1)
return -EIO;
return 0;
@@ -134,7 +137,6 @@ static struct stv0299_config alps_bsru6_config = {
.volt13_op0_op1 = STV0299_VOLT13_OP1,
.min_delay_ms = 100,
.set_symbol_rate = alps_bsru6_set_symbol_rate,
- .pll_set = alps_bsru6_pll_set,
};
#endif
diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c
index 755f774..3c7c09a 100644
--- a/drivers/media/dvb/frontends/cx22700.c
+++ b/drivers/media/dvb/frontends/cx22700.c
@@ -34,8 +34,6 @@ struct cx22700_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
-
const struct cx22700_config* config;
struct dvb_frontend frontend;
@@ -247,12 +245,6 @@ static int cx22700_init (struct dvb_frontend* fe)
cx22700_writereg (state, 0x00, 0x01);
- if (state->config->pll_init) {
- cx22700_writereg (state, 0x0a, 0x00); /* open i2c bus switch */
- state->config->pll_init(fe);
- cx22700_writereg (state, 0x0a, 0x01); /* close i2c bus switch */
- }
-
return 0;
}
@@ -333,9 +325,11 @@ static int cx22700_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/
cx22700_writereg (state, 0x00, 0x00);
- cx22700_writereg (state, 0x0a, 0x00); /* open i2c bus switch */
- state->config->pll_set(fe, p);
- cx22700_writereg (state, 0x0a, 0x01); /* close i2c bus switch */
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
cx22700_set_inversion (state, p->inversion);
cx22700_set_tps (state, &p->u.ofdm);
cx22700_writereg (state, 0x37, 0x01); /* PAL loop filter off */
@@ -353,6 +347,17 @@ static int cx22700_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
return cx22700_get_tps (state, &p->u.ofdm);
}
+static int cx22700_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct cx22700_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return cx22700_writereg(state, 0x0a, 0x00);
+ } else {
+ return cx22700_writereg(state, 0x0a, 0x01);
+ }
+}
+
static int cx22700_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
fesettings->min_delay_ms = 150;
@@ -381,13 +386,12 @@ struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &cx22700_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if (cx22700_readreg(state, 0x07) < 0) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &cx22700_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -413,6 +417,7 @@ static struct dvb_frontend_ops cx22700_ops = {
.release = cx22700_release,
.init = cx22700_init,
+ .i2c_gate_ctrl = cx22700_i2c_gate_ctrl,
.set_frontend = cx22700_set_frontend,
.get_frontend = cx22700_get_frontend,
diff --git a/drivers/media/dvb/frontends/cx22700.h b/drivers/media/dvb/frontends/cx22700.h
index c9145b4..dcd8979 100644
--- a/drivers/media/dvb/frontends/cx22700.h
+++ b/drivers/media/dvb/frontends/cx22700.h
@@ -29,10 +29,6 @@ struct cx22700_config
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index 0fc899f..4106d46 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -40,8 +40,6 @@ struct cx22702_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
-
/* configuration settings */
const struct cx22702_config* config;
@@ -211,22 +209,10 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet
u8 val;
struct cx22702_state* state = fe->demodulator_priv;
- /* set PLL */
- cx22702_i2c_gate_ctrl(fe, 1);
- if (state->config->pll_set) {
- state->config->pll_set(fe, p);
- } else if (state->config->pll_desc) {
- u8 pllbuf[4];
- struct i2c_msg msg = { .addr = state->config->pll_address,
- .buf = pllbuf, .len = 4 };
- dvb_pll_configure(state->config->pll_desc, pllbuf,
- p->frequency,
- p->u.ofdm.bandwidth);
- i2c_transfer(state->i2c, &msg, 1);
- } else {
- BUG();
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
- cx22702_i2c_gate_ctrl(fe, 0);
/* set inversion */
cx22702_set_inversion (state, p->inversion);
@@ -358,10 +344,6 @@ static int cx22702_init (struct dvb_frontend* fe)
cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02);
- /* init PLL */
- if (state->config->pll_init)
- state->config->pll_init(fe);
-
cx22702_i2c_gate_ctrl(fe, 0);
return 0;
@@ -495,7 +477,6 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &cx22702_ops, sizeof(struct dvb_frontend_ops));
state->prevUCBlocks = 0;
/* check if the demod is there */
@@ -503,7 +484,7 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &cx22702_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -530,6 +511,7 @@ static struct dvb_frontend_ops cx22702_ops = {
.release = cx22702_release,
.init = cx22702_init,
+ .i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
.set_frontend = cx22702_set_tps,
.get_frontend = cx22702_get_frontend,
@@ -540,7 +522,6 @@ static struct dvb_frontend_ops cx22702_ops = {
.read_signal_strength = cx22702_read_signal_strength,
.read_snr = cx22702_read_snr,
.read_ucblocks = cx22702_read_ucblocks,
- .i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
};
module_param(debug, int, 0644);
diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h
index 5633976..7f2f241 100644
--- a/drivers/media/dvb/frontends/cx22702.h
+++ b/drivers/media/dvb/frontends/cx22702.h
@@ -39,13 +39,6 @@ struct cx22702_config
#define CX22702_PARALLEL_OUTPUT 0
#define CX22702_SERIAL_OUTPUT 1
u8 output_mode;
-
- /* PLL maintenance */
- u8 pll_address;
- struct dvb_pll_desc *pll_desc;
-
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index f3edf8b..ce3c739 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -36,8 +36,6 @@ struct cx24110_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
-
const struct cx24110_config* config;
struct dvb_frontend frontend;
@@ -250,7 +248,7 @@ static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
static const u32 bands[]={5000000UL,15000000UL,90999000UL/2};
int i;
-dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
+ dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
if (srate>90999000UL/2)
srate=90999000UL/2;
if (srate<500000)
@@ -366,17 +364,6 @@ static int cx24110_initfe(struct dvb_frontend* fe)
cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data);
};
- if (state->config->pll_init) state->config->pll_init(fe);
-
- return 0;
-}
-
-static int cx24110_sleep(struct dvb_frontend *fe)
-{
- struct cx24110_state *state = fe->demodulator_priv;
-
- if (state->config->pll_sleep)
- return state->config->pll_sleep(fe);
return 0;
}
@@ -548,7 +535,12 @@ static int cx24110_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
{
struct cx24110_state *state = fe->demodulator_priv;
- state->config->pll_set(fe, p);
+
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
cx24110_set_inversion (state, p->inversion);
cx24110_set_fec (state, p->u.qpsk.fec_inner);
cx24110_set_symbolrate (state, p->u.qpsk.symbol_rate);
@@ -612,7 +604,6 @@ struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
state->lastber = 0;
state->lastbler = 0;
state->lastesn0 = 0;
@@ -622,7 +613,7 @@ struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
if ((ret != 0x5a) && (ret != 0x69)) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -651,7 +642,6 @@ static struct dvb_frontend_ops cx24110_ops = {
.release = cx24110_release,
.init = cx24110_initfe,
- .sleep = cx24110_sleep,
.set_frontend = cx24110_set_frontend,
.get_frontend = cx24110_get_frontend,
.read_status = cx24110_read_status,
diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h
index 609ac64..b354a64 100644
--- a/drivers/media/dvb/frontends/cx24110.h
+++ b/drivers/media/dvb/frontends/cx24110.h
@@ -31,11 +31,6 @@ struct cx24110_config
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
- int (*pll_sleep)(struct dvb_frontend* fe);
};
extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index 691dc84..f2f795c 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -41,14 +41,12 @@ static int debug;
struct cx24123_state
{
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct cx24123_config* config;
struct dvb_frontend frontend;
u32 lastber;
u16 snr;
- u8 lnbreg;
/* Some PLL specifics for tuning */
u32 VCAarg;
@@ -249,29 +247,6 @@ static int cx24123_writereg(struct cx24123_state* state, int reg, int data)
return 0;
}
-static int cx24123_writelnbreg(struct cx24123_state* state, int reg, int data)
-{
- u8 buf[] = { reg, data };
- /* fixme: put the intersil addr int the config */
- struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 2 };
- int err;
-
- if (debug>1)
- printk("cx24123: %s: writeln addr=0x08, reg 0x%02x, value 0x%02x\n",
- __FUNCTION__,reg, data);
-
- if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
- printk("%s: writelnbreg error (err == %i, reg == 0x%02x,"
- " data == 0x%02x)\n", __FUNCTION__, err, reg, data);
- return -EREMOTEIO;
- }
-
- /* cache the write, no way to read back */
- state->lnbreg = data;
-
- return 0;
-}
-
static int cx24123_readreg(struct cx24123_state* state, u8 reg)
{
int ret;
@@ -295,11 +270,6 @@ static int cx24123_readreg(struct cx24123_state* state, u8 reg)
return b1[0];
}
-static int cx24123_readlnbreg(struct cx24123_state* state, u8 reg)
-{
- return state->lnbreg;
-}
-
static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion)
{
u8 nom_reg = cx24123_readreg(state, 0x0e);
@@ -458,8 +428,8 @@ static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate)
u8 pll_mult;
/* check if symbol rate is within limits */
- if ((srate > state->ops.info.symbol_rate_max) ||
- (srate < state->ops.info.symbol_rate_min))
+ if ((srate > state->frontend.ops.info.symbol_rate_max) ||
+ (srate < state->frontend.ops.info.symbol_rate_min))
return -EOPNOTSUPP;;
/* choose the sampling rate high enough for the required operation,
@@ -687,13 +657,6 @@ static int cx24123_initfe(struct dvb_frontend* fe)
for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++)
cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
- if (state->config->pll_init)
- state->config->pll_init(fe);
-
- /* Configure the LNB for 14V */
- if (state->config->use_isl6421)
- cx24123_writelnbreg(state, 0x0, 0x2a);
-
return 0;
}
@@ -702,50 +665,18 @@ static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage
struct cx24123_state *state = fe->demodulator_priv;
u8 val;
- switch (state->config->use_isl6421) {
-
- case 1:
+ val = cx24123_readreg(state, 0x29) & ~0x40;
- val = cx24123_readlnbreg(state, 0x0);
-
- switch (voltage) {
- case SEC_VOLTAGE_13:
- dprintk("%s: isl6421 voltage = 13V\n",__FUNCTION__);
- return cx24123_writelnbreg(state, 0x0, val & 0x32); /* V 13v */
- case SEC_VOLTAGE_18:
- dprintk("%s: isl6421 voltage = 18V\n",__FUNCTION__);
- return cx24123_writelnbreg(state, 0x0, val | 0x04); /* H 18v */
- case SEC_VOLTAGE_OFF:
- dprintk("%s: isl5421 voltage off\n",__FUNCTION__);
- return cx24123_writelnbreg(state, 0x0, val & 0x30);
- default:
- return -EINVAL;
- };
-
- case 0:
-
- val = cx24123_readreg(state, 0x29);
-
- switch (voltage) {
- case SEC_VOLTAGE_13:
- dprintk("%s: setting voltage 13V\n", __FUNCTION__);
- if (state->config->enable_lnb_voltage)
- state->config->enable_lnb_voltage(fe, 1);
- return cx24123_writereg(state, 0x29, val | 0x80);
- case SEC_VOLTAGE_18:
- dprintk("%s: setting voltage 18V\n", __FUNCTION__);
- if (state->config->enable_lnb_voltage)
- state->config->enable_lnb_voltage(fe, 1);
- return cx24123_writereg(state, 0x29, val & 0x7f);
- case SEC_VOLTAGE_OFF:
- dprintk("%s: setting voltage off\n", __FUNCTION__);
- if (state->config->enable_lnb_voltage)
- state->config->enable_lnb_voltage(fe, 0);
- return 0;
- default:
- return -EINVAL;
- };
- }
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ dprintk("%s: setting voltage 13V\n", __FUNCTION__);
+ return cx24123_writereg(state, 0x29, val | 0x80);
+ case SEC_VOLTAGE_18:
+ dprintk("%s: setting voltage 18V\n", __FUNCTION__);
+ return cx24123_writereg(state, 0x29, val & 0x7f);
+ default:
+ return -EINVAL;
+ };
return 0;
}
@@ -766,27 +697,20 @@ static void cx24123_wait_for_diseqc(struct cx24123_state *state)
static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd)
{
struct cx24123_state *state = fe->demodulator_priv;
- int i, val;
+ int i, val, tone;
dprintk("%s:\n",__FUNCTION__);
- /* check if continuous tone has been stopped */
- if (state->config->use_isl6421)
- val = cx24123_readlnbreg(state, 0x00) & 0x10;
- else
- val = cx24123_readreg(state, 0x29) & 0x10;
-
-
- if (val) {
- printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__);
- return -ENOTSUPP;
- }
+ /* stop continuous tone if enabled */
+ tone = cx24123_readreg(state, 0x29);
+ if (tone & 0x10)
+ cx24123_writereg(state, 0x29, tone & ~0x50);
/* wait for diseqc queue ready */
cx24123_wait_for_diseqc(state);
/* select tone mode */
- cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xf8);
+ cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
for (i = 0; i < cmd->msg_len; i++)
cx24123_writereg(state, 0x2C + i, cmd->msg[i]);
@@ -797,36 +721,33 @@ static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma
/* wait for diseqc message to finish sending */
cx24123_wait_for_diseqc(state);
+ /* restart continuous tone if enabled */
+ if (tone & 0x10) {
+ cx24123_writereg(state, 0x29, tone & ~0x40);
+ }
+
return 0;
}
static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
{
struct cx24123_state *state = fe->demodulator_priv;
- int val;
+ int val, tone;
dprintk("%s:\n", __FUNCTION__);
- /* check if continuous tone has been stoped */
- if (state->config->use_isl6421)
- val = cx24123_readlnbreg(state, 0x00) & 0x10;
- else
- val = cx24123_readreg(state, 0x29) & 0x10;
-
-
- if (val) {
- printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__);
- return -ENOTSUPP;
- }
+ /* stop continuous tone if enabled */
+ tone = cx24123_readreg(state, 0x29);
+ if (tone & 0x10)
+ cx24123_writereg(state, 0x29, tone & ~0x50);
+ /* wait for diseqc queue ready */
cx24123_wait_for_diseqc(state);
/* select tone mode */
- val = cx24123_readreg(state, 0x2a) & 0xf8;
- cx24123_writereg(state, 0x2a, val | 0x04);
-
+ cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) | 0x4);
+ msleep(30);
val = cx24123_readreg(state, 0x29);
-
if (burst == SEC_MINI_A)
cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x00));
else if (burst == SEC_MINI_B)
@@ -835,7 +756,12 @@ static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t
return -EINVAL;
cx24123_wait_for_diseqc(state);
+ cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
+ /* restart continuous tone if enabled */
+ if (tone & 0x10) {
+ cx24123_writereg(state, 0x29, tone & ~0x40);
+ }
return 0;
}
@@ -976,38 +902,21 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
struct cx24123_state *state = fe->demodulator_priv;
u8 val;
- switch (state->config->use_isl6421) {
- case 1:
-
- val = cx24123_readlnbreg(state, 0x0);
-
- switch (tone) {
- case SEC_TONE_ON:
- dprintk("%s: isl6421 sec tone on\n",__FUNCTION__);
- return cx24123_writelnbreg(state, 0x0, val | 0x10);
- case SEC_TONE_OFF:
- dprintk("%s: isl6421 sec tone off\n",__FUNCTION__);
- return cx24123_writelnbreg(state, 0x0, val & 0x2f);
- default:
- printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
- return -EINVAL;
- }
-
- case 0:
+ /* wait for diseqc queue ready */
+ cx24123_wait_for_diseqc(state);
- val = cx24123_readreg(state, 0x29);
+ val = cx24123_readreg(state, 0x29) & ~0x40;
- switch (tone) {
- case SEC_TONE_ON:
- dprintk("%s: setting tone on\n", __FUNCTION__);
- return cx24123_writereg(state, 0x29, val | 0x10);
- case SEC_TONE_OFF:
- dprintk("%s: setting tone off\n",__FUNCTION__);
- return cx24123_writereg(state, 0x29, val & 0xef);
- default:
- printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
- return -EINVAL;
- }
+ switch (tone) {
+ case SEC_TONE_ON:
+ dprintk("%s: setting tone on\n", __FUNCTION__);
+ return cx24123_writereg(state, 0x29, val | 0x10);
+ case SEC_TONE_OFF:
+ dprintk("%s: setting tone off\n",__FUNCTION__);
+ return cx24123_writereg(state, 0x29, val & 0xef);
+ default:
+ printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
+ return -EINVAL;
}
return 0;
@@ -1040,10 +949,8 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
state->lastber = 0;
state->snr = 0;
- state->lnbreg = 0;
state->VCAarg = 0;
state->VGAarg = 0;
state->bandselectarg = 0;
@@ -1059,7 +966,7 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h
index 0c922b5..9606f82 100644
--- a/drivers/media/dvb/frontends/cx24123.h
+++ b/drivers/media/dvb/frontends/cx24123.h
@@ -28,21 +28,8 @@ struct cx24123_config
/* the demodulator's i2c address */
u8 demod_address;
- /*
- cards like Hauppauge Nova-S Plus/Nova-SE2 use an Intersil ISL6421 chip
- for LNB control, while KWorld DVB-S 100 use the LNBDC and LNBTone bits
- from register 0x29 of the CX24123 demodulator
- */
- int use_isl6421;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
/* Need to set device param for start_dma */
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
-
- void (*enable_lnb_voltage)(struct dvb_frontend* fe, int on);
};
extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
diff --git a/drivers/media/dvb/frontends/dib3000-common.h b/drivers/media/dvb/frontends/dib3000-common.h
index c31d6df..be1c0d3 100644
--- a/drivers/media/dvb/frontends/dib3000-common.h
+++ b/drivers/media/dvb/frontends/dib3000-common.h
@@ -38,8 +38,6 @@
struct dib3000_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
-
/* configuration settings */
struct dib3000_config config;
diff --git a/drivers/media/dvb/frontends/dib3000.h b/drivers/media/dvb/frontends/dib3000.h
index 2d5475b..ec92762 100644
--- a/drivers/media/dvb/frontends/dib3000.h
+++ b/drivers/media/dvb/frontends/dib3000.h
@@ -30,10 +30,6 @@ struct dib3000_config
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance and the i2c address of the PLL */
- int (*pll_init)(struct dvb_frontend *fe);
- int (*pll_set)(struct dvb_frontend *fe, struct dvb_frontend_parameters* params);
};
struct dib_fe_xfer_ops
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
index ae589ad..7c6dc7e 100644
--- a/drivers/media/dvb/frontends/dib3000mb.c
+++ b/drivers/media/dvb/frontends/dib3000mb.c
@@ -60,8 +60,9 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
fe_code_rate_t fe_cr = FEC_NONE;
int search_state, seq;
- if (tuner && state->config.pll_set) {
- state->config.pll_set(fe, fep);
+ if (tuner && fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, fep);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
deb_setf("bandwidth: ");
switch (ofdm->bandwidth) {
@@ -386,9 +387,6 @@ static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
wr(DIB3000MB_REG_DATA_IN_DIVERSITY, DIB3000MB_DATA_DIVERSITY_IN_OFF);
- if (state->config.pll_init)
- state->config.pll_init(fe);
-
return 0;
}
@@ -707,7 +705,6 @@ struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
/* setup the state */
state->i2c = i2c;
memcpy(&state->config,config,sizeof(struct dib3000_config));
- memcpy(&state->ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops));
/* check for the correct demod */
if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
@@ -717,7 +714,7 @@ struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
/* set the xfer operations */
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
index 3b303db..6c3be25 100644
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb/frontends/dib3000mc.c
@@ -462,8 +462,9 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
int search_state,auto_val;
u16 val;
- if (tuner && state->config.pll_set) { /* initial call from dvb */
- state->config.pll_set(fe,fep);
+ if (tuner && fe->ops.tuner_ops.set_params) { /* initial call from dvb */
+ fe->ops.tuner_ops.set_params(fe, fep);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
state->last_tuned_freq = fep->frequency;
// if (!scanboost) {
@@ -642,9 +643,6 @@ static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode)
set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF);
- if (state->config.pll_init)
- state->config.pll_init(fe);
-
deb_info("init end\n");
return 0;
}
@@ -839,7 +837,6 @@ struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
/* setup the state */
state->i2c = i2c;
memcpy(&state->config,config,sizeof(struct dib3000_config));
- memcpy(&state->ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
/* check for the correct demod */
if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
@@ -859,7 +856,7 @@ struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
/* set the xfer operations */
@@ -876,6 +873,7 @@ error:
kfree(state);
return NULL;
}
+EXPORT_SYMBOL(dib3000mc_attach);
static struct dvb_frontend_ops dib3000mc_ops = {
@@ -914,5 +912,3 @@ static struct dvb_frontend_ops dib3000mc_ops = {
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(dib3000mc_attach);
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 791706e..a189683 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -227,10 +227,10 @@ struct dvb_pll_desc dvb_pll_tua6034 = {
EXPORT_SYMBOL(dvb_pll_tua6034);
/* Infineon TUA6034
- * used in LG TDVS H061F and LG TDVS H062F
+ * used in LG TDVS-H061F, LG TDVS-H062F and LG TDVS-H064F
*/
-struct dvb_pll_desc dvb_pll_tdvs_tua6034 = {
- .name = "LG/Infineon TUA6034",
+struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
+ .name = "LG TDVS-H06xF",
.min = 54000000,
.max = 863000000,
.count = 3,
@@ -240,7 +240,7 @@ struct dvb_pll_desc dvb_pll_tdvs_tua6034 = {
{ 999999999, 44000000, 62500, 0xce, 0x04 },
},
};
-EXPORT_SYMBOL(dvb_pll_tdvs_tua6034);
+EXPORT_SYMBOL(dvb_pll_lg_tdvs_h06xf);
/* Philips FMD1216ME
* used in Medion Hybrid PCMCIA card and USB Box
@@ -419,6 +419,19 @@ struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
};
EXPORT_SYMBOL(dvb_pll_thomson_fe6600);
+struct dvb_pll_priv {
+ /* i2c details */
+ int pll_i2c_address;
+ struct i2c_adapter *i2c;
+
+ /* the PLL descriptor */
+ struct dvb_pll_desc *pll_desc;
+
+ /* cached frequency/bandwidth */
+ u32 frequency;
+ u32 bandwidth;
+};
+
/* ----------------------------------------------------------- */
/* code */
@@ -443,7 +456,8 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
if (debug)
printk("pll: %s: freq=%d bw=%d | i=%d/%d\n",
desc->name, freq, bandwidth, i, desc->count);
- BUG_ON(i == desc->count);
+ if (i == desc->count)
+ return -EINVAL;
div = (freq + desc->entries[i].offset) / desc->entries[i].stepsize;
buf[0] = div >> 8;
@@ -462,6 +476,163 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
}
EXPORT_SYMBOL(dvb_pll_configure);
+static int dvb_pll_release(struct dvb_frontend *fe)
+{
+ if (fe->tuner_priv)
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static int dvb_pll_sleep(struct dvb_frontend *fe)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ u8 buf[4];
+ struct i2c_msg msg =
+ { .addr = priv->pll_i2c_address, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ int i;
+ int result;
+
+ for (i = 0; i < priv->pll_desc->count; i++) {
+ if (priv->pll_desc->entries[i].limit == 0)
+ break;
+ }
+ if (i == priv->pll_desc->count)
+ return 0;
+
+ buf[0] = 0;
+ buf[1] = 0;
+ buf[2] = priv->pll_desc->entries[i].config;
+ buf[3] = priv->pll_desc->entries[i].cb;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+ return result;
+ }
+
+ return 0;
+}
+
+static int dvb_pll_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ u8 buf[4];
+ struct i2c_msg msg =
+ { .addr = priv->pll_i2c_address, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ int result;
+ u32 div;
+ int i;
+ u32 bandwidth = 0;
+
+ if (priv->i2c == NULL)
+ return -EINVAL;
+
+ // DVBT bandwidth only just now
+ if (fe->ops.info.type == FE_OFDM) {
+ bandwidth = params->u.ofdm.bandwidth;
+ }
+
+ if ((result = dvb_pll_configure(priv->pll_desc, buf, params->frequency, bandwidth)) != 0)
+ return result;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+ return result;
+ }
+
+ // calculate the frequency we set it to
+ for (i = 0; i < priv->pll_desc->count; i++) {
+ if (params->frequency > priv->pll_desc->entries[i].limit)
+ continue;
+ break;
+ }
+ div = (params->frequency + priv->pll_desc->entries[i].offset) / priv->pll_desc->entries[i].stepsize;
+ priv->frequency = (div * priv->pll_desc->entries[i].stepsize) - priv->pll_desc->entries[i].offset;
+ priv->bandwidth = bandwidth;
+
+ return 0;
+}
+
+static int dvb_pll_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8 *buf, int buf_len)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ int result;
+ u32 div;
+ int i;
+ u32 bandwidth = 0;
+
+ if (buf_len < 5)
+ return -EINVAL;
+
+ // DVBT bandwidth only just now
+ if (fe->ops.info.type == FE_OFDM) {
+ bandwidth = params->u.ofdm.bandwidth;
+ }
+
+ if ((result = dvb_pll_configure(priv->pll_desc, buf+1, params->frequency, bandwidth)) != 0)
+ return result;
+ buf[0] = priv->pll_i2c_address;
+
+ // calculate the frequency we set it to
+ for (i = 0; i < priv->pll_desc->count; i++) {
+ if (params->frequency > priv->pll_desc->entries[i].limit)
+ continue;
+ break;
+ }
+ div = (params->frequency + priv->pll_desc->entries[i].offset) / priv->pll_desc->entries[i].stepsize;
+ priv->frequency = (div * priv->pll_desc->entries[i].stepsize) - priv->pll_desc->entries[i].offset;
+ priv->bandwidth = bandwidth;
+
+ return 5;
+}
+
+static int dvb_pll_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static int dvb_pll_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ *bandwidth = priv->bandwidth;
+ return 0;
+}
+
+static struct dvb_tuner_ops dvb_pll_tuner_ops = {
+ .release = dvb_pll_release,
+ .sleep = dvb_pll_sleep,
+ .set_params = dvb_pll_set_params,
+ .calc_regs = dvb_pll_calc_regs,
+ .get_frequency = dvb_pll_get_frequency,
+ .get_bandwidth = dvb_pll_get_bandwidth,
+};
+
+int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc)
+{
+ struct dvb_pll_priv *priv = NULL;
+
+ priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+
+ priv->pll_i2c_address = pll_addr;
+ priv->i2c = i2c;
+ priv->pll_desc = desc;
+
+ memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, sizeof(struct dvb_tuner_ops));
+ strncpy(fe->ops.tuner_ops.info.name, desc->name, 128);
+ fe->ops.tuner_ops.info.frequency_min = desc->min;
+ fe->ops.tuner_ops.info.frequency_min = desc->max;
+
+ fe->tuner_priv = priv;
+ return 0;
+}
+EXPORT_SYMBOL(dvb_pll_attach);
+
MODULE_DESCRIPTION("dvb pll library");
MODULE_AUTHOR("Gerd Knorr");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index 2b84617..66361cd 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -5,6 +5,9 @@
#ifndef __DVB_PLL_H__
#define __DVB_PLL_H__
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
struct dvb_pll_desc {
char *name;
u32 min;
@@ -31,7 +34,7 @@ extern struct dvb_pll_desc dvb_pll_unknown_1;
extern struct dvb_pll_desc dvb_pll_tua6010xs;
extern struct dvb_pll_desc dvb_pll_env57h1xd5;
extern struct dvb_pll_desc dvb_pll_tua6034;
-extern struct dvb_pll_desc dvb_pll_tdvs_tua6034;
+extern struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf;
extern struct dvb_pll_desc dvb_pll_tda665x;
extern struct dvb_pll_desc dvb_pll_fmd1216me;
extern struct dvb_pll_desc dvb_pll_tded4;
@@ -44,7 +47,18 @@ extern struct dvb_pll_desc dvb_pll_philips_td1316;
extern struct dvb_pll_desc dvb_pll_thomson_fe6600;
-int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
+extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
u32 freq, int bandwidth);
+/**
+ * Attach a dvb-pll to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param pll_addr i2c address of the PLL (if used).
+ * @param i2c i2c adapter to use (set to NULL if not used).
+ * @param desc dvb_pll_desc to use.
+ * @return 0 on success, nonzero on failure.
+ */
+extern int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc);
+
#endif
diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c
index 645946a..6271b1e 100644
--- a/drivers/media/dvb/frontends/dvb_dummy_fe.c
+++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c
@@ -30,7 +30,6 @@
struct dvb_dummy_fe_state {
- struct dvb_frontend_ops ops;
struct dvb_frontend frontend;
};
@@ -77,6 +76,11 @@ static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_fronten
static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
+ if (fe->ops->tuner_ops->set_params) {
+ fe->ops->tuner_ops->set_params(fe, p);
+ if (fe->ops->i2c_gate_ctrl) fe->ops->i2c_gate_ctrl(fe, 0);
+ }
+
return 0;
}
@@ -116,11 +120,8 @@ struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void)
state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
if (state == NULL) goto error;
- /* setup the state */
- memcpy(&state->ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops));
-
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -139,11 +140,8 @@ struct dvb_frontend* dvb_dummy_fe_qpsk_attach()
state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
if (state == NULL) goto error;
- /* setup the state */
- memcpy(&state->ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops));
-
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -162,11 +160,8 @@ struct dvb_frontend* dvb_dummy_fe_qam_attach()
state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
if (state == NULL) goto error;
- /* setup the state */
- memcpy(&state->ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops));
-
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/isl6421.c b/drivers/media/dvb/frontends/isl6421.c
new file mode 100644
index 0000000..58c34db
--- /dev/null
+++ b/drivers/media/dvb/frontends/isl6421.c
@@ -0,0 +1,149 @@
+/*
+ * isl6421.h - driver for lnb supply and control ic ISL6421
+ *
+ * Copyright (C) 2006 Andrew de Quincey
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * 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.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "isl6421.h"
+
+struct isl6421 {
+ u8 config;
+ u8 override_or;
+ u8 override_and;
+ struct i2c_adapter *i2c;
+ u8 i2c_addr;
+ void (*release_chain)(struct dvb_frontend* fe);
+};
+
+static int isl6421_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+ struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0,
+ .buf = &isl6421->config,
+ .len = sizeof(isl6421->config) };
+
+ isl6421->config &= ~(ISL6421_VSEL1 | ISL6421_EN1);
+
+ switch(voltage) {
+ case SEC_VOLTAGE_OFF:
+ break;
+ case SEC_VOLTAGE_13:
+ isl6421->config |= ISL6421_EN1;
+ break;
+ case SEC_VOLTAGE_18:
+ isl6421->config |= (ISL6421_EN1 | ISL6421_VSEL1);
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ isl6421->config |= isl6421->override_or;
+ isl6421->config &= isl6421->override_and;
+
+ return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int isl6421_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+ struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+ struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0,
+ .buf = &isl6421->config,
+ .len = sizeof(isl6421->config) };
+
+ if (arg)
+ isl6421->config |= ISL6421_LLC1;
+ else
+ isl6421->config &= ~ISL6421_LLC1;
+
+ isl6421->config |= isl6421->override_or;
+ isl6421->config &= isl6421->override_and;
+
+ return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void isl6421_release(struct dvb_frontend *fe)
+{
+ struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+
+ /* power off */
+ isl6421_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+ /* free data & call next release routine */
+ fe->ops.release = isl6421->release_chain;
+ kfree(fe->misc_priv);
+ fe->misc_priv = NULL;
+ if (fe->ops.release)
+ fe->ops.release(fe);
+}
+
+int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+ u8 override_set, u8 override_clear)
+{
+ struct isl6421 *isl6421 = kmalloc(sizeof(struct isl6421), GFP_KERNEL);
+ if (!isl6421)
+ return -ENOMEM;
+
+ /* default configuration */
+ isl6421->config = ISL6421_ISEL1;
+ isl6421->i2c = i2c;
+ isl6421->i2c_addr = i2c_addr;
+ fe->misc_priv = isl6421;
+
+ /* bits which should be forced to '1' */
+ isl6421->override_or = override_set;
+
+ /* bits which should be forced to '0' */
+ isl6421->override_and = ~override_clear;
+
+ /* detect if it is present or not */
+ if (isl6421_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+ kfree(isl6421);
+ fe->misc_priv = NULL;
+ return -EIO;
+ }
+
+ /* install release callback */
+ isl6421->release_chain = fe->ops.release;
+ fe->ops.release = isl6421_release;
+
+ /* override frontend ops */
+ fe->ops.set_voltage = isl6421_set_voltage;
+ fe->ops.enable_high_lnb_voltage = isl6421_enable_high_lnb_voltage;
+
+ return 0;
+}
+EXPORT_SYMBOL(isl6421_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6421");
+MODULE_AUTHOR("Andrew de Quincey & Oliver Endriss");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/isl6421.h b/drivers/media/dvb/frontends/isl6421.h
new file mode 100644
index 0000000..675f80a
--- /dev/null
+++ b/drivers/media/dvb/frontends/isl6421.h
@@ -0,0 +1,46 @@
+/*
+ * isl6421.h - driver for lnb supply and control ic ISL6421
+ *
+ * Copyright (C) 2006 Andrew de Quincey
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * 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.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef _ISL6421_H
+#define _ISL6421_H
+
+#include <linux/dvb/frontend.h>
+
+/* system register bits */
+#define ISL6421_OLF1 0x01
+#define ISL6421_EN1 0x02
+#define ISL6421_VSEL1 0x04
+#define ISL6421_LLC1 0x08
+#define ISL6421_ENT1 0x10
+#define ISL6421_ISEL1 0x20
+#define ISL6421_DCL 0x40
+
+/* override_set and override_clear control which system register bits (above) to always set & clear */
+extern int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+ u8 override_set, u8 override_clear);
+
+#endif
diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c
index 1c7c912..f3bc82e 100644
--- a/drivers/media/dvb/frontends/l64781.c
+++ b/drivers/media/dvb/frontends/l64781.c
@@ -32,7 +32,6 @@
struct l64781_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct l64781_config* config;
struct dvb_frontend frontend;
@@ -141,7 +140,10 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa
u8 val0x06;
int bw = p->bandwidth - BANDWIDTH_8_MHZ;
- state->config->pll_set(fe, param);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
if (param->inversion != INVERSION_ON &&
param->inversion != INVERSION_OFF)
@@ -463,8 +465,6 @@ static int l64781_init(struct dvb_frontend* fe)
/* Everything is two's complement, soft bit and CSI_OUT too */
l64781_writereg (state, 0x1e, 0x09);
- if (state->config->pll_init) state->config->pll_init(fe);
-
/* delay a bit after first init attempt */
if (state->first) {
state->first = 0;
@@ -508,7 +508,6 @@ struct dvb_frontend* l64781_attach(const struct l64781_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &l64781_ops, sizeof(struct dvb_frontend_ops));
state->first = 1;
/**
@@ -554,7 +553,7 @@ struct dvb_frontend* l64781_attach(const struct l64781_config* config,
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &l64781_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/l64781.h b/drivers/media/dvb/frontends/l64781.h
index 947f65f..83b8bc2 100644
--- a/drivers/media/dvb/frontends/l64781.h
+++ b/drivers/media/dvb/frontends/l64781.h
@@ -29,10 +29,6 @@ struct l64781_config
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
diff --git a/drivers/media/dvb/frontends/lg_h06xf.h b/drivers/media/dvb/frontends/lg_h06xf.h
new file mode 100644
index 0000000..754d51d
--- /dev/null
+++ b/drivers/media/dvb/frontends/lg_h06xf.h
@@ -0,0 +1,64 @@
+/*
+ * lg_h06xf.h - ATSC Tuner support for LG TDVS-H06xF
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _LG_H06XF_H_
+#define _LG_H06XF_H_
+#include "dvb-pll.h"
+
+static int lg_h06xf_pll_set(struct dvb_frontend* fe, struct i2c_adapter* i2c_adap,
+ struct dvb_frontend_parameters* params)
+{
+ u8 buf[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0,
+ .buf = buf, .len = sizeof(buf) };
+ int err;
+
+ dvb_pll_configure(&dvb_pll_lg_tdvs_h06xf, buf, params->frequency, 0);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((err = i2c_transfer(i2c_adap, &msg, 1)) != 1) {
+ printk(KERN_WARNING "lg_h06xf: %s error "
+ "(addr %02x <- %02x, err = %i)\n",
+ __FUNCTION__, buf[0], buf[1], err);
+ if (err < 0)
+ return err;
+ else
+ return -EREMOTEIO;
+ }
+
+ /* Set the Auxiliary Byte. */
+ buf[0] = buf[2];
+ buf[0] &= ~0x20;
+ buf[0] |= 0x18;
+ buf[1] = 0x50;
+ msg.len = 2;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((err = i2c_transfer(i2c_adap, &msg, 1)) != 1) {
+ printk(KERN_WARNING "lg_h06xf: %s error "
+ "(addr %02x <- %02x, err = %i)\n",
+ __FUNCTION__, buf[0], buf[1], err);
+ if (err < 0)
+ return err;
+ else
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+#endif
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index 4691ac5..6e8ad17 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -29,6 +29,7 @@
* DViCO FusionHDTV 5 Lite
* DViCO FusionHDTV 5 USB Gold
* Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
+ * pcHDTV HD5500
*
* TODO:
* signal strength always returns 0.
@@ -59,7 +60,6 @@ if (debug) printk(KERN_DEBUG "lgdt330x: " args); \
struct lgdt330x_state
{
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* Configuration settings */
const struct lgdt330x_config* config;
@@ -399,8 +399,10 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
}
/* Tune to the specified frequency */
- if (state->config->pll_set)
- state->config->pll_set(fe, param);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
/* Keep track of the new frequency */
/* FIXME this is the wrong way to do this... */
@@ -672,6 +674,7 @@ static int lgdt3303_read_snr(struct dvb_frontend* fe, u16* snr)
if (state->current_modulation == VSB_8) {
+ i2c_read_demod_bytes(state, 0x6e, buf, 5);
/* Phase Tracker Mean-Square Error Register for VSB */
noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4];
} else {
@@ -721,16 +724,19 @@ struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
/* Setup the state */
state->config = config;
state->i2c = i2c;
+
+ /* Create dvb_frontend */
switch (config->demod_chip) {
case LGDT3302:
- memcpy(&state->ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops));
+ memcpy(&state->frontend.ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops));
break;
case LGDT3303:
- memcpy(&state->ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops));
+ memcpy(&state->frontend.ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops));
break;
default:
goto error;
}
+ state->frontend.demodulator_priv = state;
/* Verify communication with demod chip */
if (i2c_read_demod_bytes(state, 2, buf, 1))
@@ -739,9 +745,6 @@ struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
state->current_frequency = -1;
state->current_modulation = -1;
- /* Create dvb_frontend */
- state->frontend.ops = &state->ops;
- state->frontend.demodulator_priv = state;
return &state->frontend;
error:
diff --git a/drivers/media/dvb/frontends/lgdt330x.h b/drivers/media/dvb/frontends/lgdt330x.h
index 2a6529c..bad903c 100644
--- a/drivers/media/dvb/frontends/lgdt330x.h
+++ b/drivers/media/dvb/frontends/lgdt330x.h
@@ -43,7 +43,6 @@ struct lgdt330x_config
/* PLL interface */
int (*pll_rf_set) (struct dvb_frontend* fe, int index);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
/* Need to set device param for start_dma */
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c
new file mode 100644
index 0000000..e933edc
--- /dev/null
+++ b/drivers/media/dvb/frontends/lnbp21.c
@@ -0,0 +1,145 @@
+/*
+ * lnbp21.h - driver for lnb supply and control ic lnbp21
+ *
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * 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.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "lnbp21.h"
+
+struct lnbp21 {
+ u8 config;
+ u8 override_or;
+ u8 override_and;
+ struct i2c_adapter *i2c;
+ void (*release_chain)(struct dvb_frontend* fe);
+};
+
+static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+ struct i2c_msg msg = { .addr = 0x08, .flags = 0,
+ .buf = &lnbp21->config,
+ .len = sizeof(lnbp21->config) };
+
+ lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN);
+
+ switch(voltage) {
+ case SEC_VOLTAGE_OFF:
+ break;
+ case SEC_VOLTAGE_13:
+ lnbp21->config |= LNBP21_EN;
+ break;
+ case SEC_VOLTAGE_18:
+ lnbp21->config |= (LNBP21_EN | LNBP21_VSEL);
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ lnbp21->config |= lnbp21->override_or;
+ lnbp21->config &= lnbp21->override_and;
+
+ return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+ struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+ struct i2c_msg msg = { .addr = 0x08, .flags = 0,
+ .buf = &lnbp21->config,
+ .len = sizeof(lnbp21->config) };
+
+ if (arg)
+ lnbp21->config |= LNBP21_LLC;
+ else
+ lnbp21->config &= ~LNBP21_LLC;
+
+ lnbp21->config |= lnbp21->override_or;
+ lnbp21->config &= lnbp21->override_and;
+
+ return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void lnbp21_release(struct dvb_frontend *fe)
+{
+ struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+
+ /* LNBP power off */
+ lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+ /* free data & call next release routine */
+ fe->ops.release = lnbp21->release_chain;
+ kfree(fe->misc_priv);
+ fe->misc_priv = NULL;
+ if (fe->ops.release)
+ fe->ops.release(fe);
+}
+
+int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
+{
+ struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
+ if (!lnbp21)
+ return -ENOMEM;
+
+ /* default configuration */
+ lnbp21->config = LNBP21_ISEL;
+ lnbp21->i2c = i2c;
+ fe->misc_priv = lnbp21;
+
+ /* bits which should be forced to '1' */
+ lnbp21->override_or = override_set;
+
+ /* bits which should be forced to '0' */
+ lnbp21->override_and = ~override_clear;
+
+ /* detect if it is present or not */
+ if (lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+ kfree(lnbp21);
+ fe->misc_priv = NULL;
+ return -EIO;
+ }
+
+ /* install release callback */
+ lnbp21->release_chain = fe->ops.release;
+ fe->ops.release = lnbp21_release;
+
+ /* override frontend ops */
+ fe->ops.set_voltage = lnbp21_set_voltage;
+ fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+
+ return 0;
+}
+EXPORT_SYMBOL(lnbp21_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21");
+MODULE_AUTHOR("Oliver Endriss");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/lnbp21.h b/drivers/media/dvb/frontends/lnbp21.h
index 0dcbe61..047a4ab6 100644
--- a/drivers/media/dvb/frontends/lnbp21.h
+++ b/drivers/media/dvb/frontends/lnbp21.h
@@ -27,7 +27,7 @@
#ifndef _LNBP21_H
#define _LNBP21_H
-/* system register */
+/* system register bits */
#define LNBP21_OLF 0x01
#define LNBP21_OTF 0x02
#define LNBP21_EN 0x04
@@ -37,103 +37,9 @@
#define LNBP21_ISEL 0x40
#define LNBP21_PCL 0x80
-struct lnbp21 {
- u8 config;
- u8 override_or;
- u8 override_and;
- struct i2c_adapter *i2c;
- void (*release_chain)(struct dvb_frontend* fe);
-};
+#include <linux/dvb/frontend.h>
-static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
- struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
- struct i2c_msg msg = { .addr = 0x08, .flags = 0,
- .buf = &lnbp21->config,
- .len = sizeof(lnbp21->config) };
-
- lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN);
-
- switch(voltage) {
- case SEC_VOLTAGE_OFF:
- break;
- case SEC_VOLTAGE_13:
- lnbp21->config |= LNBP21_EN;
- break;
- case SEC_VOLTAGE_18:
- lnbp21->config |= (LNBP21_EN | LNBP21_VSEL);
- break;
- default:
- return -EINVAL;
- };
-
- lnbp21->config |= lnbp21->override_or;
- lnbp21->config &= lnbp21->override_and;
-
- return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
-{
- struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
- struct i2c_msg msg = { .addr = 0x08, .flags = 0,
- .buf = &lnbp21->config,
- .len = sizeof(lnbp21->config) };
-
- if (arg)
- lnbp21->config |= LNBP21_LLC;
- else
- lnbp21->config &= ~LNBP21_LLC;
-
- lnbp21->config |= lnbp21->override_or;
- lnbp21->config &= lnbp21->override_and;
-
- return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static void lnbp21_exit(struct dvb_frontend *fe)
-{
- struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
-
- /* LNBP power off */
- lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
-
- /* free data & call next release routine */
- fe->ops->release = lnbp21->release_chain;
- kfree(fe->misc_priv);
- fe->misc_priv = NULL;
- if (fe->ops->release)
- fe->ops->release(fe);
-}
-
-static int lnbp21_init(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
-{
- struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
-
- if (!lnbp21)
- return -ENOMEM;
-
- /* default configuration */
- lnbp21->config = LNBP21_ISEL;
-
- /* bits which should be forced to '1' */
- lnbp21->override_or = override_set;
-
- /* bits which should be forced to '0' */
- lnbp21->override_and = ~override_clear;
-
- /* install release callback */
- lnbp21->release_chain = fe->ops->release;
- fe->ops->release = lnbp21_exit;
-
- /* override frontend ops */
- fe->ops->set_voltage = lnbp21_set_voltage;
- fe->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
-
- lnbp21->i2c = i2c;
- fe->misc_priv = lnbp21;
-
- return lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
-}
+/* override_set and override_clear control which system register bits (above) to always set & clear */
+extern int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear);
#endif
diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c
index d3aea83..1ef8218 100644
--- a/drivers/media/dvb/frontends/mt312.c
+++ b/drivers/media/dvb/frontends/mt312.c
@@ -39,7 +39,6 @@
struct mt312_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct mt312_config* config;
struct dvb_frontend frontend;
@@ -277,12 +276,6 @@ static int mt312_initfe(struct dvb_frontend* fe)
if ((ret = mt312_writereg(state, CS_SW_LIM, 0x69)) < 0)
return ret;
- if (state->config->pll_init) {
- mt312_writereg(state, GPP_CTRL, 0x40);
- state->config->pll_init(fe);
- mt312_writereg(state, GPP_CTRL, 0x00);
- }
-
return 0;
}
@@ -477,16 +470,16 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
dprintk("%s: Freq %d\n", __FUNCTION__, p->frequency);
- if ((p->frequency < fe->ops->info.frequency_min)
- || (p->frequency > fe->ops->info.frequency_max))
+ if ((p->frequency < fe->ops.info.frequency_min)
+ || (p->frequency > fe->ops.info.frequency_max))
return -EINVAL;
if ((p->inversion < INVERSION_OFF)
|| (p->inversion > INVERSION_ON))
return -EINVAL;
- if ((p->u.qpsk.symbol_rate < fe->ops->info.symbol_rate_min)
- || (p->u.qpsk.symbol_rate > fe->ops->info.symbol_rate_max))
+ if ((p->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min)
+ || (p->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max))
return -EINVAL;
if ((p->u.qpsk.fec_inner < FEC_NONE)
@@ -529,9 +522,10 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
return -EINVAL;
}
- mt312_writereg(state, GPP_CTRL, 0x40);
- state->config->pll_set(fe, p);
- mt312_writereg(state, GPP_CTRL, 0x00);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
/* sr = (u16)(sr * 256.0 / 1000000.0) */
sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625);
@@ -578,6 +572,17 @@ static int mt312_get_frontend(struct dvb_frontend* fe,
return 0;
}
+static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct mt312_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return mt312_writereg(state, GPP_CTRL, 0x40);
+ } else {
+ return mt312_writereg(state, GPP_CTRL, 0x00);
+ }
+}
+
static int mt312_sleep(struct dvb_frontend* fe)
{
struct mt312_state *state = fe->demodulator_priv;
@@ -633,6 +638,7 @@ static struct dvb_frontend_ops vp310_mt312_ops = {
.init = mt312_initfe,
.sleep = mt312_sleep,
+ .i2c_gate_ctrl = mt312_i2c_gate_ctrl,
.set_frontend = mt312_set_frontend,
.get_frontend = mt312_get_frontend,
@@ -663,19 +669,22 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if (mt312_readreg(state, ID, &state->id) < 0)
goto error;
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+
switch (state->id) {
case ID_VP310:
- strcpy(state->ops.info.name, "Zarlink VP310 DVB-S");
+ strcpy(state->frontend.ops.info.name, "Zarlink VP310 DVB-S");
state->frequency = 90;
break;
case ID_MT312:
- strcpy(state->ops.info.name, "Zarlink MT312 DVB-S");
+ strcpy(state->frontend.ops.info.name, "Zarlink MT312 DVB-S");
state->frequency = 60;
break;
default:
@@ -683,9 +692,6 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
goto error;
}
- /* create dvb_frontend */
- state->frontend.ops = &state->ops;
- state->frontend.demodulator_priv = state;
return &state->frontend;
error:
diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h
index 074d844..666a1bd 100644
--- a/drivers/media/dvb/frontends/mt312.h
+++ b/drivers/media/dvb/frontends/mt312.h
@@ -32,10 +32,6 @@ struct mt312_config
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c
index aaaec90..5de7376 100644
--- a/drivers/media/dvb/frontends/mt352.c
+++ b/drivers/media/dvb/frontends/mt352.c
@@ -45,7 +45,6 @@
struct mt352_state {
struct i2c_adapter* i2c;
struct dvb_frontend frontend;
- struct dvb_frontend_ops ops;
/* configuration settings */
struct mt352_config config;
@@ -286,16 +285,25 @@ static int mt352_set_parameters(struct dvb_frontend* fe,
mt352_calc_nominal_rate(state, op->bandwidth, buf+4);
mt352_calc_input_freq(state, buf+6);
- state->config.pll_set(fe, param, buf+8);
- mt352_write(fe, buf, sizeof(buf));
if (state->config.no_tuner) {
- /* start decoding */
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
+ mt352_write(fe, buf, 8);
mt352_write(fe, fsm_go, 2);
} else {
- /* start tuning */
- mt352_write(fe, tuner_go, 2);
+ if (fe->ops.tuner_ops.calc_regs) {
+ fe->ops.tuner_ops.calc_regs(fe, param, buf+8, 5);
+ buf[8] <<= 1;
+ mt352_write(fe, buf, sizeof(buf));
+ mt352_write(fe, tuner_go, 2);
+ }
}
+
return 0;
}
@@ -541,13 +549,12 @@ struct dvb_frontend* mt352_attach(const struct mt352_config* config,
/* setup the state */
state->i2c = i2c;
memcpy(&state->config,config,sizeof(struct mt352_config));
- memcpy(&state->ops, &mt352_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if (mt352_read_register(state, CHIP_ID) != ID_MT352) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &mt352_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/mt352.h b/drivers/media/dvb/frontends/mt352.h
index 03040cd..9e7ff4b 100644
--- a/drivers/media/dvb/frontends/mt352.h
+++ b/drivers/media/dvb/frontends/mt352.h
@@ -49,12 +49,6 @@ struct mt352_config
/* Initialise the demodulator and PLL. Cannot be NULL */
int (*demod_init)(struct dvb_frontend* fe);
-
- /* PLL setup - fill out the supplied 5 byte buffer with your PLL settings.
- * byte0: Set to pll i2c address (nonlinux; left shifted by 1)
- * byte1-4: PLL configuration.
- */
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf);
};
extern struct dvb_frontend* mt352_attach(const struct mt352_config* config,
diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c
index 9e353539..55671cb 100644
--- a/drivers/media/dvb/frontends/nxt200x.c
+++ b/drivers/media/dvb/frontends/nxt200x.c
@@ -55,7 +55,6 @@
struct nxt200x_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct nxt200x_config* config;
struct dvb_frontend frontend;
@@ -333,17 +332,17 @@ static int nxt200x_writetuner (struct nxt200x_state* state, u8* data)
dprintk("%s\n", __FUNCTION__);
- dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[0], data[1], data[2], data[3]);
+ dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[1], data[2], data[3], data[4]);
/* if NXT2004, write directly to tuner. if NXT2002, write through NXT chip.
* direct write is required for Philips TUV1236D and ALPS TDHU2 */
switch (state->demod_chip) {
case NXT2004:
- if (i2c_writebytes(state, state->config->pll_address, data, 4))
+ if (i2c_writebytes(state, data[0], data+1, 4))
printk(KERN_WARNING "nxt200x: error writing to tuner\n");
/* wait until we have a lock */
while (count < 20) {
- i2c_readbytes(state, state->config->pll_address, &buf, 1);
+ i2c_readbytes(state, data[0], &buf, 1);
if (buf & 0x40)
return 0;
msleep(100);
@@ -361,10 +360,10 @@ static int nxt200x_writetuner (struct nxt200x_state* state, u8* data)
nxt200x_writebytes(state, 0x34, &buf, 1);
/* write actual tuner bytes */
- nxt200x_writebytes(state, 0x36, data, 4);
+ nxt200x_writebytes(state, 0x36, data+1, 4);
/* set tuner i2c address */
- buf = state->config->pll_address;
+ buf = data[0] << 1;
nxt200x_writebytes(state, 0x35, &buf, 1);
/* write UC Opmode to begin transfer */
@@ -534,7 +533,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
struct dvb_frontend_parameters *p)
{
struct nxt200x_state* state = fe->demodulator_priv;
- u8 buf[4];
+ u8 buf[5];
/* stop the micro first */
nxt200x_microcontroller_stop(state);
@@ -548,7 +547,9 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
}
/* get tuning information */
- dvb_pll_configure(state->config->pll_desc, buf, p->frequency, 0);
+ if (fe->ops.tuner_ops.calc_regs) {
+ fe->ops.tuner_ops.calc_regs(fe, p, buf, 5);
+ }
/* set additional params */
switch (p->u.vsb.modulation) {
@@ -1159,7 +1160,6 @@ struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops));
state->initialised = 0;
/* read card id */
@@ -1198,7 +1198,7 @@ struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/nxt200x.h b/drivers/media/dvb/frontends/nxt200x.h
index 1d9d70b..34d6173 100644
--- a/drivers/media/dvb/frontends/nxt200x.h
+++ b/drivers/media/dvb/frontends/nxt200x.h
@@ -38,10 +38,6 @@ struct nxt200x_config
/* the demodulator's i2c address */
u8 demod_address;
- /* tuner information */
- u8 pll_address;
- struct dvb_pll_desc *pll_desc;
-
/* used to set pll input */
int (*set_pll_input)(u8* buf, int input);
diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c
index a16eeba..d313d7d 100644
--- a/drivers/media/dvb/frontends/nxt6000.c
+++ b/drivers/media/dvb/frontends/nxt6000.c
@@ -33,7 +33,6 @@
struct nxt6000_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct nxt6000_config* config;
struct dvb_frontend frontend;
@@ -207,12 +206,6 @@ static void nxt6000_setup(struct dvb_frontend* fe)
nxt6000_writereg(state, SUB_DIAG_MODE_SEL, 0);
nxt6000_writereg(state, TS_FORMAT, 0);
-
- if (state->config->pll_init) {
- nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */
- state->config->pll_init(fe);
- nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */
- }
}
static void nxt6000_dump_status(struct nxt6000_state *state)
@@ -469,9 +462,10 @@ static int nxt6000_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
struct nxt6000_state* state = fe->demodulator_priv;
int result;
- nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */
- state->config->pll_set(fe, param);
- nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
if ((result = nxt6000_set_bandwidth(state, param->u.ofdm.bandwidth)) < 0)
return result;
@@ -532,6 +526,17 @@ static int nxt6000_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_fron
return 0;
}
+static int nxt6000_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct nxt6000_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01);
+ } else {
+ return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00);
+ }
+}
+
static struct dvb_frontend_ops nxt6000_ops;
struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
@@ -546,13 +551,12 @@ struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if (nxt6000_readreg(state, OFDM_MSC_REV) != NXT6000ASICDEVICE) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -584,6 +588,7 @@ static struct dvb_frontend_ops nxt6000_ops = {
.release = nxt6000_release,
.init = nxt6000_init,
+ .i2c_gate_ctrl = nxt6000_i2c_gate_ctrl,
.get_tune_settings = nxt6000_fe_get_tune_settings,
diff --git a/drivers/media/dvb/frontends/nxt6000.h b/drivers/media/dvb/frontends/nxt6000.h
index b7d9bea..117031d 100644
--- a/drivers/media/dvb/frontends/nxt6000.h
+++ b/drivers/media/dvb/frontends/nxt6000.h
@@ -31,10 +31,6 @@ struct nxt6000_config
/* should clock inversion be used? */
u8 clock_inversion:1;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
index 80e0f28..d20ab30 100644
--- a/drivers/media/dvb/frontends/or51132.c
+++ b/drivers/media/dvb/frontends/or51132.c
@@ -54,7 +54,6 @@ static int debug;
struct or51132_state
{
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* Configuration settings */
const struct or51132_config* config;
@@ -106,9 +105,8 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
{
struct or51132_state* state = fe->demodulator_priv;
static u8 run_buf[] = {0x7F,0x01};
- static u8 get_ver_buf[] = {0x04,0x00,0x30,0x00,0x00};
- u8 rec_buf[14];
- u8 cmd_buf[14];
+ u8 rec_buf[8];
+ u8 cmd_buf[3];
u32 firmwareAsize, firmwareBsize;
int i,ret;
@@ -157,7 +155,6 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
cmd_buf[0] = 0x10;
cmd_buf[1] = 0x10;
cmd_buf[2] = 0x00;
- cmd_buf[3] = 0x00;
msleep(20); /* 20ms */
if ((ret = i2c_writebytes(state,state->config->demod_address,
cmd_buf,3))) {
@@ -167,8 +164,6 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
cmd_buf[0] = 0x04;
cmd_buf[1] = 0x17;
- cmd_buf[2] = 0x00;
- cmd_buf[3] = 0x00;
msleep(20); /* 20ms */
if ((ret = i2c_writebytes(state,state->config->demod_address,
cmd_buf,2))) {
@@ -178,8 +173,6 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
cmd_buf[0] = 0x00;
cmd_buf[1] = 0x00;
- cmd_buf[2] = 0x00;
- cmd_buf[3] = 0x00;
msleep(20); /* 20ms */
if ((ret = i2c_writebytes(state,state->config->demod_address,
cmd_buf,2))) {
@@ -189,7 +182,11 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
for(i=0;i<4;i++) {
msleep(20); /* 20ms */
- get_ver_buf[4] = i+1;
+ /* Once upon a time, this command might have had something
+ to do with getting the firmware version, but it's
+ not used anymore:
+ {0x04,0x00,0x30,0x00,i+1} */
+ /* Read 8 bytes, two bytes at a time */
if ((ret = i2c_readbytes(state,state->config->demod_address,
&rec_buf[i*2],2))) {
printk(KERN_WARNING
@@ -208,7 +205,6 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
cmd_buf[0] = 0x10;
cmd_buf[1] = 0x00;
cmd_buf[2] = 0x00;
- cmd_buf[3] = 0x00;
msleep(20); /* 20ms */
if ((ret = i2c_writebytes(state,state->config->demod_address,
cmd_buf,3))) {
@@ -243,7 +239,7 @@ static int or51132_sleep(struct dvb_frontend* fe)
static int or51132_setmode(struct dvb_frontend* fe)
{
struct or51132_state* state = fe->demodulator_priv;
- unsigned char cmd_buf[4];
+ unsigned char cmd_buf[3];
dprintk("setmode %d\n",(int)state->current_modulation);
/* set operation mode in Receiver 1 register; */
@@ -263,7 +259,6 @@ static int or51132_setmode(struct dvb_frontend* fe)
default:
printk("setmode:Modulation set to unsupported value\n");
};
- cmd_buf[3] = 0x00;
if (i2c_writebytes(state,state->config->demod_address,
cmd_buf,3)) {
printk(KERN_WARNING "or51132: set_mode error 1\n");
@@ -301,7 +296,6 @@ static int or51132_setmode(struct dvb_frontend* fe)
default:
printk("setmode: Modulation set to unsupported value\n");
};
- cmd_buf[3] = 0x00;
msleep(20); /* 20ms */
if (i2c_writebytes(state,state->config->demod_address,
cmd_buf,3)) {
@@ -313,52 +307,65 @@ static int or51132_setmode(struct dvb_frontend* fe)
return 0;
}
+/* Some modulations use the same firmware. This classifies modulations
+ by the firmware they use. */
+#define MOD_FWCLASS_UNKNOWN 0
+#define MOD_FWCLASS_VSB 1
+#define MOD_FWCLASS_QAM 2
+static int modulation_fw_class(fe_modulation_t modulation)
+{
+ switch(modulation) {
+ case VSB_8:
+ return MOD_FWCLASS_VSB;
+ case QAM_AUTO:
+ case QAM_64:
+ case QAM_256:
+ return MOD_FWCLASS_QAM;
+ default:
+ return MOD_FWCLASS_UNKNOWN;
+ }
+}
+
static int or51132_set_parameters(struct dvb_frontend* fe,
struct dvb_frontend_parameters *param)
{
int ret;
- u8 buf[4];
struct or51132_state* state = fe->demodulator_priv;
const struct firmware *fw;
-
- /* Change only if we are actually changing the modulation */
- if (state->current_modulation != param->u.vsb.modulation) {
- switch(param->u.vsb.modulation) {
- case VSB_8:
+ const char *fwname;
+ int clock_mode;
+
+ /* Upload new firmware only if we need a different one */
+ if (modulation_fw_class(state->current_modulation) !=
+ modulation_fw_class(param->u.vsb.modulation)) {
+ switch(modulation_fw_class(param->u.vsb.modulation)) {
+ case MOD_FWCLASS_VSB:
dprintk("set_parameters VSB MODE\n");
- printk("or51132: Waiting for firmware upload(%s)...\n",
- OR51132_VSB_FIRMWARE);
- ret = request_firmware(&fw, OR51132_VSB_FIRMWARE,
- &state->i2c->dev);
- if (ret){
- printk(KERN_WARNING "or51132: No firmware up"
- "loaded(timeout or file not found?)\n");
- return ret;
- }
+ fwname = OR51132_VSB_FIRMWARE;
+
/* Set non-punctured clock for VSB */
- state->config->set_ts_params(fe, 0);
+ clock_mode = 0;
break;
- case QAM_AUTO:
- case QAM_64:
- case QAM_256:
+ case MOD_FWCLASS_QAM:
dprintk("set_parameters QAM MODE\n");
- printk("or51132: Waiting for firmware upload(%s)...\n",
- OR51132_QAM_FIRMWARE);
- ret = request_firmware(&fw, OR51132_QAM_FIRMWARE,
- &state->i2c->dev);
- if (ret){
- printk(KERN_WARNING "or51132: No firmware up"
- "loaded(timeout or file not found?)\n");
- return ret;
- }
+ fwname = OR51132_QAM_FIRMWARE;
+
/* Set punctured clock for QAM */
- state->config->set_ts_params(fe, 1);
+ clock_mode = 1;
break;
default:
- printk("or51132:Modulation type(%d) UNSUPPORTED\n",
+ printk("or51132: Modulation type(%d) UNSUPPORTED\n",
param->u.vsb.modulation);
return -1;
- };
+ }
+ printk("or51132: Waiting for firmware upload(%s)...\n",
+ fwname);
+ ret = request_firmware(&fw, fwname, &state->i2c->dev);
+ if (ret) {
+ printk(KERN_WARNING "or51132: No firmware up"
+ "loaded(timeout or file not found?)\n");
+ return ret;
+ }
ret = or51132_load_firmware(fe, fw);
release_firmware(fw);
if (ret) {
@@ -367,18 +374,18 @@ static int or51132_set_parameters(struct dvb_frontend* fe,
return ret;
}
printk("or51132: Firmware upload complete.\n");
-
+ state->config->set_ts_params(fe, clock_mode);
+ }
+ /* Change only if we are actually changing the modulation */
+ if (state->current_modulation != param->u.vsb.modulation) {
state->current_modulation = param->u.vsb.modulation;
or51132_setmode(fe);
}
- dvb_pll_configure(state->config->pll_desc, buf,
- param->frequency, 0);
- dprintk("set_parameters tuner bytes: 0x%02x 0x%02x "
- "0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]);
- if (i2c_writebytes(state, state->config->pll_address ,buf, 4))
- printk(KERN_WARNING "or51132: set_parameters error "
- "writing to tuner\n");
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
/* Set to current mode */
or51132_setmode(fe);
@@ -388,6 +395,44 @@ static int or51132_set_parameters(struct dvb_frontend* fe,
return 0;
}
+static int or51132_get_parameters(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *param)
+{
+ struct or51132_state* state = fe->demodulator_priv;
+ u8 buf[2];
+
+ /* Receiver Status */
+ buf[0]=0x04;
+ buf[1]=0x00;
+ msleep(30); /* 30ms */
+ if (i2c_writebytes(state,state->config->demod_address,buf,2)) {
+ printk(KERN_WARNING "or51132: get_parameters write error\n");
+ return -EREMOTEIO;
+ }
+ msleep(30); /* 30ms */
+ if (i2c_readbytes(state,state->config->demod_address,buf,2)) {
+ printk(KERN_WARNING "or51132: get_parameters read error\n");
+ return -EREMOTEIO;
+ }
+ switch(buf[0]) {
+ case 0x06: param->u.vsb.modulation = VSB_8; break;
+ case 0x43: param->u.vsb.modulation = QAM_64; break;
+ case 0x45: param->u.vsb.modulation = QAM_256; break;
+ default:
+ printk(KERN_WARNING "or51132: unknown status 0x%02x\n",
+ buf[0]);
+ return -EREMOTEIO;
+ }
+
+ /* FIXME: Read frequency from frontend, take AFC into account */
+ param->frequency = state->current_frequency;
+
+ /* FIXME: How to read inversion setting? Receiver 6 register? */
+ param->inversion = INVERSION_AUTO;
+
+ return 0;
+}
+
static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status)
{
struct or51132_state* state = fe->demodulator_priv;
@@ -572,12 +617,11 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config,
/* Setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &or51132_ops, sizeof(struct dvb_frontend_ops));
state->current_frequency = -1;
state->current_modulation = -1;
/* Create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -590,7 +634,7 @@ static struct dvb_frontend_ops or51132_ops = {
.info = {
.name = "Oren OR51132 VSB/QAM Frontend",
- .type = FE_ATSC,
+ .type = FE_ATSC,
.frequency_min = 44000000,
.frequency_max = 958000000,
.frequency_stepsize = 166666,
@@ -606,6 +650,7 @@ static struct dvb_frontend_ops or51132_ops = {
.sleep = or51132_sleep,
.set_frontend = or51132_set_parameters,
+ .get_frontend = or51132_get_parameters,
.get_tune_settings = or51132_get_tune_settings,
.read_status = or51132_read_status,
diff --git a/drivers/media/dvb/frontends/or51132.h b/drivers/media/dvb/frontends/or51132.h
index 622cdd1..8965888 100644
--- a/drivers/media/dvb/frontends/or51132.h
+++ b/drivers/media/dvb/frontends/or51132.h
@@ -29,8 +29,6 @@ struct or51132_config
{
/* The demodulator's i2c address */
u8 demod_address;
- u8 pll_address;
- struct dvb_pll_desc *pll_desc;
/* Need to set device param for start_dma */
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
index 7c3aed1..26bed61 100644
--- a/drivers/media/dvb/frontends/or51211.c
+++ b/drivers/media/dvb/frontends/or51211.c
@@ -54,7 +54,6 @@ static u8 cmd_buf[] = {0x04,0x01,0x50,0x80,0x06}; // ATSC
struct or51211_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* Configuration settings */
const struct or51211_config* config;
@@ -585,12 +584,11 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config,
/* Setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
state->initialized = 0;
state->current_frequency = 0;
/* Create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
index d694775..2c2c344 100644
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -38,7 +38,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
struct s5h1420_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct s5h1420_config* config;
struct dvb_frontend frontend;
@@ -584,7 +583,6 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
struct s5h1420_state* state = fe->demodulator_priv;
int frequency_delta;
struct dvb_frontend_tune_settings fesettings;
- u32 tmp;
/* check if we should do a fast-tune */
memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters));
@@ -596,10 +594,17 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
(state->fec_inner == p->u.qpsk.fec_inner) &&
(state->symbol_rate == p->u.qpsk.symbol_rate)) {
- if (state->config->pll_set) {
- s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
- state->config->pll_set(fe, p, &tmp);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ if (fe->ops.tuner_ops.get_frequency) {
+ u32 tmp;
+ fe->ops.tuner_ops.get_frequency(fe, &tmp);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
s5h1420_setfreqoffset(state, p->frequency - tmp);
+ } else {
+ s5h1420_setfreqoffset(state, 0);
}
return 0;
}
@@ -646,9 +651,9 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1);
/* set tuner PLL */
- if (state->config->pll_set) {
- s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
- state->config->pll_set(fe, p, &tmp);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
s5h1420_setfreqoffset(state, 0);
}
@@ -708,6 +713,17 @@ static int s5h1420_get_tune_settings(struct dvb_frontend* fe,
return 0;
}
+static int s5h1420_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
+ } else {
+ return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
+ }
+}
+
static int s5h1420_init (struct dvb_frontend* fe)
{
struct s5h1420_state* state = fe->demodulator_priv;
@@ -717,13 +733,6 @@ static int s5h1420_init (struct dvb_frontend* fe)
msleep(10);
s5h1420_reset(state);
- /* init PLL */
- if (state->config->pll_init) {
- s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
- state->config->pll_init(fe);
- s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
- }
-
return 0;
}
@@ -756,7 +765,6 @@ struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));
state->postlocked = 0;
state->fclk = 88000000;
state->tunedfreq = 0;
@@ -769,7 +777,7 @@ struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -800,6 +808,7 @@ static struct dvb_frontend_ops s5h1420_ops = {
.init = s5h1420_init,
.sleep = s5h1420_sleep,
+ .i2c_gate_ctrl = s5h1420_i2c_gate_ctrl,
.set_frontend = s5h1420_set_frontend,
.get_frontend = s5h1420_get_frontend,
diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h
index 73296f1..4e39015 100644
--- a/drivers/media/dvb/frontends/s5h1420.h
+++ b/drivers/media/dvb/frontends/s5h1420.h
@@ -32,10 +32,6 @@ struct s5h1420_config
/* does the inversion require inversion? */
u8 invert:1;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout);
};
extern struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c
index 73829e6..44ec5b9 100644
--- a/drivers/media/dvb/frontends/sp8870.c
+++ b/drivers/media/dvb/frontends/sp8870.c
@@ -44,8 +44,6 @@ struct sp8870_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
-
const struct sp8870_config* config;
struct dvb_frontend frontend;
@@ -262,9 +260,10 @@ static int sp8870_set_frontend_parameters (struct dvb_frontend* fe,
sp8870_microcontroller_stop(state);
// set tuner parameters
- sp8870_writereg(state, 0x206, 0x001);
- state->config->pll_set(fe, p);
- sp8870_writereg(state, 0x206, 0x000);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
// sample rate correction bit [23..17]
sp8870_writereg(state, 0x0319, 0x000A);
@@ -349,13 +348,6 @@ static int sp8870_init (struct dvb_frontend* fe)
sp8870_writereg(state, 0x0D00, 0x010);
sp8870_writereg(state, 0x0D01, 0x000);
- /* setup PLL */
- if (state->config->pll_init) {
- sp8870_writereg(state, 0x206, 0x001);
- state->config->pll_init(fe);
- sp8870_writereg(state, 0x206, 0x000);
- }
-
return 0;
}
@@ -541,6 +533,17 @@ static int sp8870_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend
return 0;
}
+static int sp8870_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct sp8870_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return sp8870_writereg(state, 0x206, 0x001);
+ } else {
+ return sp8870_writereg(state, 0x206, 0x000);
+ }
+}
+
static void sp8870_release(struct dvb_frontend* fe)
{
struct sp8870_state* state = fe->demodulator_priv;
@@ -561,14 +564,13 @@ struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &sp8870_ops, sizeof(struct dvb_frontend_ops));
state->initialised = 0;
/* check if the demod is there */
if (sp8870_readreg(state, 0x0200) < 0) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &sp8870_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -597,6 +599,7 @@ static struct dvb_frontend_ops sp8870_ops = {
.init = sp8870_init,
.sleep = sp8870_sleep,
+ .i2c_gate_ctrl = sp8870_i2c_gate_ctrl,
.set_frontend = sp8870_set_frontend,
.get_tune_settings = sp8870_get_tune_settings,
diff --git a/drivers/media/dvb/frontends/sp8870.h b/drivers/media/dvb/frontends/sp8870.h
index f3b555d..93afbb9 100644
--- a/drivers/media/dvb/frontends/sp8870.h
+++ b/drivers/media/dvb/frontends/sp8870.h
@@ -31,10 +31,6 @@ struct sp8870_config
/* the demodulator's i2c address */
u8 demod_address;
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
/* request firmware for device */
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c
index eb8a602..b0a2b02 100644
--- a/drivers/media/dvb/frontends/sp887x.c
+++ b/drivers/media/dvb/frontends/sp887x.c
@@ -24,7 +24,6 @@
struct sp887x_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct sp887x_config* config;
struct dvb_frontend frontend;
@@ -208,15 +207,6 @@ static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware
/* bit 0x010: enable data valid signal */
sp887x_writereg(state, 0xd00, 0x010);
sp887x_writereg(state, 0x0d1, 0x000);
-
- /* setup the PLL */
- if (state->config->pll_init) {
- sp887x_writereg(state, 0x206, 0x001);
- state->config->pll_init(fe);
- sp887x_writereg(state, 0x206, 0x000);
- }
-
- printk ("done.\n");
return 0;
};
@@ -362,9 +352,16 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe,
sp887x_microcontroller_stop(state);
/* setup the PLL */
- sp887x_writereg(state, 0x206, 0x001);
- actual_freq = state->config->pll_set(fe, p);
- sp887x_writereg(state, 0x206, 0x000);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ if (fe->ops.tuner_ops.get_frequency) {
+ fe->ops.tuner_ops.get_frequency(fe, &actual_freq);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ } else {
+ actual_freq = p->frequency;
+ }
/* read status reg in order to clear <pending irqs */
sp887x_readreg(state, 0x200);
@@ -486,6 +483,17 @@ static int sp887x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
return 0;
}
+static int sp887x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct sp887x_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return sp887x_writereg(state, 0x206, 0x001);
+ } else {
+ return sp887x_writereg(state, 0x206, 0x000);
+ }
+}
+
static int sp887x_sleep(struct dvb_frontend* fe)
{
struct sp887x_state* state = fe->demodulator_priv;
@@ -555,14 +563,13 @@ struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &sp887x_ops, sizeof(struct dvb_frontend_ops));
state->initialised = 0;
/* check if the demod is there */
if (sp887x_readreg(state, 0x0200) < 0) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &sp887x_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -589,6 +596,7 @@ static struct dvb_frontend_ops sp887x_ops = {
.init = sp887x_init,
.sleep = sp887x_sleep,
+ .i2c_gate_ctrl = sp887x_i2c_gate_ctrl,
.set_frontend = sp887x_setup_frontend_parameters,
.get_tune_settings = sp887x_get_tune_settings,
diff --git a/drivers/media/dvb/frontends/sp887x.h b/drivers/media/dvb/frontends/sp887x.h
index 6a05d8f..c44b0eb 100644
--- a/drivers/media/dvb/frontends/sp887x.h
+++ b/drivers/media/dvb/frontends/sp887x.h
@@ -13,12 +13,6 @@ struct sp887x_config
/* the demodulator's i2c address */
u8 demod_address;
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
-
- /* this should return the actual frequency tuned to */
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
/* request firmware for device */
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c
index eb15676..1ca6424 100644
--- a/drivers/media/dvb/frontends/stv0297.c
+++ b/drivers/media/dvb/frontends/stv0297.c
@@ -32,7 +32,6 @@
struct stv0297_state {
struct i2c_adapter *i2c;
- struct dvb_frontend_ops ops;
const struct stv0297_config *config;
struct dvb_frontend frontend;
@@ -68,19 +67,25 @@ static int stv0297_readreg(struct stv0297_state *state, u8 reg)
int ret;
u8 b0[] = { reg };
u8 b1[] = { 0 };
- struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len =
- 1},
- {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
- };
+ struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1},
+ {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
+ };
// this device needs a STOP between the register and data
- if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
- return -1;
- }
- if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
- return -1;
+ if (state->config->stop_during_read) {
+ if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+ return -1;
+ }
+ if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+ return -1;
+ }
+ } else {
+ if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+ return -1;
+ }
}
return b1[0];
@@ -107,13 +112,20 @@ static int stv0297_readregs(struct stv0297_state *state, u8 reg1, u8 * b, u8 len
};
// this device needs a STOP between the register and data
- if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
- return -1;
- }
- if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
- return -1;
+ if (state->config->stop_during_read) {
+ if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+ return -1;
+ }
+ if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+ return -1;
+ }
+ } else {
+ if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+ return -1;
+ }
}
return 0;
@@ -276,12 +288,14 @@ static int stv0297_set_inversion(struct stv0297_state *state, fe_spectral_invers
return 0;
}
-int stv0297_enable_plli2c(struct dvb_frontend *fe)
+static int stv0297_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
struct stv0297_state *state = fe->demodulator_priv;
- stv0297_writereg(state, 0x87, 0x78);
- stv0297_writereg(state, 0x86, 0xc8);
+ if (enable) {
+ stv0297_writereg(state, 0x87, 0x78);
+ stv0297_writereg(state, 0x86, 0xc8);
+ }
return 0;
}
@@ -296,9 +310,6 @@ static int stv0297_init(struct dvb_frontend *fe)
stv0297_writereg(state, state->config->inittab[i], state->config->inittab[i+1]);
msleep(200);
- if (state->config->pll_init)
- state->config->pll_init(fe);
-
return 0;
}
@@ -389,7 +400,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
case QAM_32:
case QAM_64:
delay = 100;
- sweeprate = 1500;
+ sweeprate = 1000;
break;
case QAM_128:
@@ -421,7 +432,10 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
}
stv0297_init(fe);
- state->config->pll_set(fe, p);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
/* clear software interrupts */
stv0297_writereg(state, 0x82, 0x0);
@@ -634,7 +648,6 @@ struct dvb_frontend *stv0297_attach(const struct stv0297_config *config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &stv0297_ops, sizeof(struct dvb_frontend_ops));
state->base_freq = 0;
/* check if the demod is there */
@@ -642,7 +655,7 @@ struct dvb_frontend *stv0297_attach(const struct stv0297_config *config,
goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &stv0297_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -668,6 +681,7 @@ static struct dvb_frontend_ops stv0297_ops = {
.init = stv0297_init,
.sleep = stv0297_sleep,
+ .i2c_gate_ctrl = stv0297_i2c_gate_ctrl,
.set_frontend = stv0297_set_frontend,
.get_frontend = stv0297_get_frontend,
@@ -684,4 +698,3 @@ MODULE_AUTHOR("Dennis Noermann and Andrew de Quincey");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(stv0297_attach);
-EXPORT_SYMBOL(stv0297_enable_plli2c);
diff --git a/drivers/media/dvb/frontends/stv0297.h b/drivers/media/dvb/frontends/stv0297.h
index 9e53f01..1da5384 100644
--- a/drivers/media/dvb/frontends/stv0297.h
+++ b/drivers/media/dvb/frontends/stv0297.h
@@ -38,13 +38,11 @@ struct stv0297_config
/* does the "inversion" need inverted? */
u8 invert:1;
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+ /* set to 1 if the device requires an i2c STOP during reading */
+ u8 stop_during_read:1;
};
extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
struct i2c_adapter* i2c);
-extern int stv0297_enable_plli2c(struct dvb_frontend* fe);
#endif // STV0297_H
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 5bcd00f..96648a7 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -56,7 +56,6 @@
struct stv0299_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct stv0299_config* config;
struct dvb_frontend frontend;
@@ -131,13 +130,6 @@ static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len
return ret == 2 ? 0 : ret;
}
-int stv0299_enable_plli2c (struct dvb_frontend* fe)
-{
- struct stv0299_state* state = fe->demodulator_priv;
-
- return stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
-}
-
static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec)
{
dprintk ("%s\n", __FUNCTION__);
@@ -457,12 +449,6 @@ static int stv0299_init (struct dvb_frontend* fe)
for (i=0; !(state->config->inittab[i] == 0xff && state->config->inittab[i+1] == 0xff); i+=2)
stv0299_writeregI(state, state->config->inittab[i], state->config->inittab[i+1]);
- if (state->config->pll_init) {
- stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
- state->config->pll_init(fe, state->i2c);
- stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */
- }
-
return 0;
}
@@ -560,9 +546,10 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
if (state->config->invert) invval = (~invval) & 1;
stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval);
- stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
- state->config->pll_set(fe, state->i2c, p);
- stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
stv0299_set_FEC (state, p->u.qpsk.fec_inner);
stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate);
@@ -611,6 +598,19 @@ static int stv0299_sleep(struct dvb_frontend* fe)
return 0;
}
+static int stv0299_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct stv0299_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ stv0299_writeregI(state, 0x05, 0xb5);
+ } else {
+ stv0299_writeregI(state, 0x05, 0x35);
+ }
+ udelay(1);
+ return 0;
+}
+
static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
struct stv0299_state* state = fe->demodulator_priv;
@@ -647,7 +647,6 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &stv0299_ops, sizeof(struct dvb_frontend_ops));
state->initialised = 0;
state->tuner_frequency = 0;
state->symbol_rate = 0;
@@ -664,7 +663,7 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
if (id != 0xa1 && id != 0x80) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &stv0299_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -695,6 +694,7 @@ static struct dvb_frontend_ops stv0299_ops = {
.init = stv0299_init,
.sleep = stv0299_sleep,
+ .i2c_gate_ctrl = stv0299_i2c_gate_ctrl,
.set_frontend = stv0299_set_frontend,
.get_frontend = stv0299_get_frontend,
@@ -721,9 +721,8 @@ MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
MODULE_DESCRIPTION("ST STV0299 DVB Demodulator driver");
MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, "
- "Andreas Oberritter, Andrew de Quincey, Kenneth Aafløy");
+ "Andreas Oberritter, Andrew de Quincey, Kenneth Aafly");
MODULE_LICENSE("GPL");
-EXPORT_SYMBOL(stv0299_enable_plli2c);
EXPORT_SYMBOL(stv0299_writereg);
EXPORT_SYMBOL(stv0299_attach);
diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h
index 32c87b4..1504828 100644
--- a/drivers/media/dvb/frontends/stv0299.h
+++ b/drivers/media/dvb/frontends/stv0299.h
@@ -87,14 +87,9 @@ struct stv0299_config
/* Set the symbol rate */
int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio);
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend *fe, struct i2c_adapter *i2c);
- int (*pll_set)(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params);
};
extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data);
-extern int stv0299_enable_plli2c (struct dvb_frontend* fe);
extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
struct i2c_adapter* i2c);
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index 21255ca..e83ff21 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -36,7 +36,6 @@
struct tda10021_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct tda10021_config* config;
struct dvb_frontend frontend;
@@ -90,6 +89,14 @@ static int tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data)
return (ret != 1) ? -EREMOTEIO : 0;
}
+int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data)
+{
+ struct tda10021_state* state = fe->demodulator_priv;
+
+ return tda10021_writereg(state, reg, data);
+}
+EXPORT_SYMBOL(tda10021_write_byte);
+
static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
{
u8 b0 [] = { reg };
@@ -225,13 +232,6 @@ static int tda10021_init (struct dvb_frontend *fe)
//Activate PLL
tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef);
-
- if (state->config->pll_init) {
- lock_tuner(state);
- state->config->pll_init(fe);
- unlock_tuner(state);
- }
-
return 0;
}
@@ -259,9 +259,10 @@ static int tda10021_set_parameters (struct dvb_frontend *fe,
//printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate);
- lock_tuner(state);
- state->config->pll_set(fe, p);
- unlock_tuner(state);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
tda10021_set_symbolrate (state, p->u.qam.symbol_rate);
tda10021_writereg (state, 0x34, state->pwm);
@@ -376,6 +377,18 @@ static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa
return 0;
}
+static int tda10021_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct tda10021_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ lock_tuner(state);
+ } else {
+ unlock_tuner(state);
+ }
+ return 0;
+}
+
static int tda10021_sleep(struct dvb_frontend* fe)
{
struct tda10021_state* state = fe->demodulator_priv;
@@ -407,7 +420,6 @@ struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
state->pwm = pwm;
state->reg0 = tda10021_inittab[0];
@@ -415,7 +427,7 @@ struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
if ((tda10021_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -448,6 +460,7 @@ static struct dvb_frontend_ops tda10021_ops = {
.init = tda10021_init,
.sleep = tda10021_sleep,
+ .i2c_gate_ctrl = tda10021_i2c_gate_ctrl,
.set_frontend = tda10021_set_parameters,
.get_frontend = tda10021_get_frontend,
diff --git a/drivers/media/dvb/frontends/tda10021.h b/drivers/media/dvb/frontends/tda10021.h
index 53be939..b1df425 100644
--- a/drivers/media/dvb/frontends/tda10021.h
+++ b/drivers/media/dvb/frontends/tda10021.h
@@ -30,13 +30,11 @@ struct tda10021_config
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
struct i2c_adapter* i2c, u8 pwm);
+extern int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data);
+
#endif // TDA10021_H
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index b83dafa..59a2ed6 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -47,7 +47,6 @@ enum tda1004x_demod {
struct tda1004x_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct tda1004x_config* config;
struct dvb_frontend frontend;
@@ -600,13 +599,6 @@ static int tda10045_init(struct dvb_frontend* fe)
tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC
- // Init the PLL
- if (state->config->pll_init) {
- tda1004x_enable_tuner_i2c(state);
- state->config->pll_init(fe);
- tda1004x_disable_tuner_i2c(state);
- }
-
// tda setup
tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream
@@ -635,16 +627,6 @@ static int tda10046_init(struct dvb_frontend* fe)
return -EIO;
}
- // Init the tuner PLL
- if (state->config->pll_init) {
- tda1004x_enable_tuner_i2c(state);
- if (state->config->pll_init(fe)) {
- printk(KERN_ERR "tda1004x: pll init failed\n");
- return -EIO;
- }
- tda1004x_disable_tuner_i2c(state);
- }
-
// tda setup
tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87); // 100 ppm crystal, select HP stream
@@ -712,12 +694,10 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
}
// set frequency
- tda1004x_enable_tuner_i2c(state);
- if (state->config->pll_set(fe, fe_params)) {
- printk(KERN_ERR "tda1004x: pll set failed\n");
- return -EIO;
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, fe_params);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
- tda1004x_disable_tuner_i2c(state);
// Hardcoded to use auto as much as possible on the TDA10045 as it
// is very unreliable if AUTO mode is _not_ used.
@@ -1183,16 +1163,6 @@ static int tda1004x_sleep(struct dvb_frontend* fe)
break;
case TDA1004X_DEMOD_TDA10046:
- if (state->config->pll_sleep != NULL) {
- tda1004x_enable_tuner_i2c(state);
- state->config->pll_sleep(fe);
- if (state->config->if_freq != TDA10046_FREQ_052) {
- /* special hack for Philips EUROPA Based boards:
- * keep the I2c bridge open for tuner access in analog mode
- */
- tda1004x_disable_tuner_i2c(state);
- }
- }
/* set outputs to tristate */
tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff);
tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
@@ -1202,6 +1172,17 @@ static int tda1004x_sleep(struct dvb_frontend* fe)
return 0;
}
+static int tda1004x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct tda1004x_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return tda1004x_enable_tuner_i2c(state);
+ } else {
+ return tda1004x_disable_tuner_i2c(state);
+ }
+}
+
static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
fesettings->min_delay_ms = 800;
@@ -1235,6 +1216,7 @@ static struct dvb_frontend_ops tda10045_ops = {
.init = tda10045_init,
.sleep = tda1004x_sleep,
+ .i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
.set_frontend = tda1004x_set_fe,
.get_frontend = tda1004x_get_fe,
@@ -1260,7 +1242,6 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
state->demod_type = TDA1004X_DEMOD_TDA10045;
/* check if the demod is there */
@@ -1270,7 +1251,7 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
}
@@ -1293,6 +1274,7 @@ static struct dvb_frontend_ops tda10046_ops = {
.init = tda10046_init,
.sleep = tda1004x_sleep,
+ .i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
.set_frontend = tda1004x_set_fe,
.get_frontend = tda1004x_get_fe,
@@ -1318,7 +1300,6 @@ struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
state->demod_type = TDA1004X_DEMOD_TDA10046;
/* check if the demod is there */
@@ -1328,7 +1309,7 @@ struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
}
diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h
index cc0c4af..b877b23 100644
--- a/drivers/media/dvb/frontends/tda1004x.h
+++ b/drivers/media/dvb/frontends/tda1004x.h
@@ -66,11 +66,6 @@ struct tda1004x_config
/* AGC configuration */
enum tda10046_agc agc_config;
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- void (*pll_sleep)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
/* request firmware for device */
/* set this to NULL if the card has a firmware EEPROM */
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c
index 91baa9c..3aa45eb 100644
--- a/drivers/media/dvb/frontends/tda8083.c
+++ b/drivers/media/dvb/frontends/tda8083.c
@@ -37,7 +37,6 @@
struct tda8083_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct tda8083_config* config;
struct dvb_frontend frontend;
@@ -293,7 +292,11 @@ static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
{
struct tda8083_state* state = fe->demodulator_priv;
- state->config->pll_set(fe, p);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
tda8083_set_inversion (state, p->inversion);
tda8083_set_fec (state, p->u.qpsk.fec_inner);
tda8083_set_symbolrate (state, p->u.qpsk.symbol_rate);
@@ -334,8 +337,6 @@ static int tda8083_init(struct dvb_frontend* fe)
for (i=0; i<44; i++)
tda8083_writereg (state, i, tda8083_init_tab[i]);
- if (state->config->pll_init) state->config->pll_init(fe);
-
tda8083_writereg (state, 0x00, 0x3c);
tda8083_writereg (state, 0x00, 0x04);
@@ -395,13 +396,12 @@ struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &tda8083_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if ((tda8083_readreg(state, 0x00)) != 0x05) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &tda8083_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/tda8083.h b/drivers/media/dvb/frontends/tda8083.h
index 4666633..e7a48f6 100644
--- a/drivers/media/dvb/frontends/tda8083.h
+++ b/drivers/media/dvb/frontends/tda8083.h
@@ -33,10 +33,6 @@ struct tda8083_config
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c
index ad8647a3..6bffe85 100644
--- a/drivers/media/dvb/frontends/ves1820.c
+++ b/drivers/media/dvb/frontends/ves1820.c
@@ -35,7 +35,6 @@
struct ves1820_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct ves1820_config* config;
struct dvb_frontend frontend;
@@ -204,9 +203,6 @@ static int ves1820_init(struct dvb_frontend* fe)
ves1820_writereg(state, 0x34, state->pwm);
- if (state->config->pll_init)
- state->config->pll_init(fe);
-
return 0;
}
@@ -223,7 +219,11 @@ static int ves1820_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_p
if (real_qam < 0 || real_qam > 4)
return -EINVAL;
- state->config->pll_set(fe, p);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
ves1820_set_symbolrate(state, p->u.qam.symbol_rate);
ves1820_writereg(state, 0x34, state->pwm);
@@ -380,7 +380,6 @@ struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
goto error;
/* setup the state */
- memcpy(&state->ops, &ves1820_ops, sizeof(struct dvb_frontend_ops));
state->reg0 = ves1820_inittab[0];
state->config = config;
state->i2c = i2c;
@@ -393,12 +392,12 @@ struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
if (verbose)
printk("ves1820: pwm=0x%02x\n", state->pwm);
- state->ops.info.symbol_rate_min = (state->config->xin / 2) / 64; /* SACLK/64 == (XIN/2)/64 */
- state->ops.info.symbol_rate_max = (state->config->xin / 2) / 4; /* SACLK/4 */
-
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &ves1820_ops, sizeof(struct dvb_frontend_ops));
+ state->frontend.ops.info.symbol_rate_min = (state->config->xin / 2) / 64; /* SACLK/64 == (XIN/2)/64 */
+ state->frontend.ops.info.symbol_rate_max = (state->config->xin / 2) / 4; /* SACLK/4 */
state->frontend.demodulator_priv = state;
+
return &state->frontend;
error:
diff --git a/drivers/media/dvb/frontends/ves1820.h b/drivers/media/dvb/frontends/ves1820.h
index 355f130..520f095 100644
--- a/drivers/media/dvb/frontends/ves1820.h
+++ b/drivers/media/dvb/frontends/ves1820.h
@@ -39,10 +39,6 @@ struct ves1820_config
/* SELAGC control */
u8 selagc:1;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
diff --git a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb/frontends/ves1x93.c
index 821df8e..54d7b07 100644
--- a/drivers/media/dvb/frontends/ves1x93.c
+++ b/drivers/media/dvb/frontends/ves1x93.c
@@ -36,7 +36,6 @@
struct ves1x93_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct ves1x93_config* config;
struct dvb_frontend frontend;
@@ -278,12 +277,6 @@ static int ves1x93_init (struct dvb_frontend* fe)
}
}
- if (state->config->pll_init) {
- ves1x93_writereg(state, 0x00, 0x11);
- state->config->pll_init(fe);
- ves1x93_writereg(state, 0x00, 0x01);
- }
-
return 0;
}
@@ -395,9 +388,10 @@ static int ves1x93_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
{
struct ves1x93_state* state = fe->demodulator_priv;
- ves1x93_writereg(state, 0x00, 0x11);
- state->config->pll_set(fe, p);
- ves1x93_writereg(state, 0x00, 0x01);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
ves1x93_set_inversion (state, p->inversion);
ves1x93_set_fec (state, p->u.qpsk.fec_inner);
ves1x93_set_symbolrate (state, p->u.qpsk.symbol_rate);
@@ -442,6 +436,17 @@ static void ves1x93_release(struct dvb_frontend* fe)
kfree(state);
}
+static int ves1x93_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct ves1x93_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return ves1x93_writereg(state, 0x00, 0x11);
+ } else {
+ return ves1x93_writereg(state, 0x00, 0x01);
+ }
+}
+
static struct dvb_frontend_ops ves1x93_ops;
struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
@@ -457,7 +462,6 @@ struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops));
state->inversion = INVERSION_OFF;
/* check if the demod is there + identify it */
@@ -492,7 +496,7 @@ struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -523,6 +527,7 @@ static struct dvb_frontend_ops ves1x93_ops = {
.init = ves1x93_init,
.sleep = ves1x93_sleep,
+ .i2c_gate_ctrl = ves1x93_i2c_gate_ctrl,
.set_frontend = ves1x93_set_frontend,
.get_frontend = ves1x93_get_frontend,
diff --git a/drivers/media/dvb/frontends/ves1x93.h b/drivers/media/dvb/frontends/ves1x93.h
index 1627e37..ba88ae0 100644
--- a/drivers/media/dvb/frontends/ves1x93.h
+++ b/drivers/media/dvb/frontends/ves1x93.h
@@ -38,10 +38,6 @@ struct ves1x93_config
/* should PWM be inverted? */
u8 invert_pwm:1;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
index d7d9f59..2b95e8b 100644
--- a/drivers/media/dvb/frontends/zl10353.c
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -34,7 +34,6 @@
struct zl10353_state {
struct i2c_adapter *i2c;
struct dvb_frontend frontend;
- struct dvb_frontend_ops ops;
struct zl10353_config config;
};
@@ -126,6 +125,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
struct dvb_frontend_parameters *param)
{
struct zl10353_state *state = fe->demodulator_priv;
+
u8 pllbuf[6] = { 0x67 };
/* These settings set "auto-everything" and start the FSM. */
@@ -142,7 +142,30 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
zl10353_single_write(fe, 0x66, 0xE9);
zl10353_single_write(fe, 0x62, 0x0A);
- state->config.pll_set(fe, param, pllbuf + 1);
+ // if there is no attached secondary tuner, we call set_params to program
+ // a potential tuner attached somewhere else
+ if (state->config.no_tuner) {
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ }
+
+ // if pllbuf is defined, retrieve the settings
+ if (fe->ops.tuner_ops.calc_regs) {
+ fe->ops.tuner_ops.calc_regs(fe, param, pllbuf+1, 5);
+ pllbuf[1] <<= 1;
+ } else {
+ // fake pllbuf settings
+ pllbuf[1] = 0x61 << 1;
+ pllbuf[2] = 0;
+ pllbuf[3] = 0;
+ pllbuf[3] = 0;
+ pllbuf[4] = 0;
+ }
+
+ // there is no call to _just_ start decoding, so we send the pllbuf anyway
+ // even if there isn't a PLL attached to the secondary bus
zl10353_write(fe, pllbuf, sizeof(pllbuf));
zl10353_single_write(fe, 0x70, 0x01);
@@ -254,14 +277,13 @@ struct dvb_frontend *zl10353_attach(const struct zl10353_config *config,
/* setup the state */
state->i2c = i2c;
memcpy(&state->config, config, sizeof(struct zl10353_config));
- memcpy(&state->ops, &zl10353_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if (zl10353_read_register(state, CHIP_ID) != ID_ZL10353)
goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &zl10353_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h
index 5cc4ae71..9770cb8 100644
--- a/drivers/media/dvb/frontends/zl10353.h
+++ b/drivers/media/dvb/frontends/zl10353.h
@@ -29,10 +29,8 @@ struct zl10353_config
/* demodulator's I2C address */
u8 demod_address;
- /* function which configures the PLL buffer (for secondary I2C
- * connected tuner) or tunes the PLL (for direct connected tuner) */
- int (*pll_set)(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params, u8 *pllbuf);
+ /* set if no pll is connected to the secondary i2c bus */
+ int no_tuner;
};
extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
index 1c5316e..acabea0 100644
--- a/drivers/media/dvb/pluto2/pluto2.c
+++ b/drivers/media/dvb/pluto2/pluto2.c
@@ -424,8 +424,8 @@ static inline u32 divide(u32 numerator, u32 denominator)
}
/* LG Innotek TDTE-E001P (Infineon TUA6034) */
-static int lg_tdtpe001p_pll_set(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
{
struct pluto *pluto = frontend_to_pluto(fe);
struct i2c_msg msg;
@@ -473,6 +473,8 @@ static int lg_tdtpe001p_pll_set(struct dvb_frontend *fe,
msg.buf = buf;
msg.len = sizeof(buf);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
ret = i2c_transfer(&pluto->i2c_adap, &msg, 1);
if (ret < 0)
return ret;
@@ -497,8 +499,6 @@ static struct tda1004x_config pluto2_fe_config __devinitdata = {
.xtal_freq = TDA10046_XTAL_16M,
.agc_config = TDA10046_AGC_DEFAULT,
.if_freq = TDA10046_FREQ_3617,
- .pll_set = lg_tdtpe001p_pll_set,
- .pll_sleep = NULL,
.request_firmware = pluto2_request_firmware,
};
@@ -511,11 +511,12 @@ static int __devinit frontend_init(struct pluto *pluto)
dev_err(&pluto->pdev->dev, "could not attach frontend\n");
return -ENODEV;
}
+ pluto->fe->ops.tuner_ops.set_params = lg_tdtpe001p_tuner_set_params;
ret = dvb_register_frontend(&pluto->dvb_adapter, pluto->fe);
if (ret < 0) {
- if (pluto->fe->ops->release)
- pluto->fe->ops->release(pluto->fe);
+ if (pluto->fe->ops.release)
+ pluto->fe->ops.release(pluto->fe);
return ret;
}
@@ -647,7 +648,7 @@ static int __devinit pluto2_probe(struct pci_dev *pdev,
goto err_pluto_hw_exit;
/* dvb */
- ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, THIS_MODULE);
+ ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, THIS_MODULE, &pdev->dev);
if (ret < 0)
goto err_i2c_bit_del_bus;
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index b5ac7df..987881f 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -10,6 +10,7 @@ config DVB_AV7110
select DVB_SP8870
select DVB_STV0297
select DVB_L64781
+ select DVB_LNBP21
help
Support for SAA7146 and AV7110 based DVB cards as produced
by Fujitsu-Siemens, Technotrend, Hauppauge and others.
@@ -67,6 +68,7 @@ config DVB_BUDGET
select DVB_TDA8083
select DVB_TDA10021
select DVB_S5H1420
+ select DVB_LNBP21
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
@@ -84,6 +86,7 @@ config DVB_BUDGET_CI
select DVB_STV0297
select DVB_STV0299
select DVB_TDA1004X
+ select DVB_LNBP21
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile
index a690730..aa85ecd 100644
--- a/drivers/media/dvb/ttpci/Makefile
+++ b/drivers/media/dvb/ttpci/Makefile
@@ -15,9 +15,9 @@ EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
hostprogs-y := fdump
-ifdef CONFIG_DVB_AV7110_FIRMWARE
-$(obj)/av7110.o: $(obj)/fdump $(obj)/av7110_firm.h
+ifeq ($(CONFIG_DVB_AV7110_FIRMWARE),y)
+$(obj)/av7110.o: $(obj)/av7110_firm.h
-$(obj)/av7110_firm.h:
+$(obj)/av7110_firm.h: $(obj)/fdump
$(obj)/fdump $(CONFIG_DVB_AV7110_FIRMWARE_FILE) dvb_ttpci_fw $@
endif
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index d028245..8832f80 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -1552,7 +1552,7 @@ static int get_firmware(struct av7110* av7110)
#endif
-static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
u8 pwr = 0;
@@ -1575,6 +1575,8 @@ static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
// NOTE: since we're using a prescaler of 2, we set the
// divisor frequency to 62.5kHz and divide by 125 above
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
@@ -1584,10 +1586,9 @@ static struct ves1x93_config alps_bsrv2_config = {
.demod_address = 0x08,
.xin = 90100000UL,
.invert_pwm = 0,
- .pll_set = alps_bsrv2_pll_set,
};
-static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct av7110* av7110 = fe->dvb->priv;
u32 div;
@@ -1601,6 +1602,8 @@ static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
data[2] = 0x85 | ((div >> 10) & 0x60);
data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
@@ -1611,14 +1614,12 @@ static struct ves1820_config alps_tdbe2_config = {
.xin = 57840000UL,
.invert = 1,
.selagc = VES1820_SELAGC_SIGNAMPERR,
- .pll_set = alps_tdbe2_pll_set,
};
-static int grundig_29504_451_pll_set(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params)
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct av7110* av7110 = fe->dvb->priv;
u32 div;
@@ -1631,6 +1632,8 @@ static int grundig_29504_451_pll_set(struct dvb_frontend* fe,
data[2] = 0x8e;
data[3] = 0x00;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
@@ -1638,13 +1641,11 @@ static int grundig_29504_451_pll_set(struct dvb_frontend* fe,
static struct tda8083_config grundig_29504_451_config = {
.demod_address = 0x68,
- .pll_set = grundig_29504_451_pll_set,
};
-static int philips_cd1516_pll_set(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params)
+static int philips_cd1516_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct av7110* av7110 = fe->dvb->priv;
u32 div;
@@ -1659,6 +1660,8 @@ static int philips_cd1516_pll_set(struct dvb_frontend* fe,
data[2] = 0x8e;
data[3] = (f < 174000000 ? 0xa1 : f < 470000000 ? 0x92 : 0x34);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
@@ -1669,12 +1672,11 @@ static struct ves1820_config philips_cd1516_config = {
.xin = 57840000UL,
.invert = 1,
.selagc = VES1820_SELAGC_SIGNAMPERR,
- .pll_set = philips_cd1516_pll_set,
};
-static int alps_tdlb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdlb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct av7110* av7110 = fe->dvb->priv;
u32 div, pwr;
@@ -1693,6 +1695,8 @@ static int alps_tdlb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
data[2] = 0x85;
data[3] = pwr << 6;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
@@ -1708,7 +1712,6 @@ static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct fir
static struct sp8870_config alps_tdlb7_config = {
.demod_address = 0x71,
- .pll_set = alps_tdlb7_pll_set,
.request_firmware = alps_tdlb7_request_firmware,
};
@@ -1806,7 +1809,7 @@ static u8 nexusca_stv0297_inittab[] = {
0xff, 0xff,
};
-static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int nexusca_stv0297_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct av7110* av7110 = fe->dvb->priv;
u32 div;
@@ -1832,7 +1835,8 @@ static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_
else
return -EINVAL;
- stv0297_enable_plli2c(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) {
printk("nexusca: pll transfer failed!\n");
return -EIO;
@@ -1840,8 +1844,8 @@ static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_
// wait for PLL lock
for(i = 0; i < 20; i++) {
-
- stv0297_enable_plli2c(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&av7110->i2c_adap, &readmsg, 1) == 1)
if (data[0] & 0x40) break;
msleep(10);
@@ -1855,12 +1859,12 @@ static struct stv0297_config nexusca_stv0297_config = {
.demod_address = 0x1C,
.inittab = nexusca_stv0297_inittab,
.invert = 1,
- .pll_set = nexusca_stv0297_pll_set,
+ .stop_during_read = 1,
};
-static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
u32 div;
@@ -1887,13 +1891,14 @@ static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_fronten
data[2] = ((div >> 10) & 0x60) | cfg;
data[3] = (cpump << 6) | band_select;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) return -EIO;
return 0;
}
static struct l64781_config grundig_29504_401_config = {
.demod_address = 0x55,
- .pll_set = grundig_29504_401_pll_set,
};
@@ -2079,6 +2084,9 @@ static int frontend_init(struct av7110 *av7110)
case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??))
av7110->fe = ves1820_attach(&philips_cd1516_config,
&av7110->i2c_adap, read_pwm(av7110));
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
+ }
break;
}
@@ -2091,9 +2099,10 @@ static int frontend_init(struct av7110 *av7110)
// try the ALPS BSRV2 first of all
av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap);
if (av7110->fe) {
- av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
- av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
- av7110->fe->ops->set_tone = av7110_set_tone;
+ av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+ av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+ av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+ av7110->fe->ops.set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
break;
}
@@ -2101,9 +2110,12 @@ static int frontend_init(struct av7110 *av7110)
// try the ALPS BSRU6 now
av7110->fe = stv0299_attach(&alps_bsru6_config, &av7110->i2c_adap);
if (av7110->fe) {
- av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
- av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
- av7110->fe->ops->set_tone = av7110_set_tone;
+ av7110->fe->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ av7110->fe->tuner_priv = &av7110->i2c_adap;
+
+ av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+ av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+ av7110->fe->ops.set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
break;
}
@@ -2111,9 +2123,10 @@ static int frontend_init(struct av7110 *av7110)
// Try the grundig 29504-451
av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
if (av7110->fe) {
- av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
- av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
- av7110->fe->ops->set_tone = av7110_set_tone;
+ av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+ av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+ av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+ av7110->fe->ops.set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
break;
}
@@ -2124,11 +2137,17 @@ static int frontend_init(struct av7110 *av7110)
/* Siemens DVB-C (full-length card) VES1820/Philips CD1516 */
av7110->fe = ves1820_attach(&philips_cd1516_config, &av7110->i2c_adap,
read_pwm(av7110));
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
+ }
break;
case 0x0003:
/* Hauppauge DVB-C 2.1 VES1820/ALPS TDBE2 */
av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap,
read_pwm(av7110));
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+ }
break;
}
break;
@@ -2137,20 +2156,27 @@ static int frontend_init(struct av7110 *av7110)
// ALPS TDLB7
av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap);
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = alps_tdlb7_tuner_set_params;
+ }
break;
case 0x0002: // Hauppauge/TT DVB-C premium rev2.X
av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+ }
break;
case 0x0004: // Galaxis DVB-S rev1.3
/* ALPS BSRV2 */
av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap);
if (av7110->fe) {
- av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
- av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
- av7110->fe->ops->set_tone = av7110_set_tone;
+ av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+ av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+ av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+ av7110->fe->ops.set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
}
break;
@@ -2159,9 +2185,10 @@ static int frontend_init(struct av7110 *av7110)
/* Grundig 29504-451 */
av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
if (av7110->fe) {
- av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
- av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
- av7110->fe->ops->set_tone = av7110_set_tone;
+ av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+ av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+ av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+ av7110->fe->ops.set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
}
break;
@@ -2169,12 +2196,17 @@ static int frontend_init(struct av7110 *av7110)
case 0x0008: // Hauppauge/TT DVB-T
av7110->fe = l64781_attach(&grundig_29504_401_config, &av7110->i2c_adap);
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
+ }
break;
case 0x000A: // Hauppauge/TT Nexus-CA rev1.X
av7110->fe = stv0297_attach(&nexusca_stv0297_config, &av7110->i2c_adap);
if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = nexusca_stv0297_tuner_set_params;
+
/* set TDA9819 into DVB mode */
saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD)
saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF)
@@ -2189,13 +2221,16 @@ static int frontend_init(struct av7110 *av7110)
/* ALPS BSBE1 */
av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap);
if (av7110->fe) {
- if (lnbp21_init(av7110->fe, &av7110->i2c_adap, 0, 0)) {
+ av7110->fe->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
+ av7110->fe->tuner_priv = &av7110->i2c_adap;
+
+ if (lnbp21_attach(av7110->fe, &av7110->i2c_adap, 0, 0)) {
printk("dvb-ttpci: LNBP21 not found!\n");
- if (av7110->fe->ops->release)
- av7110->fe->ops->release(av7110->fe);
+ if (av7110->fe->ops.release)
+ av7110->fe->ops.release(av7110->fe);
av7110->fe = NULL;
} else {
- av7110->fe->ops->dishnetwork_send_legacy_command = NULL;
+ av7110->fe->ops.dishnetwork_send_legacy_command = NULL;
av7110->recover = dvb_s_recover;
}
}
@@ -2212,21 +2247,21 @@ static int frontend_init(struct av7110 *av7110)
av7110->dev->pci->subsystem_vendor,
av7110->dev->pci->subsystem_device);
} else {
- FE_FUNC_OVERRIDE(av7110->fe->ops->init, av7110->fe_init, av7110_fe_init);
- FE_FUNC_OVERRIDE(av7110->fe->ops->read_status, av7110->fe_read_status, av7110_fe_read_status);
- FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload);
- FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
- FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
- FE_FUNC_OVERRIDE(av7110->fe->ops->set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
- FE_FUNC_OVERRIDE(av7110->fe->ops->set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;)
- FE_FUNC_OVERRIDE(av7110->fe->ops->dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
- FE_FUNC_OVERRIDE(av7110->fe->ops->set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.init, av7110->fe_init, av7110_fe_init);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.read_status, av7110->fe_read_status, av7110_fe_read_status);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;)
+ FE_FUNC_OVERRIDE(av7110->fe->ops.dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend);
ret = dvb_register_frontend(&av7110->dvb_adapter, av7110->fe);
if (ret < 0) {
printk("av7110: Frontend registration failed!\n");
- if (av7110->fe->ops->release)
- av7110->fe->ops->release(av7110->fe);
+ if (av7110->fe->ops.release)
+ av7110->fe->ops.release(av7110->fe);
av7110->fe = NULL;
}
}
@@ -2413,7 +2448,7 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
goto err_kfree_0;
ret = dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name,
- THIS_MODULE);
+ THIS_MODULE, &dev->pci->dev);
if (ret < 0)
goto err_put_firmware_1;
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 8a7cd7d..6163cb0 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -50,6 +50,12 @@
#define DEBICICAM 0x02420000
+#define SLOTSTATUS_NONE 1
+#define SLOTSTATUS_PRESENT 2
+#define SLOTSTATUS_RESET 4
+#define SLOTSTATUS_READY 8
+#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
+
struct budget_av {
struct budget budget;
struct video_device *vd;
@@ -58,8 +64,15 @@ struct budget_av {
struct tasklet_struct ciintf_irq_tasklet;
int slot_status;
struct dvb_ca_en50221 ca;
+ u8 reinitialise_demod:1;
+ u8 tda10021_poclkp:1;
+ u8 tda10021_ts_enabled;
+ int (*tda10021_set_frontend)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
};
+static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot);
+
+
/* GPIO Connections:
* 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*!
* 1 - CI memory select 0=>IO memory, 1=>Attribute Memory
@@ -129,9 +142,10 @@ static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int ad
udelay(1);
result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1);
-
- if (result == -ETIMEDOUT)
- budget_av->slot_status = 0;
+ if (result == -ETIMEDOUT) {
+ ciintf_slot_shutdown(ca, slot);
+ printk(KERN_INFO "budget-av: cam ejected 1\n");
+ }
return result;
}
@@ -147,9 +161,10 @@ static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int a
udelay(1);
result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1);
-
- if (result == -ETIMEDOUT)
- budget_av->slot_status = 0;
+ if (result == -ETIMEDOUT) {
+ ciintf_slot_shutdown(ca, slot);
+ printk(KERN_INFO "budget-av: cam ejected 2\n");
+ }
return result;
}
@@ -165,9 +180,11 @@ static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 addre
udelay(1);
result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0);
-
- if (result == -ETIMEDOUT)
- budget_av->slot_status = 0;
+ if ((result == -ETIMEDOUT) || ((result == 0xff) && ((address & 3) < 2))) {
+ ciintf_slot_shutdown(ca, slot);
+ printk(KERN_INFO "budget-av: cam ejected 3\n");
+ return -ETIMEDOUT;
+ }
return result;
}
@@ -183,9 +200,10 @@ static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 addr
udelay(1);
result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0);
-
- if (result == -ETIMEDOUT)
- budget_av->slot_status = 0;
+ if (result == -ETIMEDOUT) {
+ ciintf_slot_shutdown(ca, slot);
+ printk(KERN_INFO "budget-av: cam ejected 5\n");
+ }
return result;
}
@@ -193,12 +211,12 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
{
struct budget_av *budget_av = (struct budget_av *) ca->data;
struct saa7146_dev *saa = budget_av->budget.dev;
- int timeout = 50; // 5 seconds (4.4.6 Ready)
if (slot != 0)
return -EINVAL;
dprintk(1, "ciintf_slot_reset\n");
+ budget_av->slot_status = SLOTSTATUS_RESET;
saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
@@ -208,20 +226,17 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
msleep(20); /* 20 ms Vcc settling time */
saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */
+ ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
+ msleep(20);
- /* This should have been based on pin 16 READY of the pcmcia port,
- * but AFAICS it is not routed to the saa7146 */
- while (--timeout > 0 && ciintf_read_attribute_mem(ca, slot, 0) != 0x1d)
- msleep(100);
-
- /* reinitialise the frontend */
- dvb_frontend_reinitialise(budget_av->budget.dvb_frontend);
+ /* reinitialise the frontend if necessary */
+ if (budget_av->reinitialise_demod)
+ dvb_frontend_reinitialise(budget_av->budget.dvb_frontend);
- if (timeout <= 0)
- {
- printk(KERN_ERR "budget-av: cam reset failed (timeout).\n");
- saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
- return -ETIMEDOUT;
+ /* set tda10021 back to original clock configuration on reset */
+ if (budget_av->tda10021_poclkp) {
+ tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+ budget_av->tda10021_ts_enabled = 0;
}
return 0;
@@ -238,7 +253,13 @@ static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
dprintk(1, "ciintf_slot_shutdown\n");
ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
- budget_av->slot_status = 0;
+ budget_av->slot_status = SLOTSTATUS_NONE;
+
+ /* set tda10021 back to original clock configuration when cam removed */
+ if (budget_av->tda10021_poclkp) {
+ tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+ budget_av->tda10021_ts_enabled = 0;
+ }
return 0;
}
@@ -253,6 +274,13 @@ static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status);
ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
+
+ /* tda10021 seems to need a different TS clock config when data is routed to the CAM */
+ if (budget_av->tda10021_poclkp) {
+ tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1);
+ budget_av->tda10021_ts_enabled = 1;
+ }
+
return 0;
}
@@ -260,50 +288,61 @@ static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open
{
struct budget_av *budget_av = (struct budget_av *) ca->data;
struct saa7146_dev *saa = budget_av->budget.dev;
- int cam_present = 0;
+ int result;
if (slot != 0)
return -EINVAL;
- if (!budget_av->slot_status)
- {
- // first of all test the card detect line
+ /* test the card detect line - needs to be done carefully
+ * since it never goes high for some CAMs on this interface (e.g. topuptv) */
+ if (budget_av->slot_status == SLOTSTATUS_NONE) {
saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
udelay(1);
- if (saa7146_read(saa, PSR) & MASK_06)
- {
- cam_present = 1;
+ if (saa7146_read(saa, PSR) & MASK_06) {
+ if (budget_av->slot_status == SLOTSTATUS_NONE) {
+ budget_av->slot_status = SLOTSTATUS_PRESENT;
+ printk(KERN_INFO "budget-av: cam inserted A\n");
+ }
}
saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+ }
- // that is unreliable however, so try and read from IO memory
- if (!cam_present)
- {
- saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
- if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) != -ETIMEDOUT)
- {
- cam_present = 1;
+ /* We also try and read from IO memory to work round the above detection bug. If
+ * there is no CAM, we will get a timeout. Only done if there is no cam
+ * present, since this test actually breaks some cams :(
+ *
+ * if the CI interface is not open, we also do the above test since we
+ * don't care if the cam has problems - we'll be resetting it on open() anyway */
+ if ((budget_av->slot_status == SLOTSTATUS_NONE) || (!open)) {
+ saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
+ result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1);
+ if ((result >= 0) && (budget_av->slot_status == SLOTSTATUS_NONE)) {
+ budget_av->slot_status = SLOTSTATUS_PRESENT;
+ printk(KERN_INFO "budget-av: cam inserted B\n");
+ } else if (result < 0) {
+ if (budget_av->slot_status != SLOTSTATUS_NONE) {
+ ciintf_slot_shutdown(ca, slot);
+ printk(KERN_INFO "budget-av: cam ejected 5\n");
+ return 0;
}
}
+ }
- // did we find something?
- if (cam_present) {
- printk(KERN_INFO "budget-av: cam inserted\n");
- budget_av->slot_status = 1;
- }
- } else if (!open) {
- saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
- if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT)
- {
- printk(KERN_INFO "budget-av: cam ejected\n");
- saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
- budget_av->slot_status = 0;
+ /* read from attribute memory in reset/ready state to know when the CAM is ready */
+ if (budget_av->slot_status == SLOTSTATUS_RESET) {
+ result = ciintf_read_attribute_mem(ca, slot, 0);
+ if (result == 0x1d) {
+ budget_av->slot_status = SLOTSTATUS_READY;
}
}
- if (budget_av->slot_status == 1)
- return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
-
+ /* work out correct return code */
+ if (budget_av->slot_status != SLOTSTATUS_NONE) {
+ if (budget_av->slot_status & SLOTSTATUS_READY) {
+ return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
+ }
+ return DVB_CA_EN50221_POLL_CAM_PRESENT;
+ }
return 0;
}
@@ -333,6 +372,8 @@ static int ciintf_init(struct budget_av *budget_av)
budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable;
budget_av->ca.poll_slot_status = ciintf_poll_slot_status;
budget_av->ca.data = budget_av;
+ budget_av->budget.ci_present = 1;
+ budget_av->slot_status = SLOTSTATUS_NONE;
if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter,
&budget_av->ca, 0, 1)) != 0) {
@@ -341,7 +382,6 @@ static int ciintf_init(struct budget_av *budget_av)
}
printk(KERN_INFO "budget-av: ci interface initialised.\n");
- budget_av->budget.ci_present = 1;
return 0;
error:
@@ -472,12 +512,12 @@ static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 sra
return 0;
}
-static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe,
- struct i2c_adapter *i2c,
- struct dvb_frontend_parameters *params)
+static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
{
u32 div;
u8 buf[4];
+ struct budget *budget = (struct budget *) fe->dvb->priv;
struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
if ((params->frequency < 950000) || (params->frequency > 2150000))
@@ -501,7 +541,9 @@ static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe,
else if (params->frequency < 2150000)
buf[3] |= 0xC0;
- if (i2c_transfer(i2c, &msg, 1) != 1)
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
}
@@ -509,9 +551,8 @@ static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe,
#define MIN2(a,b) ((a) < (b) ? (a) : (b))
#define MIN3(a,b,c) MIN2(MIN2(a,b),c)
-static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe,
- struct i2c_adapter *i2c,
- struct dvb_frontend_parameters *params)
+static int philips_su1278sh2_tua6100_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
{
u8 reg0 [2] = { 0x00, 0x00 };
u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 };
@@ -521,6 +562,7 @@ static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe,
int R, A, N, P, M;
struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = NULL,.len = 0 };
int freq = params->frequency;
+ struct budget *budget = (struct budget *) fe->dvb->priv;
first_ZF = (freq) / 1000;
@@ -620,21 +662,25 @@ static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe,
reg0[1] |= 0x03;
/* already enabled - do not reenable i2c repeater or TX fails */
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
msg.buf = reg0;
msg.len = sizeof(reg0);
- if (i2c_transfer(i2c, &msg, 1) != 1)
+ if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
return -EIO;
- stv0299_enable_plli2c(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
msg.buf = reg1;
msg.len = sizeof(reg1);
- if (i2c_transfer(i2c, &msg, 1) != 1)
+ if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
return -EIO;
- stv0299_enable_plli2c(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
msg.buf = reg2;
msg.len = sizeof(reg2);
- if (i2c_transfer(i2c, &msg, 1) != 1)
+ if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
@@ -692,7 +738,6 @@ static struct stv0299_config typhoon_config = {
.volt13_op0_op1 = STV0299_VOLT13_OP0,
.min_delay_ms = 100,
.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
- .pll_set = philips_su1278_ty_ci_pll_set,
};
@@ -706,7 +751,6 @@ static struct stv0299_config cinergy_1200s_config = {
.volt13_op0_op1 = STV0299_VOLT13_OP0,
.min_delay_ms = 100,
.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
- .pll_set = philips_su1278_ty_ci_pll_set,
};
static struct stv0299_config cinergy_1200s_1894_0010_config = {
@@ -719,10 +763,9 @@ static struct stv0299_config cinergy_1200s_1894_0010_config = {
.volt13_op0_op1 = STV0299_VOLT13_OP0,
.min_delay_ms = 100,
.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
- .pll_set = philips_su1278sh2_tua6100_pll_set,
};
-static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct budget *budget = (struct budget *) fe->dvb->priv;
u8 buf[4];
@@ -738,6 +781,8 @@ static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_p
buf[3] = (params->frequency < 150000000 ? 0x01 :
params->frequency < 445000000 ? 0x02 : 0x04);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
@@ -745,19 +790,20 @@ static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_p
static struct tda10021_config philips_cu1216_config = {
.demod_address = 0x0c,
- .pll_set = philips_cu1216_pll_set,
};
-static int philips_tu1216_pll_init(struct dvb_frontend *fe)
+static int philips_tu1216_tuner_init(struct dvb_frontend *fe)
{
struct budget *budget = (struct budget *) fe->dvb->priv;
static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
// setup PLL configuration
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
msleep(1);
@@ -765,7 +811,7 @@ static int philips_tu1216_pll_init(struct dvb_frontend *fe)
return 0;
}
-static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct budget *budget = (struct budget *) fe->dvb->priv;
u8 tuner_buf[4];
@@ -839,6 +885,8 @@ static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_p
tuner_buf[2] = 0xca;
tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
@@ -862,9 +910,6 @@ static struct tda1004x_config philips_tu1216_config = {
.xtal_freq = TDA10046_XTAL_4M,
.agc_config = TDA10046_AGC_DEFAULT,
.if_freq = TDA10046_FREQ_3617,
- .pll_init = philips_tu1216_pll_init,
- .pll_set = philips_tu1216_pll_set,
- .pll_sleep = NULL,
.request_firmware = philips_tu1216_request_firmware,
};
@@ -911,13 +956,13 @@ static u8 philips_sd1878_inittab[] = {
0xff, 0xff
};
-static int philips_sd1878_tda8261_pll_set(struct dvb_frontend *fe,
- struct i2c_adapter *i2c,
- struct dvb_frontend_parameters *params)
+static int philips_sd1878_tda8261_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
{
u8 buf[4];
int rc;
struct i2c_msg tuner_msg = {.addr=0x60,.flags=0,.buf=buf,.len=sizeof(buf)};
+ struct budget *budget = (struct budget *) fe->dvb->priv;
if((params->frequency < 950000) || (params->frequency > 2150000))
return -EINVAL;
@@ -926,7 +971,9 @@ static int philips_sd1878_tda8261_pll_set(struct dvb_frontend *fe,
params->frequency, 0);
if(rc < 0) return rc;
- if(i2c_transfer(i2c, &tuner_msg, 1) != 1)
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if(i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
return 0;
@@ -969,7 +1016,7 @@ static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe,
static struct stv0299_config philips_sd1878_config = {
.demod_address = 0x68,
- .inittab = philips_sd1878_inittab,
+ .inittab = philips_sd1878_inittab,
.mclk = 88000000UL,
.invert = 0,
.skip_reinit = 0,
@@ -977,7 +1024,6 @@ static struct stv0299_config philips_sd1878_config = {
.volt13_op0_op1 = STV0299_VOLT13_OP0,
.min_delay_ms = 100,
.set_symbol_rate = philips_sd1878_ci_set_symbol_rate,
- .pll_set = philips_sd1878_tda8261_pll_set,
};
static u8 read_pwm(struct budget_av *budget_av)
@@ -1003,6 +1049,7 @@ static u8 read_pwm(struct budget_av *budget_av)
#define SUBID_DVBS_TV_STAR 0x0014
#define SUBID_DVBS_TV_STAR_CI 0x0016
+#define SUBID_DVBS_EASYWATCH_1 0x001a
#define SUBID_DVBS_EASYWATCH 0x001e
#define SUBID_DVBC_KNC1 0x0020
#define SUBID_DVBC_KNC1_PLUS 0x0021
@@ -1012,17 +1059,36 @@ static u8 read_pwm(struct budget_av *budget_av)
#define SUBID_DVBT_KNC1 0x0030
#define SUBID_DVBT_CINERGY1200 0x1157
+
+static int tda10021_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct budget_av* budget_av = fe->dvb->priv;
+ int result;
+
+ result = budget_av->tda10021_set_frontend(fe, p);
+ if (budget_av->tda10021_ts_enabled) {
+ tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1);
+ } else {
+ tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+ }
+
+ return result;
+}
+
static void frontend_init(struct budget_av *budget_av)
{
struct saa7146_dev * saa = budget_av->budget.dev;
struct dvb_frontend * fe = NULL;
+ /* Enable / PowerON Frontend */
+ saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
+
+ /* additional setup necessary for the PLUS cards */
switch (saa->pci->subsystem_device) {
case SUBID_DVBS_KNC1_PLUS:
case SUBID_DVBC_KNC1_PLUS:
case SUBID_DVBT_KNC1_PLUS:
- // Enable / PowerON Frontend
- saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI);
break;
}
@@ -1030,12 +1096,19 @@ static void frontend_init(struct budget_av *budget_av)
switch (saa->pci->subsystem_device) {
case SUBID_DVBS_KNC1:
+ case SUBID_DVBS_EASYWATCH_1:
if (saa->pci->subsystem_vendor == 0x1894) {
fe = stv0299_attach(&cinergy_1200s_1894_0010_config,
&budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.set_params = philips_su1278sh2_tua6100_tuner_set_params;
+ }
} else {
fe = stv0299_attach(&typhoon_config,
&budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
+ }
}
break;
@@ -1045,41 +1118,53 @@ static void frontend_init(struct budget_av *budget_av)
case SUBID_DVBS_EASYWATCH:
fe = stv0299_attach(&philips_sd1878_config,
&budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.set_params = philips_sd1878_tda8261_tuner_set_params;
+ }
break;
case SUBID_DVBS_KNC1_PLUS:
case SUBID_DVBS_TYPHOON:
fe = stv0299_attach(&typhoon_config,
&budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
+ }
break;
case SUBID_DVBS_CINERGY1200:
fe = stv0299_attach(&cinergy_1200s_config,
&budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
+ }
break;
case SUBID_DVBC_KNC1:
case SUBID_DVBC_KNC1_PLUS:
+ case SUBID_DVBC_CINERGY1200:
+ budget_av->reinitialise_demod = 1;
fe = tda10021_attach(&philips_cu1216_config,
&budget_av->budget.i2c_adap,
read_pwm(budget_av));
+ if (fe) {
+ budget_av->tda10021_poclkp = 1;
+ budget_av->tda10021_set_frontend = fe->ops.set_frontend;
+ fe->ops.set_frontend = tda10021_set_frontend;
+ fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
+ }
break;
case SUBID_DVBT_KNC1:
case SUBID_DVBT_KNC1_PLUS:
- fe = tda10046_attach(&philips_tu1216_config,
- &budget_av->budget.i2c_adap);
- break;
-
- case SUBID_DVBC_CINERGY1200:
- fe = tda10021_attach(&philips_cu1216_config,
- &budget_av->budget.i2c_adap,
- read_pwm(budget_av));
- break;
-
case SUBID_DVBT_CINERGY1200:
+ budget_av->reinitialise_demod = 1;
fe = tda10046_attach(&philips_tu1216_config,
&budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.init = philips_tu1216_tuner_init;
+ fe->ops.tuner_ops.set_params = philips_tu1216_tuner_set_params;
+ }
break;
}
@@ -1098,8 +1183,8 @@ static void frontend_init(struct budget_av *budget_av)
if (dvb_register_frontend(&budget_av->budget.dvb_adapter,
budget_av->budget.dvb_frontend)) {
printk(KERN_ERR "budget-av: Frontend registration failed!\n");
- if (budget_av->budget.dvb_frontend->ops->release)
- budget_av->budget.dvb_frontend->ops->release(budget_av->budget.dvb_frontend);
+ if (budget_av->budget.dvb_frontend->ops.release)
+ budget_av->budget.dvb_frontend->ops.release(budget_av->budget.dvb_frontend);
budget_av->budget.dvb_frontend = NULL;
}
}
@@ -1293,6 +1378,7 @@ MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C);
MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
+MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S);
MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);
@@ -1309,6 +1395,7 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014),
MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
+ MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index e64a609..4b966ee 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -620,10 +620,10 @@ static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate,
return 0;
}
-static int philips_su1278_tt_pll_set(struct dvb_frontend *fe,
- struct i2c_adapter *i2c,
- struct dvb_frontend_parameters *params)
+static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
{
+ struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
u32 div;
u8 buf[4];
struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
@@ -649,7 +649,9 @@ static int philips_su1278_tt_pll_set(struct dvb_frontend *fe,
else if (params->frequency < 2150000)
buf[3] |= 0xC0;
- if (i2c_transfer(i2c, &msg, 1) != 1)
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
}
@@ -665,12 +667,11 @@ static struct stv0299_config philips_su1278_tt_config = {
.volt13_op0_op1 = STV0299_VOLT13_OP1,
.min_delay_ms = 50,
.set_symbol_rate = philips_su1278_tt_set_symbol_rate,
- .pll_set = philips_su1278_tt_pll_set,
};
-static int philips_tdm1316l_pll_init(struct dvb_frontend *fe)
+static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
{
struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
@@ -679,6 +680,8 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend *fe)
sizeof(td1316_init) };
// setup PLL configuration
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
msleep(1);
@@ -687,14 +690,18 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend *fe)
tuner_msg.addr = 0x65;
tuner_msg.buf = disable_mc44BC374c;
tuner_msg.len = sizeof(disable_mc44BC374c);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
}
return 0;
}
-static int philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
u8 tuner_buf[4];
@@ -770,6 +777,8 @@ static int philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend
tuner_buf[2] = 0xca;
tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
@@ -793,13 +802,10 @@ static struct tda1004x_config philips_tdm1316l_config = {
.xtal_freq = TDA10046_XTAL_4M,
.agc_config = TDA10046_AGC_DEFAULT,
.if_freq = TDA10046_FREQ_3617,
- .pll_init = philips_tdm1316l_pll_init,
- .pll_set = philips_tdm1316l_pll_set,
- .pll_sleep = NULL,
.request_firmware = philips_tdm1316l_request_firmware,
};
-static int dvbc_philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
u8 tuner_buf[5];
@@ -857,13 +863,15 @@ static int dvbc_philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_fro
tuner_buf[3] = (cp << 5) | (filter << 3) | band;
tuner_buf[4] = 0x80;
- stv0297_enable_plli2c(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
msleep(50);
- stv0297_enable_plli2c(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
@@ -969,7 +977,7 @@ static struct stv0297_config dvbc_philips_tdm1316l_config = {
.demod_address = 0x1c,
.inittab = dvbc_philips_tdm1316l_inittab,
.invert = 0,
- .pll_set = dvbc_philips_tdm1316l_pll_set,
+ .stop_during_read = 1,
};
@@ -982,6 +990,8 @@ static void frontend_init(struct budget_ci *budget_ci)
budget_ci->budget.dvb_frontend =
stv0299_attach(&alps_bsru6_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
break;
}
break;
@@ -990,6 +1000,7 @@ static void frontend_init(struct budget_ci *budget_ci)
budget_ci->budget.dvb_frontend =
stv0299_attach(&philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
break;
}
break;
@@ -999,6 +1010,7 @@ static void frontend_init(struct budget_ci *budget_ci)
budget_ci->budget.dvb_frontend =
stv0297_attach(&dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
break;
}
break;
@@ -1008,6 +1020,8 @@ static void frontend_init(struct budget_ci *budget_ci)
budget_ci->budget.dvb_frontend =
tda10045_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
break;
}
break;
@@ -1017,6 +1031,8 @@ static void frontend_init(struct budget_ci *budget_ci)
budget_ci->budget.dvb_frontend =
tda10046_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
break;
}
break;
@@ -1024,11 +1040,14 @@ static void frontend_init(struct budget_ci *budget_ci)
case 0x1017: // TT S-1500 PCI
budget_ci->budget.dvb_frontend = stv0299_attach(&alps_bsbe1_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
- budget_ci->budget.dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
- if (lnbp21_init(budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0)) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
+ budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
+
+ budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
+ if (lnbp21_attach(budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0)) {
printk("%s: No LNBP21 found!\n", __FUNCTION__);
- if (budget_ci->budget.dvb_frontend->ops->release)
- budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend);
+ if (budget_ci->budget.dvb_frontend->ops.release)
+ budget_ci->budget.dvb_frontend->ops.release(budget_ci->budget.dvb_frontend);
budget_ci->budget.dvb_frontend = NULL;
}
}
@@ -1046,8 +1065,8 @@ static void frontend_init(struct budget_ci *budget_ci)
if (dvb_register_frontend
(&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
printk("budget-ci: Frontend registration failed!\n");
- if (budget_ci->budget.dvb_frontend->ops->release)
- budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend);
+ if (budget_ci->budget.dvb_frontend->ops.release)
+ budget_ci->budget.dvb_frontend->ops.release(budget_ci->budget.dvb_frontend);
budget_ci->budget.dvb_frontend = NULL;
}
}
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c
index ea2066d..e4cf777 100644
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ b/drivers/media/dvb/ttpci/budget-core.c
@@ -400,7 +400,9 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
budget->dev->name, budget->buffer_width, budget->buffer_height);
printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size);
- dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner);
+ if ((ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner, &budget->dev->pci->dev)) < 0) {
+ return ret;
+ }
/* set dd1 stream a & b */
saa7146_write(dev, DD1_STREAM_B, 0x00000000);
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
index 1b3aaac..ee60ce9 100644
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/dvb/ttpci/budget-patch.c
@@ -258,7 +258,7 @@ static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_c
return 0;
}
-static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
u8 pwr = 0;
@@ -281,7 +281,10 @@ static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
// NOTE: since we're using a prescaler of 2, we set the
// divisor frequency to 62.5kHz and divide by 125 above
- if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
+ return -EIO;
return 0;
}
@@ -289,10 +292,9 @@ static struct ves1x93_config alps_bsrv2_config = {
.demod_address = 0x08,
.xin = 90100000UL,
.invert_pwm = 0,
- .pll_set = alps_bsrv2_pll_set,
};
-static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
u32 div;
@@ -305,13 +307,15 @@ static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_fronten
data[2] = 0x8e;
data[3] = 0x00;
- if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
+ return -EIO;
return 0;
}
static struct tda8083_config grundig_29504_451_config = {
.demod_address = 0x68,
- .pll_set = grundig_29504_451_pll_set,
};
static void frontend_init(struct budget_patch* budget)
@@ -323,27 +327,32 @@ static void frontend_init(struct budget_patch* budget)
// try the ALPS BSRV2 first of all
budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
- budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst;
- budget->dvb_frontend->ops->set_tone = budget_patch_set_tone;
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+ budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops.diseqc_send_burst = budget_patch_diseqc_send_burst;
+ budget->dvb_frontend->ops.set_tone = budget_patch_set_tone;
break;
}
// try the ALPS BSRU6 now
budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
- budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
- budget->dvb_frontend->ops->set_tone = budget_set_tone;
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+
+ budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+ budget->dvb_frontend->ops.set_tone = budget_set_tone;
break;
}
// Try the grundig 29504-451
budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
- budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
- budget->dvb_frontend->ops->set_tone = budget_set_tone;
+ budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+ budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+ budget->dvb_frontend->ops.set_tone = budget_set_tone;
break;
}
break;
@@ -358,8 +367,8 @@ static void frontend_init(struct budget_patch* budget)
} else {
if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) {
printk("budget-av: Frontend registration failed!\n");
- if (budget->dvb_frontend->ops->release)
- budget->dvb_frontend->ops->release(budget->dvb_frontend);
+ if (budget->dvb_frontend->ops.release)
+ budget->dvb_frontend->ops.release(budget->dvb_frontend);
budget->dvb_frontend = NULL;
}
}
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index c23c02d..35761f1 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -186,7 +186,7 @@ static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t m
return 0;
}
-static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget* budget = (struct budget*) fe->dvb->priv;
u8 pwr = 0;
@@ -209,6 +209,8 @@ static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
// NOTE: since we're using a prescaler of 2, we set the
// divisor frequency to 62.5kHz and divide by 125 above
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
return 0;
}
@@ -218,10 +220,9 @@ static struct ves1x93_config alps_bsrv2_config =
.demod_address = 0x08,
.xin = 90100000UL,
.invert_pwm = 0,
- .pll_set = alps_bsrv2_pll_set,
};
-static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget* budget = (struct budget*) fe->dvb->priv;
u32 div;
@@ -235,6 +236,8 @@ static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
data[2] = 0x85 | ((div >> 10) & 0x60);
data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
return 0;
}
@@ -244,10 +247,9 @@ static struct ves1820_config alps_tdbe2_config = {
.xin = 57840000UL,
.invert = 1,
.selagc = VES1820_SELAGC_SIGNAMPERR,
- .pll_set = alps_tdbe2_pll_set,
};
-static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget* budget = (struct budget*) fe->dvb->priv;
u32 div;
@@ -274,16 +276,17 @@ static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_fronten
data[2] = ((div >> 10) & 0x60) | cfg;
data[3] = (cpump << 6) | band_select;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
return 0;
}
static struct l64781_config grundig_29504_401_config = {
.demod_address = 0x55,
- .pll_set = grundig_29504_401_pll_set,
};
-static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget* budget = (struct budget*) fe->dvb->priv;
u32 div;
@@ -296,16 +299,17 @@ static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_fronten
data[2] = 0x8e;
data[3] = 0x00;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
return 0;
}
static struct tda8083_config grundig_29504_451_config = {
.demod_address = 0x68,
- .pll_set = grundig_29504_451_pll_set,
};
-static int s5h1420_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout)
+static int s5h1420_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget* budget = (struct budget*) fe->dvb->priv;
u32 div;
@@ -326,16 +330,16 @@ static int s5h1420_pll_set(struct dvb_frontend* fe, struct dvb_frontend_paramete
else
data[3] = 0xc0;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
- *freqout = div * 1000;
return 0;
}
static struct s5h1420_config s5h1420_config = {
.demod_address = 0x53,
.invert = 1,
- .pll_set = s5h1420_pll_set,
};
static u8 read_pwm(struct budget* budget)
@@ -359,18 +363,21 @@ static void frontend_init(struct budget *budget)
// try the ALPS BSRV2 first of all
budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
- budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
- budget->dvb_frontend->ops->set_tone = budget_set_tone;
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+ budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+ budget->dvb_frontend->ops.set_tone = budget_set_tone;
break;
}
// try the ALPS BSRU6 now
budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
- budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
- budget->dvb_frontend->ops->set_tone = budget_set_tone;
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+ budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+ budget->dvb_frontend->ops.set_tone = budget_set_tone;
break;
}
break;
@@ -378,35 +385,45 @@ static void frontend_init(struct budget *budget)
case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
budget->dvb_frontend = ves1820_attach(&alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));
- if (budget->dvb_frontend) break;
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+ break;
+ }
break;
case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060))
budget->dvb_frontend = l64781_attach(&grundig_29504_401_config, &budget->i2c_adap);
- if (budget->dvb_frontend) break;
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
+ break;
+ }
break;
case 0x4f60: // Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/ALPS BSRU6(tsa5059))
budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
- budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+ budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
+ budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
}
break;
case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522))
budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
- budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
+ budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+ budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
+ budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
}
break;
case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
budget->dvb_frontend = s5h1420_attach(&s5h1420_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- if (lnbp21_init(budget->dvb_frontend, &budget->i2c_adap, 0, 0)) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = s5h1420_tuner_set_params;
+ if (lnbp21_attach(budget->dvb_frontend, &budget->i2c_adap, 0, 0)) {
printk("%s: No LNBP21 found!\n", __FUNCTION__);
goto error_out;
}
@@ -428,8 +445,8 @@ static void frontend_init(struct budget *budget)
error_out:
printk("budget: Frontend registration failed!\n");
- if (budget->dvb_frontend->ops->release)
- budget->dvb_frontend->ops->release(budget->dvb_frontend);
+ if (budget->dvb_frontend->ops.release)
+ budget->dvb_frontend->ops.release(budget->dvb_frontend);
budget->dvb_frontend = NULL;
return;
}
diff --git a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig
index 914587d..92c7cdc 100644
--- a/drivers/media/dvb/ttusb-budget/Kconfig
+++ b/drivers/media/dvb/ttusb-budget/Kconfig
@@ -6,6 +6,8 @@ config DVB_TTUSB_BUDGET
select DVB_VES1820
select DVB_TDA8083
select DVB_STV0299
+ select DVB_STV0297
+ select DVB_LNBP21
help
Support for external USB adapters designed by Technotrend and
produced by Hauppauge, shipped under the brand name 'Nova-USB'.
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index 6ceae38..14559ef 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -30,6 +30,8 @@
#include "tda1004x.h"
#include "stv0299.h"
#include "tda8083.h"
+#include "stv0297.h"
+#include "lnbp21.h"
#include <linux/dvb/frontend.h>
#include <linux/dvb/dmx.h>
@@ -486,31 +488,6 @@ static int ttusb_send_diseqc(struct dvb_frontend* fe,
}
#endif
-static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
- struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
- int ret;
- u8 data[1];
- struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = data, .len = sizeof(data) };
-
- switch(voltage) {
- case SEC_VOLTAGE_OFF:
- data[0] = 0x00;
- break;
- case SEC_VOLTAGE_13:
- data[0] = 0x44;
- break;
- case SEC_VOLTAGE_18:
- data[0] = 0x4c;
- break;
- default:
- return -EINVAL;
- };
-
- ret = i2c_transfer(&ttusb->i2c_adap, &msg, 1);
- return (ret != 1) ? -EIO : 0;
-}
-
static int ttusb_update_lnb(struct ttusb *ttusb)
{
u8 b[] = { 0xaa, ++ttusb->c, 0x16, 5, /*power: */ 1,
@@ -1048,7 +1025,7 @@ static u32 functionality(struct i2c_adapter *adapter)
-static int alps_tdmb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdmb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
u8 data[4];
@@ -1062,20 +1039,21 @@ static int alps_tdmb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
data[2] = ((div >> 10) & 0x60) | 0x85;
data[3] = params->frequency < 592000000 ? 0x40 : 0x80;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) return -EIO;
return 0;
}
static struct cx22700_config alps_tdmb7_config = {
.demod_address = 0x43,
- .pll_set = alps_tdmb7_pll_set,
};
-static int philips_tdm1316l_pll_init(struct dvb_frontend* fe)
+static int philips_tdm1316l_tuner_init(struct dvb_frontend* fe)
{
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
@@ -1083,6 +1061,8 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend* fe)
struct i2c_msg tuner_msg = { .addr=0x60, .flags=0, .buf=td1316_init, .len=sizeof(td1316_init) };
// setup PLL configuration
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO;
msleep(1);
@@ -1090,6 +1070,8 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend* fe)
tuner_msg.addr = 0x65;
tuner_msg.buf = disable_mc44BC374c;
tuner_msg.len = sizeof(disable_mc44BC374c);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1);
}
@@ -1097,7 +1079,7 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend* fe)
return 0;
}
-static int philips_tdm1316l_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
u8 tuner_buf[4];
@@ -1157,6 +1139,8 @@ static int philips_tdm1316l_pll_set(struct dvb_frontend* fe, struct dvb_frontend
tuner_buf[2] = 0xca;
tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
@@ -1176,8 +1160,6 @@ static struct tda1004x_config philips_tdm1316l_config = {
.demod_address = 0x8,
.invert = 1,
.invert_oclk = 0,
- .pll_init = philips_tdm1316l_pll_init,
- .pll_set = philips_tdm1316l_pll_set,
.request_firmware = philips_tdm1316l_request_firmware,
};
@@ -1299,7 +1281,7 @@ static int alps_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32
return 0;
}
-static int philips_tsa5059_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params)
+static int philips_tsa5059_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
u8 buf[4];
@@ -1322,7 +1304,9 @@ static int philips_tsa5059_pll_set(struct dvb_frontend *fe, struct i2c_adapter *
if (ttusb->revision == TTUSB_REV_2_2)
buf[3] |= 0x20;
- if (i2c_transfer(i2c, &msg, 1) != 1)
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
@@ -1338,10 +1322,9 @@ static struct stv0299_config alps_stv0299_config = {
.volt13_op0_op1 = STV0299_VOLT13_OP1,
.min_delay_ms = 100,
.set_symbol_rate = alps_stv0299_set_symbol_rate,
- .pll_set = philips_tsa5059_pll_set,
};
-static int ttusb_novas_grundig_29504_491_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int ttusb_novas_grundig_29504_491_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
u8 buf[4];
@@ -1355,6 +1338,8 @@ static int ttusb_novas_grundig_29504_491_pll_set(struct dvb_frontend *fe, struct
buf[2] = 0x8e;
buf[3] = 0x00;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1)
return -EIO;
@@ -1364,10 +1349,9 @@ static int ttusb_novas_grundig_29504_491_pll_set(struct dvb_frontend *fe, struct
static struct tda8083_config ttusb_novas_grundig_29504_491_config = {
.demod_address = 0x68,
- .pll_set = ttusb_novas_grundig_29504_491_pll_set,
};
-static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct ttusb* ttusb = fe->dvb->priv;
u32 div;
@@ -1381,6 +1365,8 @@ static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
data[2] = 0x85 | ((div >> 10) & 0x60);
data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&ttusb->i2c_adap, &msg, 1) != 1)
return -EIO;
@@ -1393,7 +1379,6 @@ static struct ves1820_config alps_tdbe2_config = {
.xin = 57840000UL,
.invert = 1,
.selagc = VES1820_SELAGC_SIGNAMPERR,
- .pll_set = alps_tdbe2_pll_set,
};
static u8 read_pwm(struct ttusb* ttusb)
@@ -1410,6 +1395,174 @@ static u8 read_pwm(struct ttusb* ttusb)
}
+static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct ttusb *ttusb = (struct ttusb *) fe->dvb->priv;
+ u8 tuner_buf[5];
+ struct i2c_msg tuner_msg = {.addr = 0x60,
+ .flags = 0,
+ .buf = tuner_buf,
+ .len = sizeof(tuner_buf) };
+ int tuner_frequency = 0;
+ u8 band, cp, filter;
+
+ // determine charge pump
+ tuner_frequency = params->frequency;
+ if (tuner_frequency < 87000000) {return -EINVAL;}
+ else if (tuner_frequency < 130000000) {cp = 3; band = 1;}
+ else if (tuner_frequency < 160000000) {cp = 5; band = 1;}
+ else if (tuner_frequency < 200000000) {cp = 6; band = 1;}
+ else if (tuner_frequency < 290000000) {cp = 3; band = 2;}
+ else if (tuner_frequency < 420000000) {cp = 5; band = 2;}
+ else if (tuner_frequency < 480000000) {cp = 6; band = 2;}
+ else if (tuner_frequency < 620000000) {cp = 3; band = 4;}
+ else if (tuner_frequency < 830000000) {cp = 5; band = 4;}
+ else if (tuner_frequency < 895000000) {cp = 7; band = 4;}
+ else {return -EINVAL;}
+
+ // assume PLL filter should always be 8MHz for the moment.
+ filter = 1;
+
+ // calculate divisor
+ // (Finput + Fif)/Fref; Fif = 36125000 Hz, Fref = 62500 Hz
+ tuner_frequency = ((params->frequency + 36125000) / 62500);
+
+ // setup tuner buffer
+ tuner_buf[0] = tuner_frequency >> 8;
+ tuner_buf[1] = tuner_frequency & 0xff;
+ tuner_buf[2] = 0xc8;
+ tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+ tuner_buf[4] = 0x80;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
+ printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 1\n");
+ return -EIO;
+ }
+
+ msleep(50);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
+ printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 2\n");
+ return -EIO;
+ }
+
+ msleep(1);
+
+ return 0;
+}
+
+static u8 dvbc_philips_tdm1316l_inittab[] = {
+ 0x80, 0x21,
+ 0x80, 0x20,
+ 0x81, 0x01,
+ 0x81, 0x00,
+ 0x00, 0x09,
+ 0x01, 0x69,
+ 0x03, 0x00,
+ 0x04, 0x00,
+ 0x07, 0x00,
+ 0x08, 0x00,
+ 0x20, 0x00,
+ 0x21, 0x40,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x24, 0x40,
+ 0x25, 0x88,
+ 0x30, 0xff,
+ 0x31, 0x00,
+ 0x32, 0xff,
+ 0x33, 0x00,
+ 0x34, 0x50,
+ 0x35, 0x7f,
+ 0x36, 0x00,
+ 0x37, 0x20,
+ 0x38, 0x00,
+ 0x40, 0x1c,
+ 0x41, 0xff,
+ 0x42, 0x29,
+ 0x43, 0x20,
+ 0x44, 0xff,
+ 0x45, 0x00,
+ 0x46, 0x00,
+ 0x49, 0x04,
+ 0x4a, 0xff,
+ 0x4b, 0x7f,
+ 0x52, 0x30,
+ 0x55, 0xae,
+ 0x56, 0x47,
+ 0x57, 0xe1,
+ 0x58, 0x3a,
+ 0x5a, 0x1e,
+ 0x5b, 0x34,
+ 0x60, 0x00,
+ 0x63, 0x00,
+ 0x64, 0x00,
+ 0x65, 0x00,
+ 0x66, 0x00,
+ 0x67, 0x00,
+ 0x68, 0x00,
+ 0x69, 0x00,
+ 0x6a, 0x02,
+ 0x6b, 0x00,
+ 0x70, 0xff,
+ 0x71, 0x00,
+ 0x72, 0x00,
+ 0x73, 0x00,
+ 0x74, 0x0c,
+ 0x80, 0x00,
+ 0x81, 0x00,
+ 0x82, 0x00,
+ 0x83, 0x00,
+ 0x84, 0x04,
+ 0x85, 0x80,
+ 0x86, 0x24,
+ 0x87, 0x78,
+ 0x88, 0x00,
+ 0x89, 0x00,
+ 0x90, 0x01,
+ 0x91, 0x01,
+ 0xa0, 0x00,
+ 0xa1, 0x00,
+ 0xa2, 0x00,
+ 0xb0, 0x91,
+ 0xb1, 0x0b,
+ 0xc0, 0x4b,
+ 0xc1, 0x00,
+ 0xc2, 0x00,
+ 0xd0, 0x00,
+ 0xd1, 0x00,
+ 0xd2, 0x00,
+ 0xd3, 0x00,
+ 0xd4, 0x00,
+ 0xd5, 0x00,
+ 0xde, 0x00,
+ 0xdf, 0x00,
+ 0x61, 0x38,
+ 0x62, 0x0a,
+ 0x53, 0x13,
+ 0x59, 0x08,
+ 0x55, 0x00,
+ 0x56, 0x40,
+ 0x57, 0x08,
+ 0x58, 0x3d,
+ 0x88, 0x10,
+ 0xa0, 0x00,
+ 0xa0, 0x00,
+ 0xa0, 0x00,
+ 0xa0, 0x04,
+ 0xff, 0xff,
+};
+
+static struct stv0297_config dvbc_philips_tdm1316l_config = {
+ .demod_address = 0x1c,
+ .inittab = dvbc_philips_tdm1316l_inittab,
+ .invert = 0,
+};
+
static void frontend_init(struct ttusb* ttusb)
{
switch(le16_to_cpu(ttusb->dev->descriptor.idProduct)) {
@@ -1417,11 +1570,13 @@ static void frontend_init(struct ttusb* ttusb)
// try the stv0299 based first
ttusb->fe = stv0299_attach(&alps_stv0299_config, &ttusb->i2c_adap);
if (ttusb->fe != NULL) {
+ ttusb->fe->ops.tuner_ops.set_params = philips_tsa5059_tuner_set_params;
+
if(ttusb->revision == TTUSB_REV_2_2) { // ALPS BSBE1
alps_stv0299_config.inittab = alps_bsbe1_inittab;
- ttusb->fe->ops->set_voltage = lnbp21_set_voltage;
+ lnbp21_attach(ttusb->fe, &ttusb->i2c_adap, 0, 0);
} else { // ALPS BSRU6
- ttusb->fe->ops->set_voltage = ttusb_set_voltage;
+ ttusb->fe->ops.set_voltage = ttusb_set_voltage;
}
break;
}
@@ -1429,28 +1584,41 @@ static void frontend_init(struct ttusb* ttusb)
// Grundig 29504-491
ttusb->fe = tda8083_attach(&ttusb_novas_grundig_29504_491_config, &ttusb->i2c_adap);
if (ttusb->fe != NULL) {
- ttusb->fe->ops->set_voltage = ttusb_set_voltage;
+ ttusb->fe->ops.tuner_ops.set_params = ttusb_novas_grundig_29504_491_tuner_set_params;
+ ttusb->fe->ops.set_voltage = ttusb_set_voltage;
break;
}
-
break;
case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
ttusb->fe = ves1820_attach(&alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb));
- if (ttusb->fe != NULL)
+ if (ttusb->fe != NULL) {
+ ttusb->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+ break;
+ }
+
+ ttusb->fe = stv0297_attach(&dvbc_philips_tdm1316l_config, &ttusb->i2c_adap);
+ if (ttusb->fe != NULL) {
+ ttusb->fe->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
break;
+ }
break;
case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??))
// try the ALPS TDMB7 first
ttusb->fe = cx22700_attach(&alps_tdmb7_config, &ttusb->i2c_adap);
- if (ttusb->fe != NULL)
+ if (ttusb->fe != NULL) {
+ ttusb->fe->ops.tuner_ops.set_params = alps_tdmb7_tuner_set_params;
break;
+ }
// Philips td1316
ttusb->fe = tda10046_attach(&philips_tdm1316l_config, &ttusb->i2c_adap);
- if (ttusb->fe != NULL)
+ if (ttusb->fe != NULL) {
+ ttusb->fe->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
+ ttusb->fe->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
break;
+ }
break;
}
@@ -1461,8 +1629,8 @@ static void frontend_init(struct ttusb* ttusb)
} else {
if (dvb_register_frontend(&ttusb->adapter, ttusb->fe)) {
printk("dvb-ttusb-budget: Frontend registration failed!\n");
- if (ttusb->fe->ops->release)
- ttusb->fe->ops->release(ttusb->fe);
+ if (ttusb->fe->ops.release)
+ ttusb->fe->ops.release(ttusb->fe);
ttusb->fe = NULL;
}
}
@@ -1507,7 +1675,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
mutex_unlock(&ttusb->semi2c);
- if ((result = dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE)) < 0) {
+ if ((result = dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE, &udev->dev)) < 0) {
ttusb_free_iso_urbs(ttusb);
kfree(ttusb);
return result;
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index 44dea32..6c1cb77 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -1432,7 +1432,7 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec)
dprintk("%s\n", __FUNCTION__);
if ((result = dvb_register_adapter(&dec->adapter,
- dec->model_name, THIS_MODULE)) < 0) {
+ dec->model_name, THIS_MODULE, &dec->udev->dev)) < 0) {
printk("%s: dvb_register_adapter failed: error %d\n",
__FUNCTION__, result);
@@ -1657,8 +1657,8 @@ static int ttusb_dec_probe(struct usb_interface *intf,
} else {
if (dvb_register_frontend(&dec->adapter, dec->fe)) {
printk("budget-ci: Frontend registration failed!\n");
- if (dec->fe->ops->release)
- dec->fe->ops->release(dec->fe);
+ if (dec->fe->ops.release)
+ dec->fe->ops.release(dec->fe);
dec->fe = NULL;
}
}
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
index a5a4617..42f39a8 100644
--- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
+++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
@@ -28,8 +28,6 @@
struct ttusbdecfe_state {
- struct dvb_frontend_ops ops;
-
/* configuration settings */
const struct ttusbdecfe_config* config;
@@ -203,10 +201,9 @@ struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* conf
/* setup the state */
state->config = config;
- memcpy(&state->ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops));
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
}
@@ -226,10 +223,9 @@ struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* conf
state->config = config;
state->voltage = 0;
state->hi_band = 0;
- memcpy(&state->ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops));
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
}
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 3fff757..de3128a 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -136,7 +136,7 @@ config RADIO_GEMTEK_PCI
Choose Y here if you have this PCI FM radio card.
In order to control your radio card, you will need to use programs
- that are compatible with the Video for Linux API. Information on
+ that are compatible with the Video for Linux API. Information on
this API and pointers to "v4l" programs may be found at
<file:Documentation/video4linux/API.html>.
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index 8b35194..e95b680 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -20,3 +20,5 @@ obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
+
+EXTRA_CFLAGS += -Isound
diff --git a/drivers/media/radio/miropcm20-radio.c b/drivers/media/radio/miropcm20-radio.c
index dc292da..c4312fa 100644
--- a/drivers/media/radio/miropcm20-radio.c
+++ b/drivers/media/radio/miropcm20-radio.c
@@ -16,13 +16,14 @@
/* What ever you think about the ACI, version 0x07 is not very well!
* I can't get frequency, 'tuner status', 'tuner flags' or mute/mono
- * conditions... Robert
+ * conditions... Robert
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/videodev.h>
-#include "../../../sound/oss/aci.h"
+#include <media/v4l2-common.h>
+#include "oss/aci.h"
#include "miropcm20-rds-core.h"
static int radio_nr = -1;
@@ -123,7 +124,7 @@ static int pcm20_do_ioctl(struct inode *inode, struct file *file,
struct video_device *dev = video_devdata(file);
struct pcm20_device *pcm20 = dev->priv;
int i;
-
+
switch(cmd)
{
case VIDIOCGCAP:
@@ -139,7 +140,7 @@ static int pcm20_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if(v->tuner) /* Only 1 tuner */
return -EINVAL;
v->rangelow=87*16000;
v->rangehigh=108*16000;
@@ -172,7 +173,7 @@ static int pcm20_do_ioctl(struct inode *inode, struct file *file,
return i;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags=VIDEO_AUDIO_MUTABLE;
@@ -183,12 +184,12 @@ static int pcm20_do_ioctl(struct inode *inode, struct file *file,
v->mode|=VIDEO_SOUND_MONO;
/* v->step=2048; */
strcpy(v->name, "Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
pcm20_mute(pcm20, !!(v->flags&VIDEO_AUDIO_MUTE));
@@ -237,7 +238,7 @@ static int __init pcm20_init(void)
{
if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO, radio_nr)==-1)
goto video_register_device;
-
+
if(attach_aci_rds()<0)
goto attach_aci_rds;
diff --git a/drivers/media/radio/miropcm20-rds-core.c b/drivers/media/radio/miropcm20-rds-core.c
index b602c73..9428d8b 100644
--- a/drivers/media/radio/miropcm20-rds-core.c
+++ b/drivers/media/radio/miropcm20-rds-core.c
@@ -21,7 +21,7 @@
#include <linux/mutex.h>
#include <asm/io.h>
-#include "../../../sound/oss/aci.h"
+#include "oss/aci.h"
#include "miropcm20-rds-core.h"
#define DEBUG 0
@@ -33,24 +33,24 @@ static struct mutex aci_rds_mutex;
#define RDS_BUSYMASK 0x10 /* Bit 4 */
#define RDS_CLOCKMASK 0x08 /* Bit 3 */
-#define RDS_DATA(x) (((x) >> RDS_DATASHIFT) & 1)
+#define RDS_DATA(x) (((x) >> RDS_DATASHIFT) & 1)
#if DEBUG
static void print_matrix(char array[], unsigned int length)
{
- int i, j;
-
- for (i=0; i<length; i++) {
- printk(KERN_DEBUG "aci-rds: ");
- for (j=7; j>=0; j--) {
- printk("%d", (array[i] >> j) & 0x1);
- }
- if (i%8 == 0)
- printk(" byte-border\n");
- else
- printk("\n");
- }
+ int i, j;
+
+ for (i=0; i<length; i++) {
+ printk(KERN_DEBUG "aci-rds: ");
+ for (j=7; j>=0; j--) {
+ printk("%d", (array[i] >> j) & 0x1);
+ }
+ if (i%8 == 0)
+ printk(" byte-border\n");
+ else
+ printk("\n");
+ }
}
#endif /* DEBUG */
@@ -114,7 +114,7 @@ static int rds_write(unsigned char cmd)
{
unsigned char sendbuffer[8];
int i;
-
+
if (byte2trans(cmd, sendbuffer, 8) != 0){
return -1;
} else {
@@ -151,7 +151,7 @@ static int rds_read(unsigned char databuffer[], int datasize)
I have to waitread() here */
if (rds_waitread() < 0)
return -1;
-
+
memset(databuffer, 0, datasize);
for (i=0; i< READSIZE; i++)
@@ -194,7 +194,7 @@ int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize)
ret = 0;
mutex_unlock(&aci_rds_mutex);
-
+
return ret;
}
EXPORT_SYMBOL(aci_rds_cmd);
diff --git a/drivers/media/radio/miropcm20-rds.c b/drivers/media/radio/miropcm20-rds.c
index e092140..87b37b7 100644
--- a/drivers/media/radio/miropcm20-rds.c
+++ b/drivers/media/radio/miropcm20-rds.c
@@ -48,7 +48,7 @@ static int rds_f_release(struct inode *in, struct file *fi)
static void print_matrix(char *ch, char out[])
{
- int j;
+ int j;
for (j=7; j>=0; j--) {
out[7-j] = ((*ch >> j) & 0x1) + '0';
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 557fb5c..df22a58 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -24,7 +24,7 @@
* out(port, start_increasing_volume);
* wait(a_wee_while);
* out(port, stop_changing_the_volume);
- *
+ *
*/
#include <linux/module.h> /* Modules */
@@ -34,6 +34,7 @@
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_RTRACK_PORT */
#include <asm/semaphore.h> /* Lock for the I/O */
@@ -41,7 +42,7 @@
#define CONFIG_RADIO_RTRACK_PORT -1
#endif
-static int io = CONFIG_RADIO_RTRACK_PORT;
+static int io = CONFIG_RADIO_RTRACK_PORT;
static int radio_nr = -1;
static struct mutex lock;
@@ -93,12 +94,12 @@ static int rt_setvol(struct rt_device *dev, int vol)
int i;
mutex_lock(&lock);
-
+
if(vol == dev->curvol) { /* requested volume = current */
if (dev->muted) { /* user is unmuting the card */
dev->muted = 0;
outb (0xd8, io); /* enable card */
- }
+ }
mutex_unlock(&lock);
return 0;
}
@@ -114,10 +115,10 @@ static int rt_setvol(struct rt_device *dev, int vol)
dev->muted = 0;
if(vol > dev->curvol)
- for(i = dev->curvol; i < vol; i++)
+ for(i = dev->curvol; i < vol; i++)
rt_incvol();
else
- for(i = dev->curvol; i > vol; i--)
+ for(i = dev->curvol; i > vol; i--)
rt_decvol();
dev->curvol = vol;
@@ -125,7 +126,7 @@ static int rt_setvol(struct rt_device *dev, int vol)
return 0;
}
-/* the 128+64 on these outb's is to keep the volume stable while tuning
+/* the 128+64 on these outb's is to keep the volume stable while tuning
* without them, the volume _will_ creep up with each frequency change
* and bit 4 (+16) is to keep the signal strength meter enabled
*/
@@ -140,7 +141,7 @@ static void send_0_byte(int port, struct rt_device *dev)
outb_p(128+64+16+8+ 1, port); /* on + wr-enable + data low */
outb_p(128+64+16+8+2+1, port); /* clock */
}
- sleep_delay(1000);
+ sleep_delay(1000);
}
static void send_1_byte(int port, struct rt_device *dev)
@@ -148,13 +149,13 @@ static void send_1_byte(int port, struct rt_device *dev)
if ((dev->curvol == 0) || (dev->muted)) {
outb_p(128+64+16+4 +1, port); /* wr-enable+data high */
outb_p(128+64+16+4+2+1, port); /* clock */
- }
+ }
else {
outb_p(128+64+16+8+4 +1, port); /* on+wr-enable+data high */
outb_p(128+64+16+8+4+2+1, port); /* clock */
}
- sleep_delay(1000);
+ sleep_delay(1000);
}
static int rt_setfreq(struct rt_device *dev, unsigned long freq)
@@ -167,9 +168,9 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
freq += 171200; /* Add 10.7 MHz IF */
freq /= 800; /* Convert to 50 kHz units */
-
+
mutex_lock(&lock); /* Stop other ops interfering */
-
+
send_0_byte (io, dev); /* 0: LSB of frequency */
for (i = 0; i < 13; i++) /* : frequency bits (1-13) */
@@ -195,7 +196,7 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
outb (0xd0, io); /* volume steady + sigstr */
else
outb (0xd8, io); /* volume steady + sigstr + on */
-
+
mutex_unlock(&lock);
return 0;
@@ -213,7 +214,7 @@ static int rt_do_ioctl(struct inode *inode, struct file *file,
{
struct video_device *dev = video_devdata(file);
struct rt_device *rt=dev->priv;
-
+
switch(cmd)
{
case VIDIOCGCAP:
@@ -229,7 +230,7 @@ static int rt_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if(v->tuner) /* Only 1 tuner */
return -EINVAL;
v->rangelow=(87*16000);
v->rangehigh=(108*16000);
@@ -261,21 +262,21 @@ static int rt_do_ioctl(struct inode *inode, struct file *file,
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
v->volume=rt->curvol * 6554;
v->step=6554;
strcpy(v->name, "Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
- if(v->flags&VIDEO_AUDIO_MUTE)
+ if(v->flags&VIDEO_AUDIO_MUTE)
rt_mute(rt);
else
rt_setvol(rt,v->volume/6554);
@@ -298,7 +299,7 @@ static struct file_operations rtrack_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
- .ioctl = rt_ioctl,
+ .ioctl = rt_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
@@ -320,14 +321,14 @@ static int __init rtrack_init(void)
return -EINVAL;
}
- if (!request_region(io, 2, "rtrack"))
+ if (!request_region(io, 2, "rtrack"))
{
printk(KERN_ERR "rtrack: port 0x%x already in use\n", io);
return -EBUSY;
}
rtrack_radio.priv=&rtrack_unit;
-
+
if(video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr)==-1)
{
release_region(io, 2);
@@ -336,10 +337,10 @@ static int __init rtrack_init(void)
printk(KERN_INFO "AIMSlab RadioTrack/RadioReveal card driver.\n");
/* Set up the I/O locking */
-
+
mutex_init(&lock);
-
- /* mute card - prevents noisy bootups */
+
+ /* mute card - prevents noisy bootups */
/* this ensures that the volume is all the way down */
outb(0x48, io); /* volume down but still "on" */
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 83bdae2..95e6322 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -1,11 +1,11 @@
-/* radio-aztech.c - Aztech radio card driver for Linux 2.2
+/* radio-aztech.c - Aztech radio card driver for Linux 2.2
*
- * Adapted to support the Video for Linux API by
+ * Adapted to support the Video for Linux API by
* Russell Kroll <rkroll@exploits.org>. Based on original tuner code by:
*
* Quay Ly
* Donald Song
- * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
+ * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
* Scott McGrath (smcgrath@twilight.vtc.vsc.edu)
* William McGrath (wmcgrath@twilight.vtc.vsc.edu)
*
@@ -31,6 +31,7 @@
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_AZTECH_PORT */
/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
@@ -39,7 +40,7 @@
#define CONFIG_RADIO_AZTECH_PORT -1
#endif
-static int io = CONFIG_RADIO_AZTECH_PORT;
+static int io = CONFIG_RADIO_AZTECH_PORT;
static int radio_nr = -1;
static int radio_wait_time = 1000;
static struct mutex lock;
@@ -53,15 +54,15 @@ struct az_device
static int volconvert(int level)
{
- level>>=14; /* Map 16bits down to 2 bit */
- level&=3;
-
+ level>>=14; /* Map 16bits down to 2 bit */
+ level&=3;
+
/* convert to card-friendly values */
- switch (level)
+ switch (level)
{
- case 0:
+ case 0:
return 0;
- case 1:
+ case 1:
return 1;
case 2:
return 4;
@@ -121,9 +122,9 @@ static int az_setfreq(struct az_device *dev, unsigned long frequency)
frequency += 171200; /* Add 10.7 MHz IF */
frequency /= 800; /* Convert to 50 kHz units */
-
+
mutex_lock(&lock);
-
+
send_0_byte (dev); /* 0: LSB of frequency */
for (i = 0; i < 13; i++) /* : frequency bits (1-13) */
@@ -151,7 +152,7 @@ static int az_setfreq(struct az_device *dev, unsigned long frequency)
udelay (radio_wait_time);
outb_p(128+64+volconvert(dev->curvol), io);
-
+
mutex_unlock(&lock);
return 0;
@@ -162,7 +163,7 @@ static int az_do_ioctl(struct inode *inode, struct file *file,
{
struct video_device *dev = video_devdata(file);
struct az_device *az = dev->priv;
-
+
switch(cmd)
{
case VIDIOCGCAP:
@@ -178,7 +179,7 @@ static int az_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if(v->tuner) /* Only 1 tuner */
return -EINVAL;
v->rangelow=(87*16000);
v->rangehigh=(108*16000);
@@ -211,7 +212,7 @@ static int az_do_ioctl(struct inode *inode, struct file *file,
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
@@ -222,17 +223,17 @@ static int az_do_ioctl(struct inode *inode, struct file *file,
v->volume=az->curvol;
v->step=16384;
strcpy(v->name, "Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
az->curvol=v->volume;
az->stereo=(v->mode&VIDEO_SOUND_STEREO)?1:0;
- if(v->flags&VIDEO_AUDIO_MUTE)
+ if(v->flags&VIDEO_AUDIO_MUTE)
az_setvol(az,0);
else
az_setvol(az,az->curvol);
@@ -277,7 +278,7 @@ static int __init aztech_init(void)
return -EINVAL;
}
- if (!request_region(io, 2, "aztech"))
+ if (!request_region(io, 2, "aztech"))
{
printk(KERN_ERR "aztech: port 0x%x already in use\n", io);
return -EBUSY;
@@ -285,13 +286,13 @@ static int __init aztech_init(void)
mutex_init(&lock);
aztech_radio.priv=&aztech_unit;
-
+
if(video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr)==-1)
{
release_region(io,2);
return -EINVAL;
}
-
+
printk(KERN_INFO "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n");
/* mute card - prevents noisy bootups */
outb (0, io);
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index f1b5ac8..8641aec 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -8,7 +8,7 @@
* Russell Kroll (rkroll@exploits.org)
* Quay Ly
* Donald Song
- * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
+ * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
* Scott McGrath (smcgrath@twilight.vtc.vsc.edu)
* William McGrath (wmcgrath@twilight.vtc.vsc.edu)
*
@@ -34,6 +34,7 @@
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/param.h>
#include <linux/pnp.h>
@@ -55,29 +56,29 @@ static int cadet_probe(void);
/*
* Signal Strength Threshold Values
- * The V4L API spec does not define any particular unit for the signal
+ * The V4L API spec does not define any particular unit for the signal
* strength value. These values are in microvolts of RF at the tuner's input.
*/
static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}};
static int cadet_getrds(void)
{
- int rdsstat=0;
+ int rdsstat=0;
spin_lock(&cadet_io_lock);
- outb(3,io); /* Select Decoder Control/Status */
+ outb(3,io); /* Select Decoder Control/Status */
outb(inb(io+1)&0x7f,io+1); /* Reset RDS detection */
spin_unlock(&cadet_io_lock);
-
+
msleep(100);
- spin_lock(&cadet_io_lock);
- outb(3,io); /* Select Decoder Control/Status */
+ spin_lock(&cadet_io_lock);
+ outb(3,io); /* Select Decoder Control/Status */
if((inb(io+1)&0x80)!=0) {
- rdsstat|=VIDEO_TUNER_RDS_ON;
+ rdsstat|=VIDEO_TUNER_RDS_ON;
}
if((inb(io+1)&0x10)!=0) {
- rdsstat|=VIDEO_TUNER_MBS_ON;
+ rdsstat|=VIDEO_TUNER_MBS_ON;
}
spin_unlock(&cadet_io_lock);
return rdsstat;
@@ -86,49 +87,49 @@ static int cadet_getrds(void)
static int cadet_getstereo(void)
{
int ret = 0;
- if(curtuner != 0) /* Only FM has stereo capability! */
- return 0;
+ if(curtuner != 0) /* Only FM has stereo capability! */
+ return 0;
spin_lock(&cadet_io_lock);
- outb(7,io); /* Select tuner control */
+ outb(7,io); /* Select tuner control */
if( (inb(io+1) & 0x40) == 0)
- ret = 1;
- spin_unlock(&cadet_io_lock);
- return ret;
+ ret = 1;
+ spin_unlock(&cadet_io_lock);
+ return ret;
}
static unsigned cadet_gettune(void)
{
- int curvol,i;
+ int curvol,i;
unsigned fifo=0;
- /*
- * Prepare for read
- */
+ /*
+ * Prepare for read
+ */
spin_lock(&cadet_io_lock);
-
- outb(7,io); /* Select tuner control */
- curvol=inb(io+1); /* Save current volume/mute setting */
- outb(0x00,io+1); /* Ensure WRITE-ENABLE is LOW */
+
+ outb(7,io); /* Select tuner control */
+ curvol=inb(io+1); /* Save current volume/mute setting */
+ outb(0x00,io+1); /* Ensure WRITE-ENABLE is LOW */
tunestat=0xffff;
- /*
- * Read the shift register
- */
- for(i=0;i<25;i++) {
- fifo=(fifo<<1)|((inb(io+1)>>7)&0x01);
- if(i<24) {
- outb(0x01,io+1);
+ /*
+ * Read the shift register
+ */
+ for(i=0;i<25;i++) {
+ fifo=(fifo<<1)|((inb(io+1)>>7)&0x01);
+ if(i<24) {
+ outb(0x01,io+1);
tunestat&=inb(io+1);
- outb(0x00,io+1);
- }
- }
-
- /*
- * Restore volume/mute setting
- */
- outb(curvol,io+1);
+ outb(0x00,io+1);
+ }
+ }
+
+ /*
+ * Restore volume/mute setting
+ */
+ outb(curvol,io+1);
spin_unlock(&cadet_io_lock);
return fifo;
@@ -136,43 +137,43 @@ static unsigned cadet_gettune(void)
static unsigned cadet_getfreq(void)
{
- int i;
- unsigned freq=0,test,fifo=0;
+ int i;
+ unsigned freq=0,test,fifo=0;
/*
* Read current tuning
*/
fifo=cadet_gettune();
- /*
- * Convert to actual frequency
- */
+ /*
+ * Convert to actual frequency
+ */
if(curtuner==0) { /* FM */
- test=12500;
- for(i=0;i<14;i++) {
- if((fifo&0x01)!=0) {
- freq+=test;
- }
- test=test<<1;
- fifo=fifo>>1;
- }
- freq-=10700000; /* IF frequency is 10.7 MHz */
- freq=(freq*16)/1000000; /* Make it 1/16 MHz */
+ test=12500;
+ for(i=0;i<14;i++) {
+ if((fifo&0x01)!=0) {
+ freq+=test;
+ }
+ test=test<<1;
+ fifo=fifo>>1;
+ }
+ freq-=10700000; /* IF frequency is 10.7 MHz */
+ freq=(freq*16)/1000000; /* Make it 1/16 MHz */
}
if(curtuner==1) { /* AM */
- freq=((fifo&0x7fff)-2010)*16;
+ freq=((fifo&0x7fff)-2010)*16;
}
- return freq;
+ return freq;
}
static void cadet_settune(unsigned fifo)
{
- int i;
- unsigned test;
+ int i;
+ unsigned test;
spin_lock(&cadet_io_lock);
-
+
outb(7,io); /* Select tuner control */
/*
* Write the shift register
@@ -183,7 +184,7 @@ static void cadet_settune(unsigned fifo)
outb(7,io); /* Select tuner control */
outb(test,io+1); /* Initialize for write */
for(i=0;i<25;i++) {
- test|=0x01; /* Toggle SCK High */
+ test|=0x01; /* Toggle SCK High */
outb(test,io+1);
test&=0xfe; /* Toggle SCK Low */
outb(test,io+1);
@@ -196,57 +197,57 @@ static void cadet_settune(unsigned fifo)
static void cadet_setfreq(unsigned freq)
{
- unsigned fifo;
- int i,j,test;
- int curvol;
+ unsigned fifo;
+ int i,j,test;
+ int curvol;
- /*
- * Formulate a fifo command
- */
+ /*
+ * Formulate a fifo command
+ */
fifo=0;
if(curtuner==0) { /* FM */
- test=102400;
- freq=(freq*1000)/16; /* Make it kHz */
- freq+=10700; /* IF is 10700 kHz */
- for(i=0;i<14;i++) {
- fifo=fifo<<1;
- if(freq>=test) {
- fifo|=0x01;
- freq-=test;
- }
- test=test>>1;
- }
+ test=102400;
+ freq=(freq*1000)/16; /* Make it kHz */
+ freq+=10700; /* IF is 10700 kHz */
+ for(i=0;i<14;i++) {
+ fifo=fifo<<1;
+ if(freq>=test) {
+ fifo|=0x01;
+ freq-=test;
+ }
+ test=test>>1;
+ }
}
if(curtuner==1) { /* AM */
- fifo=(freq/16)+2010; /* Make it kHz */
+ fifo=(freq/16)+2010; /* Make it kHz */
fifo|=0x100000; /* Select AM Band */
}
- /*
- * Save current volume/mute setting
- */
+ /*
+ * Save current volume/mute setting
+ */
spin_lock(&cadet_io_lock);
outb(7,io); /* Select tuner control */
- curvol=inb(io+1);
- spin_unlock(&cadet_io_lock);
+ curvol=inb(io+1);
+ spin_unlock(&cadet_io_lock);
/*
* Tune the card
*/
for(j=3;j>-1;j--) {
- cadet_settune(fifo|(j<<16));
-
- spin_lock(&cadet_io_lock);
+ cadet_settune(fifo|(j<<16));
+
+ spin_lock(&cadet_io_lock);
outb(7,io); /* Select tuner control */
outb(curvol,io+1);
spin_unlock(&cadet_io_lock);
-
+
msleep(100);
cadet_gettune();
if((tunestat & 0x40) == 0) { /* Tuned */
- sigstrength=sigtable[curtuner][j];
+ sigstrength=sigtable[curtuner][j];
return;
}
}
@@ -257,28 +258,28 @@ static void cadet_setfreq(unsigned freq)
static int cadet_getvol(void)
{
int ret = 0;
-
+
spin_lock(&cadet_io_lock);
-
- outb(7,io); /* Select tuner control */
- if((inb(io + 1) & 0x20) != 0)
- ret = 0xffff;
-
- spin_unlock(&cadet_io_lock);
- return ret;
+
+ outb(7,io); /* Select tuner control */
+ if((inb(io + 1) & 0x20) != 0)
+ ret = 0xffff;
+
+ spin_unlock(&cadet_io_lock);
+ return ret;
}
static void cadet_setvol(int vol)
{
spin_lock(&cadet_io_lock);
- outb(7,io); /* Select tuner control */
- if(vol>0)
- outb(0x20,io+1);
- else
- outb(0x00,io+1);
+ outb(7,io); /* Select tuner control */
+ if(vol>0)
+ outb(0x20,io+1);
+ else
+ outb(0x00,io+1);
spin_unlock(&cadet_io_lock);
-}
+}
static void cadet_handler(unsigned long data)
{
@@ -288,15 +289,15 @@ static void cadet_handler(unsigned long data)
if(spin_trylock(&cadet_io_lock))
{
- outb(0x3,io); /* Select RDS Decoder Control */
+ outb(0x3,io); /* Select RDS Decoder Control */
if((inb(io+1)&0x20)!=0) {
- printk(KERN_CRIT "cadet: RDS fifo overflow\n");
+ printk(KERN_CRIT "cadet: RDS fifo overflow\n");
}
outb(0x80,io); /* Select RDS fifo */
while((inb(io)&0x80)!=0) {
- rdsbuf[rdsin]=inb(io+1);
+ rdsbuf[rdsin]=inb(io+1);
if(rdsin==rdsout)
- printk(KERN_WARNING "cadet: RDS buffer overflow\n");
+ printk(KERN_WARNING "cadet: RDS buffer overflow\n");
else
rdsin++;
}
@@ -307,9 +308,9 @@ static void cadet_handler(unsigned long data)
* Service pending read
*/
if( rdsin!=rdsout)
- wake_up_interruptible(&read_queue);
+ wake_up_interruptible(&read_queue);
- /*
+ /*
* Clean up and exit
*/
init_timer(&readtimer);
@@ -324,12 +325,12 @@ static void cadet_handler(unsigned long data)
static ssize_t cadet_read(struct file *file, char __user *data,
size_t count, loff_t *ppos)
{
- int i=0;
+ int i=0;
unsigned char readbuf[RDS_BUFFER];
- if(rdsstat==0) {
+ if(rdsstat==0) {
spin_lock(&cadet_io_lock);
- rdsstat=1;
+ rdsstat=1;
outb(0x80,io); /* Select RDS fifo */
spin_unlock(&cadet_io_lock);
init_timer(&readtimer);
@@ -339,15 +340,15 @@ static ssize_t cadet_read(struct file *file, char __user *data,
add_timer(&readtimer);
}
if(rdsin==rdsout) {
- if (file->f_flags & O_NONBLOCK)
- return -EWOULDBLOCK;
- interruptible_sleep_on(&read_queue);
- }
+ if (file->f_flags & O_NONBLOCK)
+ return -EWOULDBLOCK;
+ interruptible_sleep_on(&read_queue);
+ }
while( i<count && rdsin!=rdsout)
- readbuf[i++]=rdsbuf[rdsout++];
+ readbuf[i++]=rdsbuf[rdsout++];
if (copy_to_user(data,readbuf,i))
- return -EFAULT;
+ return -EFAULT;
return i;
}
@@ -375,29 +376,29 @@ static int cadet_do_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
}
switch(v->tuner) {
- case 0:
- strcpy(v->name,"FM");
- v->rangelow=1400; /* 87.5 MHz */
- v->rangehigh=1728; /* 108.0 MHz */
- v->flags=0;
- v->mode=0;
- v->mode|=VIDEO_MODE_AUTO;
- v->signal=sigstrength;
- if(cadet_getstereo()==1) {
- v->flags|=VIDEO_TUNER_STEREO_ON;
- }
+ case 0:
+ strcpy(v->name,"FM");
+ v->rangelow=1400; /* 87.5 MHz */
+ v->rangehigh=1728; /* 108.0 MHz */
+ v->flags=0;
+ v->mode=0;
+ v->mode|=VIDEO_MODE_AUTO;
+ v->signal=sigstrength;
+ if(cadet_getstereo()==1) {
+ v->flags|=VIDEO_TUNER_STEREO_ON;
+ }
v->flags|=cadet_getrds();
- break;
- case 1:
- strcpy(v->name,"AM");
- v->rangelow=8320; /* 520 kHz */
- v->rangehigh=26400; /* 1650 kHz */
- v->flags=0;
- v->flags|=VIDEO_TUNER_LOW;
- v->mode=0;
- v->mode|=VIDEO_MODE_AUTO;
- v->signal=sigstrength;
- break;
+ break;
+ case 1:
+ strcpy(v->name,"AM");
+ v->rangelow=8320; /* 520 kHz */
+ v->rangehigh=26400; /* 1650 kHz */
+ v->flags=0;
+ v->flags|=VIDEO_TUNER_LOW;
+ v->mode=0;
+ v->mode|=VIDEO_MODE_AUTO;
+ v->signal=sigstrength;
+ break;
}
return 0;
}
@@ -407,49 +408,49 @@ static int cadet_do_ioctl(struct inode *inode, struct file *file,
if((v->tuner<0)||(v->tuner>1)) {
return -EINVAL;
}
- curtuner=v->tuner;
+ curtuner=v->tuner;
return 0;
}
case VIDIOCGFREQ:
{
- unsigned long *freq = arg;
+ unsigned long *freq = arg;
*freq = cadet_getfreq();
return 0;
}
case VIDIOCSFREQ:
{
- unsigned long *freq = arg;
+ unsigned long *freq = arg;
if((curtuner==0)&&((*freq<1400)||(*freq>1728))) {
- return -EINVAL;
+ return -EINVAL;
}
if((curtuner==1)&&((*freq<8320)||(*freq>26400))) {
- return -EINVAL;
+ return -EINVAL;
}
cadet_setfreq(*freq);
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
if(cadet_getstereo()==0) {
- v->mode=VIDEO_SOUND_MONO;
+ v->mode=VIDEO_SOUND_MONO;
} else {
v->mode=VIDEO_SOUND_STEREO;
}
v->volume=cadet_getvol();
v->step=0xffff;
strcpy(v->name, "Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
cadet_setvol(v->volume);
- if(v->flags&VIDEO_AUDIO_MUTE)
+ if(v->flags&VIDEO_AUDIO_MUTE)
cadet_setvol(0);
else
cadet_setvol(0xffff);
@@ -539,16 +540,16 @@ static struct pnp_driver cadet_pnp_driver = {
static int cadet_probe(void)
{
- static int iovals[8]={0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e};
+ static int iovals[8]={0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e};
int i;
for(i=0;i<8;i++) {
- io=iovals[i];
+ io=iovals[i];
if (request_region(io, 2, "cadet-probe")) {
- cadet_setfreq(1410);
+ cadet_setfreq(1410);
if(cadet_getfreq()==1410) {
release_region(io, 2);
- return io;
+ return io;
}
release_region(io, 2);
}
@@ -556,7 +557,7 @@ static int cadet_probe(void)
return -1;
}
-/*
+/*
* io should only be set if the user has used something like
* isapnp (the userspace program) to initialize this card for us
*/
@@ -564,7 +565,7 @@ static int cadet_probe(void)
static int __init cadet_init(void)
{
spin_lock_init(&cadet_io_lock);
-
+
/*
* If a probe was requested then probe ISAPnP first (safest)
*/
@@ -579,12 +580,12 @@ static int __init cadet_init(void)
/*
* Else we bail out
*/
-
- if(io < 0) {
-#ifdef MODULE
+
+ if(io < 0) {
+#ifdef MODULE
printk(KERN_ERR "You must set an I/O address with io=0x???\n");
#endif
- goto fail;
+ goto fail;
}
if (!request_region(io,2,"cadet"))
goto fail;
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index 8e499b8..9f249e7 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -1,6 +1,6 @@
/*
***************************************************************************
- *
+ *
* radio-gemtek-pci.c - Gemtek PCI Radio driver
* (C) 2001 Vladimir Shebordaev <vshebordaev@mail.ru>
*
@@ -31,7 +31,7 @@
* radio device driver.
*
* Please, let me know if this piece of code was useful :)
- *
+ *
* TODO: multiple device support and portability were not tested
*
***************************************************************************
@@ -44,6 +44,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/errno.h>
#include <asm/io.h>
@@ -69,18 +70,18 @@
#define TRUE (1)
#endif
-#ifndef FALSE
+#ifndef FALSE
#define FALSE (0)
#endif
struct gemtek_pci_card {
struct video_device *videodev;
-
+
u32 iobase;
u32 length;
u8 chiprev;
u16 model;
-
+
u32 current_frequency;
u8 mute;
};
@@ -96,7 +97,7 @@ static inline u8 gemtek_pci_out( u16 value, u32 port )
return (u8)value;
}
-#define _b0( v ) *((u8 *)&v)
+#define _b0( v ) *((u8 *)&v)
static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep )
{
register u8 byte = *last_byte;
@@ -104,7 +105,7 @@ static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep )
if ( !value ) {
if ( !keep )
value = (u16)port;
- byte &= 0xfd;
+ byte &= 0xfd;
} else
byte |= 2;
@@ -116,7 +117,7 @@ static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep )
byte &= 0xfe;
_b0( value ) = byte;
outw( value, port );
-
+
*last_byte = byte;
}
@@ -193,13 +194,13 @@ static int gemtek_pci_do_ioctl(struct inode *inode, struct file *file,
c->audios = 1;
strcpy( c->name, "Gemtek PCI Radio" );
return 0;
- }
+ }
case VIDIOCGTUNER:
{
struct video_tuner *t = arg;
- if ( t->tuner )
+ if ( t->tuner )
return -EINVAL;
t->rangelow = GEMTEK_PCI_RANGE_LOW;
@@ -228,7 +229,7 @@ static int gemtek_pci_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCSFREQ:
{
unsigned long *freq = arg;
-
+
if ( (*freq < GEMTEK_PCI_RANGE_LOW) ||
(*freq > GEMTEK_PCI_RANGE_HIGH) )
return -EINVAL;
@@ -239,9 +240,9 @@ static int gemtek_pci_do_ioctl(struct inode *inode, struct file *file,
return 0;
}
-
+
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *a = arg;
memset( a, 0, sizeof( *a ) );
@@ -249,17 +250,17 @@ static int gemtek_pci_do_ioctl(struct inode *inode, struct file *file,
a->volume = 1;
a->step = 65535;
strcpy( a->name, "Radio" );
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *a = arg;
- if ( a->audio )
+ if ( a->audio )
return -EINVAL;
- if ( a->flags & VIDEO_AUDIO_MUTE )
+ if ( a->flags & VIDEO_AUDIO_MUTE )
gemtek_pci_mute( card );
else
gemtek_pci_unmute( card );
@@ -323,9 +324,9 @@ static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci
return -ENOMEM;
}
- if ( pci_enable_device( pci_dev ) )
+ if ( pci_enable_device( pci_dev ) )
goto err_pci;
-
+
card->iobase = pci_resource_start( pci_dev, 0 );
card->length = pci_resource_len( pci_dev, 0 );
@@ -338,7 +339,7 @@ static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci
pci_read_config_word( pci_dev, PCI_SUBSYSTEM_ID, &card->model );
pci_set_drvdata( pci_dev, card );
-
+
if ( (devradio = kmalloc( sizeof( struct video_device ), GFP_KERNEL )) == NULL ) {
printk( KERN_ERR "gemtek_pci: out of memory\n" );
goto err_video;
@@ -354,7 +355,7 @@ static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci
devradio->priv = card;
gemtek_pci_mute( card );
- printk( KERN_INFO "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
+ printk( KERN_INFO "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
card->chiprev, card->iobase, card->iobase + card->length - 1 );
return 0;
@@ -364,7 +365,7 @@ err_video:
err_pci:
kfree( card );
- return -ENODEV;
+ return -ENODEV;
}
static void __devexit gemtek_pci_remove( struct pci_dev *pci_dev )
@@ -375,12 +376,12 @@ static void __devexit gemtek_pci_remove( struct pci_dev *pci_dev )
kfree( card->videodev );
release_region( card->iobase, card->length );
-
+
if ( mx )
gemtek_pci_mute( card );
kfree( card );
-
+
pci_set_drvdata( pci_dev, NULL );
}
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 47173be..162f37d 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -6,7 +6,7 @@
* Besides the protocol changes, this is mostly a copy of:
*
* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
- *
+ *
* Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
* Converted to new API by Alan Cox <Alan.Cox@linux.org>
* Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
@@ -22,6 +22,7 @@
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_GEMTEK_PORT */
#include <linux/spinlock.h>
@@ -29,7 +30,7 @@
#define CONFIG_RADIO_GEMTEK_PORT -1
#endif
-static int io = CONFIG_RADIO_GEMTEK_PORT;
+static int io = CONFIG_RADIO_GEMTEK_PORT;
static int radio_nr = -1;
static spinlock_t lock;
@@ -48,7 +49,7 @@ struct gemtek_device
*/
static void gemtek_mute(struct gemtek_device *dev)
{
- if(dev->muted)
+ if(dev->muted)
return;
spin_lock(&lock);
outb(0x10, io);
@@ -94,20 +95,20 @@ static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
freq /= 100000;
spin_lock(&lock);
-
+
/* 2 start bits */
outb_p(0x03, io);
udelay(5);
outb_p(0x07, io);
udelay(5);
- /* 28 frequency bits (lsb first) */
+ /* 28 frequency bits (lsb first) */
for (i = 0; i < 14; i++)
if (freq & (1 << i))
one();
else
zero();
- /* 36 unknown bits */
+ /* 36 unknown bits */
for (i = 0; i < 11; i++)
zero();
one();
@@ -123,7 +124,7 @@ static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
udelay(5);
spin_unlock(&lock);
-
+
return 0;
}
@@ -159,7 +160,7 @@ static int gemtek_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if(v->tuner) /* Only 1 tuner */
return -EINVAL;
v->rangelow=87*16000;
v->rangehigh=108*16000;
@@ -193,25 +194,25 @@ static int gemtek_do_ioctl(struct inode *inode, struct file *file,
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags|=VIDEO_AUDIO_MUTABLE;
v->volume=1;
v->step=65535;
strcpy(v->name, "Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
- if(v->flags&VIDEO_AUDIO_MUTE)
+ if(v->flags&VIDEO_AUDIO_MUTE)
gemtek_mute(rt);
else
- gemtek_unmute(rt);
+ gemtek_unmute(rt);
return 0;
}
@@ -254,14 +255,14 @@ static int __init gemtek_init(void)
return -EINVAL;
}
- if (!request_region(io, 4, "gemtek"))
+ if (!request_region(io, 4, "gemtek"))
{
printk(KERN_ERR "gemtek: port 0x%x already in use\n", io);
return -EBUSY;
}
gemtek_radio.priv=&gemtek_unit;
-
+
if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr)==-1)
{
release_region(io, 4);
@@ -274,7 +275,7 @@ static int __init gemtek_init(void)
/* this is _maybe_ unnecessary */
outb(0x01, io);
- /* mute card - prevents noisy bootups */
+ /* mute card - prevents noisy bootups */
gemtek_unit.muted = 0;
gemtek_mute(&gemtek_unit);
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
index 39c1d91..fcfa6c9 100644
--- a/drivers/media/radio/radio-maestro.c
+++ b/drivers/media/radio/radio-maestro.c
@@ -2,7 +2,7 @@
* (c) 2000 A. Tlalka, atlka@pg.gda.pl
* Notes on the hardware
*
- * + Frequency control is done digitally
+ * + Frequency control is done digitally
* + No volume control - only mute/unmute - you have to use Aux line volume
* control on Maestro card to set the volume
* + Radio status (tuned/not_tuned and stereo/mono) is valid some time after
@@ -26,7 +26,7 @@
#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/videodev.h>
-
+#include <media/v4l2-common.h>
#define DRIVER_VERSION "0.05"
@@ -103,7 +103,7 @@ static struct video_device maestro_radio = {
struct radio_device {
u16 io, /* base of Maestro card radio io (GPIO_DATA)*/
muted, /* VIDEO_AUDIO_MUTE */
- stereo, /* VIDEO_TUNER_STEREO_ON */
+ stereo, /* VIDEO_TUNER_STEREO_ON */
tuned; /* signal strength (0 or 0xffff) */
struct mutex lock;
};
@@ -122,14 +122,14 @@ static u32 radio_bits_get(struct radio_device *dev)
for (l=24;l--;) {
outw(STR_CLK, io); /* HI state */
udelay(2);
- if(!l)
+ if(!l)
dev->tuned = inw(io) & STR_MOST ? 0 : 0xffff;
outw(0, io); /* LO state */
udelay(2);
data <<= 1; /* shift data */
rdata = inw(io);
if(!l)
- dev->stereo = rdata & STR_MOST ?
+ dev->stereo = rdata & STR_MOST ?
0 : VIDEO_TUNER_STEREO_ON;
else
if(rdata & STR_DATA)
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index f0bf47b..f93d7af 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -1,15 +1,15 @@
-/*
- * Guillemot Maxi Radio FM 2000 PCI radio card driver for Linux
+/*
+ * Guillemot Maxi Radio FM 2000 PCI radio card driver for Linux
* (C) 2001 Dimitromanolakis Apostolos <apdim@grecian.net>
*
* Based in the radio Maestro PCI driver. Actually it uses the same chip
* for radio but different pci controller.
*
* I didn't have any specs I reversed engineered the protocol from
- * the windows driver (radio.dll).
+ * the windows driver (radio.dll).
*
* The card uses the TEA5757 chip that includes a search function but it
- * is useless as I haven't found any way to read back the frequency. If
+ * is useless as I haven't found any way to read back the frequency. If
* anybody does please mail me.
*
* For the pdf file see:
@@ -24,7 +24,7 @@
* - tiding up
* - removed support for multiple devices as it didn't work anyway
*
- * BUGS:
+ * BUGS:
* - card unmutes if you change frequency
*
*/
@@ -41,6 +41,7 @@
#include <linux/pci.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
/* version 0.75 Sun Feb 4 22:51:27 EET 2001 */
#define DRIVER_VERSION "0.75"
@@ -80,7 +81,7 @@ static struct file_operations maxiradio_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
- .ioctl = radio_ioctl,
+ .ioctl = radio_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
@@ -97,11 +98,11 @@ static struct radio_device
{
__u16 io, /* base of radio io */
muted, /* VIDEO_AUDIO_MUTE */
- stereo, /* VIDEO_TUNER_STEREO_ON */
+ stereo, /* VIDEO_TUNER_STEREO_ON */
tuned; /* signal strength (0 or 0xffff) */
-
+
unsigned long freq;
-
+
struct mutex lock;
} radio_unit = {0, 0, 0, 0, };
@@ -114,7 +115,7 @@ static void outbit(unsigned long bit, __u16 io)
outb( power|wren|data|clk ,io); udelay(4);
outb( power|wren|data ,io); udelay(4);
}
- else
+ else
{
outb( power|wren ,io); udelay(4);
outb( power|wren|clk ,io); udelay(4);
@@ -132,12 +133,12 @@ static void set_freq(__u16 io, __u32 data)
{
unsigned long int si;
int bl;
-
+
/* TEA5757 shift register bits (see pdf) */
- outbit(0,io); // 24 search
+ outbit(0,io); // 24 search
outbit(1,io); // 23 search up/down
-
+
outbit(0,io); // 22 stereo/mono
outbit(0,io); // 21 band
@@ -145,24 +146,24 @@ static void set_freq(__u16 io, __u32 data)
outbit(0,io); // 19 port ?
outbit(0,io); // 18 port ?
-
+
outbit(0,io); // 17 search level
outbit(0,io); // 16 search level
-
+
si = 0x8000;
for(bl = 1; bl <= 16 ; bl++) { outbit(data & si,io); si >>=1; }
-
+
outb(power,io);
}
static int get_stereo(__u16 io)
-{
+{
outb(power,io); udelay(4);
return !(inb(io) & mo_st);
}
static int get_tune(__u16 io)
-{
+{
outb(power+clk,io); udelay(4);
return !(inb(io) & mo_st);
}
@@ -177,7 +178,7 @@ static inline int radio_function(struct inode *inode, struct file *file,
switch(cmd) {
case VIDIOCGCAP: {
struct video_capability *v = arg;
-
+
memset(v,0,sizeof(*v));
strcpy(v->name, "Maxi Radio FM2000 radio");
v->type=VID_TYPE_TUNER;
@@ -186,22 +187,22 @@ static inline int radio_function(struct inode *inode, struct file *file,
}
case VIDIOCGTUNER: {
struct video_tuner *v = arg;
-
+
if(v->tuner)
return -EINVAL;
-
+
card->stereo = 0xffff * get_stereo(card->io);
card->tuned = 0xffff * get_tune(card->io);
-
+
v->flags = VIDEO_TUNER_LOW | card->stereo;
v->signal = card->tuned;
-
+
strcpy(v->name, "FM");
-
+
v->rangelow = FREQ_LO;
v->rangehigh = FREQ_HI;
v->mode = VIDEO_MODE_AUTO;
-
+
return 0;
}
case VIDIOCSTUNER: {
@@ -212,13 +213,13 @@ static inline int radio_function(struct inode *inode, struct file *file,
}
case VIDIOCGFREQ: {
unsigned long *freq = arg;
-
+
*freq = card->freq;
return 0;
}
case VIDIOCSFREQ: {
unsigned long *freq = arg;
-
+
if (*freq < FREQ_LO || *freq > FREQ_HI)
return -EINVAL;
card->freq = *freq;
@@ -226,18 +227,18 @@ static inline int radio_function(struct inode *inode, struct file *file,
msleep(125);
return 0;
}
- case VIDIOCGAUDIO: {
+ case VIDIOCGAUDIO: {
struct video_audio *v = arg;
memset(v,0,sizeof(*v));
strcpy(v->name, "Radio");
v->flags=VIDEO_AUDIO_MUTABLE | card->muted;
v->mode=VIDEO_SOUND_STEREO;
- return 0;
+ return 0;
}
-
+
case VIDIOCSAUDIO: {
struct video_audio *v = arg;
-
+
if(v->audio)
return -EINVAL;
card->muted = v->flags & VIDEO_AUDIO_MUTE;
@@ -249,13 +250,13 @@ static inline int radio_function(struct inode *inode, struct file *file,
}
case VIDIOCGUNIT: {
struct video_unit *v = arg;
-
+
v->video=VIDEO_NO_UNIT;
v->vbi=VIDEO_NO_UNIT;
v->radio=dev->minor;
v->audio=0;
v->teletext=VIDEO_NO_UNIT;
- return 0;
+ return 0;
}
default: return -ENOIOCTLCMD;
}
@@ -267,7 +268,7 @@ static int radio_ioctl(struct inode *inode, struct file *file,
struct video_device *dev = video_devdata(file);
struct radio_device *card=dev->priv;
int ret;
-
+
mutex_lock(&card->lock);
ret = video_usercopy(inode, file, cmd, arg, radio_function);
mutex_unlock(&card->lock);
@@ -282,21 +283,21 @@ MODULE_LICENSE("GPL");
static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
if(!request_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) {
- printk(KERN_ERR "radio-maxiradio: can't reserve I/O ports\n");
- goto err_out;
+ pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) {
+ printk(KERN_ERR "radio-maxiradio: can't reserve I/O ports\n");
+ goto err_out;
}
if (pci_enable_device(pdev))
- goto err_out_free_region;
+ goto err_out_free_region;
radio_unit.io = pci_resource_start(pdev, 0);
mutex_init(&radio_unit.lock);
maxiradio_radio.priv = &radio_unit;
if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
- printk("radio-maxiradio: can't register device!");
- goto err_out_free_region;
+ printk("radio-maxiradio: can't register device!");
+ goto err_out_free_region;
}
printk(KERN_INFO "radio-maxiradio: version "
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index 28a47c9..5b68ac4 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -1,5 +1,5 @@
/* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
- *
+ *
* Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
* Converted to new API by Alan Cox <Alan.Cox@linux.org>
* Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
@@ -15,6 +15,7 @@
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_RTRACK2_PORT */
#include <linux/spinlock.h>
@@ -22,7 +23,7 @@
#define CONFIG_RADIO_RTRACK2_PORT -1
#endif
-static int io = CONFIG_RADIO_RTRACK2_PORT;
+static int io = CONFIG_RADIO_RTRACK2_PORT;
static int radio_nr = -1;
static spinlock_t lock;
@@ -38,7 +39,7 @@ struct rt_device
static void rt_mute(struct rt_device *dev)
{
- if(dev->muted)
+ if(dev->muted)
return;
spin_lock(&lock);
outb(1, io);
@@ -58,14 +59,14 @@ static void rt_unmute(struct rt_device *dev)
static void zero(void)
{
- outb_p(1, io);
+ outb_p(1, io);
outb_p(3, io);
outb_p(1, io);
}
static void one(void)
{
- outb_p(5, io);
+ outb_p(5, io);
outb_p(7, io);
outb_p(5, io);
}
@@ -75,7 +76,7 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
int i;
freq = freq / 200 + 856;
-
+
spin_lock(&lock);
outb_p(0xc8, io);
@@ -94,7 +95,7 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
outb_p(0xc8, io);
if (!dev->muted)
outb_p(0, io);
-
+
spin_unlock(&lock);
return 0;
}
@@ -127,7 +128,7 @@ static int rt_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if(v->tuner) /* Only 1 tuner */
return -EINVAL;
v->rangelow=88*16000;
v->rangehigh=108*16000;
@@ -159,25 +160,25 @@ static int rt_do_ioctl(struct inode *inode, struct file *file,
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags|=VIDEO_AUDIO_MUTABLE;
v->volume=1;
v->step=65535;
strcpy(v->name, "Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
- if(v->flags&VIDEO_AUDIO_MUTE)
+ if(v->flags&VIDEO_AUDIO_MUTE)
rt_mute(rt);
else
- rt_unmute(rt);
+ rt_unmute(rt);
return 0;
}
@@ -219,7 +220,7 @@ static int __init rtrack2_init(void)
printk(KERN_ERR "You must set an I/O address with io=0x20c or io=0x30c\n");
return -EINVAL;
}
- if (!request_region(io, 4, "rtrack2"))
+ if (!request_region(io, 4, "rtrack2"))
{
printk(KERN_ERR "rtrack2: port 0x%x already in use\n", io);
return -EBUSY;
@@ -227,16 +228,16 @@ static int __init rtrack2_init(void)
rtrack2_radio.priv=&rtrack2_unit;
- spin_lock_init(&lock);
+ spin_lock_init(&lock);
if(video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr)==-1)
{
release_region(io, 4);
return -EINVAL;
}
-
+
printk(KERN_INFO "AIMSlab Radiotrack II card driver.\n");
- /* mute card - prevents noisy bootups */
+ /* mute card - prevents noisy bootups */
outb(1, io);
rtrack2_unit.muted = 1;
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 53073b4..efee6e3 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -12,7 +12,7 @@
* Frequency control is done digitally -- ie out(port,encodefreq(95.8));
* No volume control - only mute/unmute - you have to use line volume
* control on SB-part of SF16FMI
- *
+ *
*/
#include <linux/kernel.h> /* __setup */
@@ -21,6 +21,7 @@
#include <linux/ioport.h> /* request_region */
#include <linux/delay.h> /* udelay */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/isapnp.h>
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
@@ -29,19 +30,19 @@
struct fmi_device
{
int port;
- int curvol; /* 1 or 0 */
- unsigned long curfreq; /* freq in kHz */
- __u32 flags;
+ int curvol; /* 1 or 0 */
+ unsigned long curfreq; /* freq in kHz */
+ __u32 flags;
};
-static int io = -1;
+static int io = -1;
static int radio_nr = -1;
static struct pnp_dev *dev = NULL;
static struct mutex lock;
/* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
/* It is only useful to give freq in intervall of 800 (=0.05Mhz),
- * other bits will be truncated, e.g 92.7400016 -> 92.7, but
+ * other bits will be truncated, e.g 92.7400016 -> 92.7, but
* 92.7400017 -> 92.75
*/
#define RSF16_ENCODE(x) ((x)/800+214)
@@ -51,7 +52,7 @@ static struct mutex lock;
static void outbits(int bits, unsigned int data, int port)
{
while(bits--) {
- if(data & 1) {
+ if(data & 1) {
outb(5, port);
udelay(6);
outb(7, port);
@@ -101,7 +102,7 @@ static inline int fmi_getsigstr(struct fmi_device *dev)
int res;
int myport = dev->port;
-
+
mutex_lock(&lock);
val = dev->curvol ? 0x08 : 0x00; /* unmute/mute */
outb(val, myport);
@@ -109,7 +110,7 @@ static inline int fmi_getsigstr(struct fmi_device *dev)
msleep(143); /* was schedule_timeout(HZ/7) */
res = (int)inb(myport+1);
outb(val, myport);
-
+
mutex_unlock(&lock);
return (res & 2) ? 0 : 0xFFFF;
}
@@ -119,7 +120,7 @@ static int fmi_do_ioctl(struct inode *inode, struct file *file,
{
struct video_device *dev = video_devdata(file);
struct fmi_device *fmi=dev->priv;
-
+
switch(cmd)
{
case VIDIOCGCAP:
@@ -174,18 +175,18 @@ static int fmi_do_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
/*rounding in steps of 800 to match th freq
that will be used */
- fmi->curfreq = (*freq/800)*800;
+ fmi->curfreq = (*freq/800)*800;
fmi_setfreq(fmi);
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0,sizeof(*v));
v->flags=( (!fmi->curvol)*VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE);
strcpy(v->name, "Radio");
v->mode=VIDEO_SOUND_STEREO;
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
@@ -193,19 +194,19 @@ static int fmi_do_ioctl(struct inode *inode, struct file *file,
if(v->audio)
return -EINVAL;
fmi->curvol= v->flags&VIDEO_AUDIO_MUTE ? 0 : 1;
- fmi->curvol ?
+ fmi->curvol ?
fmi_unmute(fmi->port) : fmi_mute(fmi->port);
return 0;
}
- case VIDIOCGUNIT:
+ case VIDIOCGUNIT:
{
- struct video_unit *v = arg;
+ struct video_unit *v = arg;
v->video=VIDEO_NO_UNIT;
v->vbi=VIDEO_NO_UNIT;
v->radio=dev->minor;
v->audio=0; /* How do we find out this??? */
v->teletext=VIDEO_NO_UNIT;
- return 0;
+ return 0;
}
default:
return -ENOIOCTLCMD;
@@ -295,14 +296,14 @@ static int __init fmi_init(void)
fmi_unit.curfreq = 0;
fmi_unit.flags = VIDEO_TUNER_LOW;
fmi_radio.priv = &fmi_unit;
-
+
mutex_init(&lock);
-
+
if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) == -1) {
release_region(io, 2);
return -EINVAL;
}
-
+
printk(KERN_INFO "SF16FMx radio card driver at 0x%x\n", io);
/* mute card - prevents noisy bootups */
fmi_mute(io);
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index bcebd8c..3483b2c 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -19,6 +19,7 @@
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/mutex.h>
static struct mutex lock;
@@ -202,7 +203,7 @@ static int fmr2_setvolume(struct fmr2_device *dev)
}
static int fmr2_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+ unsigned int cmd, void *arg)
{
struct video_device *dev = video_devdata(file);
struct fmr2_device *fmr2 = dev->priv;
@@ -344,7 +345,7 @@ static int fmr2_do_ioctl(struct inode *inode, struct file *file,
}
static int fmr2_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+ unsigned int cmd, unsigned long arg)
{
return video_usercopy(inode, file, cmd, arg, fmr2_do_ioctl);
}
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index fcfde2e..dfba4ae 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -2,11 +2,11 @@
* (c) 1999 R. Offermanns (rolf@offermanns.de)
* based on the aimslab radio driver from M. Kirkwood
* many thanks to Michael Becker and Friedhelm Birth (from TerraTec)
- *
+ *
*
* History:
* 1999-05-21 First preview release
- *
+ *
* Notes on the hardware:
* There are two "main" chips on the card:
* - Philips OM5610 (http://www-us.semiconductors.philips.com/acrobat/datasheets/OM5610_2.pdf)
@@ -20,7 +20,7 @@
* (as soon i have understand how to get started :)
* If you can help me out with that, please contact me!!
*
- *
+ *
*/
#include <linux/module.h> /* Modules */
@@ -30,6 +30,7 @@
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_TERRATEC_PORT */
#include <linux/spinlock.h>
@@ -49,7 +50,7 @@
#define WRT_EN 0x10
/*******************************************************************/
-static int io = CONFIG_RADIO_TERRATEC_PORT;
+static int io = CONFIG_RADIO_TERRATEC_PORT;
static int radio_nr = -1;
static spinlock_t lock;
@@ -88,15 +89,15 @@ static void tt_mute(struct tt_device *dev)
static int tt_setvol(struct tt_device *dev, int vol)
{
-
+
// printk(KERN_ERR "setvol called, vol = %d\n", vol);
if(vol == dev->curvol) { /* requested volume = current */
if (dev->muted) { /* user is unmuting the card */
dev->muted = 0;
cardWriteVol(vol); /* enable card */
- }
-
+ }
+
return 0;
}
@@ -107,9 +108,9 @@ static int tt_setvol(struct tt_device *dev, int vol)
}
dev->muted = 0;
-
+
cardWriteVol(vol);
-
+
dev->curvol = vol;
return 0;
@@ -121,13 +122,13 @@ static int tt_setvol(struct tt_device *dev, int vol)
/* many more or less strange things are going on here, but hey, it works :) */
static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
-{
+{
int freq;
int i;
int p;
int temp;
long rest;
-
+
unsigned char buffer[25]; /* we have to bit shift 25 registers */
freq = freq1/160; /* convert the freq. to a nice to handle value */
for(i=24;i>-1;i--)
@@ -142,9 +143,9 @@ static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
{
if (rest%temp == rest)
buffer[i] = 0;
- else
+ else
{
- buffer[i] = 1;
+ buffer[i] = 1;
rest = rest-temp;
}
i--;
@@ -153,10 +154,10 @@ static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
}
spin_lock(&lock);
-
+
for (i=24;i>-1;i--) /* bit shift the values to the radiocard */
{
- if (buffer[i]==1)
+ if (buffer[i]==1)
{
outb(WRT_EN|DATA, BASEPORT);
outb(WRT_EN|DATA|CLK_ON , BASEPORT);
@@ -168,11 +169,11 @@ static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
outb(WRT_EN|0x00|CLK_ON , BASEPORT);
}
}
- outb(0x00, BASEPORT);
-
+ outb(0x00, BASEPORT);
+
spin_unlock(&lock);
-
- return 0;
+
+ return 0;
}
static int tt_getsigstr(struct tt_device *dev) /* TODO */
@@ -190,7 +191,7 @@ static int tt_do_ioctl(struct inode *inode, struct file *file,
{
struct video_device *dev = video_devdata(file);
struct tt_device *tt=dev->priv;
-
+
switch(cmd)
{
case VIDIOCGCAP:
@@ -206,7 +207,7 @@ static int tt_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if(v->tuner) /* Only 1 tuner */
return -EINVAL;
v->rangelow=(87*16000);
v->rangehigh=(108*16000);
@@ -238,21 +239,21 @@ static int tt_do_ioctl(struct inode *inode, struct file *file,
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
v->volume=tt->curvol * 6554;
v->step=6554;
strcpy(v->name, "Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
- if(v->flags&VIDEO_AUDIO_MUTE)
+ if(v->flags&VIDEO_AUDIO_MUTE)
tt_mute(tt);
else
tt_setvol(tt,v->volume/6554);
@@ -296,25 +297,25 @@ static int __init terratec_init(void)
printk(KERN_ERR "You must set an I/O address with io=0x???\n");
return -EINVAL;
}
- if (!request_region(io, 2, "terratec"))
+ if (!request_region(io, 2, "terratec"))
{
printk(KERN_ERR "TerraTec: port 0x%x already in use\n", io);
return -EBUSY;
}
terratec_radio.priv=&terratec_unit;
-
+
spin_lock_init(&lock);
-
+
if(video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr)==-1)
{
release_region(io,2);
return -EINVAL;
}
-
+
printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver.\n");
- /* mute card - prevents noisy bootups */
+ /* mute card - prevents noisy bootups */
/* this ensures that the volume is all the way down */
cardWriteVol(0);
@@ -334,7 +335,7 @@ static void __exit terratec_cleanup_module(void)
{
video_unregister_device(&terratec_radio);
release_region(io,2);
- printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n");
+ printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n");
}
module_init(terratec_init);
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index 5a099a5..8da4bad 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -1,14 +1,14 @@
-/* radio-trust.c - Trust FM Radio card driver for Linux 2.2
+/* radio-trust.c - Trust FM Radio card driver for Linux 2.2
* by Eric Lammerts <eric@scintilla.utwente.nl>
*
* Based on radio-aztech.c. Original notes:
*
- * Adapted to support the Video for Linux API by
+ * Adapted to support the Video for Linux API by
* Russell Kroll <rkroll@exploits.org>. Based on original tuner code by:
*
* Quay Ly
* Donald Song
- * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
+ * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
* Scott McGrath (smcgrath@twilight.vtc.vsc.edu)
* William McGrath (wmcgrath@twilight.vtc.vsc.edu)
*
@@ -22,6 +22,7 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_TRUST_PORT */
/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
@@ -30,7 +31,7 @@
#define CONFIG_RADIO_TRUST_PORT -1
#endif
-static int io = CONFIG_RADIO_TRUST_PORT;
+static int io = CONFIG_RADIO_TRUST_PORT;
static int radio_nr = -1;
static int ioval = 0xf;
static __u16 curvol;
@@ -135,7 +136,7 @@ static void tr_setmute(int mute)
static int tr_getsigstr(void)
{
int i, v;
-
+
for(i = 0, v = 0; i < 100; i++) v |= inb(io);
return (v & 1)? 0 : 0xffff;
}
@@ -175,7 +176,7 @@ static int tr_do_ioctl(struct inode *inode, struct file *file,
{
struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if(v->tuner) /* Only 1 tuner */
return -EINVAL;
v->rangelow = 87500 * 16;
@@ -211,28 +212,28 @@ static int tr_do_ioctl(struct inode *inode, struct file *file,
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags = VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME |
- VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
+ VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
v->mode = curstereo? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
v->volume = curvol * 2048;
v->step = 2048;
v->bass = curbass * 4370;
v->treble = curtreble * 4370;
-
+
strcpy(v->name, "Trust FM Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
- tr_setvol(v->volume);
+ tr_setvol(v->volume);
tr_setbass(v->bass);
tr_settreble(v->treble);
tr_setstereo(v->mode & VIDEO_SOUND_STEREO);
@@ -292,7 +293,7 @@ static int __init trust_init(void)
write_i2c(2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */
write_i2c(2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */
- tr_setvol(0x8000);
+ tr_setvol(0x8000);
tr_setbass(0x8000);
tr_settreble(0x8000);
tr_setstereo(1);
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index e509558..edd0122 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -36,6 +36,7 @@
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_TYPHOON_* */
#define BANNER "Typhoon Radio Card driver v0.1\n"
@@ -361,8 +362,8 @@ static int __init typhoon_init(void)
#ifdef CONFIG_RADIO_TYPHOON_PROC_FS
if (!create_proc_info_entry("driver/radio-typhoon", 0, NULL,
- typhoon_get_info))
- printk(KERN_ERR "radio-typhoon: registering /proc/driver/radio-typhoon failed\n");
+ typhoon_get_info))
+ printk(KERN_ERR "radio-typhoon: registering /proc/driver/radio-typhoon failed\n");
#endif
return 0;
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index 7bf1a42..59b86a6 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -1,7 +1,7 @@
/* zoltrix radio plus driver for Linux radio support
* (c) 1998 C. van Schaik <carl@leg.uct.ac.za>
*
- * BUGS
+ * BUGS
* Due to the inconsistency in reading from the signal flags
* it is difficult to get an accurate tuned signal.
*
@@ -14,7 +14,7 @@
*
* 1999-05-06 - (C. van Schaik)
* - Make signal strength and stereo scans
- * kinder to cpu while in delay
+ * kinder to cpu while in delay
* 1999-01-05 - (C. van Schaik)
* - Changed tuning to 1/160Mhz accuracy
* - Added stereo support
@@ -33,6 +33,7 @@
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_ZOLTRIX_PORT */
#ifndef CONFIG_RADIO_ZOLTRIX_PORT
@@ -105,7 +106,7 @@ static int zol_setfreq(struct zol_device *dev, unsigned long freq)
i = 45;
mutex_lock(&dev->lock);
-
+
outb(0, io);
outb(0, io);
inb(io + 3); /* Zoltrix needs to be read to confirm */
@@ -139,8 +140,8 @@ static int zol_setfreq(struct zol_device *dev, unsigned long freq)
udelay(1000);
inb(io+2);
- udelay(1000);
-
+ udelay(1000);
+
if (dev->muted)
{
outb(0, io);
@@ -148,12 +149,12 @@ static int zol_setfreq(struct zol_device *dev, unsigned long freq)
inb(io + 3);
udelay(1000);
}
-
+
mutex_unlock(&dev->lock);
-
+
if(!dev->muted)
{
- zol_setvol(dev, dev->curvol);
+ zol_setvol(dev, dev->curvol);
}
return 0;
}
@@ -174,14 +175,14 @@ static int zol_getsigstr(struct zol_device *dev)
b = inb(io);
mutex_unlock(&dev->lock);
-
+
if (a != b)
return (0);
- if ((a == 0xcf) || (a == 0xdf) /* I found this out by playing */
+ if ((a == 0xcf) || (a == 0xdf) /* I found this out by playing */
|| (a == 0xef)) /* with a binary scanner on the card io */
return (1);
- return (0);
+ return (0);
}
static int zol_is_stereo (struct zol_device *dev)
@@ -189,7 +190,7 @@ static int zol_is_stereo (struct zol_device *dev)
int x1, x2;
mutex_lock(&dev->lock);
-
+
outb(0x00, io);
outb(dev->curvol, io);
msleep(20);
@@ -199,7 +200,7 @@ static int zol_is_stereo (struct zol_device *dev)
x2 = inb(io);
mutex_unlock(&dev->lock);
-
+
if ((x1 == x2) && (x1 == 0xcf))
return 1;
return 0;
@@ -226,7 +227,7 @@ static int zol_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
- if (v->tuner)
+ if (v->tuner)
return -EINVAL;
strcpy(v->name, "FM");
v->rangelow = (int) (88.0 * 16000);
@@ -351,7 +352,7 @@ static int __init zoltrix_init(void)
printk(KERN_INFO "Zoltrix Radio Plus card driver.\n");
mutex_init(&zoltrix_unit.lock);
-
+
/* mute card - prevents noisy bootups */
/* this ensures that the volume is all the way down */
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 6b41970..824a63c 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -224,6 +224,12 @@ config VIDEO_ZORAN_LML33R10
support for the Linux Media Labs LML33R10 MJPEG capture/playback
card.
+config VIDEO_ZORAN_AVS6EYES
+ tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
+ depends on VIDEO_ZORAN && EXPERIMENTAL && VIDEO_V4L1
+ help
+ Support for the AverMedia 6 Eyes video surveillance card.
+
config VIDEO_ZR36120
tristate "Zoran ZR36120/36125 Video For Linux"
depends on PCI && I2C && VIDEO_V4L1 && BROKEN
@@ -306,17 +312,6 @@ config VIDEO_HEXIUM_GEMINI
source "drivers/media/video/cx88/Kconfig"
-config VIDEO_OVCAMCHIP
- tristate "OmniVision Camera Chip support"
- depends on I2C && VIDEO_V4L1
- ---help---
- Support for the OmniVision OV6xxx and OV7xxx series of camera chips.
- This driver is intended to be used with the ov511 and w9968cf USB
- camera drivers.
-
- To compile this driver as a module, choose M here: the
- module will be called ovcamchip.
-
config VIDEO_M32R_AR
tristate "AR devices"
depends on M32R && VIDEO_V4L1
@@ -357,6 +352,15 @@ config VIDEO_CS53L32A
To compile this driver as a module, choose M here: the
module will be called cs53l32a.
+config VIDEO_TLV320AIC23B
+ tristate "Texas Instruments TLV320AIC23B audio codec"
+ depends on VIDEO_DEV && I2C && EXPERIMENTAL
+ ---help---
+ Support for the Texas Instruments TLV320AIC23B audio codec.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tlv320aic23b.
+
config VIDEO_WM8775
tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer"
depends on VIDEO_DEV && I2C && EXPERIMENTAL
@@ -380,10 +384,10 @@ config VIDEO_WM8739
source "drivers/media/video/cx25840/Kconfig"
config VIDEO_SAA711X
- tristate "Philips SAA7113/4/5 video decoders (OBSOLETED)"
- depends on VIDEO_V4L1 && I2C && EXPERIMENTAL
+ tristate "Philips SAA7113/4/5 video decoders"
+ depends on VIDEO_DEV && I2C && EXPERIMENTAL
---help---
- Old support for the Philips SAA7113/4 video decoders.
+ Support for the Philips SAA7113/4/5 video decoders.
To compile this driver as a module, choose M here: the
module will be called saa7115.
@@ -447,6 +451,35 @@ source "drivers/media/video/usbvideo/Kconfig"
source "drivers/media/video/et61x251/Kconfig"
+config VIDEO_OVCAMCHIP
+ tristate "OmniVision Camera Chip support"
+ depends on I2C && VIDEO_V4L1
+ ---help---
+ Support for the OmniVision OV6xxx and OV7xxx series of camera chips.
+ This driver is intended to be used with the ov511 and w9968cf USB
+ camera drivers.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ovcamchip.
+
+config USB_W9968CF
+ tristate "USB W996[87]CF JPEG Dual Mode Camera support"
+ depends on USB && VIDEO_V4L1 && I2C
+ select VIDEO_OVCAMCHIP
+ ---help---
+ Say Y here if you want support for cameras based on OV681 or
+ Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
+
+ This driver has an optional plugin, which is distributed as a
+ separate module only (released under GPL). It allows to use higher
+ resolutions and framerates, but cannot be included in the official
+ Linux kernel for performance purposes.
+
+ See <file:Documentation/video4linux/w9968cf.txt> for more info.
+
+ To compile this driver as a module, choose M here: the
+ module will be called w9968cf.
+
config USB_OV511
tristate "USB OV511 Camera support"
depends on USB && VIDEO_V4L1
@@ -483,24 +516,6 @@ config USB_STV680
To compile this driver as a module, choose M here: the
module will be called stv680.
-config USB_W9968CF
- tristate "USB W996[87]CF JPEG Dual Mode Camera support"
- depends on USB && VIDEO_V4L1 && I2C
- select VIDEO_OVCAMCHIP
- ---help---
- Say Y here if you want support for cameras based on OV681 or
- Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
-
- This driver has an optional plugin, which is distributed as a
- separate module only (released under GPL). It allows to use higher
- resolutions and framerates, but cannot be included in the official
- Linux kernel for performance purposes.
-
- See <file:Documentation/video4linux/w9968cf.txt> for more info.
-
- To compile this driver as a module, choose M here: the
- module will be called w9968cf.
-
source "drivers/media/video/zc0301/Kconfig"
source "drivers/media/video/pwc/Kconfig"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index e5bf268..6c401b4 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -6,7 +6,7 @@ zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o
zr36067-objs := zoran_procfs.o zoran_device.o \
zoran_driver.o zoran_card.o
tuner-objs := tuner-core.o tuner-types.o tuner-simple.o \
- mt20xx.o tda8290.o tea5767.o
+ mt20xx.o tda8290.o tea5767.o tda9887.o
msp3400-objs := msp3400-driver.o msp3400-kthreads.o
@@ -33,6 +33,7 @@ obj-$(CONFIG_VIDEO_ZORAN_DC30) += adv7175.o vpx3220.o zr36050.o \
zr36016.o
obj-$(CONFIG_VIDEO_ZORAN_LML33) += bt819.o bt856.o zr36060.o
obj-$(CONFIG_VIDEO_ZORAN_LML33R10) += saa7114.o adv7170.o zr36060.o
+obj-$(CONFIG_VIDEO_ZORAN_AVS6EYES) += bt866.o ks0127.o zr36060.o
obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o
obj-$(CONFIG_VIDEO_PMS) += pms.o
obj-$(CONFIG_VIDEO_PLANB) += planb.o
@@ -48,6 +49,7 @@ obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
obj-$(CONFIG_VIDEO_EM28XX) += tvp5150.o
obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
+obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
@@ -58,7 +60,7 @@ obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
obj-$(CONFIG_VIDEO_DPC) += saa7111.o dpc7146.o
obj-$(CONFIG_TUNER_3036) += tuner-3036.o
-obj-$(CONFIG_VIDEO_TUNER) += tuner.o tda9887.o
+obj-$(CONFIG_VIDEO_TUNER) += tuner.o
obj-$(CONFIG_VIDEO_BUF) += video-buf.o
obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o
obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o
@@ -71,6 +73,7 @@ obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
+obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
obj-$(CONFIG_USB_DABUSB) += dabusb.o
obj-$(CONFIG_USB_DSBR) += dsbr100.o
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index dbe0251..6e08e32 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -31,6 +31,7 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
@@ -212,7 +213,7 @@ void init_iic(void)
ar_outl(0x0300, PLDI2CMOD); /* I2CMOD ACK/8b-data/7b-addr/auto */
ar_outl(0x1, PLDI2CACK); /* I2CACK ACK */
- /* I2C CLK */
+ /* I2C CLK */
/* 50MH-100k */
if (freq == 75) {
ar_outl(369, PLDI2CFREQ); /* BCLK = 75MHz */
diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c
new file mode 100644
index 0000000..05e42bb
--- /dev/null
+++ b/drivers/media/video/bt866.c
@@ -0,0 +1,377 @@
+/*
+ bt866 - BT866 Digital Video Encoder (Rockwell Part)
+
+ Copyright (C) 1999 Mike Bernson <mike@mlb.org>
+ Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+
+ Modifications for LML33/DC10plus unified driver
+ Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+
+ This code was modify/ported from the saa7111 driver written
+ by Dave Perks.
+
+ This code was adapted for the bt866 by Christer Weinigel and ported
+ to 2.6 by Martin Samuelsson.
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+
+#include <linux/videodev.h>
+#include <asm/uaccess.h>
+
+#include <linux/video_encoder.h>
+
+MODULE_LICENSE("GPL");
+
+#define BT866_DEVNAME "bt866"
+#define I2C_BT866 0x88
+
+MODULE_LICENSE("GPL");
+
+#define DEBUG(x) /* Debug driver */
+
+/* ----------------------------------------------------------------------- */
+
+struct bt866 {
+ struct i2c_client *i2c;
+ int addr;
+ unsigned char reg[128];
+
+ int norm;
+ int enable;
+ int bright;
+ int contrast;
+ int hue;
+ int sat;
+};
+
+static int bt866_write(struct bt866 *dev,
+ unsigned char subaddr, unsigned char data);
+
+static int bt866_do_command(struct bt866 *encoder,
+ unsigned int cmd, void *arg)
+{
+ switch (cmd) {
+ case ENCODER_GET_CAPABILITIES:
+ {
+ struct video_encoder_capability *cap = arg;
+
+ DEBUG(printk
+ (KERN_INFO "%s: get capabilities\n",
+ encoder->i2c->name));
+
+ cap->flags
+ = VIDEO_ENCODER_PAL
+ | VIDEO_ENCODER_NTSC
+ | VIDEO_ENCODER_CCIR;
+ cap->inputs = 2;
+ cap->outputs = 1;
+ }
+ break;
+
+ case ENCODER_SET_NORM:
+ {
+ int *iarg = arg;
+
+ DEBUG(printk(KERN_INFO "%s: set norm %d\n",
+ encoder->i2c->name, *iarg));
+
+ switch (*iarg) {
+
+ case VIDEO_MODE_NTSC:
+ break;
+
+ case VIDEO_MODE_PAL:
+ break;
+
+ default:
+ return -EINVAL;
+
+ }
+ encoder->norm = *iarg;
+ }
+ break;
+
+ case ENCODER_SET_INPUT:
+ {
+ int *iarg = arg;
+ static const __u8 init[] = {
+ 0xc8, 0xcc, /* CRSCALE */
+ 0xca, 0x91, /* CBSCALE */
+ 0xcc, 0x24, /* YC16 | OSDNUM */
+ 0xda, 0x00, /* */
+ 0xdc, 0x24, /* SETMODE | PAL */
+ 0xde, 0x02, /* EACTIVE */
+
+ /* overlay colors */
+ 0x70, 0xEB, 0x90, 0x80, 0xB0, 0x80, /* white */
+ 0x72, 0xA2, 0x92, 0x8E, 0xB2, 0x2C, /* yellow */
+ 0x74, 0x83, 0x94, 0x2C, 0xB4, 0x9C, /* cyan */
+ 0x76, 0x70, 0x96, 0x3A, 0xB6, 0x48, /* green */
+ 0x78, 0x54, 0x98, 0xC6, 0xB8, 0xB8, /* magenta */
+ 0x7A, 0x41, 0x9A, 0xD4, 0xBA, 0x64, /* red */
+ 0x7C, 0x23, 0x9C, 0x72, 0xBC, 0xD4, /* blue */
+ 0x7E, 0x10, 0x9E, 0x80, 0xBE, 0x80, /* black */
+
+ 0x60, 0xEB, 0x80, 0x80, 0xc0, 0x80, /* white */
+ 0x62, 0xA2, 0x82, 0x8E, 0xc2, 0x2C, /* yellow */
+ 0x64, 0x83, 0x84, 0x2C, 0xc4, 0x9C, /* cyan */
+ 0x66, 0x70, 0x86, 0x3A, 0xc6, 0x48, /* green */
+ 0x68, 0x54, 0x88, 0xC6, 0xc8, 0xB8, /* magenta */
+ 0x6A, 0x41, 0x8A, 0xD4, 0xcA, 0x64, /* red */
+ 0x6C, 0x23, 0x8C, 0x72, 0xcC, 0xD4, /* blue */
+ 0x6E, 0x10, 0x8E, 0x80, 0xcE, 0x80, /* black */
+ };
+ int i;
+ u8 val;
+
+ for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2)
+ bt866_write(encoder, init[i], init[i+1]);
+
+ val = encoder->reg[0xdc];
+
+ if (*iarg == 0)
+ val |= 0x40; /* CBSWAP */
+ else
+ val &= ~0x40; /* !CBSWAP */
+
+ bt866_write(encoder, 0xdc, val);
+
+ val = encoder->reg[0xcc];
+ if (*iarg == 2)
+ val |= 0x01; /* OSDBAR */
+ else
+ val &= ~0x01; /* !OSDBAR */
+ bt866_write(encoder, 0xcc, val);
+
+ DEBUG(printk(KERN_INFO "%s: set input %d\n",
+ encoder->i2c->name, *iarg));
+
+ switch (*iarg) {
+ case 0:
+ break;
+ case 1:
+ break;
+ default:
+ return -EINVAL;
+
+ }
+ }
+ break;
+
+ case ENCODER_SET_OUTPUT:
+ {
+ int *iarg = arg;
+
+ DEBUG(printk(KERN_INFO "%s: set output %d\n",
+ encoder->i2c->name, *iarg));
+
+ /* not much choice of outputs */
+ if (*iarg != 0)
+ return -EINVAL;
+ }
+ break;
+
+ case ENCODER_ENABLE_OUTPUT:
+ {
+ int *iarg = arg;
+ encoder->enable = !!*iarg;
+
+ DEBUG(printk
+ (KERN_INFO "%s: enable output %d\n",
+ encoder->i2c->name, encoder->enable));
+ }
+ break;
+
+ case 4711:
+ {
+ int *iarg = arg;
+ __u8 val;
+
+ printk("bt866: square = %d\n", *iarg);
+
+ val = encoder->reg[0xdc];
+ if (*iarg)
+ val |= 1; /* SQUARE */
+ else
+ val &= ~1; /* !SQUARE */
+ bt866_write(encoder, 0xdc, val);
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int bt866_write(struct bt866 *encoder,
+ unsigned char subaddr, unsigned char data)
+{
+ unsigned char buffer[2];
+ int err;
+
+ buffer[0] = subaddr;
+ buffer[1] = data;
+
+ encoder->reg[subaddr] = data;
+
+ DEBUG(printk
+ ("%s: write 0x%02X = 0x%02X\n",
+ encoder->i2c->name, subaddr, data));
+
+ for (err = 0; err < 3;) {
+ if (i2c_master_send(encoder->i2c, buffer, 2) == 2)
+ break;
+ err++;
+ printk(KERN_WARNING "%s: I/O error #%d "
+ "(write 0x%02x/0x%02x)\n",
+ encoder->i2c->name, err, encoder->addr, subaddr);
+ schedule_timeout_interruptible(HZ/10);
+ }
+ if (err == 3) {
+ printk(KERN_WARNING "%s: giving up\n",
+ encoder->i2c->name);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int bt866_attach(struct i2c_adapter *adapter);
+static int bt866_detach(struct i2c_client *client);
+static int bt866_command(struct i2c_client *client,
+ unsigned int cmd, void *arg);
+
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {I2C_BT866>>1, I2C_CLIENT_END};
+static unsigned short probe[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
+static unsigned short ignore[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
+
+static struct i2c_client_address_data addr_data = {
+ normal_i2c,
+ probe,
+ ignore,
+};
+
+static struct i2c_driver i2c_driver_bt866 = {
+ .driver.name = BT866_DEVNAME,
+ .id = I2C_DRIVERID_BT866,
+ .attach_adapter = bt866_attach,
+ .detach_client = bt866_detach,
+ .command = bt866_command
+};
+
+
+static struct i2c_client bt866_client_tmpl =
+{
+ .name = "(nil)",
+ .addr = 0,
+ .adapter = NULL,
+ .driver = &i2c_driver_bt866,
+ .usage_count = 0
+};
+
+static int bt866_found_proc(struct i2c_adapter *adapter,
+ int addr, int kind)
+{
+ struct bt866 *encoder;
+ struct i2c_client *client;
+
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (client == NULL)
+ return -ENOMEM;
+ memcpy(client, &bt866_client_tmpl, sizeof(*client));
+
+ encoder = kzalloc(sizeof(*encoder), GFP_KERNEL);
+ if (encoder == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(client, encoder);
+ client->adapter = adapter;
+ client->addr = addr;
+ sprintf(client->name, "%s-%02x", BT866_DEVNAME, adapter->id);
+
+ encoder->i2c = client;
+ encoder->addr = addr;
+ //encoder->encoder_type = ENCODER_TYPE_UNKNOWN;
+
+ /* initialize */
+
+ i2c_attach_client(client);
+
+ return 0;
+}
+
+static int bt866_attach(struct i2c_adapter *adapter)
+{
+ if (adapter->id == I2C_HW_B_ZR36067)
+ return i2c_probe(adapter, &addr_data, bt866_found_proc);
+ return 0;
+}
+
+static int bt866_detach(struct i2c_client *client)
+{
+ struct bt866 *encoder = i2c_get_clientdata(client);
+
+ i2c_detach_client(client);
+ kfree(encoder);
+ kfree(client);
+
+ return 0;
+}
+
+static int bt866_command(struct i2c_client *client,
+ unsigned int cmd, void *arg)
+{
+ struct bt866 *encoder = i2c_get_clientdata(client);
+ return bt866_do_command(encoder, cmd, arg);
+}
+
+static int __devinit bt866_init(void)
+{
+ i2c_add_driver(&i2c_driver_bt866);
+ return 0;
+}
+
+static void __devexit bt866_exit(void)
+{
+ i2c_del_driver(&i2c_driver_bt866);
+}
+
+module_init(bt866_init);
+module_exit(bt866_exit);
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 2b64aa8..3116345 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -269,7 +269,7 @@ static struct CARD {
{ 0x41a0a051, BTTV_BOARD_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" },
{ 0x18501f7f, BTTV_BOARD_FLYVIDEO_98, "Lifeview Flyvideo 98" },
- { 0x010115cb, BTTV_BOARD_GMV1, "AG GMV1" },
+ { 0x010115cb, BTTV_BOARD_GMV1, "AG GMV1" },
{ 0x010114c7, BTTV_BOARD_MODTEC_205, "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" },
{ 0x10b42636, BTTV_BOARD_HAUPPAUGE878, "STB ???" },
@@ -309,6 +309,7 @@ static struct CARD {
{ 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" },
{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" },
{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
+ { 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini "},
{ 0, -1, NULL }
};
@@ -1903,7 +1904,7 @@ struct tvcard bttv_tvcards[] = {
.no_tda7432 = 1,
},
[BTTV_BOARD_OSPREY2x0] = {
- .name = "Osprey 210/220", /* 0x1(A|B)-04C0-C1 */
+ .name = "Osprey 210/220/230", /* 0x1(A|B)-04C0-C1 */
.video_inputs = 2,
.audio_inputs = 1,
.tuner = -1,
@@ -2745,7 +2746,7 @@ struct tvcard bttv_tvcards[] = {
/* Michael Krufky <mkrufky@m1k.net> */
.name = "DViCO FusionHDTV 5 Lite",
.tuner = 0,
- .tuner_type = TUNER_LG_TDVS_H062F,
+ .tuner_type = TUNER_LG_TDVS_H06XF, /* TDVS-H064F */
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.video_inputs = 3,
@@ -2762,7 +2763,7 @@ struct tvcard bttv_tvcards[] = {
},
/* ---- card 0x88---------------------------------- */
[BTTV_BOARD_ACORP_Y878F] = {
- /* Mauro Carvalho Chehab <mchehab@brturbo.com.br> */
+ /* Mauro Carvalho Chehab <mchehab@infradead.org> */
.name = "Acorp Y878F",
.video_inputs = 3,
.audio_inputs = 1,
@@ -3790,6 +3791,7 @@ static void __devinit osprey_eeprom(struct bttv *btv)
break;
case 0x0060:
case 0x0070:
+ case 0x00A0:
btv->c.type = BTTV_BOARD_OSPREY2x0;
/* enable output on select control lines */
gpio_inout(0xffffff,0x000303);
diff --git a/drivers/media/video/bt8xx/bttv-gpio.c b/drivers/media/video/bt8xx/bttv-gpio.c
index c4d5e2b..ba081f6 100644
--- a/drivers/media/video/bt8xx/bttv-gpio.c
+++ b/drivers/media/video/bt8xx/bttv-gpio.c
@@ -118,20 +118,6 @@ int bttv_sub_del_devices(struct bttv_core *core)
return 0;
}
-void bttv_gpio_irq(struct bttv_core *core)
-{
- struct bttv_sub_driver *drv;
- struct bttv_sub_device *dev;
- struct list_head *item;
-
- list_for_each(item,&core->subs) {
- dev = list_entry(item,struct bttv_sub_device,list);
- drv = to_bttv_sub_drv(dev->dev.driver);
- if (drv && drv->gpio_irq)
- drv->gpio_irq(dev);
- }
-}
-
/* ----------------------------------------------------------------------- */
/* external: sub-driver register/unregister */
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index 69efa0e..b41f81d 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -355,7 +355,7 @@ int bttv_input_init(struct bttv *btv)
if (ir->rc5_gpio) {
u32 gpio;
- /* enable remote irq */
+ /* enable remote irq */
bttv_gpio_inout(&btv->c, (1 << 4), 1 << 4);
gpio = bttv_gpio_read(&btv->c);
bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index 3a23265..f9c9e3c 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -350,7 +350,6 @@ struct bttv_sub_driver {
char wanted[BUS_ID_SIZE];
int (*probe)(struct bttv_sub_device *sub);
void (*remove)(struct bttv_sub_device *sub);
- void (*gpio_irq)(struct bttv_sub_device *sub);
};
#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv)
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index ee989d2..d295601 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -33,6 +33,7 @@
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/pci.h>
#include <linux/input.h>
#include <linux/mutex.h>
@@ -214,7 +215,6 @@ extern struct videobuf_queue_ops bttv_vbi_qops;
extern struct bus_type bttv_sub_bus_type;
int bttv_sub_add_device(struct bttv_core *core, char *name);
int bttv_sub_del_devices(struct bttv_core *core);
-void bttv_gpio_irq(struct bttv_core *core);
/* ---------------------------------------------------------- */
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index cf61c59..7d0b6e5 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -73,6 +73,7 @@ OTHER DEALINGS IN THE SOFTWARE.
#include <linux/parport.h>
#include <linux/sched.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
@@ -759,7 +760,7 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
{
struct video_picture *p = arg;
if(p->palette!=VIDEO_PALETTE_GREY)
- return -EINVAL;
+ return -EINVAL;
if(p->depth!=4 && p->depth!=6)
return -EINVAL;
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index 22a7386..a3989bd 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -34,6 +34,7 @@
#include <linux/parport.h>
#include <linux/sched.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index 85d84e8..95c5ace 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -47,13 +47,6 @@
#include "cpia.h"
-#ifdef CONFIG_VIDEO_CPIA_PP
-extern int cpia_pp_init(void);
-#endif
-#ifdef CONFIG_VIDEO_CPIA_USB
-extern int cpia_usb_init(void);
-#endif
-
static int video_nr = -1;
#ifdef MODULE
@@ -67,10 +60,10 @@ MODULE_SUPPORTED_DEVICE("video");
static unsigned short colorspace_conv;
module_param(colorspace_conv, ushort, 0444);
MODULE_PARM_DESC(colorspace_conv,
- " Colorspace conversion:"
- "\n 0 = disable, 1 = enable"
- "\n Default value is 0"
- );
+ " Colorspace conversion:"
+ "\n 0 = disable, 1 = enable"
+ "\n Default value is 0"
+ );
#define ABOUT "V4L-Driver for Vision CPiA based cameras"
@@ -4047,13 +4040,6 @@ static int __init cpia_init(void)
proc_cpia_create();
#endif
-#ifdef CONFIG_VIDEO_CPIA_PP
- cpia_pp_init();
-#endif
-#ifdef CONFIG_VIDEO_CPIA_USB
- cpia_usb_init();
-#endif
-
return 0;
}
diff --git a/drivers/media/video/cpia.h b/drivers/media/video/cpia.h
index dde27a6..6eaa692 100644
--- a/drivers/media/video/cpia.h
+++ b/drivers/media/video/cpia.h
@@ -45,6 +45,7 @@
#include <asm/uaccess.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/list.h>
#include <linux/smp_lock.h>
#include <linux/mutex.h>
@@ -247,7 +248,7 @@ enum v4l_camstates {
struct cam_data {
struct list_head cam_data_list;
- struct mutex busy_lock; /* guard against SMP multithreading */
+ struct mutex busy_lock; /* guard against SMP multithreading */
struct cpia_camera_ops *ops; /* lowlevel driver operations */
void *lowlevel_data; /* private data for lowlevel driver */
u8 *raw_image; /* buffer for raw image data */
diff --git a/drivers/media/video/cpia2/cpia2.h b/drivers/media/video/cpia2/cpia2.h
index 1764991..c5ecb2b 100644
--- a/drivers/media/video/cpia2/cpia2.h
+++ b/drivers/media/video/cpia2/cpia2.h
@@ -33,6 +33,7 @@
#include <linux/version.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/usb.h>
#include <linux/poll.h>
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index 481e178..d129db5 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -343,7 +343,9 @@ static int cpia2_close(struct inode *inode, struct file *file)
cpia2_free_buffers(cam);
if (!cam->present) {
video_unregister_device(dev);
+ mutex_unlock(&cam->busy_lock);
kfree(cam);
+ return 0;
}
}
@@ -1167,9 +1169,9 @@ static int ioctl_g_ctrl(void *arg,struct camera_data *cam)
} else {
if(cam->params.flicker_control.cam_register &
CPIA2_VP_FLICKER_MODES_50HZ) {
- mode = FLICKER_50;
+ mode = FLICKER_50;
} else {
- mode = FLICKER_60;
+ mode = FLICKER_60;
}
}
for(i=0; i<NUM_FLICKER_CONTROLS; i++) {
diff --git a/drivers/media/video/cpia_pp.c b/drivers/media/video/cpia_pp.c
index 0b00e60..4c89bd3 100644
--- a/drivers/media/video/cpia_pp.c
+++ b/drivers/media/video/cpia_pp.c
@@ -803,7 +803,7 @@ static struct parport_driver cpia_pp_driver = {
.detach = cpia_pp_detach,
};
-int cpia_pp_init(void)
+static int cpia_pp_init(void)
{
printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT,
CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER);
@@ -860,6 +860,8 @@ void cleanup_module(void)
static int __init cpia_pp_setup(char *str)
{
+ int err;
+
if (!strncmp(str, "parport", 7)) {
int n = simple_strtoul(str + 7, NULL, 10);
if (parport_ptr < PARPORT_MAX) {
@@ -873,6 +875,10 @@ static int __init cpia_pp_setup(char *str)
parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE;
}
+ err=cpia_pp_init();
+ if (err)
+ return err;
+
return 1;
}
diff --git a/drivers/media/video/cpia_usb.c b/drivers/media/video/cpia_usb.c
index 9c49a4b..2ee34a3 100644
--- a/drivers/media/video/cpia_usb.c
+++ b/drivers/media/video/cpia_usb.c
@@ -474,12 +474,6 @@ static int cpia_usb_close(void *privdata)
return 0;
}
-int cpia_usb_init(void)
-{
- /* return -ENODEV; */
- return 0;
-}
-
/* Probing and initializing */
static int cpia_probe(struct usb_interface *intf,
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
new file mode 100644
index 0000000..554813e
--- /dev/null
+++ b/drivers/media/video/cx2341x.c
@@ -0,0 +1,915 @@
+/*
+ * cx2341x - generic code for cx23415/6 based devices
+ *
+ * Copyright (C) 2006 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+
+#include <media/tuner.h>
+#include <media/cx2341x.h>
+#include <media/v4l2-common.h>
+
+MODULE_DESCRIPTION("cx23415/6 driver");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+const u32 cx2341x_mpeg_ctrls[] = {
+ V4L2_CID_MPEG_CLASS,
+ V4L2_CID_MPEG_STREAM_TYPE,
+ V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+ V4L2_CID_MPEG_AUDIO_ENCODING,
+ V4L2_CID_MPEG_AUDIO_L2_BITRATE,
+ V4L2_CID_MPEG_AUDIO_MODE,
+ V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
+ V4L2_CID_MPEG_AUDIO_EMPHASIS,
+ V4L2_CID_MPEG_AUDIO_CRC,
+ V4L2_CID_MPEG_VIDEO_ENCODING,
+ V4L2_CID_MPEG_VIDEO_ASPECT,
+ V4L2_CID_MPEG_VIDEO_B_FRAMES,
+ V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+ V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
+ V4L2_CID_MPEG_VIDEO_PULLDOWN,
+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+ V4L2_CID_MPEG_VIDEO_BITRATE,
+ V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+ V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION,
+ V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,
+ V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE,
+ V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE,
+ V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER,
+ V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE,
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM,
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,
+ 0
+};
+
+
+/* Map the control ID to the correct field in the cx2341x_mpeg_params
+ struct. Return -EINVAL if the ID is unknown, else return 0. */
+static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
+ struct v4l2_ext_control *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ ctrl->value = params->audio_sampling_freq;
+ break;
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ ctrl->value = params->audio_encoding;
+ break;
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ ctrl->value = params->audio_l2_bitrate;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ ctrl->value = params->audio_mode;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ ctrl->value = params->audio_mode_extension;
+ break;
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ ctrl->value = params->audio_emphasis;
+ break;
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ ctrl->value = params->audio_crc;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ ctrl->value = params->video_encoding;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ ctrl->value = params->video_aspect;
+ break;
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ ctrl->value = params->video_b_frames;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ ctrl->value = params->video_gop_size;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ ctrl->value = params->video_gop_closure;
+ break;
+ case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+ ctrl->value = params->video_pulldown;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ ctrl->value = params->video_bitrate_mode;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ ctrl->value = params->video_bitrate;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ ctrl->value = params->video_bitrate_peak;
+ break;
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+ ctrl->value = params->video_temporal_decimation;
+ break;
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ ctrl->value = params->stream_type;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ ctrl->value = params->video_spatial_filter_mode;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ ctrl->value = params->video_spatial_filter;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ ctrl->value = params->video_luma_spatial_filter_type;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ ctrl->value = params->video_chroma_spatial_filter_type;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ ctrl->value = params->video_temporal_filter_mode;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+ ctrl->value = params->video_temporal_filter;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ ctrl->value = params->video_median_filter_type;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ ctrl->value = params->video_luma_median_filter_top;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+ ctrl->value = params->video_luma_median_filter_bottom;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+ ctrl->value = params->video_chroma_median_filter_top;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+ ctrl->value = params->video_chroma_median_filter_bottom;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* Map the control ID to the correct field in the cx2341x_mpeg_params
+ struct. Return -EINVAL if the ID is unknown, else return 0. */
+static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
+ struct v4l2_ext_control *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ params->audio_sampling_freq = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ params->audio_encoding = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ params->audio_l2_bitrate = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ params->audio_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ params->audio_mode_extension = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ params->audio_emphasis = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ params->audio_crc = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ params->video_aspect = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES: {
+ int b = ctrl->value + 1;
+ int gop = params->video_gop_size;
+ params->video_b_frames = ctrl->value;
+ params->video_gop_size = b * ((gop + b - 1) / b);
+ /* Max GOP size = 34 */
+ while (params->video_gop_size > 34)
+ params->video_gop_size -= b;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE: {
+ int b = params->video_b_frames + 1;
+ int gop = ctrl->value;
+ params->video_gop_size = b * ((gop + b - 1) / b);
+ /* Max GOP size = 34 */
+ while (params->video_gop_size > 34)
+ params->video_gop_size -= b;
+ ctrl->value = params->video_gop_size;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ params->video_gop_closure = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+ params->video_pulldown = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ /* MPEG-1 only allows CBR */
+ if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 &&
+ ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+ return -EINVAL;
+ params->video_bitrate_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ params->video_bitrate = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ params->video_bitrate_peak = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+ params->video_temporal_decimation = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ params->stream_type = ctrl->value;
+ params->video_encoding =
+ (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
+ params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+ if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
+ /* MPEG-1 implies CBR */
+ params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+ }
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ params->video_spatial_filter_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ params->video_spatial_filter = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ params->video_luma_spatial_filter_type = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ params->video_chroma_spatial_filter_type = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ params->video_temporal_filter_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+ params->video_temporal_filter = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ params->video_median_filter_type = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ params->video_luma_median_filter_top = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+ params->video_luma_median_filter_bottom = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+ params->video_chroma_median_filter_top = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+ params->video_chroma_median_filter_bottom = ctrl->value;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
+{
+ const char *name;
+
+ qctrl->flags = 0;
+ switch (qctrl->id) {
+ /* MPEG controls */
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ name = "Spatial Filter Mode";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ name = "Spatial Filter";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ name = "Spatial Luma Filter Type";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ name = "Spatial Chroma Filter Type";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ name = "Temporal Filter Mode";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+ name = "Temporal Filter";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ name = "Median Filter Type";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ name = "Median Luma Filter Maximum";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+ name = "Median Luma Filter Minimum";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+ name = "Median Chroma Filter Maximum";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+ name = "Median Chroma Filter Minimum";
+ break;
+
+ default:
+ return v4l2_ctrl_query_fill(qctrl, min, max, step, def);
+ }
+ switch (qctrl->id) {
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ qctrl->type = V4L2_CTRL_TYPE_MENU;
+ min = 0;
+ step = 1;
+ break;
+ default:
+ qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ break;
+ }
+ switch (qctrl->id) {
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ qctrl->flags |= V4L2_CTRL_FLAG_UPDATE;
+ break;
+ }
+ qctrl->minimum = min;
+ qctrl->maximum = max;
+ qctrl->step = step;
+ qctrl->default_value = def;
+ qctrl->reserved[0] = qctrl->reserved[1] = 0;
+ snprintf(qctrl->name, sizeof(qctrl->name), name);
+ return 0;
+}
+
+int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl)
+{
+ int err;
+
+ switch (qctrl->id) {
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_L2_BITRATE_192K,
+ V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
+ V4L2_MPEG_AUDIO_L2_BITRATE_224K);
+
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ return -EINVAL;
+
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ err = v4l2_ctrl_query_fill_std(qctrl);
+ if (err == 0 && params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return err;
+
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ /* this setting is read-only for the cx2341x since the
+ V4L2_CID_MPEG_STREAM_TYPE really determines the
+ MPEG-1/2 setting */
+ err = v4l2_ctrl_query_fill_std(qctrl);
+ if (err == 0)
+ qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ return err;
+
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ err = v4l2_ctrl_query_fill_std(qctrl);
+ if (err == 0 && params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return err;
+
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ err = v4l2_ctrl_query_fill_std(qctrl);
+ if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return err;
+
+ /* CX23415/6 specific */
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ return cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, 0);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, 1,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF);
+ if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, 1,
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF);
+ if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ return cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+ cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, 0);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_temporal_filter_mode == V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ return cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+ cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+ cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+ cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ default:
+ return v4l2_ctrl_query_fill_std(qctrl);
+
+ }
+}
+
+const char **cx2341x_ctrl_get_menu(u32 id)
+{
+ static const char *mpeg_stream_type[] = {
+ "MPEG-2 Program Stream",
+ "",
+ "MPEG-1 System Stream",
+ "MPEG-2 DVD-compatible Stream",
+ "MPEG-1 VCD-compatible Stream",
+ "MPEG-2 SVCD-compatible Stream",
+ NULL
+ };
+
+ static const char *cx2341x_video_spatial_filter_mode_menu[] = {
+ "Manual",
+ "Auto",
+ NULL
+ };
+
+ static const char *cx2341x_video_luma_spatial_filter_type_menu[] = {
+ "Off",
+ "1D Horizontal",
+ "1D Vertical",
+ "2D H/V Separable",
+ "2D Symmetric non-separable",
+ NULL
+ };
+
+ static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = {
+ "Off",
+ "1D Horizontal",
+ NULL
+ };
+
+ static const char *cx2341x_video_temporal_filter_mode_menu[] = {
+ "Manual",
+ "Auto",
+ NULL
+ };
+
+ static const char *cx2341x_video_median_filter_type_menu[] = {
+ "Off",
+ "Horizontal",
+ "Vertical",
+ "Horizontal/Vertical",
+ "Diagonal",
+ NULL
+ };
+
+ switch (id) {
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ return mpeg_stream_type;
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ return NULL;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ return cx2341x_video_spatial_filter_mode_menu;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ return cx2341x_video_luma_spatial_filter_type_menu;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ return cx2341x_video_chroma_spatial_filter_type_menu;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ return cx2341x_video_temporal_filter_mode_menu;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ return cx2341x_video_median_filter_type_menu;
+ default:
+ return v4l2_ctrl_get_menu(id);
+ }
+}
+
+static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
+{
+ params->audio_properties = (params->audio_sampling_freq << 0) |
+ ((3 - params->audio_encoding) << 2) |
+ ((1 + params->audio_l2_bitrate) << 4) |
+ (params->audio_mode << 8) |
+ (params->audio_mode_extension << 10) |
+ (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) ?
+ 3 :
+ params->audio_emphasis) << 12) |
+ (params->audio_crc << 14);
+}
+
+int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
+ struct v4l2_ext_controls *ctrls, int cmd)
+{
+ int err = 0;
+ int i;
+
+ if (cmd == VIDIOC_G_EXT_CTRLS) {
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+ err = cx2341x_get_ctrl(params, ctrl);
+ if (err) {
+ ctrls->error_idx = i;
+ break;
+ }
+ }
+ return err;
+ }
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl = ctrls->controls + i;
+ struct v4l2_queryctrl qctrl;
+ const char **menu_items = NULL;
+
+ qctrl.id = ctrl->id;
+ err = cx2341x_ctrl_query(params, &qctrl);
+ if (err)
+ break;
+ if (qctrl.type == V4L2_CTRL_TYPE_MENU)
+ menu_items = cx2341x_ctrl_get_menu(qctrl.id);
+ err = v4l2_ctrl_check(ctrl, &qctrl, menu_items);
+ if (err)
+ break;
+ err = cx2341x_set_ctrl(params, ctrl);
+ if (err)
+ break;
+ }
+ if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+ params->video_bitrate_peak < params->video_bitrate) {
+ err = -ERANGE;
+ ctrls->error_idx = ctrls->count;
+ }
+ if (err) {
+ ctrls->error_idx = i;
+ }
+ else {
+ cx2341x_calc_audio_properties(params);
+ }
+ return err;
+}
+
+void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
+{
+ static struct cx2341x_mpeg_params default_params = {
+ /* misc */
+ .port = CX2341X_PORT_MEMORY,
+ .width = 720,
+ .height = 480,
+ .is_50hz = 0,
+
+ /* stream */
+ .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+
+ /* audio */
+ .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
+ .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+ .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K,
+ .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO,
+ .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
+ .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
+ .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE,
+
+ /* video */
+ .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
+ .video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
+ .video_b_frames = 2,
+ .video_gop_size = 12,
+ .video_gop_closure = 1,
+ .video_pulldown = 0,
+ .video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ .video_bitrate = 6000000,
+ .video_bitrate_peak = 8000000,
+ .video_temporal_decimation = 0,
+
+ /* encoding filters */
+ .video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+ .video_spatial_filter = 0,
+ .video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
+ .video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
+ .video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+ .video_temporal_filter = 0,
+ .video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+ .video_luma_median_filter_top = 255,
+ .video_luma_median_filter_bottom = 0,
+ .video_chroma_median_filter_top = 255,
+ .video_chroma_median_filter_bottom = 0,
+ };
+
+ *p = default_params;
+ cx2341x_calc_audio_properties(p);
+}
+
+static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ...)
+{
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ va_list vargs;
+ int i;
+
+ va_start(vargs, args);
+
+ for (i = 0; i < args; i++) {
+ data[i] = va_arg(vargs, int);
+ }
+ va_end(vargs);
+ return func(priv, cmd, args, 0, data);
+}
+
+int cx2341x_update(void *priv, cx2341x_mbox_func func,
+ const struct cx2341x_mpeg_params *old, const struct cx2341x_mpeg_params *new)
+{
+ static int mpeg_stream_type[] = {
+ 0, /* MPEG-2 PS */
+ 1, /* MPEG-2 TS */
+ 2, /* MPEG-1 SS */
+ 14, /* DVD */
+ 11, /* VCD */
+ 12, /* SVCD */
+ };
+
+ int err = 0;
+
+ cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
+
+ if (old == NULL || old->is_50hz != new->is_50hz) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, new->is_50hz);
+ if (err) return err;
+ }
+
+ if (old == NULL || old->width != new->width || old->height != new->height ||
+ old->video_encoding != new->video_encoding) {
+ u16 w = new->width;
+ u16 h = new->height;
+
+ if (new->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
+ w /= 2;
+ h /= 2;
+ }
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
+ if (err) return err;
+ }
+
+ if (old == NULL || old->stream_type != new->stream_type) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[new->stream_type]);
+ if (err) return err;
+ }
+ if (old == NULL || old->video_aspect != new->video_aspect) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, 1 + new->video_aspect);
+ if (err) return err;
+ }
+ if (old == NULL || old->video_b_frames != new->video_b_frames ||
+ old->video_gop_size != new->video_gop_size) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
+ new->video_gop_size, new->video_b_frames + 1);
+ if (err) return err;
+ }
+ if (old == NULL || old->video_gop_closure != new->video_gop_closure) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure);
+ if (err) return err;
+ }
+ if (old == NULL || old->video_pulldown != new->video_pulldown) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_3_2_PULLDOWN, 1, new->video_pulldown);
+ if (err) return err;
+ }
+ if (old == NULL || old->audio_properties != new->audio_properties) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties);
+ if (err) return err;
+ }
+ if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode ||
+ old->video_bitrate != new->video_bitrate ||
+ old->video_bitrate_peak != new->video_bitrate_peak) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5,
+ new->video_bitrate_mode, new->video_bitrate,
+ new->video_bitrate_peak / 400, 0, 0);
+ if (err) return err;
+ }
+ if (old == NULL || old->video_spatial_filter_mode != new->video_spatial_filter_mode ||
+ old->video_temporal_filter_mode != new->video_temporal_filter_mode ||
+ old->video_median_filter_type != new->video_median_filter_type) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
+ new->video_spatial_filter_mode | (new->video_temporal_filter_mode << 1),
+ new->video_median_filter_type);
+ if (err) return err;
+ }
+ if (old == NULL ||
+ old->video_luma_median_filter_bottom != new->video_luma_median_filter_bottom ||
+ old->video_luma_median_filter_top != new->video_luma_median_filter_top ||
+ old->video_chroma_median_filter_bottom != new->video_chroma_median_filter_bottom ||
+ old->video_chroma_median_filter_top != new->video_chroma_median_filter_top) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4,
+ new->video_luma_median_filter_bottom,
+ new->video_luma_median_filter_top,
+ new->video_chroma_median_filter_bottom,
+ new->video_chroma_median_filter_top);
+ if (err) return err;
+ }
+ if (old == NULL ||
+ old->video_luma_spatial_filter_type != new->video_luma_spatial_filter_type ||
+ old->video_chroma_spatial_filter_type != new->video_chroma_spatial_filter_type) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
+ new->video_luma_spatial_filter_type, new->video_chroma_spatial_filter_type);
+ if (err) return err;
+ }
+ if (old == NULL ||
+ old->video_spatial_filter != new->video_spatial_filter ||
+ old->video_temporal_filter != new->video_temporal_filter) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2,
+ new->video_spatial_filter, new->video_temporal_filter);
+ if (err) return err;
+ }
+ if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, 1,
+ new->video_temporal_decimation);
+ if (err) return err;
+ }
+ return 0;
+}
+
+static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id)
+{
+ const char **menu = cx2341x_ctrl_get_menu(id);
+ struct v4l2_ext_control ctrl;
+
+ if (menu == NULL)
+ goto invalid;
+ ctrl.id = id;
+ if (cx2341x_get_ctrl(p, &ctrl))
+ goto invalid;
+ while (ctrl.value-- && *menu) menu++;
+ if (*menu == NULL)
+ goto invalid;
+ return *menu;
+
+invalid:
+ return "<invalid>";
+}
+
+void cx2341x_log_status(struct cx2341x_mpeg_params *p, int card_id)
+{
+ int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+
+ /* Stream */
+ printk(KERN_INFO "cx2341x-%d: Stream: %s\n",
+ card_id,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
+
+ /* Video */
+ printk(KERN_INFO "cx2341x-%d: Video: %dx%d, %d fps\n",
+ card_id,
+ p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1),
+ p->is_50hz ? 25 : 30);
+ printk(KERN_INFO "cx2341x-%d: Video: %s, %s, %s, %d",
+ card_id,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
+ p->video_bitrate);
+ if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
+ printk(", Peak %d", p->video_bitrate_peak);
+ }
+ printk("\n");
+ printk(KERN_INFO "cx2341x-%d: Video: GOP Size %d, %d B-Frames, %sGOP Closure, %s3:2 Pulldown\n",
+ card_id,
+ p->video_gop_size, p->video_b_frames,
+ p->video_gop_closure ? "" : "No ",
+ p->video_pulldown ? "" : "No ");
+ if (p->video_temporal_decimation) {
+ printk(KERN_INFO "cx2341x-%d: Video: Temporal Decimation %d\n",
+ card_id, p->video_temporal_decimation);
+ }
+
+ /* Audio */
+ printk(KERN_INFO "cx2341x-%d: Audio: %s, %s, %s, %s",
+ card_id,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE));
+ if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) {
+ printk(", %s",
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
+ }
+ printk(", %s, %s\n",
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
+
+ /* Encoding filters */
+ printk(KERN_INFO "cx2341x-%d: Spatial Filter: %s, Luma %s, Chroma %s, %d\n",
+ card_id,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
+ p->video_spatial_filter);
+ printk(KERN_INFO "cx2341x-%d: Temporal Filter: %s, %d\n",
+ card_id,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
+ p->video_temporal_filter);
+ printk(KERN_INFO "cx2341x-%d: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n",
+ card_id,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
+ p->video_luma_median_filter_bottom,
+ p->video_luma_median_filter_top,
+ p->video_chroma_median_filter_bottom,
+ p->video_chroma_median_filter_top);
+}
+
+EXPORT_SYMBOL(cx2341x_fill_defaults);
+EXPORT_SYMBOL(cx2341x_ctrl_query);
+EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
+EXPORT_SYMBOL(cx2341x_ext_ctrls);
+EXPORT_SYMBOL(cx2341x_update);
+EXPORT_SYMBOL(cx2341x_log_status);
+EXPORT_SYMBOL(cx2341x_mpeg_ctrls);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c
index 9a4b813..f897c1e 100644
--- a/drivers/media/video/cx25840/cx25840-audio.c
+++ b/drivers/media/video/cx25840/cx25840-audio.c
@@ -30,9 +30,6 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
if (freq != 32000 && freq != 44100 && freq != 48000)
return -EINVAL;
- /* assert soft reset */
- cx25840_and_or(client, 0x810, ~0x1, 0x01);
-
/* common for all inputs and rates */
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
cx25840_write(client, 0x127, 0x50);
@@ -46,6 +43,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
/* AUX_PLL_FRAC */
cx25840_write4(client, 0x110, 0xee39bb01);
+ if (state->is_cx25836)
+ break;
+
/* src3/4/6_ctl = 0x0801f77f */
cx25840_write4(client, 0x900, 0x7ff70108);
cx25840_write4(client, 0x904, 0x7ff70108);
@@ -59,6 +59,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
/* AUX_PLL_FRAC */
cx25840_write4(client, 0x110, 0xd66bec00);
+ if (state->is_cx25836)
+ break;
+
/* src3/4/6_ctl = 0x08016d59 */
cx25840_write4(client, 0x900, 0x596d0108);
cx25840_write4(client, 0x904, 0x596d0108);
@@ -72,6 +75,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
/* AUX_PLL_FRAC */
cx25840_write4(client, 0x110, 0xe5d69800);
+ if (state->is_cx25836)
+ break;
+
/* src3/4/6_ctl = 0x08014faa */
cx25840_write4(client, 0x900, 0xaa4f0108);
cx25840_write4(client, 0x904, 0xaa4f0108);
@@ -87,6 +93,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
/* AUX_PLL_FRAC */
cx25840_write4(client, 0x110, 0x69082a01);
+ if (state->is_cx25836)
+ break;
+
/* src1_ctl = 0x08010000 */
cx25840_write4(client, 0x8f8, 0x00000108);
@@ -106,6 +115,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
/* AUX_PLL_FRAC */
cx25840_write4(client, 0x110, 0xd66bec00);
+ if (state->is_cx25836)
+ break;
+
/* src1_ctl = 0x08010000 */
cx25840_write4(client, 0x8f8, 0xcd600108);
@@ -122,6 +134,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
/* AUX_PLL_FRAC */
cx25840_write4(client, 0x110, 0xe5d69800);
+ if (state->is_cx25836)
+ break;
+
/* src1_ctl = 0x08010000 */
cx25840_write4(client, 0x8f8, 0x00800108);
@@ -133,9 +148,6 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
}
}
- /* deassert soft reset */
- cx25840_and_or(client, 0x810, ~0x1, 0x00);
-
state->audclk_freq = freq;
return 0;
@@ -148,6 +160,10 @@ void cx25840_audio_set_path(struct i2c_client *client)
/* stop microcontroller */
cx25840_and_or(client, 0x803, ~0x10, 0);
+ /* assert soft reset */
+ if (!state->is_cx25836)
+ cx25840_and_or(client, 0x810, ~0x1, 0x01);
+
/* Mute everything to prevent the PFFT! */
cx25840_write(client, 0x8d3, 0x1f);
@@ -161,13 +177,19 @@ void cx25840_audio_set_path(struct i2c_client *client)
} else {
/* Set Path1 to Analog Demod Main Channel */
cx25840_write4(client, 0x8d0, 0x7038061f);
+ }
+ set_audclk_freq(client, state->audclk_freq);
+
+ /* deassert soft reset */
+ if (!state->is_cx25836)
+ cx25840_and_or(client, 0x810, ~0x1, 0x00);
+
+ if (state->aud_input != CX25840_AUDIO_SERIAL) {
/* When the microcontroller detects the
* audio format, it will unmute the lines */
cx25840_and_or(client, 0x803, ~0x10, 0x10);
}
-
- set_audclk_freq(client, state->audclk_freq);
}
static int get_volume(struct i2c_client *client)
@@ -291,11 +313,25 @@ static void set_mute(struct i2c_client *client, int mute)
int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
{
+ struct cx25840_state *state = i2c_get_clientdata(client);
struct v4l2_control *ctrl = arg;
+ int retval;
switch (cmd) {
case VIDIOC_INT_AUDIO_CLOCK_FREQ:
- return set_audclk_freq(client, *(u32 *)arg);
+ if (state->aud_input != CX25840_AUDIO_SERIAL) {
+ cx25840_and_or(client, 0x803, ~0x10, 0);
+ cx25840_write(client, 0x8d3, 0x1f);
+ }
+ if (!state->is_cx25836)
+ cx25840_and_or(client, 0x810, ~0x1, 1);
+ retval = set_audclk_freq(client, *(u32 *)arg);
+ if (!state->is_cx25836)
+ cx25840_and_or(client, 0x810, ~0x1, 0);
+ if (state->aud_input != CX25840_AUDIO_SERIAL) {
+ cx25840_and_or(client, 0x803, ~0x10, 0x10);
+ }
+ return retval;
case VIDIOC_G_CTRL:
switch (ctrl->id) {
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index a961bb2..5c2036b 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -10,6 +10,9 @@
*
* VBI support by Hans Verkuil <hverkuil@xs4all.nl>.
*
+ * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca>
+ * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>.
+ *
* 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
@@ -43,7 +46,7 @@ MODULE_LICENSE("GPL");
static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
-static int cx25840_debug;
+int cx25840_debug;
module_param_named(debug,cx25840_debug, int, 0644);
@@ -105,7 +108,7 @@ u32 cx25840_read4(struct i2c_client * client, u16 addr)
(buffer[2] << 8) | buffer[3];
}
-int cx25840_and_or(struct i2c_client *client, u16 addr, u8 and_mask,
+int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask,
u8 or_value)
{
return cx25840_write(client, addr,
@@ -117,7 +120,8 @@ int cx25840_and_or(struct i2c_client *client, u16 addr, u8 and_mask,
static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
enum cx25840_audio_input aud_input);
-static void log_status(struct i2c_client *client);
+static void log_audio_status(struct i2c_client *client);
+static void log_video_status(struct i2c_client *client);
/* ----------------------------------------------------------------------- */
@@ -147,6 +151,33 @@ static void init_dll2(struct i2c_client *client)
cx25840_write(client, 0x15d, 0xe1);
}
+static void cx25836_initialize(struct i2c_client *client)
+{
+ /* reset configuration is described on page 3-77 of the CX25836 datasheet */
+ /* 2. */
+ cx25840_and_or(client, 0x000, ~0x01, 0x01);
+ cx25840_and_or(client, 0x000, ~0x01, 0x00);
+ /* 3a. */
+ cx25840_and_or(client, 0x15a, ~0x70, 0x00);
+ /* 3b. */
+ cx25840_and_or(client, 0x15b, ~0x1e, 0x06);
+ /* 3c. */
+ cx25840_and_or(client, 0x159, ~0x02, 0x02);
+ /* 3d. */
+ /* There should be a 10-us delay here, but since the
+ i2c bus already has a 10-us delay we don't need to do
+ anything */
+ /* 3e. */
+ cx25840_and_or(client, 0x159, ~0x02, 0x00);
+ /* 3f. */
+ cx25840_and_or(client, 0x159, ~0xc0, 0xc0);
+ /* 3g. */
+ cx25840_and_or(client, 0x159, ~0x01, 0x00);
+ cx25840_and_or(client, 0x159, ~0x01, 0x01);
+ /* 3h. */
+ cx25840_and_or(client, 0x15b, ~0x1e, 0x10);
+}
+
static void cx25840_initialize(struct i2c_client *client, int loadfw)
{
struct cx25840_state *state = i2c_get_clientdata(client);
@@ -220,17 +251,7 @@ static void input_change(struct i2c_client *client)
cx25840_and_or(client, 0x401, ~0x60, 0);
cx25840_and_or(client, 0x401, ~0x60, 0x60);
- /* Note: perhaps V4L2_STD_PAL_M should be handled as V4L2_STD_NTSC
- instead of V4L2_STD_PAL. Someone needs to test this. */
- if (std & V4L2_STD_PAL) {
- /* Follow tuner change procedure for PAL */
- cx25840_write(client, 0x808, 0xff);
- cx25840_write(client, 0x80b, 0x10);
- } else if (std & V4L2_STD_SECAM) {
- /* Select autodetect for SECAM */
- cx25840_write(client, 0x808, 0xff);
- cx25840_write(client, 0x80b, 0x10);
- } else if (std & V4L2_STD_NTSC) {
+ if (std & V4L2_STD_525_60) {
/* Certain Hauppauge PVR150 models have a hardware bug
that causes audio to drop out. For these models the
audio standard must be set explicitly.
@@ -249,6 +270,14 @@ static void input_change(struct i2c_client *client)
cx25840_write(client, 0x808, hw_fix ? 0x1f : 0xf6);
}
cx25840_write(client, 0x80b, 0x00);
+ } else if (std & V4L2_STD_PAL) {
+ /* Follow tuner change procedure for PAL */
+ cx25840_write(client, 0x808, 0xff);
+ cx25840_write(client, 0x80b, 0x10);
+ } else if (std & V4L2_STD_SECAM) {
+ /* Select autodetect for SECAM */
+ cx25840_write(client, 0x808, 0xff);
+ cx25840_write(client, 0x80b, 0x10);
}
if (cx25840_read(client, 0x803) & 0x10) {
@@ -319,8 +348,10 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
state->vid_input = vid_input;
state->aud_input = aud_input;
- cx25840_audio_set_path(client);
- input_change(client);
+ if (!state->is_cx25836) {
+ cx25840_audio_set_path(client);
+ input_change(client);
+ }
return 0;
}
@@ -354,6 +385,8 @@ static int set_v4lstd(struct i2c_client *client, v4l2_std_id std)
}
}
+ v4l_dbg(1, cx25840_debug, client, "changing video std to fmt %i\n",fmt);
+
/* Follow step 9 of section 3.16 in the cx25840 datasheet.
Without this PAL may display a vertical ghosting effect.
This happens for example with the Yuan MPC622. */
@@ -370,6 +403,7 @@ static int set_v4lstd(struct i2c_client *client, v4l2_std_id std)
v4l2_std_id cx25840_get_v4lstd(struct i2c_client * client)
{
+ struct cx25840_state *state = i2c_get_clientdata(client);
/* check VID_FMT_SEL first */
u8 fmt = cx25840_read(client, 0x400) & 0xf;
@@ -383,7 +417,7 @@ v4l2_std_id cx25840_get_v4lstd(struct i2c_client * client)
{
/* if the audio std is A2-M, then this is the South Korean
NTSC standard */
- if (cx25840_read(client, 0x805) == 2)
+ if (!state->is_cx25836 && cx25840_read(client, 0x805) == 2)
return V4L2_STD_NTSC_M_KR;
return V4L2_STD_NTSC_M;
}
@@ -456,6 +490,8 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
case V4L2_CID_AUDIO_TREBLE:
case V4L2_CID_AUDIO_BALANCE:
case V4L2_CID_AUDIO_MUTE:
+ if (state->is_cx25836)
+ return -EINVAL;
return cx25840_audio(client, VIDIOC_S_CTRL, ctrl);
default:
@@ -490,6 +526,8 @@ static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
case V4L2_CID_AUDIO_TREBLE:
case V4L2_CID_AUDIO_BALANCE:
case V4L2_CID_AUDIO_MUTE:
+ if (state->is_cx25836)
+ return -EINVAL;
return cx25840_audio(client, VIDIOC_G_CTRL, ctrl);
default:
return -EINVAL;
@@ -579,91 +617,6 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
/* ----------------------------------------------------------------------- */
-static struct v4l2_queryctrl cx25840_qctrl[] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 128,
- .flags = 0,
- }, {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 64,
- .flags = 0,
- }, {
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 64,
- .flags = 0,
- }, {
- .id = V4L2_CID_HUE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hue",
- .minimum = -128,
- .maximum = 127,
- .step = 1,
- .default_value = 0,
- .flags = 0,
- }, {
- .id = V4L2_CID_AUDIO_VOLUME,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Volume",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 58880,
- .flags = 0,
- }, {
- .id = V4L2_CID_AUDIO_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Balance",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- .flags = 0,
- }, {
- .id = V4L2_CID_AUDIO_MUTE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- .flags = 0,
- }, {
- .id = V4L2_CID_AUDIO_BASS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Bass",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- }, {
- .id = V4L2_CID_AUDIO_TREBLE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Treble",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- },
-};
-
-/* ----------------------------------------------------------------------- */
-
static int cx25840_command(struct i2c_client *client, unsigned int cmd,
void *arg)
{
@@ -706,8 +659,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
case VIDIOC_STREAMON:
v4l_dbg(1, cx25840_debug, client, "enable output\n");
- cx25840_write(client, 0x115, 0x8c);
- cx25840_write(client, 0x116, 0x07);
+ cx25840_write(client, 0x115, state->is_cx25836 ? 0x0c : 0x8c);
+ cx25840_write(client, 0x116, state->is_cx25836 ? 0x04 : 0x07);
break;
case VIDIOC_STREAMOFF:
@@ -717,7 +670,9 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
break;
case VIDIOC_LOG_STATUS:
- log_status(client);
+ log_video_status(client);
+ if (!state->is_cx25836)
+ log_audio_status(client);
break;
case VIDIOC_G_CTRL:
@@ -729,13 +684,29 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
case VIDIOC_QUERYCTRL:
{
struct v4l2_queryctrl *qc = arg;
- int i;
- for (i = 0; i < ARRAY_SIZE(cx25840_qctrl); i++)
- if (qc->id && qc->id == cx25840_qctrl[i].id) {
- memcpy(qc, &cx25840_qctrl[i], sizeof(*qc));
- return 0;
- }
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ break;
+ }
+ if (state->is_cx25836)
+ return -EINVAL;
+
+ switch (qc->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ return -EINVAL;
+ }
return -EINVAL;
}
@@ -760,31 +731,41 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
return set_input(client, route->input, state->aud_input);
case VIDIOC_INT_G_AUDIO_ROUTING:
+ if (state->is_cx25836)
+ return -EINVAL;
route->input = state->aud_input;
route->output = 0;
break;
case VIDIOC_INT_S_AUDIO_ROUTING:
+ if (state->is_cx25836)
+ return -EINVAL;
return set_input(client, state->vid_input, route->input);
case VIDIOC_S_FREQUENCY:
- input_change(client);
+ if (!state->is_cx25836) {
+ input_change(client);
+ }
break;
case VIDIOC_G_TUNER:
{
- u8 mode = cx25840_read(client, 0x804);
- u8 vpres = cx25840_read(client, 0x80a) & 0x10;
+ u8 vpres = cx25840_read(client, 0x40e) & 0x20;
+ u8 mode;
int val = 0;
if (state->radio)
break;
+ vt->signal = vpres ? 0xffff : 0x0;
+ if (state->is_cx25836)
+ break;
+
vt->capability |=
V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
- vt->signal = vpres ? 0xffff : 0x0;
+ mode = cx25840_read(client, 0x804);
/* get rxsubchans and audmode */
if ((mode & 0xf) == 1)
@@ -804,7 +785,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
}
case VIDIOC_S_TUNER:
- if (state->radio)
+ if (state->radio || state->is_cx25836)
break;
switch (vt->audmode) {
@@ -846,12 +827,14 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
return set_v4lfmt(client, (struct v4l2_format *)arg);
case VIDIOC_INT_RESET:
- cx25840_initialize(client, 0);
+ if (state->is_cx25836)
+ cx25836_initialize(client);
+ else
+ cx25840_initialize(client, 0);
break;
case VIDIOC_INT_G_CHIP_IDENT:
- *(enum v4l2_chip_ident *)arg =
- V4L2_IDENT_CX25840 + ((cx25840_read(client, 0x100) >> 4) & 0xf);
+ *(enum v4l2_chip_ident *)arg = state->id;
break;
default:
@@ -870,6 +853,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
{
struct i2c_client *client;
struct cx25840_state *state;
+ enum v4l2_chip_ident id;
u16 device_id;
/* Check if the adapter supports the needed features
@@ -878,10 +862,11 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
return 0;
- client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL);
+ if (state == 0)
return -ENOMEM;
+ client = &state->c;
client->addr = address;
client->adapter = adapter;
client->driver = &i2c_driver_cx25840;
@@ -893,10 +878,18 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
device_id |= cx25840_read(client, 0x100);
/* The high byte of the device ID should be
- * 0x84 if chip is present */
- if ((device_id & 0xff00) != 0x8400) {
+ * 0x83 for the cx2583x and 0x84 for the cx2584x */
+ if ((device_id & 0xff00) == 0x8300) {
+ id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
+ state->is_cx25836 = 1;
+ }
+ else if ((device_id & 0xff00) == 0x8400) {
+ id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
+ state->is_cx25836 = 0;
+ }
+ else {
v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n");
- kfree(client);
+ kfree(state);
return 0;
}
@@ -905,21 +898,19 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
(device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : 3,
address << 1, adapter->name);
- state = kmalloc(sizeof(struct cx25840_state), GFP_KERNEL);
- if (state == NULL) {
- kfree(client);
- return -ENOMEM;
- }
-
i2c_set_clientdata(client, state);
- memset(state, 0, sizeof(struct cx25840_state));
state->vid_input = CX25840_COMPOSITE7;
state->aud_input = CX25840_AUDIO8;
state->audclk_freq = 48000;
state->pvr150_workaround = 0;
state->audmode = V4L2_TUNER_MODE_LANG1;
+ state->vbi_line_offset = 8;
+ state->id = id;
- cx25840_initialize(client, 1);
+ if (state->is_cx25836)
+ cx25836_initialize(client);
+ else
+ cx25840_initialize(client, 1);
i2c_attach_client(client);
@@ -944,7 +935,6 @@ static int cx25840_detach_client(struct i2c_client *client)
}
kfree(state);
- kfree(client);
return 0;
}
@@ -977,7 +967,7 @@ module_exit(m__exit);
/* ----------------------------------------------------------------------- */
-static void log_status(struct i2c_client *client)
+static void log_video_status(struct i2c_client *client)
{
static const char *const fmt_strs[] = {
"0x0",
@@ -989,9 +979,36 @@ static void log_status(struct i2c_client *client)
};
struct cx25840_state *state = i2c_get_clientdata(client);
- u8 microctrl_vidfmt = cx25840_read(client, 0x80a);
u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
u8 gen_stat1 = cx25840_read(client, 0x40d);
+ u8 gen_stat2 = cx25840_read(client, 0x40e);
+ int vid_input = state->vid_input;
+
+ v4l_info(client, "Video signal: %spresent\n",
+ (gen_stat2 & 0x20) ? "" : "not ");
+ v4l_info(client, "Detected format: %s\n",
+ fmt_strs[gen_stat1 & 0xf]);
+
+ v4l_info(client, "Specified standard: %s\n",
+ vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
+
+ if (vid_input >= CX25840_COMPOSITE1 &&
+ vid_input <= CX25840_COMPOSITE8) {
+ v4l_info(client, "Specified video input: Composite %d\n",
+ vid_input - CX25840_COMPOSITE1 + 1);
+ } else {
+ v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n",
+ (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
+ }
+
+ v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void log_audio_status(struct i2c_client *client)
+{
+ struct cx25840_state *state = i2c_get_clientdata(client);
u8 download_ctl = cx25840_read(client, 0x803);
u8 mod_det_stat0 = cx25840_read(client, 0x804);
u8 mod_det_stat1 = cx25840_read(client, 0x805);
@@ -999,15 +1016,9 @@ static void log_status(struct i2c_client *client)
u8 pref_mode = cx25840_read(client, 0x809);
u8 afc0 = cx25840_read(client, 0x80b);
u8 mute_ctl = cx25840_read(client, 0x8d3);
- int vid_input = state->vid_input;
int aud_input = state->aud_input;
char *p;
- v4l_info(client, "Video signal: %spresent\n",
- (microctrl_vidfmt & 0x10) ? "" : "not ");
- v4l_info(client, "Detected format: %s\n",
- fmt_strs[gen_stat1 & 0xf]);
-
switch (mod_det_stat0) {
case 0x00: p = "mono"; break;
case 0x01: p = "stereo"; break;
@@ -1107,25 +1118,12 @@ static void log_status(struct i2c_client *client)
v4l_info(client, "Configured audio system: %s\n", p);
}
- v4l_info(client, "Specified standard: %s\n",
- vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
-
- if (vid_input >= CX25840_COMPOSITE1 &&
- vid_input <= CX25840_COMPOSITE8) {
- v4l_info(client, "Specified video input: Composite %d\n",
- vid_input - CX25840_COMPOSITE1 + 1);
- } else {
- v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n",
- (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
- }
if (aud_input) {
v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input);
} else {
v4l_info(client, "Specified audio input: External\n");
}
- v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
-
switch (pref_mode & 0xf) {
case 0: p = "mono/language A"; break;
case 1: p = "language B"; break;
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h
index 1736929..2804906 100644
--- a/drivers/media/video/cx25840/cx25840-core.h
+++ b/drivers/media/video/cx25840/cx25840-core.h
@@ -24,6 +24,8 @@
#include <linux/videodev2.h>
#include <linux/i2c.h>
+extern int cx25840_debug;
+
/* ENABLE_PVR150_WORKAROUND activates a workaround for a hardware bug that is
present in Hauppauge PVR-150 (and possibly PVR-500) cards that have
certain NTSC tuners (tveeprom tuner model numbers 85, 99 and 112). The
@@ -33,12 +35,16 @@
#define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0)
struct cx25840_state {
+ struct i2c_client c;
int pvr150_workaround;
int radio;
enum cx25840_video_input vid_input;
enum cx25840_audio_input aud_input;
u32 audclk_freq;
int audmode;
+ int vbi_line_offset;
+ enum v4l2_chip_ident id;
+ int is_cx25836;
};
/* ----------------------------------------------------------------------- */
@@ -47,7 +53,7 @@ int cx25840_write(struct i2c_client *client, u16 addr, u8 value);
int cx25840_write4(struct i2c_client *client, u16 addr, u32 value);
u8 cx25840_read(struct i2c_client *client, u16 addr);
u32 cx25840_read4(struct i2c_client *client, u16 addr);
-int cx25840_and_or(struct i2c_client *client, u16 addr, u8 mask, u8 value);
+int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned mask, u8 value);
v4l2_std_id cx25840_get_v4lstd(struct i2c_client *client);
/* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
index 57feca2..6cc8bf2 100644
--- a/drivers/media/video/cx25840/cx25840-vbi.c
+++ b/drivers/media/video/cx25840/cx25840-vbi.c
@@ -84,67 +84,140 @@ static int decode_vps(u8 * dst, u8 * p)
void cx25840_vbi_setup(struct i2c_client *client)
{
+ struct cx25840_state *state = i2c_get_clientdata(client);
v4l2_std_id std = cx25840_get_v4lstd(client);
+ int hblank,hactive,burst,vblank,vactive,sc,vblank656,src_decimation;
+ int luma_lpf,uv_lpf, comb;
+ u32 pll_int,pll_frac,pll_post;
+ /* datasheet startup, step 8d */
if (std & ~V4L2_STD_NTSC) {
- /* datasheet startup, step 8d */
cx25840_write(client, 0x49f, 0x11);
+ } else {
+ cx25840_write(client, 0x49f, 0x14);
+ }
- cx25840_write(client, 0x470, 0x84);
- cx25840_write(client, 0x471, 0x00);
- cx25840_write(client, 0x472, 0x2d);
- cx25840_write(client, 0x473, 0x5d);
-
- cx25840_write(client, 0x474, 0x24);
- cx25840_write(client, 0x475, 0x40);
- cx25840_write(client, 0x476, 0x24);
- cx25840_write(client, 0x477, 0x28);
-
- cx25840_write(client, 0x478, 0x1f);
- cx25840_write(client, 0x479, 0x02);
+ if (std & V4L2_STD_625_50) {
+ hblank=0x084;
+ hactive=0x2d0;
+ burst=0x5d;
+ vblank=0x024;
+ vactive=0x244;
+ vblank656=0x28;
+ src_decimation=0x21f;
+ luma_lpf=2;
if (std & V4L2_STD_SECAM) {
- cx25840_write(client, 0x47a, 0x80);
- cx25840_write(client, 0x47b, 0x00);
- cx25840_write(client, 0x47c, 0x5f);
- cx25840_write(client, 0x47d, 0x42);
+ uv_lpf=0;
+ comb=0;
+ sc=0x0a425f;
} else {
- cx25840_write(client, 0x47a, 0x90);
- cx25840_write(client, 0x47b, 0x20);
- cx25840_write(client, 0x47c, 0x63);
- cx25840_write(client, 0x47d, 0x82);
+ uv_lpf=1;
+ comb=0x20;
+ sc=0x0a8263;
}
-
- cx25840_write(client, 0x47e, 0x0a);
- cx25840_write(client, 0x47f, 0x01);
} else {
- /* datasheet startup, step 8d */
- cx25840_write(client, 0x49f, 0x14);
+ hactive=720;
+ hblank=122;
+ vactive=487;
+ luma_lpf=1;
+ uv_lpf=1;
+
+ src_decimation=0x21f;
+ if (std == V4L2_STD_PAL_M) {
+ vblank=20;
+ vblank656=24;
+ burst=0x61;
+ comb=0x20;
+
+ sc=555452;
+ } else {
+ vblank=26;
+ vblank656=26;
+ burst=0x5b;
+ comb=0x66;
+ sc=556063;
+ }
+ }
+
+ /* DEBUG: Displays configured PLL frequency */
+ pll_int=cx25840_read(client, 0x108);
+ pll_frac=cx25840_read4(client, 0x10c)&0x1ffffff;
+ pll_post=cx25840_read(client, 0x109);
+ v4l_dbg(1, cx25840_debug, client,
+ "PLL regs = int: %u, frac: %u, post: %u\n",
+ pll_int,pll_frac,pll_post);
+
+ if (pll_post) {
+ int fin, fsc;
+ int pll= (28636363L*((((u64)pll_int)<<25L)+pll_frac)) >>25L;
+
+ pll/=pll_post;
+ v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n",
+ pll/1000000, pll%1000000);
+ v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n",
+ pll/8000000, (pll/8)%1000000);
+
+ fin=((u64)src_decimation*pll)>>12;
+ v4l_dbg(1, cx25840_debug, client, "ADC Sampling freq = "
+ "%d.%06d MHz\n",
+ fin/1000000,fin%1000000);
+
+ fsc= (((u64)sc)*pll) >> 24L;
+ v4l_dbg(1, cx25840_debug, client, "Chroma sub-carrier freq = "
+ "%d.%06d MHz\n",
+ fsc/1000000,fsc%1000000);
+
+ v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, "
+ "vblank %i , vactive %i, vblank656 %i, src_dec %i,"
+ "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
+ " sc 0x%06x\n",
+ hblank, hactive, vblank, vactive, vblank656,
+ src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
+ }
+
+ /* Sets horizontal blanking delay and active lines */
+ cx25840_write(client, 0x470, hblank);
+ cx25840_write(client, 0x471, 0xff&(((hblank>>8)&0x3)|(hactive <<4)));
+ cx25840_write(client, 0x472, hactive>>4);
+
+ /* Sets burst gate delay */
+ cx25840_write(client, 0x473, burst);
- cx25840_write(client, 0x470, 0x7a);
- cx25840_write(client, 0x471, 0x00);
- cx25840_write(client, 0x472, 0x2d);
- cx25840_write(client, 0x473, 0x5b);
+ /* Sets vertical blanking delay and active duration */
+ cx25840_write(client, 0x474, vblank);
+ cx25840_write(client, 0x475, 0xff&(((vblank>>8)&0x3)|(vactive <<4)));
+ cx25840_write(client, 0x476, vactive>>4);
+ cx25840_write(client, 0x477, vblank656);
- cx25840_write(client, 0x474, 0x1a);
- cx25840_write(client, 0x475, 0x70);
- cx25840_write(client, 0x476, 0x1e);
- cx25840_write(client, 0x477, 0x1e);
+ /* Sets src decimation rate */
+ cx25840_write(client, 0x478, 0xff&src_decimation);
+ cx25840_write(client, 0x479, 0xff&(src_decimation>>8));
- cx25840_write(client, 0x478, 0x1f);
- cx25840_write(client, 0x479, 0x02);
- cx25840_write(client, 0x47a, 0x50);
- cx25840_write(client, 0x47b, 0x66);
+ /* Sets Luma and UV Low pass filters */
+ cx25840_write(client, 0x47a, luma_lpf<<6|((uv_lpf<<4)&0x30));
- cx25840_write(client, 0x47c, 0x1f);
- cx25840_write(client, 0x47d, 0x7c);
- cx25840_write(client, 0x47e, 0x08);
+ /* Enables comb filters */
+ cx25840_write(client, 0x47b, comb);
+
+ /* Sets SC Step*/
+ cx25840_write(client, 0x47c, sc);
+ cx25840_write(client, 0x47d, 0xff&sc>>8);
+ cx25840_write(client, 0x47e, 0xff&sc>>16);
+
+ /* Sets VBI parameters */
+ if (std & V4L2_STD_625_50) {
+ cx25840_write(client, 0x47f, 0x01);
+ state->vbi_line_offset = 5;
+ } else {
cx25840_write(client, 0x47f, 0x00);
+ state->vbi_line_offset = 8;
}
}
int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
{
+ struct cx25840_state *state = i2c_get_clientdata(client);
struct v4l2_format *fmt;
struct v4l2_sliced_vbi_format *svbi;
@@ -182,7 +255,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
case VIDIOC_S_FMT:
{
- int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_NTSC);
+ int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_525_60);
int vbi_offset = is_pal ? 1 : 0;
int i, x;
u8 lcr[24];
@@ -211,7 +284,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
cx25840_vbi_setup(client);
/* Sliced VBI */
- cx25840_write(client, 0x404, 0x36); /* Ancillery data */
+ cx25840_write(client, 0x404, 0x32); /* Ancillary data */
cx25840_write(client, 0x406, 0x13);
cx25840_write(client, 0x47f, vbi_offset);
@@ -248,8 +321,18 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
}
}
- for (x = 1, i = 0x424; i <= 0x434; i++, x++) {
- cx25840_write(client, i, lcr[6 + x]);
+ if (is_pal) {
+ for (x = 1, i = 0x424; i <= 0x434; i++, x++) {
+ cx25840_write(client, i, lcr[6 + x]);
+ }
+ }
+ else {
+ for (x = 1, i = 0x424; i <= 0x430; i++, x++) {
+ cx25840_write(client, i, lcr[9 + x]);
+ }
+ for (i = 0x431; i <= 0x434; i++) {
+ cx25840_write(client, i, 0);
+ }
}
cx25840_write(client, 0x43c, 0x16);
@@ -257,7 +340,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
if (is_pal) {
cx25840_write(client, 0x474, 0x2a);
} else {
- cx25840_write(client, 0x474, 0x1a + 6);
+ cx25840_write(client, 0x474, 0x22);
}
break;
}
@@ -278,7 +361,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
id1 = p[-1];
id2 = p[0] & 0xf;
l = p[2] & 0x3f;
- l += 5;
+ l += state->vbi_line_offset;
p += 4;
switch (id2) {
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 6302739..91e1c48 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -11,6 +11,7 @@ config VIDEO_CX88
select VIDEO_BUF
select VIDEO_TUNER
select VIDEO_TVEEPROM
+ select VIDEO_CX2341X
select VIDEO_IR
---help---
This is a video4linux driver for Conexant 2388x based
@@ -61,6 +62,7 @@ config VIDEO_CX88_DVB_ALL_FRONTENDS
select DVB_LGDT330X
select DVB_NXT200X
select DVB_CX24123
+ select DVB_ISL6421
---help---
This builds cx88-dvb with all currently supported frontend
demodulators. If you wish to tweak your configuration, and
@@ -139,6 +141,7 @@ config VIDEO_CX88_DVB_CX24123
default y
depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
select DVB_CX24123
+ select DVB_ISL6421
---help---
This adds DVB-S support for cards based on the
Connexant 2388x chip and the CX24123 demodulator.
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 320b3d9..2194cbe 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -4,7 +4,7 @@
* PCI function #1 of the cx2388x.
*
* (c) 2005,2006 Ricardo Cerqueira <v4l@cerqueira.org>
- * (c) 2005 Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ * (c) 2005 Mauro Carvalho Chehab <mchehab@infradead.org>
* Based on a dummy cx88 module by Gerd Knorr <kraxel@bytesex.org>
* Based on dummy.c by Jaroslav Kysela <perex@suse.cz>
*
@@ -111,7 +111,7 @@ MODULE_PARM_DESC(index, "Index value for cx88x capture interface(s).");
MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards");
MODULE_AUTHOR("Ricardo Cerqueira");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@brturbo.com.br>");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Conexant,23881},"
"{{Conexant,23882},"
@@ -696,7 +696,6 @@ static int __devinit snd_cx88_create(struct snd_card *card,
chip->irq = -1;
spin_lock_init(&chip->reg_lock);
- cx88_reset(core);
chip->core = core;
/* get irq */
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index e100d8e..67fd330 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -30,9 +30,10 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/firmware.h>
+#include <media/v4l2-common.h>
+#include <media/cx2341x.h>
#include "cx88.h"
-#include <media/v4l2-common.h>
MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards");
MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>, Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -53,7 +54,6 @@ static LIST_HEAD(cx8802_devlist);
/* ------------------------------------------------------------------ */
-#define BLACKBIRD_FIRM_ENC_FILENAME "blackbird-fw-enc.bin"
#define BLACKBIRD_FIRM_IMAGE_SIZE 256*1024
/* defines below are from ivtv-driver.h */
@@ -63,8 +63,6 @@ static LIST_HEAD(cx8802_devlist);
/* Firmware API commands */
#define IVTV_API_STD_TIMEOUT 500
-#define BLACKBIRD_API_PING 0x80
-#define BLACKBIRD_API_BEGIN_CAPTURE 0x81
enum blackbird_capture_type {
BLACKBIRD_MPEG_CAPTURE,
BLACKBIRD_RAW_CAPTURE,
@@ -78,205 +76,29 @@ enum blackbird_capture_bits {
BLACKBIRD_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
BLACKBIRD_RAW_BITS_TO_HOST_CAPTURE = 0x10
};
-#define BLACKBIRD_API_END_CAPTURE 0x82
enum blackbird_capture_end {
BLACKBIRD_END_AT_GOP, /* stop at the end of gop, generate irq */
BLACKBIRD_END_NOW, /* stop immediately, no irq */
};
-#define BLACKBIRD_API_SET_AUDIO_ID 0x89
-#define BLACKBIRD_API_SET_VIDEO_ID 0x8B
-#define BLACKBIRD_API_SET_PCR_ID 0x8D
-#define BLACKBIRD_API_SET_FRAMERATE 0x8F
enum blackbird_framerate {
BLACKBIRD_FRAMERATE_NTSC_30, /* NTSC: 30fps */
BLACKBIRD_FRAMERATE_PAL_25 /* PAL: 25fps */
};
-#define BLACKBIRD_API_SET_RESOLUTION 0x91
-#define BLACKBIRD_API_SET_VIDEO_BITRATE 0x95
-enum blackbird_video_bitrate_type {
- BLACKBIRD_VIDEO_VBR,
- BLACKBIRD_VIDEO_CBR
-};
-#define BLACKBIRD_PEAK_RATE_DIVISOR 400
-enum blackbird_mux_rate {
- BLACKBIRD_MUX_RATE_DEFAULT,
- /* dvd mux rate: multiply by 400 to get the actual rate */
- BLACKBIRD_MUX_RATE_DVD = 25200
-};
-#define BLACKBIRD_API_SET_GOP_STRUCTURE 0x97
-#define BLACKBIRD_API_SET_ASPECT_RATIO 0x99
-enum blackbird_aspect_ratio {
- BLACKBIRD_ASPECT_RATIO_FORBIDDEN,
- BLACKBIRD_ASPECT_RATIO_1_1_SQUARE,
- BLACKBIRD_ASPECT_RATIO_4_3,
- BLACKBIRD_ASPECT_RATIO_16_9,
- BLACKBIRD_ASPECT_RATIO_221_100,
- BLACKBIRD_ASPECT_RATIO_RESERVED
-};
-#define BLACKBIRD_API_SET_DNR_MODE 0x9B
-enum blackbird_dnr_bits {
- BLACKBIRD_DNR_BITS_MANUAL,
- BLACKBIRD_DNR_BITS_AUTO_SPATIAL,
- BLACKBIRD_DNR_BITS_AUTO_TEMPORAL,
- BLACKBIRD_DNR_BITS_AUTO
-};
-enum blackbird_median_filter {
- BLACKBIRD_MEDIAN_FILTER_DISABLED,
- BLACKBIRD_MEDIAN_FILTER_HORIZONTAL,
- BLACKBIRD_MEDIAN_FILTER_VERTICAL,
- BLACKBIRD_MEDIAN_FILTER_HV,
- BLACKBIRD_MEDIAN_FILTER_DIAGONAL
-};
-#define BLACKBIRD_API_SET_MANUAL_DNR 0x9D
-#define BLACKBIRD_API_SET_DNR_MEDIAN 0x9F
-#define BLACKBIRD_API_SET_SPATIAL_FILTER 0xA1
-enum blackbird_spatial_filter_luma {
- BLACKBIRD_SPATIAL_FILTER_LUMA_DISABLED,
- BLACKBIRD_SPATIAL_FILTER_LUMA_1D_HORIZ,
- BLACKBIRD_SPATIAL_FILTER_LUMA_1D_VERT,
- BLACKBIRD_SPATIAL_FILTER_LUMA_2D_HV, /* separable, default */
- BLACKBIRD_SPATIAL_FILTER_LUMA_2D_SYMM /* symmetric non-separable */
-};
-enum blackbird_spatial_filter_chroma {
- BLACKBIRD_SPATIAL_FILTER_CHROMA_DISABLED,
- BLACKBIRD_SPATIAL_FILTER_CHROMA_1D_HORIZ /* default */
-};
-#define BLACKBIRD_API_SET_3_2_PULLDOWN 0xB1
-enum blackbird_pulldown {
- BLACKBIRD_3_2_PULLDOWN_DISABLED,
- BLACKBIRD_3_2_PULLDOWN_ENABLED
-};
-#define BLACKBIRD_API_SET_VBI_LINE_NO 0xB7
-enum blackbird_vbi_line_bits {
- BLACKBIRD_VBI_LINE_BITS_TOP_FIELD,
- BLACKBIRD_VBI_LINE_BITS_BOT_FIELD = (1 << 31),
- BLACKBIRD_VBI_LINE_BITS_ALL_LINES = 0xFFFFFFFF
-};
-enum blackbird_vbi_line {
- BLACKBIRD_VBI_LINE_DISABLED,
- BLACKBIRD_VBI_LINE_ENABLED
-};
-enum blackbird_vbi_slicing {
- BLACKBIRD_VBI_SLICING_NONE,
- BLACKBIRD_VBI_SLICING_CLOSED_CAPTION
-};
-#define BLACKBIRD_API_SET_STREAM_TYPE 0xB9
-enum blackbird_stream_type {
- BLACKBIRD_STREAM_PROGRAM,
- BLACKBIRD_STREAM_TRANSPORT,
- BLACKBIRD_STREAM_MPEG1,
- BLACKBIRD_STREAM_PES_AV,
- BLACKBIRD_STREAM_UNKNOWN4,
- BLACKBIRD_STREAM_PES_VIDEO,
- BLACKBIRD_STREAM_UNKNOWN6,
- BLACKBIRD_STREAM_PES_AUDIO,
- BLACKBIRD_STREAM_UNKNOWN8,
- BLACKBIRD_STREAM_UNKNOWN9, /* audio/pcm ? */
- BLACKBIRD_STREAM_DVD,
- BLACKBIRD_STREAM_VCD,
- BLACKBIRD_STREAM_UNKNOWN12 /* svcd/xvcd ? */
-};
-#define BLACKBIRD_API_SET_OUTPUT_PORT 0xBB
enum blackbird_stream_port {
BLACKBIRD_OUTPUT_PORT_MEMORY,
BLACKBIRD_OUTPUT_PORT_STREAMING,
BLACKBIRD_OUTPUT_PORT_SERIAL
};
-#define BLACKBIRD_API_SET_AUDIO_PARAMS 0xBD
-enum blackbird_audio_bits_sample_rate {
- BLACKBIRD_AUDIO_BITS_44100HZ,
- BLACKBIRD_AUDIO_BITS_48000HZ,
- BLACKBIRD_AUDIO_BITS_32000HZ,
- BLACKBIRD_AUDIO_BITS_RESERVED_HZ,
-};
-enum blackbird_audio_bits_encoding {
- BLACKBIRD_AUDIO_BITS_LAYER_1 = 0x1 << 2,
- BLACKBIRD_AUDIO_BITS_LAYER_2 = 0x2 << 2,
-};
-enum blackbird_audio_bits_bitrate_layer_1 {
- BLACKBIRD_AUDIO_BITS_LAYER_1_FREE_FORMAT,
- BLACKBIRD_AUDIO_BITS_LAYER_1_32 = 0x01 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_64 = 0x02 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_96 = 0x03 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_128 = 0x04 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_160 = 0x05 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_192 = 0x06 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_224 = 0x07 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_256 = 0x08 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_288 = 0x09 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_320 = 0x0A << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_352 = 0x0B << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_384 = 0x0C << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_416 = 0x0D << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_448 = 0x0E << 4,
-};
-enum blackbird_audio_bits_bitrate_layer_2 {
- BLACKBIRD_AUDIO_BITS_LAYER_2_FREE_FORMAT,
- BLACKBIRD_AUDIO_BITS_LAYER_2_32 = 0x01 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_48 = 0x02 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_56 = 0x03 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_64 = 0x04 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_80 = 0x05 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_96 = 0x06 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_112 = 0x07 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_128 = 0x08 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_160 = 0x09 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_192 = 0x0A << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_224 = 0x0B << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_256 = 0x0C << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_320 = 0x0D << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_384 = 0x0E << 4,
-};
-enum blackbird_audio_bits_mode {
- BLACKBIRD_AUDIO_BITS_STEREO,
- BLACKBIRD_AUDIO_BITS_JOINT_STEREO = 0x1 << 8,
- BLACKBIRD_AUDIO_BITS_DUAL = 0x2 << 8,
- BLACKBIRD_AUDIO_BITS_MONO = 0x3 << 8,
-};
-enum blackbird_audio_bits_mode_extension {
- BLACKBIRD_AUDIO_BITS_BOUND_4,
- BLACKBIRD_AUDIO_BITS_BOUND_8 = 0x1 << 10,
- BLACKBIRD_AUDIO_BITS_BOUND_12 = 0x2 << 10,
- BLACKBIRD_AUDIO_BITS_BOUND_16 = 0x3 << 10,
-};
-enum blackbird_audio_bits_emphasis {
- BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE,
- BLACKBIRD_AUDIO_BITS_EMPHASIS_50_15 = 0x1 << 12,
- BLACKBIRD_AUDIO_BITS_EMPHASIS_RESERVED = 0x2 << 12,
- BLACKBIRD_AUDIO_BITS_EMPHASIS_CCITT_J17 = 0x3 << 12,
-};
-enum blackbird_audio_bits_crc {
- BLACKBIRD_AUDIO_BITS_CRC_OFF,
- BLACKBIRD_AUDIO_BITS_CRC_ON = 0x1 << 14,
-};
-enum blackbird_audio_bits_copyright {
- BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF,
- BLACKBIRD_AUDIO_BITS_COPYRIGHT_ON = 0x1 << 15,
-};
-enum blackbird_audio_bits_original {
- BLACKBIRD_AUDIO_BITS_COPY,
- BLACKBIRD_AUDIO_BITS_ORIGINAL = 0x1 << 16,
-};
-#define BLACKBIRD_API_HALT 0xC3
-#define BLACKBIRD_API_GET_VERSION 0xC4
-#define BLACKBIRD_API_SET_GOP_CLOSURE 0xC5
-enum blackbird_gop_closure {
- BLACKBIRD_GOP_CLOSURE_OFF,
- BLACKBIRD_GOP_CLOSURE_ON,
-};
-#define BLACKBIRD_API_DATA_XFER_STATUS 0xC6
enum blackbird_data_xfer_status {
BLACKBIRD_MORE_BUFFERS_FOLLOW,
BLACKBIRD_LAST_BUFFER,
};
-#define BLACKBIRD_API_PROGRAM_INDEX_INFO 0xC7
enum blackbird_picture_mask {
BLACKBIRD_PICTURE_MASK_NONE,
BLACKBIRD_PICTURE_MASK_I_FRAMES,
BLACKBIRD_PICTURE_MASK_I_P_FRAMES = 0x3,
BLACKBIRD_PICTURE_MASK_ALL_FRAMES = 0x7,
};
-#define BLACKBIRD_API_SET_VBI_PARAMS 0xC8
enum blackbird_vbi_mode_bits {
BLACKBIRD_VBI_BITS_SLICED,
BLACKBIRD_VBI_BITS_RAW,
@@ -288,33 +110,23 @@ enum blackbird_vbi_insertion_bits {
BLACKBIRD_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
BLACKBIRD_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
};
-#define BLACKBIRD_API_SET_DMA_BLOCK_SIZE 0xC9
enum blackbird_dma_unit {
BLACKBIRD_DMA_BYTES,
BLACKBIRD_DMA_FRAMES,
};
-#define BLACKBIRD_API_DMA_TRANSFER_INFO 0xCA
-#define BLACKBIRD_API_DMA_TRANSFER_STAT 0xCB
enum blackbird_dma_transfer_status_bits {
BLACKBIRD_DMA_TRANSFER_BITS_DONE = 0x01,
BLACKBIRD_DMA_TRANSFER_BITS_ERROR = 0x04,
BLACKBIRD_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
};
-#define BLACKBIRD_API_SET_DMA2HOST_ADDR 0xCC
-#define BLACKBIRD_API_INIT_VIDEO_INPUT 0xCD
-#define BLACKBIRD_API_SET_FRAMESKIP 0xD0
-#define BLACKBIRD_API_PAUSE 0xD2
enum blackbird_pause {
BLACKBIRD_PAUSE_ENCODING,
BLACKBIRD_RESUME_ENCODING,
};
-#define BLACKBIRD_API_REFRESH_INPUT 0xD3
-#define BLACKBIRD_API_SET_COPYRIGHT 0xD4
enum blackbird_copyright {
BLACKBIRD_COPYRIGHT_OFF,
BLACKBIRD_COPYRIGHT_ON,
};
-#define BLACKBIRD_API_SET_NOTIFICATION 0xD5
enum blackbird_notification_type {
BLACKBIRD_NOTIFICATION_REFRESH,
};
@@ -325,7 +137,6 @@ enum blackbird_notification_status {
enum blackbird_notification_mailbox {
BLACKBIRD_NOTIFICATION_NO_MAILBOX = -1,
};
-#define BLACKBIRD_API_SET_CAPTURE_LINES 0xD6
enum blackbird_field1_lines {
BLACKBIRD_FIELD1_SAA7114 = 0x00EF, /* 239 */
BLACKBIRD_FIELD1_SAA7115 = 0x00F0, /* 240 */
@@ -336,12 +147,10 @@ enum blackbird_field2_lines {
BLACKBIRD_FIELD2_SAA7115 = 0x00F0, /* 240 */
BLACKBIRD_FIELD2_MICRONAS = 0x0106, /* 262 */
};
-#define BLACKBIRD_API_SET_CUSTOM_DATA 0xD7
enum blackbird_custom_data_type {
BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,
BLACKBIRD_CUSTOM_PRIVATE_PACKET,
};
-#define BLACKBIRD_API_MUTE_VIDEO 0xD9
enum blackbird_mute {
BLACKBIRD_UNMUTE,
BLACKBIRD_MUTE,
@@ -356,7 +165,6 @@ enum blackbird_mute_video_shift {
BLACKBIRD_MUTE_VIDEO_U_SHIFT = 16,
BLACKBIRD_MUTE_VIDEO_Y_SHIFT = 24,
};
-#define BLACKBIRD_API_MUTE_AUDIO 0xDA
/* Registers */
#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8 /*| IVTV_REG_OFFSET*/)
@@ -498,15 +306,12 @@ static int register_read(struct cx88_core *core, u32 address, u32 *value)
/* ------------------------------------------------------------------ */
-/* We don't need to call the API often, so using just one mailbox will probably suffice */
-static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
- u32 inputcnt, u32 outputcnt, ...)
+static int blackbird_mbox_func(void *priv, int command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
{
+ struct cx8802_dev *dev = priv;
unsigned long timeout;
u32 value, flag, retval;
int i;
- va_list args;
- va_start(args, outputcnt);
dprintk(1,"%s: 0x%X\n", __FUNCTION__, command);
@@ -530,12 +335,11 @@ static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
/* write command + args + fill remaining with zeros */
memory_write(dev->core, dev->mailbox + 1, command); /* command code */
memory_write(dev->core, dev->mailbox + 3, IVTV_API_STD_TIMEOUT); /* timeout */
- for (i = 0; i < inputcnt ; i++) {
- value = va_arg(args, int);
- memory_write(dev->core, dev->mailbox + 4 + i, value);
- dprintk(1, "API Input %d = %d\n", i, value);
+ for (i = 0; i < in; i++) {
+ memory_write(dev->core, dev->mailbox + 4 + i, data[i]);
+ dprintk(1, "API Input %d = %d\n", i, data[i]);
}
- for (; i < 16 ; i++)
+ for (; i < CX2341X_MBOX_MAX_DATA; i++)
memory_write(dev->core, dev->mailbox + 4 + i, 0);
flag |= 3; /* tell 'em we're done writing */
@@ -555,12 +359,10 @@ static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
}
/* read output values */
- for (i = 0; i < outputcnt ; i++) {
- int *vptr = va_arg(args, int *);
- memory_read(dev->core, dev->mailbox + 4 + i, vptr);
- dprintk(1, "API Output %d = %d\n", i, *vptr);
+ for (i = 0; i < out; i++) {
+ memory_read(dev->core, dev->mailbox + 4 + i, data + i);
+ dprintk(1, "API Output %d = %d\n", i, data[i]);
}
- va_end(args);
memory_read(dev->core, dev->mailbox + 2, &retval);
dprintk(1, "API result = %d\n",retval);
@@ -569,7 +371,29 @@ static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
memory_write(dev->core, dev->mailbox, flag);
return retval;
}
+/* ------------------------------------------------------------------ */
+/* We don't need to call the API often, so using just one mailbox will probably suffice */
+static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
+ u32 inputcnt, u32 outputcnt, ...)
+{
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ va_list vargs;
+ int i, err;
+
+ va_start(vargs, outputcnt);
+
+ for (i = 0; i < inputcnt; i++) {
+ data[i] = va_arg(vargs, int);
+ }
+ err = blackbird_mbox_func(dev, command, inputcnt, outputcnt, data);
+ for (i = 0; i < outputcnt; i++) {
+ int *vptr = va_arg(vargs, int *);
+ *vptr = data[i];
+ }
+ va_end(vargs);
+ return err;
+}
static int blackbird_find_mailbox(struct cx8802_dev *dev)
{
@@ -614,13 +438,13 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
if (retval < 0)
dprintk(0, "Error with register_write\n");
- retval = request_firmware(&firmware, BLACKBIRD_FIRM_ENC_FILENAME,
+ retval = request_firmware(&firmware, CX2341X_FIRM_ENC_FILENAME,
&dev->pci->dev);
if (retval != 0) {
dprintk(0, "ERROR: Hotplug firmware request failed (%s).\n",
- BLACKBIRD_FIRM_ENC_FILENAME);
+ CX2341X_FIRM_ENC_FILENAME);
dprintk(0, "Please fix your hotplug setup, the board will "
"not work without firmware loaded!\n");
return -1;
@@ -686,12 +510,19 @@ DB* DVD | MPEG2 | 720x576PAL | CBR | 600 :Good | 6000 Kbps | 25fps | M
*DB: "DirectBurn"
*/
-static struct blackbird_dnr default_dnr_params = {
- .mode = BLACKBIRD_DNR_BITS_MANUAL,
- .type = BLACKBIRD_MEDIAN_FILTER_DISABLED,
- .spatial = 0,
- .temporal = 0
-};
+static void blackbird_codec_settings(struct cx8802_dev *dev)
+{
+ /* assign frame size */
+ blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
+ dev->height, dev->width);
+
+ dev->params.width = dev->width;
+ dev->params.height = dev->height;
+ dev->params.is_50hz = (dev->core->tvnorm->id & V4L2_STD_625_50) != 0;
+
+ cx2341x_update(dev, blackbird_mbox_func, NULL, &dev->params);
+}
+
static struct v4l2_mpeg_compression default_mpeg_params = {
.st_type = V4L2_MPEG_PS_2,
.st_bitrate = {
@@ -712,7 +543,7 @@ static struct v4l2_mpeg_compression default_mpeg_params = {
.target = 224,
.max = 224
},
- .au_sample_rate = 44100,
+ .au_sample_rate = 48000,
.au_pesid = 0,
.vi_type = V4L2_MPEG_VI_2,
.vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3,
@@ -723,524 +554,13 @@ static struct v4l2_mpeg_compression default_mpeg_params = {
.max = 6000
},
.vi_frame_rate = 25,
- .vi_frames_per_gop = 15,
+ .vi_frames_per_gop = 12,
.vi_bframes_count = 2,
.vi_pesid = 0,
- .closed_gops = 0,
+ .closed_gops = 1,
.pulldown = 0
};
-static enum blackbird_stream_type mpeg_stream_types[] = {
- [V4L2_MPEG_SS_1] = BLACKBIRD_STREAM_MPEG1,
- [V4L2_MPEG_PS_2] = BLACKBIRD_STREAM_PROGRAM,
- [V4L2_MPEG_TS_2] = BLACKBIRD_STREAM_TRANSPORT,
- [V4L2_MPEG_PS_DVD] = BLACKBIRD_STREAM_DVD,
-};
-static enum blackbird_aspect_ratio mpeg_stream_ratios[] = {
- [V4L2_MPEG_ASPECT_SQUARE] = BLACKBIRD_ASPECT_RATIO_1_1_SQUARE,
- [V4L2_MPEG_ASPECT_4_3] = BLACKBIRD_ASPECT_RATIO_4_3,
- [V4L2_MPEG_ASPECT_16_9] = BLACKBIRD_ASPECT_RATIO_16_9,
- [V4L2_MPEG_ASPECT_1_221] = BLACKBIRD_ASPECT_RATIO_221_100,
-};
-static enum blackbird_video_bitrate_type mpeg_video_bitrates[] = {
- [V4L2_BITRATE_NONE] = BLACKBIRD_VIDEO_CBR,
- [V4L2_BITRATE_CBR] = BLACKBIRD_VIDEO_CBR,
- [V4L2_BITRATE_VBR] = BLACKBIRD_VIDEO_VBR,
-};
-/* find the best layer I/II bitrate to fit a given numeric value */
-struct bitrate_bits {
- u32 bits; /* layer bits for the best fit */
- u32 rate; /* actual numeric value for the layer best fit */
-};
-struct bitrate_approximation {
- u32 target; /* numeric value of the rate we want */
- struct bitrate_bits layer[2];
-};
-static struct bitrate_approximation mpeg_audio_bitrates[] = {
- /* target layer[0].bits layer[0].rate layer[1].bits layer[1].rate */
- { 0, { { 0, 0, }, { 0, 0, }, }, },
- { 32, { { BLACKBIRD_AUDIO_BITS_LAYER_1_32 , 32, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_32 , 32, }, }, },
- { 48, { { BLACKBIRD_AUDIO_BITS_LAYER_1_64 , 64, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_48 , 48, }, }, },
- { 56, { { BLACKBIRD_AUDIO_BITS_LAYER_1_64 , 64, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_56 , 56, }, }, },
- { 64, { { BLACKBIRD_AUDIO_BITS_LAYER_1_64 , 64, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_64 , 64, }, }, },
- { 80, { { BLACKBIRD_AUDIO_BITS_LAYER_1_96 , 96, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_80 , 80, }, }, },
- { 96, { { BLACKBIRD_AUDIO_BITS_LAYER_1_96 , 96, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_96 , 96, }, }, },
- { 112, { { BLACKBIRD_AUDIO_BITS_LAYER_1_128, 128, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_112, 112, }, }, },
- { 128, { { BLACKBIRD_AUDIO_BITS_LAYER_1_128, 128, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_128, 128, }, }, },
- { 160, { { BLACKBIRD_AUDIO_BITS_LAYER_1_160, 160, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_160, 160, }, }, },
- { 192, { { BLACKBIRD_AUDIO_BITS_LAYER_1_192, 192, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_192, 192, }, }, },
- { 224, { { BLACKBIRD_AUDIO_BITS_LAYER_1_224, 224, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_224, 224, }, }, },
- { 256, { { BLACKBIRD_AUDIO_BITS_LAYER_1_256, 256, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_256, 256, }, }, },
- { 288, { { BLACKBIRD_AUDIO_BITS_LAYER_1_288, 288, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_320, 320, }, }, },
- { 320, { { BLACKBIRD_AUDIO_BITS_LAYER_1_320, 320, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_320, 320, }, }, },
- { 352, { { BLACKBIRD_AUDIO_BITS_LAYER_1_352, 352, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
- { 384, { { BLACKBIRD_AUDIO_BITS_LAYER_1_384, 384, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
- { 416, { { BLACKBIRD_AUDIO_BITS_LAYER_1_416, 416, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
- { 448, { { BLACKBIRD_AUDIO_BITS_LAYER_1_448, 448, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
-};
-static const int BITRATES_SIZE = ARRAY_SIZE(mpeg_audio_bitrates);
-
-static void blackbird_set_default_params(struct cx8802_dev *dev)
-{
- struct v4l2_mpeg_compression *params = &dev->params;
- u32 au_params;
-
- /* assign stream type */
- if( params->st_type >= ARRAY_SIZE(mpeg_stream_types) )
- params->st_type = V4L2_MPEG_PS_2;
- if( params->st_type == V4L2_MPEG_SS_1 )
- params->vi_type = V4L2_MPEG_VI_1;
- else
- params->vi_type = V4L2_MPEG_VI_2;
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, mpeg_stream_types[params->st_type]);
-
- /* assign framerate */
- if( params->vi_frame_rate <= 25 )
- {
- params->vi_frame_rate = 25;
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_PAL_25);
- }
- else
- {
- params->vi_frame_rate = 30;
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_NTSC_30);
- }
-
- /* assign aspect ratio */
- if( params->vi_aspect_ratio >= ARRAY_SIZE(mpeg_stream_ratios) )
- params->vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3;
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_ASPECT_RATIO, 1, 0, mpeg_stream_ratios[params->vi_aspect_ratio]);
-
- /* assign gop properties */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_STRUCTURE, 2, 0, params->vi_frames_per_gop, params->vi_bframes_count+1);
-
- /* assign gop closure */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_CLOSURE, 1, 0, params->closed_gops);
-
- /* assign 3 2 pulldown */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_3_2_PULLDOWN, 1, 0, params->pulldown);
-
- /* make sure the params are within bounds */
- if( params->st_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
- params->vi_bitrate.mode = V4L2_BITRATE_NONE;
- if( params->vi_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
- params->vi_bitrate.mode = V4L2_BITRATE_NONE;
- if( params->au_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
- params->au_bitrate.mode = V4L2_BITRATE_NONE;
-
- /* assign audio properties */
- /* note: it's not necessary to set the samplerate, the mpeg encoder seems to autodetect/adjust */
- au_params = BLACKBIRD_AUDIO_BITS_STEREO |
- /* BLACKBIRD_AUDIO_BITS_BOUND_4 | */
- BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE |
- BLACKBIRD_AUDIO_BITS_CRC_OFF |
- BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF |
- BLACKBIRD_AUDIO_BITS_COPY |
- 0;
- if( params->au_sample_rate <= 32000 )
- {
- params->au_sample_rate = 32000;
- au_params |= BLACKBIRD_AUDIO_BITS_32000HZ;
- }
- else if( params->au_sample_rate <= 44100 )
- {
- params->au_sample_rate = 44100;
- au_params |= BLACKBIRD_AUDIO_BITS_44100HZ;
- }
- else
- {
- params->au_sample_rate = 48000;
- au_params |= BLACKBIRD_AUDIO_BITS_48000HZ;
- }
- if( params->au_type == V4L2_MPEG_AU_2_I )
- {
- au_params |= BLACKBIRD_AUDIO_BITS_LAYER_1;
- }
- else
- {
- /* TODO: try to handle the other formats more gracefully */
- params->au_type = V4L2_MPEG_AU_2_II;
- au_params |= BLACKBIRD_AUDIO_BITS_LAYER_2;
- }
- if( params->au_bitrate.mode )
- {
- int layer;
-
- if( params->au_bitrate.mode == V4L2_BITRATE_CBR )
- params->au_bitrate.max = params->vi_bitrate.target;
- else
- params->au_bitrate.target = params->vi_bitrate.max;
-
- layer = params->au_type;
- if( params->au_bitrate.target == 0 )
- {
- /* TODO: use the minimum possible bitrate instead of 0 ? */
- au_params |= 0;
- }
- else if( params->au_bitrate.target >=
- mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate )
- {
- /* clamp the bitrate to the max supported by the standard */
- params->au_bitrate.target = mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate;
- params->au_bitrate.max = params->au_bitrate.target;
- au_params |= mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].bits;
- }
- else
- {
- /* round up to the nearest supported bitrate */
- int i;
- for(i = 1; i < BITRATES_SIZE; i++)
- {
- if( params->au_bitrate.target > mpeg_audio_bitrates[i-1].layer[layer].rate &&
- params->au_bitrate.target <= mpeg_audio_bitrates[i].layer[layer].rate )
- {
- params->au_bitrate.target = mpeg_audio_bitrates[i].layer[layer].rate;
- params->au_bitrate.max = params->au_bitrate.target;
- au_params |= mpeg_audio_bitrates[i].layer[layer].bits;
- break;
- }
- }
- }
- }
- else
- {
- /* TODO: ??? */
- params->au_bitrate.target = params->au_bitrate.max = 0;
- au_params |= 0;
- }
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_AUDIO_PARAMS, 1, 0, au_params );
-
- /* assign bitrates */
- if( params->vi_bitrate.mode )
- {
- /* bitrate is set, let's figure out the cbr/vbr mess */
- if( params->vi_bitrate.max < params->vi_bitrate.target )
- {
- if( params->vi_bitrate.mode == V4L2_BITRATE_CBR )
- params->vi_bitrate.max = params->vi_bitrate.target;
- else
- params->vi_bitrate.target = params->vi_bitrate.max;
- }
- }
- else
- {
- if( params->st_bitrate.max < params->st_bitrate.target )
- {
- if( params->st_bitrate.mode == V4L2_BITRATE_VBR )
- params->st_bitrate.target = params->st_bitrate.max;
- else
- params->st_bitrate.max = params->st_bitrate.target;
- }
- /* calculate vi_bitrate = st_bitrate - au_bitrate */
- params->vi_bitrate.max = params->st_bitrate.max - params->au_bitrate.max;
- params->vi_bitrate.target = params->st_bitrate.target - params->au_bitrate.target;
- }
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_VIDEO_BITRATE, 4, 0,
- mpeg_video_bitrates[params->vi_bitrate.mode],
- params->vi_bitrate.target * 1000, /* kbps -> bps */
- params->vi_bitrate.max * 1000 / BLACKBIRD_PEAK_RATE_DIVISOR, /* peak/400 */
- BLACKBIRD_MUX_RATE_DEFAULT /*, 0x70*/); /* encoding buffer, ckennedy */
-
- /* TODO: implement the stream ID stuff:
- ts_pid_pmt, ts_pid_audio, ts_pid_video, ts_pid_pcr,
- ps_size, au_pesid, vi_pesid
- */
-}
-#define CHECK_PARAM( name ) ( dev->params.name != params->name )
-#define IF_PARAM( name ) if( CHECK_PARAM( name ) )
-#define UPDATE_PARAM( name ) dev->params.name = params->name
-void blackbird_set_params(struct cx8802_dev *dev, struct v4l2_mpeg_compression *params)
-{
- u32 au_params;
-
- /* assign stream type */
- if( params->st_type >= ARRAY_SIZE(mpeg_stream_types) )
- params->st_type = V4L2_MPEG_PS_2;
- if( params->st_type == V4L2_MPEG_SS_1 )
- params->vi_type = V4L2_MPEG_VI_1;
- else
- params->vi_type = V4L2_MPEG_VI_2;
- if( CHECK_PARAM( st_type ) || CHECK_PARAM( vi_type ) )
- {
- UPDATE_PARAM( st_type );
- UPDATE_PARAM( vi_type );
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, mpeg_stream_types[params->st_type]);
- }
-
- /* assign framerate */
- if( params->vi_frame_rate <= 25 )
- params->vi_frame_rate = 25;
- else
- params->vi_frame_rate = 30;
- IF_PARAM( vi_frame_rate )
- {
- UPDATE_PARAM( vi_frame_rate );
- if( params->vi_frame_rate == 25 )
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_PAL_25);
- else
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_NTSC_30);
- }
-
- /* assign aspect ratio */
- if( params->vi_aspect_ratio >= ARRAY_SIZE(mpeg_stream_ratios) )
- params->vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3;
- IF_PARAM( vi_aspect_ratio )
- {
- UPDATE_PARAM( vi_aspect_ratio );
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_ASPECT_RATIO, 1, 0, mpeg_stream_ratios[params->vi_aspect_ratio]);
- }
-
- /* assign gop properties */
- if( CHECK_PARAM( vi_frames_per_gop ) || CHECK_PARAM( vi_bframes_count ) )
- {
- UPDATE_PARAM( vi_frames_per_gop );
- UPDATE_PARAM( vi_bframes_count );
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_STRUCTURE, 2, 0, params->vi_frames_per_gop, params->vi_bframes_count+1);
- }
-
- /* assign gop closure */
- IF_PARAM( closed_gops )
- {
- UPDATE_PARAM( closed_gops );
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_CLOSURE, 1, 0, params->closed_gops);
- }
-
- /* assign 3 2 pulldown */
- IF_PARAM( pulldown )
- {
- UPDATE_PARAM( pulldown );
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_3_2_PULLDOWN, 1, 0, params->pulldown);
- }
-
- /* make sure the params are within bounds */
- if( params->st_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
- params->vi_bitrate.mode = V4L2_BITRATE_NONE;
- if( params->vi_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
- params->vi_bitrate.mode = V4L2_BITRATE_NONE;
- if( params->au_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
- params->au_bitrate.mode = V4L2_BITRATE_NONE;
-
- /* assign audio properties */
- /* note: it's not necessary to set the samplerate, the mpeg encoder seems to autodetect/adjust */
- au_params = BLACKBIRD_AUDIO_BITS_STEREO |
- /* BLACKBIRD_AUDIO_BITS_BOUND_4 | */
- BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE |
- BLACKBIRD_AUDIO_BITS_CRC_OFF |
- BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF |
- BLACKBIRD_AUDIO_BITS_COPY |
- 0;
- if( params->au_sample_rate < 32000 )
- {
- params->au_sample_rate = 32000;
- au_params |= BLACKBIRD_AUDIO_BITS_32000HZ;
- }
- else if( params->au_sample_rate < 44100 )
- {
- params->au_sample_rate = 44100;
- au_params |= BLACKBIRD_AUDIO_BITS_44100HZ;
- }
- else
- {
- params->au_sample_rate = 48000;
- au_params |= BLACKBIRD_AUDIO_BITS_48000HZ;
- }
- if( params->au_type == V4L2_MPEG_AU_2_I )
- {
- au_params |= BLACKBIRD_AUDIO_BITS_LAYER_1;
- }
- else
- {
- /* TODO: try to handle the other formats more gracefully */
- params->au_type = V4L2_MPEG_AU_2_II;
- au_params |= BLACKBIRD_AUDIO_BITS_LAYER_2;
- }
- if( params->au_bitrate.mode )
- {
- int layer;
-
- if( params->au_bitrate.mode == V4L2_BITRATE_CBR )
- params->au_bitrate.max = params->vi_bitrate.target;
- else
- params->au_bitrate.target = params->vi_bitrate.max;
-
- layer = params->au_type;
- if( params->au_bitrate.target == 0 )
- {
- /* TODO: use the minimum possible bitrate instead of 0 ? */
- au_params |= 0;
- }
- else if( params->au_bitrate.target >=
- mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate )
- {
- /* clamp the bitrate to the max supported by the standard */
- params->au_bitrate.target = mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate;
- params->au_bitrate.max = params->au_bitrate.target;
- au_params |= mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].bits;
- }
- else
- {
- /* round up to the nearest supported bitrate */
- int i;
- for(i = 1; i < BITRATES_SIZE; i++)
- {
- if( params->au_bitrate.target > mpeg_audio_bitrates[i-1].layer[layer].rate &&
- params->au_bitrate.target <= mpeg_audio_bitrates[i].layer[layer].rate )
- {
- params->au_bitrate.target = mpeg_audio_bitrates[i].layer[layer].rate;
- params->au_bitrate.max = params->au_bitrate.target;
- au_params |= mpeg_audio_bitrates[i].layer[layer].bits;
- break;
- }
- }
- }
- }
- else
- {
- /* TODO: ??? */
- params->au_bitrate.target = params->au_bitrate.max = 0;
- au_params |= 0;
- }
- if( CHECK_PARAM( au_type ) || CHECK_PARAM( au_sample_rate )
- || CHECK_PARAM( au_bitrate.mode ) || CHECK_PARAM( au_bitrate.max )
- || CHECK_PARAM( au_bitrate.target )
- )
- {
- UPDATE_PARAM( au_type );
- UPDATE_PARAM( au_sample_rate );
- UPDATE_PARAM( au_bitrate );
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_AUDIO_PARAMS, 1, 0, au_params );
- }
-
- /* assign bitrates */
- if( params->vi_bitrate.mode )
- {
- /* bitrate is set, let's figure out the cbr/vbr mess */
- if( params->vi_bitrate.max < params->vi_bitrate.target )
- {
- if( params->vi_bitrate.mode == V4L2_BITRATE_CBR )
- params->vi_bitrate.max = params->vi_bitrate.target;
- else
- params->vi_bitrate.target = params->vi_bitrate.max;
- }
- }
- else
- {
- if( params->st_bitrate.max < params->st_bitrate.target )
- {
- if( params->st_bitrate.mode == V4L2_BITRATE_VBR )
- params->st_bitrate.target = params->st_bitrate.max;
- else
- params->st_bitrate.max = params->st_bitrate.target;
- }
- /* calculate vi_bitrate = st_bitrate - au_bitrate */
- params->vi_bitrate.max = params->st_bitrate.max - params->au_bitrate.max;
- params->vi_bitrate.target = params->st_bitrate.target - params->au_bitrate.target;
- }
- UPDATE_PARAM( st_bitrate );
- if( CHECK_PARAM( vi_bitrate.mode ) || CHECK_PARAM( vi_bitrate.max )
- || CHECK_PARAM( vi_bitrate.target )
- )
- {
- UPDATE_PARAM( vi_bitrate );
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_VIDEO_BITRATE, 4, 0,
- mpeg_video_bitrates[params->vi_bitrate.mode],
- params->vi_bitrate.target * 1000, /* kbps -> bps */
- params->vi_bitrate.max * 1000 / BLACKBIRD_PEAK_RATE_DIVISOR, /* peak/400 */
- BLACKBIRD_MUX_RATE_DEFAULT /*, 0x70*/); /* encoding buffer, ckennedy */
- }
-
- /* TODO: implement the stream ID stuff:
- ts_pid_pmt, ts_pid_audio, ts_pid_video, ts_pid_pcr,
- ps_size, au_pesid, vi_pesid
- */
- UPDATE_PARAM( ts_pid_pmt );
- UPDATE_PARAM( ts_pid_audio );
- UPDATE_PARAM( ts_pid_video );
- UPDATE_PARAM( ts_pid_pcr );
- UPDATE_PARAM( ps_size );
- UPDATE_PARAM( au_pesid );
- UPDATE_PARAM( vi_pesid );
-}
-
-static void blackbird_set_default_dnr_params(struct cx8802_dev *dev)
-{
- /* assign dnr filter mode */
- if( dev->dnr_params.mode > BLACKBIRD_DNR_BITS_AUTO )
- dev->dnr_params.mode = BLACKBIRD_DNR_BITS_MANUAL;
- if( dev->dnr_params.type > BLACKBIRD_MEDIAN_FILTER_DIAGONAL )
- dev->dnr_params.type = BLACKBIRD_MEDIAN_FILTER_DISABLED;
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MODE, 2, 0,
- dev->dnr_params.mode,
- dev->dnr_params.type
- );
-
- /* assign dnr filter props*/
- if( dev->dnr_params.spatial > 15 )
- dev->dnr_params.spatial = 15;
- if( dev->dnr_params.temporal > 31 )
- dev->dnr_params.temporal = 31;
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_MANUAL_DNR, 2, 0,
- dev->dnr_params.spatial,
- dev->dnr_params.temporal
- );
-}
-#define CHECK_DNR_PARAM( name ) ( dev->dnr_params.name != dnr_params->name )
-#define UPDATE_DNR_PARAM( name ) dev->dnr_params.name = dnr_params->name
-void blackbird_set_dnr_params(struct cx8802_dev *dev, struct blackbird_dnr* dnr_params)
-{
- /* assign dnr filter mode */
- /* clamp values */
- if( dnr_params->mode > BLACKBIRD_DNR_BITS_AUTO )
- dnr_params->mode = BLACKBIRD_DNR_BITS_MANUAL;
- if( dnr_params->type > BLACKBIRD_MEDIAN_FILTER_DIAGONAL )
- dnr_params->type = BLACKBIRD_MEDIAN_FILTER_DISABLED;
- /* check if the params actually changed */
- if( CHECK_DNR_PARAM( mode ) || CHECK_DNR_PARAM( type ) )
- {
- UPDATE_DNR_PARAM( mode );
- UPDATE_DNR_PARAM( type );
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MODE, 2, 0, dnr_params->mode, dnr_params->type);
- }
-
- /* assign dnr filter props*/
- if( dnr_params->spatial > 15 )
- dnr_params->spatial = 15;
- if( dnr_params->temporal > 31 )
- dnr_params->temporal = 31;
- if( CHECK_DNR_PARAM( spatial ) || CHECK_DNR_PARAM( temporal ) )
- {
- UPDATE_DNR_PARAM( spatial );
- UPDATE_DNR_PARAM( temporal );
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_MANUAL_DNR, 2, 0, dnr_params->spatial, dnr_params->temporal);
- }
-}
-
-static void blackbird_codec_settings(struct cx8802_dev *dev)
-{
-
- /* assign output port */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_OUTPUT_PORT, 1, 0, BLACKBIRD_OUTPUT_PORT_STREAMING); /* Host */
-
- /* assign frame size */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_RESOLUTION, 2, 0,
- dev->height, dev->width);
-
- /* assign coring levels (luma_h, luma_l, chroma_h, chroma_l) */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MEDIAN, 4, 0, 0, 255, 0, 255);
-
- /* assign spatial filter type: luma_t: horiz_only, chroma_t: horiz_only */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_SPATIAL_FILTER, 2, 0,
- BLACKBIRD_SPATIAL_FILTER_LUMA_1D_HORIZ,
- BLACKBIRD_SPATIAL_FILTER_CHROMA_1D_HORIZ
- );
-
- /* assign frame drop rate */
- /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_DROP_RATE, 1, 0, 0); */
-
- blackbird_set_default_params(dev);
- blackbird_set_default_dnr_params(dev);
-}
-
static int blackbird_initialize_codec(struct cx8802_dev *dev)
{
struct cx88_core *core = dev->core;
@@ -1248,7 +568,7 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
int retval;
dprintk(1,"Initialize codec\n");
- retval = blackbird_api_cmd(dev, BLACKBIRD_API_PING, 0, 0); /* ping */
+ retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
if (retval < 0) {
/* ping was not successful, reset and upload firmware */
cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */
@@ -1263,13 +583,13 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
if (dev->mailbox < 0)
return -1;
- retval = blackbird_api_cmd(dev, BLACKBIRD_API_PING, 0, 0); /* ping */
+ retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
if (retval < 0) {
dprintk(0, "ERROR: Firmware ping failed!\n");
return -1;
}
- retval = blackbird_api_cmd(dev, BLACKBIRD_API_GET_VERSION, 0, 1, &version);
+ retval = blackbird_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, &version);
if (retval < 0) {
dprintk(0, "ERROR: Firmware get encoder version failed!\n");
return -1;
@@ -1289,35 +609,35 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
/* blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xef, 0xef);
blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xf0, 0xf0);
blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0x180, 0x180); */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_CAPTURE_LINES, 2, 0,
+ blackbird_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
BLACKBIRD_FIELD1_SAA7115,
- BLACKBIRD_FIELD1_SAA7115
+ BLACKBIRD_FIELD2_SAA7115
);
/* blackbird_api_cmd(dev, IVTV_API_ASSIGN_PLACEHOLDER, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_CUSTOM_DATA, 12, 0,
+ blackbird_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
/* initialize the video input */
- blackbird_api_cmd(dev, BLACKBIRD_API_INIT_VIDEO_INPUT, 0, 0);
+ blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
msleep(1);
- blackbird_api_cmd(dev, BLACKBIRD_API_MUTE_VIDEO, 1, 0, BLACKBIRD_UNMUTE);
+ blackbird_api_cmd(dev, CX2341X_ENC_MUTE_VIDEO, 1, 0, BLACKBIRD_UNMUTE);
msleep(1);
- blackbird_api_cmd(dev, BLACKBIRD_API_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE);
+ blackbird_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE);
msleep(1);
/* start capturing to the host interface */
- /* blackbird_api_cmd(dev, BLACKBIRD_API_BEGIN_CAPTURE, 2, 0, 0, 0x13); */
- blackbird_api_cmd(dev, BLACKBIRD_API_BEGIN_CAPTURE, 2, 0,
+ /* blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, 0, 0x13); */
+ blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
BLACKBIRD_MPEG_CAPTURE,
BLACKBIRD_RAW_BITS_NONE
);
msleep(10);
- blackbird_api_cmd(dev, BLACKBIRD_API_REFRESH_INPUT, 0,0);
+ blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0,0);
return 0;
}
@@ -1485,14 +805,52 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
{
struct v4l2_mpeg_compression *f = arg;
- memcpy(f,&dev->params,sizeof(*f));
+ printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. "
+ "Replace with VIDIOC_G_EXT_CTRLS!");
+ memcpy(f,&default_mpeg_params,sizeof(*f));
return 0;
}
case VIDIOC_S_MPEGCOMP:
+ printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
+ "Replace with VIDIOC_S_EXT_CTRLS!");
+ return 0;
+ case VIDIOC_G_EXT_CTRLS:
{
- struct v4l2_mpeg_compression *f = arg;
+ struct v4l2_ext_controls *f = arg;
- blackbird_set_params(dev, f);
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ return cx2341x_ext_ctrls(&dev->params, f, cmd);
+ }
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *f = arg;
+ struct cx2341x_mpeg_params p;
+ int err;
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ p = dev->params;
+ err = cx2341x_ext_ctrls(&p, f, cmd);
+ if (err == 0 && cmd == VIDIOC_S_EXT_CTRLS) {
+ err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p);
+ dev->params = p;
+ }
+ return err;
+ }
+ case VIDIOC_S_FREQUENCY:
+ {
+ blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+ BLACKBIRD_END_NOW,
+ BLACKBIRD_MPEG_CAPTURE,
+ BLACKBIRD_RAW_BITS_NONE);
+
+ cx88_do_ioctl( inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook );
+
+ blackbird_initialize_codec(dev);
+ cx88_set_scale(dev->core, dev->width, dev->height,
+ fh->mpegq.field);
return 0;
}
@@ -1562,13 +920,14 @@ static int mpeg_release(struct inode *inode, struct file *file)
{
struct cx8802_fh *fh = file->private_data;
- /* blackbird_api_cmd(fh->dev, BLACKBIRD_API_END_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */
- blackbird_api_cmd(fh->dev, BLACKBIRD_API_END_CAPTURE, 3, 0,
+ /* blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */
+ blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
BLACKBIRD_END_NOW,
BLACKBIRD_MPEG_CAPTURE,
BLACKBIRD_RAW_BITS_NONE
);
+ cx8802_cancel_buffers(fh->dev);
/* stop mpeg capture */
if (fh->mpegq.streaming)
videobuf_streamoff(&fh->mpegq);
@@ -1683,19 +1042,13 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev,
dev->core = core;
dev->width = 720;
dev->height = 576;
- memcpy(&dev->params,&default_mpeg_params,sizeof(default_mpeg_params));
- memcpy(&dev->dnr_params,&default_dnr_params,sizeof(default_dnr_params));
-
- if (core->board == CX88_BOARD_HAUPPAUGE_ROSLYN) {
-
- if (core->tuner_formats & V4L2_STD_525_60) {
- dev->height = 480;
- dev->params.vi_frame_rate = 30;
- } else {
- dev->height = 576;
- dev->params.vi_frame_rate = 25;
- }
+ cx2341x_fill_defaults(&dev->params);
+ dev->params.port = CX2341X_PORT_STREAMING;
+ if (core->tvnorm->id & V4L2_STD_525_60) {
+ dev->height = 480;
+ } else {
+ dev->height = 576;
}
err = cx8802_init_common(dev);
@@ -1781,8 +1134,6 @@ module_exit(blackbird_fini);
EXPORT_SYMBOL(cx88_ioctl_hook);
EXPORT_SYMBOL(cx88_ioctl_translator);
-EXPORT_SYMBOL(blackbird_set_params);
-EXPORT_SYMBOL(blackbird_set_dnr_params);
/* ----------------------------------------------------------- */
/*
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index f80154b..67cdd82 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -114,7 +114,7 @@ struct cx88_board cx88_boards[] = {
.radio = {
.type = CX88_RADIO,
.gpio0 = 0xff10,
- },
+ },
},
[CX88_BOARD_ATI_WONDER_PRO] = {
.name = "ATI TV Wonder Pro",
@@ -267,7 +267,7 @@ struct cx88_board cx88_boards[] = {
.gpio1 = 0x00007004,
.gpio2 = 0x0035d700,
.gpio3 = 0x02000000,
- },
+ },
},
[CX88_BOARD_LEADTEK_PVR2000] = {
// gpio values for PAL version from regspy by DScaler
@@ -413,7 +413,7 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x000027df,
- },{
+ },{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x000027df,
@@ -536,7 +536,7 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x000027df,
- },{
+ },{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x000027df,
@@ -759,7 +759,7 @@ struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD] = {
.name = "DViCO FusionHDTV 5 Gold",
- .tuner_type = TUNER_LG_TDVS_H062F,
+ .tuner_type = TUNER_LG_TDVS_H06XF, /* TDVS-H062F */
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -1050,11 +1050,7 @@ struct cx88_board cx88_boards[] = {
.dvb = 1,
},
[CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = {
- /* FIXME: Standard video using the cx88 broadcast decoder is
- * working, but blackbird isn't working yet, audio is only
- * working correctly for television mode. S-Video and Composite
- * are working for video-only, so I have them disabled for now.
- */
+ /* FIXME: Audio not working for s-video / composite inputs. */
.name = "KWorld HardwareMpegTV XPert",
.tuner_type = TUNER_PHILIPS_TDA8290,
.radio_type = UNSET,
@@ -1065,12 +1061,21 @@ struct cx88_board cx88_boards[] = {
.vmux = 0,
.gpio0 = 0x3de2,
.gpio2 = 0x00ff,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x3de6,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x3de6,
}},
.radio = {
.type = CX88_RADIO,
.gpio0 = 0x3de6,
.gpio2 = 0x00ff,
},
+ .blackbird = 1,
},
[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID] = {
.name = "DViCO FusionHDTV DVB-T Hybrid",
@@ -1093,7 +1098,102 @@ struct cx88_board cx88_boards[] = {
}},
.dvb = 1,
},
-
+ [CX88_BOARD_PCHDTV_HD5500] = {
+ .name = "pcHDTV HD5500 HDTV",
+ .tuner_type = TUNER_LG_TDVS_H06XF, /* TDVS-H064F */
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x87fd,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x87f9,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x87f9,
+ }},
+ .dvb = 1,
+ },
+ [CX88_BOARD_KWORLD_MCE200_DELUXE] = {
+ /* FIXME: tested TV input only, disabled composite,
+ svideo and radio until they can be tested also. */
+ .name = "Kworld MCE 200 Deluxe",
+ .tuner_type = TUNER_TENA_9533_DI,
+ .radio_type = UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x0000BDE6
+ }},
+ .blackbird = 1,
+ },
+ [CX88_BOARD_PIXELVIEW_PLAYTV_P7000] = {
+ /* FIXME: SVideo, Composite and FM inputs are untested */
+ .name = "PixelView PlayTV P7000",
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE |
+ TDA9887_PORT2_ACTIVE,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x5da6,
+ }},
+ .blackbird = 1,
+ },
+ [CX88_BOARD_NPGTECH_REALTV_TOP10FM] = {
+ .name = "NPG Tech Real TV FM Top 10",
+ .tuner_type = TUNER_TNF_5335MF, /* Actually a TNF9535 */
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x0788,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x078b,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x078b,
+ }},
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x074a,
+ },
+ },
+ [CX88_BOARD_WINFAST_DTV2000H] = {
+ /* video inputs and radio still in testing */
+ .name = "WinFast DTV2000 H",
+ .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x00017304,
+ .gpio1 = 0x00008203,
+ .gpio2 = 0x00017304,
+ .gpio3 = 0x02000000,
+ }},
+ .dvb = 1,
+ },
};
const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
@@ -1311,6 +1411,34 @@ struct cx88_subid cx88_subids[] = {
.subvendor = 0x18ac,
.subdevice = 0xdb44,
.card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
+ },{
+ .subvendor = 0x7063,
+ .subdevice = 0x5500,
+ .card = CX88_BOARD_PCHDTV_HD5500,
+ },{
+ .subvendor = 0x17de,
+ .subdevice = 0x0841,
+ .card = CX88_BOARD_KWORLD_MCE200_DELUXE,
+ },{
+ .subvendor = 0x1822,
+ .subdevice = 0x0019,
+ .card = CX88_BOARD_DNTV_LIVE_DVB_T_PRO,
+ },{
+ .subvendor = 0x1554,
+ .subdevice = 0x4813,
+ .card = CX88_BOARD_PIXELVIEW_PLAYTV_P7000,
+ },{
+ .subvendor = 0x14f1,
+ .subdevice = 0x0842,
+ .card = CX88_BOARD_NPGTECH_REALTV_TOP10FM,
+ },{
+ .subvendor = 0x107d,
+ .subdevice = 0x665e,
+ .card = CX88_BOARD_WINFAST_DTV2000H,
+ },{
+ .subvendor = 0x18ac,
+ .subdevice = 0xd800, /* FusionHDTV 3 Gold (original revision) */
+ .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q,
},
};
const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index e1092d5..c56292d 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -677,7 +677,7 @@ static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
static unsigned int inline norm_vbipack(struct cx88_tvnorm *norm)
{
- return (norm->id & V4L2_STD_625_50) ? 511 : 288;
+ return (norm->id & V4L2_STD_625_50) ? 511 : 400;
}
int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
@@ -932,9 +932,9 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
htotal, cx_read(MO_HTOTAL), (u32)tmp64);
cx_write(MO_HTOTAL, htotal);
- // vbi stuff
- cx_write(MO_VBI_PACKET, ((1 << 11) | /* (norm_vdelay(norm) << 11) | */
- norm_vbipack(norm)));
+ // vbi stuff, set vbi offset to 10 (for 20 Clk*2 pixels), this makes
+ // the effective vbi offset ~244 samples, the same as the Bt8x8
+ cx_write(MO_VBI_PACKET, (10<<11) | norm_vbipack(norm));
// this is needed as well to set all tvnorm parameter
cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED);
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 3619a44..dce1fed 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -51,6 +51,7 @@
#endif
#ifdef HAVE_LGDT330X
# include "lgdt330x.h"
+# include "lg_h06xf.h"
#endif
#ifdef HAVE_NXT200X
# include "nxt200x.h"
@@ -58,6 +59,7 @@
#ifdef HAVE_CX24123
# include "cx24123.h"
#endif
+#include "isl6421.h"
MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -113,21 +115,6 @@ static struct videobuf_queue_ops dvb_qops = {
/* ------------------------------------------------------------------ */
-#if defined(HAVE_MT352) || defined(HAVE_ZL10353)
-static int zarlink_pll_set(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params,
- u8 *pllbuf)
-{
- struct cx8802_dev *dev = fe->dvb->priv;
-
- pllbuf[0] = dev->core->pll_addr << 1;
- dvb_pll_configure(dev->core->pll_desc, pllbuf + 1,
- params->frequency,
- params->u.ofdm.bandwidth);
- return 0;
-}
-#endif
-
#ifdef HAVE_MT352
static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
{
@@ -196,19 +183,16 @@ static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
static struct mt352_config dvico_fusionhdtv = {
.demod_address = 0x0F,
.demod_init = dvico_fusionhdtv_demod_init,
- .pll_set = zarlink_pll_set,
};
static struct mt352_config dntv_live_dvbt_config = {
.demod_address = 0x0f,
.demod_init = dntv_live_dvbt_demod_init,
- .pll_set = zarlink_pll_set,
};
static struct mt352_config dvico_fusionhdtv_dual = {
.demod_address = 0x0F,
.demod_init = dvico_dual_demod_init,
- .pll_set = zarlink_pll_set,
};
#ifdef HAVE_VP3054_I2C
@@ -246,6 +230,8 @@ static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
.buf = fmd1216_init, .len = sizeof(fmd1216_init) };
int err;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
if (err < 0)
return err;
@@ -256,14 +242,14 @@ static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
return 0;
}
-static int dntv_live_dvbt_pro_pll_set(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params,
- u8* pllbuf)
+static int dntv_live_dvbt_pro_tuner_set_params(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* params)
{
struct cx8802_dev *dev= fe->dvb->priv;
+ u8 buf[4];
struct i2c_msg msg =
{ .addr = dev->core->pll_addr, .flags = 0,
- .buf = pllbuf+1, .len = 4 };
+ .buf = buf, .len = 4 };
int err;
/* Switch PLL to DVB mode */
@@ -272,14 +258,16 @@ static int dntv_live_dvbt_pro_pll_set(struct dvb_frontend* fe,
return err;
/* Tune PLL */
- pllbuf[0] = dev->core->pll_addr << 1;
- dvb_pll_configure(dev->core->pll_desc, pllbuf+1,
+ dvb_pll_configure(dev->core->pll_desc, buf,
params->frequency,
params->u.ofdm.bandwidth);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
+
printk(KERN_WARNING "cx88-dvb: %s error "
"(addr %02x <- %02x, err = %i)\n",
- __FUNCTION__, pllbuf[0], pllbuf[1], err);
+ __FUNCTION__, dev->core->pll_addr, buf[0], err);
if (err < 0)
return err;
else
@@ -293,27 +281,27 @@ static struct mt352_config dntv_live_dvbt_pro_config = {
.demod_address = 0x0f,
.no_tuner = 1,
.demod_init = dntv_live_dvbt_pro_demod_init,
- .pll_set = dntv_live_dvbt_pro_pll_set,
};
#endif
#endif
#ifdef HAVE_ZL10353
-static int dvico_hybrid_tune_pll(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params,
- u8 *pllbuf)
+static int dvico_hybrid_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
{
+ u8 pllbuf[4];
struct cx8802_dev *dev= fe->dvb->priv;
struct i2c_msg msg =
{ .addr = dev->core->pll_addr, .flags = 0,
- .buf = pllbuf + 1, .len = 4 };
+ .buf = pllbuf, .len = 4 };
int err;
- pllbuf[0] = dev->core->pll_addr << 1;
- dvb_pll_configure(dev->core->pll_desc, pllbuf + 1,
+ dvb_pll_configure(dev->core->pll_desc, pllbuf,
params->frequency,
params->u.ofdm.bandwidth);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
printk(KERN_WARNING "cx88-dvb: %s error "
"(addr %02x <- %02x, err = %i)\n",
@@ -329,12 +317,11 @@ static int dvico_hybrid_tune_pll(struct dvb_frontend *fe,
static struct zl10353_config dvico_fusionhdtv_hybrid = {
.demod_address = 0x0F,
- .pll_set = dvico_hybrid_tune_pll,
+ .no_tuner = 1,
};
static struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
.demod_address = 0x0F,
- .pll_set = zarlink_pll_set,
};
#endif
@@ -342,21 +329,15 @@ static struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
static struct cx22702_config connexant_refboard_config = {
.demod_address = 0x43,
.output_mode = CX22702_SERIAL_OUTPUT,
- .pll_address = 0x60,
- .pll_desc = &dvb_pll_thomson_dtt7579,
};
static struct cx22702_config hauppauge_novat_config = {
.demod_address = 0x43,
.output_mode = CX22702_SERIAL_OUTPUT,
- .pll_address = 0x61,
- .pll_desc = &dvb_pll_thomson_dtt759x,
};
static struct cx22702_config hauppauge_hvr1100_config = {
.demod_address = 0x63,
.output_mode = CX22702_SERIAL_OUTPUT,
- .pll_address = 0x61,
- .pll_desc = &dvb_pll_fmd1216me,
};
#endif
@@ -371,15 +352,13 @@ static int or51132_set_ts_param(struct dvb_frontend* fe,
static struct or51132_config pchdtv_hd3000 = {
.demod_address = 0x15,
- .pll_address = 0x61,
- .pll_desc = &dvb_pll_thomson_dtt761x,
.set_ts_params = or51132_set_ts_param,
};
#endif
#ifdef HAVE_LGDT330X
-static int lgdt330x_pll_set(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params)
+static int lgdt3302_tuner_set_params(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* params)
{
/* FIXME make this routine use the tuner-simple code.
* It could probably be shared with a number of ATSC
@@ -392,12 +371,12 @@ static int lgdt330x_pll_set(struct dvb_frontend* fe,
{ .addr = dev->core->pll_addr, .flags = 0, .buf = buf, .len = 4 };
int err;
- /* Put the analog decoder in standby to keep it quiet */
- cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
-
dvb_pll_configure(core->pll_desc, buf, params->frequency, 0);
dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
__FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if ((err = i2c_transfer(&core->i2c_adap, &msg, 1)) != 1) {
printk(KERN_WARNING "cx88-dvb: %s error "
"(addr %02x <- %02x, err = %i)\n",
@@ -407,16 +386,21 @@ static int lgdt330x_pll_set(struct dvb_frontend* fe,
else
return -EREMOTEIO;
}
- if (core->tuner_type == TUNER_LG_TDVS_H062F) {
- /* Set the Auxiliary Byte. */
- buf[2] &= ~0x20;
- buf[2] |= 0x18;
- buf[3] = 0x50;
- i2c_transfer(&core->i2c_adap, &msg, 1);
- }
return 0;
}
+static int lgdt3303_tuner_set_params(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* params)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ struct cx88_core *core = dev->core;
+
+ /* Put the analog decoder in standby to keep it quiet */
+ cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
+
+ return lg_h06xf_pll_set(fe, &core->i2c_adap, params);
+}
+
static int lgdt330x_pll_rf_set(struct dvb_frontend* fe, int index)
{
struct cx8802_dev *dev= fe->dvb->priv;
@@ -444,7 +428,6 @@ static struct lgdt330x_config fusionhdtv_3_gold = {
.demod_address = 0x0e,
.demod_chip = LGDT3302,
.serial_mpeg = 0x04, /* TPSERIAL for 3302 in TOP_CONTROL */
- .pll_set = lgdt330x_pll_set,
.set_ts_params = lgdt330x_set_ts_param,
};
@@ -452,7 +435,13 @@ static struct lgdt330x_config fusionhdtv_5_gold = {
.demod_address = 0x0e,
.demod_chip = LGDT3303,
.serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
- .pll_set = lgdt330x_pll_set,
+ .set_ts_params = lgdt330x_set_ts_param,
+};
+
+static struct lgdt330x_config pchdtv_hd5500 = {
+ .demod_address = 0x59,
+ .demod_chip = LGDT3303,
+ .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
.set_ts_params = lgdt330x_set_ts_param,
};
#endif
@@ -477,8 +466,6 @@ static int nxt200x_set_pll_input(u8* buf, int input)
static struct nxt200x_config ati_hdtvwonder = {
.demod_address = 0x0a,
- .pll_address = 0x61,
- .pll_desc = &dvb_pll_tuv1236d,
.set_pll_input = nxt200x_set_pll_input,
.set_ts_params = nxt200x_set_ts_param,
};
@@ -493,28 +480,30 @@ static int cx24123_set_ts_param(struct dvb_frontend* fe,
return 0;
}
-static void cx24123_enable_lnb_voltage(struct dvb_frontend* fe, int on)
+static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{
struct cx8802_dev *dev= fe->dvb->priv;
struct cx88_core *core = dev->core;
- if (on)
- cx_write(MO_GP0_IO, 0x000006f9);
- else
+ if (voltage == SEC_VOLTAGE_OFF) {
cx_write(MO_GP0_IO, 0x000006fB);
+ } else {
+ cx_write(MO_GP0_IO, 0x000006f9);
+ }
+
+ if (core->prev_set_voltage)
+ return core->prev_set_voltage(fe, voltage);
+ return 0;
}
static struct cx24123_config hauppauge_novas_config = {
.demod_address = 0x55,
- .use_isl6421 = 1,
.set_ts_params = cx24123_set_ts_param,
};
static struct cx24123_config kworld_dvbs_100_config = {
.demod_address = 0x15,
- .use_isl6421 = 0,
.set_ts_params = cx24123_set_ts_param,
- .enable_lnb_voltage = cx24123_enable_lnb_voltage,
};
#endif
@@ -530,6 +519,11 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_HAUPPAUGE_DVB_T1:
dev->dvb.frontend = cx22702_attach(&hauppauge_novat_config,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt759x);
+ }
break;
case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
case CX88_BOARD_CONEXANT_DVB_T1:
@@ -537,44 +531,92 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_WINFAST_DTV1000:
dev->dvb.frontend = cx22702_attach(&connexant_refboard_config,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x60,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt7579);
+ }
break;
+ case CX88_BOARD_WINFAST_DTV2000H:
case CX88_BOARD_HAUPPAUGE_HVR1100:
case CX88_BOARD_HAUPPAUGE_HVR1100LP:
dev->dvb.frontend = cx22702_attach(&hauppauge_hvr1100_config,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_fmd1216me);
+ }
break;
#endif
#if defined(HAVE_MT352) || defined(HAVE_ZL10353)
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
- dev->core->pll_addr = 0x60;
- dev->core->pll_desc = &dvb_pll_thomson_dtt7579;
#ifdef HAVE_MT352
dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
&dev->core->i2c_adap);
- if (dev->dvb.frontend != NULL)
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x60,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt7579);
break;
+ }
#endif
#ifdef HAVE_ZL10353
/* ZL10353 replaces MT352 on later cards */
dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_plus_v1_1,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x60,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt7579);
+ }
+#endif
+ break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
+#ifdef HAVE_MT352
+ /* The tin box says DEE1601, but it seems to be DTT7579
+ * compatible, with a slightly different MT352 AGC gain. */
+ dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dual,
+ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt7579);
+ break;
+ }
+#endif
+#ifdef HAVE_ZL10353
+ /* ZL10353 replaces MT352 on later cards */
+ dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_plus_v1_1,
+ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt7579);
+ }
#endif
break;
#endif /* HAVE_MT352 || HAVE_ZL10353 */
#ifdef HAVE_MT352
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
- dev->core->pll_addr = 0x61;
- dev->core->pll_desc = &dvb_pll_lg_z201;
dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_lg_z201);
+ }
break;
case CX88_BOARD_KWORLD_DVB_T:
case CX88_BOARD_DNTV_LIVE_DVB_T:
case CX88_BOARD_ADSTECH_DVB_T_PCI:
- dev->core->pll_addr = 0x61;
- dev->core->pll_desc = &dvb_pll_unknown_1;
dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_unknown_1);
+ }
break;
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
#ifdef HAVE_VP3054_I2C
@@ -582,18 +624,13 @@ static int dvb_register(struct cx8802_dev *dev)
dev->core->pll_desc = &dvb_pll_fmd1216me;
dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_pro_config,
&((struct vp3054_i2c_state *)dev->card_priv)->adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = dntv_live_dvbt_pro_tuner_set_params;
+ }
#else
printk("%s: built without vp3054 support\n", dev->core->name);
#endif
break;
- case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
- /* The tin box says DEE1601, but it seems to be DTT7579
- * compatible, with a slightly different MT352 AGC gain. */
- dev->core->pll_addr = 0x61;
- dev->core->pll_desc = &dvb_pll_thomson_dtt7579;
- dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dual,
- &dev->core->i2c_adap);
- break;
#endif
#ifdef HAVE_ZL10353
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
@@ -601,12 +638,20 @@ static int dvb_register(struct cx8802_dev *dev)
dev->core->pll_desc = &dvb_pll_thomson_fe6600;
dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_hybrid,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = dvico_hybrid_tuner_set_params;
+ }
break;
#endif
#ifdef HAVE_OR51132
case CX88_BOARD_PCHDTV_HD3000:
dev->dvb.frontend = or51132_attach(&pchdtv_hd3000,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt761x);
+ }
break;
#endif
#ifdef HAVE_LGDT330X
@@ -627,6 +672,9 @@ static int dvb_register(struct cx8802_dev *dev)
dev->core->pll_desc = &dvb_pll_microtune_4042;
dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_3_gold,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3302_tuner_set_params;
+ }
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
@@ -643,6 +691,9 @@ static int dvb_register(struct cx8802_dev *dev)
dev->core->pll_desc = &dvb_pll_thomson_dtt761x;
dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_3_gold,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3302_tuner_set_params;
+ }
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
@@ -655,10 +706,28 @@ static int dvb_register(struct cx8802_dev *dev)
mdelay(100);
cx_set(MO_GP0_IO, 1);
mdelay(200);
- dev->core->pll_addr = 0x61;
- dev->core->pll_desc = &dvb_pll_tdvs_tua6034;
dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_5_gold,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
+ }
+ }
+ break;
+ case CX88_BOARD_PCHDTV_HD5500:
+ dev->ts_gen_cntrl = 0x08;
+ {
+ /* Do a hardware reset of chip before using it. */
+ struct cx88_core *core = dev->core;
+
+ cx_clear(MO_GP0_IO, 1);
+ mdelay(100);
+ cx_set(MO_GP0_IO, 1);
+ mdelay(200);
+ dev->dvb.frontend = lgdt330x_attach(&pchdtv_hd5500,
+ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
+ }
}
break;
#endif
@@ -666,6 +735,11 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_ATI_HDTVWONDER:
dev->dvb.frontend = nxt200x_attach(&ati_hdtvwonder,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_tuv1236d);
+ }
break;
#endif
#ifdef HAVE_CX24123
@@ -673,10 +747,18 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
dev->dvb.frontend = cx24123_attach(&hauppauge_novas_config,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend) {
+ isl6421_attach(dev->dvb.frontend, &dev->core->i2c_adap,
+ 0x08, 0x00, 0x00);
+ }
break;
case CX88_BOARD_KWORLD_DVBS_100:
dev->dvb.frontend = cx24123_attach(&kworld_dvbs_100_config,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+ dev->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
+ }
break;
#endif
default:
@@ -690,15 +772,15 @@ static int dvb_register(struct cx8802_dev *dev)
}
if (dev->core->pll_desc) {
- dev->dvb.frontend->ops->info.frequency_min = dev->core->pll_desc->min;
- dev->dvb.frontend->ops->info.frequency_max = dev->core->pll_desc->max;
+ dev->dvb.frontend->ops.info.frequency_min = dev->core->pll_desc->min;
+ dev->dvb.frontend->ops.info.frequency_max = dev->core->pll_desc->max;
}
/* Put the analog decoder in standby to keep it quiet */
cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
/* register everything */
- return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev);
+ return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev);
}
/* ----------------------------------------------------------- */
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index f720901..7efa6de 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -138,13 +138,13 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
return;
if (core->dvbdev) {
- if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl)
- core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
+ if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
+ core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
i2c_clients_command(&core->i2c_adap, cmd, arg);
- if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl)
- core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
+ if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
+ core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
} else
i2c_clients_command(&core->i2c_adap, cmd, arg);
}
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index 78a63b7..72b630a 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -70,14 +70,33 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
static void cx88_ir_handle_key(struct cx88_IR *ir)
{
struct cx88_core *core = ir->core;
- u32 gpio, data;
+ u32 gpio, data, auxgpio;
/* read gpio value */
gpio = cx_read(ir->gpio_addr);
+ if (core->board == CX88_BOARD_NPGTECH_REALTV_TOP10FM) {
+ /* This board apparently uses a combination of 2 GPIO
+ to represent the keys. Additionally, the second GPIO
+ can be used for parity.
+
+ Example:
+
+ for key "5"
+ gpio = 0x758, auxgpio = 0xe5 or 0xf5
+ for key "Power"
+ gpio = 0x758, auxgpio = 0xed or 0xfd
+ */
+
+ auxgpio = cx_read(MO_GP1_IO);
+ /* Take out the parity part */
+ gpio+=(gpio & 0x7fd) + (auxgpio & 0xef);
+ } else
+ auxgpio = gpio;
+
if (ir->polling) {
- if (ir->last_gpio == gpio)
+ if (ir->last_gpio == auxgpio)
return;
- ir->last_gpio = gpio;
+ ir->last_gpio = auxgpio;
}
/* extract data */
@@ -172,12 +191,13 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir_type = IR_TYPE_RC5;
ir->sampling = 1;
break;
+ case CX88_BOARD_WINFAST_DTV2000H:
case CX88_BOARD_WINFAST2000XP_EXPERT:
ir_codes = ir_codes_winfast;
ir->gpio_addr = MO_GP0_IO;
ir->mask_keycode = 0x8f8;
ir->mask_keyup = 0x100;
- ir->polling = 1; /* ms */
+ ir->polling = 50; /* ms */
break;
case CX88_BOARD_IODATA_GVBCTV7E:
ir_codes = ir_codes_iodata_bctv7e;
@@ -228,6 +248,12 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir_type = IR_TYPE_PD;
ir->sampling = 0xff00; /* address */
break;
+ case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
+ ir_codes = ir_codes_npgtech;
+ ir->gpio_addr = MO_GP0_IO;
+ ir->mask_keycode = 0xfa;
+ ir->polling = 50; /* ms */
+ break;
}
if (NULL == ir_codes) {
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 7d16888..a9d7795 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -54,7 +54,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
{
struct cx88_core *core = dev->core;
- dprintk(0, "cx8802_start_dma w: %d, h: %d, f: %d\n", dev->width, dev->height, buf->vb.field);
+ dprintk(1, "cx8802_start_dma w: %d, h: %d, f: %d\n", dev->width, dev->height, buf->vb.field);
/* setup fifo + format */
cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28],
@@ -76,6 +76,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
+ case CX88_BOARD_PCHDTV_HD5500:
cx_write(TS_SOP_STAT, 1<<13);
break;
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
@@ -109,7 +110,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
q->count = 1;
/* enable irqs */
- dprintk( 0, "setting the interrupt mask\n" );
+ dprintk( 1, "setting the interrupt mask\n" );
cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x04);
cx_set(MO_TS_INTMSK, 0x1f0011);
@@ -122,7 +123,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
static int cx8802_stop_dma(struct cx8802_dev *dev)
{
struct cx88_core *core = dev->core;
- dprintk( 0, "cx8802_stop_dma\n" );
+ dprintk( 1, "cx8802_stop_dma\n" );
/* stop dma */
cx_clear(MO_TS_DMACNTRL, 0x11);
@@ -142,10 +143,43 @@ static int cx8802_restart_queue(struct cx8802_dev *dev,
struct cx88_buffer *buf;
struct list_head *item;
- dprintk( 0, "cx8802_restart_queue\n" );
+ dprintk( 1, "cx8802_restart_queue\n" );
if (list_empty(&q->active))
{
- dprintk( 0, "cx8802_restart_queue: queue is empty\n" );
+ struct cx88_buffer *prev;
+ prev = NULL;
+
+ dprintk(1, "cx8802_restart_queue: queue is empty\n" );
+
+ for (;;) {
+ if (list_empty(&q->queued))
+ return 0;
+ buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
+ if (NULL == prev) {
+ list_del(&buf->vb.queue);
+ list_add_tail(&buf->vb.queue,&q->active);
+ cx8802_start_dma(dev, q, buf);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = q->count++;
+ mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+ dprintk(1,"[%p/%d] restart_queue - first active\n",
+ buf,buf->vb.i);
+
+ } else if (prev->vb.width == buf->vb.width &&
+ prev->vb.height == buf->vb.height &&
+ prev->fmt == buf->fmt) {
+ list_del(&buf->vb.queue);
+ list_add_tail(&buf->vb.queue,&q->active);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = q->count++;
+ prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+ dprintk(1,"[%p/%d] restart_queue - move to active\n",
+ buf,buf->vb.i);
+ } else {
+ return 0;
+ }
+ prev = buf;
+ }
return 0;
}
@@ -204,13 +238,13 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma);
if (list_empty(&cx88q->active)) {
- dprintk( 0, "queue is empty - first active\n" );
+ dprintk( 1, "queue is empty - first active\n" );
list_add_tail(&buf->vb.queue,&cx88q->active);
cx8802_start_dma(dev, cx88q, buf);
buf->vb.state = STATE_ACTIVE;
buf->count = cx88q->count++;
mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT);
- dprintk(0,"[%p/%d] %s - first active\n",
+ dprintk(1,"[%p/%d] %s - first active\n",
buf, buf->vb.i, __FUNCTION__);
} else {
@@ -244,7 +278,7 @@ static void do_cancel_buffers(struct cx8802_dev *dev, char *reason, int restart)
}
if (restart)
{
- dprintk(0, "restarting queue\n" );
+ dprintk(1, "restarting queue\n" );
cx8802_restart_queue(dev,q);
}
spin_unlock_irqrestore(&dev->slock,flags);
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 641a0c5..1e4278b 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -52,6 +52,7 @@
#include <linux/init.h>
#include <linux/smp_lock.h>
#include <linux/delay.h>
+#include <linux/config.h>
#include <linux/kthread.h>
#include "cx88.h"
@@ -137,21 +138,28 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
{
u32 volume;
-#ifndef USING_CX88_ALSA
+#ifndef CONFIG_VIDEO_CX88_ALSA
/* restart dma; This avoids buzz in NICAM and is good in others */
cx88_stop_audio_dma(core);
#endif
cx_write(AUD_RATE_THRES_DMD, 0x000000C0);
-#ifndef USING_CX88_ALSA
+#ifndef CONFIG_VIDEO_CX88_ALSA
cx88_start_audio_dma(core);
#endif
if (cx88_boards[core->board].blackbird) {
/* sets sound input from external adc */
- if (core->board == CX88_BOARD_HAUPPAUGE_ROSLYN)
+ switch (core->board) {
+ case CX88_BOARD_HAUPPAUGE_ROSLYN:
+ case CX88_BOARD_KWORLD_MCE200_DELUXE:
+ case CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT:
+ case CX88_BOARD_PIXELVIEW_PLAYTV_P7000:
+ case CX88_BOARD_ASUS_PVR_416:
cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
- else
+ break;
+ default:
cx_set(AUD_CTL, EN_I2SIN_ENABLE);
+ }
cx_write(AUD_I2SINPUTCNTL, 4);
cx_write(AUD_BAUDRATE, 1);
diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c
index 846faad..aa2a697 100644
--- a/drivers/media/video/cx88/cx88-vbi.c
+++ b/drivers/media/video/cx88/cx88-vbi.c
@@ -34,8 +34,8 @@ void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f)
if (dev->core->tvnorm->id & V4L2_STD_525_60) {
/* ntsc */
f->fmt.vbi.sampling_rate = 28636363;
- f->fmt.vbi.start[0] = 10 -1;
- f->fmt.vbi.start[1] = 273 -1;
+ f->fmt.vbi.start[0] = 10;
+ f->fmt.vbi.start[1] = 273;
} else if (dev->core->tvnorm->id & V4L2_STD_625_50) {
/* pal */
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 326a25f..dc7bc35 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -25,9 +25,11 @@
#include <linux/videodev2.h>
#include <linux/kdev_t.h>
+#include <media/v4l2-common.h>
#include <media/tuner.h>
#include <media/tveeprom.h>
#include <media/video-buf.h>
+#include <media/cx2341x.h>
#include <media/video-buf-dvb.h>
#include "btcx-risc.h"
@@ -35,7 +37,7 @@
#include <linux/version.h>
#include <linux/mutex.h>
-#define CX88_VERSION_CODE KERNEL_VERSION(0,0,5)
+#define CX88_VERSION_CODE KERNEL_VERSION(0,0,6)
#ifndef TRUE
# define TRUE (1==1)
@@ -189,6 +191,11 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL 44
#define CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT 45
#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID 46
+#define CX88_BOARD_PCHDTV_HD5500 47
+#define CX88_BOARD_KWORLD_MCE200_DELUXE 48
+#define CX88_BOARD_PIXELVIEW_PLAYTV_P7000 49
+#define CX88_BOARD_NPGTECH_REALTV_TOP10FM 50
+#define CX88_BOARD_WINFAST_DTV2000H 51
enum cx88_itype {
CX88_VMUX_COMPOSITE1 = 1,
@@ -296,6 +303,7 @@ struct cx88_core {
/* config info -- dvb */
struct dvb_pll_desc *pll_desc;
unsigned int pll_addr;
+ int (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
/* state info */
struct task_struct *kthread;
@@ -391,14 +399,6 @@ struct cx8802_suspend_state {
int disabled;
};
-/* TODO: move this to struct v4l2_mpeg_compression ? */
-struct blackbird_dnr {
- u32 mode;
- u32 type;
- u32 spatial;
- u32 temporal;
-};
-
struct cx8802_dev {
struct cx88_core *core;
spinlock_t slock;
@@ -432,8 +432,7 @@ struct cx8802_dev {
unsigned char ts_gen_cntrl;
/* mpeg params */
- struct v4l2_mpeg_compression params;
- struct blackbird_dnr dnr_params;
+ struct cx2341x_mpeg_params params;
};
/* ----------------------------------------------------------- */
@@ -598,10 +597,6 @@ extern int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
extern int (*cx88_ioctl_hook)(struct inode *inode, struct file *file,
unsigned int cmd, void *arg);
extern unsigned int (*cx88_ioctl_translator)(unsigned int cmd);
-void blackbird_set_params(struct cx8802_dev *dev,
- struct v4l2_mpeg_compression *params);
-void blackbird_set_dnr_params(struct cx8802_dev *dev,
- struct blackbird_dnr* dnr_params);
/*
* Local variables:
diff --git a/drivers/media/video/dsbr100.c b/drivers/media/video/dsbr100.c
index 3b4e998..f7e33f9 100644
--- a/drivers/media/video/dsbr100.c
+++ b/drivers/media/video/dsbr100.c
@@ -72,6 +72,7 @@
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/usb.h>
#include <linux/smp_lock.h>
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 3ba3439..ed882eb 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -3,7 +3,7 @@
Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Mauro Carvalho Chehab <mchehab@infradead.org>
Sascha Sommer <saschasommer@freenet.de>
This program is free software; you can redistribute it and/or modify
@@ -29,6 +29,8 @@
#include <linux/usb.h>
#include <media/tuner.h>
#include <media/msp3400.h>
+#include <media/saa7115.h>
+#include <media/tvp5150.h>
#include <media/tveeprom.h>
#include <media/audiochip.h>
#include <media/v4l2-common.h>
@@ -46,11 +48,11 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
@@ -64,11 +66,11 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
@@ -82,11 +84,11 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
@@ -100,15 +102,15 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 2,
+ .vmux = SAA7115_COMPOSITE2,
.amux = 1,
},{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
@@ -122,15 +124,15 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 2,
+ .vmux = SAA7115_COMPOSITE2,
.amux = 0,
},{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
@@ -146,11 +148,11 @@ struct em28xx_board em28xx_boards[] = {
/*FIXME: S-Video not tested */
.input = {{
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 0,
+ .vmux = TVP5150_COMPOSITE0,
.amux = MSP_INPUT_DEFAULT,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 2,
+ .vmux = TVP5150_SVIDEO,
.amux = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
MSP_DSP_IN_SCART, MSP_DSP_IN_SCART),
}},
@@ -165,15 +167,15 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA7114,
.input = {{
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 4,
+ .vmux = SAA7115_COMPOSITE4,
.amux = 0,
},{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
@@ -188,15 +190,15 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 2,
+ .vmux = SAA7115_COMPOSITE2,
.amux = 0,
},{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
@@ -211,15 +213,15 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 2,
+ .vmux = SAA7115_COMPOSITE2,
.amux = 0,
},{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
@@ -234,15 +236,15 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 2,
+ .vmux = SAA7115_COMPOSITE2,
.amux = 0,
},{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
@@ -254,11 +256,11 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
@@ -324,8 +326,4 @@ void em28xx_card_setup(struct em28xx *dev)
}
}
-EXPORT_SYMBOL(em28xx_boards);
-EXPORT_SYMBOL(em28xx_bcount);
-EXPORT_SYMBOL(em28xx_id_table);
-
MODULE_DEVICE_TABLE (usb, em28xx_id_table);
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index e5ee8bc..4350cc7 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -3,7 +3,7 @@
Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Mauro Carvalho Chehab <mchehab@infradead.org>
Sascha Sommer <saschasommer@freenet.de>
This program is free software; you can redistribute it and/or modify
@@ -317,8 +317,8 @@ int em28xx_outfmt_set_yuv422(struct em28xx *dev)
return em28xx_write_regs(dev, VINCTRL_REG, "\x11", 1);
}
-int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, u8 ymin,
- u8 ymax)
+static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
+ u8 ymin, u8 ymax)
{
em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n", xmin, ymin, xmax, ymax);
@@ -328,7 +328,7 @@ int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, u8 ymin,
return em28xx_write_regs(dev, YMAX_REG, &ymax, 1);
}
-int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
+static int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
u16 width, u16 height)
{
u8 cwidth = width;
@@ -345,7 +345,7 @@ int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
return em28xx_write_regs(dev, OFLOW_REG, &overflow, 1);
}
-int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
+static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
{
u8 mode;
/* the em2800 scaler only supports scaling down to 50% */
@@ -534,7 +534,7 @@ static inline void em28xx_isoc_video_copy(struct em28xx *dev,
* em28xx_isoIrq()
* handles the incoming isoc urbs and fills the frames from our inqueue
*/
-void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs)
+static void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs)
{
struct em28xx *dev = urb->context;
int i, status;
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index 5b6cece..d829d8f 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -3,7 +3,7 @@
Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Mauro Carvalho Chehab <mchehab@infradead.org>
Sascha Sommer <saschasommer@freenet.de>
This program is free software; you can redistribute it and/or modify
@@ -399,17 +399,6 @@ static u32 functionality(struct i2c_adapter *adap)
return I2C_FUNC_SMBUS_EMUL;
}
-#ifndef I2C_PEC
-static void inc_use(struct i2c_adapter *adap)
-{
- MOD_INC_USE_COUNT;
-}
-
-static void dec_use(struct i2c_adapter *adap)
-{
- MOD_DEC_USE_COUNT;
-}
-#endif
static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client)
{
@@ -436,9 +425,19 @@ static int attach_inform(struct i2c_client *client)
struct em28xx *dev = client->adapter->algo_data;
switch (client->addr << 1) {
- case 0x86:
+ case 0x43:
+ case 0x4b:
+ {
+ struct tuner_setup tun_setup;
+
+ tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+ tun_setup.type = TUNER_TDA9887;
+ tun_setup.addr = client->addr;
+
+ em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
em28xx_i2c_call_clients(dev, TDA9887_SET_CONFIG, &dev->tda9887_conf);
break;
+ }
case 0x42:
dprintk1(1,"attach_inform: saa7114 detected.\n");
break;
@@ -464,6 +463,7 @@ static int attach_inform(struct i2c_client *client)
case 0xba:
dprintk1(1,"attach_inform: tvp5150 detected.\n");
break;
+
default:
dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1);
dev->tuner_addr = client->addr;
@@ -480,12 +480,7 @@ static struct i2c_algorithm em28xx_algo = {
};
static struct i2c_adapter em28xx_adap_template = {
-#ifdef I2C_PEC
.owner = THIS_MODULE,
-#else
- .inc_use = inc_use,
- .dec_use = dec_use,
-#endif
.class = I2C_CLASS_TV_ANALOG,
.name = "em28xx",
.id = I2C_HW_B_EM28XX,
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 31e89e4..3ffb568 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -3,7 +3,7 @@
Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Mauro Carvalho Chehab <mchehab@infradead.org>
Sascha Sommer <saschasommer@freenet.de>
This program is free software; you can redistribute it and/or modify
@@ -105,7 +105,7 @@ static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
-static int get_key_pinnacle_usb(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
unsigned char buf[3];
@@ -148,8 +148,8 @@ void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir)
snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Terratec)");
break;
case (EM2820_BOARD_PINNACLE_USB_2):
- ir->ir_codes = ir_codes_em_pinnacle_usb;
- ir->get_key = get_key_pinnacle_usb;
+ ir->ir_codes = ir_codes_pinnacle_grey;
+ ir->get_key = get_key_pinnacle_usb_grey;
snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Pinnacle PCTV)");
break;
case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index cf7cdf9..9286090 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -3,7 +3,7 @@
Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Mauro Carvalho Chehab <mchehab@infradead.org>
Sascha Sommer <saschasommer@freenet.de>
Some parts based on SN9C10x PC Camera Controllers GPL driver made
@@ -42,7 +42,7 @@
#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
"Markus Rechberger <mrechberger@gmail.com>, " \
- "Mauro Carvalho Chehab <mchehab@brturbo.com.br>, " \
+ "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
"Sascha Sommer <saschasommer@freenet.de>"
#define DRIVER_NAME "em28xx"
@@ -170,8 +170,12 @@ static int em28xx_config(struct em28xx *dev)
static void em28xx_config_i2c(struct em28xx *dev)
{
struct v4l2_frequency f;
+ struct v4l2_routing route;
+
+ route.input = INPUT(dev->ctl_input)->vmux;
+ route.output = 0;
em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL);
- em28xx_i2c_call_clients(dev, VIDIOC_S_INPUT, &dev->ctl_input);
+ em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
/* configure tuner */
@@ -206,19 +210,19 @@ static void em28xx_empty_framequeues(struct em28xx *dev)
static void video_mux(struct em28xx *dev, int index)
{
- int input, ainput;
+ int ainput;
+ struct v4l2_routing route;
- input = INPUT(index)->vmux;
+ route.input = INPUT(index)->vmux;
+ route.output = 0;
dev->ctl_input = index;
dev->ctl_ainput = INPUT(index)->amux;
- em28xx_i2c_call_clients(dev, VIDIOC_S_INPUT, &input);
+ em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
- em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput);
+ em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,route.input,dev->ctl_ainput);
if (dev->has_msp34xx) {
- struct v4l2_routing route;
-
if (dev->i2s_speed)
em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed);
route.input = dev->ctl_ainput;
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index e1ddc2f..d8fcc9e 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -3,7 +3,7 @@
Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
Ludovico Cavedon <cavedon@sssup.it>
- Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Mauro Carvalho Chehab <mchehab@infradead.org>
Based on the em2800 driver from Sascha Sommer <saschasommer@freenet.de>
@@ -319,13 +319,7 @@ int em28xx_audio_analog_set(struct em28xx *dev);
int em28xx_colorlevels_set_default(struct em28xx *dev);
int em28xx_capture_start(struct em28xx *dev, int start);
int em28xx_outfmt_set_yuv422(struct em28xx *dev);
-int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, u8 ymin,
- u8 ymax);
-int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
- u16 width, u16 height);
-int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v);
int em28xx_resolution_set(struct em28xx *dev);
-void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs);
int em28xx_init_isoc(struct em28xx *dev);
void em28xx_uninit_isoc(struct em28xx *dev);
int em28xx_set_alternate(struct em28xx *dev);
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index dfc9dd7..8992b6e 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -2341,11 +2341,9 @@ static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_G_CTRL:
return et61x251_vidioc_g_ctrl(cam, arg);
- case VIDIOC_S_CTRL_OLD:
case VIDIOC_S_CTRL:
return et61x251_vidioc_s_ctrl(cam, arg);
- case VIDIOC_CROPCAP_OLD:
case VIDIOC_CROPCAP:
return et61x251_vidioc_cropcap(cam, arg);
@@ -2392,7 +2390,6 @@ static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_G_PARM:
return et61x251_vidioc_g_parm(cam, arg);
- case VIDIOC_S_PARM_OLD:
case VIDIOC_S_PARM:
return et61x251_vidioc_s_parm(cam, arg);
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 7e66d83..fba30a4 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -150,12 +150,11 @@ static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
-/* The new pinnacle PCTV remote (with the colored buttons)
+/* Common (grey or coloured) pinnacle PCTV remote handling
*
- * Ricardo Cerqueira <v4l@cerqueira.org>
*/
-
-int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
+ int parity_offset, int marker, int code_modulo)
{
unsigned char b[4];
unsigned int start = 0,parity = 0,code = 0;
@@ -167,9 +166,9 @@ int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
}
for (start = 0; start<4; start++) {
- if (b[start] == 0x80) {
- code=b[(start+3)%4];
- parity=b[(start+2)%4];
+ if (b[start] == marker) {
+ code=b[(start+parity_offset+1)%4];
+ parity=b[(start+parity_offset)%4];
}
}
@@ -181,16 +180,14 @@ int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
if (ir->old == parity)
return 0;
-
ir->old = parity;
- /* Reduce code value to fit inside IR_KEYTAB_SIZE
- *
- * this is the only value that results in 42 unique
- * codes < 128
- */
+ /* drop special codes when a key is held down a long time for the grey controller
+ In this case, the second bit of the code is asserted */
+ if (marker == 0xfe && (code & 0x40))
+ return 0;
- code %= 0x88;
+ code %= code_modulo;
*ir_raw = code;
*ir_key = code;
@@ -200,7 +197,40 @@ int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
-EXPORT_SYMBOL_GPL(get_key_pinnacle);
+/* The grey pinnacle PCTV remote
+ *
+ * There are one issue with this remote:
+ * - I2c packet does not change when the same key is pressed quickly. The workaround
+ * is to hold down each key for about half a second, so that another code is generated
+ * in the i2c packet, and the function can distinguish key presses.
+ *
+ * Sylvain Pasche <sylvain.pasche@gmail.com>
+ */
+int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+
+ return get_key_pinnacle(ir, ir_key, ir_raw, 1, 0xfe, 0xff);
+}
+
+EXPORT_SYMBOL_GPL(get_key_pinnacle_grey);
+
+
+/* The new pinnacle PCTV remote (with the colored buttons)
+ *
+ * Ricardo Cerqueira <v4l@cerqueira.org>
+ */
+int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ /* code_modulo parameter (0x88) is used to reduce code value to fit inside IR_KEYTAB_SIZE
+ *
+ * this is the only value that results in 42 unique
+ * codes < 128
+ */
+
+ return get_key_pinnacle(ir, ir_key, ir_raw, 2, 0x80, 0x88);
+}
+
+EXPORT_SYMBOL_GPL(get_key_pinnacle_color);
/* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c
new file mode 100644
index 0000000..3bf7ac4
--- /dev/null
+++ b/drivers/media/video/ks0127.c
@@ -0,0 +1,846 @@
+/*
+ * Video Capture Driver (Video for Linux 1/2)
+ * for the Matrox Marvel G200,G400 and Rainbow Runner-G series
+ *
+ * This module is an interface to the KS0127 video decoder chip.
+ *
+ * Copyright (C) 1999 Ryan Drake <stiletto@mediaone.net>
+ *
+ * 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.
+ *
+ *****************************************************************************
+ *
+ * Modified and extended by
+ * Mike Bernson <mike@mlb.org>
+ * Gerard v.d. Horst
+ * Leon van Stuivenberg <l.vanstuivenberg@chello.nl>
+ * Gernot Ziegler <gz@lysator.liu.se>
+ *
+ * Version History:
+ * V1.0 Ryan Drake Initial version by Ryan Drake
+ * V1.1 Gerard v.d. Horst Added some debugoutput, reset the video-standard
+ */
+
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include "ks0127.h"
+
+#include <linux/i2c.h>
+#include <linux/video_decoder.h>
+
+#define dprintk if (debug) printk
+
+/* i2c identification */
+#define I2C_KS0127_ADDON 0xD8
+#define I2C_KS0127_ONBOARD 0xDA
+
+#define KS_TYPE_UNKNOWN 0
+#define KS_TYPE_0122S 1
+#define KS_TYPE_0127 2
+#define KS_TYPE_0127B 3
+
+/* ks0127 control registers */
+#define KS_STAT 0x00
+#define KS_CMDA 0x01
+#define KS_CMDB 0x02
+#define KS_CMDC 0x03
+#define KS_CMDD 0x04
+#define KS_HAVB 0x05
+#define KS_HAVE 0x06
+#define KS_HS1B 0x07
+#define KS_HS1E 0x08
+#define KS_HS2B 0x09
+#define KS_HS2E 0x0a
+#define KS_AGC 0x0b
+#define KS_HXTRA 0x0c
+#define KS_CDEM 0x0d
+#define KS_PORTAB 0x0e
+#define KS_LUMA 0x0f
+#define KS_CON 0x10
+#define KS_BRT 0x11
+#define KS_CHROMA 0x12
+#define KS_CHROMB 0x13
+#define KS_DEMOD 0x14
+#define KS_SAT 0x15
+#define KS_HUE 0x16
+#define KS_VERTIA 0x17
+#define KS_VERTIB 0x18
+#define KS_VERTIC 0x19
+#define KS_HSCLL 0x1a
+#define KS_HSCLH 0x1b
+#define KS_VSCLL 0x1c
+#define KS_VSCLH 0x1d
+#define KS_OFMTA 0x1e
+#define KS_OFMTB 0x1f
+#define KS_VBICTL 0x20
+#define KS_CCDAT2 0x21
+#define KS_CCDAT1 0x22
+#define KS_VBIL30 0x23
+#define KS_VBIL74 0x24
+#define KS_VBIL118 0x25
+#define KS_VBIL1512 0x26
+#define KS_TTFRAM 0x27
+#define KS_TESTA 0x28
+#define KS_UVOFFH 0x29
+#define KS_UVOFFL 0x2a
+#define KS_UGAIN 0x2b
+#define KS_VGAIN 0x2c
+#define KS_VAVB 0x2d
+#define KS_VAVE 0x2e
+#define KS_CTRACK 0x2f
+#define KS_POLCTL 0x30
+#define KS_REFCOD 0x31
+#define KS_INVALY 0x32
+#define KS_INVALU 0x33
+#define KS_INVALV 0x34
+#define KS_UNUSEY 0x35
+#define KS_UNUSEU 0x36
+#define KS_UNUSEV 0x37
+#define KS_USRSAV 0x38
+#define KS_USREAV 0x39
+#define KS_SHS1A 0x3a
+#define KS_SHS1B 0x3b
+#define KS_SHS1C 0x3c
+#define KS_CMDE 0x3d
+#define KS_VSDEL 0x3e
+#define KS_CMDF 0x3f
+#define KS_GAMMA0 0x40
+#define KS_GAMMA1 0x41
+#define KS_GAMMA2 0x42
+#define KS_GAMMA3 0x43
+#define KS_GAMMA4 0x44
+#define KS_GAMMA5 0x45
+#define KS_GAMMA6 0x46
+#define KS_GAMMA7 0x47
+#define KS_GAMMA8 0x48
+#define KS_GAMMA9 0x49
+#define KS_GAMMA10 0x4a
+#define KS_GAMMA11 0x4b
+#define KS_GAMMA12 0x4c
+#define KS_GAMMA13 0x4d
+#define KS_GAMMA14 0x4e
+#define KS_GAMMA15 0x4f
+#define KS_GAMMA16 0x50
+#define KS_GAMMA17 0x51
+#define KS_GAMMA18 0x52
+#define KS_GAMMA19 0x53
+#define KS_GAMMA20 0x54
+#define KS_GAMMA21 0x55
+#define KS_GAMMA22 0x56
+#define KS_GAMMA23 0x57
+#define KS_GAMMA24 0x58
+#define KS_GAMMA25 0x59
+#define KS_GAMMA26 0x5a
+#define KS_GAMMA27 0x5b
+#define KS_GAMMA28 0x5c
+#define KS_GAMMA29 0x5d
+#define KS_GAMMA30 0x5e
+#define KS_GAMMA31 0x5f
+#define KS_GAMMAD0 0x60
+#define KS_GAMMAD1 0x61
+#define KS_GAMMAD2 0x62
+#define KS_GAMMAD3 0x63
+#define KS_GAMMAD4 0x64
+#define KS_GAMMAD5 0x65
+#define KS_GAMMAD6 0x66
+#define KS_GAMMAD7 0x67
+#define KS_GAMMAD8 0x68
+#define KS_GAMMAD9 0x69
+#define KS_GAMMAD10 0x6a
+#define KS_GAMMAD11 0x6b
+#define KS_GAMMAD12 0x6c
+#define KS_GAMMAD13 0x6d
+#define KS_GAMMAD14 0x6e
+#define KS_GAMMAD15 0x6f
+#define KS_GAMMAD16 0x70
+#define KS_GAMMAD17 0x71
+#define KS_GAMMAD18 0x72
+#define KS_GAMMAD19 0x73
+#define KS_GAMMAD20 0x74
+#define KS_GAMMAD21 0x75
+#define KS_GAMMAD22 0x76
+#define KS_GAMMAD23 0x77
+#define KS_GAMMAD24 0x78
+#define KS_GAMMAD25 0x79
+#define KS_GAMMAD26 0x7a
+#define KS_GAMMAD27 0x7b
+#define KS_GAMMAD28 0x7c
+#define KS_GAMMAD29 0x7d
+#define KS_GAMMAD30 0x7e
+#define KS_GAMMAD31 0x7f
+
+
+/****************************************************************************
+* mga_dev : represents one ks0127 chip.
+****************************************************************************/
+
+struct adjust {
+ int contrast;
+ int bright;
+ int hue;
+ int ugain;
+ int vgain;
+};
+
+struct ks0127 {
+ struct i2c_client *client;
+ unsigned char addr;
+ int format_width;
+ int format_height;
+ int cap_width;
+ int cap_height;
+ int norm;
+ int ks_type;
+ u8 regs[256];
+};
+
+
+static int debug; /* insmod parameter */
+
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug output");
+MODULE_LICENSE("GPL");
+
+static u8 reg_defaults[64];
+
+
+
+static void init_reg_defaults(void)
+{
+ u8 *table = reg_defaults;
+
+ table[KS_CMDA] = 0x2c; /* VSE=0, CCIR 601, autodetect standard */
+ table[KS_CMDB] = 0x12; /* VALIGN=0, AGC control and input */
+ table[KS_CMDC] = 0x00; /* Test options */
+ /* clock & input select, write 1 to PORTA */
+ table[KS_CMDD] = 0x01;
+ table[KS_HAVB] = 0x00; /* HAV Start Control */
+ table[KS_HAVE] = 0x00; /* HAV End Control */
+ table[KS_HS1B] = 0x10; /* HS1 Start Control */
+ table[KS_HS1E] = 0x00; /* HS1 End Control */
+ table[KS_HS2B] = 0x00; /* HS2 Start Control */
+ table[KS_HS2E] = 0x00; /* HS2 End Control */
+ table[KS_AGC] = 0x53; /* Manual setting for AGC */
+ table[KS_HXTRA] = 0x00; /* Extra Bits for HAV and HS1/2 */
+ table[KS_CDEM] = 0x00; /* Chroma Demodulation Control */
+ table[KS_PORTAB] = 0x0f; /* port B is input, port A output GPPORT */
+ table[KS_LUMA] = 0x01; /* Luma control */
+ table[KS_CON] = 0x00; /* Contrast Control */
+ table[KS_BRT] = 0x00; /* Brightness Control */
+ table[KS_CHROMA] = 0x2a; /* Chroma control A */
+ table[KS_CHROMB] = 0x90; /* Chroma control B */
+ table[KS_DEMOD] = 0x00; /* Chroma Demodulation Control & Status */
+ table[KS_SAT] = 0x00; /* Color Saturation Control*/
+ table[KS_HUE] = 0x00; /* Hue Control */
+ table[KS_VERTIA] = 0x00; /* Vertical Processing Control A */
+ /* Vertical Processing Control B, luma 1 line delayed */
+ table[KS_VERTIB] = 0x12;
+ table[KS_VERTIC] = 0x0b; /* Vertical Processing Control C */
+ table[KS_HSCLL] = 0x00; /* Horizontal Scaling Ratio Low */
+ table[KS_HSCLH] = 0x00; /* Horizontal Scaling Ratio High */
+ table[KS_VSCLL] = 0x00; /* Vertical Scaling Ratio Low */
+ table[KS_VSCLH] = 0x00; /* Vertical Scaling Ratio High */
+ /* 16 bit YCbCr 4:2:2 output; I can't make the bt866 like 8 bit /Sam */
+ table[KS_OFMTA] = 0x30;
+ table[KS_OFMTB] = 0x00; /* Output Control B */
+ /* VBI Decoder Control; 4bit fmt: avoid Y overflow */
+ table[KS_VBICTL] = 0x5d;
+ table[KS_CCDAT2] = 0x00; /* Read Only register */
+ table[KS_CCDAT1] = 0x00; /* Read Only register */
+ table[KS_VBIL30] = 0xa8; /* VBI data decoding options */
+ table[KS_VBIL74] = 0xaa; /* VBI data decoding options */
+ table[KS_VBIL118] = 0x2a; /* VBI data decoding options */
+ table[KS_VBIL1512] = 0x00; /* VBI data decoding options */
+ table[KS_TTFRAM] = 0x00; /* Teletext frame alignment pattern */
+ table[KS_TESTA] = 0x00; /* test register, shouldn't be written */
+ table[KS_UVOFFH] = 0x00; /* UV Offset Adjustment High */
+ table[KS_UVOFFL] = 0x00; /* UV Offset Adjustment Low */
+ table[KS_UGAIN] = 0x00; /* U Component Gain Adjustment */
+ table[KS_VGAIN] = 0x00; /* V Component Gain Adjustment */
+ table[KS_VAVB] = 0x07; /* VAV Begin */
+ table[KS_VAVE] = 0x00; /* VAV End */
+ table[KS_CTRACK] = 0x00; /* Chroma Tracking Control */
+ table[KS_POLCTL] = 0x41; /* Timing Signal Polarity Control */
+ table[KS_REFCOD] = 0x80; /* Reference Code Insertion Control */
+ table[KS_INVALY] = 0x10; /* Invalid Y Code */
+ table[KS_INVALU] = 0x80; /* Invalid U Code */
+ table[KS_INVALV] = 0x80; /* Invalid V Code */
+ table[KS_UNUSEY] = 0x10; /* Unused Y Code */
+ table[KS_UNUSEU] = 0x80; /* Unused U Code */
+ table[KS_UNUSEV] = 0x80; /* Unused V Code */
+ table[KS_USRSAV] = 0x00; /* reserved */
+ table[KS_USREAV] = 0x00; /* reserved */
+ table[KS_SHS1A] = 0x00; /* User Defined SHS1 A */
+ /* User Defined SHS1 B, ALT656=1 on 0127B */
+ table[KS_SHS1B] = 0x80;
+ table[KS_SHS1C] = 0x00; /* User Defined SHS1 C */
+ table[KS_CMDE] = 0x00; /* Command Register E */
+ table[KS_VSDEL] = 0x00; /* VS Delay Control */
+ /* Command Register F, update -immediately- */
+ /* (there might come no vsync)*/
+ table[KS_CMDF] = 0x02;
+}
+
+
+/* We need to manually read because of a bug in the KS0127 chip.
+ *
+ * An explanation from kayork@mail.utexas.edu:
+ *
+ * During I2C reads, the KS0127 only samples for a stop condition
+ * during the place where the acknoledge bit should be. Any standard
+ * I2C implementation (correctly) throws in another clock transition
+ * at the 9th bit, and the KS0127 will not recognize the stop condition
+ * and will continue to clock out data.
+ *
+ * So we have to do the read ourself. Big deal.
+ workaround in i2c-algo-bit
+ */
+
+
+static u8 ks0127_read(struct ks0127 *ks, u8 reg)
+{
+ struct i2c_client *c = ks->client;
+ char val = 0;
+ struct i2c_msg msgs[] = {
+ {c->addr, 0, sizeof(reg), &reg},
+ {c->addr, I2C_M_RD | I2C_M_NO_RD_ACK, sizeof(val), &val}};
+ int ret;
+
+ ret = i2c_transfer(c->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret != ARRAY_SIZE(msgs))
+ dprintk("ks0127_write error\n");
+
+ return val;
+}
+
+
+static void ks0127_write(struct ks0127 *ks, u8 reg, u8 val)
+{
+ char msg[] = {reg, val};
+
+ if (i2c_master_send(ks->client, msg, sizeof(msg)) != sizeof(msg))
+ dprintk("ks0127_write error\n");
+
+ ks->regs[reg] = val;
+}
+
+
+/* generic bit-twiddling */
+static void ks0127_and_or(struct ks0127 *ks, u8 reg, u8 and_v, u8 or_v)
+{
+ u8 val = ks->regs[reg];
+ val = (val & and_v) | or_v;
+ ks0127_write(ks, reg, val);
+}
+
+
+
+/****************************************************************************
+* ks0127 private api
+****************************************************************************/
+static void ks0127_reset(struct ks0127* ks)
+{
+ int i;
+ u8 *table = reg_defaults;
+
+ ks->ks_type = KS_TYPE_UNKNOWN;
+
+ dprintk("ks0127: reset\n");
+ msleep(1);
+
+ /* initialize all registers to known values */
+ /* (except STAT, 0x21, 0x22, TEST and 0x38,0x39) */
+
+ for(i = 1; i < 33; i++)
+ ks0127_write(ks, i, table[i]);
+
+ for(i = 35; i < 40; i++)
+ ks0127_write(ks, i, table[i]);
+
+ for(i = 41; i < 56; i++)
+ ks0127_write(ks, i, table[i]);
+
+ for(i = 58; i < 64; i++)
+ ks0127_write(ks, i, table[i]);
+
+
+ if ((ks0127_read(ks, KS_STAT) & 0x80) == 0) {
+ ks->ks_type = KS_TYPE_0122S;
+ dprintk("ks0127: ks0122s Found\n");
+ return;
+ }
+
+ switch(ks0127_read(ks, KS_CMDE) & 0x0f) {
+
+ case 0:
+ ks->ks_type = KS_TYPE_0127;
+ dprintk("ks0127: ks0127 found\n");
+ break;
+
+ case 9:
+ ks->ks_type = KS_TYPE_0127B;
+ dprintk("ks0127: ks0127B Revision A found\n");
+ break;
+
+ default:
+ dprintk("ks0127: unknown revision\n");
+ break;
+ }
+}
+
+static int ks0127_command(struct i2c_client *client,
+ unsigned int cmd, void *arg)
+{
+ struct ks0127 *ks = i2c_get_clientdata(client);
+
+ int *iarg = (int*)arg;
+
+ int status;
+
+ if (!ks)
+ return -ENODEV;
+
+ switch (cmd) {
+
+ case DECODER_INIT:
+ dprintk("ks0127: command DECODER_INIT\n");
+ ks0127_reset(ks);
+ break;
+
+ case DECODER_SET_INPUT:
+ switch(*iarg) {
+ case KS_INPUT_COMPOSITE_1:
+ case KS_INPUT_COMPOSITE_2:
+ case KS_INPUT_COMPOSITE_3:
+ case KS_INPUT_COMPOSITE_4:
+ case KS_INPUT_COMPOSITE_5:
+ case KS_INPUT_COMPOSITE_6:
+ dprintk("ks0127: command DECODER_SET_INPUT %d: "
+ "Composite\n", *iarg);
+ /* autodetect 50/60 Hz */
+ ks0127_and_or(ks, KS_CMDA, 0xfc, 0x00);
+ /* VSE=0 */
+ ks0127_and_or(ks, KS_CMDA, ~0x40, 0x00);
+ /* set input line */
+ ks0127_and_or(ks, KS_CMDB, 0xb0, *iarg);
+ /* non-freerunning mode */
+ ks0127_and_or(ks, KS_CMDC, 0x70, 0x0a);
+ /* analog input */
+ ks0127_and_or(ks, KS_CMDD, 0x03, 0x00);
+ /* enable chroma demodulation */
+ ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x00);
+ /* chroma trap, HYBWR=1 */
+ ks0127_and_or(ks, KS_LUMA, 0x00,
+ (reg_defaults[KS_LUMA])|0x0c);
+ /* scaler fullbw, luma comb off */
+ ks0127_and_or(ks, KS_VERTIA, 0x08, 0x81);
+ /* manual chroma comb .25 .5 .25 */
+ ks0127_and_or(ks, KS_VERTIC, 0x0f, 0x90);
+
+ /* chroma path delay */
+ ks0127_and_or(ks, KS_CHROMB, 0x0f, 0x90);
+
+ ks0127_write(ks, KS_UGAIN, reg_defaults[KS_UGAIN]);
+ ks0127_write(ks, KS_VGAIN, reg_defaults[KS_VGAIN]);
+ ks0127_write(ks, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
+ ks0127_write(ks, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
+ break;
+
+ case KS_INPUT_SVIDEO_1:
+ case KS_INPUT_SVIDEO_2:
+ case KS_INPUT_SVIDEO_3:
+ dprintk("ks0127: command DECODER_SET_INPUT %d: "
+ "S-Video\n", *iarg);
+ /* autodetect 50/60 Hz */
+ ks0127_and_or(ks, KS_CMDA, 0xfc, 0x00);
+ /* VSE=0 */
+ ks0127_and_or(ks, KS_CMDA, ~0x40, 0x00);
+ /* set input line */
+ ks0127_and_or(ks, KS_CMDB, 0xb0, *iarg);
+ /* non-freerunning mode */
+ ks0127_and_or(ks, KS_CMDC, 0x70, 0x0a);
+ /* analog input */
+ ks0127_and_or(ks, KS_CMDD, 0x03, 0x00);
+ /* enable chroma demodulation */
+ ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x00);
+ ks0127_and_or(ks, KS_LUMA, 0x00,
+ reg_defaults[KS_LUMA]);
+ /* disable luma comb */
+ ks0127_and_or(ks, KS_VERTIA, 0x08,
+ (reg_defaults[KS_VERTIA]&0xf0)|0x01);
+ ks0127_and_or(ks, KS_VERTIC, 0x0f,
+ reg_defaults[KS_VERTIC]&0xf0);
+
+ ks0127_and_or(ks, KS_CHROMB, 0x0f,
+ reg_defaults[KS_CHROMB]&0xf0);
+
+ ks0127_write(ks, KS_UGAIN, reg_defaults[KS_UGAIN]);
+ ks0127_write(ks, KS_VGAIN, reg_defaults[KS_VGAIN]);
+ ks0127_write(ks, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
+ ks0127_write(ks, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
+ break;
+
+ case KS_INPUT_YUV656:
+ dprintk("ks0127: command DECODER_SET_INPUT 15: "
+ "YUV656\n");
+ if (ks->norm == VIDEO_MODE_NTSC ||
+ ks->norm == KS_STD_PAL_M)
+ /* force 60 Hz */
+ ks0127_and_or(ks, KS_CMDA, 0xfc, 0x03);
+ else
+ /* force 50 Hz */
+ ks0127_and_or(ks, KS_CMDA, 0xfc, 0x02);
+
+ ks0127_and_or(ks, KS_CMDA, 0xff, 0x40); /* VSE=1 */
+ /* set input line and VALIGN */
+ ks0127_and_or(ks, KS_CMDB, 0xb0, (*iarg | 0x40));
+ /* freerunning mode, */
+ /* TSTGEN = 1 TSTGFR=11 TSTGPH=0 TSTGPK=0 VMEM=1*/
+ ks0127_and_or(ks, KS_CMDC, 0x70, 0x87);
+ /* digital input, SYNDIR = 0 INPSL=01 CLKDIR=0 EAV=0 */
+ ks0127_and_or(ks, KS_CMDD, 0x03, 0x08);
+ /* disable chroma demodulation */
+ ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x30);
+ /* HYPK =01 CTRAP = 0 HYBWR=0 PED=1 RGBH=1 UNIT=1 */
+ ks0127_and_or(ks, KS_LUMA, 0x00, 0x71);
+ ks0127_and_or(ks, KS_VERTIC, 0x0f,
+ reg_defaults[KS_VERTIC]&0xf0);
+
+ /* scaler fullbw, luma comb off */
+ ks0127_and_or(ks, KS_VERTIA, 0x08, 0x81);
+
+ ks0127_and_or(ks, KS_CHROMB, 0x0f,
+ reg_defaults[KS_CHROMB]&0xf0);
+
+ ks0127_and_or(ks, KS_CON, 0x00, 0x00);
+ ks0127_and_or(ks, KS_BRT, 0x00, 32); /* spec: 34 */
+ /* spec: 229 (e5) */
+ ks0127_and_or(ks, KS_SAT, 0x00, 0xe8);
+ ks0127_and_or(ks, KS_HUE, 0x00, 0);
+
+ ks0127_and_or(ks, KS_UGAIN, 0x00, 238);
+ ks0127_and_or(ks, KS_VGAIN, 0x00, 0x00);
+
+ /*UOFF:0x30, VOFF:0x30, TSTCGN=1 */
+ ks0127_and_or(ks, KS_UVOFFH, 0x00, 0x4f);
+ ks0127_and_or(ks, KS_UVOFFL, 0x00, 0x00);
+ break;
+
+ default:
+ dprintk("ks0127: command DECODER_SET_INPUT: "
+ "Unknown input %d\n", *iarg);
+ break;
+ }
+
+ /* hack: CDMLPF sometimes spontaneously switches on; */
+ /* force back off */
+ ks0127_write(ks, KS_DEMOD, reg_defaults[KS_DEMOD]);
+ break;
+
+ case DECODER_SET_OUTPUT:
+ switch(*iarg) {
+ case KS_OUTPUT_YUV656E:
+ dprintk("ks0127: command DECODER_SET_OUTPUT: "
+ "OUTPUT_YUV656E (Missing)\n");
+ return -EINVAL;
+ break;
+
+ case KS_OUTPUT_EXV:
+ dprintk("ks0127: command DECODER_SET_OUTPUT: "
+ "OUTPUT_EXV\n");
+ ks0127_and_or(ks, KS_OFMTA, 0xf0, 0x09);
+ break;
+ }
+ break;
+
+ case DECODER_SET_NORM: //sam This block mixes old and new norm names...
+ /* Set to automatic SECAM/Fsc mode */
+ ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x00);
+
+ ks->norm = *iarg;
+ switch(*iarg)
+ {
+ /* this is untested !! */
+ /* It just detects PAL_N/NTSC_M (no special frequencies) */
+ /* And you have to set the standard a second time afterwards */
+ case VIDEO_MODE_AUTO:
+ dprintk("ks0127: command DECODER_SET_NORM: AUTO\n");
+
+ /* The chip determines the format */
+ /* based on the current field rate */
+ ks0127_and_or(ks, KS_CMDA, 0xfc, 0x00);
+ ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
+ /* This is wrong for PAL ! As I said, */
+ /* you need to set the standard once again !! */
+ ks->format_height = 240;
+ ks->format_width = 704;
+ break;
+
+ case VIDEO_MODE_NTSC:
+ dprintk("ks0127: command DECODER_SET_NORM: NTSC_M\n");
+ ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
+ ks->format_height = 240;
+ ks->format_width = 704;
+ break;
+
+ case KS_STD_NTSC_N:
+ dprintk("ks0127: command KS0127_SET_STANDARD: "
+ "NTSC_N (fixme)\n");
+ ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x40);
+ ks->format_height = 240;
+ ks->format_width = 704;
+ break;
+
+ case VIDEO_MODE_PAL:
+ dprintk("ks0127: command DECODER_SET_NORM: PAL_N\n");
+ ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
+ ks->format_height = 290;
+ ks->format_width = 704;
+ break;
+
+ case KS_STD_PAL_M:
+ dprintk("ks0127: command KS0127_SET_STANDARD: "
+ "PAL_M (fixme)\n");
+ ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x40);
+ ks->format_height = 290;
+ ks->format_width = 704;
+ break;
+
+ case VIDEO_MODE_SECAM:
+ dprintk("ks0127: command KS0127_SET_STANDARD: "
+ "SECAM\n");
+ ks->format_height = 290;
+ ks->format_width = 704;
+
+ /* set to secam autodetection */
+ ks0127_and_or(ks, KS_CHROMA, 0xdf, 0x20);
+ ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x00);
+ schedule_timeout_interruptible(HZ/10+1);
+
+ /* did it autodetect? */
+ if (ks0127_read(ks, KS_DEMOD) & 0x40)
+ break;
+
+ /* force to secam mode */
+ ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x0f);
+ break;
+
+ default:
+ dprintk("ks0127: command DECODER_SET_NORM: "
+ "Unknown norm %d\n", *iarg);
+ break;
+ }
+ break;
+
+ case DECODER_SET_PICTURE:
+ dprintk("ks0127: command DECODER_SET_PICTURE "
+ "not yet supported (fixme)\n");
+ return -EINVAL;
+
+ //sam todo: KS0127_SET_BRIGHTNESS: Merge into DECODER_SET_PICTURE
+ //sam todo: KS0127_SET_CONTRAST: Merge into DECODER_SET_PICTURE
+ //sam todo: KS0127_SET_HUE: Merge into DECODER_SET_PICTURE?
+ //sam todo: KS0127_SET_SATURATION: Merge into DECODER_SET_PICTURE
+ //sam todo: KS0127_SET_AGC_MODE:
+ //sam todo: KS0127_SET_AGC:
+ //sam todo: KS0127_SET_CHROMA_MODE:
+ //sam todo: KS0127_SET_PIXCLK_MODE:
+ //sam todo: KS0127_SET_GAMMA_MODE:
+ //sam todo: KS0127_SET_UGAIN:
+ //sam todo: KS0127_SET_VGAIN:
+ //sam todo: KS0127_SET_INVALY:
+ //sam todo: KS0127_SET_INVALU:
+ //sam todo: KS0127_SET_INVALV:
+ //sam todo: KS0127_SET_UNUSEY:
+ //sam todo: KS0127_SET_UNUSEU:
+ //sam todo: KS0127_SET_UNUSEV:
+ //sam todo: KS0127_SET_VSALIGN_MODE:
+
+ case DECODER_ENABLE_OUTPUT:
+ {
+
+ int *iarg = arg;
+ int enable = (*iarg != 0);
+ if (enable) {
+ dprintk("ks0127: command "
+ "DECODER_ENABLE_OUTPUT on "
+ "(%d)\n", enable);
+ /* All output pins on */
+ ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x30);
+ /* Obey the OEN pin */
+ ks0127_and_or(ks, KS_CDEM, 0x7f, 0x00);
+ } else {
+ dprintk("ks0127: command "
+ "DECODER_ENABLE_OUTPUT off "
+ "(%d)\n", enable);
+ /* Video output pins off */
+ ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x00);
+ /* Ignore the OEN pin */
+ ks0127_and_or(ks, KS_CDEM, 0x7f, 0x80);
+ }
+ }
+ break;
+
+ //sam todo: KS0127_SET_OUTPUT_MODE:
+ //sam todo: KS0127_SET_WIDTH:
+ //sam todo: KS0127_SET_HEIGHT:
+ //sam todo: KS0127_SET_HSCALE:
+
+ case DECODER_GET_STATUS:
+ dprintk("ks0127: command DECODER_GET_STATUS\n");
+ *iarg = 0;
+ status = ks0127_read(ks, KS_STAT);
+ if (!(status & 0x20)) /* NOVID not set */
+ *iarg = (*iarg & DECODER_STATUS_GOOD);
+ if ((status & 0x01)) /* CLOCK set */
+ *iarg = (*iarg & DECODER_STATUS_COLOR);
+ if ((status & 0x08)) /* PALDET set */
+ *iarg = (*iarg & DECODER_STATUS_PAL);
+ else
+ *iarg = (*iarg & DECODER_STATUS_NTSC);
+ break;
+
+ //Catch any unknown command
+ default:
+ dprintk("ks0127: command unknown: %04X\n", cmd);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+
+
+static int ks0127_probe(struct i2c_adapter *adapter);
+static int ks0127_detach(struct i2c_client *client);
+static int ks0127_command(struct i2c_client *client,
+ unsigned int cmd, void *arg);
+
+
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {I2C_KS0127_ADDON>>1,
+ I2C_KS0127_ONBOARD>>1, I2C_CLIENT_END};
+static unsigned short probe[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
+static unsigned short ignore[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
+static struct i2c_client_address_data addr_data = {
+ normal_i2c,
+ probe,
+ ignore,
+};
+
+static struct i2c_driver i2c_driver_ks0127 = {
+ .driver.name = "ks0127",
+ .id = I2C_DRIVERID_KS0127,
+ .attach_adapter = ks0127_probe,
+ .detach_client = ks0127_detach,
+ .command = ks0127_command
+};
+
+static struct i2c_client ks0127_client_tmpl =
+{
+ .name = "(ks0127 unset)",
+ .addr = 0,
+ .adapter = NULL,
+ .driver = &i2c_driver_ks0127,
+ .usage_count = 0
+};
+
+static int ks0127_found_proc(struct i2c_adapter *adapter, int addr, int kind)
+{
+ struct ks0127 *ks;
+ struct i2c_client *client;
+
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (client == NULL)
+ return -ENOMEM;
+ memcpy(client, &ks0127_client_tmpl, sizeof(*client));
+
+ ks = kzalloc(sizeof(*ks), GFP_KERNEL);
+ if (ks == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(client, ks);
+ client->adapter = adapter;
+ client->addr = addr;
+ sprintf(client->name, "ks0127-%02x", adapter->id);
+
+ ks->client = client;
+ ks->addr = addr;
+ ks->ks_type = KS_TYPE_UNKNOWN;
+
+ /* power up */
+ ks0127_write(ks, KS_CMDA, 0x2c);
+ mdelay(10);
+
+ /* reset the device */
+ ks0127_reset(ks);
+ printk(KERN_INFO "ks0127: attach: %s video decoder\n",
+ ks->addr==(I2C_KS0127_ADDON>>1) ? "addon" : "on-board");
+
+ i2c_attach_client(client);
+ return 0;
+}
+
+
+static int ks0127_probe(struct i2c_adapter *adapter)
+{
+ if (adapter->id == I2C_HW_B_ZR36067)
+ return i2c_probe(adapter, &addr_data, ks0127_found_proc);
+ return 0;
+}
+
+static int ks0127_detach(struct i2c_client *client)
+{
+ struct ks0127 *ks = i2c_get_clientdata(client);
+
+ ks0127_write(ks, KS_OFMTA, 0x20); /*tristate*/
+ ks0127_write(ks, KS_CMDA, 0x2c | 0x80); /* power down */
+
+ i2c_detach_client(client);
+ kfree(ks);
+ kfree(client);
+
+ dprintk("ks0127: detach\n");
+ return 0;
+}
+
+
+static int __devinit ks0127_init_module(void)
+{
+ init_reg_defaults();
+ i2c_add_driver(&i2c_driver_ks0127);
+ return 0;
+}
+
+static void __devexit ks0127_cleanup_module(void)
+{
+ i2c_del_driver(&i2c_driver_ks0127);
+}
+
+
+module_init(ks0127_init_module);
+module_exit(ks0127_cleanup_module);
diff --git a/drivers/media/video/ks0127.h b/drivers/media/video/ks0127.h
new file mode 100644
index 0000000..1ec5788
--- /dev/null
+++ b/drivers/media/video/ks0127.h
@@ -0,0 +1,53 @@
+/*
+ * Video Capture Driver ( Video for Linux 1/2 )
+ * for the Matrox Marvel G200,G400 and Rainbow Runner-G series
+ *
+ * This module is an interface to the KS0127 video decoder chip.
+ *
+ * Copyright (C) 1999 Ryan Drake <stiletto@mediaone.net>
+ *
+ * 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 KS0127_H
+#define KS0127_H
+
+#include <linux/videodev.h>
+
+/* input channels */
+#define KS_INPUT_COMPOSITE_1 0
+#define KS_INPUT_COMPOSITE_2 1
+#define KS_INPUT_COMPOSITE_3 2
+#define KS_INPUT_COMPOSITE_4 4
+#define KS_INPUT_COMPOSITE_5 5
+#define KS_INPUT_COMPOSITE_6 6
+
+#define KS_INPUT_SVIDEO_1 8
+#define KS_INPUT_SVIDEO_2 9
+#define KS_INPUT_SVIDEO_3 10
+
+#define KS_INPUT_YUV656 15
+#define KS_INPUT_COUNT 10
+
+/* output channels */
+#define KS_OUTPUT_YUV656E 0
+#define KS_OUTPUT_EXV 1
+
+/* video standards */
+#define KS_STD_NTSC_N 112 /* 50 Hz NTSC */
+#define KS_STD_PAL_M 113 /* 60 Hz PAL */
+
+#endif /* KS0127_H */
+
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 850bee9..f68ca7d 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -32,6 +32,7 @@
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/delay.h>
@@ -1682,13 +1683,13 @@ static unsigned int meye_poll(struct file *file, poll_table *wait)
static void meye_vm_open(struct vm_area_struct *vma)
{
- int idx = (int)vma->vm_private_data;
+ long idx = (long)vma->vm_private_data;
meye.vma_use_count[idx]++;
}
static void meye_vm_close(struct vm_area_struct *vma)
{
- int idx = (int)vma->vm_private_data;
+ long idx = (long)vma->vm_private_data;
meye.vma_use_count[idx]--;
}
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index b806999..dbb75a7 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -385,67 +385,6 @@ static int msp_mode_v4l1_to_v4l2(int mode)
return V4L2_TUNER_MODE_MONO;
}
-static struct v4l2_queryctrl msp_qctrl_std[] = {
- {
- .id = V4L2_CID_AUDIO_VOLUME,
- .name = "Volume",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 58880,
- .flags = 0,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_AUDIO_MUTE,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- .flags = 0,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },
-};
-
-static struct v4l2_queryctrl msp_qctrl_sound_processing[] = {
- {
- .id = V4L2_CID_AUDIO_BALANCE,
- .name = "Balance",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- .flags = 0,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_AUDIO_BASS,
- .name = "Bass",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_AUDIO_TREBLE,
- .name = "Treble",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_AUDIO_LOUDNESS,
- .name = "Loudness",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- .flags = 0,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },
-};
-
-
static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
{
struct msp_state *state = i2c_get_clientdata(client);
@@ -674,22 +613,31 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
int sc1_out = rt->output & 0xf;
int sc2_out = (rt->output >> 4) & 0xf;
u16 val, reg;
+ int i;
+ int extern_input = 1;
if (state->routing.input == rt->input &&
state->routing.output == rt->output)
break;
state->routing = *rt;
+ /* check if the tuner input is used */
+ for (i = 0; i < 5; i++) {
+ if (((rt->input >> (4 + i * 4)) & 0xf) == 0)
+ extern_input = 0;
+ }
+ if (extern_input)
+ state->mode = MSP_MODE_EXTERN;
+ else
+ state->mode = MSP_MODE_AM_DETECT;
msp_set_scart(client, sc_in, 0);
msp_set_scart(client, sc1_out, 1);
msp_set_scart(client, sc2_out, 2);
msp_set_audmode(client);
reg = (state->opmode == OPMODE_AUTOSELECT) ? 0x30 : 0xbb;
val = msp_read_dem(client, reg);
- if (tuner != ((val >> 8) & 1)) {
- msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8));
- /* wake thread when a new tuner input is chosen */
- msp_wake_thread(client);
- }
+ msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8));
+ /* wake thread when a new input is chosen */
+ msp_wake_thread(client);
break;
}
@@ -744,21 +692,25 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
case VIDIOC_QUERYCTRL:
{
struct v4l2_queryctrl *qc = arg;
- int i;
- for (i = 0; i < ARRAY_SIZE(msp_qctrl_std); i++)
- if (qc->id && qc->id == msp_qctrl_std[i].id) {
- memcpy(qc, &msp_qctrl_std[i], sizeof(*qc));
- return 0;
- }
+ switch (qc->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_MUTE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ break;
+ }
if (!state->has_sound_processing)
return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(msp_qctrl_sound_processing); i++)
- if (qc->id && qc->id == msp_qctrl_sound_processing[i].id) {
- memcpy(qc, &msp_qctrl_sound_processing[i], sizeof(*qc));
- return 0;
- }
- return -EINVAL;
+ switch (qc->id) {
+ case V4L2_CID_AUDIO_LOUDNESS:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ return -EINVAL;
+ }
}
case VIDIOC_G_CTRL:
@@ -794,7 +746,9 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
case MSP_MODE_EXTERN: p = "External input"; break;
default: p = "unknown"; break;
}
- if (state->opmode == OPMODE_MANUAL) {
+ if (state->mode == MSP_MODE_EXTERN) {
+ v4l_info(client, "Mode: %s\n", p);
+ } else if (state->opmode == OPMODE_MANUAL) {
v4l_info(client, "Mode: %s (%s%s)\n", p,
(state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono",
(state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : "");
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
index 633a102..f2fd919 100644
--- a/drivers/media/video/msp3400-kthreads.c
+++ b/drivers/media/video/msp3400-kthreads.c
@@ -244,19 +244,21 @@ static void msp3400c_set_audmode(struct i2c_client *client)
the hardware does not support SAP. So the rxsubchans combination
of STEREO | LANG2 does not occur. */
- /* switch to mono if only mono is available */
- if (state->rxsubchans == V4L2_TUNER_SUB_MONO)
- audmode = V4L2_TUNER_MODE_MONO;
- /* if bilingual */
- else if (state->rxsubchans & V4L2_TUNER_SUB_LANG2) {
- /* and mono or stereo, then fallback to lang1 */
- if (audmode == V4L2_TUNER_MODE_MONO ||
- audmode == V4L2_TUNER_MODE_STEREO)
- audmode = V4L2_TUNER_MODE_LANG1;
+ if (state->mode != MSP_MODE_EXTERN) {
+ /* switch to mono if only mono is available */
+ if (state->rxsubchans == V4L2_TUNER_SUB_MONO)
+ audmode = V4L2_TUNER_MODE_MONO;
+ /* if bilingual */
+ else if (state->rxsubchans & V4L2_TUNER_SUB_LANG2) {
+ /* and mono or stereo, then fallback to lang1 */
+ if (audmode == V4L2_TUNER_MODE_MONO ||
+ audmode == V4L2_TUNER_MODE_STEREO)
+ audmode = V4L2_TUNER_MODE_LANG1;
+ }
+ /* if stereo, and audmode is not mono, then switch to stereo */
+ else if (audmode != V4L2_TUNER_MODE_MONO)
+ audmode = V4L2_TUNER_MODE_STEREO;
}
- /* if stereo, and audmode is not mono, then switch to stereo */
- else if (audmode != V4L2_TUNER_MODE_MONO)
- audmode = V4L2_TUNER_MODE_STEREO;
/* switch demodulator */
switch (state->mode) {
@@ -481,6 +483,7 @@ int msp3400c_thread(void *data)
/* no carrier scan, just unmute */
v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
state->scan_in_progress = 0;
+ state->rxsubchans = V4L2_TUNER_SUB_STEREO;
msp_set_audio(client);
continue;
}
@@ -947,6 +950,14 @@ int msp34xxg_thread(void *data)
if (kthread_should_stop())
break;
+ if (state->mode == MSP_MODE_EXTERN) {
+ /* no carrier scan needed, just unmute */
+ v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
+ state->scan_in_progress = 0;
+ msp_set_audio(client);
+ continue;
+ }
+
/* setup the chip*/
msp34xxg_reset(client);
state->std = state->radio ? 0x40 : msp_standard;
@@ -978,6 +989,11 @@ int msp34xxg_thread(void *data)
v4l_dbg(1, msp_debug, client, "detected standard: %s (0x%04x)\n",
msp_standard_std_name(state->std), state->std);
+ if (state->std == 9) {
+ /* AM NICAM mode */
+ msp_write_dsp(client, 0x0e, 0x7c00);
+ }
+
/* unmute: dispatch sound to scart output, set scart volume */
msp_set_audio(client);
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
index fdc8e3f..a988df2 100644
--- a/drivers/media/video/ov511.c
+++ b/drivers/media/video/ov511.c
@@ -3239,7 +3239,7 @@ ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
if (frame->scanstate == STATE_LINES) {
- int nextf;
+ int nextf;
frame->grabstate = FRAME_DONE;
wake_up_interruptible(&frame->wq);
@@ -3405,7 +3405,7 @@ eof:
RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
if (frame->scanstate == STATE_LINES) {
- int nextf;
+ int nextf;
frame->grabstate = FRAME_DONE;
wake_up_interruptible(&frame->wq);
diff --git a/drivers/media/video/ov511.h b/drivers/media/video/ov511.h
index 12b3d51..68b082b 100644
--- a/drivers/media/video/ov511.h
+++ b/drivers/media/video/ov511.h
@@ -3,6 +3,7 @@
#include <asm/uaccess.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/smp_lock.h>
#include <linux/usb.h>
#include <linux/mutex.h>
diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c
index d9e3cad..3484e36 100644
--- a/drivers/media/video/planb.c
+++ b/drivers/media/video/planb.c
@@ -40,6 +40,7 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/wait.h>
#include <asm/uaccess.h>
#include <asm/io.h>
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index 09835ca..5d681fa 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -30,6 +30,7 @@
#include <asm/io.h>
#include <linux/sched.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
@@ -804,7 +805,7 @@ static int pms_do_ioctl(struct inode *inode, struct file *file,
struct video_picture *p = arg;
if(!((p->palette==VIDEO_PALETTE_RGB565 && p->depth==16)
||(p->palette==VIDEO_PALETTE_RGB555 && p->depth==15)))
- return -EINVAL;
+ return -EINVAL;
pd->picture= *p;
/*
diff --git a/drivers/media/video/pwc/Kconfig b/drivers/media/video/pwc/Kconfig
index 53cbc95..697145e 100644
--- a/drivers/media/video/pwc/Kconfig
+++ b/drivers/media/video/pwc/Kconfig
@@ -7,6 +7,7 @@ config USB_PWC
* Philips PCA645, PCA646
* Philips PCVC675, PCVC680, PCVC690
* Philips PCVC720/40, PCVC730, PCVC740, PCVC750
+ * Philips SPC900NC
* Askey VC010
* Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro'
and 'Orbit'/'Sphere'
@@ -19,10 +20,18 @@ config USB_PWC
and never will be, but the 665 and 720/20 are supported by other
drivers.
- See <file:Documentation/usb/philips.txt> for more information and
- installation instructions.
+ Some newer logitech webcams are not handled by this driver but by the
+ Usb Video Class driver (linux-uvc).
The built-in microphone is enabled by selecting USB Audio support.
To compile this driver as a module, choose M here: the
module will be called pwc.
+
+config USB_PWC_DEBUG
+ bool "USB Philips Cameras verbose debug"
+ depends USB_PWC
+ help
+ Say Y here in order to have the pwc driver generate verbose debugging
+ messages.
+ A special module options 'trace' is used to control the verbosity.
diff --git a/drivers/media/video/pwc/Makefile b/drivers/media/video/pwc/Makefile
index 33d6012..9db2260 100644
--- a/drivers/media/video/pwc/Makefile
+++ b/drivers/media/video/pwc/Makefile
@@ -1,3 +1,12 @@
-pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o pwc-timon.o pwc-kiara.o
+pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-v4l.o pwc-uncompress.o
+pwc-objs += pwc-dec1.o pwc-dec23.o pwc-kiara.o pwc-timon.o
obj-$(CONFIG_USB_PWC) += pwc.o
+
+ifeq ($(CONFIG_USB_PWC_DEBUG),y)
+EXTRA_CFLAGS += -DCONFIG_PWC_DEBUG=1
+else
+EXTRA_CFLAGS += -DCONFIG_PWC_DEBUG=0
+endif
+
+
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c
index 4ba549b..0bd1155 100644
--- a/drivers/media/video/pwc/pwc-ctrl.c
+++ b/drivers/media/video/pwc/pwc-ctrl.c
@@ -2,7 +2,7 @@
Functions that send various control messages to the webcam, including
video modes.
(C) 1999-2003 Nemosoft Unv.
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
@@ -41,12 +41,14 @@
#include <asm/uaccess.h>
#endif
#include <asm/errno.h>
+#include <linux/version.h>
#include "pwc.h"
-#include "pwc-ioctl.h"
#include "pwc-uncompress.h"
#include "pwc-kiara.h"
#include "pwc-timon.h"
+#include "pwc-dec1.h"
+#include "pwc-dec23.h"
/* Request types: video */
#define SET_LUM_CTL 0x01
@@ -57,6 +59,10 @@
#define GET_STATUS_CTL 0x06
#define SET_EP_STREAM_CTL 0x07
#define GET_EP_STREAM_CTL 0x08
+#define GET_XX_CTL 0x09
+#define SET_XX_CTL 0x0A
+#define GET_XY_CTL 0x0B
+#define SET_XY_CTL 0x0C
#define SET_MPT_CTL 0x0D
#define GET_MPT_CTL 0x0E
@@ -93,12 +99,20 @@
#define READ_SHUTTER_FORMATTER 0x0600
#define READ_RED_GAIN_FORMATTER 0x0700
#define READ_BLUE_GAIN_FORMATTER 0x0800
+#define GET_STATUS_B00 0x0B00
#define SENSOR_TYPE_FORMATTER1 0x0C00
+#define GET_STATUS_3000 0x3000
#define READ_RAW_Y_MEAN_FORMATTER 0x3100
#define SET_POWER_SAVE_MODE_FORMATTER 0x3200
#define MIRROR_IMAGE_FORMATTER 0x3300
#define LED_FORMATTER 0x3400
+#define LOWLIGHT 0x3500
+#define GET_STATUS_3600 0x3600
#define SENSOR_TYPE_FORMATTER2 0x3700
+#define GET_STATUS_3800 0x3800
+#define GET_STATUS_4000 0x4000
+#define GET_STATUS_4100 0x4100 /* Get */
+#define CTL_STATUS_4200 0x4200 /* [GS] 1 */
/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
#define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100
@@ -138,6 +152,7 @@ static struct Nala_table_entry Nala_table[PSZ_MAX][8] =
#include "pwc-nala.h"
};
+static void pwc_set_image_buffer_size(struct pwc_device *pdev);
/****************************************************************************/
@@ -159,31 +174,7 @@ static struct Nala_table_entry Nala_table[PSZ_MAX][8] =
&buf, buflen, 500)
-#if PWC_DEBUG
-void pwc_hexdump(void *p, int len)
-{
- int i;
- unsigned char *s;
- char buf[100], *d;
-
- s = (unsigned char *)p;
- d = buf;
- *d = '\0';
- Debug("Doing hexdump @ %p, %d bytes.\n", p, len);
- for (i = 0; i < len; i++) {
- d += sprintf(d, "%02X ", *s++);
- if ((i & 0xF) == 0xF) {
- Debug("%s\n", buf);
- d = buf;
- *d = '\0';
- }
- }
- if ((i & 0xF) != 0)
- Debug("%s\n", buf);
-}
-#endif
-
-static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen)
+static int send_video_command(struct usb_device *udev, int index, void *buf, int buflen)
{
return usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
@@ -196,7 +187,7 @@ static inline int send_video_command(struct usb_device *udev, int index, void *b
-static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
+static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
{
unsigned char buf[3];
int ret, fps;
@@ -229,34 +220,14 @@ static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int fra
if (pEntry->alternate == 0)
return -EINVAL;
- if (pEntry->compressed)
- return -ENOENT; /* Not supported. */
-
memcpy(buf, pEntry->mode, 3);
ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3);
if (ret < 0) {
- Debug("Failed to send video command... %d\n", ret);
+ PWC_DEBUG_MODULE("Failed to send video command... %d\n", ret);
return ret;
}
if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW)
- {
- switch(pdev->type) {
- case 645:
- case 646:
-/* pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
- break;
-
- case 675:
- case 680:
- case 690:
- case 720:
- case 730:
- case 740:
- case 750:
-/* pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
- break;
- }
- }
+ pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data);
pdev->cmd_len = 3;
memcpy(pdev->cmd_buf, buf, 3);
@@ -283,7 +254,7 @@ static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int fra
}
-static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
{
unsigned char buf[13];
const struct Timon_table_entry *pChoose;
@@ -315,8 +286,8 @@ static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int fr
if (ret < 0)
return ret;
-/* if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
- pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+ if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+ pwc_dec23_init(pdev, pdev->type, buf);
pdev->cmd_len = 13;
memcpy(pdev->cmd_buf, buf, 13);
@@ -336,7 +307,7 @@ static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int fr
}
-static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
{
const struct Kiara_table_entry *pChoose = NULL;
int fps, ret;
@@ -350,21 +321,14 @@ static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int fr
fps = (frames / 5) - 1;
/* special case: VGA @ 5 fps and snapshot is raw bayer mode */
- if (size == PSZ_VGA && frames == 5 && snapshot)
+ if (size == PSZ_VGA && frames == 5 && snapshot && pdev->vpalette == VIDEO_PALETTE_RAW)
{
/* Only available in case the raw palette is selected or
we have the decompressor available. This mode is
only available in compressed form
*/
- if (pdev->vpalette == VIDEO_PALETTE_RAW)
- {
- Info("Choosing VGA/5 BAYER mode (%d).\n", pdev->vpalette);
- pChoose = &RawEntry;
- }
- else
- {
- Info("VGA/5 BAYER mode _must_ have a decompressor available, or use RAW palette.\n");
- }
+ PWC_DEBUG_SIZE("Choosing VGA/5 BAYER mode.\n");
+ pChoose = &RawEntry;
}
else
{
@@ -372,6 +336,7 @@ static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int fr
if the preferred ratio is not available.
Skip this step when using RAW modes.
*/
+ snapshot = 0;
while (compression <= 3) {
pChoose = &Kiara_table[size][fps][compression];
if (pChoose->alternate != 0)
@@ -382,7 +347,7 @@ static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int fr
if (pChoose == NULL || pChoose->alternate == 0)
return -ENOENT; /* Not supported. */
- Debug("Using alternate setting %d.\n", pChoose->alternate);
+ PWC_TRACE("Using alternate setting %d.\n", pChoose->alternate);
/* usb_control_msg won't take staticly allocated arrays as argument?? */
memcpy(buf, pChoose->mode, 12);
@@ -394,8 +359,8 @@ static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int fr
if (ret < 0)
return ret;
-/* if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
- pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+ if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+ pwc_dec23_init(pdev, pdev->type, buf);
pdev->cmd_len = 12;
memcpy(pdev->cmd_buf, buf, 12);
@@ -410,49 +375,13 @@ static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int fr
pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4;
else
pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
+ PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vsnapshot=%d, vbandlength=%d\n",
+ pdev->frame_size,pdev->vframes,pdev->vsize,pdev->vsnapshot,pdev->vbandlength);
return 0;
}
-static void pwc_set_image_buffer_size(struct pwc_device *pdev)
-{
- int i, factor = 0, filler = 0;
-
- /* for PALETTE_YUV420P */
- switch(pdev->vpalette)
- {
- case VIDEO_PALETTE_YUV420P:
- factor = 6;
- filler = 128;
- break;
- case VIDEO_PALETTE_RAW:
- factor = 6; /* can be uncompressed YUV420P */
- filler = 0;
- break;
- }
-
- /* Set sizes in bytes */
- pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
- pdev->view.size = pdev->view.x * pdev->view.y * factor / 4;
-
- /* Align offset, or you'll get some very weird results in
- YUV420 mode... x must be multiple of 4 (to get the Y's in
- place), and y even (or you'll mixup U & V). This is less of a
- problem for YUV420P.
- */
- pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
- pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
-
- /* Fill buffers with gray or black */
- for (i = 0; i < MAX_IMAGES; i++) {
- if (pdev->image_ptr[i] != NULL)
- memset(pdev->image_ptr[i], filler, pdev->view.size);
- }
-}
-
-
-
/**
@pdev: device structure
@width: viewport width
@@ -465,50 +394,78 @@ int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frame
{
int ret, size;
- Trace(TRACE_FLOW, "set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette);
+ PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette);
size = pwc_decode_size(pdev, width, height);
if (size < 0) {
- Debug("Could not find suitable size.\n");
+ PWC_DEBUG_MODULE("Could not find suitable size.\n");
return -ERANGE;
}
- Debug("decode_size = %d.\n", size);
+ PWC_TRACE("decode_size = %d.\n", size);
- ret = -EINVAL;
- switch(pdev->type) {
- case 645:
- case 646:
+ if (DEVICE_USE_CODEC1(pdev->type)) {
ret = set_video_mode_Nala(pdev, size, frames);
- break;
- case 675:
- case 680:
- case 690:
- ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
- break;
-
- case 720:
- case 730:
- case 740:
- case 750:
+ } else if (DEVICE_USE_CODEC3(pdev->type)) {
ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot);
- break;
+
+ } else {
+ ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
}
if (ret < 0) {
- if (ret == -ENOENT)
- Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames);
- else {
- Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
- }
+ PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
return ret;
}
pdev->view.x = width;
pdev->view.y = height;
pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
pwc_set_image_buffer_size(pdev);
- Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
+ PWC_DEBUG_SIZE("Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
return 0;
}
+#define BLACK_Y 0
+#define BLACK_U 128
+#define BLACK_V 128
+
+static void pwc_set_image_buffer_size(struct pwc_device *pdev)
+{
+ int i, factor = 0;
+
+ /* for PALETTE_YUV420P */
+ switch(pdev->vpalette)
+ {
+ case VIDEO_PALETTE_YUV420P:
+ factor = 6;
+ break;
+ case VIDEO_PALETTE_RAW:
+ factor = 6; /* can be uncompressed YUV420P */
+ break;
+ }
+
+ /* Set sizes in bytes */
+ pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
+ pdev->view.size = pdev->view.x * pdev->view.y * factor / 4;
+
+ /* Align offset, or you'll get some very weird results in
+ YUV420 mode... x must be multiple of 4 (to get the Y's in
+ place), and y even (or you'll mixup U & V). This is less of a
+ problem for YUV420P.
+ */
+ pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
+ pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
+
+ /* Fill buffers with black colors */
+ for (i = 0; i < pwc_mbufs; i++) {
+ unsigned char *p = pdev->image_data + pdev->images[i].offset;
+ memset(p, BLACK_Y, pdev->view.x * pdev->view.y);
+ p += pdev->view.x * pdev->view.y;
+ memset(p, BLACK_U, pdev->view.x * pdev->view.y/4);
+ p += pdev->view.x * pdev->view.y/4;
+ memset(p, BLACK_V, pdev->view.x * pdev->view.y/4);
+ }
+}
+
+
/* BRIGHTNESS */
@@ -520,7 +477,7 @@ int pwc_get_brightness(struct pwc_device *pdev)
ret = RecvControlMsg(GET_LUM_CTL, BRIGHTNESS_FORMATTER, 1);
if (ret < 0)
return ret;
- return buf << 9;
+ return buf;
}
int pwc_set_brightness(struct pwc_device *pdev, int value)
@@ -545,7 +502,7 @@ int pwc_get_contrast(struct pwc_device *pdev)
ret = RecvControlMsg(GET_LUM_CTL, CONTRAST_FORMATTER, 1);
if (ret < 0)
return ret;
- return buf << 10;
+ return buf;
}
int pwc_set_contrast(struct pwc_device *pdev, int value)
@@ -570,7 +527,7 @@ int pwc_get_gamma(struct pwc_device *pdev)
ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1);
if (ret < 0)
return ret;
- return buf << 11;
+ return buf;
}
int pwc_set_gamma(struct pwc_device *pdev, int value)
@@ -588,37 +545,47 @@ int pwc_set_gamma(struct pwc_device *pdev, int value)
/* SATURATION */
-int pwc_get_saturation(struct pwc_device *pdev)
+/* return a value between [-100 , 100] */
+int pwc_get_saturation(struct pwc_device *pdev, int *value)
{
char buf;
- int ret;
+ int ret, saturation_register;
if (pdev->type < 675)
- return -1;
- ret = RecvControlMsg(GET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1);
+ return -EINVAL;
+ if (pdev->type < 730)
+ saturation_register = SATURATION_MODE_FORMATTER2;
+ else
+ saturation_register = SATURATION_MODE_FORMATTER1;
+ ret = RecvControlMsg(GET_CHROM_CTL, saturation_register, 1);
if (ret < 0)
return ret;
- return 32768 + buf * 327;
+ *value = (signed)buf;
+ return 0;
}
+/* @param value saturation color between [-100 , 100] */
int pwc_set_saturation(struct pwc_device *pdev, int value)
{
char buf;
+ int saturation_register;
if (pdev->type < 675)
return -EINVAL;
- if (value < 0)
- value = 0;
- if (value > 0xffff)
- value = 0xffff;
- /* saturation ranges from -100 to +100 */
- buf = (value - 32768) / 327;
- return SendControlMsg(SET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1);
+ if (value < -100)
+ value = -100;
+ if (value > 100)
+ value = 100;
+ if (pdev->type < 730)
+ saturation_register = SATURATION_MODE_FORMATTER2;
+ else
+ saturation_register = SATURATION_MODE_FORMATTER1;
+ return SendControlMsg(SET_CHROM_CTL, saturation_register, 1);
}
/* AGC */
-static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
+int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
{
char buf;
int ret;
@@ -643,7 +610,7 @@ static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
return 0;
}
-static inline int pwc_get_agc(struct pwc_device *pdev, int *value)
+int pwc_get_agc(struct pwc_device *pdev, int *value)
{
unsigned char buf;
int ret;
@@ -673,7 +640,7 @@ static inline int pwc_get_agc(struct pwc_device *pdev, int *value)
return 0;
}
-static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
+int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
{
char buf[2];
int speed, ret;
@@ -691,23 +658,16 @@ static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int v
value = 0;
if (value > 0xffff)
value = 0xffff;
- switch(pdev->type) {
- case 675:
- case 680:
- case 690:
+
+ if (DEVICE_USE_CODEC2(pdev->type)) {
/* speed ranges from 0x0 to 0x290 (656) */
speed = (value / 100);
buf[1] = speed >> 8;
buf[0] = speed & 0xff;
- break;
- case 720:
- case 730:
- case 740:
- case 750:
+ } else if (DEVICE_USE_CODEC3(pdev->type)) {
/* speed seems to range from 0x0 to 0xff */
buf[1] = 0;
buf[0] = value >> 8;
- break;
}
ret = SendControlMsg(SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, 2);
@@ -715,6 +675,25 @@ static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int v
return ret;
}
+/* This function is not exported to v4l1, so output values between 0 -> 256 */
+int pwc_get_shutter_speed(struct pwc_device *pdev, int *value)
+{
+ unsigned char buf[2];
+ int ret;
+
+ ret = RecvControlMsg(GET_STATUS_CTL, READ_SHUTTER_FORMATTER, 2);
+ if (ret < 0)
+ return ret;
+ *value = buf[0] + (buf[1] << 8);
+ if (DEVICE_USE_CODEC2(pdev->type)) {
+ /* speed ranges from 0x0 to 0x290 (656) */
+ *value *= 256/656;
+ } else if (DEVICE_USE_CODEC3(pdev->type)) {
+ /* speed seems to range from 0x0 to 0xff */
+ }
+ return 0;
+}
+
/* POWER */
@@ -736,19 +715,19 @@ int pwc_camera_power(struct pwc_device *pdev, int power)
/* private calls */
-static inline int pwc_restore_user(struct pwc_device *pdev)
+int pwc_restore_user(struct pwc_device *pdev)
{
char buf; /* dummy */
return SendControlMsg(SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, 0);
}
-static inline int pwc_save_user(struct pwc_device *pdev)
+int pwc_save_user(struct pwc_device *pdev)
{
char buf; /* dummy */
return SendControlMsg(SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, 0);
}
-static inline int pwc_restore_factory(struct pwc_device *pdev)
+int pwc_restore_factory(struct pwc_device *pdev)
{
char buf; /* dummy */
return SendControlMsg(SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, 0);
@@ -766,7 +745,7 @@ static inline int pwc_restore_factory(struct pwc_device *pdev)
* 03: manual
* 04: auto
*/
-static inline int pwc_set_awb(struct pwc_device *pdev, int mode)
+int pwc_set_awb(struct pwc_device *pdev, int mode)
{
char buf;
int ret;
@@ -786,7 +765,7 @@ static inline int pwc_set_awb(struct pwc_device *pdev, int mode)
return 0;
}
-static inline int pwc_get_awb(struct pwc_device *pdev)
+int pwc_get_awb(struct pwc_device *pdev)
{
unsigned char buf;
int ret;
@@ -798,7 +777,7 @@ static inline int pwc_get_awb(struct pwc_device *pdev)
return buf;
}
-static inline int pwc_set_red_gain(struct pwc_device *pdev, int value)
+int pwc_set_red_gain(struct pwc_device *pdev, int value)
{
unsigned char buf;
@@ -811,7 +790,7 @@ static inline int pwc_set_red_gain(struct pwc_device *pdev, int value)
return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1);
}
-static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value)
+int pwc_get_red_gain(struct pwc_device *pdev, int *value)
{
unsigned char buf;
int ret;
@@ -824,7 +803,7 @@ static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value)
}
-static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value)
+int pwc_set_blue_gain(struct pwc_device *pdev, int value)
{
unsigned char buf;
@@ -837,7 +816,7 @@ static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value)
return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1);
}
-static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
+int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
{
unsigned char buf;
int ret;
@@ -854,7 +833,7 @@ static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
internal red/blue gains, which may be different from the manual
gains set or read above.
*/
-static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value)
+static int pwc_read_red_gain(struct pwc_device *pdev, int *value)
{
unsigned char buf;
int ret;
@@ -866,7 +845,7 @@ static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value)
return 0;
}
-static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
+static int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
{
unsigned char buf;
int ret;
@@ -879,7 +858,7 @@ static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
}
-static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
+static int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
{
unsigned char buf;
@@ -888,7 +867,7 @@ static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1);
}
-static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
+static int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
{
unsigned char buf;
int ret;
@@ -901,7 +880,7 @@ static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
}
-static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
+static int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
{
unsigned char buf;
@@ -910,7 +889,7 @@ static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1);
}
-static inline int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
+static int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
{
unsigned char buf;
int ret;
@@ -965,7 +944,7 @@ static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
return 0;
}
-static inline int pwc_set_contour(struct pwc_device *pdev, int contour)
+int pwc_set_contour(struct pwc_device *pdev, int contour)
{
unsigned char buf;
int ret;
@@ -990,7 +969,7 @@ static inline int pwc_set_contour(struct pwc_device *pdev, int contour)
return 0;
}
-static inline int pwc_get_contour(struct pwc_device *pdev, int *contour)
+int pwc_get_contour(struct pwc_device *pdev, int *contour)
{
unsigned char buf;
int ret;
@@ -1012,7 +991,7 @@ static inline int pwc_get_contour(struct pwc_device *pdev, int *contour)
}
-static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight)
+int pwc_set_backlight(struct pwc_device *pdev, int backlight)
{
unsigned char buf;
@@ -1023,7 +1002,7 @@ static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight)
return SendControlMsg(SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
}
-static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
+int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
{
int ret;
unsigned char buf;
@@ -1031,12 +1010,35 @@ static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
ret = RecvControlMsg(GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
if (ret < 0)
return ret;
- *backlight = buf;
+ *backlight = !!buf;
return 0;
}
+int pwc_set_colour_mode(struct pwc_device *pdev, int colour)
+{
+ unsigned char buf;
-static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker)
+ if (colour)
+ buf = 0xff;
+ else
+ buf = 0x0;
+ return SendControlMsg(SET_CHROM_CTL, COLOUR_MODE_FORMATTER, 1);
+}
+
+int pwc_get_colour_mode(struct pwc_device *pdev, int *colour)
+{
+ int ret;
+ unsigned char buf;
+
+ ret = RecvControlMsg(GET_CHROM_CTL, COLOUR_MODE_FORMATTER, 1);
+ if (ret < 0)
+ return ret;
+ *colour = !!buf;
+ return 0;
+}
+
+
+int pwc_set_flicker(struct pwc_device *pdev, int flicker)
{
unsigned char buf;
@@ -1047,7 +1049,7 @@ static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker)
return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
}
-static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
+int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
{
int ret;
unsigned char buf;
@@ -1055,12 +1057,11 @@ static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
if (ret < 0)
return ret;
- *flicker = buf;
+ *flicker = !!buf;
return 0;
}
-
-static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
+int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
{
unsigned char buf;
@@ -1072,7 +1073,7 @@ static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
}
-static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
+int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
{
int ret;
unsigned char buf;
@@ -1084,7 +1085,7 @@ static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
return 0;
}
-static int pwc_mpt_reset(struct pwc_device *pdev, int flags)
+static int _pwc_mpt_reset(struct pwc_device *pdev, int flags)
{
unsigned char buf;
@@ -1092,7 +1093,18 @@ static int pwc_mpt_reset(struct pwc_device *pdev, int flags)
return SendControlMsg(SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, 1);
}
-static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
+int pwc_mpt_reset(struct pwc_device *pdev, int flags)
+{
+ int ret;
+ ret = _pwc_mpt_reset(pdev, flags);
+ if (ret >= 0) {
+ pdev->pan_angle = 0;
+ pdev->tilt_angle = 0;
+ }
+ return ret;
+}
+
+static int _pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
{
unsigned char buf[4];
@@ -1110,7 +1122,35 @@ static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
return SendControlMsg(SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, 4);
}
-static inline int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status)
+int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
+{
+ int ret;
+
+ /* check absolute ranges */
+ if (pan < pdev->angle_range.pan_min ||
+ pan > pdev->angle_range.pan_max ||
+ tilt < pdev->angle_range.tilt_min ||
+ tilt > pdev->angle_range.tilt_max)
+ return -ERANGE;
+
+ /* go to relative range, check again */
+ pan -= pdev->pan_angle;
+ tilt -= pdev->tilt_angle;
+ /* angles are specified in degrees * 100, thus the limit = 36000 */
+ if (pan < -36000 || pan > 36000 || tilt < -36000 || tilt > 36000)
+ return -ERANGE;
+
+ ret = _pwc_mpt_set_angle(pdev, pan, tilt);
+ if (ret >= 0) {
+ pdev->pan_angle += pan;
+ pdev->tilt_angle += tilt;
+ }
+ if (ret == -EPIPE) /* stall -> out of range */
+ ret = -ERANGE;
+ return ret;
+}
+
+static int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status)
{
int ret;
unsigned char buf[5];
@@ -1151,6 +1191,26 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
/* End of Add-Ons */
/* ************************************************* */
+/* Linux 2.5.something and 2.6 pass direct pointers to arguments of
+ ioctl() calls. With 2.4, you have to do tedious copy_from_user()
+ and copy_to_user() calls. With these macros we circumvent this,
+ and let me maintain only one source file. The functionality is
+ exactly the same otherwise.
+ */
+
+
+/* define local variable for arg */
+#define ARG_DEF(ARG_type, ARG_name)\
+ ARG_type *ARG_name = arg;
+/* copy arg to local variable */
+#define ARG_IN(ARG_name) /* nothing */
+/* argument itself (referenced) */
+#define ARGR(ARG_name) (*ARG_name)
+/* argument address */
+#define ARGA(ARG_name) ARG_name
+/* copy local variable to arg */
+#define ARG_OUT(ARG_name) /* nothing */
+
int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
{
@@ -1180,206 +1240,243 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
case VIDIOCPWCSCQUAL:
{
- int *qual = arg;
+ ARG_DEF(int, qual)
- if (*qual < 0 || *qual > 3)
+ ARG_IN(qual)
+ if (ARGR(qual) < 0 || ARGR(qual) > 3)
ret = -EINVAL;
else
- ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, *qual, pdev->vsnapshot);
+ ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot);
if (ret >= 0)
- pdev->vcompression = *qual;
+ pdev->vcompression = ARGR(qual);
break;
}
case VIDIOCPWCGCQUAL:
{
- int *qual = arg;
- *qual = pdev->vcompression;
+ ARG_DEF(int, qual)
+
+ ARGR(qual) = pdev->vcompression;
+ ARG_OUT(qual)
break;
}
case VIDIOCPWCPROBE:
{
- struct pwc_probe *probe = arg;
- strcpy(probe->name, pdev->vdev->name);
- probe->type = pdev->type;
+ ARG_DEF(struct pwc_probe, probe)
+
+ strcpy(ARGR(probe).name, pdev->vdev->name);
+ ARGR(probe).type = pdev->type;
+ ARG_OUT(probe)
break;
}
case VIDIOCPWCGSERIAL:
{
- struct pwc_serial *serial = arg;
- strcpy(serial->serial, pdev->serial);
+ ARG_DEF(struct pwc_serial, serial)
+
+ strcpy(ARGR(serial).serial, pdev->serial);
+ ARG_OUT(serial)
break;
}
case VIDIOCPWCSAGC:
{
- int *agc = arg;
- if (pwc_set_agc(pdev, *agc < 0 ? 1 : 0, *agc))
+ ARG_DEF(int, agc)
+
+ ARG_IN(agc)
+ if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc)))
ret = -EINVAL;
break;
}
case VIDIOCPWCGAGC:
{
- int *agc = arg;
+ ARG_DEF(int, agc)
- if (pwc_get_agc(pdev, agc))
+ if (pwc_get_agc(pdev, ARGA(agc)))
ret = -EINVAL;
+ ARG_OUT(agc)
break;
}
case VIDIOCPWCSSHUTTER:
{
- int *shutter_speed = arg;
- ret = pwc_set_shutter_speed(pdev, *shutter_speed < 0 ? 1 : 0, *shutter_speed);
+ ARG_DEF(int, shutter_speed)
+
+ ARG_IN(shutter_speed)
+ ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed));
break;
}
case VIDIOCPWCSAWB:
{
- struct pwc_whitebalance *wb = arg;
+ ARG_DEF(struct pwc_whitebalance, wb)
- ret = pwc_set_awb(pdev, wb->mode);
- if (ret >= 0 && wb->mode == PWC_WB_MANUAL) {
- pwc_set_red_gain(pdev, wb->manual_red);
- pwc_set_blue_gain(pdev, wb->manual_blue);
+ ARG_IN(wb)
+ ret = pwc_set_awb(pdev, ARGR(wb).mode);
+ if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) {
+ pwc_set_red_gain(pdev, ARGR(wb).manual_red);
+ pwc_set_blue_gain(pdev, ARGR(wb).manual_blue);
}
break;
}
case VIDIOCPWCGAWB:
{
- struct pwc_whitebalance *wb = arg;
+ ARG_DEF(struct pwc_whitebalance, wb)
- memset(wb, 0, sizeof(struct pwc_whitebalance));
- wb->mode = pwc_get_awb(pdev);
- if (wb->mode < 0)
+ memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance));
+ ARGR(wb).mode = pwc_get_awb(pdev);
+ if (ARGR(wb).mode < 0)
ret = -EINVAL;
else {
- if (wb->mode == PWC_WB_MANUAL) {
- ret = pwc_get_red_gain(pdev, &wb->manual_red);
+ if (ARGR(wb).mode == PWC_WB_MANUAL) {
+ ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red);
if (ret < 0)
break;
- ret = pwc_get_blue_gain(pdev, &wb->manual_blue);
+ ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue);
if (ret < 0)
break;
}
- if (wb->mode == PWC_WB_AUTO) {
- ret = pwc_read_red_gain(pdev, &wb->read_red);
+ if (ARGR(wb).mode == PWC_WB_AUTO) {
+ ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red);
if (ret < 0)
break;
- ret = pwc_read_blue_gain(pdev, &wb->read_blue);
+ ret =pwc_read_blue_gain(pdev, &ARGR(wb).read_blue);
if (ret < 0)
break;
}
}
+ ARG_OUT(wb)
break;
}
case VIDIOCPWCSAWBSPEED:
{
- struct pwc_wb_speed *wbs = arg;
+ ARG_DEF(struct pwc_wb_speed, wbs)
- if (wbs->control_speed > 0) {
- ret = pwc_set_wb_speed(pdev, wbs->control_speed);
+ if (ARGR(wbs).control_speed > 0) {
+ ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed);
}
- if (wbs->control_delay > 0) {
- ret = pwc_set_wb_delay(pdev, wbs->control_delay);
+ if (ARGR(wbs).control_delay > 0) {
+ ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay);
}
break;
}
case VIDIOCPWCGAWBSPEED:
{
- struct pwc_wb_speed *wbs = arg;
+ ARG_DEF(struct pwc_wb_speed, wbs)
- ret = pwc_get_wb_speed(pdev, &wbs->control_speed);
+ ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed);
if (ret < 0)
break;
- ret = pwc_get_wb_delay(pdev, &wbs->control_delay);
+ ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay);
if (ret < 0)
break;
+ ARG_OUT(wbs)
break;
}
case VIDIOCPWCSLED:
{
- struct pwc_leds *leds = arg;
- ret = pwc_set_leds(pdev, leds->led_on, leds->led_off);
- break;
+ ARG_DEF(struct pwc_leds, leds)
+
+ ARG_IN(leds)
+ ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off);
+ break;
}
case VIDIOCPWCGLED:
{
- struct pwc_leds *leds = arg;
- ret = pwc_get_leds(pdev, &leds->led_on, &leds->led_off);
+ ARG_DEF(struct pwc_leds, leds)
+
+ ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off);
+ ARG_OUT(leds)
break;
}
case VIDIOCPWCSCONTOUR:
{
- int *contour = arg;
- ret = pwc_set_contour(pdev, *contour);
+ ARG_DEF(int, contour)
+
+ ARG_IN(contour)
+ ret = pwc_set_contour(pdev, ARGR(contour));
break;
}
case VIDIOCPWCGCONTOUR:
{
- int *contour = arg;
- ret = pwc_get_contour(pdev, contour);
+ ARG_DEF(int, contour)
+
+ ret = pwc_get_contour(pdev, ARGA(contour));
+ ARG_OUT(contour)
break;
}
case VIDIOCPWCSBACKLIGHT:
{
- int *backlight = arg;
- ret = pwc_set_backlight(pdev, *backlight);
+ ARG_DEF(int, backlight)
+
+ ARG_IN(backlight)
+ ret = pwc_set_backlight(pdev, ARGR(backlight));
break;
}
case VIDIOCPWCGBACKLIGHT:
{
- int *backlight = arg;
- ret = pwc_get_backlight(pdev, backlight);
+ ARG_DEF(int, backlight)
+
+ ret = pwc_get_backlight(pdev, ARGA(backlight));
+ ARG_OUT(backlight)
break;
}
case VIDIOCPWCSFLICKER:
{
- int *flicker = arg;
- ret = pwc_set_flicker(pdev, *flicker);
+ ARG_DEF(int, flicker)
+
+ ARG_IN(flicker)
+ ret = pwc_set_flicker(pdev, ARGR(flicker));
break;
}
case VIDIOCPWCGFLICKER:
{
- int *flicker = arg;
- ret = pwc_get_flicker(pdev, flicker);
+ ARG_DEF(int, flicker)
+
+ ret = pwc_get_flicker(pdev, ARGA(flicker));
+ ARG_OUT(flicker)
break;
}
case VIDIOCPWCSDYNNOISE:
{
- int *dynnoise = arg;
- ret = pwc_set_dynamic_noise(pdev, *dynnoise);
+ ARG_DEF(int, dynnoise)
+
+ ARG_IN(dynnoise)
+ ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise));
break;
}
case VIDIOCPWCGDYNNOISE:
{
- int *dynnoise = arg;
- ret = pwc_get_dynamic_noise(pdev, dynnoise);
+ ARG_DEF(int, dynnoise)
+
+ ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise));
+ ARG_OUT(dynnoise);
break;
}
case VIDIOCPWCGREALSIZE:
{
- struct pwc_imagesize *size = arg;
- size->width = pdev->image.x;
- size->height = pdev->image.y;
+ ARG_DEF(struct pwc_imagesize, size)
+
+ ARGR(size).width = pdev->image.x;
+ ARGR(size).height = pdev->image.y;
+ ARG_OUT(size)
break;
}
@@ -1387,14 +1484,10 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
{
if (pdev->features & FEATURE_MOTOR_PANTILT)
{
- int *flags = arg;
+ ARG_DEF(int, flags)
- ret = pwc_mpt_reset(pdev, *flags);
- if (ret >= 0)
- {
- pdev->pan_angle = 0;
- pdev->tilt_angle = 0;
- }
+ ARG_IN(flags)
+ ret = pwc_mpt_reset(pdev, ARGR(flags));
}
else
{
@@ -1407,8 +1500,10 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
{
if (pdev->features & FEATURE_MOTOR_PANTILT)
{
- struct pwc_mpt_range *range = arg;
- *range = pdev->angle_range;
+ ARG_DEF(struct pwc_mpt_range, range)
+
+ ARGR(range) = pdev->angle_range;
+ ARG_OUT(range)
}
else
{
@@ -1423,48 +1518,23 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
if (pdev->features & FEATURE_MOTOR_PANTILT)
{
- struct pwc_mpt_angles *angles = arg;
+ ARG_DEF(struct pwc_mpt_angles, angles)
+
+ ARG_IN(angles)
/* The camera can only set relative angles, so
do some calculations when getting an absolute angle .
*/
- if (angles->absolute)
+ if (ARGR(angles).absolute)
{
- new_pan = angles->pan;
- new_tilt = angles->tilt;
+ new_pan = ARGR(angles).pan;
+ new_tilt = ARGR(angles).tilt;
}
else
{
- new_pan = pdev->pan_angle + angles->pan;
- new_tilt = pdev->tilt_angle + angles->tilt;
- }
- /* check absolute ranges */
- if (new_pan < pdev->angle_range.pan_min ||
- new_pan > pdev->angle_range.pan_max ||
- new_tilt < pdev->angle_range.tilt_min ||
- new_tilt > pdev->angle_range.tilt_max)
- {
- ret = -ERANGE;
- }
- else
- {
- /* go to relative range, check again */
- new_pan -= pdev->pan_angle;
- new_tilt -= pdev->tilt_angle;
- /* angles are specified in degrees * 100, thus the limit = 36000 */
- if (new_pan < -36000 || new_pan > 36000 || new_tilt < -36000 || new_tilt > 36000)
- ret = -ERANGE;
- }
- if (ret == 0) /* no errors so far */
- {
- ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt);
- if (ret >= 0)
- {
- pdev->pan_angle += new_pan;
- pdev->tilt_angle += new_tilt;
- }
- if (ret == -EPIPE) /* stall -> out of range */
- ret = -ERANGE;
+ new_pan = pdev->pan_angle + ARGR(angles).pan;
+ new_tilt = pdev->tilt_angle + ARGR(angles).tilt;
}
+ ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt);
}
else
{
@@ -1478,11 +1548,12 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
if (pdev->features & FEATURE_MOTOR_PANTILT)
{
- struct pwc_mpt_angles *angles = arg;
+ ARG_DEF(struct pwc_mpt_angles, angles)
- angles->absolute = 1;
- angles->pan = pdev->pan_angle;
- angles->tilt = pdev->tilt_angle;
+ ARGR(angles).absolute = 1;
+ ARGR(angles).pan = pdev->pan_angle;
+ ARGR(angles).tilt = pdev->tilt_angle;
+ ARG_OUT(angles)
}
else
{
@@ -1495,8 +1566,10 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
{
if (pdev->features & FEATURE_MOTOR_PANTILT)
{
- struct pwc_mpt_status *status = arg;
- ret = pwc_mpt_get_status(pdev, status);
+ ARG_DEF(struct pwc_mpt_status, status)
+
+ ret = pwc_mpt_get_status(pdev, ARGA(status));
+ ARG_OUT(status)
}
else
{
@@ -1507,22 +1580,24 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
case VIDIOCPWCGVIDCMD:
{
- struct pwc_video_command *cmd = arg;
-
- cmd->type = pdev->type;
- cmd->release = pdev->release;
- cmd->command_len = pdev->cmd_len;
- memcpy(&cmd->command_buf, pdev->cmd_buf, pdev->cmd_len);
- cmd->bandlength = pdev->vbandlength;
- cmd->frame_size = pdev->frame_size;
+ ARG_DEF(struct pwc_video_command, cmd);
+
+ ARGR(cmd).type = pdev->type;
+ ARGR(cmd).release = pdev->release;
+ ARGR(cmd).command_len = pdev->cmd_len;
+ memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len);
+ ARGR(cmd).bandlength = pdev->vbandlength;
+ ARGR(cmd).frame_size = pdev->frame_size;
+ ARG_OUT(cmd)
break;
}
/*
case VIDIOCPWCGVIDTABLE:
{
- struct pwc_table_init_buffer *table = arg;
- table->len = pdev->cmd_len;
- memcpy(&table->buffer, pdev->decompress_data, pdev->decompressor->table_size);
+ ARG_DEF(struct pwc_table_init_buffer, table);
+ ARGR(table).len = pdev->cmd_len;
+ memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size);
+ ARG_OUT(table)
break;
}
*/
@@ -1538,4 +1613,4 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
}
-
+/* vim: set cinoptions= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc-dec1.c b/drivers/media/video/pwc/pwc-dec1.c
new file mode 100644
index 0000000..c29593f
--- /dev/null
+++ b/drivers/media/video/pwc/pwc-dec1.c
@@ -0,0 +1,50 @@
+/* Linux driver for Philips webcam
+ Decompression for chipset version 1
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+ NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+ driver and thus may have bugs that are not present in the original version.
+ Please send bug reports and support requests to <luc@saillard.org>.
+ The decompression routines have been implemented by reverse-engineering the
+ Nemosoft binary pwcx module. Caveat emptor.
+
+ 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 "pwc-dec1.h"
+
+
+void pwc_dec1_init(int type, int release, void *buffer, void *table)
+{
+
+}
+
+void pwc_dec1_exit(void)
+{
+
+
+
+}
+
+int pwc_dec1_alloc(struct pwc_device *pwc)
+{
+ pwc->decompress_data = kmalloc(sizeof(struct pwc_dec1_private), GFP_KERNEL);
+ if (pwc->decompress_data == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
diff --git a/drivers/media/video/pwc/pwc-dec1.h b/drivers/media/video/pwc/pwc-dec1.h
new file mode 100644
index 0000000..8b62ddc
--- /dev/null
+++ b/drivers/media/video/pwc/pwc-dec1.h
@@ -0,0 +1,43 @@
+/* Linux driver for Philips webcam
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+ NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+ driver and thus may have bugs that are not present in the original version.
+ Please send bug reports and support requests to <luc@saillard.org>.
+ The decompression routines have been implemented by reverse-engineering the
+ Nemosoft binary pwcx module. Caveat emptor.
+
+ 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 PWC_DEC1_H
+#define PWC_DEC1_H
+
+#include "pwc.h"
+
+struct pwc_dec1_private
+{
+ int version;
+
+};
+
+int pwc_dec1_alloc(struct pwc_device *pwc);
+void pwc_dec1_init(int type, int release, void *buffer, void *private_data);
+void pwc_dec1_exit(void);
+
+#endif
+
diff --git a/drivers/media/video/pwc/pwc-dec23.c b/drivers/media/video/pwc/pwc-dec23.c
new file mode 100644
index 0000000..9e2d91f
--- /dev/null
+++ b/drivers/media/video/pwc/pwc-dec23.c
@@ -0,0 +1,941 @@
+/* Linux driver for Philips webcam
+ Decompression for chipset version 2 et 3
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+ NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+ driver and thus may have bugs that are not present in the original version.
+ Please send bug reports and support requests to <luc@saillard.org>.
+ The decompression routines have been implemented by reverse-engineering the
+ Nemosoft binary pwcx module. Caveat emptor.
+
+ 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 "pwc-timon.h"
+#include "pwc-kiara.h"
+#include "pwc-dec23.h"
+#include <media/pwc-ioctl.h>
+
+#include <linux/string.h>
+
+/*
+ * USE_LOOKUP_TABLE_TO_CLAMP
+ * 0: use a C version of this tests: { a<0?0:(a>255?255:a) }
+ * 1: use a faster lookup table for cpu with a big cache (intel)
+ */
+#define USE_LOOKUP_TABLE_TO_CLAMP 1
+/*
+ * UNROLL_LOOP_FOR_COPYING_BLOCK
+ * 0: use a loop for a smaller code (but little slower)
+ * 1: when unrolling the loop, gcc produces some faster code (perhaps only
+ * valid for intel processor class). Activating this option, automaticaly
+ * activate USE_LOOKUP_TABLE_TO_CLAMP
+ */
+#define UNROLL_LOOP_FOR_COPY 1
+#if UNROLL_LOOP_FOR_COPY
+# undef USE_LOOKUP_TABLE_TO_CLAMP
+# define USE_LOOKUP_TABLE_TO_CLAMP 1
+#endif
+
+/*
+ * ENABLE_BAYER_DECODER
+ * 0: bayer decoder is not build (save some space)
+ * 1: bayer decoder is build and can be used
+ */
+#define ENABLE_BAYER_DECODER 0
+
+static void build_subblock_pattern(struct pwc_dec23_private *pdec)
+{
+ static const unsigned int initial_values[12] = {
+ -0x526500, -0x221200, 0x221200, 0x526500,
+ -0x3de200, 0x3de200,
+ -0x6db480, -0x2d5d00, 0x2d5d00, 0x6db480,
+ -0x12c200, 0x12c200
+
+ };
+ static const unsigned int values_derivated[12] = {
+ 0xa4ca, 0x4424, -0x4424, -0xa4ca,
+ 0x7bc4, -0x7bc4,
+ 0xdb69, 0x5aba, -0x5aba, -0xdb69,
+ 0x2584, -0x2584
+ };
+ unsigned int temp_values[12];
+ int i, j;
+
+ memcpy(temp_values, initial_values, sizeof(initial_values));
+ for (i = 0; i < 256; i++) {
+ for (j = 0; j < 12; j++) {
+ pdec->table_subblock[i][j] = temp_values[j];
+ temp_values[j] += values_derivated[j];
+ }
+ }
+}
+
+static void build_bit_powermask_table(struct pwc_dec23_private *pdec)
+{
+ unsigned char *p;
+ unsigned int bit, byte, mask, val;
+ unsigned int bitpower = 1;
+
+ for (bit = 0; bit < 8; bit++) {
+ mask = bitpower - 1;
+ p = pdec->table_bitpowermask[bit];
+ for (byte = 0; byte < 256; byte++) {
+ val = (byte & mask);
+ if (byte & bitpower)
+ val = -val;
+ *p++ = val;
+ }
+ bitpower<<=1;
+ }
+}
+
+
+static void build_table_color(const unsigned int romtable[16][8],
+ unsigned char p0004[16][1024],
+ unsigned char p8004[16][256])
+{
+ int compression_mode, j, k, bit, pw;
+ unsigned char *p0, *p8;
+ const unsigned int *r;
+
+ /* We have 16 compressions tables */
+ for (compression_mode = 0; compression_mode < 16; compression_mode++) {
+ p0 = p0004[compression_mode];
+ p8 = p8004[compression_mode];
+ r = romtable[compression_mode];
+
+ for (j = 0; j < 8; j++, r++, p0 += 128) {
+
+ for (k = 0; k < 16; k++) {
+ if (k == 0)
+ bit = 1;
+ else if (k >= 1 && k < 3)
+ bit = (r[0] >> 15) & 7;
+ else if (k >= 3 && k < 6)
+ bit = (r[0] >> 12) & 7;
+ else if (k >= 6 && k < 10)
+ bit = (r[0] >> 9) & 7;
+ else if (k >= 10 && k < 13)
+ bit = (r[0] >> 6) & 7;
+ else if (k >= 13 && k < 15)
+ bit = (r[0] >> 3) & 7;
+ else
+ bit = (r[0]) & 7;
+ if (k == 0)
+ *p8++ = 8;
+ else
+ *p8++ = j - bit;
+ *p8++ = bit;
+
+ pw = 1 << bit;
+ p0[k + 0x00] = (1 * pw) + 0x80;
+ p0[k + 0x10] = (2 * pw) + 0x80;
+ p0[k + 0x20] = (3 * pw) + 0x80;
+ p0[k + 0x30] = (4 * pw) + 0x80;
+ p0[k + 0x40] = (-1 * pw) + 0x80;
+ p0[k + 0x50] = (-2 * pw) + 0x80;
+ p0[k + 0x60] = (-3 * pw) + 0x80;
+ p0[k + 0x70] = (-4 * pw) + 0x80;
+ } /* end of for (k=0; k<16; k++, p8++) */
+ } /* end of for (j=0; j<8; j++ , table++) */
+ } /* end of foreach compression_mode */
+}
+
+/*
+ *
+ */
+static void fill_table_dc00_d800(struct pwc_dec23_private *pdec)
+{
+#define SCALEBITS 15
+#define ONE_HALF (1UL << (SCALEBITS - 1))
+ int i;
+ unsigned int offset1 = ONE_HALF;
+ unsigned int offset2 = 0x0000;
+
+ for (i=0; i<256; i++) {
+ pdec->table_dc00[i] = offset1 & ~(ONE_HALF);
+ pdec->table_d800[i] = offset2;
+
+ offset1 += 0x7bc4;
+ offset2 += 0x7bc4;
+ }
+}
+
+/*
+ * To decode the stream:
+ * if look_bits(2) == 0: # op == 2 in the lookup table
+ * skip_bits(2)
+ * end of the stream
+ * elif look_bits(3) == 7: # op == 1 in the lookup table
+ * skip_bits(3)
+ * yyyy = get_bits(4)
+ * xxxx = get_bits(8)
+ * else: # op == 0 in the lookup table
+ * skip_bits(x)
+ *
+ * For speedup processing, we build a lookup table and we takes the first 6 bits.
+ *
+ * struct {
+ * unsigned char op; // operation to execute
+ * unsigned char bits; // bits use to perform operation
+ * unsigned char offset1; // offset to add to access in the table_0004 % 16
+ * unsigned char offset2; // offset to add to access in the table_0004
+ * }
+ *
+ * How to build this table ?
+ * op == 2 when (i%4)==0
+ * op == 1 when (i%8)==7
+ * op == 0 otherwise
+ *
+ */
+static const unsigned char hash_table_ops[64*4] = {
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x10,
+ 0x00, 0x06, 0x01, 0x30,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x01, 0x20,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x50,
+ 0x00, 0x05, 0x02, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x03, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x10,
+ 0x00, 0x06, 0x02, 0x10,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x01, 0x60,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x50,
+ 0x00, 0x05, 0x02, 0x40,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x03, 0x40,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x10,
+ 0x00, 0x06, 0x01, 0x70,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x01, 0x20,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x50,
+ 0x00, 0x05, 0x02, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x03, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x10,
+ 0x00, 0x06, 0x02, 0x50,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x01, 0x60,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x50,
+ 0x00, 0x05, 0x02, 0x40,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x03, 0x40,
+ 0x01, 0x00, 0x00, 0x00
+};
+
+/*
+ *
+ */
+static const unsigned int MulIdx[16][16] = {
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
+ {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,},
+ {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,},
+ {4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4,},
+ {6, 7, 8, 9, 7, 10, 11, 8, 8, 11, 10, 7, 9, 8, 7, 6,},
+ {4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4,},
+ {1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2,},
+ {0, 3, 3, 0, 1, 2, 2, 1, 2, 1, 1, 2, 3, 0, 0, 3,},
+ {0, 1, 2, 3, 3, 2, 1, 0, 3, 2, 1, 0, 0, 1, 2, 3,},
+ {1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0, 2, 2, 2, 2,},
+ {7, 10, 11, 8, 9, 8, 7, 6, 6, 7, 8, 9, 8, 11, 10, 7,},
+ {4, 5, 5, 4, 5, 4, 4, 5, 5, 4, 4, 5, 4, 5, 5, 4,},
+ {7, 9, 6, 8, 10, 8, 7, 11, 11, 7, 8, 10, 8, 6, 9, 7,},
+ {1, 3, 0, 2, 2, 0, 3, 1, 2, 0, 3, 1, 1, 3, 0, 2,},
+ {1, 2, 2, 1, 3, 0, 0, 3, 0, 3, 3, 0, 2, 1, 1, 2,},
+ {10, 8, 7, 11, 8, 6, 9, 7, 7, 9, 6, 8, 11, 7, 8, 10}
+};
+
+#if USE_LOOKUP_TABLE_TO_CLAMP
+#define MAX_OUTER_CROP_VALUE (512)
+static unsigned char pwc_crop_table[256 + 2*MAX_OUTER_CROP_VALUE];
+#define CLAMP(x) (pwc_crop_table[MAX_OUTER_CROP_VALUE+(x)])
+#else
+#define CLAMP(x) ((x)>255?255:((x)<0?0:x))
+#endif
+
+
+/* If the type or the command change, we rebuild the lookup table */
+int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd)
+{
+ int flags, version, shift, i;
+ struct pwc_dec23_private *pdec;
+
+ if (pwc->decompress_data == NULL) {
+ pdec = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
+ if (pdec == NULL)
+ return -ENOMEM;
+ pwc->decompress_data = pdec;
+ }
+ pdec = pwc->decompress_data;
+
+ if (DEVICE_USE_CODEC3(type)) {
+ flags = cmd[2] & 0x18;
+ if (flags == 8)
+ pdec->nbits = 7; /* More bits, mean more bits to encode the stream, but better quality */
+ else if (flags == 0x10)
+ pdec->nbits = 8;
+ else
+ pdec->nbits = 6;
+
+ version = cmd[2] >> 5;
+ build_table_color(KiaraRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1);
+ build_table_color(KiaraRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2);
+
+ } else {
+
+ flags = cmd[2] & 6;
+ if (flags == 2)
+ pdec->nbits = 7;
+ else if (flags == 4)
+ pdec->nbits = 8;
+ else
+ pdec->nbits = 6;
+
+ version = cmd[2] >> 3;
+ build_table_color(TimonRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1);
+ build_table_color(TimonRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2);
+ }
+
+ /* Informations can be coded on a variable number of bits but never less than 8 */
+ shift = 8 - pdec->nbits;
+ pdec->scalebits = SCALEBITS - shift;
+ pdec->nbitsmask = 0xFF >> shift;
+
+ fill_table_dc00_d800(pdec);
+ build_subblock_pattern(pdec);
+ build_bit_powermask_table(pdec);
+
+#if USE_LOOKUP_TABLE_TO_CLAMP
+ /* Build the static table to clamp value [0-255] */
+ for (i=0;i<MAX_OUTER_CROP_VALUE;i++)
+ pwc_crop_table[i] = 0;
+ for (i=0; i<256; i++)
+ pwc_crop_table[MAX_OUTER_CROP_VALUE+i] = i;
+ for (i=0; i<MAX_OUTER_CROP_VALUE; i++)
+ pwc_crop_table[MAX_OUTER_CROP_VALUE+256+i] = 255;
+#endif
+
+ return 0;
+}
+
+/*
+ * Copy the 4x4 image block to Y plane buffer
+ */
+static void copy_image_block_Y(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+ const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+ const int *c = src;
+ unsigned char *d = dst;
+
+ *d++ = cm[c[0] >> scalebits];
+ *d++ = cm[c[1] >> scalebits];
+ *d++ = cm[c[2] >> scalebits];
+ *d++ = cm[c[3] >> scalebits];
+
+ d = dst + bytes_per_line;
+ *d++ = cm[c[4] >> scalebits];
+ *d++ = cm[c[5] >> scalebits];
+ *d++ = cm[c[6] >> scalebits];
+ *d++ = cm[c[7] >> scalebits];
+
+ d = dst + bytes_per_line*2;
+ *d++ = cm[c[8] >> scalebits];
+ *d++ = cm[c[9] >> scalebits];
+ *d++ = cm[c[10] >> scalebits];
+ *d++ = cm[c[11] >> scalebits];
+
+ d = dst + bytes_per_line*3;
+ *d++ = cm[c[12] >> scalebits];
+ *d++ = cm[c[13] >> scalebits];
+ *d++ = cm[c[14] >> scalebits];
+ *d++ = cm[c[15] >> scalebits];
+#else
+ int i;
+ const int *c = src;
+ unsigned char *d = dst;
+ for (i = 0; i < 4; i++, c++)
+ *d++ = CLAMP((*c) >> scalebits);
+
+ d = dst + bytes_per_line;
+ for (i = 0; i < 4; i++, c++)
+ *d++ = CLAMP((*c) >> scalebits);
+
+ d = dst + bytes_per_line*2;
+ for (i = 0; i < 4; i++, c++)
+ *d++ = CLAMP((*c) >> scalebits);
+
+ d = dst + bytes_per_line*3;
+ for (i = 0; i < 4; i++, c++)
+ *d++ = CLAMP((*c) >> scalebits);
+#endif
+}
+
+/*
+ * Copy the 4x4 image block to a CrCb plane buffer
+ *
+ */
+static void copy_image_block_CrCb(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+ /* Unroll all loops */
+ const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+ const int *c = src;
+ unsigned char *d = dst;
+
+ *d++ = cm[c[0] >> scalebits];
+ *d++ = cm[c[4] >> scalebits];
+ *d++ = cm[c[1] >> scalebits];
+ *d++ = cm[c[5] >> scalebits];
+ *d++ = cm[c[2] >> scalebits];
+ *d++ = cm[c[6] >> scalebits];
+ *d++ = cm[c[3] >> scalebits];
+ *d++ = cm[c[7] >> scalebits];
+
+ d = dst + bytes_per_line;
+ *d++ = cm[c[12] >> scalebits];
+ *d++ = cm[c[8] >> scalebits];
+ *d++ = cm[c[13] >> scalebits];
+ *d++ = cm[c[9] >> scalebits];
+ *d++ = cm[c[14] >> scalebits];
+ *d++ = cm[c[10] >> scalebits];
+ *d++ = cm[c[15] >> scalebits];
+ *d++ = cm[c[11] >> scalebits];
+#else
+ int i;
+ const int *c1 = src;
+ const int *c2 = src + 4;
+ unsigned char *d = dst;
+
+ for (i = 0; i < 4; i++, c1++, c2++) {
+ *d++ = CLAMP((*c1) >> scalebits);
+ *d++ = CLAMP((*c2) >> scalebits);
+ }
+ c1 = src + 12;
+ d = dst + bytes_per_line;
+ for (i = 0; i < 4; i++, c1++, c2++) {
+ *d++ = CLAMP((*c1) >> scalebits);
+ *d++ = CLAMP((*c2) >> scalebits);
+ }
+#endif
+}
+
+#if ENABLE_BAYER_DECODER
+/*
+ * Format: 8x2 pixels
+ * . G . G . G . G . G . G . G
+ * . . . . . . . . . . . . . .
+ * . G . G . G . G . G . G . G
+ * . . . . . . . . . . . . . .
+ * or
+ * . . . . . . . . . . . . . .
+ * G . G . G . G . G . G . G .
+ * . . . . . . . . . . . . . .
+ * G . G . G . G . G . G . G .
+*/
+static void copy_image_block_Green(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+ /* Unroll all loops */
+ const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+ unsigned char *d = dst;
+ const int *c = src;
+
+ d[0] = cm[c[0] >> scalebits];
+ d[2] = cm[c[1] >> scalebits];
+ d[4] = cm[c[2] >> scalebits];
+ d[6] = cm[c[3] >> scalebits];
+ d[8] = cm[c[4] >> scalebits];
+ d[10] = cm[c[5] >> scalebits];
+ d[12] = cm[c[6] >> scalebits];
+ d[14] = cm[c[7] >> scalebits];
+
+ d = dst + bytes_per_line;
+ d[0] = cm[c[8] >> scalebits];
+ d[2] = cm[c[9] >> scalebits];
+ d[4] = cm[c[10] >> scalebits];
+ d[6] = cm[c[11] >> scalebits];
+ d[8] = cm[c[12] >> scalebits];
+ d[10] = cm[c[13] >> scalebits];
+ d[12] = cm[c[14] >> scalebits];
+ d[14] = cm[c[15] >> scalebits];
+#else
+ int i;
+ unsigned char *d;
+ const int *c = src;
+
+ d = dst;
+ for (i = 0; i < 8; i++, c++)
+ d[i*2] = CLAMP((*c) >> scalebits);
+
+ d = dst + bytes_per_line;
+ for (i = 0; i < 8; i++, c++)
+ d[i*2] = CLAMP((*c) >> scalebits);
+#endif
+}
+#endif
+
+#if ENABLE_BAYER_DECODER
+/*
+ * Format: 4x4 pixels
+ * R . R . R . R
+ * . B . B . B .
+ * R . R . R . R
+ * . B . B . B .
+ */
+static void copy_image_block_RedBlue(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+ /* Unroll all loops */
+ const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+ unsigned char *d = dst;
+ const int *c = src;
+
+ d[0] = cm[c[0] >> scalebits];
+ d[2] = cm[c[1] >> scalebits];
+ d[4] = cm[c[2] >> scalebits];
+ d[6] = cm[c[3] >> scalebits];
+
+ d = dst + bytes_per_line;
+ d[1] = cm[c[4] >> scalebits];
+ d[3] = cm[c[5] >> scalebits];
+ d[5] = cm[c[6] >> scalebits];
+ d[7] = cm[c[7] >> scalebits];
+
+ d = dst + bytes_per_line*2;
+ d[0] = cm[c[8] >> scalebits];
+ d[2] = cm[c[9] >> scalebits];
+ d[4] = cm[c[10] >> scalebits];
+ d[6] = cm[c[11] >> scalebits];
+
+ d = dst + bytes_per_line*3;
+ d[1] = cm[c[12] >> scalebits];
+ d[3] = cm[c[13] >> scalebits];
+ d[5] = cm[c[14] >> scalebits];
+ d[7] = cm[c[15] >> scalebits];
+#else
+ int i;
+ unsigned char *d;
+ const int *c = src;
+
+ d = dst;
+ for (i = 0; i < 4; i++, c++)
+ d[i*2] = CLAMP((*c) >> scalebits);
+
+ d = dst + bytes_per_line;
+ for (i = 0; i < 4; i++, c++)
+ d[i*2+1] = CLAMP((*c) >> scalebits);
+
+ d = dst + bytes_per_line*2;
+ for (i = 0; i < 4; i++, c++)
+ d[i*2] = CLAMP((*c) >> scalebits);
+
+ d = dst + bytes_per_line*3;
+ for (i = 0; i < 4; i++, c++)
+ d[i*2+1] = CLAMP((*c) >> scalebits);
+#endif
+}
+#endif
+
+/*
+ * To manage the stream, we keep bits in a 32 bits register.
+ * fill_nbits(n): fill the reservoir with at least n bits
+ * skip_bits(n): discard n bits from the reservoir
+ * get_bits(n): fill the reservoir, returns the first n bits and discard the
+ * bits from the reservoir.
+ * __get_nbits(n): faster version of get_bits(n), but asumes that the reservoir
+ * contains at least n bits. bits returned is discarded.
+ */
+#define fill_nbits(pdec, nbits_wanted) do { \
+ while (pdec->nbits_in_reservoir<(nbits_wanted)) \
+ { \
+ pdec->reservoir |= (*(pdec->stream)++) << (pdec->nbits_in_reservoir); \
+ pdec->nbits_in_reservoir += 8; \
+ } \
+} while(0);
+
+#define skip_nbits(pdec, nbits_to_skip) do { \
+ pdec->reservoir >>= (nbits_to_skip); \
+ pdec->nbits_in_reservoir -= (nbits_to_skip); \
+} while(0);
+
+#define get_nbits(pdec, nbits_wanted, result) do { \
+ fill_nbits(pdec, nbits_wanted); \
+ result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \
+ skip_nbits(pdec, nbits_wanted); \
+} while(0);
+
+#define __get_nbits(pdec, nbits_wanted, result) do { \
+ result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \
+ skip_nbits(pdec, nbits_wanted); \
+} while(0);
+
+#define look_nbits(pdec, nbits_wanted) \
+ ((pdec->reservoir) & ((1U<<(nbits_wanted))-1))
+
+/*
+ * Decode a 4x4 pixel block
+ */
+static void decode_block(struct pwc_dec23_private *pdec,
+ const unsigned char *ptable0004,
+ const unsigned char *ptable8004)
+{
+ unsigned int primary_color;
+ unsigned int channel_v, offset1, op;
+ int i;
+
+ fill_nbits(pdec, 16);
+ __get_nbits(pdec, pdec->nbits, primary_color);
+
+ if (look_nbits(pdec,2) == 0) {
+ skip_nbits(pdec, 2);
+ /* Very simple, the color is the same for all pixels of the square */
+ for (i = 0; i < 16; i++)
+ pdec->temp_colors[i] = pdec->table_dc00[primary_color];
+
+ return;
+ }
+
+ /* This block is encoded with small pattern */
+ for (i = 0; i < 16; i++)
+ pdec->temp_colors[i] = pdec->table_d800[primary_color];
+
+ __get_nbits(pdec, 3, channel_v);
+ channel_v = ((channel_v & 1) << 2) | (channel_v & 2) | ((channel_v & 4) >> 2);
+
+ ptable0004 += (channel_v * 128);
+ ptable8004 += (channel_v * 32);
+
+ offset1 = 0;
+ do
+ {
+ unsigned int htable_idx, rows = 0;
+ const unsigned int *block;
+
+ /* [ zzzz y x x ]
+ * xx == 00 :=> end of the block def, remove the two bits from the stream
+ * yxx == 111
+ * yxx == any other value
+ *
+ */
+ fill_nbits(pdec, 16);
+ htable_idx = look_nbits(pdec, 6);
+ op = hash_table_ops[htable_idx * 4];
+
+ if (op == 2) {
+ skip_nbits(pdec, 2);
+
+ } else if (op == 1) {
+ /* 15bits [ xxxx xxxx yyyy 111 ]
+ * yyy => offset in the table8004
+ * xxx => offset in the tabled004 (tree)
+ */
+ unsigned int mask, shift;
+ unsigned int nbits, col1;
+ unsigned int yyyy;
+
+ skip_nbits(pdec, 3);
+ /* offset1 += yyyy */
+ __get_nbits(pdec, 4, yyyy);
+ offset1 += 1 + yyyy;
+ offset1 &= 0x0F;
+ nbits = ptable8004[offset1 * 2];
+
+ /* col1 = xxxx xxxx */
+ __get_nbits(pdec, nbits+1, col1);
+
+ /* Bit mask table */
+ mask = pdec->table_bitpowermask[nbits][col1];
+ shift = ptable8004[offset1 * 2 + 1];
+ rows = ((mask << shift) + 0x80) & 0xFF;
+
+ block = pdec->table_subblock[rows];
+ for (i = 0; i < 16; i++)
+ pdec->temp_colors[i] += block[MulIdx[offset1][i]];
+
+ } else {
+ /* op == 0
+ * offset1 is coded on 3 bits
+ */
+ unsigned int shift;
+
+ offset1 += hash_table_ops [htable_idx * 4 + 2];
+ offset1 &= 0x0F;
+
+ rows = ptable0004[offset1 + hash_table_ops [htable_idx * 4 + 3]];
+ block = pdec->table_subblock[rows];
+ for (i = 0; i < 16; i++)
+ pdec->temp_colors[i] += block[MulIdx[offset1][i]];
+
+ shift = hash_table_ops[htable_idx * 4 + 1];
+ skip_nbits(pdec, shift);
+ }
+
+ } while (op != 2);
+
+}
+
+static void DecompressBand23(struct pwc_dec23_private *pdec,
+ const unsigned char *rawyuv,
+ unsigned char *planar_y,
+ unsigned char *planar_u,
+ unsigned char *planar_v,
+ unsigned int compressed_image_width,
+ unsigned int real_image_width)
+{
+ int compression_index, nblocks;
+ const unsigned char *ptable0004;
+ const unsigned char *ptable8004;
+
+ pdec->reservoir = 0;
+ pdec->nbits_in_reservoir = 0;
+ pdec->stream = rawyuv + 1; /* The first byte of the stream is skipped */
+
+ get_nbits(pdec, 4, compression_index);
+
+ /* pass 1: uncompress Y component */
+ nblocks = compressed_image_width / 4;
+
+ ptable0004 = pdec->table_0004_pass1[compression_index];
+ ptable8004 = pdec->table_8004_pass1[compression_index];
+
+ /* Each block decode a square of 4x4 */
+ while (nblocks) {
+ decode_block(pdec, ptable0004, ptable8004);
+ copy_image_block_Y(pdec->temp_colors, planar_y, real_image_width, pdec->scalebits);
+ planar_y += 4;
+ nblocks--;
+ }
+
+ /* pass 2: uncompress UV component */
+ nblocks = compressed_image_width / 8;
+
+ ptable0004 = pdec->table_0004_pass2[compression_index];
+ ptable8004 = pdec->table_8004_pass2[compression_index];
+
+ /* Each block decode a square of 4x4 */
+ while (nblocks) {
+ decode_block(pdec, ptable0004, ptable8004);
+ copy_image_block_CrCb(pdec->temp_colors, planar_u, real_image_width/2, pdec->scalebits);
+
+ decode_block(pdec, ptable0004, ptable8004);
+ copy_image_block_CrCb(pdec->temp_colors, planar_v, real_image_width/2, pdec->scalebits);
+
+ planar_v += 8;
+ planar_u += 8;
+ nblocks -= 2;
+ }
+
+}
+
+#if ENABLE_BAYER_DECODER
+/*
+ * Size need to be a multiple of 8 in width
+ *
+ * Return a block of four line encoded like this:
+ *
+ * G R G R G R G R G R G R G R G R
+ * B G B G B G B G B G B G B G B G
+ * G R G R G R G R G R G R G R G R
+ * B G B G B G B G B G B G B G B G
+ *
+ */
+static void DecompressBandBayer(struct pwc_dec23_private *pdec,
+ const unsigned char *rawyuv,
+ unsigned char *rgbbayer,
+ unsigned int compressed_image_width,
+ unsigned int real_image_width)
+{
+ int compression_index, nblocks;
+ const unsigned char *ptable0004;
+ const unsigned char *ptable8004;
+ unsigned char *dest;
+
+ pdec->reservoir = 0;
+ pdec->nbits_in_reservoir = 0;
+ pdec->stream = rawyuv + 1; /* The first byte of the stream is skipped */
+
+ get_nbits(pdec, 4, compression_index);
+
+ /* pass 1: uncompress RB component */
+ nblocks = compressed_image_width / 4;
+
+ ptable0004 = pdec->table_0004_pass1[compression_index];
+ ptable8004 = pdec->table_8004_pass1[compression_index];
+ dest = rgbbayer;
+
+ /* Each block decode a square of 4x4 */
+ while (nblocks) {
+ decode_block(pdec, ptable0004, ptable8004);
+ copy_image_block_RedBlue(pdec->temp_colors, rgbbayer, real_image_width, pdec->scalebits);
+ dest += 8;
+ nblocks--;
+ }
+
+ /* pass 2: uncompress G component */
+ nblocks = compressed_image_width / 8;
+
+ ptable0004 = pdec->table_0004_pass2[compression_index];
+ ptable8004 = pdec->table_8004_pass2[compression_index];
+
+ /* Each block decode a square of 4x4 */
+ while (nblocks) {
+ decode_block(pdec, ptable0004, ptable8004);
+ copy_image_block_Green(pdec->temp_colors, rgbbayer+1, real_image_width, pdec->scalebits);
+
+ decode_block(pdec, ptable0004, ptable8004);
+ copy_image_block_Green(pdec->temp_colors, rgbbayer+real_image_width, real_image_width, pdec->scalebits);
+
+ rgbbayer += 16;
+ nblocks -= 2;
+ }
+}
+#endif
+
+
+/**
+ *
+ * Uncompress a pwc23 buffer.
+ *
+ * pwc.view: size of the image wanted
+ * pwc.image: size of the image returned by the camera
+ * pwc.offset: (x,y) to displayer image in the view
+ *
+ * src: raw data
+ * dst: image output
+ * flags: PWCX_FLAG_PLANAR or PWCX_FLAG_BAYER
+ */
+void pwc_dec23_decompress(const struct pwc_device *pwc,
+ const void *src,
+ void *dst,
+ int flags)
+{
+ int bandlines_left, stride, bytes_per_block;
+
+ bandlines_left = pwc->image.y / 4;
+ bytes_per_block = pwc->view.x * 4;
+
+ if (flags & PWCX_FLAG_BAYER) {
+#if ENABLE_BAYER_DECODER
+ /* RGB Bayer format */
+ unsigned char *rgbout;
+
+ stride = pwc->view.x * pwc->offset.y;
+ rgbout = dst + stride + pwc->offset.x;
+
+
+ while (bandlines_left--) {
+
+ DecompressBandBayer(pwc->decompress_data,
+ src,
+ rgbout,
+ pwc->image.x, pwc->view.x);
+
+ src += pwc->vbandlength;
+ rgbout += bytes_per_block;
+
+ }
+#else
+ memset(dst, 0, pwc->view.x * pwc->view.y);
+#endif
+
+ } else {
+ /* YUV420P image format */
+ unsigned char *pout_planar_y;
+ unsigned char *pout_planar_u;
+ unsigned char *pout_planar_v;
+ unsigned int plane_size;
+
+ plane_size = pwc->view.x * pwc->view.y;
+
+ /* offset in Y plane */
+ stride = pwc->view.x * pwc->offset.y;
+ pout_planar_y = dst + stride + pwc->offset.x;
+
+ /* offsets in U/V planes */
+ stride = (pwc->view.x * pwc->offset.y) / 4 + pwc->offset.x / 2;
+ pout_planar_u = dst + plane_size + stride;
+ pout_planar_v = dst + plane_size + plane_size / 4 + stride;
+
+ while (bandlines_left--) {
+
+ DecompressBand23(pwc->decompress_data,
+ src,
+ pout_planar_y, pout_planar_u, pout_planar_v,
+ pwc->image.x, pwc->view.x);
+ src += pwc->vbandlength;
+ pout_planar_y += bytes_per_block;
+ pout_planar_u += pwc->view.x;
+ pout_planar_v += pwc->view.x;
+
+ }
+
+ }
+
+}
+
+void pwc_dec23_exit(void)
+{
+ /* Do nothing */
+
+}
+
+/**
+ * Allocate a private structure used by lookup table.
+ * You must call kfree() to free the memory allocated.
+ */
+int pwc_dec23_alloc(struct pwc_device *pwc)
+{
+ pwc->decompress_data = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
+ if (pwc->decompress_data == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc-dec23.h b/drivers/media/video/pwc/pwc-dec23.h
new file mode 100644
index 0000000..1c55298
--- /dev/null
+++ b/drivers/media/video/pwc/pwc-dec23.h
@@ -0,0 +1,67 @@
+/* Linux driver for Philips webcam
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+ NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+ driver and thus may have bugs that are not present in the original version.
+ Please send bug reports and support requests to <luc@saillard.org>.
+ The decompression routines have been implemented by reverse-engineering the
+ Nemosoft binary pwcx module. Caveat emptor.
+
+ 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 PWC_DEC23_H
+#define PWC_DEC23_H
+
+#include "pwc.h"
+
+struct pwc_dec23_private
+{
+ unsigned int scalebits;
+ unsigned int nbitsmask, nbits; /* Number of bits of a color in the compressed stream */
+
+ unsigned int reservoir;
+ unsigned int nbits_in_reservoir;
+ const unsigned char *stream;
+ int temp_colors[16];
+
+ unsigned char table_0004_pass1[16][1024];
+ unsigned char table_0004_pass2[16][1024];
+ unsigned char table_8004_pass1[16][256];
+ unsigned char table_8004_pass2[16][256];
+ unsigned int table_subblock[256][12];
+
+ unsigned char table_bitpowermask[8][256];
+ unsigned int table_d800[256];
+ unsigned int table_dc00[256];
+
+};
+
+
+int pwc_dec23_alloc(struct pwc_device *pwc);
+int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd);
+void pwc_dec23_exit(void);
+void pwc_dec23_decompress(const struct pwc_device *pwc,
+ const void *src,
+ void *dst,
+ int flags);
+
+
+
+#endif
+
+
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
+
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 4141829..47d0d83 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -1,7 +1,7 @@
/* Linux driver for Philips webcam
USB and Video4Linux interface part.
(C) 1999-2004 Nemosoft Unv.
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
@@ -62,18 +62,21 @@
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
+#include <linux/version.h>
#include <asm/io.h>
+#include <linux/moduleparam.h>
#include "pwc.h"
-#include "pwc-ioctl.h"
#include "pwc-kiara.h"
#include "pwc-timon.h"
+#include "pwc-dec23.h"
+#include "pwc-dec1.h"
#include "pwc-uncompress.h"
/* Function prototypes and driver templates */
/* hotplug device table support */
-static struct usb_device_id pwc_device_table [] = {
+static const struct usb_device_id pwc_device_table [] = {
{ USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
{ USB_DEVICE(0x0471, 0x0303) },
{ USB_DEVICE(0x0471, 0x0304) },
@@ -81,9 +84,10 @@ static struct usb_device_id pwc_device_table [] = {
{ USB_DEVICE(0x0471, 0x0308) },
{ USB_DEVICE(0x0471, 0x030C) },
{ USB_DEVICE(0x0471, 0x0310) },
- { USB_DEVICE(0x0471, 0x0311) },
+ { USB_DEVICE(0x0471, 0x0311) }, /* Philips ToUcam PRO II */
{ USB_DEVICE(0x0471, 0x0312) },
{ USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
+ { USB_DEVICE(0x0471, 0x0329) }, /* Philips SPC 900NC PC Camera */
{ USB_DEVICE(0x069A, 0x0001) }, /* Askey */
{ USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
{ USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
@@ -94,8 +98,9 @@ static struct usb_device_id pwc_device_table [] = {
{ USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */
{ USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */
{ USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */
- { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */
- { USB_DEVICE(0x055D, 0x9001) },
+ { USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */
+ { USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */
+ { USB_DEVICE(0x055D, 0x9002) }, /* Samsung SNC-35E (Ver3.0) */
{ USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
{ USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */
{ USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
@@ -122,11 +127,13 @@ static struct usb_driver pwc_driver = {
static int default_size = PSZ_QCIF;
static int default_fps = 10;
static int default_fbufs = 3; /* Default number of frame buffers */
-static int default_mbufs = 2; /* Default number of mmap() buffers */
- int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX;
+ int pwc_mbufs = 2; /* Default number of mmap() buffers */
+#if CONFIG_PWC_DEBUG
+ int pwc_trace = PWC_DEBUG_LEVEL;
+#endif
static int power_save = 0;
static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */
-static int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */
+static int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */
static struct {
int type;
char serial_number[30];
@@ -138,7 +145,7 @@ static struct {
static int pwc_video_open(struct inode *inode, struct file *file);
static int pwc_video_close(struct inode *inode, struct file *file);
-static ssize_t pwc_video_read(struct file *file, char __user * buf,
+static ssize_t pwc_video_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos);
static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
static int pwc_video_ioctl(struct inode *inode, struct file *file,
@@ -153,7 +160,6 @@ static struct file_operations pwc_fops = {
.poll = pwc_video_poll,
.mmap = pwc_video_mmap,
.ioctl = pwc_video_ioctl,
- .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
static struct video_device pwc_template = {
@@ -203,52 +209,44 @@ static struct video_device pwc_template = {
/* Here we want the physical address of the memory.
* This is used when initializing the contents of the area.
*/
-static inline unsigned long kvirt_to_pa(unsigned long adr)
-{
- unsigned long kva, ret;
- kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
- kva |= adr & (PAGE_SIZE-1); /* restore the offset */
- ret = __pa(kva);
- return ret;
-}
-static void * rvmalloc(unsigned long size)
+
+static void *pwc_rvmalloc(unsigned long size)
{
void * mem;
unsigned long adr;
- size=PAGE_ALIGN(size);
mem=vmalloc_32(size);
- if (mem)
- {
- memset(mem, 0, size); /* Clear the ram out, no junk to the user */
- adr=(unsigned long) mem;
- while (size > 0)
- {
- SetPageReserved(vmalloc_to_page((void *)adr));
- adr+=PAGE_SIZE;
- size-=PAGE_SIZE;
- }
- }
+ if (!mem)
+ return NULL;
+
+ memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+ adr=(unsigned long) mem;
+ while (size > 0)
+ {
+ SetPageReserved(vmalloc_to_page((void *)adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
return mem;
}
-static void rvfree(void * mem, unsigned long size)
+static void pwc_rvfree(void * mem, unsigned long size)
{
unsigned long adr;
- if (mem)
- {
- adr=(unsigned long) mem;
- while ((long) size > 0)
- {
- ClearPageReserved(vmalloc_to_page((void *)adr));
- adr+=PAGE_SIZE;
- size-=PAGE_SIZE;
- }
- vfree(mem);
- }
+ if (!mem)
+ return;
+
+ adr=(unsigned long) mem;
+ while ((long) size > 0)
+ {
+ ClearPageReserved(vmalloc_to_page((void *)adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ vfree(mem);
}
@@ -256,100 +254,83 @@ static void rvfree(void * mem, unsigned long size)
static int pwc_allocate_buffers(struct pwc_device *pdev)
{
- int i;
+ int i, err;
void *kbuf;
- Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
+ PWC_DEBUG_MEMORY(">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
if (pdev == NULL)
return -ENXIO;
-#ifdef PWC_MAGIC
- if (pdev->magic != PWC_MAGIC) {
- Err("allocate_buffers(): magic failed.\n");
- return -ENXIO;
- }
-#endif
- /* Allocate Isochronous pipe buffers */
+ /* Allocate Isochronuous pipe buffers */
for (i = 0; i < MAX_ISO_BUFS; i++) {
if (pdev->sbuf[i].data == NULL) {
- kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
+ kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
if (kbuf == NULL) {
- Err("Failed to allocate iso buffer %d.\n", i);
+ PWC_ERROR("Failed to allocate iso buffer %d.\n", i);
return -ENOMEM;
}
- Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf);
+ PWC_DEBUG_MEMORY("Allocated iso buffer at %p.\n", kbuf);
pdev->sbuf[i].data = kbuf;
- memset(kbuf, 0, ISO_BUFFER_SIZE);
}
}
/* Allocate frame buffer structure */
if (pdev->fbuf == NULL) {
- kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
+ kbuf = kzalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
if (kbuf == NULL) {
- Err("Failed to allocate frame buffer structure.\n");
+ PWC_ERROR("Failed to allocate frame buffer structure.\n");
return -ENOMEM;
}
- Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf);
+ PWC_DEBUG_MEMORY("Allocated frame buffer structure at %p.\n", kbuf);
pdev->fbuf = kbuf;
- memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf));
}
+
/* create frame buffers, and make circular ring */
for (i = 0; i < default_fbufs; i++) {
if (pdev->fbuf[i].data == NULL) {
kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
if (kbuf == NULL) {
- Err("Failed to allocate frame buffer %d.\n", i);
+ PWC_ERROR("Failed to allocate frame buffer %d.\n", i);
return -ENOMEM;
}
- Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf);
+ PWC_DEBUG_MEMORY("Allocated frame buffer %d at %p.\n", i, kbuf);
pdev->fbuf[i].data = kbuf;
- memset(kbuf, 128, PWC_FRAME_SIZE);
+ memset(kbuf, 0, PWC_FRAME_SIZE);
}
}
/* Allocate decompressor table space */
- kbuf = NULL;
- switch (pdev->type)
- {
- case 675:
- case 680:
- case 690:
- case 720:
- case 730:
- case 740:
- case 750:
-#if 0
- Trace(TRACE_MEMORY,"private_data(%zu)\n",sizeof(struct pwc_dec23_private));
- kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); /* Timon & Kiara */
- break;
- case 645:
- case 646:
- /* TODO & FIXME */
- kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
- break;
-#endif
- ;
- }
- pdev->decompress_data = kbuf;
+ if (DEVICE_USE_CODEC1(pdev->type))
+ err = pwc_dec1_alloc(pdev);
+ else
+ err = pwc_dec23_alloc(pdev);
+
+ if (err) {
+ PWC_ERROR("Failed to allocate decompress table.\n");
+ return err;
+ }
/* Allocate image buffer; double buffer for mmap() */
- kbuf = rvmalloc(default_mbufs * pdev->len_per_image);
+ kbuf = pwc_rvmalloc(pwc_mbufs * pdev->len_per_image);
if (kbuf == NULL) {
- Err("Failed to allocate image buffer(s). needed (%d)\n",default_mbufs * pdev->len_per_image);
+ PWC_ERROR("Failed to allocate image buffer(s). needed (%d)\n",
+ pwc_mbufs * pdev->len_per_image);
return -ENOMEM;
}
- Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf);
+ PWC_DEBUG_MEMORY("Allocated image buffer at %p.\n", kbuf);
pdev->image_data = kbuf;
- for (i = 0; i < default_mbufs; i++)
- pdev->image_ptr[i] = kbuf + i * pdev->len_per_image;
- for (; i < MAX_IMAGES; i++)
- pdev->image_ptr[i] = NULL;
+ for (i = 0; i < pwc_mbufs; i++) {
+ pdev->images[i].offset = i * pdev->len_per_image;
+ pdev->images[i].vma_use_count = 0;
+ }
+ for (; i < MAX_IMAGES; i++) {
+ pdev->images[i].offset = 0;
+ }
kbuf = NULL;
- Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n");
+ PWC_DEBUG_MEMORY("<< pwc_allocate_buffers()\n");
return 0;
}
@@ -357,21 +338,14 @@ static void pwc_free_buffers(struct pwc_device *pdev)
{
int i;
- Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev);
+ PWC_DEBUG_MEMORY("Entering free_buffers(%p).\n", pdev);
if (pdev == NULL)
return;
-#ifdef PWC_MAGIC
- if (pdev->magic != PWC_MAGIC) {
- Err("free_buffers(): magic failed.\n");
- return;
- }
-#endif
-
/* Release Iso-pipe buffers */
for (i = 0; i < MAX_ISO_BUFS; i++)
if (pdev->sbuf[i].data != NULL) {
- Trace(TRACE_MEMORY, "Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
+ PWC_DEBUG_MEMORY("Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
kfree(pdev->sbuf[i].data);
pdev->sbuf[i].data = NULL;
}
@@ -380,7 +354,7 @@ static void pwc_free_buffers(struct pwc_device *pdev)
if (pdev->fbuf != NULL) {
for (i = 0; i < default_fbufs; i++) {
if (pdev->fbuf[i].data != NULL) {
- Trace(TRACE_MEMORY, "Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
+ PWC_DEBUG_MEMORY("Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
vfree(pdev->fbuf[i].data);
pdev->fbuf[i].data = NULL;
}
@@ -391,20 +365,19 @@ static void pwc_free_buffers(struct pwc_device *pdev)
/* Intermediate decompression buffer & tables */
if (pdev->decompress_data != NULL) {
- Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data);
+ PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n", pdev->decompress_data);
kfree(pdev->decompress_data);
pdev->decompress_data = NULL;
}
- pdev->decompressor = NULL;
/* Release image buffers */
if (pdev->image_data != NULL) {
- Trace(TRACE_MEMORY, "Freeing image buffer at %p.\n", pdev->image_data);
- rvfree(pdev->image_data, default_mbufs * pdev->len_per_image);
+ PWC_DEBUG_MEMORY("Freeing image buffer at %p.\n", pdev->image_data);
+ pwc_rvfree(pdev->image_data, pwc_mbufs * pdev->len_per_image);
}
pdev->image_data = NULL;
- Trace(TRACE_MEMORY, "Leaving free_buffers().\n");
+ PWC_DEBUG_MEMORY("Leaving free_buffers().\n");
}
/* The frame & image buffer mess.
@@ -464,7 +437,7 @@ static void pwc_free_buffers(struct pwc_device *pdev)
/**
\brief Find next frame buffer to fill. Take from empty or full list, whichever comes first.
*/
-static inline int pwc_next_fill_frame(struct pwc_device *pdev)
+static int pwc_next_fill_frame(struct pwc_device *pdev)
{
int ret;
unsigned long flags;
@@ -489,23 +462,17 @@ static inline int pwc_next_fill_frame(struct pwc_device *pdev)
}
else {
/* Hmm. Take it from the full list */
-#if PWC_DEBUG
/* sanity check */
if (pdev->full_frames == NULL) {
- Err("Neither empty or full frames available!\n");
+ PWC_ERROR("Neither empty or full frames available!\n");
spin_unlock_irqrestore(&pdev->ptrlock, flags);
return -EINVAL;
}
-#endif
pdev->fill_frame = pdev->full_frames;
pdev->full_frames = pdev->full_frames->next;
ret = 1;
}
pdev->fill_frame->next = NULL;
-#if PWC_DEBUG
- Trace(TRACE_SEQUENCE, "Assigning sequence number %d.\n", pdev->sequence);
- pdev->fill_frame->sequence = pdev->sequence++;
-#endif
spin_unlock_irqrestore(&pdev->ptrlock, flags);
return ret;
}
@@ -521,6 +488,8 @@ static void pwc_reset_buffers(struct pwc_device *pdev)
int i;
unsigned long flags;
+ PWC_DEBUG_MEMORY(">> %s __enter__\n", __FUNCTION__);
+
spin_lock_irqsave(&pdev->ptrlock, flags);
pdev->full_frames = NULL;
pdev->full_frames_tail = NULL;
@@ -540,13 +509,15 @@ static void pwc_reset_buffers(struct pwc_device *pdev)
pdev->image_read_pos = 0;
pdev->fill_image = 0;
spin_unlock_irqrestore(&pdev->ptrlock, flags);
+
+ PWC_DEBUG_MEMORY("<< %s __leaving__\n", __FUNCTION__);
}
/**
\brief Do all the handling for getting one frame: get pointer, decompress, advance pointers.
*/
-static int pwc_handle_frame(struct pwc_device *pdev)
+int pwc_handle_frame(struct pwc_device *pdev)
{
int ret = 0;
unsigned long flags;
@@ -556,41 +527,40 @@ static int pwc_handle_frame(struct pwc_device *pdev)
we can release the lock after this without problems */
if (pdev->read_frame != NULL) {
/* This can't theoretically happen */
- Err("Huh? Read frame still in use?\n");
+ PWC_ERROR("Huh? Read frame still in use?\n");
+ spin_unlock_irqrestore(&pdev->ptrlock, flags);
+ return ret;
+ }
+
+
+ if (pdev->full_frames == NULL) {
+ PWC_ERROR("Woops. No frames ready.\n");
}
else {
- if (pdev->full_frames == NULL) {
- Err("Woops. No frames ready.\n");
+ pdev->read_frame = pdev->full_frames;
+ pdev->full_frames = pdev->full_frames->next;
+ pdev->read_frame->next = NULL;
+ }
+
+ if (pdev->read_frame != NULL) {
+ /* Decompression is a lenghty process, so it's outside of the lock.
+ This gives the isoc_handler the opportunity to fill more frames
+ in the mean time.
+ */
+ spin_unlock_irqrestore(&pdev->ptrlock, flags);
+ ret = pwc_decompress(pdev);
+ spin_lock_irqsave(&pdev->ptrlock, flags);
+
+ /* We're done with read_buffer, tack it to the end of the empty buffer list */
+ if (pdev->empty_frames == NULL) {
+ pdev->empty_frames = pdev->read_frame;
+ pdev->empty_frames_tail = pdev->empty_frames;
}
else {
- pdev->read_frame = pdev->full_frames;
- pdev->full_frames = pdev->full_frames->next;
- pdev->read_frame->next = NULL;
- }
-
- if (pdev->read_frame != NULL) {
-#if PWC_DEBUG
- Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence);
-#endif
- /* Decompression is a lenghty process, so it's outside of the lock.
- This gives the isoc_handler the opportunity to fill more frames
- in the mean time.
- */
- spin_unlock_irqrestore(&pdev->ptrlock, flags);
- ret = pwc_decompress(pdev);
- spin_lock_irqsave(&pdev->ptrlock, flags);
-
- /* We're done with read_buffer, tack it to the end of the empty buffer list */
- if (pdev->empty_frames == NULL) {
- pdev->empty_frames = pdev->read_frame;
- pdev->empty_frames_tail = pdev->empty_frames;
- }
- else {
- pdev->empty_frames_tail->next = pdev->read_frame;
- pdev->empty_frames_tail = pdev->read_frame;
- }
- pdev->read_frame = NULL;
+ pdev->empty_frames_tail->next = pdev->read_frame;
+ pdev->empty_frames_tail = pdev->read_frame;
}
+ pdev->read_frame = NULL;
}
spin_unlock_irqrestore(&pdev->ptrlock, flags);
return ret;
@@ -599,12 +569,114 @@ static int pwc_handle_frame(struct pwc_device *pdev)
/**
\brief Advance pointers of image buffer (after each user request)
*/
-static inline void pwc_next_image(struct pwc_device *pdev)
+void pwc_next_image(struct pwc_device *pdev)
{
pdev->image_used[pdev->fill_image] = 0;
- pdev->fill_image = (pdev->fill_image + 1) % default_mbufs;
+ pdev->fill_image = (pdev->fill_image + 1) % pwc_mbufs;
}
+/**
+ * Print debug information when a frame is discarded because all of our buffer
+ * is full
+ */
+static void pwc_frame_dumped(struct pwc_device *pdev)
+{
+ pdev->vframes_dumped++;
+ if (pdev->vframe_count < FRAME_LOWMARK)
+ return;
+
+ if (pdev->vframes_dumped < 20)
+ PWC_DEBUG_FLOW("Dumping frame %d\n", pdev->vframe_count);
+ else if (pdev->vframes_dumped == 20)
+ PWC_DEBUG_FLOW("Dumping frame %d (last message)\n",
+ pdev->vframe_count);
+}
+
+static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_buf *fbuf)
+{
+ int awake = 0;
+
+ /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
+ frames on the USB wire after an exposure change. This conditition is
+ however detected in the cam and a bit is set in the header.
+ */
+ if (pdev->type == 730) {
+ unsigned char *ptr = (unsigned char *)fbuf->data;
+
+ if (ptr[1] == 1 && ptr[0] & 0x10) {
+ PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n");
+ pdev->drop_frames += 2;
+ pdev->vframes_error++;
+ }
+ if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+ if (ptr[0] & 0x01) {
+ pdev->snapshot_button_status = 1;
+ PWC_TRACE("Snapshot button pressed.\n");
+ }
+ else {
+ PWC_TRACE("Snapshot button released.\n");
+ }
+ }
+ if ((ptr[0] ^ pdev->vmirror) & 0x02) {
+ if (ptr[0] & 0x02)
+ PWC_TRACE("Image is mirrored.\n");
+ else
+ PWC_TRACE("Image is normal.\n");
+ }
+ pdev->vmirror = ptr[0] & 0x03;
+ /* Sometimes the trailer of the 730 is still sent as a 4 byte packet
+ after a short frame; this condition is filtered out specifically. A 4 byte
+ frame doesn't make sense anyway.
+ So we get either this sequence:
+ drop_bit set -> 4 byte frame -> short frame -> good frame
+ Or this one:
+ drop_bit set -> short frame -> good frame
+ So we drop either 3 or 2 frames in all!
+ */
+ if (fbuf->filled == 4)
+ pdev->drop_frames++;
+ }
+ else if (pdev->type == 740 || pdev->type == 720) {
+ unsigned char *ptr = (unsigned char *)fbuf->data;
+ if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+ if (ptr[0] & 0x01) {
+ pdev->snapshot_button_status = 1;
+ PWC_TRACE("Snapshot button pressed.\n");
+ }
+ else
+ PWC_TRACE("Snapshot button released.\n");
+ }
+ pdev->vmirror = ptr[0] & 0x03;
+ }
+
+ /* In case we were instructed to drop the frame, do so silently.
+ The buffer pointers are not updated either (but the counters are reset below).
+ */
+ if (pdev->drop_frames > 0)
+ pdev->drop_frames--;
+ else {
+ /* Check for underflow first */
+ if (fbuf->filled < pdev->frame_total_size) {
+ PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);"
+ " discarded.\n", fbuf->filled);
+ pdev->vframes_error++;
+ }
+ else {
+ /* Send only once per EOF */
+ awake = 1; /* delay wake_ups */
+
+ /* Find our next frame to fill. This will always succeed, since we
+ * nick a frame from either empty or full list, but if we had to
+ * take it from the full list, it means a frame got dropped.
+ */
+ if (pwc_next_fill_frame(pdev))
+ pwc_frame_dumped(pdev);
+
+ }
+ } /* !drop_frames */
+ pdev->vframe_count++;
+ return awake;
+}
/* This gets called for the Isochronous pipe (video). This is done in
* interrupt time, so it has to be fast, not crash, and not stall. Neat.
@@ -620,17 +692,12 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
awake = 0;
pdev = (struct pwc_device *)urb->context;
if (pdev == NULL) {
- Err("isoc_handler() called with NULL device?!\n");
- return;
- }
-#ifdef PWC_MAGIC
- if (pdev->magic != PWC_MAGIC) {
- Err("isoc_handler() called with bad magic!\n");
+ PWC_ERROR("isoc_handler() called with NULL device?!\n");
return;
}
-#endif
+
if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
- Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
+ PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
return;
}
if (urb->status != -EINPROGRESS && urb->status != 0) {
@@ -645,13 +712,13 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break;
case -ETIMEDOUT: errmsg = "NAK (device does not respond)"; break;
}
- Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
+ PWC_DEBUG_FLOW("pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
/* Give up after a number of contiguous errors on the USB bus.
Appearantly something is wrong so we simulate an unplug event.
*/
if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
{
- Info("Too many ISOC errors, bailing out.\n");
+ PWC_INFO("Too many ISOC errors, bailing out.\n");
pdev->error_status = EIO;
awake = 1;
wake_up_interruptible(&pdev->frameq);
@@ -661,7 +728,7 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
fbuf = pdev->fill_frame;
if (fbuf == NULL) {
- Err("pwc_isoc_handler without valid fill frame.\n");
+ PWC_ERROR("pwc_isoc_handler without valid fill frame.\n");
awake = 1;
goto handler_end;
}
@@ -688,7 +755,7 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
/* ...copy data to frame buffer, if possible */
if (flen + fbuf->filled > pdev->frame_total_size) {
- Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size);
+ PWC_DEBUG_FLOW("Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size);
pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */
pdev->vframes_error++;
}
@@ -704,96 +771,28 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
/* Shorter packet... We probably have the end of an image-frame;
wake up read() process and let select()/poll() do something.
Decompression is done in user time over there.
- */
+ */
if (pdev->vsync == 2) {
- /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
- frames on the USB wire after an exposure change. This conditition is
- however detected in the cam and a bit is set in the header.
- */
- if (pdev->type == 730) {
- unsigned char *ptr = (unsigned char *)fbuf->data;
-
- if (ptr[1] == 1 && ptr[0] & 0x10) {
-#if PWC_DEBUG
- Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence);
-#endif
- pdev->drop_frames += 2;
- pdev->vframes_error++;
- }
- if ((ptr[0] ^ pdev->vmirror) & 0x01) {
- if (ptr[0] & 0x01)
- Info("Snapshot button pressed.\n");
- else
- Info("Snapshot button released.\n");
- }
- if ((ptr[0] ^ pdev->vmirror) & 0x02) {
- if (ptr[0] & 0x02)
- Info("Image is mirrored.\n");
- else
- Info("Image is normal.\n");
- }
- pdev->vmirror = ptr[0] & 0x03;
- /* Sometimes the trailer of the 730 is still sent as a 4 byte packet
- after a short frame; this condition is filtered out specifically. A 4 byte
- frame doesn't make sense anyway.
- So we get either this sequence:
- drop_bit set -> 4 byte frame -> short frame -> good frame
- Or this one:
- drop_bit set -> short frame -> good frame
- So we drop either 3 or 2 frames in all!
- */
- if (fbuf->filled == 4)
- pdev->drop_frames++;
+ if (pwc_rcv_short_packet(pdev, fbuf)) {
+ awake = 1;
+ fbuf = pdev->fill_frame;
}
-
- /* In case we were instructed to drop the frame, do so silently.
- The buffer pointers are not updated either (but the counters are reset below).
- */
- if (pdev->drop_frames > 0)
- pdev->drop_frames--;
- else {
- /* Check for underflow first */
- if (fbuf->filled < pdev->frame_total_size) {
- Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled);
- pdev->vframes_error++;
- }
- else {
- /* Send only once per EOF */
- awake = 1; /* delay wake_ups */
-
- /* Find our next frame to fill. This will always succeed, since we
- * nick a frame from either empty or full list, but if we had to
- * take it from the full list, it means a frame got dropped.
- */
- if (pwc_next_fill_frame(pdev)) {
- pdev->vframes_dumped++;
- if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) {
- if (pdev->vframes_dumped < 20)
- Trace(TRACE_FLOW, "Dumping frame %d.\n", pdev->vframe_count);
- if (pdev->vframes_dumped == 20)
- Trace(TRACE_FLOW, "Dumping frame %d (last message).\n", pdev->vframe_count);
- }
- }
- fbuf = pdev->fill_frame;
- }
- } /* !drop_frames */
- pdev->vframe_count++;
}
fbuf->filled = 0;
fillptr = fbuf->data;
pdev->vsync = 1;
- } /* .. flen < last_packet_size */
+ }
+
pdev->vlast_packet_size = flen;
} /* ..status == 0 */
-#if PWC_DEBUG
- /* This is normally not interesting to the user, unless you are really debugging something */
else {
+ /* This is normally not interesting to the user, unless
+ * you are really debugging something */
static int iso_error = 0;
iso_error++;
if (iso_error < 20)
- Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);
+ PWC_DEBUG_FLOW("Iso frame %d of USB has error %d\n", i, fst);
}
-#endif
}
handler_end:
@@ -803,11 +802,11 @@ handler_end:
urb->dev = pdev->udev;
i = usb_submit_urb(urb, GFP_ATOMIC);
if (i != 0)
- Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
+ PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
}
-static int pwc_isoc_init(struct pwc_device *pdev)
+int pwc_isoc_init(struct pwc_device *pdev)
{
struct usb_device *udev;
struct urb *urb;
@@ -826,7 +825,6 @@ static int pwc_isoc_init(struct pwc_device *pdev)
/* Get the current alternate interface, adjust packet size */
if (!udev->actconfig)
return -EFAULT;
-
intf = usb_ifnum_to_if(udev, 0);
if (intf)
idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
@@ -836,20 +834,21 @@ static int pwc_isoc_init(struct pwc_device *pdev)
/* Search video endpoint */
pdev->vmax_packet_size = -1;
- for (i = 0; i < idesc->desc.bNumEndpoints; i++)
+ for (i = 0; i < idesc->desc.bNumEndpoints; i++) {
if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) {
pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize);
break;
}
+ }
if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
- Err("Failed to find packet size for video endpoint in current alternate setting.\n");
+ PWC_ERROR("Failed to find packet size for video endpoint in current alternate setting.\n");
return -ENFILE; /* Odd error, that should be noticeable */
}
/* Set alternate interface */
ret = 0;
- Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate);
+ PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate);
ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
if (ret < 0)
return ret;
@@ -857,12 +856,12 @@ static int pwc_isoc_init(struct pwc_device *pdev)
for (i = 0; i < MAX_ISO_BUFS; i++) {
urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
if (urb == NULL) {
- Err("Failed to allocate urb %d\n", i);
+ PWC_ERROR("Failed to allocate urb %d\n", i);
ret = -ENOMEM;
break;
}
pdev->sbuf[i].urb = urb;
- Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb);
+ PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb);
}
if (ret) {
/* De-allocate in reverse order */
@@ -899,24 +898,26 @@ static int pwc_isoc_init(struct pwc_device *pdev)
for (i = 0; i < MAX_ISO_BUFS; i++) {
ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);
if (ret)
- Err("isoc_init() submit_urb %d failed with error %d\n", i, ret);
+ PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
else
- Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb);
+ PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->sbuf[i].urb);
}
/* All is done... */
pdev->iso_init = 1;
- Trace(TRACE_OPEN, "<< pwc_isoc_init()\n");
+ PWC_DEBUG_OPEN("<< pwc_isoc_init()\n");
return 0;
}
-static void pwc_isoc_cleanup(struct pwc_device *pdev)
+void pwc_isoc_cleanup(struct pwc_device *pdev)
{
int i;
- Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n");
+ PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
if (pdev == NULL)
return;
+ if (pdev->iso_init == 0)
+ return;
/* Unlinking ISOC buffers one by one */
for (i = 0; i < MAX_ISO_BUFS; i++) {
@@ -925,10 +926,10 @@ static void pwc_isoc_cleanup(struct pwc_device *pdev)
urb = pdev->sbuf[i].urb;
if (urb != 0) {
if (pdev->iso_init) {
- Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb);
+ PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);
usb_kill_urb(urb);
}
- Trace(TRACE_MEMORY, "Freeing URB\n");
+ PWC_DEBUG_MEMORY("Freeing URB\n");
usb_free_urb(urb);
pdev->sbuf[i].urb = NULL;
}
@@ -938,12 +939,12 @@ static void pwc_isoc_cleanup(struct pwc_device *pdev)
is signalled by EPIPE)
*/
if (pdev->error_status && pdev->error_status != EPIPE) {
- Trace(TRACE_OPEN, "Setting alternate interface 0.\n");
+ PWC_DEBUG_OPEN("Setting alternate interface 0.\n");
usb_set_interface(pdev->udev, 0, 0);
}
pdev->iso_init = 0;
- Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n");
+ PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");
}
int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
@@ -957,18 +958,18 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f
/* Try to set video mode... */
start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);
if (ret) {
- Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n");
+ PWC_DEBUG_FLOW("pwc_set_video_mode attempt 1 failed.\n");
/* That failed... restore old mode (we know that worked) */
start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
if (start) {
- Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n");
+ PWC_DEBUG_FLOW("pwc_set_video_mode attempt 2 failed.\n");
}
}
if (start == 0)
{
if (pwc_isoc_init(pdev) < 0)
{
- Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
+ PWC_WARNING("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
ret = -EAGAIN; /* let's try again, who knows if it works a second time */
}
}
@@ -976,54 +977,129 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f
return ret; /* Return original error code */
}
+/*********
+ * sysfs
+ *********/
+static struct pwc_device *cd_to_pwc(struct class_device *cd)
+{
+ struct video_device *vdev = to_video_device(cd);
+ return video_get_drvdata(vdev);
+}
+
+static ssize_t show_pan_tilt(struct class_device *class_dev, char *buf)
+{
+ struct pwc_device *pdev = cd_to_pwc(class_dev);
+ return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle);
+}
+
+static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf,
+ size_t count)
+{
+ struct pwc_device *pdev = cd_to_pwc(class_dev);
+ int pan, tilt;
+ int ret = -EINVAL;
+
+ if (strncmp(buf, "reset", 5) == 0)
+ ret = pwc_mpt_reset(pdev, 0x3);
+
+ else if (sscanf(buf, "%d %d", &pan, &tilt) > 0)
+ ret = pwc_mpt_set_angle(pdev, pan, tilt);
+
+ if (ret < 0)
+ return ret;
+ return strlen(buf);
+}
+static CLASS_DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt,
+ store_pan_tilt);
+
+static ssize_t show_snapshot_button_status(struct class_device *class_dev, char *buf)
+{
+ struct pwc_device *pdev = cd_to_pwc(class_dev);
+ int status = pdev->snapshot_button_status;
+ pdev->snapshot_button_status = 0;
+ return sprintf(buf, "%d\n", status);
+}
+
+static CLASS_DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
+ NULL);
+
+static void pwc_create_sysfs_files(struct video_device *vdev)
+{
+ struct pwc_device *pdev = video_get_drvdata(vdev);
+ if (pdev->features & FEATURE_MOTOR_PANTILT)
+ video_device_create_file(vdev, &class_device_attr_pan_tilt);
+ video_device_create_file(vdev, &class_device_attr_button);
+}
+
+static void pwc_remove_sysfs_files(struct video_device *vdev)
+{
+ struct pwc_device *pdev = video_get_drvdata(vdev);
+ if (pdev->features & FEATURE_MOTOR_PANTILT)
+ video_device_remove_file(vdev, &class_device_attr_pan_tilt);
+ video_device_remove_file(vdev, &class_device_attr_button);
+}
+
+#if CONFIG_PWC_DEBUG
+static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
+{
+ switch(sensor_type) {
+ case 0x00:
+ return "Hyundai CMOS sensor";
+ case 0x20:
+ return "Sony CCD sensor + TDA8787";
+ case 0x2E:
+ return "Sony CCD sensor + Exas 98L59";
+ case 0x2F:
+ return "Sony CCD sensor + ADI 9804";
+ case 0x30:
+ return "Sharp CCD sensor + TDA8787";
+ case 0x3E:
+ return "Sharp CCD sensor + Exas 98L59";
+ case 0x3F:
+ return "Sharp CCD sensor + ADI 9804";
+ case 0x40:
+ return "UPA 1021 sensor";
+ case 0x100:
+ return "VGA sensor";
+ case 0x101:
+ return "PAL MR sensor";
+ default:
+ return "unknown type of sensor";
+ }
+}
+#endif
/***************************************************************************/
/* Video4Linux functions */
static int pwc_video_open(struct inode *inode, struct file *file)
{
- int i;
+ int i, ret;
struct video_device *vdev = video_devdata(file);
struct pwc_device *pdev;
- Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev);
+ PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev);
pdev = (struct pwc_device *)vdev->priv;
if (pdev == NULL)
BUG();
- if (pdev->vopen)
+ if (pdev->vopen) {
+ PWC_DEBUG_OPEN("I'm busy, someone is using the device.\n");
return -EBUSY;
+ }
down(&pdev->modlock);
if (!pdev->usb_init) {
- Trace(TRACE_OPEN, "Doing first time initialization.\n");
+ PWC_DEBUG_OPEN("Doing first time initialization.\n");
pdev->usb_init = 1;
- if (pwc_trace & TRACE_OPEN)
+ /* Query sensor type */
+ ret = pwc_get_cmos_sensor(pdev, &i);
+ if (ret >= 0)
{
- /* Query sensor type */
- const char *sensor_type = NULL;
- int ret;
-
- ret = pwc_get_cmos_sensor(pdev, &i);
- if (ret >= 0)
- {
- switch(i) {
- case 0x00: sensor_type = "Hyundai CMOS sensor"; break;
- case 0x20: sensor_type = "Sony CCD sensor + TDA8787"; break;
- case 0x2E: sensor_type = "Sony CCD sensor + Exas 98L59"; break;
- case 0x2F: sensor_type = "Sony CCD sensor + ADI 9804"; break;
- case 0x30: sensor_type = "Sharp CCD sensor + TDA8787"; break;
- case 0x3E: sensor_type = "Sharp CCD sensor + Exas 98L59"; break;
- case 0x3F: sensor_type = "Sharp CCD sensor + ADI 9804"; break;
- case 0x40: sensor_type = "UPA 1021 sensor"; break;
- case 0x100: sensor_type = "VGA sensor"; break;
- case 0x101: sensor_type = "PAL MR sensor"; break;
- default: sensor_type = "unknown type of sensor"; break;
- }
- }
- if (sensor_type != NULL)
- Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i);
+ PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n",
+ pdev->vdev->name,
+ pwc_sensor_type_to_string(i), i);
}
}
@@ -1031,34 +1107,32 @@ static int pwc_video_open(struct inode *inode, struct file *file)
if (power_save) {
i = pwc_camera_power(pdev, 1);
if (i < 0)
- Info("Failed to restore power to the camera! (%d)\n", i);
+ PWC_DEBUG_OPEN("Failed to restore power to the camera! (%d)\n", i);
}
/* Set LED on/off time */
if (pwc_set_leds(pdev, led_on, led_off) < 0)
- Info("Failed to set LED on/off time.\n");
+ PWC_DEBUG_OPEN("Failed to set LED on/off time.\n");
pwc_construct(pdev); /* set min/max sizes correct */
/* So far, so good. Allocate memory. */
i = pwc_allocate_buffers(pdev);
if (i < 0) {
- Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n");
+ PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n");
+ pwc_free_buffers(pdev);
up(&pdev->modlock);
return i;
}
/* Reset buffers & parameters */
pwc_reset_buffers(pdev);
- for (i = 0; i < default_mbufs; i++)
+ for (i = 0; i < pwc_mbufs; i++)
pdev->image_used[i] = 0;
pdev->vframe_count = 0;
pdev->vframes_dumped = 0;
pdev->vframes_error = 0;
pdev->visoc_errors = 0;
pdev->error_status = 0;
-#if PWC_DEBUG
- pdev->sequence = 0;
-#endif
pwc_construct(pdev); /* set min/max sizes correct */
/* Set some defaults */
@@ -1070,29 +1144,44 @@ static int pwc_video_open(struct inode *inode, struct file *file)
*/
i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0);
if (i) {
- Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n");
- if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750)
- i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0);
+ unsigned int default_resolution;
+ PWC_DEBUG_OPEN("First attempt at set_video_mode failed.\n");
+ if (pdev->type>= 730)
+ default_resolution = PSZ_QSIF;
else
- i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0);
+ default_resolution = PSZ_QCIF;
+
+ i = pwc_set_video_mode(pdev,
+ pwc_image_sizes[default_resolution].x,
+ pwc_image_sizes[default_resolution].y,
+ 10,
+ pdev->vcompression,
+ 0);
}
if (i) {
- Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n");
+ PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n");
+ pwc_free_buffers(pdev);
up(&pdev->modlock);
return i;
}
i = pwc_isoc_init(pdev);
if (i) {
- Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i);
+ PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i);
+ pwc_isoc_cleanup(pdev);
+ pwc_free_buffers(pdev);
up(&pdev->modlock);
return i;
}
+ /* Initialize the webcam to sane value */
+ pwc_set_brightness(pdev, 0x7fff);
+ pwc_set_agc(pdev, 1, 0);
+
pdev->vopen++;
file->private_data = vdev;
up(&pdev->modlock);
- Trace(TRACE_OPEN, "<< video_open() returns 0.\n");
+ PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
return 0;
}
@@ -1103,35 +1192,23 @@ static int pwc_video_close(struct inode *inode, struct file *file)
struct pwc_device *pdev;
int i;
- Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev);
+ PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
pdev = (struct pwc_device *)vdev->priv;
if (pdev->vopen == 0)
- Info("video_close() called on closed device?\n");
+ PWC_DEBUG_MODULE("video_close() called on closed device?\n");
/* Dump statistics, but only if a reasonable amount of frames were
processed (to prevent endless log-entries in case of snap-shot
programs)
*/
if (pdev->vframe_count > 20)
- Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
+ PWC_DEBUG_MODULE("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
- switch (pdev->type)
- {
- case 675:
- case 680:
- case 690:
- case 720:
- case 730:
- case 740:
- case 750:
-/* pwc_dec23_exit(); *//* Timon & Kiara */
- break;
- case 645:
- case 646:
-/* pwc_dec1_exit(); */
- break;
- }
+ if (DEVICE_USE_CODEC1(pdev->type))
+ pwc_dec1_exit();
+ else
+ pwc_dec23_exit();
pwc_isoc_cleanup(pdev);
pwc_free_buffers(pdev);
@@ -1140,15 +1217,15 @@ static int pwc_video_close(struct inode *inode, struct file *file)
if (pdev->error_status != EPIPE) {
/* Turn LEDs off */
if (pwc_set_leds(pdev, 0, 0) < 0)
- Info("Failed to set LED on/off time.\n");
+ PWC_DEBUG_MODULE("Failed to set LED on/off time.\n");
if (power_save) {
i = pwc_camera_power(pdev, 0);
if (i < 0)
- Err("Failed to power down camera (%d)\n", i);
+ PWC_ERROR("Failed to power down camera (%d)\n", i);
}
}
- pdev->vopen = 0;
- Trace(TRACE_OPEN, "<< video_close()\n");
+ pdev->vopen--;
+ PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
return 0;
}
@@ -1164,7 +1241,7 @@ static int pwc_video_close(struct inode *inode, struct file *file)
device is tricky anyhow.
*/
-static ssize_t pwc_video_read(struct file *file, char __user * buf,
+static ssize_t pwc_video_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct video_device *vdev = file->private_data;
@@ -1172,8 +1249,10 @@ static ssize_t pwc_video_read(struct file *file, char __user * buf,
int noblock = file->f_flags & O_NONBLOCK;
DECLARE_WAITQUEUE(wait, current);
int bytes_to_read;
+ void *image_buffer_addr;
- Trace(TRACE_READ, "video_read(0x%p, %p, %zu) called.\n", vdev, buf, count);
+ PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n",
+ vdev, buf, count);
if (vdev == NULL)
return -EFAULT;
pdev = vdev->priv;
@@ -1214,16 +1293,19 @@ static ssize_t pwc_video_read(struct file *file, char __user * buf,
return -EFAULT;
}
- Trace(TRACE_READ, "Copying data to user space.\n");
+ PWC_DEBUG_READ("Copying data to user space.\n");
if (pdev->vpalette == VIDEO_PALETTE_RAW)
- bytes_to_read = pdev->frame_size;
+ bytes_to_read = pdev->frame_size + sizeof(struct pwc_raw_frame);
else
bytes_to_read = pdev->view.size;
/* copy bytes to user space; we allow for partial reads */
if (count + pdev->image_read_pos > bytes_to_read)
count = bytes_to_read - pdev->image_read_pos;
- if (copy_to_user(buf, pdev->image_ptr[pdev->fill_image] + pdev->image_read_pos, count))
+ image_buffer_addr = pdev->image_data;
+ image_buffer_addr += pdev->images[pdev->fill_image].offset;
+ image_buffer_addr += pdev->image_read_pos;
+ if (copy_to_user(buf, image_buffer_addr, count))
return -EFAULT;
pdev->image_read_pos += count;
if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */
@@ -1253,370 +1335,56 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
return 0;
}
-static int pwc_video_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
-{
- struct video_device *vdev = file->private_data;
- struct pwc_device *pdev;
- DECLARE_WAITQUEUE(wait, current);
-
- if (vdev == NULL)
- return -EFAULT;
- pdev = vdev->priv;
- if (pdev == NULL)
- return -EFAULT;
-
- switch (cmd) {
- /* Query cabapilities */
- case VIDIOCGCAP:
- {
- struct video_capability *caps = arg;
-
- strcpy(caps->name, vdev->name);
- caps->type = VID_TYPE_CAPTURE;
- caps->channels = 1;
- caps->audios = 1;
- caps->minwidth = pdev->view_min.x;
- caps->minheight = pdev->view_min.y;
- caps->maxwidth = pdev->view_max.x;
- caps->maxheight = pdev->view_max.y;
- break;
- }
-
- /* Channel functions (simulate 1 channel) */
- case VIDIOCGCHAN:
- {
- struct video_channel *v = arg;
-
- if (v->channel != 0)
- return -EINVAL;
- v->flags = 0;
- v->tuners = 0;
- v->type = VIDEO_TYPE_CAMERA;
- strcpy(v->name, "Webcam");
- return 0;
- }
-
- case VIDIOCSCHAN:
- {
- /* The spec says the argument is an integer, but
- the bttv driver uses a video_channel arg, which
- makes sense becasue it also has the norm flag.
- */
- struct video_channel *v = arg;
- if (v->channel != 0)
- return -EINVAL;
- return 0;
- }
-
-
- /* Picture functions; contrast etc. */
- case VIDIOCGPICT:
- {
- struct video_picture *p = arg;
- int val;
-
- val = pwc_get_brightness(pdev);
- if (val >= 0)
- p->brightness = val;
- else
- p->brightness = 0xffff;
- val = pwc_get_contrast(pdev);
- if (val >= 0)
- p->contrast = val;
- else
- p->contrast = 0xffff;
- /* Gamma, Whiteness, what's the difference? :) */
- val = pwc_get_gamma(pdev);
- if (val >= 0)
- p->whiteness = val;
- else
- p->whiteness = 0xffff;
- val = pwc_get_saturation(pdev);
- if (val >= 0)
- p->colour = val;
- else
- p->colour = 0xffff;
- p->depth = 24;
- p->palette = pdev->vpalette;
- p->hue = 0xFFFF; /* N/A */
- break;
- }
-
- case VIDIOCSPICT:
- {
- struct video_picture *p = arg;
- /*
- * FIXME: Suppose we are mid read
- ANSWER: No problem: the firmware of the camera
- can handle brightness/contrast/etc
- changes at _any_ time, and the palette
- is used exactly once in the uncompress
- routine.
- */
- pwc_set_brightness(pdev, p->brightness);
- pwc_set_contrast(pdev, p->contrast);
- pwc_set_gamma(pdev, p->whiteness);
- pwc_set_saturation(pdev, p->colour);
- if (p->palette && p->palette != pdev->vpalette) {
- switch (p->palette) {
- case VIDEO_PALETTE_YUV420P:
- case VIDEO_PALETTE_RAW:
- pdev->vpalette = p->palette;
- return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
- break;
- default:
- return -EINVAL;
- break;
- }
- }
- break;
- }
-
- /* Window/size parameters */
- case VIDIOCGWIN:
- {
- struct video_window *vw = arg;
-
- vw->x = 0;
- vw->y = 0;
- vw->width = pdev->view.x;
- vw->height = pdev->view.y;
- vw->chromakey = 0;
- vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
- (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
- break;
- }
-
- case VIDIOCSWIN:
- {
- struct video_window *vw = arg;
- int fps, snapshot, ret;
-
- fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
- snapshot = vw->flags & PWC_FPS_SNAPSHOT;
- if (fps == 0)
- fps = pdev->vframes;
- if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
- return 0;
- ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
- if (ret)
- return ret;
- break;
- }
-
- /* We don't have overlay support (yet) */
- case VIDIOCGFBUF:
- {
- struct video_buffer *vb = arg;
-
- memset(vb,0,sizeof(*vb));
- break;
- }
-
- /* mmap() functions */
- case VIDIOCGMBUF:
- {
- /* Tell the user program how much memory is needed for a mmap() */
- struct video_mbuf *vm = arg;
- int i;
-
- memset(vm, 0, sizeof(*vm));
- vm->size = default_mbufs * pdev->len_per_image;
- vm->frames = default_mbufs; /* double buffering should be enough for most applications */
- for (i = 0; i < default_mbufs; i++)
- vm->offsets[i] = i * pdev->len_per_image;
- break;
- }
-
- case VIDIOCMCAPTURE:
- {
- /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
- struct video_mmap *vm = arg;
-
- Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
- if (vm->frame < 0 || vm->frame >= default_mbufs)
- return -EINVAL;
-
- /* xawtv is nasty. It probes the available palettes
- by setting a very small image size and trying
- various palettes... The driver doesn't support
- such small images, so I'm working around it.
- */
- if (vm->format)
- {
- switch (vm->format)
- {
- case VIDEO_PALETTE_YUV420P:
- case VIDEO_PALETTE_RAW:
- break;
- default:
- return -EINVAL;
- break;
- }
- }
-
- if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
- (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
- int ret;
-
- Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
- ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
- if (ret)
- return ret;
- } /* ... size mismatch */
-
- /* FIXME: should we lock here? */
- if (pdev->image_used[vm->frame])
- return -EBUSY; /* buffer wasn't available. Bummer */
- pdev->image_used[vm->frame] = 1;
-
- /* Okay, we're done here. In the SYNC call we wait until a
- frame comes available, then expand image into the given
- buffer.
- In contrast to the CPiA cam the Philips cams deliver a
- constant stream, almost like a grabber card. Also,
- we have separate buffers for the rawdata and the image,
- meaning we can nearly always expand into the requested buffer.
- */
- Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n");
- break;
- }
-
- case VIDIOCSYNC:
- {
- /* The doc says: "Whenever a buffer is used it should
- call VIDIOCSYNC to free this frame up and continue."
-
- The only odd thing about this whole procedure is
- that MCAPTURE flags the buffer as "in use", and
- SYNC immediately unmarks it, while it isn't
- after SYNC that you know that the buffer actually
- got filled! So you better not start a CAPTURE in
- the same frame immediately (use double buffering).
- This is not a problem for this cam, since it has
- extra intermediate buffers, but a hardware
- grabber card will then overwrite the buffer
- you're working on.
- */
- int *mbuf = arg;
- int ret;
-
- Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf);
-
- /* bounds check */
- if (*mbuf < 0 || *mbuf >= default_mbufs)
- return -EINVAL;
- /* check if this buffer was requested anyway */
- if (pdev->image_used[*mbuf] == 0)
- return -EINVAL;
-
- /* Add ourselves to the frame wait-queue.
-
- FIXME: needs auditing for safety.
- QUESTION: In what respect? I think that using the
- frameq is safe now.
- */
- add_wait_queue(&pdev->frameq, &wait);
- while (pdev->full_frames == NULL) {
- if (pdev->error_status) {
- remove_wait_queue(&pdev->frameq, &wait);
- set_current_state(TASK_RUNNING);
- return -pdev->error_status;
- }
-
- if (signal_pending(current)) {
- remove_wait_queue(&pdev->frameq, &wait);
- set_current_state(TASK_RUNNING);
- return -ERESTARTSYS;
- }
- schedule();
- set_current_state(TASK_INTERRUPTIBLE);
- }
- remove_wait_queue(&pdev->frameq, &wait);
- set_current_state(TASK_RUNNING);
-
- /* The frame is ready. Expand in the image buffer
- requested by the user. I don't care if you
- mmap() 5 buffers and request data in this order:
- buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
- Grabber hardware may not be so forgiving.
- */
- Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n");
- pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
- /* Decompress, etc */
- ret = pwc_handle_frame(pdev);
- pdev->image_used[*mbuf] = 0;
- if (ret)
- return -EFAULT;
- break;
- }
-
- case VIDIOCGAUDIO:
- {
- struct video_audio *v = arg;
-
- strcpy(v->name, "Microphone");
- v->audio = -1; /* unknown audio minor */
- v->flags = 0;
- v->mode = VIDEO_SOUND_MONO;
- v->volume = 0;
- v->bass = 0;
- v->treble = 0;
- v->balance = 0x8000;
- v->step = 1;
- break;
- }
-
- case VIDIOCSAUDIO:
- {
- /* Dummy: nothing can be set */
- break;
- }
-
- case VIDIOCGUNIT:
- {
- struct video_unit *vu = arg;
-
- vu->video = pdev->vdev->minor & 0x3F;
- vu->audio = -1; /* not known yet */
- vu->vbi = -1;
- vu->radio = -1;
- vu->teletext = -1;
- break;
- }
- default:
- return pwc_ioctl(pdev, cmd, arg);
- } /* ..switch */
- return 0;
-}
-
static int pwc_video_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl);
}
-
static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
{
struct video_device *vdev = file->private_data;
struct pwc_device *pdev;
- unsigned long start = vma->vm_start;
- unsigned long size = vma->vm_end-vma->vm_start;
- unsigned long page, pos;
+ unsigned long start;
+ unsigned long size;
+ unsigned long page, pos = 0;
+ int index;
- Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size);
+ PWC_DEBUG_MEMORY(">> %s\n", __FUNCTION__);
pdev = vdev->priv;
+ size = vma->vm_end - vma->vm_start;
+ start = vma->vm_start;
- vma->vm_flags |= VM_IO;
+ /* Find the idx buffer for this mapping */
+ for (index = 0; index < pwc_mbufs; index++) {
+ pos = pdev->images[index].offset;
+ if ((pos>>PAGE_SHIFT) == vma->vm_pgoff)
+ break;
+ }
+ if (index == MAX_IMAGES)
+ return -EINVAL;
+ if (index == 0) {
+ /*
+ * Special case for v4l1. In v4l1, we map only one big buffer,
+ * but in v4l2 each buffer is mapped
+ */
+ unsigned long total_size;
+ total_size = pwc_mbufs * pdev->len_per_image;
+ if (size != pdev->len_per_image && size != total_size) {
+ PWC_ERROR("Wrong size (%lu) needed to be len_per_image=%d or total_size=%lu\n",
+ size, pdev->len_per_image, total_size);
+ return -EINVAL;
+ }
+ } else if (size > pdev->len_per_image)
+ return -EINVAL;
- pos = (unsigned long)pdev->image_data;
+ vma->vm_flags |= VM_IO; /* from 2.6.9-acX */
+
+ pos += (unsigned long)pdev->image_data;
while (size > 0) {
page = vmalloc_to_pfn((void *)pos);
if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
return -EAGAIN;
-
start += PAGE_SIZE;
pos += PAGE_SIZE;
if (size > PAGE_SIZE)
@@ -1624,7 +1392,6 @@ static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
else
size = 0;
}
-
return 0;
}
@@ -1645,10 +1412,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
int video_nr = -1; /* default: use next available device */
char serial_number[30], *name;
+ vendor_id = le16_to_cpu(udev->descriptor.idVendor);
+ product_id = le16_to_cpu(udev->descriptor.idProduct);
+
/* Check if we can handle this device */
- Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n",
- le16_to_cpu(udev->descriptor.idVendor),
- le16_to_cpu(udev->descriptor.idProduct),
+ PWC_DEBUG_PROBE("probe() called [%04X %04X], if %d\n",
+ vendor_id, product_id,
intf->altsetting->desc.bInterfaceNumber);
/* the interfaces are probed one by one. We are only interested in the
@@ -1658,61 +1427,63 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
if (intf->altsetting->desc.bInterfaceNumber > 0)
return -ENODEV;
- vendor_id = le16_to_cpu(udev->descriptor.idVendor);
- product_id = le16_to_cpu(udev->descriptor.idProduct);
-
if (vendor_id == 0x0471) {
switch (product_id) {
case 0x0302:
- Info("Philips PCA645VC USB webcam detected.\n");
+ PWC_INFO("Philips PCA645VC USB webcam detected.\n");
name = "Philips 645 webcam";
type_id = 645;
break;
case 0x0303:
- Info("Philips PCA646VC USB webcam detected.\n");
+ PWC_INFO("Philips PCA646VC USB webcam detected.\n");
name = "Philips 646 webcam";
type_id = 646;
break;
case 0x0304:
- Info("Askey VC010 type 2 USB webcam detected.\n");
+ PWC_INFO("Askey VC010 type 2 USB webcam detected.\n");
name = "Askey VC010 webcam";
type_id = 646;
break;
case 0x0307:
- Info("Philips PCVC675K (Vesta) USB webcam detected.\n");
+ PWC_INFO("Philips PCVC675K (Vesta) USB webcam detected.\n");
name = "Philips 675 webcam";
type_id = 675;
break;
case 0x0308:
- Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
+ PWC_INFO("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
name = "Philips 680 webcam";
type_id = 680;
break;
case 0x030C:
- Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
+ PWC_INFO("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
name = "Philips 690 webcam";
type_id = 690;
break;
case 0x0310:
- Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
+ PWC_INFO("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
name = "Philips 730 webcam";
type_id = 730;
break;
case 0x0311:
- Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
+ PWC_INFO("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
name = "Philips 740 webcam";
type_id = 740;
break;
case 0x0312:
- Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
+ PWC_INFO("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
name = "Philips 750 webcam";
type_id = 750;
break;
case 0x0313:
- Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
+ PWC_INFO("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
name = "Philips 720K/40 webcam";
type_id = 720;
break;
+ case 0x0329:
+ PWC_INFO("Philips SPC 900NC USB webcam detected.\n");
+ name = "Philips SPC 900NC webcam";
+ type_id = 720;
+ break;
default:
return -ENODEV;
break;
@@ -1721,7 +1492,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
else if (vendor_id == 0x069A) {
switch(product_id) {
case 0x0001:
- Info("Askey VC010 type 1 USB webcam detected.\n");
+ PWC_INFO("Askey VC010 type 1 USB webcam detected.\n");
name = "Askey VC010 webcam";
type_id = 645;
break;
@@ -1733,32 +1504,33 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
else if (vendor_id == 0x046d) {
switch(product_id) {
case 0x08b0:
- Info("Logitech QuickCam Pro 3000 USB webcam detected.\n");
+ PWC_INFO("Logitech QuickCam Pro 3000 USB webcam detected.\n");
name = "Logitech QuickCam Pro 3000";
type_id = 740; /* CCD sensor */
break;
case 0x08b1:
- Info("Logitech QuickCam Notebook Pro USB webcam detected.\n");
+ PWC_INFO("Logitech QuickCam Notebook Pro USB webcam detected.\n");
name = "Logitech QuickCam Notebook Pro";
type_id = 740; /* CCD sensor */
break;
case 0x08b2:
- Info("Logitech QuickCam 4000 Pro USB webcam detected.\n");
+ PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n");
name = "Logitech QuickCam Pro 4000";
type_id = 740; /* CCD sensor */
break;
case 0x08b3:
- Info("Logitech QuickCam Zoom USB webcam detected.\n");
+ PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n");
name = "Logitech QuickCam Zoom";
type_id = 740; /* CCD sensor */
break;
case 0x08B4:
- Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
+ PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
name = "Logitech QuickCam Zoom";
type_id = 740; /* CCD sensor */
+ power_save = 1;
break;
case 0x08b5:
- Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
+ PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
name = "Logitech QuickCam Orbit";
type_id = 740; /* CCD sensor */
features |= FEATURE_MOTOR_PANTILT;
@@ -1766,7 +1538,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
case 0x08b6:
case 0x08b7:
case 0x08b8:
- Info("Logitech QuickCam detected (reserved ID).\n");
+ PWC_INFO("Logitech QuickCam detected (reserved ID).\n");
name = "Logitech QuickCam (res.)";
type_id = 730; /* Assuming CMOS */
break;
@@ -1782,15 +1554,20 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
*/
switch(product_id) {
case 0x9000:
- Info("Samsung MPC-C10 USB webcam detected.\n");
+ PWC_INFO("Samsung MPC-C10 USB webcam detected.\n");
name = "Samsung MPC-C10";
type_id = 675;
break;
case 0x9001:
- Info("Samsung MPC-C30 USB webcam detected.\n");
+ PWC_INFO("Samsung MPC-C30 USB webcam detected.\n");
name = "Samsung MPC-C30";
type_id = 675;
break;
+ case 0x9002:
+ PWC_INFO("Samsung SNC-35E (v3.0) USB webcam detected.\n");
+ name = "Samsung MPC-C30";
+ type_id = 740;
+ break;
default:
return -ENODEV;
break;
@@ -1799,12 +1576,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
else if (vendor_id == 0x041e) {
switch(product_id) {
case 0x400c:
- Info("Creative Labs Webcam 5 detected.\n");
+ PWC_INFO("Creative Labs Webcam 5 detected.\n");
name = "Creative Labs Webcam 5";
type_id = 730;
break;
case 0x4011:
- Info("Creative Labs Webcam Pro Ex detected.\n");
+ PWC_INFO("Creative Labs Webcam Pro Ex detected.\n");
name = "Creative Labs Webcam Pro Ex";
type_id = 740;
break;
@@ -1816,7 +1593,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
else if (vendor_id == 0x04cc) {
switch(product_id) {
case 0x8116:
- Info("Sotec Afina Eye USB webcam detected.\n");
+ PWC_INFO("Sotec Afina Eye USB webcam detected.\n");
name = "Sotec Afina Eye";
type_id = 730;
break;
@@ -1829,7 +1606,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
switch(product_id) {
case 0x8116:
/* This is essentially the same cam as the Sotec Afina Eye */
- Info("AME Co. Afina Eye USB webcam detected.\n");
+ PWC_INFO("AME Co. Afina Eye USB webcam detected.\n");
name = "AME Co. Afina Eye";
type_id = 750;
break;
@@ -1842,12 +1619,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
else if (vendor_id == 0x0d81) {
switch(product_id) {
case 0x1900:
- Info("Visionite VCS-UC300 USB webcam detected.\n");
+ PWC_INFO("Visionite VCS-UC300 USB webcam detected.\n");
name = "Visionite VCS-UC300";
type_id = 740; /* CCD sensor */
break;
case 0x1910:
- Info("Visionite VCS-UM100 USB webcam detected.\n");
+ PWC_INFO("Visionite VCS-UM100 USB webcam detected.\n");
name = "Visionite VCS-UM100";
type_id = 730; /* CMOS sensor */
break;
@@ -1861,15 +1638,15 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
memset(serial_number, 0, 30);
usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
- Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number);
+ PWC_DEBUG_PROBE("Device serial number is %s\n", serial_number);
if (udev->descriptor.bNumConfigurations > 1)
- Info("Warning: more than 1 configuration available.\n");
+ PWC_WARNING("Warning: more than 1 configuration available.\n");
/* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL);
if (pdev == NULL) {
- Err("Oops, could not allocate memory for pwc_device.\n");
+ PWC_ERROR("Oops, could not allocate memory for pwc_device.\n");
return -ENOMEM;
}
pdev->type = type_id;
@@ -1900,17 +1677,18 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->vdev = video_device_alloc();
if (pdev->vdev == 0)
{
- Err("Err, cannot allocate video_device struture. Failing probe.");
+ PWC_ERROR("Err, cannot allocate video_device struture. Failing probe.");
kfree(pdev);
return -ENOMEM;
}
memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
+ pdev->vdev->dev = &(udev->dev);
strcpy(pdev->vdev->name, name);
pdev->vdev->owner = THIS_MODULE;
video_set_drvdata(pdev->vdev, pdev);
pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
- Trace(TRACE_PROBE, "Release: %04x\n", pdev->release);
+ PWC_DEBUG_PROBE("Release: %04x\n", pdev->release);
/* Now search device_hint[] table for a match, so we can hint a node number. */
for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
@@ -1918,10 +1696,10 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
(device_hint[hint].pdev == NULL)) {
/* so far, so good... try serial number */
if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) {
- /* match! */
- video_nr = device_hint[hint].device_node;
- Trace(TRACE_PROBE, "Found hint, will try to register as /dev/video%d\n", video_nr);
- break;
+ /* match! */
+ video_nr = device_hint[hint].device_node;
+ PWC_DEBUG_PROBE("Found hint, will try to register as /dev/video%d\n", video_nr);
+ break;
}
}
}
@@ -1929,21 +1707,27 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->vdev->release = video_device_release;
i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
if (i < 0) {
- Err("Failed to register as video device (%d).\n", i);
+ PWC_ERROR("Failed to register as video device (%d).\n", i);
video_device_release(pdev->vdev); /* Drip... drip... drip... */
kfree(pdev); /* Oops, no memory leaks please */
return -EIO;
}
else {
- Info("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F);
+ PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F);
}
/* occupy slot */
if (hint < MAX_DEV_HINTS)
device_hint[hint].pdev = pdev;
- Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev);
+ PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
usb_set_intfdata (intf, pdev);
+ pwc_create_sysfs_files(pdev->vdev);
+
+ /* Set the leds off */
+ pwc_set_leds(pdev, 0, 0);
+ pwc_camera_power(pdev, 0);
+
return 0;
}
@@ -1957,27 +1741,21 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
pdev = usb_get_intfdata (intf);
usb_set_intfdata (intf, NULL);
if (pdev == NULL) {
- Err("pwc_disconnect() Called without private pointer.\n");
+ PWC_ERROR("pwc_disconnect() Called without private pointer.\n");
goto disconnect_out;
}
if (pdev->udev == NULL) {
- Err("pwc_disconnect() already called for %p\n", pdev);
+ PWC_ERROR("pwc_disconnect() already called for %p\n", pdev);
goto disconnect_out;
}
if (pdev->udev != interface_to_usbdev(intf)) {
- Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
- goto disconnect_out;
- }
-#ifdef PWC_MAGIC
- if (pdev->magic != PWC_MAGIC) {
- Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n");
+ PWC_ERROR("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
goto disconnect_out;
}
-#endif
/* We got unplugged; this is signalled by an EPIPE error code */
if (pdev->vopen) {
- Info("Disconnected while webcam is in use!\n");
+ PWC_INFO("Disconnected while webcam is in use!\n");
pdev->error_status = EPIPE;
}
@@ -1987,7 +1765,8 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
while (pdev->vopen)
schedule();
/* Device is now closed, so we can safely unregister it */
- Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n");
+ PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
+ pwc_remove_sysfs_files(pdev->vdev);
video_unregister_device(pdev->vdev);
/* Free memory (don't set pdev to 0 just yet) */
@@ -2021,58 +1800,64 @@ static int pwc_atoi(const char *s)
* Initialization code & module stuff
*/
-static char size[10];
-static int fps = 0;
-static int fbufs = 0;
-static int mbufs = 0;
-static int trace = -1;
+static char *size;
+static int fps;
+static int fbufs;
+static int mbufs;
static int compression = -1;
static int leds[2] = { -1, -1 };
-static char *dev_hint[MAX_DEV_HINTS] = { };
+static int leds_nargs;
+static char *dev_hint[MAX_DEV_HINTS];
+static int dev_hint_nargs;
+
+module_param(size, charp, 0444);
+module_param(fps, int, 0444);
+module_param(fbufs, int, 0444);
+module_param(mbufs, int, 0444);
+#if CONFIG_PWC_DEBUG
+module_param_named(trace, pwc_trace, int, 0644);
+#endif
+module_param(power_save, int, 0444);
+module_param(compression, int, 0444);
+module_param_array(leds, int, &leds_nargs, 0444);
+module_param_array(dev_hint, charp, &dev_hint_nargs, 0444);
-module_param_string(size, size, sizeof(size), 0);
MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");
-module_param(fps, int, 0000);
MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
-module_param(fbufs, int, 0000);
MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve");
-module_param(mbufs, int, 0000);
MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers");
-module_param(trace, int, 0000);
MODULE_PARM_DESC(trace, "For debugging purposes");
-module_param(power_save, bool, 0000);
MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off");
-module_param(compression, int, 0000);
MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
-module_param_array(leds, int, NULL, 0000);
MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
-module_param_array(dev_hint, charp, NULL, 0000);
MODULE_PARM_DESC(dev_hint, "Device node hints");
MODULE_DESCRIPTION("Philips & OEM USB webcam driver");
MODULE_AUTHOR("Luc Saillard <luc@saillard.org>");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("pwcx");
+MODULE_VERSION( PWC_VERSION );
static int __init usb_pwc_init(void)
{
int i, sz;
char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
- Info("Philips webcam module version " PWC_VERSION " loaded.\n");
- Info("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
- Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
- Info("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
+ PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n");
+ PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
+ PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
+ PWC_INFO("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
if (fps) {
if (fps < 4 || fps > 30) {
- Err("Framerate out of bounds (4-30).\n");
+ PWC_ERROR("Framerate out of bounds (4-30).\n");
return -EINVAL;
}
default_fps = fps;
- Info("Default framerate set to %d.\n", default_fps);
+ PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps);
}
- if (size[0]) {
+ if (size) {
/* string; try matching with array */
for (sz = 0; sz < PSZ_MAX; sz++) {
if (!strcmp(sizenames[sz], size)) { /* Found! */
@@ -2081,41 +1866,42 @@ static int __init usb_pwc_init(void)
}
}
if (sz == PSZ_MAX) {
- Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
+ PWC_ERROR("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
return -EINVAL;
}
- Info("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y);
+ PWC_DEBUG_MODULE("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y);
}
if (mbufs) {
if (mbufs < 1 || mbufs > MAX_IMAGES) {
- Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
+ PWC_ERROR("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
return -EINVAL;
}
- default_mbufs = mbufs;
- Info("Number of image buffers set to %d.\n", default_mbufs);
+ pwc_mbufs = mbufs;
+ PWC_DEBUG_MODULE("Number of image buffers set to %d.\n", pwc_mbufs);
}
if (fbufs) {
if (fbufs < 2 || fbufs > MAX_FRAMES) {
- Err("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
+ PWC_ERROR("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
return -EINVAL;
}
default_fbufs = fbufs;
- Info("Number of frame buffers set to %d.\n", default_fbufs);
+ PWC_DEBUG_MODULE("Number of frame buffers set to %d.\n", default_fbufs);
}
- if (trace >= 0) {
- Info("Trace options: 0x%04x\n", trace);
- pwc_trace = trace;
+#if CONFIG_PWC_DEBUG
+ if (pwc_trace >= 0) {
+ PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
}
+#endif
if (compression >= 0) {
if (compression > 3) {
- Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
+ PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
return -EINVAL;
}
pwc_preferred_compression = compression;
- Info("Preferred compression set to %d.\n", pwc_preferred_compression);
+ PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression);
}
if (power_save)
- Info("Enabling power save on open/close.\n");
+ PWC_DEBUG_MODULE("Enabling power save on open/close.\n");
if (leds[0] >= 0)
led_on = leds[0];
if (leds[1] >= 0)
@@ -2146,14 +1932,14 @@ static int __init usb_pwc_init(void)
dot++;
/* Few sanity checks */
if (*dot != '\0' && dot > colon) {
- Err("Malformed camera hint: the colon must be after the dot.\n");
+ PWC_ERROR("Malformed camera hint: the colon must be after the dot.\n");
return -EINVAL;
}
if (*colon == '\0') {
/* No colon */
if (*dot != '\0') {
- Err("Malformed camera hint: no colon + device node given.\n");
+ PWC_ERROR("Malformed camera hint: no colon + device node given.\n");
return -EINVAL;
}
else {
@@ -2178,28 +1964,27 @@ static int __init usb_pwc_init(void)
device_hint[i].serial_number[k] = '\0';
}
}
-#if PWC_DEBUG
- Debug("device_hint[%d]:\n", i);
- Debug(" type : %d\n", device_hint[i].type);
- Debug(" serial# : %s\n", device_hint[i].serial_number);
- Debug(" node : %d\n", device_hint[i].device_node);
-#endif
+ PWC_TRACE("device_hint[%d]:\n", i);
+ PWC_TRACE(" type : %d\n", device_hint[i].type);
+ PWC_TRACE(" serial# : %s\n", device_hint[i].serial_number);
+ PWC_TRACE(" node : %d\n", device_hint[i].device_node);
}
else
device_hint[i].type = 0; /* not filled */
} /* ..for MAX_DEV_HINTS */
- Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver);
+ PWC_DEBUG_PROBE("Registering driver at address 0x%p.\n", &pwc_driver);
return usb_register(&pwc_driver);
}
static void __exit usb_pwc_exit(void)
{
- Trace(TRACE_MODULE, "Deregistering driver.\n");
+ PWC_DEBUG_MODULE("Deregistering driver.\n");
usb_deregister(&pwc_driver);
- Info("Philips webcam module removed.\n");
+ PWC_INFO("Philips webcam module removed.\n");
}
module_init(usb_pwc_init);
module_exit(usb_pwc_exit);
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc-kiara.c b/drivers/media/video/pwc/pwc-kiara.c
index 4c96037..fec39cc 100644
--- a/drivers/media/video/pwc/pwc-kiara.c
+++ b/drivers/media/video/pwc/pwc-kiara.c
@@ -1,5 +1,5 @@
/* Linux driver for Philips webcam
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
@@ -316,3 +316,576 @@ const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] =
},
};
+
+/*
+ * Rom table for kiara chips
+ *
+ * 32 roms tables (one for each resolution ?)
+ * 2 tables per roms (one for each passes) (Y, and U&V)
+ * 128 bytes per passes
+ */
+
+const unsigned int KiaraRomTable [8][2][16][8] =
+{
+ { /* version 0 */
+ { /* version 0, passes 0 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000001,0x00000001},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000009,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000249,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000249,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x0000124a,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x0000124a,0x00009252,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00009252,0x00009292,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009292,0x00009292,0x00009493,0x000124db},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x0000a493,0x000124db,0x000124db,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x000124db,0x000126dc,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000124db,0x000136e4,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 0, passes 1 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000001,0x00000009,
+ 0x00000009,0x00000009,0x00000009,0x00000001},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000249,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00001252},
+ {0x00000000,0x00000000,0x00000049,0x00001249,
+ 0x0000124a,0x0000124a,0x00001252,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009252,0x00009292,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009292,0x00009292,0x00009292,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00009292,
+ 0x00009492,0x00009493,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009252,0x00009493,
+ 0x000126dc,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000136e4,0x000136e4,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 1 */
+ { /* version 1, passes 0 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000001},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00001252},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009252,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009252,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009292,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00009252,
+ 0x00009492,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x000124db,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000126dc,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 1, passes 1 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000009,
+ 0x00000049,0x00000009,0x00000001,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000000},
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000249,0x00000049,0x0000024a,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x0000024a,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x0000024a,0x00000009},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009252,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009292,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009292,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009292,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x0000924a,0x0000924a,
+ 0x00009492,0x00009493,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 2 */
+ { /* version 2, passes 0 */
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x00009252,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009493,0x00009493,0x0000a49b},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009292,0x00009493,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x000124db,0x000124db,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x00009252,0x000124db,
+ 0x000126dc,0x0001b724,0x0001b725,0x0001b925},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 2, passes 1 */
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00000249,
+ 0x0000124a,0x0000124a,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00009292,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x0000a49b,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00009252,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 3 */
+ { /* version 3, passes 0 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000136e4,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x0001b725,0x0001b925},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x000136e4,0x0001b925,0x00025bb6,0x00024b77},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 3, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00000249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x00009493,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x000126dc,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000136e4,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 4 */
+ { /* version 4, passes 0 */
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000249,0x00000249,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x00009252,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009292,0x00009493,0x00009493,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0001249b,0x000126dc,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00009252,0x00009493,
+ 0x000124db,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009252,0x0000a49b,
+ 0x000124db,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 4, passes 1 */
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000009,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000049,0x00000049,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00000249,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x0000124a,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009252,0x0000124a,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x00009252,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x00009292,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009292,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009493,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000124db,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009252,0x000124db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 5 */
+ { /* version 5, passes 0 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b725,0x000136e4},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001c96e,0x0001b925},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001c924,0x0002496d,0x00025bb6,0x00024b77},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 5, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009252,0x00009252,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000124db,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000124db,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000126dc,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 6 */
+ { /* version 6, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b725,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0002496e},
+ {0x00000000,0x00000000,0x00012492,0x000126db,
+ 0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 6, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x00009252,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009292,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000124db,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000126dc,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 7 */
+ { /* version 7, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x0001b725,0x000124db},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b724,0x0001c96e,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001b925},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b924,0x0001c92d,0x00024b76,0x0002496e},
+ {0x00000000,0x00000000,0x00012492,0x000136db,
+ 0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 7, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x00009492,0x00009292,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000124db,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000136db,
+ 0x0001b724,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000136db,
+ 0x0001b724,0x000126dc,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00009292,0x000136db,
+ 0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00012492,0x0001b6db,
+ 0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ }
+};
+
diff --git a/drivers/media/video/pwc/pwc-kiara.h b/drivers/media/video/pwc/pwc-kiara.h
index 12929ab..0bdb225 100644
--- a/drivers/media/video/pwc/pwc-kiara.h
+++ b/drivers/media/video/pwc/pwc-kiara.h
@@ -1,5 +1,5 @@
/* Linux driver for Philips webcam
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
@@ -27,7 +27,7 @@
#ifndef PWC_KIARA_H
#define PWC_KIARA_H
-#include "pwc-ioctl.h"
+#include <media/pwc-ioctl.h>
struct Kiara_table_entry
{
@@ -37,8 +37,8 @@ struct Kiara_table_entry
unsigned char mode[12]; /* precomputed mode settings for cam */
};
-const extern struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4];
-const extern unsigned int KiaraRomTable[8][2][16][8];
+extern const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4];
+extern const unsigned int KiaraRomTable[8][2][16][8];
#endif
diff --git a/drivers/media/video/pwc/pwc-misc.c b/drivers/media/video/pwc/pwc-misc.c
index 58fe797..589c687 100644
--- a/drivers/media/video/pwc/pwc-misc.c
+++ b/drivers/media/video/pwc/pwc-misc.c
@@ -1,7 +1,7 @@
/* Linux driver for Philips webcam
Various miscellaneous functions and tables.
(C) 1999-2003 Nemosoft Unv.
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
@@ -24,18 +24,17 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/slab.h>
#include "pwc.h"
-struct pwc_coord pwc_image_sizes[PSZ_MAX] =
+const struct pwc_coord pwc_image_sizes[PSZ_MAX] =
{
- { 128, 96, 0 },
- { 160, 120, 0 },
- { 176, 144, 0 },
- { 320, 240, 0 },
- { 352, 288, 0 },
- { 640, 480, 0 },
+ { 128, 96, 0 }, /* sqcif */
+ { 160, 120, 0 }, /* qsif */
+ { 176, 144, 0 }, /* qcif */
+ { 320, 240, 0 }, /* sif */
+ { 352, 288, 0 }, /* cif */
+ { 640, 480, 0 }, /* vga */
};
/* x,y -> PSZ_ */
@@ -52,7 +51,7 @@ int pwc_decode_size(struct pwc_device *pdev, int width, int height)
{
if (width > pdev->abs_max.x || height > pdev->abs_max.y)
{
- Debug("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
+ PWC_DEBUG_SIZE("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
return -1;
}
}
@@ -60,7 +59,7 @@ int pwc_decode_size(struct pwc_device *pdev, int width, int height)
{
if (width > pdev->view_max.x || height > pdev->view_max.y)
{
- Debug("VIDEO_PALETTE_ not RAW: going beyond view_max.\n");
+ PWC_DEBUG_SIZE("VIDEO_PALETTE_not RAW: going beyond view_max.\n");
return -1;
}
}
@@ -81,9 +80,8 @@ int pwc_decode_size(struct pwc_device *pdev, int width, int height)
/* initialize variables depending on type and decompressor*/
void pwc_construct(struct pwc_device *pdev)
{
- switch(pdev->type) {
- case 645:
- case 646:
+ if (DEVICE_USE_CODEC1(pdev->type)) {
+
pdev->view_min.x = 128;
pdev->view_min.y = 96;
pdev->view_max.x = 352;
@@ -95,10 +93,23 @@ void pwc_construct(struct pwc_device *pdev)
pdev->vendpoint = 4;
pdev->frame_header_size = 0;
pdev->frame_trailer_size = 0;
- break;
- case 675:
- case 680:
- case 690:
+
+ } else if (DEVICE_USE_CODEC3(pdev->type)) {
+
+ pdev->view_min.x = 160;
+ pdev->view_min.y = 120;
+ pdev->view_max.x = 640;
+ pdev->view_max.y = 480;
+ pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA;
+ pdev->abs_max.x = 640;
+ pdev->abs_max.y = 480;
+ pdev->vcinterface = 3;
+ pdev->vendpoint = 5;
+ pdev->frame_header_size = TOUCAM_HEADER_SIZE;
+ pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE;
+
+ } else /* if (DEVICE_USE_CODEC2(pdev->type)) */ {
+
pdev->view_min.x = 128;
pdev->view_min.y = 96;
/* Anthill bug #38: PWC always reports max size, even without PWCX */
@@ -111,30 +122,12 @@ void pwc_construct(struct pwc_device *pdev)
pdev->vendpoint = 4;
pdev->frame_header_size = 0;
pdev->frame_trailer_size = 0;
- break;
- case 720:
- case 730:
- case 740:
- case 750:
- pdev->view_min.x = 160;
- pdev->view_min.y = 120;
- pdev->view_max.x = 640;
- pdev->view_max.y = 480;
- pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA;
- pdev->abs_max.x = 640;
- pdev->abs_max.y = 480;
- pdev->vcinterface = 3;
- pdev->vendpoint = 5;
- pdev->frame_header_size = TOUCAM_HEADER_SIZE;
- pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE;
- break;
}
- Debug("type = %d\n",pdev->type);
pdev->vpalette = VIDEO_PALETTE_YUV420P; /* default */
pdev->view_min.size = pdev->view_min.x * pdev->view_min.y;
pdev->view_max.size = pdev->view_max.x * pdev->view_max.y;
/* length of image, in YUV format; always allocate enough memory. */
- pdev->len_per_image = (pdev->abs_max.x * pdev->abs_max.y * 3) / 2;
+ pdev->len_per_image = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2);
}
diff --git a/drivers/media/video/pwc/pwc-timon.c b/drivers/media/video/pwc/pwc-timon.c
index 175250d..be65bdc 100644
--- a/drivers/media/video/pwc/pwc-timon.c
+++ b/drivers/media/video/pwc/pwc-timon.c
@@ -1,5 +1,5 @@
/* Linux driver for Philips webcam
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
@@ -314,3 +314,1133 @@ const struct Timon_table_entry Timon_table[PSZ_MAX][6][4] =
},
};
+/*
+ * 16 versions:
+ * 2 tables (one for Y, and one for U&V)
+ * 16 levels of details per tables
+ * 8 blocs
+ */
+
+const unsigned int TimonRomTable [16][2][16][8] =
+{
+ { /* version 0 */
+ { /* version 0, passes 0 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000001},
+ {0x00000000,0x00000000,0x00000001,0x00000001,
+ 0x00000001,0x00000001,0x00000001,0x00000001},
+ {0x00000000,0x00000000,0x00000001,0x00000001,
+ 0x00000001,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000009,0x00000001,
+ 0x00000009,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000049,0x00000009},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000009,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000249,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000249,0x00000249,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000249,0x0000124a,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009252,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 0, passes 1 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000001,0x00000001,
+ 0x00000001,0x00000001,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000009,0x00000001,
+ 0x00000001,0x00000009,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000001,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000009,
+ 0x00000009,0x00000049,0x00000001,0x00000001},
+ {0x00000000,0x00000000,0x00000049,0x00000009,
+ 0x00000009,0x00000049,0x00000001,0x00000001},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000009,0x00000001},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000009,0x00000001},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000009,0x00000001},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000249,0x00000049,0x00000009},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000249,0x00000049,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000249,0x00000249,0x00000049,0x00000009},
+ {0x00000000,0x00000000,0x00001249,0x00000249,
+ 0x0000124a,0x0000124a,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 1 */
+ { /* version 1, passes 0 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000001},
+ {0x00000000,0x00000000,0x00000001,0x00000001,
+ 0x00000001,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000009,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000249,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00001252},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009252,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009252,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009292,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 1, passes 1 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000001,0x00000001,0x00000000},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000001,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000009,0x00000001,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000001,0x00000001},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000009,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000049,0x00000249,0x00000009,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000249,0x00000249,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x00000049,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00000049,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00000049,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009252,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 2 */
+ { /* version 2, passes 0 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000001},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00001252},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009252,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009252,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009292,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00009252,
+ 0x00009492,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x000124db,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000126dc,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 2, passes 1 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000009,
+ 0x00000049,0x00000009,0x00000001,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000000},
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000249,0x00000049,0x0000024a,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x0000024a,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x0000024a,0x00000009},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009252,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009292,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009292,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009292,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x0000924a,0x0000924a,
+ 0x00009492,0x00009493,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 3 */
+ { /* version 3, passes 0 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000001},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x00000249,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x00009252,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009292,0x00009292,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009292,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00009252,
+ 0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009292,0x0000a49b,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x0000a49b,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x0001b725,0x000136e4},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 3, passes 1 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000001,0x00000000},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x00000049,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x00001252,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009252,0x00009292,0x00000009},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009252,0x00009292,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009252,0x00009292,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009493,0x00009292,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009493,0x00009292,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009493,0x00009493,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009292,0x00009493,0x00009493,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x00009493,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009292,
+ 0x0000a493,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 4 */
+ { /* version 4, passes 0 */
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x00009252,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009493,0x00009493,0x0000a49b},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009292,0x00009493,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x000124db,0x000124db,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x00009252,0x000124db,
+ 0x000126dc,0x0001b724,0x0001b725,0x0001b925},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 4, passes 1 */
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00000249,
+ 0x0000124a,0x0000124a,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00009292,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x0000a49b,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00009252,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 5 */
+ { /* version 5, passes 0 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009292,0x00009292,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x000124db,0x000124db,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0001249b,0x000126dc,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000126dc,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b724,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 5, passes 1 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x00009493,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x00009493,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x00009493,0x000124db,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x00009493,0x000124db,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x000124db,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x000124db,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009252,0x000124db,
+ 0x000126dc,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 6 */
+ { /* version 6, passes 0 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000136e4,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x0001b725,0x0001b925},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x000136e4,0x0001b925,0x00025bb6,0x00024b77},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 6, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00000249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x00009493,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x000126dc,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000136e4,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 7 */
+ { /* version 7, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x0000a49b,0x000124db,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x0001b725,0x0001b925},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b724,0x0001c96e,0x0002496e},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x000136e4,0x0001b925,0x0001c96e,0x0002496e},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x0002496d,0x00025bb6,0x00025bbf},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 7, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x00009493,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x000136e4,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x000136e4,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000124db,0x000136e4,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x000136e4,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00012492,0x000126db,
+ 0x0001b724,0x0001b925,0x0001b725,0x000136e4},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 8 */
+ { /* version 8, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x0001b725,0x0001b925},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+ {0x00000000,0x00000000,0x00009252,0x000124db,
+ 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000126dc,0x0001b925,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x00024b76,0x00024b77},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x000136e4,0x0001b925,0x00024b76,0x00025bbf},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x000136e4,0x0001c92d,0x00024b76,0x00025bbf},
+ {0x00000000,0x00000000,0x00012492,0x000136db,
+ 0x0001b724,0x00024b6d,0x0002ddb6,0x0002efff},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 8, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000126dc,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000136e4,0x0001b724,0x0001b725,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x000136e4,0x0001b925,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x000136e4,0x0001b925,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x0002496d,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 9 */
+ { /* version 9, passes 0 */
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000249,0x00000249,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x00009252,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009292,0x00009493,0x00009493,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0001249b,0x000126dc,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00009252,0x00009493,
+ 0x000124db,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009252,0x0000a49b,
+ 0x000124db,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 9, passes 1 */
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000009,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000049,0x00000049,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00000249,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x0000124a,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009252,0x0000124a,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x00009252,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x00009292,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009292,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009493,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000124db,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009252,0x000124db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 10 */
+ { /* version 10, passes 0 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x00009493,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x000124db,0x000124db,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0001249b,0x000126dc,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000126dc,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009252,0x0000a49b,
+ 0x000124db,0x000136e4,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000126dc,0x0001b925,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x000136e4,0x0002496d,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 10, passes 1 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00000249,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009252,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009493,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x00009493,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x00009493,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x00009492,0x00009493,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009493,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009252,0x000126db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 11 */
+ { /* version 11, passes 0 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b725,0x000136e4},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001c96e,0x0001b925},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001c924,0x0002496d,0x00025bb6,0x00024b77},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 11, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009252,0x00009252,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000124db,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000124db,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000126dc,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 12 */
+ { /* version 12, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b725,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0002496e},
+ {0x00000000,0x00000000,0x00012492,0x000126db,
+ 0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 12, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x00009252,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009292,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000124db,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000126dc,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 13 */
+ { /* version 13, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x0001b725,0x000124db},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b724,0x0001c96e,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001b925},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b924,0x0001c92d,0x00024b76,0x0002496e},
+ {0x00000000,0x00000000,0x00012492,0x000136db,
+ 0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 13, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x00009492,0x00009292,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000124db,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000136db,
+ 0x0001b724,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000136db,
+ 0x0001b724,0x000126dc,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00009292,0x000136db,
+ 0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00012492,0x0001b6db,
+ 0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 14 */
+ { /* version 14, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009292,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x0000a49b,
+ 0x0000a493,0x000124db,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000136e4,0x0001b725,0x000124db},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000126dc,0x0001b724,0x0001b92d,0x000126dc},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b724,0x0001b92d,0x000126dc},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001c92d,0x0001c96e,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0001b925},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0002496e},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b924,0x0002496d,0x00024b76,0x00024b77},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b924,0x00024b6d,0x0002ddb6,0x00025bbf},
+ {0x00000000,0x00000000,0x00012492,0x0001b6db,
+ 0x00024924,0x0002db6d,0x00036db6,0x0002efff},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 14, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009292,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000136e4,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000136e4,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000136e4,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001b724,0x000136e4,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001b724,0x000136e4,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001b724,0x000136e4,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001b724,0x000136e4,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00012492,0x0001b6db,
+ 0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 15 */
+ { /* version 15, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b725,0x000126dc},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x0001b724,0x0001b92d,0x000126dc},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001c96e,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001b925},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b924,0x0002496d,0x00024b76,0x0002496e},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0002496d,0x00025bb6,0x00024b77},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x00024b6d,0x00025bb6,0x00024b77},
+ {0x00000000,0x00000000,0x00012492,0x000136db,
+ 0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf},
+ {0x00000000,0x00000000,0x00012492,0x0001b6db,
+ 0x00024924,0x0002db6d,0x00036db6,0x0002efff},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 15, passes 1 */
+ {0x00000000,0x00000000,0x0000924a,0x0000924a,
+ 0x00009292,0x00009292,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000124db,0x0001b724,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x0001b724,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x0001b724,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00009292,0x000136db,
+ 0x0001b724,0x0001b724,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001c924,0x0001b724,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001c924,0x0001b724,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0001b724,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0001b925,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0001b925,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0001b925,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0001b925,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x00012492,0x000136db,
+ 0x0001c924,0x0001b925,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x00012492,0x0001b6db,
+ 0x00024924,0x0002496d,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ }
+};
diff --git a/drivers/media/video/pwc/pwc-timon.h b/drivers/media/video/pwc/pwc-timon.h
index a86b378..eef9e2c 100644
--- a/drivers/media/video/pwc/pwc-timon.h
+++ b/drivers/media/video/pwc/pwc-timon.h
@@ -1,5 +1,5 @@
/* Linux driver for Philips webcam
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
@@ -42,7 +42,7 @@
#ifndef PWC_TIMON_H
#define PWC_TIMON_H
-#include "pwc-ioctl.h"
+#include <media/pwc-ioctl.h>
struct Timon_table_entry
{
@@ -52,8 +52,8 @@ struct Timon_table_entry
unsigned char mode[13]; /* precomputed mode settings for cam */
};
-const extern struct Timon_table_entry Timon_table[PSZ_MAX][6][4];
-const extern unsigned int TimonRomTable [16][2][16][8];
+extern const struct Timon_table_entry Timon_table[PSZ_MAX][6][4];
+extern const unsigned int TimonRomTable [16][2][16][8];
#endif
diff --git a/drivers/media/video/pwc/pwc-uncompress.c b/drivers/media/video/pwc/pwc-uncompress.c
index b37a89a..5d82028 100644
--- a/drivers/media/video/pwc/pwc-uncompress.c
+++ b/drivers/media/video/pwc/pwc-uncompress.c
@@ -1,7 +1,7 @@
/* Linux driver for Philips webcam
Decompression frontend.
(C) 1999-2003 Nemosoft Unv.
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
@@ -22,6 +22,8 @@
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
+
+ vim: set ts=8:
*/
#include <asm/current.h>
@@ -29,6 +31,8 @@
#include "pwc.h"
#include "pwc-uncompress.h"
+#include "pwc-dec1.h"
+#include "pwc-dec23.h"
int pwc_decompress(struct pwc_device *pdev)
{
@@ -40,107 +44,95 @@ int pwc_decompress(struct pwc_device *pdev)
if (pdev == NULL)
return -EFAULT;
-#if defined(__KERNEL__) && defined(PWC_MAGIC)
- if (pdev->magic != PWC_MAGIC) {
- Err("pwc_decompress(): magic failed.\n");
- return -EFAULT;
- }
-#endif
fbuf = pdev->read_frame;
if (fbuf == NULL)
return -EFAULT;
- image = pdev->image_ptr[pdev->fill_image];
- if (!image)
- return -EFAULT;
+ image = pdev->image_data;
+ image += pdev->images[pdev->fill_image].offset;
yuv = fbuf->data + pdev->frame_header_size; /* Skip header */
/* Raw format; that's easy... */
if (pdev->vpalette == VIDEO_PALETTE_RAW)
{
- memcpy(image, yuv, pdev->frame_size);
+ struct pwc_raw_frame *raw_frame = image;
+ raw_frame->type = cpu_to_le16(pdev->type);
+ raw_frame->vbandlength = cpu_to_le16(pdev->vbandlength);
+ /* cmd_buf is always 4 bytes, but sometimes, only the
+ * first 3 bytes is filled (Nala case). We can
+ * determine this using the type of the webcam */
+ memcpy(raw_frame->cmd, pdev->cmd_buf, 4);
+ memcpy(raw_frame+1, yuv, pdev->frame_size);
return 0;
}
if (pdev->vbandlength == 0) {
- /* Uncompressed mode. We copy the data into the output buffer,
- using the viewport size (which may be larger than the image
- size). Unfortunately we have to do a bit of byte stuffing
- to get the desired output format/size.
+ /* Uncompressed mode.
+ * We copy the data into the output buffer, using the viewport
+ * size (which may be larger than the image size).
+ * Unfortunately we have to do a bit of byte stuffing to get
+ * the desired output format/size.
+ *
+ * We do some byte shuffling here to go from the
+ * native format to YUV420P.
*/
- /*
- * We do some byte shuffling here to go from the
- * native format to YUV420P.
- */
- src = (u16 *)yuv;
- n = pdev->view.x * pdev->view.y;
-
- /* offset in Y plane */
- stride = pdev->view.x * pdev->offset.y + pdev->offset.x;
- dsty = (u16 *)(image + stride);
-
- /* offsets in U/V planes */
- stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2;
- dstu = (u16 *)(image + n + stride);
- dstv = (u16 *)(image + n + n / 4 + stride);
-
- /* increment after each line */
- stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */
-
- for (line = 0; line < pdev->image.y; line++) {
- for (col = 0; col < pdev->image.x; col += 4) {
- *dsty++ = *src++;
- *dsty++ = *src++;
- if (line & 1)
- *dstv++ = *src++;
- else
- *dstu++ = *src++;
- }
- dsty += stride;
+ src = (u16 *)yuv;
+ n = pdev->view.x * pdev->view.y;
+
+ /* offset in Y plane */
+ stride = pdev->view.x * pdev->offset.y + pdev->offset.x;
+ dsty = (u16 *)(image + stride);
+
+ /* offsets in U/V planes */
+ stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2;
+ dstu = (u16 *)(image + n + stride);
+ dstv = (u16 *)(image + n + n / 4 + stride);
+
+ /* increment after each line */
+ stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */
+
+ for (line = 0; line < pdev->image.y; line++) {
+ for (col = 0; col < pdev->image.x; col += 4) {
+ *dsty++ = *src++;
+ *dsty++ = *src++;
if (line & 1)
- dstv += (stride >> 1);
+ *dstv++ = *src++;
else
- dstu += (stride >> 1);
+ *dstu++ = *src++;
}
+ dsty += stride;
+ if (line & 1)
+ dstv += (stride >> 1);
+ else
+ dstu += (stride >> 1);
+ }
+
+ return 0;
}
- else {
- /* Compressed; the decompressor routines will write the data
- in planar format immediately.
- */
- int flags;
-
- flags = PWCX_FLAG_PLANAR;
- if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot)
- {
- printk(KERN_ERR "pwc: Mode Bayer is not supported for now\n");
- flags |= PWCX_FLAG_BAYER;
- return -ENXIO; /* No such device or address: missing decompressor */
- }
-
-#if 0
- switch (pdev->type)
- {
- case 675:
- case 680:
- case 690:
- case 720:
- case 730:
- case 740:
- case 750:
- pwc_dec23_decompress(&pdev->image, &pdev->view,
- &pdev->offset, yuv, image, flags,
- pdev->decompress_data, pdev->vbandlength);
- break;
- case 645:
- case 646:
- /* TODO & FIXME */
- return -ENXIO; /* Missing decompressor */
- break;
- }
-#endif
+
+ /*
+ * Compressed;
+ * the decompressor routines will write the data in planar format
+ * immediately.
+ */
+ if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot) {
+ PWC_ERROR("Mode Bayer is not supported for now\n");
+ /* flags |= PWCX_FLAG_BAYER; */
+ return -ENXIO; /* No such device or address: missing decompressor */
+ }
+
+ if (DEVICE_USE_CODEC1(pdev->type)) {
+
+ /* TODO & FIXME */
+ PWC_ERROR("This chipset is not supported for now\n");
+ return -ENXIO; /* No such device or address: missing decompressor */
+
+ } else {
+ pwc_dec23_decompress(pdev, yuv, image, PWCX_FLAG_PLANAR);
}
return 0;
}
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc-uncompress.h b/drivers/media/video/pwc/pwc-uncompress.h
index f75e1b6..041227f 100644
--- a/drivers/media/video/pwc/pwc-uncompress.h
+++ b/drivers/media/video/pwc/pwc-uncompress.h
@@ -1,5 +1,5 @@
/* (C) 1999-2003 Nemosoft Unv.
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
@@ -32,7 +32,7 @@
#include <linux/config.h>
-#include "pwc-ioctl.h"
+#include <media/pwc-ioctl.h>
/* from pwc-dec.h */
#define PWCX_FLAG_PLANAR 0x0001
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
new file mode 100644
index 0000000..b7eb3ce
--- /dev/null
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -0,0 +1,1202 @@
+/* Linux driver for Philips webcam
+ USB and Video4Linux interface part.
+ (C) 1999-2004 Nemosoft Unv.
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+ NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+ driver and thus may have bugs that are not present in the original version.
+ Please send bug reports and support requests to <luc@saillard.org>.
+ The decompression routines have been implemented by reverse-engineering the
+ Nemosoft binary pwcx module. Caveat emptor.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+
+#include "pwc.h"
+
+static struct v4l2_queryctrl pwc_controls[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 128,
+ .step = 1,
+ .default_value = 64,
+ },
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 64,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = -100,
+ .maximum = 100,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_GAMMA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gamma",
+ .minimum = 0,
+ .maximum = 32,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red Gain",
+ .minimum = 0,
+ .maximum = 256,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue Gain",
+ .minimum = 0,
+ .maximum = 256,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto White Balance",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Shutter Speed (Exposure)",
+ .minimum = 0,
+ .maximum = 256,
+ .step = 1,
+ .default_value = 200,
+ },
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain Enabled",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain Level",
+ .minimum = 0,
+ .maximum = 256,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_SAVE_USER,
+ .type = V4L2_CTRL_TYPE_BUTTON,
+ .name = "Save User Settings",
+ .minimum = 0,
+ .maximum = 0,
+ .step = 0,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_RESTORE_USER,
+ .type = V4L2_CTRL_TYPE_BUTTON,
+ .name = "Restore User Settings",
+ .minimum = 0,
+ .maximum = 0,
+ .step = 0,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_RESTORE_FACTORY,
+ .type = V4L2_CTRL_TYPE_BUTTON,
+ .name = "Restore Factory Settings",
+ .minimum = 0,
+ .maximum = 0,
+ .step = 0,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_COLOUR_MODE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Colour mode",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_AUTOCONTOUR,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto contour",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_CONTOUR,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contour",
+ .minimum = 0,
+ .maximum = 63,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_BACKLIGHT,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Backlight compensation",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_FLICKERLESS,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Flickerless",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_NOISE_REDUCTION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Noise reduction",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+ .default_value = 0,
+ },
+};
+
+
+static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f)
+{
+ memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
+ f->fmt.pix.width = pdev->view.x;
+ f->fmt.pix.height = pdev->view.y;
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ if (pdev->vpalette == VIDEO_PALETTE_YUV420P) {
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
+ f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2;
+ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+ } else {
+ /* vbandlength contains 4 lines ... */
+ f->fmt.pix.bytesperline = pdev->vbandlength/4;
+ f->fmt.pix.sizeimage = pdev->frame_size + sizeof(struct pwc_raw_frame);
+ if (DEVICE_USE_CODEC1(pdev->type))
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC1;
+ else
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC2;
+ }
+ PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() "
+ "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n",
+ f->fmt.pix.width,
+ f->fmt.pix.height,
+ f->fmt.pix.bytesperline,
+ f->fmt.pix.sizeimage,
+ (f->fmt.pix.pixelformat)&255,
+ (f->fmt.pix.pixelformat>>8)&255,
+ (f->fmt.pix.pixelformat>>16)&255,
+ (f->fmt.pix.pixelformat>>24)&255);
+}
+
+/* ioctl(VIDIOC_TRY_FMT) */
+static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
+{
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
+ return -EINVAL;
+ }
+
+ switch (f->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_YUV420:
+ break;
+ case V4L2_PIX_FMT_PWC1:
+ if (DEVICE_USE_CODEC23(pdev->type)) {
+ PWC_DEBUG_IOCTL("codec1 is only supported for old pwc webcam\n");
+ return -EINVAL;
+ }
+ break;
+ case V4L2_PIX_FMT_PWC2:
+ if (DEVICE_USE_CODEC1(pdev->type)) {
+ PWC_DEBUG_IOCTL("codec23 is only supported for new pwc webcam\n");
+ return -EINVAL;
+ }
+ break;
+ default:
+ PWC_DEBUG_IOCTL("Unsupported pixel format\n");
+ return -EINVAL;
+
+ }
+
+ if (f->fmt.pix.width > pdev->view_max.x)
+ f->fmt.pix.width = pdev->view_max.x;
+ else if (f->fmt.pix.width < pdev->view_min.x)
+ f->fmt.pix.width = pdev->view_min.x;
+
+ if (f->fmt.pix.height > pdev->view_max.y)
+ f->fmt.pix.height = pdev->view_max.y;
+ else if (f->fmt.pix.height < pdev->view_min.y)
+ f->fmt.pix.height = pdev->view_min.y;
+
+ return 0;
+}
+
+/* ioctl(VIDIOC_SET_FMT) */
+static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
+{
+ int ret, fps, snapshot, compression, pixelformat;
+
+ ret = pwc_vidioc_try_fmt(pdev, f);
+ if (ret<0)
+ return ret;
+
+ pixelformat = f->fmt.pix.pixelformat;
+ compression = pdev->vcompression;
+ snapshot = 0;
+ fps = pdev->vframes;
+ if (f->fmt.pix.priv) {
+ compression = (f->fmt.pix.priv & PWC_QLT_MASK) >> PWC_QLT_SHIFT;
+ snapshot = !!(f->fmt.pix.priv & PWC_FPS_SNAPSHOT);
+ fps = (f->fmt.pix.priv & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
+ if (fps == 0)
+ fps = pdev->vframes;
+ }
+
+ if (pixelformat == V4L2_PIX_FMT_YUV420)
+ pdev->vpalette = VIDEO_PALETTE_YUV420P;
+ else
+ pdev->vpalette = VIDEO_PALETTE_RAW;
+
+ PWC_DEBUG_IOCTL("Try to change format to: width=%d height=%d fps=%d "
+ "compression=%d snapshot=%d format=%c%c%c%c\n",
+ f->fmt.pix.width, f->fmt.pix.height, fps,
+ compression, snapshot,
+ (pixelformat)&255,
+ (pixelformat>>8)&255,
+ (pixelformat>>16)&255,
+ (pixelformat>>24)&255);
+
+ ret = pwc_try_video_mode(pdev,
+ f->fmt.pix.width,
+ f->fmt.pix.height,
+ fps,
+ compression,
+ snapshot);
+
+ PWC_DEBUG_IOCTL("pwc_try_video_mode(), return=%d\n", ret);
+
+ if (ret)
+ return ret;
+
+ pwc_vidioc_fill_fmt(pdev, f);
+
+ return 0;
+
+}
+
+int pwc_video_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct pwc_device *pdev;
+ DECLARE_WAITQUEUE(wait, current);
+
+ if (vdev == NULL)
+ return -EFAULT;
+ pdev = vdev->priv;
+ if (pdev == NULL)
+ return -EFAULT;
+
+#if CONFIG_PWC_DEBUG
+ if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace)
+ v4l_printk_ioctl(cmd);
+#endif
+
+
+ switch (cmd) {
+ /* Query cabapilities */
+ case VIDIOCGCAP:
+ {
+ struct video_capability *caps = arg;
+
+ strcpy(caps->name, vdev->name);
+ caps->type = VID_TYPE_CAPTURE;
+ caps->channels = 1;
+ caps->audios = 1;
+ caps->minwidth = pdev->view_min.x;
+ caps->minheight = pdev->view_min.y;
+ caps->maxwidth = pdev->view_max.x;
+ caps->maxheight = pdev->view_max.y;
+ break;
+ }
+
+ /* Channel functions (simulate 1 channel) */
+ case VIDIOCGCHAN:
+ {
+ struct video_channel *v = arg;
+
+ if (v->channel != 0)
+ return -EINVAL;
+ v->flags = 0;
+ v->tuners = 0;
+ v->type = VIDEO_TYPE_CAMERA;
+ strcpy(v->name, "Webcam");
+ return 0;
+ }
+
+ case VIDIOCSCHAN:
+ {
+ /* The spec says the argument is an integer, but
+ the bttv driver uses a video_channel arg, which
+ makes sense becasue it also has the norm flag.
+ */
+ struct video_channel *v = arg;
+ if (v->channel != 0)
+ return -EINVAL;
+ return 0;
+ }
+
+
+ /* Picture functions; contrast etc. */
+ case VIDIOCGPICT:
+ {
+ struct video_picture *p = arg;
+ int val;
+
+ val = pwc_get_brightness(pdev);
+ if (val >= 0)
+ p->brightness = (val<<9);
+ else
+ p->brightness = 0xffff;
+ val = pwc_get_contrast(pdev);
+ if (val >= 0)
+ p->contrast = (val<<10);
+ else
+ p->contrast = 0xffff;
+ /* Gamma, Whiteness, what's the difference? :) */
+ val = pwc_get_gamma(pdev);
+ if (val >= 0)
+ p->whiteness = (val<<11);
+ else
+ p->whiteness = 0xffff;
+ if (pwc_get_saturation(pdev, &val)<0)
+ p->colour = 0xffff;
+ else
+ p->colour = 32768 + val * 327;
+ p->depth = 24;
+ p->palette = pdev->vpalette;
+ p->hue = 0xFFFF; /* N/A */
+ break;
+ }
+
+ case VIDIOCSPICT:
+ {
+ struct video_picture *p = arg;
+ /*
+ * FIXME: Suppose we are mid read
+ ANSWER: No problem: the firmware of the camera
+ can handle brightness/contrast/etc
+ changes at _any_ time, and the palette
+ is used exactly once in the uncompress
+ routine.
+ */
+ pwc_set_brightness(pdev, p->brightness);
+ pwc_set_contrast(pdev, p->contrast);
+ pwc_set_gamma(pdev, p->whiteness);
+ pwc_set_saturation(pdev, (p->colour-32768)/327);
+ if (p->palette && p->palette != pdev->vpalette) {
+ switch (p->palette) {
+ case VIDEO_PALETTE_YUV420P:
+ case VIDEO_PALETTE_RAW:
+ pdev->vpalette = p->palette;
+ return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ }
+ break;
+ }
+
+ /* Window/size parameters */
+ case VIDIOCGWIN:
+ {
+ struct video_window *vw = arg;
+
+ vw->x = 0;
+ vw->y = 0;
+ vw->width = pdev->view.x;
+ vw->height = pdev->view.y;
+ vw->chromakey = 0;
+ vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
+ (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
+ break;
+ }
+
+ case VIDIOCSWIN:
+ {
+ struct video_window *vw = arg;
+ int fps, snapshot, ret;
+
+ fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
+ snapshot = vw->flags & PWC_FPS_SNAPSHOT;
+ if (fps == 0)
+ fps = pdev->vframes;
+ if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
+ return 0;
+ ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
+ if (ret)
+ return ret;
+ break;
+ }
+
+ /* We don't have overlay support (yet) */
+ case VIDIOCGFBUF:
+ {
+ struct video_buffer *vb = arg;
+
+ memset(vb,0,sizeof(*vb));
+ break;
+ }
+
+ /* mmap() functions */
+ case VIDIOCGMBUF:
+ {
+ /* Tell the user program how much memory is needed for a mmap() */
+ struct video_mbuf *vm = arg;
+ int i;
+
+ memset(vm, 0, sizeof(*vm));
+ vm->size = pwc_mbufs * pdev->len_per_image;
+ vm->frames = pwc_mbufs; /* double buffering should be enough for most applications */
+ for (i = 0; i < pwc_mbufs; i++)
+ vm->offsets[i] = i * pdev->len_per_image;
+ break;
+ }
+
+ case VIDIOCMCAPTURE:
+ {
+ /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
+ struct video_mmap *vm = arg;
+
+ PWC_DEBUG_READ("VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
+ if (vm->frame < 0 || vm->frame >= pwc_mbufs)
+ return -EINVAL;
+
+ /* xawtv is nasty. It probes the available palettes
+ by setting a very small image size and trying
+ various palettes... The driver doesn't support
+ such small images, so I'm working around it.
+ */
+ if (vm->format)
+ {
+ switch (vm->format)
+ {
+ case VIDEO_PALETTE_YUV420P:
+ case VIDEO_PALETTE_RAW:
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ }
+
+ if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
+ (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
+ int ret;
+
+ PWC_DEBUG_OPEN("VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
+ ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+ if (ret)
+ return ret;
+ } /* ... size mismatch */
+
+ /* FIXME: should we lock here? */
+ if (pdev->image_used[vm->frame])
+ return -EBUSY; /* buffer wasn't available. Bummer */
+ pdev->image_used[vm->frame] = 1;
+
+ /* Okay, we're done here. In the SYNC call we wait until a
+ frame comes available, then expand image into the given
+ buffer.
+ In contrast to the CPiA cam the Philips cams deliver a
+ constant stream, almost like a grabber card. Also,
+ we have separate buffers for the rawdata and the image,
+ meaning we can nearly always expand into the requested buffer.
+ */
+ PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n");
+ break;
+ }
+
+ case VIDIOCSYNC:
+ {
+ /* The doc says: "Whenever a buffer is used it should
+ call VIDIOCSYNC to free this frame up and continue."
+
+ The only odd thing about this whole procedure is
+ that MCAPTURE flags the buffer as "in use", and
+ SYNC immediately unmarks it, while it isn't
+ after SYNC that you know that the buffer actually
+ got filled! So you better not start a CAPTURE in
+ the same frame immediately (use double buffering).
+ This is not a problem for this cam, since it has
+ extra intermediate buffers, but a hardware
+ grabber card will then overwrite the buffer
+ you're working on.
+ */
+ int *mbuf = arg;
+ int ret;
+
+ PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf);
+
+ /* bounds check */
+ if (*mbuf < 0 || *mbuf >= pwc_mbufs)
+ return -EINVAL;
+ /* check if this buffer was requested anyway */
+ if (pdev->image_used[*mbuf] == 0)
+ return -EINVAL;
+
+ /* Add ourselves to the frame wait-queue.
+
+ FIXME: needs auditing for safety.
+ QUESTION: In what respect? I think that using the
+ frameq is safe now.
+ */
+ add_wait_queue(&pdev->frameq, &wait);
+ while (pdev->full_frames == NULL) {
+ /* Check for unplugged/etc. here */
+ if (pdev->error_status) {
+ remove_wait_queue(&pdev->frameq, &wait);
+ set_current_state(TASK_RUNNING);
+ return -pdev->error_status;
+ }
+
+ if (signal_pending(current)) {
+ remove_wait_queue(&pdev->frameq, &wait);
+ set_current_state(TASK_RUNNING);
+ return -ERESTARTSYS;
+ }
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+ remove_wait_queue(&pdev->frameq, &wait);
+ set_current_state(TASK_RUNNING);
+
+ /* The frame is ready. Expand in the image buffer
+ requested by the user. I don't care if you
+ mmap() 5 buffers and request data in this order:
+ buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
+ Grabber hardware may not be so forgiving.
+ */
+ PWC_DEBUG_READ("VIDIOCSYNC: frame ready.\n");
+ pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
+ /* Decompress, etc */
+ ret = pwc_handle_frame(pdev);
+ pdev->image_used[*mbuf] = 0;
+ if (ret)
+ return -EFAULT;
+ break;
+ }
+
+ case VIDIOCGAUDIO:
+ {
+ struct video_audio *v = arg;
+
+ strcpy(v->name, "Microphone");
+ v->audio = -1; /* unknown audio minor */
+ v->flags = 0;
+ v->mode = VIDEO_SOUND_MONO;
+ v->volume = 0;
+ v->bass = 0;
+ v->treble = 0;
+ v->balance = 0x8000;
+ v->step = 1;
+ break;
+ }
+
+ case VIDIOCSAUDIO:
+ {
+ /* Dummy: nothing can be set */
+ break;
+ }
+
+ case VIDIOCGUNIT:
+ {
+ struct video_unit *vu = arg;
+
+ vu->video = pdev->vdev->minor & 0x3F;
+ vu->audio = -1; /* not known yet */
+ vu->vbi = -1;
+ vu->radio = -1;
+ vu->teletext = -1;
+ break;
+ }
+
+ /* V4L2 Layer */
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *cap = arg;
+
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCAP) This application "\
+ "try to use the v4l2 layer\n");
+ strcpy(cap->driver,PWC_NAME);
+ strlcpy(cap->card, vdev->name, sizeof(cap->card));
+ usb_make_path(pdev->udev,cap->bus_info,sizeof(cap->bus_info));
+ cap->version = PWC_VERSION_CODE;
+ cap->capabilities =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
+ return 0;
+ }
+
+ case VIDIOC_ENUMINPUT:
+ {
+ struct v4l2_input *i = arg;
+
+ if ( i->index ) /* Only one INPUT is supported */
+ return -EINVAL;
+
+ memset(i, 0, sizeof(struct v4l2_input));
+ strcpy(i->name, "usb");
+ return 0;
+ }
+
+ case VIDIOC_G_INPUT:
+ {
+ int *i = arg;
+ *i = 0; /* Only one INPUT is supported */
+ return 0;
+ }
+ case VIDIOC_S_INPUT:
+ {
+ int *i = arg;
+
+ if ( *i ) { /* Only one INPUT is supported */
+ PWC_DEBUG_IOCTL("Only one input source is"\
+ " supported with this webcam.\n");
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ /* TODO: */
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *c = arg;
+ int i;
+
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) query id=%d\n", c->id);
+ for (i=0; i<sizeof(pwc_controls)/sizeof(struct v4l2_queryctrl); i++) {
+ if (pwc_controls[i].id == c->id) {
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
+ memcpy(c,&pwc_controls[i],sizeof(struct v4l2_queryctrl));
+ return 0;
+ }
+ }
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n");
+
+ return -EINVAL;
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *c = arg;
+ int ret;
+
+ switch (c->id)
+ {
+ case V4L2_CID_BRIGHTNESS:
+ c->value = pwc_get_brightness(pdev);
+ if (c->value<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_CONTRAST:
+ c->value = pwc_get_contrast(pdev);
+ if (c->value<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_SATURATION:
+ ret = pwc_get_saturation(pdev, &c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_GAMMA:
+ c->value = pwc_get_gamma(pdev);
+ if (c->value<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_RED_BALANCE:
+ ret = pwc_get_red_gain(pdev, &c->value);
+ if (ret<0)
+ return -EINVAL;
+ c->value >>= 8;
+ return 0;
+ case V4L2_CID_BLUE_BALANCE:
+ ret = pwc_get_blue_gain(pdev, &c->value);
+ if (ret<0)
+ return -EINVAL;
+ c->value >>= 8;
+ return 0;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ret = pwc_get_awb(pdev);
+ if (ret<0)
+ return -EINVAL;
+ c->value = (ret == PWC_WB_MANUAL)?0:1;
+ return 0;
+ case V4L2_CID_GAIN:
+ ret = pwc_get_agc(pdev, &c->value);
+ if (ret<0)
+ return -EINVAL;
+ c->value >>= 8;
+ return 0;
+ case V4L2_CID_AUTOGAIN:
+ ret = pwc_get_agc(pdev, &c->value);
+ if (ret<0)
+ return -EINVAL;
+ c->value = (c->value < 0)?1:0;
+ return 0;
+ case V4L2_CID_EXPOSURE:
+ ret = pwc_get_shutter_speed(pdev, &c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_COLOUR_MODE:
+ ret = pwc_get_colour_mode(pdev, &c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_AUTOCONTOUR:
+ ret = pwc_get_contour(pdev, &c->value);
+ if (ret < 0)
+ return -EINVAL;
+ c->value=(c->value == -1?1:0);
+ return 0;
+ case V4L2_CID_PRIVATE_CONTOUR:
+ ret = pwc_get_contour(pdev, &c->value);
+ if (ret < 0)
+ return -EINVAL;
+ c->value >>= 10;
+ return 0;
+ case V4L2_CID_PRIVATE_BACKLIGHT:
+ ret = pwc_get_backlight(pdev, &c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_FLICKERLESS:
+ ret = pwc_get_flicker(pdev, &c->value);
+ if (ret < 0)
+ return -EINVAL;
+ c->value=(c->value?1:0);
+ return 0;
+ case V4L2_CID_PRIVATE_NOISE_REDUCTION:
+ ret = pwc_get_dynamic_noise(pdev, &c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+
+ case V4L2_CID_PRIVATE_SAVE_USER:
+ case V4L2_CID_PRIVATE_RESTORE_USER:
+ case V4L2_CID_PRIVATE_RESTORE_FACTORY:
+ return -EINVAL;
+ }
+ return -EINVAL;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *c = arg;
+ int ret;
+
+ switch (c->id)
+ {
+ case V4L2_CID_BRIGHTNESS:
+ c->value <<= 9;
+ ret = pwc_set_brightness(pdev, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_CONTRAST:
+ c->value <<= 10;
+ ret = pwc_set_contrast(pdev, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_SATURATION:
+ ret = pwc_set_saturation(pdev, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_GAMMA:
+ c->value <<= 11;
+ ret = pwc_set_gamma(pdev, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_RED_BALANCE:
+ c->value <<= 8;
+ ret = pwc_set_red_gain(pdev, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_BLUE_BALANCE:
+ c->value <<= 8;
+ ret = pwc_set_blue_gain(pdev, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ c->value = (c->value == 0)?PWC_WB_MANUAL:PWC_WB_AUTO;
+ ret = pwc_set_awb(pdev, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_EXPOSURE:
+ c->value <<= 8;
+ ret = pwc_set_shutter_speed(pdev, c->value?0:1, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_AUTOGAIN:
+ /* autogain off means nothing without a gain */
+ if (c->value == 0)
+ return 0;
+ ret = pwc_set_agc(pdev, c->value, 0);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_GAIN:
+ c->value <<= 8;
+ ret = pwc_set_agc(pdev, 0, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_SAVE_USER:
+ if (pwc_save_user(pdev))
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_RESTORE_USER:
+ if (pwc_restore_user(pdev))
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_RESTORE_FACTORY:
+ if (pwc_restore_factory(pdev))
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_COLOUR_MODE:
+ ret = pwc_set_colour_mode(pdev, c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_AUTOCONTOUR:
+ c->value=(c->value == 1)?-1:0;
+ ret = pwc_set_contour(pdev, c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_CONTOUR:
+ c->value <<= 10;
+ ret = pwc_set_contour(pdev, c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_BACKLIGHT:
+ ret = pwc_set_backlight(pdev, c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_FLICKERLESS:
+ ret = pwc_set_flicker(pdev, c->value);
+ if (ret < 0)
+ return -EINVAL;
+ case V4L2_CID_PRIVATE_NOISE_REDUCTION:
+ ret = pwc_set_dynamic_noise(pdev, c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+
+ }
+ return -EINVAL;
+ }
+
+ case VIDIOC_ENUM_FMT:
+ {
+ struct v4l2_fmtdesc *f = arg;
+ int index;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ /* We only support two format: the raw format, and YUV */
+ index = f->index;
+ memset(f,0,sizeof(struct v4l2_fmtdesc));
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->index = index;
+ switch(index)
+ {
+ case 0:
+ /* RAW format */
+ f->pixelformat = pdev->type<=646?V4L2_PIX_FMT_PWC1:V4L2_PIX_FMT_PWC2;
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
+ strlcpy(f->description,"Raw Philips Webcam",sizeof(f->description));
+ break;
+ case 1:
+ f->pixelformat = V4L2_PIX_FMT_YUV420;
+ strlcpy(f->description,"4:2:0, planar, Y-Cb-Cr",sizeof(f->description));
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ case VIDIOC_G_FMT:
+ {
+ struct v4l2_format *f = arg;
+
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",pdev->image.x,pdev->image.y);
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ pwc_vidioc_fill_fmt(pdev, f);
+
+ return 0;
+ }
+
+ case VIDIOC_TRY_FMT:
+ return pwc_vidioc_try_fmt(pdev, arg);
+
+ case VIDIOC_S_FMT:
+ return pwc_vidioc_set_fmt(pdev, arg);
+
+ case VIDIOC_G_STD:
+ {
+ v4l2_std_id *std = arg;
+ *std = V4L2_STD_UNKNOWN;
+ return 0;
+ }
+
+ case VIDIOC_S_STD:
+ {
+ v4l2_std_id *std = arg;
+ if (*std != V4L2_STD_UNKNOWN)
+ return -EINVAL;
+ return 0;
+ }
+
+ case VIDIOC_ENUMSTD:
+ {
+ struct v4l2_standard *std = arg;
+ if (std->index != 0)
+ return -EINVAL;
+ std->id = V4L2_STD_UNKNOWN;
+ strncpy(std->name, "webcam", sizeof(std->name));
+ return 0;
+ }
+
+ case VIDIOC_REQBUFS:
+ {
+ struct v4l2_requestbuffers *rb = arg;
+ int nbuffers;
+
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb->count);
+ if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (rb->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+ nbuffers = rb->count;
+ if (nbuffers < 2)
+ nbuffers = 2;
+ else if (nbuffers > pwc_mbufs)
+ nbuffers = pwc_mbufs;
+ /* Force to use our # of buffers */
+ rb->count = pwc_mbufs;
+ return 0;
+ }
+
+ case VIDIOC_QUERYBUF:
+ {
+ struct v4l2_buffer *buf = arg;
+ int index;
+
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf->index);
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
+ return -EINVAL;
+ }
+ if (buf->memory != V4L2_MEMORY_MMAP) {
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n");
+ return -EINVAL;
+ }
+ index = buf->index;
+ if (index < 0 || index >= pwc_mbufs) {
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
+ return -EINVAL;
+ }
+
+ memset(buf, 0, sizeof(struct v4l2_buffer));
+ buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf->index = index;
+ buf->m.offset = index * pdev->len_per_image;
+ if (pdev->vpalette == VIDEO_PALETTE_RAW)
+ buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
+ else
+ buf->bytesused = pdev->view.size;
+ buf->field = V4L2_FIELD_NONE;
+ buf->memory = V4L2_MEMORY_MMAP;
+ //buf->flags = V4L2_BUF_FLAG_MAPPED;
+ buf->length = pdev->len_per_image;
+
+ PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n",buf->index);
+ PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n",buf->m.offset);
+ PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n",buf->bytesused);
+
+ return 0;
+ }
+
+ case VIDIOC_QBUF:
+ {
+ struct v4l2_buffer *buf = arg;
+
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf->index);
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (buf->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+ if (buf->index < 0 || buf->index >= pwc_mbufs)
+ return -EINVAL;
+
+ buf->flags |= V4L2_BUF_FLAG_QUEUED;
+ buf->flags &= ~V4L2_BUF_FLAG_DONE;
+
+ return 0;
+ }
+
+ case VIDIOC_DQBUF:
+ {
+ struct v4l2_buffer *buf = arg;
+ int ret;
+
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
+
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ /* Add ourselves to the frame wait-queue.
+
+ FIXME: needs auditing for safety.
+ QUESTION: In what respect? I think that using the
+ frameq is safe now.
+ */
+ add_wait_queue(&pdev->frameq, &wait);
+ while (pdev->full_frames == NULL) {
+ if (pdev->error_status) {
+ remove_wait_queue(&pdev->frameq, &wait);
+ set_current_state(TASK_RUNNING);
+ return -pdev->error_status;
+ }
+
+ if (signal_pending(current)) {
+ remove_wait_queue(&pdev->frameq, &wait);
+ set_current_state(TASK_RUNNING);
+ return -ERESTARTSYS;
+ }
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+ remove_wait_queue(&pdev->frameq, &wait);
+ set_current_state(TASK_RUNNING);
+
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
+ /* Decompress data in pdev->images[pdev->fill_image] */
+ ret = pwc_handle_frame(pdev);
+ if (ret)
+ return -EFAULT;
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
+
+ buf->index = pdev->fill_image;
+ if (pdev->vpalette == VIDEO_PALETTE_RAW)
+ buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
+ else
+ buf->bytesused = pdev->view.size;
+ buf->flags = V4L2_BUF_FLAG_MAPPED;
+ buf->field = V4L2_FIELD_NONE;
+ do_gettimeofday(&buf->timestamp);
+ buf->sequence = 0;
+ buf->memory = V4L2_MEMORY_MMAP;
+ buf->m.offset = pdev->fill_image * pdev->len_per_image;
+ buf->length = buf->bytesused;
+ pwc_next_image(pdev);
+
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index);
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n",buf->length);
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf->m.offset);
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n",buf->bytesused);
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
+ return 0;
+
+ }
+
+ case VIDIOC_STREAMON:
+ {
+ /* WARNING: pwc_try_video_mode() called pwc_isoc_init */
+ pwc_isoc_init(pdev);
+ return 0;
+ }
+
+ case VIDIOC_STREAMOFF:
+ {
+ pwc_isoc_cleanup(pdev);
+ return 0;
+ }
+
+ default:
+ return pwc_ioctl(pdev, cmd, arg);
+ } /* ..switch */
+ return 0;
+}
+
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
index 1b0ee0c..629f79e 100644
--- a/drivers/media/video/pwc/pwc.h
+++ b/drivers/media/video/pwc/pwc.h
@@ -1,5 +1,5 @@
/* (C) 1999-2003 Nemosoft Unv.
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
@@ -29,51 +29,87 @@
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/spinlock.h>
-#include <linux/videodev.h>
#include <linux/wait.h>
#include <linux/smp_lock.h>
+#include <linux/version.h>
#include <asm/semaphore.h>
#include <asm/errno.h>
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include "pwc-uncompress.h"
-#include "pwc-ioctl.h"
-
-/* Defines and structures for the Philips webcam */
-/* Used for checking memory corruption/pointer validation */
-#define PWC_MAGIC 0x89DC10ABUL
-#undef PWC_MAGIC
+#include <media/pwc-ioctl.h>
/* Turn some debugging options on/off */
-#define PWC_DEBUG 0
+#ifndef CONFIG_PWC_DEBUG
+#define CONFIG_PWC_DEBUG 1
+#endif
+
+/* Version block */
+#define PWC_MAJOR 10
+#define PWC_MINOR 0
+#define PWC_EXTRAMINOR 12
+#define PWC_VERSION_CODE KERNEL_VERSION(PWC_MAJOR,PWC_MINOR,PWC_EXTRAMINOR)
+#define PWC_VERSION "10.0.12"
+#define PWC_NAME "pwc"
+#define PFX PWC_NAME ": "
+
/* Trace certain actions in the driver */
-#define TRACE_MODULE 0x0001
-#define TRACE_PROBE 0x0002
-#define TRACE_OPEN 0x0004
-#define TRACE_READ 0x0008
-#define TRACE_MEMORY 0x0010
-#define TRACE_FLOW 0x0020
-#define TRACE_SIZE 0x0040
-#define TRACE_PWCX 0x0080
-#define TRACE_SEQUENCE 0x1000
-
-#define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A)
-#define Debug(A...) printk(KERN_DEBUG PWC_NAME " " A)
-#define Info(A...) printk(KERN_INFO PWC_NAME " " A)
-#define Err(A...) printk(KERN_ERR PWC_NAME " " A)
+#define PWC_DEBUG_LEVEL_MODULE (1<<0)
+#define PWC_DEBUG_LEVEL_PROBE (1<<1)
+#define PWC_DEBUG_LEVEL_OPEN (1<<2)
+#define PWC_DEBUG_LEVEL_READ (1<<3)
+#define PWC_DEBUG_LEVEL_MEMORY (1<<4)
+#define PWC_DEBUG_LEVEL_FLOW (1<<5)
+#define PWC_DEBUG_LEVEL_SIZE (1<<6)
+#define PWC_DEBUG_LEVEL_IOCTL (1<<7)
+#define PWC_DEBUG_LEVEL_TRACE (1<<8)
+
+#define PWC_DEBUG_MODULE(fmt, args...) PWC_DEBUG(MODULE, fmt, ##args)
+#define PWC_DEBUG_PROBE(fmt, args...) PWC_DEBUG(PROBE, fmt, ##args)
+#define PWC_DEBUG_OPEN(fmt, args...) PWC_DEBUG(OPEN, fmt, ##args)
+#define PWC_DEBUG_READ(fmt, args...) PWC_DEBUG(READ, fmt, ##args)
+#define PWC_DEBUG_MEMORY(fmt, args...) PWC_DEBUG(MEMORY, fmt, ##args)
+#define PWC_DEBUG_FLOW(fmt, args...) PWC_DEBUG(FLOW, fmt, ##args)
+#define PWC_DEBUG_SIZE(fmt, args...) PWC_DEBUG(SIZE, fmt, ##args)
+#define PWC_DEBUG_IOCTL(fmt, args...) PWC_DEBUG(IOCTL, fmt, ##args)
+#define PWC_DEBUG_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args)
+
+
+#if CONFIG_PWC_DEBUG
+
+#define PWC_DEBUG_LEVEL (PWC_DEBUG_LEVEL_MODULE)
+
+#define PWC_DEBUG(level, fmt, args...) do {\
+ if ((PWC_DEBUG_LEVEL_ ##level) & pwc_trace) \
+ printk(KERN_DEBUG PFX fmt, ##args); \
+ } while(0)
+
+#define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args)
+#define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args)
+#define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args)
+#define PWC_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args)
+
+#else /* if ! CONFIG_PWC_DEBUG */
+
+#define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args)
+#define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args)
+#define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args)
+#define PWC_TRACE(fmt, args...) do { } while(0)
+#define PWC_DEBUG(level, fmt, args...) do { } while(0)
+
+#define pwc_trace 0
+#endif
/* Defines for ToUCam cameras */
#define TOUCAM_HEADER_SIZE 8
#define TOUCAM_TRAILER_SIZE 4
#define FEATURE_MOTOR_PANTILT 0x0001
-
-/* Version block */
-#define PWC_MAJOR 9
-#define PWC_MINOR 0
-#define PWC_VERSION "9.0.2-unofficial"
-#define PWC_NAME "pwc"
+#define FEATURE_CODEC1 0x0002
+#define FEATURE_CODEC2 0x0004
/* Turn certain features on/off */
#define PWC_INT_PIPE 0
@@ -95,6 +131,18 @@
/* Absolute maximum number of buffers available for mmap() */
#define MAX_IMAGES 10
+/* Some macros to quickly find the type of a webcam */
+#define DEVICE_USE_CODEC1(x) ((x)<675)
+#define DEVICE_USE_CODEC2(x) ((x)>=675 && (x)<700)
+#define DEVICE_USE_CODEC3(x) ((x)>=700)
+#define DEVICE_USE_CODEC23(x) ((x)>=675)
+
+
+#ifndef V4L2_PIX_FMT_PWC1
+#define V4L2_PIX_FMT_PWC1 v4l2_fourcc('P','W','C','1')
+#define V4L2_PIX_FMT_PWC2 v4l2_fourcc('P','W','C','2')
+#endif
+
/* The following structures were based on cpia.h. Why reinvent the wheel? :-) */
struct pwc_iso_buf
{
@@ -110,17 +158,19 @@ struct pwc_frame_buf
void *data;
volatile int filled; /* number of bytes filled */
struct pwc_frame_buf *next; /* list */
-#if PWC_DEBUG
- int sequence; /* Sequence number */
-#endif
+};
+
+/* additionnal informations used when dealing image between kernel and userland */
+struct pwc_imgbuf
+{
+ unsigned long offset; /* offset of this buffer in the big array of image_data */
+ int vma_use_count; /* count the number of time this memory is mapped */
};
struct pwc_device
{
struct video_device *vdev;
-#ifdef PWC_MAGIC
- int magic;
-#endif
+
/* Pointer to our usb_device */
struct usb_device *udev;
@@ -177,12 +227,8 @@ struct pwc_device
int frame_size;
int frame_total_size; /* including header & trailer */
int drop_frames;
-#if PWC_DEBUG
- int sequence; /* Debugging aid */
-#endif
/* 3: decompression */
- struct pwc_decompressor *decompressor; /* function block with decompression routines */
void *decompress_data; /* private data for decompression engine */
/* 4: image */
@@ -198,7 +244,7 @@ struct pwc_device
struct pwc_coord offset; /* offset within the viewport */
void *image_data; /* total buffer, which is subdivided into ... */
- void *image_ptr[MAX_IMAGES]; /* ...several images... */
+ struct pwc_imgbuf images[MAX_IMAGES];/* ...several images... */
int fill_image; /* ...which are rotated. */
int len_per_image; /* length per image */
int image_read_pos; /* In case we read data in pieces, keep track of were we are in the imagebuffer */
@@ -211,6 +257,7 @@ struct pwc_device
struct pwc_mpt_range angle_range;
int pan_angle; /* in degrees * 100 */
int tilt_angle; /* absolute angle; 0,0 is home position */
+ int snapshot_button_status; /* set to 1 when the user push the button, reset to 0 when this value is read */
/*** Misc. data ***/
wait_queue_head_t frameq; /* When waiting for a frame to finish... */
@@ -219,20 +266,26 @@ struct pwc_device
#endif
};
-
#ifdef __cplusplus
extern "C" {
#endif
-/* Global variable */
+/* Global variables */
+#if CONFIG_PWC_DEBUG
extern int pwc_trace;
+#endif
+extern int pwc_mbufs;
/** functions in pwc-if.c */
int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot);
+int pwc_handle_frame(struct pwc_device *pdev);
+void pwc_next_image(struct pwc_device *pdev);
+int pwc_isoc_init(struct pwc_device *pdev);
+void pwc_isoc_cleanup(struct pwc_device *pdev);
/** Functions in pwc-misc.c */
/* sizes in pixels */
-extern struct pwc_coord pwc_image_sizes[PSZ_MAX];
+extern const struct pwc_coord pwc_image_sizes[PSZ_MAX];
int pwc_decode_size(struct pwc_device *pdev, int width, int height);
void pwc_construct(struct pwc_device *pdev);
@@ -240,6 +293,9 @@ void pwc_construct(struct pwc_device *pdev);
/** Functions in pwc-ctrl.c */
/* Request a certain video mode. Returns < 0 if not possible */
extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot);
+/* Calculate the number of bytes per image (not frame) */
+extern int pwc_mpt_reset(struct pwc_device *pdev, int flags);
+extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt);
/* Various controls; should be obvious. Value 0..65535, or < 0 on error */
extern int pwc_get_brightness(struct pwc_device *pdev);
@@ -248,10 +304,36 @@ extern int pwc_get_contrast(struct pwc_device *pdev);
extern int pwc_set_contrast(struct pwc_device *pdev, int value);
extern int pwc_get_gamma(struct pwc_device *pdev);
extern int pwc_set_gamma(struct pwc_device *pdev, int value);
-extern int pwc_get_saturation(struct pwc_device *pdev);
+extern int pwc_get_saturation(struct pwc_device *pdev, int *value);
extern int pwc_set_saturation(struct pwc_device *pdev, int value);
extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value);
extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor);
+extern int pwc_restore_user(struct pwc_device *pdev);
+extern int pwc_save_user(struct pwc_device *pdev);
+extern int pwc_restore_factory(struct pwc_device *pdev);
+
+/* exported for use by v4l2 controls */
+extern int pwc_get_red_gain(struct pwc_device *pdev, int *value);
+extern int pwc_set_red_gain(struct pwc_device *pdev, int value);
+extern int pwc_get_blue_gain(struct pwc_device *pdev, int *value);
+extern int pwc_set_blue_gain(struct pwc_device *pdev, int value);
+extern int pwc_get_awb(struct pwc_device *pdev);
+extern int pwc_set_awb(struct pwc_device *pdev, int mode);
+extern int pwc_set_agc(struct pwc_device *pdev, int mode, int value);
+extern int pwc_get_agc(struct pwc_device *pdev, int *value);
+extern int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value);
+extern int pwc_get_shutter_speed(struct pwc_device *pdev, int *value);
+
+extern int pwc_set_colour_mode(struct pwc_device *pdev, int colour);
+extern int pwc_get_colour_mode(struct pwc_device *pdev, int *colour);
+extern int pwc_set_contour(struct pwc_device *pdev, int contour);
+extern int pwc_get_contour(struct pwc_device *pdev, int *contour);
+extern int pwc_set_backlight(struct pwc_device *pdev, int backlight);
+extern int pwc_get_backlight(struct pwc_device *pdev, int *backlight);
+extern int pwc_set_flicker(struct pwc_device *pdev, int flicker);
+extern int pwc_get_flicker(struct pwc_device *pdev, int *flicker);
+extern int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise);
+extern int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise);
/* Power down or up the camera; not supported by all models */
extern int pwc_camera_power(struct pwc_device *pdev, int power);
@@ -259,6 +341,9 @@ extern int pwc_camera_power(struct pwc_device *pdev, int power);
/* Private ioctl()s; see pwc-ioctl.h */
extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg);
+/** Functions in pwc-v4l.c */
+extern int pwc_video_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg);
/** pwc-uncompress.c */
/* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */
@@ -270,3 +355,4 @@ extern int pwc_decompress(struct pwc_device *pdev);
#endif
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c
index dd830e0..59a1872 100644
--- a/drivers/media/video/saa5246a.c
+++ b/drivers/media/video/saa5246a.c
@@ -46,6 +46,7 @@
#include <linux/i2c.h>
#include <linux/videotext.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/mutex.h>
#include "saa5246a.h"
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index 531e946..19a8d65 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -56,6 +56,7 @@
#include <linux/i2c.h>
#include <linux/videotext.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/mutex.h>
diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c
index 41d951d..676b997 100644
--- a/drivers/media/video/saa7110.c
+++ b/drivers/media/video/saa7110.c
@@ -43,6 +43,7 @@ MODULE_LICENSE("GPL");
#define I2C_NAME(s) (s)->name
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/video_decoder.h>
static int debug = 0;
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index dceebc0..b59c117 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -72,6 +72,10 @@ struct saa7115_state {
int sat;
enum v4l2_chip_ident ident;
u32 audclk_freq;
+ u32 crystal_freq;
+ u8 ucgc;
+ u8 cgcdiv;
+ u8 apll;
};
/* ----------------------------------------------------------------------- */
@@ -375,10 +379,6 @@ static const unsigned char saa7113_init_auto_input[] = {
};
static const unsigned char saa7115_init_misc[] = {
- 0x38, 0x03, /* audio stuff */
- 0x39, 0x10,
- 0x3a, 0x08,
-
0x81, 0x01, /* reg 0x15,0x16 define blanking window */
0x82, 0x00,
0x83, 0x01, /* I port settings */
@@ -584,6 +584,7 @@ static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
u32 acni;
u32 hz;
u64 f;
+ u8 acc = 0; /* reg 0x3a, audio clock control */
v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
@@ -591,18 +592,34 @@ static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
if (freq < 32000 || freq > 48000)
return -EINVAL;
+ /* The saa7113 has no audio clock */
+ if (state->ident == V4L2_IDENT_SAA7113)
+ return 0;
+
/* hz is the refresh rate times 100 */
hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
/* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
acpf = (25600 * freq) / hz;
/* acni = (256 * freq * 2^23) / crystal_frequency =
(freq * 2^(8+23)) / crystal_frequency =
- (freq << 31) / 32.11 MHz */
+ (freq << 31) / crystal_frequency */
f = freq;
f = f << 31;
- do_div(f, 32110000);
+ do_div(f, state->crystal_freq);
acni = f;
+ if (state->ucgc) {
+ acpf = acpf * state->cgcdiv / 16;
+ acni = acni * state->cgcdiv / 16;
+ acc = 0x80;
+ if (state->cgcdiv == 3)
+ acc |= 0x40;
+ }
+ if (state->apll)
+ acc |= 0x08;
+ saa7115_write(client, 0x38, 0x03);
+ saa7115_write(client, 0x39, 0x10);
+ saa7115_write(client, 0x3a, acc);
saa7115_write(client, 0x30, acpf & 0xff);
saa7115_write(client, 0x31, (acpf >> 8) & 0xff);
saa7115_write(client, 0x32, (acpf >> 16) & 0x03);
@@ -1073,48 +1090,6 @@ static void saa7115_decode_vbi_line(struct i2c_client *client,
/* ============ SAA7115 AUDIO settings (end) ============= */
-static struct v4l2_queryctrl saa7115_qctrl[] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 128,
- .flags = 0,
- }, {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 64,
- .flags = 0,
- }, {
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 64,
- .flags = 0,
- }, {
- .id = V4L2_CID_HUE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hue",
- .minimum = -128,
- .maximum = 127,
- .step = 1,
- .default_value = 0,
- .flags = 0,
- },
-};
-
-/* ----------------------------------------------------------------------- */
-
static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct saa7115_state *state = i2c_get_clientdata(client);
@@ -1158,14 +1133,16 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
case VIDIOC_QUERYCTRL:
{
struct v4l2_queryctrl *qc = arg;
- int i;
- for (i = 0; i < ARRAY_SIZE(saa7115_qctrl); i++)
- if (qc->id && qc->id == saa7115_qctrl[i].id) {
- memcpy(qc, &saa7115_qctrl[i], sizeof(*qc));
- return 0;
- }
- return -EINVAL;
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ return -EINVAL;
+ }
}
case VIDIOC_G_STD:
@@ -1221,34 +1198,6 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
break;
}
- case VIDIOC_G_INPUT:
- *(int *)arg = state->input;
- break;
-
- case VIDIOC_S_INPUT:
- v4l_dbg(1, debug, client, "decoder set input %d\n", *iarg);
- /* inputs from 0-9 are available */
- if (*iarg < 0 || *iarg > 9) {
- return -EINVAL;
- }
-
- if (state->input == *iarg)
- break;
- v4l_dbg(1, debug, client, "now setting %s input\n",
- *iarg >= 6 ? "S-Video" : "Composite");
- state->input = *iarg;
-
- /* select mode */
- saa7115_write(client, 0x02,
- (saa7115_read(client, 0x02) & 0xf0) |
- state->input);
-
- /* bypass chrominance trap for modes 6..9 */
- saa7115_write(client, 0x09,
- (saa7115_read(client, 0x09) & 0x7f) |
- (state->input < 6 ? 0x0 : 0x80));
- break;
-
case VIDIOC_STREAMON:
case VIDIOC_STREAMOFF:
v4l_dbg(1, debug, client, "%s output\n",
@@ -1260,6 +1209,21 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
}
break;
+ case VIDIOC_INT_S_CRYSTAL_FREQ:
+ {
+ struct v4l2_crystal_freq *freq = arg;
+
+ if (freq->freq != SAA7115_FREQ_32_11_MHZ &&
+ freq->freq != SAA7115_FREQ_24_576_MHZ)
+ return -EINVAL;
+ state->crystal_freq = freq->freq;
+ state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
+ state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
+ state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
+ saa7115_set_audio_clock_freq(client, state->audclk_freq);
+ break;
+ }
+
case VIDIOC_INT_DECODE_VBI_LINE:
saa7115_decode_vbi_line(client, arg);
break;
@@ -1401,10 +1365,13 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
v4l_dbg(1, debug, client, "writing init values\n");
/* init to 60hz/48khz */
- if (state->ident == V4L2_IDENT_SAA7113)
+ if (state->ident == V4L2_IDENT_SAA7113) {
+ state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
saa7115_writeregs(client, saa7113_init_auto_input);
- else
+ } else {
+ state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
saa7115_writeregs(client, saa7115_init_auto_input);
+ }
saa7115_writeregs(client, saa7115_init_misc);
saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index c271e2e..ad401bd 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -270,7 +270,7 @@ static const char * const wss_strs[] = {
"letterbox 16:9 top",
"invalid",
"invalid",
- "16:9 full format anamorphic"
+ "16:9 full format anamorphic",
"4:3 full format",
"invalid",
"invalid",
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
index 0e0ba50..de7b9e6 100644
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -39,6 +39,23 @@ enum saa6752hs_videoformat {
SAA6752HS_VF_UNKNOWN,
};
+struct saa6752hs_mpeg_params {
+ /* transport streams */
+ __u16 ts_pid_pmt;
+ __u16 ts_pid_audio;
+ __u16 ts_pid_video;
+ __u16 ts_pid_pcr;
+
+ /* audio */
+ enum v4l2_mpeg_audio_l2_bitrate au_l2_bitrate;
+
+ /* video */
+ enum v4l2_mpeg_video_aspect vi_aspect;
+ enum v4l2_mpeg_video_bitrate_mode vi_bitrate_mode;
+ __u32 vi_bitrate;
+ __u32 vi_bitrate_peak;
+};
+
static const struct v4l2_format v4l2_format_table[] =
{
[SAA6752HS_VF_D1] =
@@ -55,18 +72,19 @@ static const struct v4l2_format v4l2_format_table[] =
struct saa6752hs_state {
struct i2c_client client;
- struct v4l2_mpeg_compression params;
+ struct v4l2_mpeg_compression old_params;
+ struct saa6752hs_mpeg_params params;
enum saa6752hs_videoformat video_format;
v4l2_std_id standard;
};
enum saa6752hs_command {
SAA6752HS_COMMAND_RESET = 0,
- SAA6752HS_COMMAND_STOP = 1,
- SAA6752HS_COMMAND_START = 2,
- SAA6752HS_COMMAND_PAUSE = 3,
- SAA6752HS_COMMAND_RECONFIGURE = 4,
- SAA6752HS_COMMAND_SLEEP = 5,
+ SAA6752HS_COMMAND_STOP = 1,
+ SAA6752HS_COMMAND_START = 2,
+ SAA6752HS_COMMAND_PAUSE = 3,
+ SAA6752HS_COMMAND_RECONFIGURE = 4,
+ SAA6752HS_COMMAND_SLEEP = 5,
SAA6752HS_COMMAND_RECONFIGURE_FORCE = 6,
SAA6752HS_COMMAND_MAX
@@ -129,7 +147,22 @@ static u8 PMT[] = {
0x00, 0x00, 0x00, 0x00 /* CRC32 */
};
-static struct v4l2_mpeg_compression param_defaults =
+static struct saa6752hs_mpeg_params param_defaults =
+{
+ .ts_pid_pmt = 16,
+ .ts_pid_video = 260,
+ .ts_pid_audio = 256,
+ .ts_pid_pcr = 259,
+
+ .vi_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
+ .vi_bitrate = 4000,
+ .vi_bitrate_peak = 6000,
+ .vi_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+
+ .au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_256K,
+};
+
+static struct v4l2_mpeg_compression old_param_defaults =
{
.st_type = V4L2_MPEG_TS_2,
.st_bitrate = {
@@ -228,45 +261,57 @@ static int saa6752hs_chip_command(struct i2c_client* client,
static int saa6752hs_set_bitrate(struct i2c_client* client,
- struct v4l2_mpeg_compression* params)
+ struct saa6752hs_mpeg_params* params)
{
u8 buf[3];
+ int tot_bitrate;
/* set the bitrate mode */
buf[0] = 0x71;
- buf[1] = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ? 0 : 1;
+ buf[1] = (params->vi_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) ? 0 : 1;
i2c_master_send(client, buf, 2);
/* set the video bitrate */
- if (params->vi_bitrate.mode == V4L2_BITRATE_VBR) {
+ if (params->vi_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
/* set the target bitrate */
buf[0] = 0x80;
- buf[1] = params->vi_bitrate.target >> 8;
- buf[2] = params->vi_bitrate.target & 0xff;
+ buf[1] = params->vi_bitrate >> 8;
+ buf[2] = params->vi_bitrate & 0xff;
i2c_master_send(client, buf, 3);
/* set the max bitrate */
buf[0] = 0x81;
- buf[1] = params->vi_bitrate.max >> 8;
- buf[2] = params->vi_bitrate.max & 0xff;
+ buf[1] = params->vi_bitrate_peak >> 8;
+ buf[2] = params->vi_bitrate_peak & 0xff;
i2c_master_send(client, buf, 3);
+ tot_bitrate = params->vi_bitrate_peak;
} else {
/* set the target bitrate (no max bitrate for CBR) */
buf[0] = 0x81;
- buf[1] = params->vi_bitrate.target >> 8;
- buf[2] = params->vi_bitrate.target & 0xff;
+ buf[1] = params->vi_bitrate >> 8;
+ buf[2] = params->vi_bitrate & 0xff;
i2c_master_send(client, buf, 3);
+ tot_bitrate = params->vi_bitrate;
}
/* set the audio bitrate */
buf[0] = 0x94;
- buf[1] = (256 == params->au_bitrate.target) ? 0 : 1;
+ buf[1] = (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 0 : 1;
i2c_master_send(client, buf, 2);
+ tot_bitrate += (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 256 : 384;
+
+ /* Note: the total max bitrate is determined by adding the video and audio
+ bitrates together and also adding an extra 768kbit/s to stay on the
+ safe side. If more control should be required, then an extra MPEG control
+ should be added. */
+ tot_bitrate += 768;
+ if (tot_bitrate > MPEG_TOTAL_TARGET_BITRATE_MAX)
+ tot_bitrate = MPEG_TOTAL_TARGET_BITRATE_MAX;
/* set the total bitrate */
buf[0] = 0xb1;
- buf[1] = params->st_bitrate.target >> 8;
- buf[2] = params->st_bitrate.target & 0xff;
+ buf[1] = tot_bitrate >> 8;
+ buf[2] = tot_bitrate & 0xff;
i2c_master_send(client, buf, 3);
return 0;
@@ -318,50 +363,188 @@ static void saa6752hs_set_subsampling(struct i2c_client* client,
}
-static void saa6752hs_set_params(struct i2c_client* client,
+static void saa6752hs_old_set_params(struct i2c_client* client,
struct v4l2_mpeg_compression* params)
{
struct saa6752hs_state *h = i2c_get_clientdata(client);
/* check PIDs */
- if (params->ts_pid_pmt <= MPEG_PID_MAX)
+ if (params->ts_pid_pmt <= MPEG_PID_MAX) {
+ h->old_params.ts_pid_pmt = params->ts_pid_pmt;
h->params.ts_pid_pmt = params->ts_pid_pmt;
- if (params->ts_pid_pcr <= MPEG_PID_MAX)
+ }
+ if (params->ts_pid_pcr <= MPEG_PID_MAX) {
+ h->old_params.ts_pid_pcr = params->ts_pid_pcr;
h->params.ts_pid_pcr = params->ts_pid_pcr;
- if (params->ts_pid_video <= MPEG_PID_MAX)
+ }
+ if (params->ts_pid_video <= MPEG_PID_MAX) {
+ h->old_params.ts_pid_video = params->ts_pid_video;
h->params.ts_pid_video = params->ts_pid_video;
- if (params->ts_pid_audio <= MPEG_PID_MAX)
+ }
+ if (params->ts_pid_audio <= MPEG_PID_MAX) {
+ h->old_params.ts_pid_audio = params->ts_pid_audio;
h->params.ts_pid_audio = params->ts_pid_audio;
+ }
/* check bitrate parameters */
if ((params->vi_bitrate.mode == V4L2_BITRATE_CBR) ||
- (params->vi_bitrate.mode == V4L2_BITRATE_VBR))
- h->params.vi_bitrate.mode = params->vi_bitrate.mode;
+ (params->vi_bitrate.mode == V4L2_BITRATE_VBR)) {
+ h->old_params.vi_bitrate.mode = params->vi_bitrate.mode;
+ h->params.vi_bitrate_mode = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ?
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR : V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+ }
if (params->vi_bitrate.mode != V4L2_BITRATE_NONE)
- h->params.st_bitrate.target = params->st_bitrate.target;
+ h->old_params.st_bitrate.target = params->st_bitrate.target;
if (params->vi_bitrate.mode != V4L2_BITRATE_NONE)
- h->params.vi_bitrate.target = params->vi_bitrate.target;
+ h->old_params.vi_bitrate.target = params->vi_bitrate.target;
if (params->vi_bitrate.mode == V4L2_BITRATE_VBR)
- h->params.vi_bitrate.max = params->vi_bitrate.max;
+ h->old_params.vi_bitrate.max = params->vi_bitrate.max;
if (params->au_bitrate.mode != V4L2_BITRATE_NONE)
- h->params.au_bitrate.target = params->au_bitrate.target;
+ h->old_params.au_bitrate.target = params->au_bitrate.target;
/* aspect ratio */
if (params->vi_aspect_ratio == V4L2_MPEG_ASPECT_4_3 ||
- params->vi_aspect_ratio == V4L2_MPEG_ASPECT_16_9)
- h->params.vi_aspect_ratio = params->vi_aspect_ratio;
+ params->vi_aspect_ratio == V4L2_MPEG_ASPECT_16_9) {
+ h->old_params.vi_aspect_ratio = params->vi_aspect_ratio;
+ if (params->vi_aspect_ratio == V4L2_MPEG_ASPECT_4_3)
+ h->params.vi_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3;
+ else
+ h->params.vi_aspect = V4L2_MPEG_VIDEO_ASPECT_16x9;
+ }
/* range checks */
- if (h->params.st_bitrate.target > MPEG_TOTAL_TARGET_BITRATE_MAX)
- h->params.st_bitrate.target = MPEG_TOTAL_TARGET_BITRATE_MAX;
- if (h->params.vi_bitrate.target > MPEG_VIDEO_TARGET_BITRATE_MAX)
- h->params.vi_bitrate.target = MPEG_VIDEO_TARGET_BITRATE_MAX;
- if (h->params.vi_bitrate.max > MPEG_VIDEO_MAX_BITRATE_MAX)
- h->params.vi_bitrate.max = MPEG_VIDEO_MAX_BITRATE_MAX;
- if (h->params.au_bitrate.target <= 256)
- h->params.au_bitrate.target = 256;
+ if (h->old_params.st_bitrate.target > MPEG_TOTAL_TARGET_BITRATE_MAX)
+ h->old_params.st_bitrate.target = MPEG_TOTAL_TARGET_BITRATE_MAX;
+ if (h->old_params.vi_bitrate.target > MPEG_VIDEO_TARGET_BITRATE_MAX)
+ h->old_params.vi_bitrate.target = MPEG_VIDEO_TARGET_BITRATE_MAX;
+ if (h->old_params.vi_bitrate.max > MPEG_VIDEO_MAX_BITRATE_MAX)
+ h->old_params.vi_bitrate.max = MPEG_VIDEO_MAX_BITRATE_MAX;
+ h->params.vi_bitrate = params->vi_bitrate.target;
+ h->params.vi_bitrate_peak = params->vi_bitrate.max;
+ if (h->old_params.au_bitrate.target <= 256) {
+ h->old_params.au_bitrate.target = 256;
+ h->params.au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
+ }
+ else {
+ h->old_params.au_bitrate.target = 384;
+ h->params.au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
+ }
+}
+
+static int handle_ctrl(struct saa6752hs_mpeg_params *params,
+ struct v4l2_ext_control *ctrl, int cmd)
+{
+ int old = 0, new;
+ int set = cmd == VIDIOC_S_EXT_CTRLS;
+
+ new = ctrl->value;
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ old = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
+ if (set && new != old)
+ return -ERANGE;
+ new = old;
+ break;
+ case V4L2_CID_MPEG_STREAM_PID_PMT:
+ old = params->ts_pid_pmt;
+ if (set && new > MPEG_PID_MAX)
+ return -ERANGE;
+ if (new > MPEG_PID_MAX)
+ new = MPEG_PID_MAX;
+ params->ts_pid_pmt = new;
+ break;
+ case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+ old = params->ts_pid_audio;
+ if (set && new > MPEG_PID_MAX)
+ return -ERANGE;
+ if (new > MPEG_PID_MAX)
+ new = MPEG_PID_MAX;
+ params->ts_pid_audio = new;
+ break;
+ case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+ old = params->ts_pid_video;
+ if (set && new > MPEG_PID_MAX)
+ return -ERANGE;
+ if (new > MPEG_PID_MAX)
+ new = MPEG_PID_MAX;
+ params->ts_pid_video = new;
+ break;
+ case V4L2_CID_MPEG_STREAM_PID_PCR:
+ old = params->ts_pid_pcr;
+ if (set && new > MPEG_PID_MAX)
+ return -ERANGE;
+ if (new > MPEG_PID_MAX)
+ new = MPEG_PID_MAX;
+ params->ts_pid_pcr = new;
+ break;
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ old = V4L2_MPEG_AUDIO_ENCODING_LAYER_2;
+ if (set && new != old)
+ return -ERANGE;
+ new = old;
+ break;
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ old = params->au_l2_bitrate;
+ if (set && new != V4L2_MPEG_AUDIO_L2_BITRATE_256K &&
+ new != V4L2_MPEG_AUDIO_L2_BITRATE_384K)
+ return -ERANGE;
+ if (new <= V4L2_MPEG_AUDIO_L2_BITRATE_256K)
+ new = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
+ else
+ new = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
+ params->au_l2_bitrate = new;
+ break;
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
+ if (set && new != old)
+ return -ERANGE;
+ new = old;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ old = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+ if (set && new != old)
+ return -ERANGE;
+ new = old;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ old = params->vi_aspect;
+ if (set && new != V4L2_MPEG_VIDEO_ASPECT_16x9 &&
+ new != V4L2_MPEG_VIDEO_ASPECT_4x3)
+ return -ERANGE;
+ if (new != V4L2_MPEG_VIDEO_ASPECT_16x9)
+ new = V4L2_MPEG_VIDEO_ASPECT_4x3;
+ params->vi_aspect = new;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ old = params->vi_bitrate * 1000;
+ new = 1000 * (new / 1000);
+ if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+ return -ERANGE;
+ if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+ new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
+ params->vi_bitrate = new / 1000;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ old = params->vi_bitrate_peak * 1000;
+ new = 1000 * (new / 1000);
+ if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+ return -ERANGE;
+ if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+ new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
+ params->vi_bitrate_peak = new / 1000;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ old = params->vi_bitrate_mode;
+ params->vi_bitrate_mode = new;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (cmd == VIDIOC_G_EXT_CTRLS)
+ ctrl->value = old;
else
- h->params.au_bitrate.target = 384;
+ ctrl->value = new;
+ return 0;
}
static int saa6752hs_init(struct i2c_client* client)
@@ -395,22 +578,22 @@ static int saa6752hs_init(struct i2c_client* client)
buf[2] = 0x0D;
i2c_master_send(client,buf,3);
- /* Set minimum Q-scale {4} */
+ /* Set minimum Q-scale {4} */
buf[0] = 0x82;
buf[1] = 0x04;
i2c_master_send(client,buf,2);
- /* Set maximum Q-scale {12} */
+ /* Set maximum Q-scale {12} */
buf[0] = 0x83;
buf[1] = 0x0C;
i2c_master_send(client,buf,2);
- /* Set Output Protocol */
+ /* Set Output Protocol */
buf[0] = 0xD0;
buf[1] = 0x81;
i2c_master_send(client,buf,2);
- /* Set video output stream format {TS} */
+ /* Set video output stream format {TS} */
buf[0] = 0xB0;
buf[1] = 0x05;
i2c_master_send(client,buf,2);
@@ -441,7 +624,7 @@ static int saa6752hs_init(struct i2c_client* client)
localPMT[sizeof(PMT) - 2] = (crc >> 8) & 0xFF;
localPMT[sizeof(PMT) - 1] = crc & 0xFF;
- /* Set Audio PID */
+ /* Set Audio PID */
buf[0] = 0xC1;
buf[1] = (h->params.ts_pid_audio >> 8) & 0xFF;
buf[2] = h->params.ts_pid_audio & 0xFF;
@@ -489,11 +672,11 @@ static int saa6752hs_init(struct i2c_client* client)
buf[3] = 0x82;
buf[4] = 0xB0;
buf[5] = buf2[0];
- switch(h->params.vi_aspect_ratio) {
- case V4L2_MPEG_ASPECT_16_9:
+ switch(h->params.vi_aspect) {
+ case V4L2_MPEG_VIDEO_ASPECT_16x9:
buf[6] = buf2[1] | 0x40;
break;
- case V4L2_MPEG_ASPECT_4_3:
+ case V4L2_MPEG_VIDEO_ASPECT_4x3:
default:
buf[6] = buf2[1] & 0xBF;
break;
@@ -515,6 +698,7 @@ static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
return -ENOMEM;
h->client = client_template;
h->params = param_defaults;
+ h->old_params = old_param_defaults;
h->client.adapter = adap;
h->client.addr = addr;
@@ -550,20 +734,45 @@ static int
saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct saa6752hs_state *h = i2c_get_clientdata(client);
- struct v4l2_mpeg_compression *params = arg;
+ struct v4l2_ext_controls *ctrls = arg;
+ struct v4l2_mpeg_compression *old_params = arg;
+ struct saa6752hs_mpeg_params params;
int err = 0;
+ int i;
switch (cmd) {
case VIDIOC_S_MPEGCOMP:
- if (NULL == params) {
+ if (NULL == old_params) {
/* apply settings and start encoder */
saa6752hs_init(client);
break;
}
- saa6752hs_set_params(client, params);
+ saa6752hs_old_set_params(client, old_params);
/* fall through */
case VIDIOC_G_MPEGCOMP:
- *params = h->params;
+ *old_params = h->old_params;
+ break;
+ case VIDIOC_S_EXT_CTRLS:
+ if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ if (ctrls->count == 0) {
+ /* apply settings and start encoder */
+ saa6752hs_init(client);
+ break;
+ }
+ /* fall through */
+ case VIDIOC_TRY_EXT_CTRLS:
+ case VIDIOC_G_EXT_CTRLS:
+ if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ params = h->params;
+ for (i = 0; i < ctrls->count; i++) {
+ if ((err = handle_ctrl(&params, ctrls->controls + i, cmd))) {
+ ctrls->error_idx = i;
+ return err;
+ }
+ }
+ h->params = params;
break;
case VIDIOC_G_FMT:
{
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index bb3e0ba..d77e6a8 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -818,7 +818,7 @@ static int snd_saa7134_capsrc_put(struct snd_kcontrol * kcontrol,
break;
}
- /* output xbar always main channel */
+ /* output xbar always main channel */
saa_dsp_writel(dev, SAA7133_DIGITAL_OUTPUT_SEL1, 0xbbbb10);
if (left || right) { // We've got data, turn the input on
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 86eae35..927413a 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -2160,7 +2160,7 @@ struct saa7134_board saa7134_boards[] = {
.radio = {
.name = name_radio,
.amux = LINE2,
- },
+ },
},
[SAA7134_BOARD_GOTVIEW_7135] = {
/* Mike Baikov <mike@baikov.com> */
@@ -2842,6 +2842,55 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x000000, /* GPIO21=Low for FM radio antenna */
},
},
+ [SAA7134_BOARD_FLYVIDEO3000_NTSC] = {
+ /* "Zac Bowling" <zac@zacbowling.com> */
+ .name = "LifeView FlyVIDEO3000 (NTSC)",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
+ .gpiomask = 0xe000,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x8000,
+ .tv = 1,
+ },{
+ .name = name_tv_mono,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x0000,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ },{
+ .name = name_comp2,
+ .vmux = 3,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ .gpio = 0x2000,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = TV,
+ .gpio = 0x8000,
+ },
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -2901,6 +2950,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x5169,
+ .subdevice = 0x0138,
+ .driver_data = SAA7134_BOARD_FLYVIDEO3000_NTSC,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
.subvendor = 0x5168,
.subdevice = 0x0138,
.driver_data = SAA7134_BOARD_FLYVIDEO3000,
@@ -3459,6 +3514,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
switch (dev->board) {
case SAA7134_BOARD_FLYVIDEO2000:
case SAA7134_BOARD_FLYVIDEO3000:
+ case SAA7134_BOARD_FLYVIDEO3000_NTSC:
dev->has_remote = SAA7134_REMOTE_GPIO;
board_flyvideo(dev);
break;
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 222a36c..279828b 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -132,9 +132,8 @@ static int mt352_aver777_init(struct dvb_frontend* fe)
return 0;
}
-static int mt352_pinnacle_pll_set(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params,
- u8* pllbuf)
+static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* params)
{
u8 off[] = { 0x00, 0xf1};
u8 on[] = { 0x00, 0x71};
@@ -147,30 +146,31 @@ static int mt352_pinnacle_pll_set(struct dvb_frontend* fe,
f.tuner = 0;
f.type = V4L2_TUNER_DIGITAL_TV;
f.frequency = params->frequency / 1000 * 16 / 1000;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &msg, 1);
saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,&f);
msg.buf = on;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &msg, 1);
pinnacle_antenna_pwr(dev, antenna_pwr);
/* mt352 setup */
- mt352_pinnacle_init(fe);
- pllbuf[0] = 0xc2;
- pllbuf[1] = 0x00;
- pllbuf[2] = 0x00;
- pllbuf[3] = 0x80;
- pllbuf[4] = 0x00;
- return 0;
+ return mt352_pinnacle_init(fe);
}
-static int mt352_aver777_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8* pllbuf)
+static int mt352_aver777_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
{
- pllbuf[0] = 0xc2;
+ if (buf_len < 5)
+ return -EINVAL;
+
+ pllbuf[0] = 0x61;
dvb_pll_configure(&dvb_pll_philips_td1316, pllbuf+1,
params->frequency,
params->u.ofdm.bandwidth);
- return 0;
+ return 5;
}
static struct mt352_config pinnacle_300i = {
@@ -179,13 +179,11 @@ static struct mt352_config pinnacle_300i = {
.if2 = 36150,
.no_tuner = 1,
.demod_init = mt352_pinnacle_init,
- .pll_set = mt352_pinnacle_pll_set,
};
static struct mt352_config avermedia_777 = {
.demod_address = 0xf,
.demod_init = mt352_aver777_init,
- .pll_set = mt352_aver777_pll_set,
};
#endif
@@ -268,6 +266,8 @@ static int philips_tda6651_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_
tuner_buf[2] = 0xca;
tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
msleep(1);
@@ -281,6 +281,8 @@ static int philips_tda6651_pll_init(u8 addr, struct dvb_frontend *fe)
struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
/* setup PLL configuration */
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
msleep(1);
@@ -290,12 +292,12 @@ static int philips_tda6651_pll_init(u8 addr, struct dvb_frontend *fe)
/* ------------------------------------------------------------------ */
-static int philips_tu1216_pll_60_init(struct dvb_frontend *fe)
+static int philips_tu1216_tuner_60_init(struct dvb_frontend *fe)
{
return philips_tda6651_pll_init(0x60, fe);
}
-static int philips_tu1216_pll_60_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tu1216_tuner_60_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
return philips_tda6651_pll_set(0x60, fe, params);
}
@@ -315,20 +317,17 @@ static struct tda1004x_config philips_tu1216_60_config = {
.xtal_freq = TDA10046_XTAL_4M,
.agc_config = TDA10046_AGC_DEFAULT,
.if_freq = TDA10046_FREQ_3617,
- .pll_init = philips_tu1216_pll_60_init,
- .pll_set = philips_tu1216_pll_60_set,
- .pll_sleep = NULL,
.request_firmware = philips_tu1216_request_firmware,
};
/* ------------------------------------------------------------------ */
-static int philips_tu1216_pll_61_init(struct dvb_frontend *fe)
+static int philips_tu1216_tuner_61_init(struct dvb_frontend *fe)
{
return philips_tda6651_pll_init(0x61, fe);
}
-static int philips_tu1216_pll_61_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tu1216_tuner_61_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
return philips_tda6651_pll_set(0x61, fe, params);
}
@@ -341,21 +340,20 @@ static struct tda1004x_config philips_tu1216_61_config = {
.xtal_freq = TDA10046_XTAL_4M,
.agc_config = TDA10046_AGC_DEFAULT,
.if_freq = TDA10046_FREQ_3617,
- .pll_init = philips_tu1216_pll_61_init,
- .pll_set = philips_tu1216_pll_61_set,
- .pll_sleep = NULL,
.request_firmware = philips_tu1216_request_firmware,
};
/* ------------------------------------------------------------------ */
-static int philips_europa_pll_init(struct dvb_frontend *fe)
+static int philips_europa_tuner_init(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab };
struct i2c_msg init_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) };
/* setup PLL configuration */
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
return -EIO;
msleep(1);
@@ -365,18 +363,20 @@ static int philips_europa_pll_init(struct dvb_frontend *fe)
init_msg.len = 0x02;
msg[0] = 0x00;
msg[1] = 0x40;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
return -EIO;
return 0;
}
-static int philips_td1316_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_td1316_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
return philips_tda6651_pll_set(0x61, fe, params);
}
-static void philips_europa_analog(struct dvb_frontend *fe)
+static int philips_europa_tuner_sleep(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
/* this message actually turns the tuner back to analog mode */
@@ -391,7 +391,20 @@ static void philips_europa_analog(struct dvb_frontend *fe)
analog_msg.len = 0x02;
msg[0] = 0x00;
msg[1] = 0x14;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
+ return 0;
+}
+
+static int philips_europa_demod_sleep(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+
+ if (dev->original_demod_sleep)
+ dev->original_demod_sleep(fe);
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ return 0;
}
static struct tda1004x_config philips_europa_config = {
@@ -402,21 +415,20 @@ static struct tda1004x_config philips_europa_config = {
.xtal_freq = TDA10046_XTAL_4M,
.agc_config = TDA10046_AGC_IFO_AUTO_POS,
.if_freq = TDA10046_FREQ_052,
- .pll_init = philips_europa_pll_init,
- .pll_set = philips_td1316_pll_set,
- .pll_sleep = philips_europa_analog,
.request_firmware = NULL,
};
/* ------------------------------------------------------------------ */
-static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
+static int philips_fmd1216_tuner_init(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
/* this message is to set up ATC and ALC */
static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
msleep(1);
@@ -424,22 +436,27 @@ static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
return 0;
}
-static void philips_fmd1216_analog(struct dvb_frontend *fe)
+static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
/* this message actually turns the tuner back to analog mode */
static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 };
struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
msleep(1);
fmd1216_init[2] = 0x86;
fmd1216_init[3] = 0x54;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
msleep(1);
+ return 0;
}
-static int philips_fmd1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct saa7134_dev *dev = fe->dvb->priv;
u8 tuner_buf[4];
@@ -516,6 +533,8 @@ static int philips_fmd1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_
tuner_buf[2] = 0x80 | (cp << 6) | (mode << 3) | 4;
tuner_buf[3] = 0x40 | band;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
return 0;
@@ -528,9 +547,6 @@ static struct tda1004x_config medion_cardbus = {
.xtal_freq = TDA10046_XTAL_16M,
.agc_config = TDA10046_AGC_IFO_AUTO_NEG,
.if_freq = TDA10046_FREQ_3613,
- .pll_init = philips_fmd1216_pll_init,
- .pll_set = philips_fmd1216_pll_set,
- .pll_sleep = philips_fmd1216_analog,
.request_firmware = NULL,
};
@@ -578,12 +594,12 @@ static struct tda827x_data tda827x_dvbt[] = {
{ .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}
};
-static int philips_tda827x_pll_init(struct dvb_frontend *fe)
+static int philips_tda827x_tuner_init(struct dvb_frontend *fe)
{
return 0;
}
-static int philips_tda827x_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tda827x_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct saa7134_dev *dev = fe->dvb->priv;
u8 tuner_buf[14];
@@ -630,6 +646,8 @@ static int philips_tda827x_pll_set(struct dvb_frontend *fe, struct dvb_frontend_
tuner_buf[13] = 0x40;
tuner_msg.len = 14;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
@@ -638,18 +656,23 @@ static int philips_tda827x_pll_set(struct dvb_frontend *fe, struct dvb_frontend_
tuner_buf[0] = 0x30;
tuner_buf[1] = 0x50 + tda827x_dvbt[i].cp;
tuner_msg.len = 2;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
return 0;
}
-static void philips_tda827x_pll_sleep(struct dvb_frontend *fe)
+static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
static u8 tda827x_sleep[] = { 0x30, 0xd0};
struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tda827x_sleep,
.len = sizeof(tda827x_sleep) };
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
+ return 0;
}
static struct tda1004x_config tda827x_lifeview_config = {
@@ -659,9 +682,6 @@ static struct tda1004x_config tda827x_lifeview_config = {
.xtal_freq = TDA10046_XTAL_16M,
.agc_config = TDA10046_AGC_TDA827X,
.if_freq = TDA10046_FREQ_045,
- .pll_init = philips_tda827x_pll_init,
- .pll_set = philips_tda827x_pll_set,
- .pll_sleep = philips_tda827x_pll_sleep,
.request_firmware = NULL,
};
@@ -753,6 +773,8 @@ static int philips_tda827xa_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb
tuner_buf[12] = 0x00;
tuner_buf[13] = 0x39; // lpsel
msg.len = 14;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
return -EIO;
@@ -760,10 +782,14 @@ static int philips_tda827xa_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb
msg.len = 2;
reg2[0] = 0x60;
reg2[1] = 0x3c;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &msg, 1);
reg2[0] = 0xa0;
reg2[1] = 0x40;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &msg, 1);
msleep(2);
@@ -771,36 +797,43 @@ static int philips_tda827xa_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb
reg2[0] = 0x30;
reg2[1] = 0x10 + tda827xa_dvbt[i].scr;
msg.len = 2;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &msg, 1);
msleep(550);
reg2[0] = 0x50;
reg2[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &msg, 1);
return 0;
}
-static void philips_tda827xa_pll_sleep(u8 addr, struct dvb_frontend *fe)
+static int philips_tda827xa_tuner_sleep(u8 addr, struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
static u8 tda827xa_sleep[] = { 0x30, 0x90};
struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tda827xa_sleep,
.len = sizeof(tda827xa_sleep) };
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
-
+ return 0;
}
/* ------------------------------------------------------------------ */
-static int philips_tiger_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tiger_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
int ret;
struct saa7134_dev *dev = fe->dvb->priv;
static u8 tda8290_close[] = { 0x21, 0xc0};
static u8 tda8290_open[] = { 0x21, 0x80};
struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2};
+
/* close tda8290 i2c bridge */
tda8290_msg.buf = tda8290_close;
ret = i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
@@ -816,7 +849,7 @@ static int philips_tiger_pll_set(struct dvb_frontend *fe, struct dvb_frontend_pa
return ret;
}
-static int philips_tiger_dvb_mode(struct dvb_frontend *fe)
+static int philips_tiger_tuner_init(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
static u8 data[] = { 0x3c, 0x33, 0x6a};
@@ -827,14 +860,15 @@ static int philips_tiger_dvb_mode(struct dvb_frontend *fe)
return 0;
}
-static void philips_tiger_analog_mode(struct dvb_frontend *fe)
+static int philips_tiger_tuner_sleep(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
static u8 data[] = { 0x3c, 0x33, 0x68};
struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
i2c_transfer(&dev->i2c_adap, &msg, 1);
- philips_tda827xa_pll_sleep( 0x61, fe);
+ philips_tda827xa_tuner_sleep( 0x61, fe);
+ return 0;
}
static struct tda1004x_config philips_tiger_config = {
@@ -844,15 +878,12 @@ static struct tda1004x_config philips_tiger_config = {
.xtal_freq = TDA10046_XTAL_16M,
.agc_config = TDA10046_AGC_TDA827X,
.if_freq = TDA10046_FREQ_045,
- .pll_init = philips_tiger_dvb_mode,
- .pll_set = philips_tiger_pll_set,
- .pll_sleep = philips_tiger_analog_mode,
.request_firmware = NULL,
};
/* ------------------------------------------------------------------ */
-static int lifeview_trio_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int lifeview_trio_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
int ret;
@@ -860,16 +891,12 @@ static int lifeview_trio_pll_set(struct dvb_frontend *fe, struct dvb_frontend_pa
return ret;
}
-static int lifeview_trio_dvb_mode(struct dvb_frontend *fe)
+static int lifeview_trio_tuner_sleep(struct dvb_frontend *fe)
{
+ philips_tda827xa_tuner_sleep(0x60, fe);
return 0;
}
-static void lifeview_trio_analog_mode(struct dvb_frontend *fe)
-{
- philips_tda827xa_pll_sleep(0x60, fe);
-}
-
static struct tda1004x_config lifeview_trio_config = {
.demod_address = 0x09,
.invert = 1,
@@ -877,15 +904,12 @@ static struct tda1004x_config lifeview_trio_config = {
.xtal_freq = TDA10046_XTAL_16M,
.agc_config = TDA10046_AGC_TDA827X_GPL,
.if_freq = TDA10046_FREQ_045,
- .pll_init = lifeview_trio_dvb_mode,
- .pll_set = lifeview_trio_pll_set,
- .pll_sleep = lifeview_trio_analog_mode,
.request_firmware = NULL,
};
/* ------------------------------------------------------------------ */
-static int ads_duo_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int ads_duo_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
int ret;
@@ -893,7 +917,7 @@ static int ads_duo_pll_set(struct dvb_frontend *fe, struct dvb_frontend_paramete
return ret;
}
-static int ads_duo_dvb_mode(struct dvb_frontend *fe)
+static int ads_duo_tuner_init(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
/* route TDA8275a AGC input to the channel decoder */
@@ -901,12 +925,13 @@ static int ads_duo_dvb_mode(struct dvb_frontend *fe)
return 0;
}
-static void ads_duo_analog_mode(struct dvb_frontend *fe)
+static int ads_duo_tuner_sleep(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
/* route TDA8275a AGC input to the analog IF chip*/
saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x20);
- philips_tda827xa_pll_sleep( 0x61, fe);
+ philips_tda827xa_tuner_sleep( 0x61, fe);
+ return 0;
}
static struct tda1004x_config ads_tech_duo_config = {
@@ -916,31 +941,24 @@ static struct tda1004x_config ads_tech_duo_config = {
.xtal_freq = TDA10046_XTAL_16M,
.agc_config = TDA10046_AGC_TDA827X_GPL,
.if_freq = TDA10046_FREQ_045,
- .pll_init = ads_duo_dvb_mode,
- .pll_set = ads_duo_pll_set,
- .pll_sleep = ads_duo_analog_mode,
.request_firmware = NULL,
};
/* ------------------------------------------------------------------ */
-static int tevion_dvb220rf_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int tevion_dvb220rf_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
int ret;
ret = philips_tda827xa_pll_set(0x60, fe, params);
return ret;
}
-static int tevion_dvb220rf_pll_init(struct dvb_frontend *fe)
+static int tevion_dvb220rf_tuner_sleep(struct dvb_frontend *fe)
{
+ philips_tda827xa_tuner_sleep( 0x61, fe);
return 0;
}
-static void tevion_dvb220rf_pll_sleep(struct dvb_frontend *fe)
-{
- philips_tda827xa_pll_sleep( 0x61, fe);
-}
-
static struct tda1004x_config tevion_dvbt220rf_config = {
.demod_address = 0x08,
.invert = 1,
@@ -948,9 +966,6 @@ static struct tda1004x_config tevion_dvbt220rf_config = {
.xtal_freq = TDA10046_XTAL_16M,
.agc_config = TDA10046_AGC_TDA827X,
.if_freq = TDA10046_FREQ_045,
- .pll_init = tevion_dvb220rf_pll_init,
- .pll_set = tevion_dvb220rf_pll_set,
- .pll_sleep = tevion_dvb220rf_pll_sleep,
.request_firmware = NULL,
};
@@ -961,8 +976,6 @@ static struct tda1004x_config tevion_dvbt220rf_config = {
#ifdef HAVE_NXT200X
static struct nxt200x_config avertvhda180 = {
.demod_address = 0x0a,
- .pll_address = 0x61,
- .pll_desc = &dvb_pll_tdhu2,
};
static int nxt200x_set_pll_input(u8 *buf, int input)
@@ -976,8 +989,6 @@ static int nxt200x_set_pll_input(u8 *buf, int input)
static struct nxt200x_config kworldatsc110 = {
.demod_address = 0x0a,
- .pll_address = 0x61,
- .pll_desc = &dvb_pll_tuv1236d,
.set_pll_input = nxt200x_set_pll_input,
};
#endif
@@ -1003,78 +1014,158 @@ static int dvb_init(struct saa7134_dev *dev)
printk("%s: pinnacle 300i dvb setup\n",dev->name);
dev->dvb.frontend = mt352_attach(&pinnacle_300i,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = mt352_pinnacle_tuner_set_params;
+ }
break;
case SAA7134_BOARD_AVERMEDIA_777:
printk("%s: avertv 777 dvb setup\n",dev->name);
dev->dvb.frontend = mt352_attach(&avermedia_777,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.calc_regs = mt352_aver777_tuner_calc_regs;
+ }
break;
#endif
#ifdef HAVE_TDA1004X
case SAA7134_BOARD_MD7134:
dev->dvb.frontend = tda10046_attach(&medion_cardbus,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
+ }
break;
case SAA7134_BOARD_PHILIPS_TOUGH:
dev->dvb.frontend = tda10046_attach(&philips_tu1216_60_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_60_init;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_60_set_params;
+ }
break;
case SAA7134_BOARD_FLYDVBTDUO:
dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params;
+ }
break;
case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params;
+ }
break;
case SAA7134_BOARD_PHILIPS_EUROPA:
dev->dvb.frontend = tda10046_attach(&philips_europa_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
+ dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+ dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+ }
break;
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
dev->dvb.frontend = tda10046_attach(&philips_europa_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+ }
break;
case SAA7134_BOARD_VIDEOMATE_DVBT_200:
dev->dvb.frontend = tda10046_attach(&philips_tu1216_61_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_61_init;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_61_set_params;
+ }
break;
case SAA7134_BOARD_PHILIPS_TIGER:
dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
+ }
break;
case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
+ }
break;
case SAA7134_BOARD_FLYDVBT_LR301:
dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params;
+ }
break;
case SAA7134_BOARD_FLYDVB_TRIO:
dev->dvb.frontend = tda10046_attach(&lifeview_trio_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.sleep = lifeview_trio_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = lifeview_trio_tuner_set_params;
+ }
break;
case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
dev->dvb.frontend = tda10046_attach(&ads_tech_duo_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = ads_duo_tuner_set_params;
+ }
break;
case SAA7134_BOARD_TEVION_DVBT_220RF:
dev->dvb.frontend = tda10046_attach(&tevion_dvbt220rf_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.sleep = tevion_dvb220rf_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = tevion_dvb220rf_tuner_set_params;
+ }
break;
case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
dev->dvb.frontend = tda10046_attach(&ads_tech_duo_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = ads_duo_tuner_set_params;
+ }
break;
#endif
#ifdef HAVE_NXT200X
case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
dev->dvb.frontend = nxt200x_attach(&avertvhda180, &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61, &dev->i2c_adap, &dvb_pll_tdhu2);
+ }
break;
case SAA7134_BOARD_KWORLD_ATSC110:
dev->dvb.frontend = nxt200x_attach(&kworldatsc110, &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61, &dev->i2c_adap, &dvb_pll_tuv1236d);
+ }
break;
#endif
default:
@@ -1088,7 +1179,7 @@ static int dvb_init(struct saa7134_dev *dev)
}
/* register everything else */
- return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev);
+ return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev);
}
static int dvb_fini(struct saa7134_dev *dev)
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index 1d972ed..65d0440 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -64,8 +64,10 @@ static void ts_reset_encoder(struct saa7134_dev* dev)
static int ts_init_encoder(struct saa7134_dev* dev)
{
+ struct v4l2_ext_controls ctrls = { V4L2_CTRL_CLASS_MPEG, 0 };
+
ts_reset_encoder(dev);
- saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, NULL);
+ saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, &ctrls);
dev->empress_started = 1;
return 0;
}
@@ -162,6 +164,7 @@ static int ts_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{
struct saa7134_dev *dev = file->private_data;
+ struct v4l2_ext_controls *ctrls = arg;
if (debug > 1)
v4l_print_ioctl(dev->name,cmd);
@@ -278,12 +281,31 @@ static int ts_do_ioctl(struct inode *inode, struct file *file,
return saa7134_common_ioctl(dev, cmd, arg);
case VIDIOC_S_MPEGCOMP:
+ printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
+ "Replace with VIDIOC_S_EXT_CTRLS!");
saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, arg);
ts_init_encoder(dev);
return 0;
case VIDIOC_G_MPEGCOMP:
+ printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. "
+ "Replace with VIDIOC_G_EXT_CTRLS!");
saa7134_i2c_call_clients(dev, VIDIOC_G_MPEGCOMP, arg);
return 0;
+ case VIDIOC_S_EXT_CTRLS:
+ /* count == 0 is abused in saa6752hs.c, so that special
+ case is handled here explicitly. */
+ if (ctrls->count == 0)
+ return 0;
+ if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, arg);
+ ts_init_encoder(dev);
+ return 0;
+ case VIDIOC_G_EXT_CTRLS:
+ if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, arg);
+ return 0;
default:
return -ENOIOCTLCMD;
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 1426e4c..7c59549 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -37,6 +37,10 @@ static unsigned int ir_debug = 0;
module_param(ir_debug, int, 0644);
MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
+static int pinnacle_remote = 0;
+module_param(pinnacle_remote, int, 0644); /* Choose Pinnacle PCTV remote */
+MODULE_PARM_DESC(pinnacle_remote, "Specify Pinnacle PCTV remote: 0=coloured, 1=grey (defaults to 0)");
+
#define dprintk(fmt, arg...) if (ir_debug) \
printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
#define i2cdprintk(fmt, arg...) if (ir_debug) \
@@ -316,8 +320,13 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
switch (dev->board) {
case SAA7134_BOARD_PINNACLE_PCTV_110i:
snprintf(ir->c.name, sizeof(ir->c.name), "Pinnacle PCTV");
- ir->get_key = get_key_pinnacle;
- ir->ir_codes = ir_codes_pinnacle;
+ if (pinnacle_remote == 0) {
+ ir->get_key = get_key_pinnacle_color;
+ ir->ir_codes = ir_codes_pinnacle_color;
+ } else {
+ ir->get_key = get_key_pinnacle_grey;
+ ir->ir_codes = ir_codes_pinnacle_grey;
+ }
break;
case SAA7134_BOARD_UPMOST_PURPLE_TV:
snprintf(ir->c.name, sizeof(ir->c.name), "Purple TV");
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 353af3a..d5ee99c 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -33,6 +33,7 @@
#include <asm/io.h>
+#include <media/v4l2-common.h>
#include <media/tuner.h>
#include <media/ir-common.h>
#include <media/ir-kbd-i2c.h>
@@ -221,6 +222,7 @@ struct saa7134_format {
#define SAA7134_BOARD_AVERMEDIA_A169_B1 92
#define SAA7134_BOARD_MD7134_BRIDGE_2 93
#define SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS 94
+#define SAA7134_BOARD_FLYVIDEO3000_NTSC 95
#define SAA7134_MAXBOARDS 8
#define SAA7134_INPUT_MAX 8
@@ -531,6 +533,7 @@ struct saa7134_dev {
/* SAA7134_MPEG_DVB only */
struct videobuf_dvb dvb;
+ int (*original_demod_sleep)(struct dvb_frontend* fe);
};
/* ----------------------------------------------------------- */
diff --git a/drivers/media/video/se401.h b/drivers/media/video/se401.h
index a7a216b..c0891b3 100644
--- a/drivers/media/video/se401.h
+++ b/drivers/media/video/se401.h
@@ -4,6 +4,7 @@
#include <asm/uaccess.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/smp_lock.h>
#include <linux/mutex.h>
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index ea4394d..48d138a 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -2608,11 +2608,9 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_G_CTRL:
return sn9c102_vidioc_g_ctrl(cam, arg);
- case VIDIOC_S_CTRL_OLD:
case VIDIOC_S_CTRL:
return sn9c102_vidioc_s_ctrl(cam, arg);
- case VIDIOC_CROPCAP_OLD:
case VIDIOC_CROPCAP:
return sn9c102_vidioc_cropcap(cam, arg);
@@ -2659,7 +2657,6 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_G_PARM:
return sn9c102_vidioc_g_parm(cam, arg);
- case VIDIOC_S_PARM_OLD:
case VIDIOC_S_PARM:
return sn9c102_vidioc_s_parm(cam, arg);
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
index 07476c7..6be9c11 100644
--- a/drivers/media/video/stradis.c
+++ b/drivers/media/video/stradis.c
@@ -42,6 +42,7 @@
#include <asm/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include "saa7146.h"
#include "saa7146reg.h"
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
index b38bda8..351b182 100644
--- a/drivers/media/video/stv680.c
+++ b/drivers/media/video/stv680.c
@@ -66,6 +66,7 @@
#include <linux/pagemap.h>
#include <linux/errno.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/usb.h>
#include <linux/mutex.h>
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
index 103ccb9..827633b 100644
--- a/drivers/media/video/tda9875.c
+++ b/drivers/media/video/tda9875.c
@@ -26,6 +26,7 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/init.h>
@@ -163,7 +164,7 @@ static void do_tda9875_init(struct i2c_client *client)
struct tda9875 *t = i2c_get_clientdata(client);
dprintk("In tda9875_init\n");
tda9875_write(client, TDA9875_CFG, 0xd0 ); /*reg de config 0 (reset)*/
- tda9875_write(client, TDA9875_MSR, 0x03 ); /* Monitor 0b00000XXX*/
+ tda9875_write(client, TDA9875_MSR, 0x03 ); /* Monitor 0b00000XXX*/
tda9875_write(client, TDA9875_C1MSB, 0x00 ); /*Car1(FM) MSB XMHz*/
tda9875_write(client, TDA9875_C1MIB, 0x00 ); /*Car1(FM) MIB XMHz*/
tda9875_write(client, TDA9875_C1LSB, 0x00 ); /*Car1(FM) LSB XMHz*/
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index 0d54f6c..b6ae969 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -18,49 +18,21 @@
TDA9886 (PAL, SECAM, NTSC)
TDA9887 (PAL, SECAM, NTSC, FM Radio)
- found on:
- - Pinnacle PCTV (Jul.2002 Version with MT2032, bttv)
- TDA9887 (world), TDA9885 (USA)
- Note: OP2 of tda988x must be set to 1, else MT2032 is disabled!
- - KNC One TV-Station RDS (saa7134)
- - Hauppauge PVR-150/500 (possibly more)
+ Used as part of several tuners
*/
+#define tda9887_info(fmt, arg...) do {\
+ printk(KERN_INFO "%s %d-%04x (tda9887): " fmt, t->i2c.name, \
+ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+#define tda9887_dbg(fmt, arg...) do {\
+ if (tuner_debug) \
+ printk(KERN_INFO "%s %d-%04x (tda9887): " fmt, t->i2c.name, \
+ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-/* Addresses to scan */
-static unsigned short normal_i2c[] = {
- 0x84 >>1,
- 0x86 >>1,
- 0x96 >>1,
- I2C_CLIENT_END,
-};
-I2C_CLIENT_INSMOD;
-
-/* insmod options */
-static unsigned int debug = 0;
-module_param(debug, int, 0644);
-MODULE_LICENSE("GPL");
/* ---------------------------------------------------------------------- */
#define UNSET (-1U)
-#define tda9887_info(fmt, arg...) do {\
- printk(KERN_INFO "%s %d-%04x: " fmt, t->client.name, \
- i2c_adapter_id(t->client.adapter), t->client.addr , ##arg); } while (0)
-#define tda9887_dbg(fmt, arg...) do {\
- if (debug) \
- printk(KERN_INFO "%s %d-%04x: " fmt, t->client.name, \
- i2c_adapter_id(t->client.adapter), t->client.addr , ##arg); } while (0)
-
-struct tda9887 {
- struct i2c_client client;
- v4l2_std_id std;
- enum tuner_mode mode;
- unsigned int config;
- unsigned int using_v4l2;
- unsigned int radio_mode;
- unsigned char data[4];
-};
struct tvnorm {
v4l2_std_id std;
@@ -70,9 +42,6 @@ struct tvnorm {
unsigned char e;
};
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
/* ---------------------------------------------------------------------- */
//
@@ -281,7 +250,7 @@ static struct tvnorm radio_mono = {
/* ---------------------------------------------------------------------- */
-static void dump_read_message(struct tda9887 *t, unsigned char *buf)
+static void dump_read_message(struct tuner *t, unsigned char *buf)
{
static char *afc[16] = {
"- 12.5 kHz",
@@ -309,7 +278,7 @@ static void dump_read_message(struct tda9887 *t, unsigned char *buf)
tda9887_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low");
}
-static void dump_write_message(struct tda9887 *t, unsigned char *buf)
+static void dump_write_message(struct tuner *t, unsigned char *buf)
{
static char *sound[4] = {
"AM/TV",
@@ -405,13 +374,13 @@ static void dump_write_message(struct tda9887 *t, unsigned char *buf)
/* ---------------------------------------------------------------------- */
-static int tda9887_set_tvnorm(struct tda9887 *t, char *buf)
+static int tda9887_set_tvnorm(struct tuner *t, char *buf)
{
struct tvnorm *norm = NULL;
int i;
- if (t->mode == T_RADIO) {
- if (t->radio_mode == V4L2_TUNER_MODE_MONO)
+ if (t->mode == V4L2_TUNER_RADIO) {
+ if (t->audmode == V4L2_TUNER_MODE_MONO)
norm = &radio_mono;
else
norm = &radio_stereo;
@@ -445,7 +414,7 @@ module_param(port2, int, 0644);
module_param(qss, int, 0644);
module_param(adjust, int, 0644);
-static int tda9887_set_insmod(struct tda9887 *t, char *buf)
+static int tda9887_set_insmod(struct tuner *t, char *buf)
{
if (UNSET != port1) {
if (port1)
@@ -474,27 +443,27 @@ static int tda9887_set_insmod(struct tda9887 *t, char *buf)
return 0;
}
-static int tda9887_set_config(struct tda9887 *t, char *buf)
+static int tda9887_set_config(struct tuner *t, char *buf)
{
- if (t->config & TDA9887_PORT1_ACTIVE)
+ if (t->tda9887_config & TDA9887_PORT1_ACTIVE)
buf[1] &= ~cOutputPort1Inactive;
- if (t->config & TDA9887_PORT1_INACTIVE)
+ if (t->tda9887_config & TDA9887_PORT1_INACTIVE)
buf[1] |= cOutputPort1Inactive;
- if (t->config & TDA9887_PORT2_ACTIVE)
+ if (t->tda9887_config & TDA9887_PORT2_ACTIVE)
buf[1] &= ~cOutputPort2Inactive;
- if (t->config & TDA9887_PORT2_INACTIVE)
+ if (t->tda9887_config & TDA9887_PORT2_INACTIVE)
buf[1] |= cOutputPort2Inactive;
- if (t->config & TDA9887_QSS)
+ if (t->tda9887_config & TDA9887_QSS)
buf[1] |= cQSS;
- if (t->config & TDA9887_INTERCARRIER)
+ if (t->tda9887_config & TDA9887_INTERCARRIER)
buf[1] &= ~cQSS;
- if (t->config & TDA9887_AUTOMUTE)
+ if (t->tda9887_config & TDA9887_AUTOMUTE)
buf[1] |= cAutoMuteFmActive;
- if (t->config & TDA9887_DEEMPHASIS_MASK) {
+ if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
buf[2] &= ~0x60;
- switch (t->config & TDA9887_DEEMPHASIS_MASK) {
+ switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
case TDA9887_DEEMPHASIS_NONE:
buf[2] |= cDeemphasisOFF;
break;
@@ -506,153 +475,36 @@ static int tda9887_set_config(struct tda9887 *t, char *buf)
break;
}
}
- if (t->config & TDA9887_TOP_SET) {
+ if (t->tda9887_config & TDA9887_TOP_SET) {
buf[2] &= ~cTopMask;
- buf[2] |= (t->config >> 8) & cTopMask;
+ buf[2] |= (t->tda9887_config >> 8) & cTopMask;
}
- if ((t->config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
+ if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
buf[1] &= ~cQSS;
return 0;
}
/* ---------------------------------------------------------------------- */
-static char pal[] = "--";
-static char secam[] = "--";
-static char ntsc[] = "-";
-
-module_param_string(pal, pal, sizeof(pal), 0644);
-module_param_string(secam, secam, sizeof(secam), 0644);
-module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
-
-static int tda9887_fixup_std(struct tda9887 *t)
-{
- /* get more precise norm info from insmod option */
- if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
- switch (pal[0]) {
- case 'b':
- case 'B':
- case 'g':
- case 'G':
- case 'h':
- case 'H':
- case 'n':
- case 'N':
- if (pal[1] == 'c' || pal[1] == 'C') {
- tda9887_dbg("insmod fixup: PAL => PAL-Nc\n");
- t->std = V4L2_STD_PAL_Nc;
- } else {
- tda9887_dbg("insmod fixup: PAL => PAL-BGHN\n");
- t->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N;
- }
- break;
- case 'i':
- case 'I':
- tda9887_dbg("insmod fixup: PAL => PAL-I\n");
- t->std = V4L2_STD_PAL_I;
- break;
- case 'd':
- case 'D':
- case 'k':
- case 'K':
- tda9887_dbg("insmod fixup: PAL => PAL-DK\n");
- t->std = V4L2_STD_PAL_DK;
- break;
- case 'm':
- case 'M':
- tda9887_dbg("insmod fixup: PAL => PAL-M\n");
- t->std = V4L2_STD_PAL_M;
- break;
- case '-':
- /* default parameter, do nothing */
- break;
- default:
- tda9887_info("pal= argument not recognised\n");
- break;
- }
- }
- if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
- switch (secam[0]) {
- case 'b':
- case 'B':
- case 'g':
- case 'G':
- case 'h':
- case 'H':
- tda9887_dbg("insmod fixup: SECAM => SECAM-BGH\n");
- t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
- break;
- case 'd':
- case 'D':
- case 'k':
- case 'K':
- tda9887_dbg("insmod fixup: SECAM => SECAM-DK\n");
- t->std = V4L2_STD_SECAM_DK;
- break;
- case 'l':
- case 'L':
- if (secam[1] == 'c' || secam[1] == 'C') {
- tda9887_dbg("insmod fixup: SECAM => SECAM-L'\n");
- t->std = V4L2_STD_SECAM_LC;
- } else {
- tda9887_dbg("insmod fixup: SECAM => SECAM-L\n");
- t->std = V4L2_STD_SECAM_L;
- }
- break;
- case '-':
- /* default parameter, do nothing */
- break;
- default:
- tda9887_info("secam= argument not recognised\n");
- break;
- }
- }
- if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
- switch (ntsc[0]) {
- case 'm':
- case 'M':
- tda9887_dbg("insmod fixup: NTSC => NTSC-M\n");
- t->std = V4L2_STD_NTSC_M;
- break;
- case 'j':
- case 'J':
- tda9887_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
- t->std = V4L2_STD_NTSC_M_JP;
- break;
- case 'k':
- case 'K':
- tda9887_dbg("insmod fixup: NTSC => NTSC_M_KR\n");
- t->std = V4L2_STD_NTSC_M_KR;
- break;
- case '-':
- /* default parameter, do nothing */
- break;
- default:
- tda9887_info("ntsc= argument not recognised\n");
- break;
- }
- }
- return 0;
-}
-
-static int tda9887_status(struct tda9887 *t)
+static int tda9887_status(struct tuner *t)
{
unsigned char buf[1];
int rc;
memset(buf,0,sizeof(buf));
- if (1 != (rc = i2c_master_recv(&t->client,buf,1)))
+ if (1 != (rc = i2c_master_recv(&t->i2c,buf,1)))
tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
dump_read_message(t, buf);
return 0;
}
-static int tda9887_configure(struct tda9887 *t)
+static void tda9887_configure(struct i2c_client *client)
{
+ struct tuner *t = i2c_get_clientdata(client);
int rc;
- memset(t->data,0,sizeof(t->data));
- tda9887_set_tvnorm(t,t->data);
+ memset(t->tda9887_data,0,sizeof(t->tda9887_data));
+ tda9887_set_tvnorm(t,t->tda9887_data);
/* A note on the port settings:
These settings tend to depend on the specifics of the board.
@@ -667,249 +519,84 @@ static int tda9887_configure(struct tda9887 *t)
the ports should be set to active (0), but, again, that may
differ depending on the precise hardware configuration.
*/
- t->data[1] |= cOutputPort1Inactive;
- t->data[1] |= cOutputPort2Inactive;
+ t->tda9887_data[1] |= cOutputPort1Inactive;
+ t->tda9887_data[1] |= cOutputPort2Inactive;
- tda9887_set_config(t,t->data);
- tda9887_set_insmod(t,t->data);
+ tda9887_set_config(t,t->tda9887_data);
+ tda9887_set_insmod(t,t->tda9887_data);
if (t->mode == T_STANDBY) {
- t->data[1] |= cForcedMuteAudioON;
+ t->tda9887_data[1] |= cForcedMuteAudioON;
}
tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
- t->data[1],t->data[2],t->data[3]);
- if (debug > 1)
- dump_write_message(t, t->data);
+ t->tda9887_data[1],t->tda9887_data[2],t->tda9887_data[3]);
+ if (tuner_debug > 1)
+ dump_write_message(t, t->tda9887_data);
- if (4 != (rc = i2c_master_send(&t->client,t->data,4)))
+ if (4 != (rc = i2c_master_send(&t->i2c,t->tda9887_data,4)))
tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
- if (debug > 2) {
+ if (tuner_debug > 2) {
msleep_interruptible(1000);
tda9887_status(t);
}
- return 0;
}
/* ---------------------------------------------------------------------- */
-static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind)
+static void tda9887_tuner_status(struct i2c_client *client)
{
- struct tda9887 *t;
-
- client_template.adapter = adap;
- client_template.addr = addr;
-
- if (NULL == (t = kzalloc(sizeof(*t), GFP_KERNEL)))
- return -ENOMEM;
-
- t->client = client_template;
- t->std = 0;
- t->radio_mode = V4L2_TUNER_MODE_STEREO;
-
- tda9887_info("chip found @ 0x%x (%s)\n", addr<<1, adap->name);
-
- i2c_set_clientdata(&t->client, t);
- i2c_attach_client(&t->client);
-
- return 0;
+ struct tuner *t = i2c_get_clientdata(client);
+ tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->tda9887_data[1], t->tda9887_data[2], t->tda9887_data[3]);
}
-static int tda9887_probe(struct i2c_adapter *adap)
+static int tda9887_get_afc(struct i2c_client *client)
{
- if (adap->class & I2C_CLASS_TV_ANALOG)
- return i2c_probe(adap, &addr_data, tda9887_attach);
- return 0;
-}
+ struct tuner *t = i2c_get_clientdata(client);
+ static int AFC_BITS_2_kHz[] = {
+ -12500, -37500, -62500, -97500,
+ -112500, -137500, -162500, -187500,
+ 187500, 162500, 137500, 112500,
+ 97500 , 62500, 37500 , 12500
+ };
+ int afc=0;
+ __u8 reg = 0;
-static int tda9887_detach(struct i2c_client *client)
-{
- struct tda9887 *t = i2c_get_clientdata(client);
+ if (1 == i2c_master_recv(&t->i2c,&reg,1))
+ afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
- i2c_detach_client(client);
- kfree(t);
- return 0;
+ return afc;
}
-#define SWITCH_V4L2 if (!t->using_v4l2 && debug) \
- tda9887_info("switching to v4l2\n"); \
- t->using_v4l2 = 1;
-#define CHECK_V4L2 if (t->using_v4l2) { if (debug) \
- tda9887_info("ignore v4l1 call\n"); \
- return 0; }
-
-static int
-tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
+static void tda9887_standby(struct i2c_client *client)
{
- struct tda9887 *t = i2c_get_clientdata(client);
-
- switch (cmd) {
-
- /* --- configuration --- */
- case AUDC_SET_RADIO:
- {
- t->mode = T_RADIO;
- tda9887_configure(t);
- break;
- }
- case TUNER_SET_STANDBY:
- {
- t->mode = T_STANDBY;
- tda9887_configure(t);
- break;
- }
- case TDA9887_SET_CONFIG:
- {
- int *i = arg;
-
- t->config = *i;
- tda9887_configure(t);
- break;
- }
- /* --- v4l ioctls --- */
- /* take care: bttv does userspace copying, we'll get a
- kernel pointer here... */
- case VIDIOCSCHAN:
- {
- static const v4l2_std_id map[] = {
- [ VIDEO_MODE_PAL ] = V4L2_STD_PAL,
- [ VIDEO_MODE_NTSC ] = V4L2_STD_NTSC_M,
- [ VIDEO_MODE_SECAM ] = V4L2_STD_SECAM,
- [ 4 /* bttv */ ] = V4L2_STD_PAL_M,
- [ 5 /* bttv */ ] = V4L2_STD_PAL_N,
- [ 6 /* bttv */ ] = V4L2_STD_NTSC_M_JP,
- };
- struct video_channel *vc = arg;
-
- CHECK_V4L2;
- t->mode = T_ANALOG_TV;
- if (vc->norm < ARRAY_SIZE(map))
- t->std = map[vc->norm];
- tda9887_fixup_std(t);
- tda9887_configure(t);
- break;
- }
- case VIDIOC_S_STD:
- {
- v4l2_std_id *id = arg;
-
- SWITCH_V4L2;
- t->mode = T_ANALOG_TV;
- t->std = *id;
- tda9887_fixup_std(t);
- tda9887_configure(t);
- break;
- }
- case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
-
- SWITCH_V4L2;
- if (V4L2_TUNER_ANALOG_TV == f->type) {
- if (t->mode == T_ANALOG_TV)
- return 0;
- t->mode = T_ANALOG_TV;
- }
- if (V4L2_TUNER_RADIO == f->type) {
- if (t->mode == T_RADIO)
- return 0;
- t->mode = T_RADIO;
- }
- tda9887_configure(t);
- break;
- }
- case VIDIOC_G_TUNER:
- {
- static int AFC_BITS_2_kHz[] = {
- -12500, -37500, -62500, -97500,
- -112500, -137500, -162500, -187500,
- 187500, 162500, 137500, 112500,
- 97500 , 62500, 37500 , 12500
- };
- struct v4l2_tuner* tuner = arg;
-
- if (t->mode == T_RADIO) {
- __u8 reg = 0;
- tuner->afc=0;
- if (1 == i2c_master_recv(&t->client,&reg,1))
- tuner->afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
- }
- break;
- }
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner* tuner = arg;
-
- if (t->mode == T_RADIO) {
- t->radio_mode = tuner->audmode;
- tda9887_configure (t);
- }
- break;
- }
- case VIDIOC_LOG_STATUS:
- {
- tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->data[1], t->data[2], t->data[3]);
- break;
- }
- default:
- /* nothing */
- break;
- }
- return 0;
+ tda9887_configure(client);
}
-static int tda9887_suspend(struct device * dev, pm_message_t state)
+static void tda9887_set_freq(struct i2c_client *client, unsigned int freq)
{
- struct i2c_client *c = container_of(dev, struct i2c_client, dev);
- struct tda9887 *t = i2c_get_clientdata(c);
-
- tda9887_dbg("suspend\n");
- return 0;
+ tda9887_configure(client);
}
-static int tda9887_resume(struct device * dev)
+int tda9887_tuner_init(struct i2c_client *c)
{
- struct i2c_client *c = container_of(dev, struct i2c_client, dev);
- struct tda9887 *t = i2c_get_clientdata(c);
+ struct tuner *t = i2c_get_clientdata(c);
- tda9887_dbg("resume\n");
- tda9887_configure(t);
- return 0;
-}
+ strlcpy(c->name, "tda9887", sizeof(c->name));
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_driver driver = {
- .id = I2C_DRIVERID_TDA9887,
- .attach_adapter = tda9887_probe,
- .detach_client = tda9887_detach,
- .command = tda9887_command,
- .driver = {
- .name = "tda9887",
- .suspend = tda9887_suspend,
- .resume = tda9887_resume,
- },
-};
-static struct i2c_client client_template =
-{
- .name = "tda9887",
- .driver = &driver,
-};
+ tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
+ t->i2c.driver->driver.name);
-static int __init tda9887_init_module(void)
-{
- return i2c_add_driver(&driver);
-}
+ t->set_tv_freq = tda9887_set_freq;
+ t->set_radio_freq = tda9887_set_freq;
+ t->standby = tda9887_standby;
+ t->tuner_status=tda9887_tuner_status;
+ t->get_afc=tda9887_get_afc;
-static void __exit tda9887_cleanup_module(void)
-{
- i2c_del_driver(&driver);
+ return 0;
}
-module_init(tda9887_init_module);
-module_exit(tda9887_cleanup_module);
-
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
index c2b98f8..d1c4178 100644
--- a/drivers/media/video/tea5767.c
+++ b/drivers/media/video/tea5767.c
@@ -3,7 +3,7 @@
* I2C address is allways 0xC0.
*
*
- * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br)
+ * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@infradead.org)
* This code is placed under the terms of the GNU General Public License
*
* tea5767 autodetection thanks to Torsten Seeboth and Atsushi Nakagawa
diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c
new file mode 100644
index 0000000..76b2e96
--- /dev/null
+++ b/drivers/media/video/tlv320aic23b.c
@@ -0,0 +1,217 @@
+/*
+ * tlv320aic23b - driver version 0.0.1
+ *
+ * Copyright (C) 2006 Scott Alfter <salfter@ssai.us>
+ *
+ * Based on wm8775 driver
+ *
+ * Copyright (C) 2004 Ulf Eklund <ivtv at eklund.to>
+ * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
+
+MODULE_DESCRIPTION("tlv320aic23b driver");
+MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static unsigned short normal_i2c[] = { 0x34 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+
+struct tlv320aic23b_state {
+ u8 muted;
+};
+
+static int tlv320aic23b_write(struct i2c_client *client, int reg, u16 val)
+{
+ int i;
+
+ if ((reg < 0 || reg > 9) && (reg != 15)) {
+ v4l_err(client, "Invalid register R%d\n", reg);
+ return -1;
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (i2c_smbus_write_byte_data(client, (reg << 1) |
+ (val >> 8), val & 0xff) == 0) {
+ return 0;
+ }
+ }
+ v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
+ return -1;
+}
+
+static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd,
+ void *arg)
+{
+ struct tlv320aic23b_state *state = i2c_get_clientdata(client);
+ struct v4l2_control *ctrl = arg;
+ u32* freq = arg;
+
+ switch (cmd) {
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ switch (*freq) {
+ case 32000: /* set sample rate to 32 kHz */
+ tlv320aic23b_write(client, 8, 0x018);
+ break;
+ case 44100: /* set sample rate to 44.1 kHz */
+ tlv320aic23b_write(client, 8, 0x022);
+ break;
+ case 48000: /* set sample rate to 48 kHz */
+ tlv320aic23b_write(client, 8, 0x000);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ case VIDIOC_G_CTRL:
+ if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+ return -EINVAL;
+ ctrl->value = state->muted;
+ break;
+
+ case VIDIOC_S_CTRL:
+ if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+ return -EINVAL;
+ state->muted = ctrl->value;
+ tlv320aic23b_write(client, 0, 0x180); /* mute both channels */
+ /* set gain on both channels to +3.0 dB */
+ if (!state->muted)
+ tlv320aic23b_write(client, 0, 0x119);
+ break;
+
+ case VIDIOC_LOG_STATUS:
+ v4l_info(client, "Input: %s\n",
+ state->muted ? "muted" : "active");
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+static struct i2c_driver i2c_driver;
+
+static int tlv320aic23b_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct tlv320aic23b_state *state;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == 0)
+ return -ENOMEM;
+
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &i2c_driver;
+ snprintf(client->name, sizeof(client->name) - 1, "tlv320aic23b");
+
+ v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+
+ state = kmalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL);
+ if (state == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+ state->muted = 0;
+ i2c_set_clientdata(client, state);
+
+ /* initialize tlv320aic23b */
+ tlv320aic23b_write(client, 15, 0x000); /* RESET */
+ tlv320aic23b_write(client, 6, 0x00A); /* turn off DAC & mic input */
+ tlv320aic23b_write(client, 7, 0x049); /* left-justified, 24-bit, master mode */
+ tlv320aic23b_write(client, 0, 0x119); /* set gain on both channels to +3.0 dB */
+ tlv320aic23b_write(client, 8, 0x000); /* set sample rate to 48 kHz */
+ tlv320aic23b_write(client, 9, 0x001); /* activate digital interface */
+
+ i2c_attach_client(client);
+
+ return 0;
+}
+
+static int tlv320aic23b_probe(struct i2c_adapter *adapter)
+{
+ if (adapter->class & I2C_CLASS_TV_ANALOG)
+ return i2c_probe(adapter, &addr_data, tlv320aic23b_attach);
+ return 0;
+}
+
+static int tlv320aic23b_detach(struct i2c_client *client)
+{
+ int err;
+
+ err = i2c_detach_client(client);
+ if (err) {
+ return err;
+ }
+ kfree(client);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+static struct i2c_driver i2c_driver = {
+ .driver = {
+ .name = "tlv320aic23b",
+ },
+ .id = I2C_DRIVERID_TLV320AIC23B,
+ .attach_adapter = tlv320aic23b_probe,
+ .detach_client = tlv320aic23b_detach,
+ .command = tlv320aic23b_command,
+};
+
+
+static int __init tlv320aic23b_init_module(void)
+{
+ return i2c_add_driver(&i2c_driver);
+}
+
+static void __exit tlv320aic23b_cleanup_module(void)
+{
+ i2c_del_driver(&i2c_driver);
+}
+
+module_init(tlv320aic23b_init_module);
+module_exit(tlv320aic23b_cleanup_module);
diff --git a/drivers/media/video/tuner-3036.c b/drivers/media/video/tuner-3036.c
index 74ab48c..bdf506e 100644
--- a/drivers/media/video/tuner-3036.c
+++ b/drivers/media/video/tuner-3036.c
@@ -25,6 +25,7 @@
#include <linux/i2c.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <media/tuner.h>
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 1013b4d..e95792f 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -199,7 +199,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
i2c_master_send(c, buffer, 4);
default_tuner_init(c);
break;
- case TUNER_LG_TDVS_H062F:
+ case TUNER_LG_TDVS_H06XF:
/* Set the Auxiliary Byte. */
buffer[2] &= ~0x20;
buffer[2] |= 0x18;
@@ -215,6 +215,9 @@ static void set_type(struct i2c_client *c, unsigned int type,
i2c_master_send(c,buffer,4);
default_tuner_init(c);
break;
+ case TUNER_TDA9887:
+ tda9887_tuner_init(c);
+ break;
default:
default_tuner_init(c);
break;
@@ -241,6 +244,8 @@ static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
{
struct tuner *t = i2c_get_clientdata(c);
+ tuner_dbg("set addr for type %i\n", t->type);
+
if ( t->type == UNSET && ((tun_setup->addr == ADDR_UNSET &&
(t->mode_mask & tun_setup->mode_mask)) ||
tun_setup->addr == c->addr)) {
@@ -436,6 +441,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
t->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */
t->audmode = V4L2_TUNER_MODE_STEREO;
t->mode_mask = T_UNINITIALIZED;
+ t->tuner_status = tuner_status;
if (tuner_debug_old) {
tuner_debug = tuner_debug_old;
printk(KERN_ERR "tuner: tuner_debug is deprecated and will be removed in 2.6.17.\n");
@@ -462,10 +468,14 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
case 0x4b:
/* If chip is not tda8290, don't register.
since it can be tda9887*/
- if (tda8290_probe(&t->i2c) != 0) {
- tuner_dbg("chip at addr %x is not a tda8290\n", addr);
- kfree(t);
- return 0;
+ if (tda8290_probe(&t->i2c) == 0) {
+ tuner_dbg("chip at addr %x is a tda8290\n", addr);
+ } else {
+ /* Default is being tda9887 */
+ t->type = TUNER_TDA9887;
+ t->mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
+ t->mode = T_STANDBY;
+ goto register_client;
}
break;
case 0x60:
@@ -592,6 +602,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
case TUNER_SET_STANDBY:
if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
return 0;
+ t->mode = T_STANDBY;
if (t->standby)
t->standby (client);
break;
@@ -604,6 +615,14 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
/* Should be implemented, since bttv calls it */
tuner_dbg("VIDIOCSAUDIO not implemented.\n");
break;
+ case TDA9887_SET_CONFIG:
+ {
+ int *i = arg;
+
+ t->tda9887_config = *i;
+ set_freq(client, t->tv_freq);
+ break;
+ }
/* --- v4l ioctls --- */
/* take care: bttv does userspace copying, we'll get a
kernel pointer here... */
@@ -744,6 +763,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
switch_v4l2();
tuner->type = t->mode;
+ if (t->get_afc)
+ tuner->afc=t->get_afc(client);
if (t->mode == V4L2_TUNER_ANALOG_TV)
tuner->capability |= V4L2_TUNER_CAP_NORM;
if (t->mode != V4L2_TUNER_RADIO) {
@@ -787,7 +808,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
break;
}
case VIDIOC_LOG_STATUS:
- tuner_status(client);
+ if (t->tuner_status)
+ t->tuner_status(client);
break;
}
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index 5d7abed..6da6f82 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -105,7 +105,7 @@ static int tuner_stereo(struct i2c_client *c)
switch (t->type) {
case TUNER_PHILIPS_FM1216ME_MK3:
- case TUNER_PHILIPS_FM1236_MK3:
+ case TUNER_PHILIPS_FM1236_MK3:
case TUNER_PHILIPS_FM1256_IH3:
stereo = ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
break;
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c
index a1ae036..9d9226c 100644
--- a/drivers/media/video/tuner-types.c
+++ b/drivers/media/video/tuner-types.c
@@ -874,7 +874,7 @@ static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = {
};
-/* ------------ TUNER_LG_TDVS_H062F - INFINEON ATSC ------------ */
+/* ------ TUNER_LG_TDVS_H06XF - LG INNOTEK / INFINEON ATSC ----- */
static struct tuner_range tuner_tua6034_ntsc_ranges[] = {
{ 16 * 165.00 /*MHz*/, 0x8e, 0x01 },
@@ -883,7 +883,7 @@ static struct tuner_range tuner_tua6034_ntsc_ranges[] = {
};
-static struct tuner_params tuner_tua6034_params[] = {
+static struct tuner_params tuner_lg_tdvs_h06xf_params[] = {
{
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_tua6034_ntsc_ranges,
@@ -1024,6 +1024,22 @@ static struct tuner_params tuner_thomson_fe6600_params[] = {
},
};
+/* ------------ TUNER_SAMSUNG_TCPG_6121P30A - Samsung PAL ------------ */
+
+static struct tuner_range tuner_samsung_tcpg_6121p30a_pal_ranges[] = {
+ { 16 * 146.25 /*MHz*/, 0xce, 0x01, },
+ { 16 * 428.50 /*MHz*/, 0xce, 0x02, },
+ { 16 * 999.99 , 0xce, 0x08, },
+};
+
+static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = {
+ {
+ .type = TUNER_PARAM_TYPE_PAL,
+ .ranges = tuner_samsung_tcpg_6121p30a_pal_ranges,
+ .count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_pal_ranges),
+ },
+};
+
/* --------------------------------------------------------------------- */
struct tunertype tuners[] = {
@@ -1354,10 +1370,10 @@ struct tunertype tuners[] = {
.params = tuner_philips_fmd1216me_mk3_params,
.count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_params),
},
- [TUNER_LG_TDVS_H062F] = { /* LGINNOTEK ATSC */
- .name = "LG TDVS-H062F/TUA6034",
- .params = tuner_tua6034_params,
- .count = ARRAY_SIZE(tuner_tua6034_params),
+ [TUNER_LG_TDVS_H06XF] = { /* LGINNOTEK ATSC */
+ .name = "LG TDVS-H06xF", /* H061F, H062F & H064F */
+ .params = tuner_lg_tdvs_h06xf_params,
+ .count = ARRAY_SIZE(tuner_lg_tdvs_h06xf_params),
},
[TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */
.name = "Ymec TVF66T5-B/DFF",
@@ -1400,6 +1416,16 @@ struct tunertype tuners[] = {
.params = tuner_thomson_fe6600_params,
.count = ARRAY_SIZE(tuner_thomson_fe6600_params),
},
+ [TUNER_SAMSUNG_TCPG_6121P30A] = { /* Samsung PAL */
+ .name = "Samsung TCPG 6121P30A",
+ .params = tuner_samsung_tcpg_6121p30a_params,
+ .count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_params),
+ },
+ [TUNER_TDA9887] = { /* Philips TDA 9887 IF PLL Demodulator.
+ This chip is part of some modern tuners */
+ .name = "Philips TDA988[5,6,7] IF PLL Demodulator",
+ /* see tda9887.c for details */
+ },
};
unsigned const int tuner_count = ARRAY_SIZE(tuners);
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index b463e99..30f8d80 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -200,7 +200,7 @@ hauppauge_tuner[] =
{ TUNER_ABSENT, "Philips FQ1286A MK4"},
{ TUNER_ABSENT, "Philips FQ1216ME MK5"},
{ TUNER_ABSENT, "Philips FQ1236 MK5"},
- { TUNER_ABSENT, "Samsung TCPG_6121P30A"},
+ { TUNER_SAMSUNG_TCPG_6121P30A, "Samsung TCPG 6121P30A"},
{ TUNER_TCL_2002MB, "TCL 2002MB_3H"},
{ TUNER_ABSENT, "TCL 2002MI_3H"},
{ TUNER_TCL_2002N, "TCL 2002N 5H"},
diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
index 9e86cae..1654576 100644
--- a/drivers/media/video/tvmixer.c
+++ b/drivers/media/video/tvmixer.c
@@ -198,10 +198,6 @@ static int tvmixer_open(struct inode *inode, struct file *file)
/* lock bttv in memory while the mixer is in use */
file->private_data = mix;
-#ifndef I2C_PEC
- if (client->adapter->inc_use)
- client->adapter->inc_use(client->adapter);
-#endif
if (client->adapter->owner)
try_module_get(client->adapter->owner);
return 0;
@@ -217,10 +213,6 @@ static int tvmixer_release(struct inode *inode, struct file *file)
return -ENODEV;
}
-#ifndef I2C_PEC
- if (client->adapter->dec_use)
- client->adapter->dec_use(client->adapter);
-#endif
if (client->adapter->owner)
module_put(client->adapter->owner);
return 0;
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index dab4973..b167ffa 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -10,6 +10,7 @@
#include <linux/delay.h>
#include <linux/video_decoder.h>
#include <media/v4l2-common.h>
+#include <media/tvp5150.h>
#include "tvp5150_reg.h"
@@ -89,7 +90,7 @@ struct tvp5150 {
struct i2c_client *client;
v4l2_std_id norm; /* Current set standard */
- int input;
+ struct v4l2_routing route;
int enable;
int bright;
int contrast;
@@ -283,29 +284,26 @@ static void dump_reg(struct i2c_client *c)
/****************************************************************************
Basic functions
****************************************************************************/
-enum tvp5150_input {
- TVP5150_ANALOG_CH0 = 0,
- TVP5150_SVIDEO = 1,
- TVP5150_ANALOG_CH1 = 2,
- TVP5150_BLACK_SCREEN = 8
-};
-static inline void tvp5150_selmux(struct i2c_client *c,
- enum tvp5150_input input)
+static inline void tvp5150_selmux(struct i2c_client *c)
{
int opmode=0;
-
struct tvp5150 *decoder = i2c_get_clientdata(c);
+ int input = 0;
- if (!decoder->enable)
- input |= TVP5150_BLACK_SCREEN;
+ if ((decoder->route.output & TVP5150_BLACK_SCREEN) || !decoder->enable)
+ input = 8;
switch (input) {
- case TVP5150_ANALOG_CH0:
- case TVP5150_ANALOG_CH1:
+ case TVP5150_COMPOSITE1:
+ input |= 2;
+ /* fall through */
+ case TVP5150_COMPOSITE0:
opmode=0x30; /* TV Mode */
break;
+ case TVP5150_SVIDEO:
default:
+ input |= 1;
opmode=0; /* Auto Mode */
break;
}
@@ -790,7 +788,7 @@ static inline void tvp5150_reset(struct i2c_client *c)
tvp5150_vdp_init(c, vbi_ram_default);
/* Selects decoder input */
- tvp5150_selmux(c, decoder->input);
+ tvp5150_selmux(c);
/* Initializes TVP5150 to stream enabled values */
tvp5150_write_inittab(c, tvp5150_init_enable);
@@ -860,6 +858,21 @@ static int tvp5150_command(struct i2c_client *c,
case VIDIOC_INT_RESET:
tvp5150_reset(c);
break;
+ case VIDIOC_INT_G_VIDEO_ROUTING:
+ {
+ struct v4l2_routing *route = arg;
+
+ *route = decoder->route;
+ break;
+ }
+ case VIDIOC_INT_S_VIDEO_ROUTING:
+ {
+ struct v4l2_routing *route = arg;
+
+ decoder->route = *route;
+ tvp5150_selmux(c);
+ break;
+ }
case VIDIOC_S_STD:
if (decoder->norm == *(v4l2_std_id *)arg)
break;
@@ -1063,7 +1076,7 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter,
rv = i2c_attach_client(c);
core->norm = V4L2_STD_ALL; /* Default is autodetect */
- core->input = 2;
+ core->route.input = TVP5150_COMPOSITE1;
core->enable = 1;
core->bright = 32768;
core->contrast = 32768;
diff --git a/drivers/media/video/usbvideo/Kconfig b/drivers/media/video/usbvideo/Kconfig
index 39269a2..59fb899 100644
--- a/drivers/media/video/usbvideo/Kconfig
+++ b/drivers/media/video/usbvideo/Kconfig
@@ -36,3 +36,15 @@ config USB_KONICAWC
To compile this driver as a module, choose M here: the
module will be called konicawc.
+
+config USB_QUICKCAM_MESSENGER
+ tristate "USB Logitech Quickcam Messenger"
+ depends on USB && VIDEO_DEV
+ select VIDEO_USBVIDEO
+ ---help---
+ Say Y or M here to enable support for the USB Logitech Quickcam
+ Messenger webcam.
+
+ To compile this driver as a module, choose M here: the
+ module will be called quickcam_messenger.
+
diff --git a/drivers/media/video/usbvideo/Makefile b/drivers/media/video/usbvideo/Makefile
index bb52eb8..4a1b144 100644
--- a/drivers/media/video/usbvideo/Makefile
+++ b/drivers/media/video/usbvideo/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_VIDEO_USBVIDEO) += usbvideo.o
obj-$(CONFIG_USB_IBMCAM) += ibmcam.o ultracam.o
obj-$(CONFIG_USB_KONICAWC) += konicawc.o
obj-$(CONFIG_USB_VICAM) += vicam.o
+obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += quickcam_messenger.o
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
new file mode 100644
index 0000000..3f3182a
--- /dev/null
+++ b/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -0,0 +1,1120 @@
+/*
+ * Driver for Logitech Quickcam Messenger usb video camera
+ * Copyright (C) Jaya Kumar
+ *
+ * This work was sponsored by CIS(M) Sdn Bhd.
+ * History:
+ * 05/08/2006 - Jaya Kumar
+ * I wrote this based on the konicawc by Simon Evans.
+ * -
+ * Full credit for reverse engineering and creating an initial
+ * working linux driver for the VV6422 goes to the qce-ga project by
+ * Tuukka Toivonen, Jochen Hoenicke, Peter McConnell,
+ * Cristiano De Michele, Georg Acher, Jean-Frederic Clere as well as
+ * others.
+ * ---
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/usb_input.h>
+
+#include "usbvideo.h"
+#include "quickcam_messenger.h"
+
+/*
+ * Version Information
+ */
+
+#ifdef CONFIG_USB_DEBUG
+static int debug;
+#define DEBUG(n, format, arg...) \
+ if (n <= debug) { \
+ printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+ }
+#else
+#define DEBUG(n, arg...)
+static const int debug = 0;
+#endif
+
+#define DRIVER_VERSION "v0.01"
+#define DRIVER_DESC "Logitech Quickcam Messenger USB"
+
+#define USB_LOGITECH_VENDOR_ID 0x046D
+#define USB_QCM_PRODUCT_ID 0x08F0
+
+#define MAX_CAMERAS 1
+
+#define MAX_COLOUR 32768
+#define MAX_HUE 32768
+#define MAX_BRIGHTNESS 32768
+#define MAX_CONTRAST 32768
+#define MAX_WHITENESS 32768
+
+static int size = SIZE_320X240;
+static int colour = MAX_COLOUR;
+static int hue = MAX_HUE;
+static int brightness = MAX_BRIGHTNESS;
+static int contrast = MAX_CONTRAST;
+static int whiteness = MAX_WHITENESS;
+
+static struct usbvideo *cams;
+
+static struct usb_device_id qcm_table [] = {
+ { USB_DEVICE(USB_LOGITECH_VENDOR_ID, USB_QCM_PRODUCT_ID) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, qcm_table);
+
+#ifdef CONFIG_INPUT
+static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
+{
+ struct input_dev *input_dev;
+
+ usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
+ strncat(cam->input_physname, "/input0", sizeof(cam->input_physname));
+
+ cam->input = input_dev = input_allocate_device();
+ if (!input_dev) {
+ warn("insufficient mem for cam input device");
+ return;
+ }
+
+ input_dev->name = "QCM button";
+ input_dev->phys = cam->input_physname;
+ usb_to_input_id(dev, &input_dev->id);
+ input_dev->cdev.dev = &dev->dev;
+
+ input_dev->evbit[0] = BIT(EV_KEY);
+ input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
+
+ input_dev->private = cam;
+
+ input_register_device(cam->input);
+}
+
+static void qcm_unregister_input(struct qcm *cam)
+{
+ if (cam->input) {
+ input_unregister_device(cam->input);
+ cam->input = NULL;
+ }
+}
+
+static void qcm_report_buttonstat(struct qcm *cam)
+{
+ if (cam->input) {
+ input_report_key(cam->input, BTN_0, cam->button_sts);
+ input_sync(cam->input);
+ }
+}
+
+static void qcm_int_irq(struct urb *urb, struct pt_regs *regs)
+{
+ int ret;
+ struct uvd *uvd = urb->context;
+ struct qcm *cam;
+
+ if (!CAMERA_IS_OPERATIONAL(uvd))
+ return;
+
+ if (!uvd->streaming)
+ return;
+
+ uvd->stats.urb_count++;
+
+ if (urb->status < 0)
+ uvd->stats.iso_err_count++;
+ else {
+ if (urb->actual_length > 0 ) {
+ cam = (struct qcm *) uvd->user_data;
+ if (cam->button_sts_buf == 0x88)
+ cam->button_sts = 0x0;
+ else if (cam->button_sts_buf == 0x80)
+ cam->button_sts = 0x1;
+ qcm_report_buttonstat(cam);
+ }
+ }
+
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret < 0)
+ err("usb_submit_urb error (%d)", ret);
+}
+
+static int qcm_setup_input_int(struct qcm *cam, struct uvd *uvd)
+{
+ int errflag;
+ usb_fill_int_urb(cam->button_urb, uvd->dev,
+ usb_rcvintpipe(uvd->dev, uvd->video_endp + 1),
+ &cam->button_sts_buf,
+ 1,
+ qcm_int_irq,
+ uvd, 16);
+
+ errflag = usb_submit_urb(cam->button_urb, GFP_KERNEL);
+ if (errflag)
+ err ("usb_submit_int ret %d", errflag);
+ return errflag;
+}
+
+static void qcm_stop_int_data(struct qcm *cam)
+{
+ usb_kill_urb(cam->button_urb);
+}
+
+static int qcm_alloc_int_urb(struct qcm *cam)
+{
+ cam->button_urb = usb_alloc_urb(0, GFP_KERNEL);
+
+ if (!cam->button_urb)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void qcm_free_int(struct qcm *cam)
+{
+ if (cam->button_urb)
+ usb_free_urb(cam->button_urb);
+}
+#endif /* CONFIG_INPUT */
+
+static int qcm_stv_setb(struct usb_device *dev, u16 reg, u8 val)
+{
+ int ret;
+
+ /* we'll wait up to 3 slices but no more */
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ 0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+ reg, 0, &val, 1, 3*HZ);
+ return ret;
+}
+
+static int qcm_stv_setw(struct usb_device *dev, u16 reg, u16 val)
+{
+ int ret;
+
+ /* we'll wait up to 3 slices but no more */
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ 0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+ reg, 0, &val, 2, 3*HZ);
+ return ret;
+}
+
+static int qcm_stv_getw(struct usb_device *dev, unsigned short reg,
+ __le16 *val)
+{
+ int ret;
+
+ /* we'll wait up to 3 slices but no more */
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ 0x04, USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
+ reg, 0, val, 2, 3*HZ);
+ return ret;
+}
+
+static int qcm_camera_on(struct uvd *uvd)
+{
+ int ret;
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x01));
+ return 0;
+}
+
+static int qcm_camera_off(struct uvd *uvd)
+{
+ int ret;
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
+ return 0;
+}
+
+static void qcm_hsv2rgb(u16 hue, u16 sat, u16 val, u16 *r, u16 *g, u16 *b)
+{
+ unsigned int segment, valsat;
+ signed int h = (signed int) hue;
+ unsigned int s = (sat - 32768) * 2; /* rescale */
+ unsigned int v = val;
+ unsigned int p;
+
+ /*
+ the registers controling gain are 8 bit of which
+ we affect only the last 4 bits with our gain.
+ we know that if saturation is 0, (unsaturated) then
+ we're grayscale (center axis of the colour cone) so
+ we set rgb=value. we use a formula obtained from
+ wikipedia to map the cone to the RGB plane. it's
+ as follows for the human value case of h=0..360,
+ s=0..1, v=0..1
+ h_i = h/60 % 6 , f = h/60 - h_i , p = v(1-s)
+ q = v(1 - f*s) , t = v(1 - (1-f)s)
+ h_i==0 => r=v , g=t, b=p
+ h_i==1 => r=q , g=v, b=p
+ h_i==2 => r=p , g=v, b=t
+ h_i==3 => r=p , g=q, b=v
+ h_i==4 => r=t , g=p, b=v
+ h_i==5 => r=v , g=p, b=q
+ the bottom side (the point) and the stuff just up
+ of that is black so we simplify those two cases.
+ */
+ if (sat < 32768) {
+ /* anything less than this is unsaturated */
+ *r = val;
+ *g = val;
+ *b = val;
+ return;
+ }
+ if (val <= (0xFFFF/8)) {
+ /* anything less than this is black */
+ *r = 0;
+ *g = 0;
+ *b = 0;
+ return;
+ }
+
+ /* the rest of this code is copying tukkat's
+ implementation of the hsv2rgb conversion as taken
+ from qc-usb-messenger code. the 10923 is 0xFFFF/6
+ to divide the cone into 6 sectors. */
+
+ segment = (h + 10923) & 0xFFFF;
+ segment = segment*3 >> 16; /* 0..2: 0=R, 1=G, 2=B */
+ hue -= segment * 21845; /* -10923..10923 */
+ h = hue;
+ h *= 3;
+ valsat = v*s >> 16; /* 0..65534 */
+ p = v - valsat;
+ if (h >= 0) {
+ unsigned int t = v - (valsat * (32769 - h) >> 15);
+ switch (segment) {
+ case 0: /* R-> */
+ *r = v;
+ *g = t;
+ *b = p;
+ break;
+ case 1: /* G-> */
+ *r = p;
+ *g = v;
+ *b = t;
+ break;
+ case 2: /* B-> */
+ *r = t;
+ *g = p;
+ *b = v;
+ break;
+ }
+ } else {
+ unsigned int q = v - (valsat * (32769 + h) >> 15);
+ switch (segment) {
+ case 0: /* ->R */
+ *r = v;
+ *g = p;
+ *b = q;
+ break;
+ case 1: /* ->G */
+ *r = q;
+ *g = v;
+ *b = p;
+ break;
+ case 2: /* ->B */
+ *r = p;
+ *g = q;
+ *b = v;
+ break;
+ }
+ }
+}
+
+static int qcm_sensor_set_gains(struct uvd *uvd, u16 hue,
+ u16 saturation, u16 value)
+{
+ int ret;
+ u16 r=0,g=0,b=0;
+
+ /* this code is based on qc-usb-messenger */
+ qcm_hsv2rgb(hue, saturation, value, &r, &g, &b);
+
+ r >>= 12;
+ g >>= 12;
+ b >>= 12;
+
+ /* min val is 8 */
+ r = max((u16) 8, r);
+ g = max((u16) 8, g);
+ b = max((u16) 8, b);
+
+ r |= 0x30;
+ g |= 0x30;
+ b |= 0x30;
+
+ /* set the r,g,b gain registers */
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x0509, r));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050A, g));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050B, b));
+
+ /* doing as qc-usb did */
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050C, 0x2A));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050D, 0x01));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
+
+ return 0;
+}
+
+static int qcm_sensor_set_exposure(struct uvd *uvd, int exposure)
+{
+ int ret;
+ int formedval;
+
+ /* calculation was from qc-usb-messenger driver */
+ formedval = ( exposure >> 12 );
+
+ /* max value for formedval is 14 */
+ formedval = min(formedval, 14);
+
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev,
+ 0x143A, 0xF0 | formedval));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
+ return 0;
+}
+
+static int qcm_sensor_setlevels(struct uvd *uvd, int brightness, int contrast,
+ int hue, int colour)
+{
+ int ret;
+ /* brightness is exposure, contrast is gain, colour is saturation */
+ CHECK_RET(ret,
+ qcm_sensor_set_exposure(uvd, brightness));
+ CHECK_RET(ret, qcm_sensor_set_gains(uvd, hue, colour, contrast));
+
+ return 0;
+}
+
+static int qcm_sensor_setsize(struct uvd *uvd, u8 size)
+{
+ int ret;
+
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x1505, size));
+ return 0;
+}
+
+static int qcm_sensor_set_shutter(struct uvd *uvd, int whiteness)
+{
+ int ret;
+ /* some rescaling as done by the qc-usb-messenger code */
+ if (whiteness > 0xC000)
+ whiteness = 0xC000 + (whiteness & 0x3FFF)*8;
+
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143D,
+ (whiteness >> 8) & 0xFF));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143E,
+ (whiteness >> 16) & 0x03));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
+
+ return 0;
+}
+
+static int qcm_sensor_init(struct uvd *uvd)
+{
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+ int ret;
+ int i;
+
+ for (i=0; i < sizeof(regval_table)/sizeof(regval_table[0]) ; i++) {
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev,
+ regval_table[i].reg,
+ regval_table[i].val));
+ }
+
+ CHECK_RET(ret, qcm_stv_setw(uvd->dev, 0x15c1,
+ cpu_to_le16(ISOC_PACKET_SIZE)));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x15c3, 0x08));
+ CHECK_RET(ret, ret = qcm_stv_setb(uvd->dev, 0x143f, 0x01));
+
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
+
+ CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
+
+ CHECK_RET(ret, qcm_sensor_setlevels(uvd, uvd->vpic.brightness,
+ uvd->vpic.contrast, uvd->vpic.hue, uvd->vpic.colour));
+
+ CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));
+ CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
+
+ return 0;
+}
+
+static int qcm_set_camera_size(struct uvd *uvd)
+{
+ int ret;
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+
+ CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
+ cam->width = camera_sizes[cam->size].width;
+ cam->height = camera_sizes[cam->size].height;
+ uvd->videosize = VIDEOSIZE(cam->width, cam->height);
+
+ return 0;
+}
+
+static int qcm_setup_on_open(struct uvd *uvd)
+{
+ int ret;
+
+ CHECK_RET(ret, qcm_sensor_set_gains(uvd, uvd->vpic.hue,
+ uvd->vpic.colour, uvd->vpic.contrast));
+ CHECK_RET(ret, qcm_sensor_set_exposure(uvd, uvd->vpic.brightness));
+ CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));
+ CHECK_RET(ret, qcm_set_camera_size(uvd));
+ CHECK_RET(ret, qcm_camera_on(uvd));
+ return 0;
+}
+
+static void qcm_adjust_picture(struct uvd *uvd)
+{
+ int ret;
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+
+ ret = qcm_camera_off(uvd);
+ if (ret) {
+ err("can't turn camera off. abandoning pic adjustment");
+ return;
+ }
+
+ /* if there's been a change in contrast, hue, or
+ colour then we need to recalculate hsv in order
+ to update gains */
+ if ((cam->contrast != uvd->vpic.contrast) ||
+ (cam->hue != uvd->vpic.hue) ||
+ (cam->colour != uvd->vpic.colour)) {
+ cam->contrast = uvd->vpic.contrast;
+ cam->hue = uvd->vpic.hue;
+ cam->colour = uvd->vpic.colour;
+ ret = qcm_sensor_set_gains(uvd, cam->hue, cam->colour,
+ cam->contrast);
+ if (ret) {
+ err("can't set gains. abandoning pic adjustment");
+ return;
+ }
+ }
+
+ if (cam->brightness != uvd->vpic.brightness) {
+ cam->brightness = uvd->vpic.brightness;
+ ret = qcm_sensor_set_exposure(uvd, cam->brightness);
+ if (ret) {
+ err("can't set exposure. abandoning pic adjustment");
+ return;
+ }
+ }
+
+ if (cam->whiteness != uvd->vpic.whiteness) {
+ cam->whiteness = uvd->vpic.whiteness;
+ qcm_sensor_set_shutter(uvd, cam->whiteness);
+ if (ret) {
+ err("can't set shutter. abandoning pic adjustment");
+ return;
+ }
+ }
+
+ ret = qcm_camera_on(uvd);
+ if (ret) {
+ err("can't reenable camera. pic adjustment failed");
+ return;
+ }
+}
+
+static int qcm_process_frame(struct uvd *uvd, u8 *cdata, int framelen)
+{
+ int datalen;
+ int totaldata;
+ struct framehdr {
+ __be16 id;
+ __be16 len;
+ };
+ struct framehdr *fhdr;
+
+ totaldata = 0;
+ while (framelen) {
+ fhdr = (struct framehdr *) cdata;
+ datalen = be16_to_cpu(fhdr->len);
+ framelen -= 4;
+ cdata += 4;
+
+ if ((fhdr->id) == cpu_to_be16(0x8001)) {
+ RingQueue_Enqueue(&uvd->dp, marker, 4);
+ totaldata += 4;
+ continue;
+ }
+ if ((fhdr->id & cpu_to_be16(0xFF00)) == cpu_to_be16(0x0200)) {
+ RingQueue_Enqueue(&uvd->dp, cdata, datalen);
+ totaldata += datalen;
+ }
+ framelen -= datalen;
+ cdata += datalen;
+ }
+ return totaldata;
+}
+
+static int qcm_compress_iso(struct uvd *uvd, struct urb *dataurb)
+{
+ int totlen;
+ int i;
+ unsigned char *cdata;
+
+ totlen=0;
+ for (i = 0; i < dataurb->number_of_packets; i++) {
+ int n = dataurb->iso_frame_desc[i].actual_length;
+ int st = dataurb->iso_frame_desc[i].status;
+
+ cdata = dataurb->transfer_buffer +
+ dataurb->iso_frame_desc[i].offset;
+
+ if (st < 0) {
+ warn("Data error: packet=%d. len=%d. status=%d.",
+ i, n, st);
+ uvd->stats.iso_err_count++;
+ continue;
+ }
+ if (!n)
+ continue;
+
+ totlen += qcm_process_frame(uvd, cdata, n);
+ }
+ return totlen;
+}
+
+static void resubmit_urb(struct uvd *uvd, struct urb *urb)
+{
+ int ret;
+
+ urb->dev = uvd->dev;
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret)
+ err("usb_submit_urb error (%d)", ret);
+}
+
+static void qcm_isoc_irq(struct urb *urb, struct pt_regs *regs)
+{
+ int len;
+ struct uvd *uvd = urb->context;
+
+ if (!CAMERA_IS_OPERATIONAL(uvd))
+ return;
+
+ if (!uvd->streaming)
+ return;
+
+ uvd->stats.urb_count++;
+
+ if (!urb->actual_length) {
+ resubmit_urb(uvd, urb);
+ return;
+ }
+
+ len = qcm_compress_iso(uvd, urb);
+ resubmit_urb(uvd, urb);
+ uvd->stats.urb_length = len;
+ uvd->stats.data_count += len;
+ if (len)
+ RingQueue_WakeUpInterruptible(&uvd->dp);
+}
+
+static int qcm_start_data(struct uvd *uvd)
+{
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+ int i;
+ int errflag;
+ int pktsz;
+ int err;
+
+ pktsz = uvd->iso_packet_len;
+ if (!CAMERA_IS_OPERATIONAL(uvd)) {
+ err("Camera is not operational");
+ return -EFAULT;
+ }
+
+ err = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltActive);
+ if (err < 0) {
+ err("usb_set_interface error");
+ uvd->last_error = err;
+ return -EBUSY;
+ }
+
+ for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+ int j, k;
+ struct urb *urb = uvd->sbuf[i].urb;
+ urb->dev = uvd->dev;
+ urb->context = uvd;
+ urb->pipe = usb_rcvisocpipe(uvd->dev, uvd->video_endp);
+ urb->interval = 1;
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->transfer_buffer = uvd->sbuf[i].data;
+ urb->complete = qcm_isoc_irq;
+ urb->number_of_packets = FRAMES_PER_DESC;
+ urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC;
+ for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) {
+ urb->iso_frame_desc[j].offset = k;
+ urb->iso_frame_desc[j].length = pktsz;
+ }
+ }
+
+ uvd->streaming = 1;
+ uvd->curframe = -1;
+ for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+ errflag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
+ if (errflag)
+ err ("usb_submit_isoc(%d) ret %d", i, errflag);
+ }
+
+ CHECK_RET(err, qcm_setup_input_int(cam, uvd));
+ CHECK_RET(err, qcm_camera_on(uvd));
+ return 0;
+}
+
+static void qcm_stop_data(struct uvd *uvd)
+{
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+ int i, j;
+ int ret;
+
+ if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
+ return;
+
+ ret = qcm_camera_off(uvd);
+ if (ret)
+ warn("couldn't turn the cam off.");
+
+ uvd->streaming = 0;
+
+ /* Unschedule all of the iso td's */
+ for (i=0; i < USBVIDEO_NUMSBUF; i++)
+ usb_kill_urb(uvd->sbuf[i].urb);
+
+ qcm_stop_int_data(cam);
+
+ if (!uvd->remove_pending) {
+ /* Set packet size to 0 */
+ j = usb_set_interface(uvd->dev, uvd->iface,
+ uvd->ifaceAltInactive);
+ if (j < 0) {
+ err("usb_set_interface() error %d.", j);
+ uvd->last_error = j;
+ }
+ }
+}
+
+static void qcm_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame)
+{
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+ int x;
+ struct rgb *rgbL0;
+ struct rgb *rgbL1;
+ struct bayL0 *bayL0;
+ struct bayL1 *bayL1;
+ int hor,ver,hordel,verdel;
+ assert(frame != NULL);
+
+ switch (cam->size) {
+ case SIZE_160X120:
+ hor = 162; ver = 124; hordel = 1; verdel = 2;
+ break;
+ case SIZE_320X240:
+ default:
+ hor = 324; ver = 248; hordel = 2; verdel = 4;
+ break;
+ }
+
+ if (frame->scanstate == ScanState_Scanning) {
+ while (RingQueue_GetLength(&uvd->dp) >=
+ 4 + (hor*verdel + hordel)) {
+ if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
+ (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) &&
+ (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) &&
+ (RING_QUEUE_PEEK(&uvd->dp, 3) == 0xff)) {
+ frame->curline = 0;
+ frame->scanstate = ScanState_Lines;
+ frame->frameState = FrameState_Grabbing;
+ RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4);
+ /*
+ * if we're starting, we need to discard the first
+ * 4 lines of y bayer data
+ * and the first 2 gr elements of x bayer data
+ */
+ RING_QUEUE_DEQUEUE_BYTES(&uvd->dp,
+ (hor*verdel + hordel));
+ break;
+ }
+ RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
+ }
+ }
+
+ if (frame->scanstate == ScanState_Scanning)
+ return;
+
+ /* now we can start processing bayer data so long as we have at least
+ * 2 lines worth of data. this is the simplest demosaicing method that
+ * I could think of. I use each 2x2 bayer element without interpolation
+ * to generate 4 rgb pixels.
+ */
+ while ( frame->curline < cam->height &&
+ (RingQueue_GetLength(&uvd->dp) >= hor*2)) {
+ /* get 2 lines of bayer for demosaicing
+ * into 2 lines of RGB */
+ RingQueue_Dequeue(&uvd->dp, cam->scratch, hor*2);
+ bayL0 = (struct bayL0 *) cam->scratch;
+ bayL1 = (struct bayL1 *) (cam->scratch + hor);
+ /* frame->curline is the rgb y line */
+ rgbL0 = (struct rgb *)
+ ( frame->data + (cam->width*3*frame->curline));
+ /* w/2 because we're already doing 2 pixels */
+ rgbL1 = rgbL0 + (cam->width/2);
+
+ for (x=0; x < cam->width; x+=2) {
+ rgbL0->r = bayL0->r;
+ rgbL0->g = bayL0->g;
+ rgbL0->b = bayL1->b;
+
+ rgbL0->r2 = bayL0->r;
+ rgbL0->g2 = bayL1->g;
+ rgbL0->b2 = bayL1->b;
+
+ rgbL1->r = bayL0->r;
+ rgbL1->g = bayL1->g;
+ rgbL1->b = bayL1->b;
+
+ rgbL1->r2 = bayL0->r;
+ rgbL1->g2 = bayL1->g;
+ rgbL1->b2 = bayL1->b;
+
+ rgbL0++;
+ rgbL1++;
+
+ bayL0++;
+ bayL1++;
+ }
+
+ frame->seqRead_Length += cam->width*3*2;
+ frame->curline += 2;
+ }
+ /* See if we filled the frame */
+ if (frame->curline == cam->height) {
+ frame->frameState = FrameState_Done_Hold;
+ frame->curline = 0;
+ uvd->curframe = -1;
+ uvd->stats.frame_num++;
+ }
+}
+
+/* taken from konicawc */
+static int qcm_set_video_mode(struct uvd *uvd, struct video_window *vw)
+{
+ int ret;
+ int newsize;
+ int oldsize;
+ int x = vw->width;
+ int y = vw->height;
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+
+ if (x > 0 && y > 0) {
+ DEBUG(2, "trying to find size %d,%d", x, y);
+ for (newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) {
+ if ((camera_sizes[newsize].width == x) &&
+ (camera_sizes[newsize].height == y))
+ break;
+ }
+ } else
+ newsize = cam->size;
+
+ if (newsize > MAX_FRAME_SIZE) {
+ DEBUG(1, "couldn't find size %d,%d", x, y);
+ return -EINVAL;
+ }
+
+ if (newsize == cam->size) {
+ DEBUG(1, "Nothing to do");
+ return 0;
+ }
+
+ qcm_stop_data(uvd);
+
+ if (cam->size != newsize) {
+ oldsize = cam->size;
+ cam->size = newsize;
+ ret = qcm_set_camera_size(uvd);
+ if (ret) {
+ err("Couldn't set camera size, err=%d",ret);
+ /* restore the original size */
+ cam->size = oldsize;
+ return ret;
+ }
+ }
+
+ /* Flush the input queue and clear any current frame in progress */
+
+ RingQueue_Flush(&uvd->dp);
+ if (uvd->curframe != -1) {
+ uvd->frame[uvd->curframe].curline = 0;
+ uvd->frame[uvd->curframe].seqRead_Length = 0;
+ uvd->frame[uvd->curframe].seqRead_Index = 0;
+ }
+
+ CHECK_RET(ret, qcm_start_data(uvd));
+ return 0;
+}
+
+static int qcm_configure_video(struct uvd *uvd)
+{
+ int ret;
+ memset(&uvd->vpic, 0, sizeof(uvd->vpic));
+ memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
+
+ uvd->vpic.colour = colour;
+ uvd->vpic.hue = hue;
+ uvd->vpic.brightness = brightness;
+ uvd->vpic.contrast = contrast;
+ uvd->vpic.whiteness = whiteness;
+ uvd->vpic.depth = 24;
+ uvd->vpic.palette = VIDEO_PALETTE_RGB24;
+
+ memset(&uvd->vcap, 0, sizeof(uvd->vcap));
+ strcpy(uvd->vcap.name, "QCM USB Camera");
+ uvd->vcap.type = VID_TYPE_CAPTURE;
+ uvd->vcap.channels = 1;
+ uvd->vcap.audios = 0;
+
+ uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width;
+ uvd->vcap.minheight = camera_sizes[SIZE_160X120].height;
+ uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width;
+ uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height;
+
+ memset(&uvd->vchan, 0, sizeof(uvd->vchan));
+ uvd->vchan.flags = 0 ;
+ uvd->vchan.tuners = 0;
+ uvd->vchan.channel = 0;
+ uvd->vchan.type = VIDEO_TYPE_CAMERA;
+ strcpy(uvd->vchan.name, "Camera");
+
+ CHECK_RET(ret, qcm_sensor_init(uvd));
+ return 0;
+}
+
+static int qcm_probe(struct usb_interface *intf,
+ const struct usb_device_id *devid)
+{
+ int err;
+ struct uvd *uvd;
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct qcm *cam;
+ size_t buffer_size;
+ unsigned char video_ep;
+ struct usb_host_interface *interface;
+ struct usb_endpoint_descriptor *endpoint;
+ int i,j;
+ unsigned int ifacenum, ifacenum_inact=0;
+ __le16 sensor_id;
+
+ /* we don't support multiconfig cams */
+ if (dev->descriptor.bNumConfigurations != 1)
+ return -ENODEV;
+
+ /* first check for the video interface and not
+ * the audio interface */
+ interface = &intf->cur_altsetting[0];
+ if ((interface->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
+ || (interface->desc.bInterfaceSubClass !=
+ USB_CLASS_VENDOR_SPEC))
+ return -ENODEV;
+
+ /*
+ walk through each endpoint in each setting in the interface
+ stop when we find the one that's an isochronous IN endpoint.
+ */
+ for (i=0; i < intf->num_altsetting; i++) {
+ interface = &intf->cur_altsetting[i];
+ ifacenum = interface->desc.bAlternateSetting;
+ /* walk the end points */
+ for (j=0; j < interface->desc.bNumEndpoints; j++) {
+ endpoint = &interface->endpoint[j].desc;
+
+ if ((endpoint->bEndpointAddress &
+ USB_ENDPOINT_DIR_MASK) != USB_DIR_IN)
+ continue; /* not input then not good */
+
+ buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ if (!buffer_size) {
+ ifacenum_inact = ifacenum;
+ continue; /* 0 pkt size is not what we want */
+ }
+
+ if ((endpoint->bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_ISOC) {
+ video_ep = endpoint->bEndpointAddress;
+ /* break out of the search */
+ goto good_videoep;
+ }
+ }
+ }
+ /* failed out since nothing useful was found */
+ err("No suitable endpoint was found\n");
+ return -ENODEV;
+
+good_videoep:
+ /* disable isochronous stream before doing anything else */
+ err = qcm_stv_setb(dev, STV_ISO_ENABLE, 0);
+ if (err < 0) {
+ err("Failed to disable sensor stream");
+ return -EIO;
+ }
+
+ /*
+ Check that this is the same unknown sensor that is known to work. This
+ sensor is suspected to be the ST VV6422C001. I'll check the same value
+ that the qc-usb driver checks. This value is probably not even the
+ sensor ID since it matches the USB dev ID. Oh well. If it doesn't
+ match, it's probably a diff sensor so exit and apologize.
+ */
+ err = qcm_stv_getw(dev, CMOS_SENSOR_IDREV, &sensor_id);
+ if (err < 0) {
+ err("Couldn't read sensor values. Err %d\n",err);
+ return err;
+ }
+ if (sensor_id != cpu_to_le16(0x08F0)) {
+ err("Sensor ID %x != %x. Unsupported. Sorry\n",
+ le16_to_cpu(sensor_id), (0x08F0));
+ return -ENODEV;
+ }
+
+ uvd = usbvideo_AllocateDevice(cams);
+ if (!uvd)
+ return -ENOMEM;
+
+ cam = (struct qcm *) uvd->user_data;
+
+ /* buf for doing demosaicing */
+ cam->scratch = kmalloc(324*2, GFP_KERNEL);
+ if (!cam->scratch) /* uvd freed in dereg */
+ return -ENOMEM;
+
+ /* yes, if we fail after here, cam->scratch gets freed
+ by qcm_free_uvd */
+
+ err = qcm_alloc_int_urb(cam);
+ if (err < 0)
+ return err;
+
+ /* yes, if we fail after here, int urb gets freed
+ by qcm_free_uvd */
+
+ RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240);
+ cam->width = camera_sizes[size].width;
+ cam->height = camera_sizes[size].height;
+ cam->size = size;
+
+ uvd->debug = debug;
+ uvd->flags = 0;
+ uvd->dev = dev;
+ uvd->iface = intf->altsetting->desc.bInterfaceNumber;
+ uvd->ifaceAltActive = ifacenum;
+ uvd->ifaceAltInactive = ifacenum_inact;
+ uvd->video_endp = video_ep;
+ uvd->iso_packet_len = buffer_size;
+ uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
+ uvd->defaultPalette = VIDEO_PALETTE_RGB24;
+ uvd->canvas = VIDEOSIZE(320, 240);
+ uvd->videosize = VIDEOSIZE(cam->width, cam->height);
+ err = qcm_configure_video(uvd);
+ if (err) {
+ err("failed to configure video settings");
+ return err;
+ }
+
+ err = usbvideo_RegisterVideoDevice(uvd);
+ if (err) { /* the uvd gets freed in Deregister */
+ err("usbvideo_RegisterVideoDevice() failed.");
+ return err;
+ }
+
+ uvd->max_frame_size = (320 * 240 * 3);
+ qcm_register_input(cam, dev);
+ usb_set_intfdata(intf, uvd);
+ return 0;
+}
+
+static void qcm_free_uvd(struct uvd *uvd)
+{
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+
+ kfree(cam->scratch);
+ qcm_unregister_input(cam);
+ qcm_free_int(cam);
+}
+
+static struct usbvideo_cb qcm_driver = {
+ .probe = qcm_probe,
+ .setupOnOpen = qcm_setup_on_open,
+ .processData = qcm_process_isoc,
+ .setVideoMode = qcm_set_video_mode,
+ .startDataPump = qcm_start_data,
+ .stopDataPump = qcm_stop_data,
+ .adjustPicture = qcm_adjust_picture,
+ .userFree = qcm_free_uvd
+};
+
+static int __init qcm_init(void)
+{
+ info(DRIVER_DESC " " DRIVER_VERSION);
+
+ return usbvideo_register(
+ &cams,
+ MAX_CAMERAS,
+ sizeof(struct qcm),
+ "QCM",
+ &qcm_driver,
+ THIS_MODULE,
+ qcm_table);
+}
+
+static void __exit qcm_exit(void)
+{
+ usbvideo_Deregister(&cams);
+}
+
+module_param(size, int, 0);
+MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 320x240");
+module_param(colour, int, 0);
+MODULE_PARM_DESC(colour, "Initial colour");
+module_param(hue, int, 0);
+MODULE_PARM_DESC(hue, "Initial hue");
+module_param(brightness, int, 0);
+MODULE_PARM_DESC(brightness, "Initial brightness");
+module_param(contrast, int, 0);
+MODULE_PARM_DESC(contrast, "Initial contrast");
+module_param(whiteness, int, 0);
+MODULE_PARM_DESC(whiteness, "Initial whiteness");
+
+#ifdef CONFIG_USB_DEBUG
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
+#endif
+
+module_init(qcm_init);
+module_exit(qcm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jaya Kumar");
+MODULE_DESCRIPTION("QCM USB Camera");
+MODULE_SUPPORTED_DEVICE("QCM USB Camera");
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.h b/drivers/media/video/usbvideo/quickcam_messenger.h
new file mode 100644
index 0000000..baab9c0
--- /dev/null
+++ b/drivers/media/video/usbvideo/quickcam_messenger.h
@@ -0,0 +1,126 @@
+#ifndef quickcam_messenger_h
+#define quickcam_messenger_h
+
+#ifndef CONFIG_INPUT
+/* if we're not using input we dummy out these functions */
+#define qcm_register_input(...)
+#define qcm_unregister_input(...)
+#define qcm_report_buttonstat(...)
+#define qcm_setup_input_int(...) 0
+#define qcm_stop_int_data(...)
+#define qcm_alloc_int_urb(...) 0
+#define qcm_free_int(...)
+#endif
+
+
+#define CHECK_RET(ret, expr) \
+ if ((ret = expr) < 0) return ret
+
+/* Control Registers for the STVV6422 ASIC
+ * - this define is taken from the qc-usb-messenger code
+ */
+#define STV_ISO_ENABLE 0x1440
+#define ISOC_PACKET_SIZE 1023
+
+/* Chip identification number including revision indicator */
+#define CMOS_SENSOR_IDREV 0xE00A
+
+struct rgb {
+ u8 b;
+ u8 g;
+ u8 r;
+ u8 b2;
+ u8 g2;
+ u8 r2;
+};
+
+struct bayL0 {
+#ifdef __BIG_ENDIAN
+ u8 r;
+ u8 g;
+#elif __LITTLE_ENDIAN
+ u8 g;
+ u8 r;
+#else
+#error not byte order defined
+#endif
+};
+
+struct bayL1 {
+#ifdef __BIG_ENDIAN
+ u8 g;
+ u8 b;
+#elif __LITTLE_ENDIAN
+ u8 b;
+ u8 g;
+#else
+#error not byte order defined
+#endif
+};
+
+struct cam_size {
+ u16 width;
+ u16 height;
+ u8 cmd;
+};
+
+static const struct cam_size camera_sizes[] = {
+ { 160, 120, 0xf },
+ { 320, 240, 0x2 },
+};
+
+enum frame_sizes {
+ SIZE_160X120 = 0,
+ SIZE_320X240 = 1,
+};
+
+#define MAX_FRAME_SIZE SIZE_320X240
+
+struct qcm {
+ u16 colour;
+ u16 hue;
+ u16 brightness;
+ u16 contrast;
+ u16 whiteness;
+
+ u8 size;
+ int height;
+ int width;
+ u8 *scratch;
+ struct urb *button_urb;
+ u8 button_sts;
+ u8 button_sts_buf;
+
+#ifdef CONFIG_INPUT
+ struct input_dev *input;
+ char input_physname[64];
+#endif
+};
+
+struct regval {
+ u16 reg;
+ u8 val;
+};
+/* this table is derived from the
+qc-usb-messenger code */
+static const struct regval regval_table[] = {
+ { STV_ISO_ENABLE, 0x00 },
+ { 0x1436, 0x00 }, { 0x1432, 0x03 },
+ { 0x143a, 0xF9 }, { 0x0509, 0x38 },
+ { 0x050a, 0x38 }, { 0x050b, 0x38 },
+ { 0x050c, 0x2A }, { 0x050d, 0x01 },
+ { 0x1431, 0x00 }, { 0x1433, 0x34 },
+ { 0x1438, 0x18 }, { 0x1439, 0x00 },
+ { 0x143b, 0x05 }, { 0x143c, 0x00 },
+ { 0x143e, 0x01 }, { 0x143d, 0x00 },
+ { 0x1442, 0xe2 }, { 0x1500, 0xd0 },
+ { 0x1500, 0xd0 }, { 0x1500, 0x50 },
+ { 0x1501, 0xaf }, { 0x1502, 0xc2 },
+ { 0x1503, 0x45 }, { 0x1505, 0x02 },
+ { 0x150e, 0x8e }, { 0x150f, 0x37 },
+ { 0x15c0, 0x00 },
+};
+
+static const unsigned char marker[] = { 0x00, 0xff, 0x00, 0xFF };
+
+#endif /* quickcam_messenger_h */
diff --git a/drivers/media/video/usbvideo/usbvideo.h b/drivers/media/video/usbvideo/usbvideo.h
index 3cbf4fc..49dbee5 100644
--- a/drivers/media/video/usbvideo/usbvideo.h
+++ b/drivers/media/video/usbvideo/usbvideo.h
@@ -18,6 +18,7 @@
#include <linux/config.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/usb.h>
#include <linux/mutex.h>
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index 474a29b..19d3c20 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -32,6 +32,7 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <asm/uaccess.h>
#include <asm/system.h>
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index d330fa9..14e5234 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -59,6 +59,7 @@
#include <asm/io.h>
#include <asm/div64.h>
#include <linux/video_decoder.h>
+#define __OLD_VIDIOC_ /* To allow fixing old calls*/
#include <media/v4l2-common.h>
#ifdef CONFIG_KMOD
@@ -293,7 +294,10 @@ static const char *v4l2_ioctls[] = {
#if 1
[_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP",
#endif
- [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS"
+ [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS",
+ [_IOC_NR(VIDIOC_G_EXT_CTRLS)] = "VIDIOC_G_EXT_CTRLS",
+ [_IOC_NR(VIDIOC_S_EXT_CTRLS)] = "VIDIOC_S_EXT_CTRLS",
+ [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS"
};
#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
@@ -331,7 +335,8 @@ static const char *v4l2_int_ioctls[] = {
[_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)] = "VIDIOC_INT_S_AUDIO_ROUTING",
[_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)] = "VIDIOC_INT_G_AUDIO_ROUTING",
[_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)] = "VIDIOC_INT_S_VIDEO_ROUTING",
- [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING"
+ [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING",
+ [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)] = "VIDIOC_INT_S_CRYSTAL_FREQ"
};
#define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls)
@@ -423,7 +428,9 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
case TUNER_SET_TYPE_ADDR:
case TUNER_SET_STANDBY:
case TDA9887_SET_CONFIG:
+#ifdef __OLD_VIDIOC_
case VIDIOC_OVERLAY_OLD:
+#endif
case VIDIOC_STREAMOFF:
case VIDIOC_G_OUTPUT:
case VIDIOC_S_OUTPUT:
@@ -439,7 +446,9 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
case VIDIOC_G_AUDIO:
case VIDIOC_S_AUDIO:
case VIDIOC_ENUMAUDIO:
+#ifdef __OLD_VIDIOC_
case VIDIOC_G_AUDIO_OLD:
+#endif
{
struct v4l2_audio *p=arg;
@@ -450,7 +459,9 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
case VIDIOC_G_AUDOUT:
case VIDIOC_S_AUDOUT:
case VIDIOC_ENUMAUDOUT:
+#ifdef __OLD_VIDIOC_
case VIDIOC_G_AUDOUT_OLD:
+#endif
{
struct v4l2_audioout *p=arg;
printk ("%s: index=%d, name=%s, capability=%d, mode=%d\n", s,
@@ -478,9 +489,9 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
prt_names(p->memory,v4l2_memory_names),
p->m.userptr);
printk ("%s: timecode= %02d:%02d:%02d type=%d, "
- "flags=0x%08x, frames=%d, userbits=0x%p\n",
+ "flags=0x%08x, frames=%d, userbits=0x%08x\n",
s,tc->hours,tc->minutes,tc->seconds,
- tc->type, tc->flags, tc->frames, tc->userbits);
+ tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits);
break;
}
case VIDIOC_QUERYCAP:
@@ -495,12 +506,31 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
}
case VIDIOC_G_CTRL:
case VIDIOC_S_CTRL:
+#ifdef __OLD_VIDIOC_
case VIDIOC_S_CTRL_OLD:
+#endif
{
struct v4l2_control *p=arg;
printk ("%s: id=%d, value=%d\n", s, p->id, p->value);
break;
}
+ case VIDIOC_G_EXT_CTRLS:
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *p = arg;
+ int i;
+
+ printk("%s: ctrl_class=%d, count=%d\n", s, p->ctrl_class, p->count);
+ for (i = 0; i < p->count; i++) {
+ struct v4l2_ext_control *c = &p->controls[i];
+ if (cmd == VIDIOC_G_EXT_CTRLS)
+ printk("%s: id=%d\n", s, c->id);
+ else
+ printk("%s: id=%d, value=%d\n", s, c->id, c->value);
+ }
+ break;
+ }
case VIDIOC_G_CROP:
case VIDIOC_S_CROP:
{
@@ -510,7 +540,9 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
break;
}
case VIDIOC_CROPCAP:
+#ifdef __OLD_VIDIOC_
case VIDIOC_CROPCAP_OLD:
+#endif
{
struct v4l2_cropcap *p=arg;
/*FIXME: Should also show rect structs */
@@ -667,6 +699,12 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
printk ("%s: input=0x%x, output=0x%x\n", s, p->input, p->output);
break;
}
+ case VIDIOC_INT_S_CRYSTAL_FREQ:
+ {
+ struct v4l2_crystal_freq *p=arg;
+ printk ("%s: freq=%u, flags=0x%x\n", s, p->freq, p->flags);
+ break;
+ }
case VIDIOC_G_SLICED_VBI_CAP:
{
struct v4l2_sliced_vbi_cap *p=arg;
@@ -696,7 +734,9 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
}
case VIDIOC_G_PARM:
case VIDIOC_S_PARM:
+#ifdef __OLD_VIDIOC_
case VIDIOC_S_PARM_OLD:
+#endif
{
struct v4l2_streamparm *p=arg;
printk ("%s: type=%d\n", s, p->type);
@@ -915,6 +955,484 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
/* ----------------------------------------------------------------- */
+/* Helper functions for control handling */
+
+/* Check for correctness of the ctrl's value based on the data from
+ struct v4l2_queryctrl and the available menu items. Note that
+ menu_items may be NULL, in that case it is ignored. */
+int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
+ const char **menu_items)
+{
+ if (qctrl->flags & V4L2_CTRL_FLAG_DISABLED)
+ return -EINVAL;
+ if (qctrl->flags & V4L2_CTRL_FLAG_GRABBED)
+ return -EBUSY;
+ if (qctrl->type == V4L2_CTRL_TYPE_BUTTON ||
+ qctrl->type == V4L2_CTRL_TYPE_INTEGER64 ||
+ qctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
+ return 0;
+ if (ctrl->value < qctrl->minimum || ctrl->value > qctrl->maximum)
+ return -ERANGE;
+ if (qctrl->type == V4L2_CTRL_TYPE_MENU && menu_items != NULL) {
+ if (menu_items[ctrl->value] == NULL ||
+ menu_items[ctrl->value][0] == '\0')
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* Returns NULL or a character pointer array containing the menu for
+ the given control ID. The pointer array ends with a NULL pointer.
+ An empty string signifies a menu entry that is invalid. This allows
+ drivers to disable certain options if it is not supported. */
+const char **v4l2_ctrl_get_menu(u32 id)
+{
+ static const char *mpeg_audio_sampling_freq[] = {
+ "44.1 kHz",
+ "48 kHz",
+ "32 kHz",
+ NULL
+ };
+ static const char *mpeg_audio_encoding[] = {
+ "Layer I",
+ "Layer II",
+ "Layer III",
+ NULL
+ };
+ static const char *mpeg_audio_l1_bitrate[] = {
+ "32 kbps",
+ "64 kbps",
+ "96 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "288 kbps",
+ "320 kbps",
+ "352 kbps",
+ "384 kbps",
+ "416 kbps",
+ "448 kbps",
+ NULL
+ };
+ static const char *mpeg_audio_l2_bitrate[] = {
+ "32 kbps",
+ "48 kbps",
+ "56 kbps",
+ "64 kbps",
+ "80 kbps",
+ "96 kbps",
+ "112 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "320 kbps",
+ "384 kbps",
+ NULL
+ };
+ static const char *mpeg_audio_l3_bitrate[] = {
+ "32 kbps",
+ "40 kbps",
+ "48 kbps",
+ "56 kbps",
+ "64 kbps",
+ "80 kbps",
+ "96 kbps",
+ "112 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "320 kbps",
+ NULL
+ };
+ static const char *mpeg_audio_mode[] = {
+ "Stereo",
+ "Joint Stereo",
+ "Dual",
+ "Mono",
+ NULL
+ };
+ static const char *mpeg_audio_mode_extension[] = {
+ "Bound 4",
+ "Bound 8",
+ "Bound 12",
+ "Bound 16",
+ NULL
+ };
+ static const char *mpeg_audio_emphasis[] = {
+ "No Emphasis",
+ "50/15 us",
+ "CCITT J17",
+ NULL
+ };
+ static const char *mpeg_audio_crc[] = {
+ "No CRC",
+ "16-bit CRC",
+ NULL
+ };
+ static const char *mpeg_video_encoding[] = {
+ "MPEG-1",
+ "MPEG-2",
+ NULL
+ };
+ static const char *mpeg_video_aspect[] = {
+ "1x1",
+ "4x3",
+ "16x9",
+ "2.21x1",
+ NULL
+ };
+ static const char *mpeg_video_bitrate_mode[] = {
+ "Variable Bitrate",
+ "Constant Bitrate",
+ NULL
+ };
+ static const char *mpeg_stream_type[] = {
+ "MPEG-2 Program Stream",
+ "MPEG-2 Transport Stream",
+ "MPEG-1 System Stream",
+ "MPEG-2 DVD-compatible Stream",
+ "MPEG-1 VCD-compatible Stream",
+ "MPEG-2 SVCD-compatible Stream",
+ NULL
+ };
+
+ switch (id) {
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ return mpeg_audio_sampling_freq;
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ return mpeg_audio_encoding;
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ return mpeg_audio_l1_bitrate;
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ return mpeg_audio_l2_bitrate;
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ return mpeg_audio_l3_bitrate;
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ return mpeg_audio_mode;
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ return mpeg_audio_mode_extension;
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ return mpeg_audio_emphasis;
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ return mpeg_audio_crc;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ return mpeg_video_encoding;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ return mpeg_video_aspect;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ return mpeg_video_bitrate_mode;
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ return mpeg_stream_type;
+ default:
+ return NULL;
+ }
+}
+
+/* Fill in a struct v4l2_queryctrl */
+int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
+{
+ const char *name;
+
+ qctrl->flags = 0;
+ switch (qctrl->id) {
+ /* USER controls */
+ case V4L2_CID_USER_CLASS: name = "User Controls"; break;
+ case V4L2_CID_AUDIO_VOLUME: name = "Volume"; break;
+ case V4L2_CID_AUDIO_MUTE: name = "Mute"; break;
+ case V4L2_CID_AUDIO_BALANCE: name = "Balance"; break;
+ case V4L2_CID_AUDIO_BASS: name = "Bass"; break;
+ case V4L2_CID_AUDIO_TREBLE: name = "Treble"; break;
+ case V4L2_CID_AUDIO_LOUDNESS: name = "Loudness"; break;
+ case V4L2_CID_BRIGHTNESS: name = "Brightness"; break;
+ case V4L2_CID_CONTRAST: name = "Contrast"; break;
+ case V4L2_CID_SATURATION: name = "Saturation"; break;
+ case V4L2_CID_HUE: name = "Hue"; break;
+
+ /* MPEG controls */
+ case V4L2_CID_MPEG_CLASS: name = "MPEG Encoder Controls"; break;
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: name = "Audio Sampling Frequency"; break;
+ case V4L2_CID_MPEG_AUDIO_ENCODING: name = "Audio Encoding Layer"; break;
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE: name = "Audio Layer I Bitrate"; break;
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE: name = "Audio Layer II Bitrate"; break;
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE: name = "Audio Layer III Bitrate"; break;
+ case V4L2_CID_MPEG_AUDIO_MODE: name = "Audio Stereo Mode"; break;
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: name = "Audio Stereo Mode Extension"; break;
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS: name = "Audio Emphasis"; break;
+ case V4L2_CID_MPEG_AUDIO_CRC: name = "Audio CRC"; break;
+ case V4L2_CID_MPEG_VIDEO_ENCODING: name = "Video Encoding"; break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT: name = "Video Aspect"; break;
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES: name = "Video B Frames"; break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE: name = "Video GOP Size"; break;
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: name = "Video GOP Closure"; break;
+ case V4L2_CID_MPEG_VIDEO_PULLDOWN: name = "Video Pulldown"; break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: name = "Video Bitrate Mode"; break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE: name = "Video Bitrate"; break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: name = "Video Peak Bitrate"; break;
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: name = "Video Temporal Decimation"; break;
+ case V4L2_CID_MPEG_STREAM_TYPE: name = "Stream Type"; break;
+ case V4L2_CID_MPEG_STREAM_PID_PMT: name = "Stream PMT Program ID"; break;
+ case V4L2_CID_MPEG_STREAM_PID_AUDIO: name = "Stream Audio Program ID"; break;
+ case V4L2_CID_MPEG_STREAM_PID_VIDEO: name = "Stream Video Program ID"; break;
+ case V4L2_CID_MPEG_STREAM_PID_PCR: name = "Stream PCR Program ID"; break;
+ case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: name = "Stream PES Audio ID"; break;
+ case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: name = "Stream PES Video ID"; break;
+
+ default:
+ return -EINVAL;
+ }
+ switch (qctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+ qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
+ min = 0;
+ max = step = 1;
+ break;
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ qctrl->type = V4L2_CTRL_TYPE_MENU;
+ step = 1;
+ break;
+ case V4L2_CID_USER_CLASS:
+ case V4L2_CID_MPEG_CLASS:
+ qctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS;
+ qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ min = max = step = def = 0;
+ break;
+ default:
+ qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ break;
+ }
+ switch (qctrl->id) {
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ qctrl->flags |= V4L2_CTRL_FLAG_UPDATE;
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ break;
+ }
+ qctrl->minimum = min;
+ qctrl->maximum = max;
+ qctrl->step = step;
+ qctrl->default_value = def;
+ qctrl->reserved[0] = qctrl->reserved[1] = 0;
+ snprintf(qctrl->name, sizeof(qctrl->name), name);
+ return 0;
+}
+
+/* Fill in a struct v4l2_queryctrl with standard values based on
+ the control ID. */
+int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl)
+{
+ switch (qctrl->id) {
+ /* USER controls */
+ case V4L2_CID_USER_CLASS:
+ case V4L2_CID_MPEG_CLASS:
+ return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0);
+ case V4L2_CID_AUDIO_VOLUME:
+ return v4l2_ctrl_query_fill(qctrl, 0, 65535, 65535 / 100, 58880);
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+ return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ return v4l2_ctrl_query_fill(qctrl, 0, 65535, 65535 / 100, 32768);
+ case V4L2_CID_BRIGHTNESS:
+ return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ return v4l2_ctrl_query_fill(qctrl, 0, 127, 1, 64);
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill(qctrl, -128, 127, 1, 0);
+
+ /* MPEG controls */
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 1,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_1,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_3, 1,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_L1_BITRATE_32K,
+ V4L2_MPEG_AUDIO_L1_BITRATE_448K, 1,
+ V4L2_MPEG_AUDIO_L1_BITRATE_256K);
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_L2_BITRATE_32K,
+ V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
+ V4L2_MPEG_AUDIO_L2_BITRATE_224K);
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_L3_BITRATE_32K,
+ V4L2_MPEG_AUDIO_L3_BITRATE_320K, 1,
+ V4L2_MPEG_AUDIO_L3_BITRATE_192K);
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_MODE_STEREO,
+ V4L2_MPEG_AUDIO_MODE_MONO, 1,
+ V4L2_MPEG_AUDIO_MODE_STEREO);
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 1,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4);
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_EMPHASIS_NONE,
+ V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 1,
+ V4L2_MPEG_AUDIO_EMPHASIS_NONE);
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_CRC_NONE,
+ V4L2_MPEG_AUDIO_CRC_CRC16, 1,
+ V4L2_MPEG_AUDIO_CRC_NONE);
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_VIDEO_ASPECT_1x1,
+ V4L2_MPEG_VIDEO_ASPECT_221x100, 1,
+ V4L2_MPEG_VIDEO_ASPECT_4x3);
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ return v4l2_ctrl_query_fill(qctrl, 0, 33, 1, 2);
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ return v4l2_ctrl_query_fill(qctrl, 1, 34, 1, 12);
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1);
+ case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+ return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000);
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000);
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+ return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, 1,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
+ case V4L2_CID_MPEG_STREAM_PID_PMT:
+ return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 16);
+ case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+ return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 260);
+ case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+ return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 256);
+ case V4L2_CID_MPEG_STREAM_PID_PCR:
+ return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 259);
+ case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO:
+ return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+ case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO:
+ return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+ default:
+ return -EINVAL;
+ }
+}
+
+/* Fill in a struct v4l2_querymenu based on the struct v4l2_queryctrl and
+ the menu. The qctrl pointer may be NULL, in which case it is ignored. */
+int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qctrl,
+ const char **menu_items)
+{
+ int i;
+
+ if (menu_items == NULL ||
+ (qctrl && (qmenu->index < qctrl->minimum || qmenu->index > qctrl->maximum)))
+ return -EINVAL;
+ for (i = 0; i < qmenu->index && menu_items[i]; i++) ;
+ if (menu_items[i] == NULL || menu_items[i][0] == '\0')
+ return -EINVAL;
+ snprintf(qmenu->name, sizeof(qmenu->name), menu_items[qmenu->index]);
+ qmenu->reserved = 0;
+ return 0;
+}
+
+/* ctrl_classes points to an array of u32 pointers, the last element is
+ a NULL pointer. Each u32 array is a 0-terminated array of control IDs.
+ Each array must be sorted low to high and belong to the same control
+ class. The array of u32 pointer must also be sorted, from low class IDs
+ to high class IDs.
+
+ This function returns the first ID that follows after the given ID.
+ When no more controls are available 0 is returned. */
+u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
+{
+ u32 ctrl_class;
+ const u32 *pctrl;
+
+ /* if no query is desired, then just return the control ID */
+ if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0)
+ return id;
+ if (ctrl_classes == NULL)
+ return 0;
+ id &= V4L2_CTRL_ID_MASK;
+ ctrl_class = V4L2_CTRL_ID2CLASS(id);
+ id++; /* select next control */
+ /* find first class that matches (or is greater than) the class of
+ the ID */
+ while (*ctrl_classes && V4L2_CTRL_ID2CLASS(**ctrl_classes) < ctrl_class)
+ ctrl_classes++;
+ /* no more classes */
+ if (*ctrl_classes == NULL)
+ return 0;
+ pctrl = *ctrl_classes;
+ /* find first ctrl within the class that is >= ID */
+ while (*pctrl && *pctrl < id) pctrl++;
+ if (*pctrl)
+ return *pctrl;
+ /* we are at the end of the controls of the current class. */
+ /* continue with next class if available */
+ ctrl_classes++;
+ if (*ctrl_classes == NULL)
+ return 0;
+ return **ctrl_classes;
+}
+
+/* ----------------------------------------------------------------- */
+
EXPORT_SYMBOL(v4l2_video_std_construct);
EXPORT_SYMBOL(v4l2_prio_init);
@@ -929,6 +1447,13 @@ EXPORT_SYMBOL(v4l2_type_names);
EXPORT_SYMBOL(v4l_printk_ioctl);
EXPORT_SYMBOL(v4l_printk_ioctl_arg);
+EXPORT_SYMBOL(v4l2_ctrl_next);
+EXPORT_SYMBOL(v4l2_ctrl_check);
+EXPORT_SYMBOL(v4l2_ctrl_get_menu);
+EXPORT_SYMBOL(v4l2_ctrl_query_menu);
+EXPORT_SYMBOL(v4l2_ctrl_query_fill);
+EXPORT_SYMBOL(v4l2_ctrl_query_fill_std);
+
/*
* Local variables:
* c-basic-offset: 8
diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c
index caf3e7e..7ee8a53 100644
--- a/drivers/media/video/video-buf-dvb.c
+++ b/drivers/media/video/video-buf-dvb.c
@@ -135,14 +135,15 @@ static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed)
int videobuf_dvb_register(struct videobuf_dvb *dvb,
struct module *module,
- void *adapter_priv)
+ void *adapter_priv,
+ struct device *device)
{
int result;
mutex_init(&dvb->lock);
/* register adapter */
- result = dvb_register_adapter(&dvb->adapter, dvb->name, module);
+ result = dvb_register_adapter(&dvb->adapter, dvb->name, module, device);
if (result < 0) {
printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
dvb->name, result);
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index 5f87dd5..2dfa7f2 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -1,20 +1,31 @@
/*
- * Video capture interface for Linux
+ * Video capture interface for Linux version 2
*
- * A generic video device interface for the LINUX operating system
- * using a set of device structures/vectors for low level operations.
+ * A generic video device interface for the LINUX operating system
+ * using a set of device structures/vectors for low level operations.
*
- * 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 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.
*
- * Author: Alan Cox, <alan@redhat.com>
+ * Authors: Alan Cox, <alan@redhat.com> (version 1)
+ * Mauro Carvalho Chehab <mchehab@infradead.org> (version 2)
*
* Fixes: 20000516 Claudio Matsuoka <claudio@conectiva.com>
* - Added procfs support
*/
+#define dbgarg(cmd, fmt, arg...) \
+ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \
+ printk (KERN_DEBUG "%s: ", vfd->name); \
+ v4l_printk_ioctl(cmd); \
+ printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
+
+#define dbgarg2(fmt, arg...) \
+ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \
+ printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
+
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -30,7 +41,13 @@
#include <asm/uaccess.h>
#include <asm/system.h>
+#define __OLD_VIDIOC_ /* To allow fixing old calls*/
+#include <linux/videodev2.h>
+
+#ifdef CONFIG_VIDEO_V4L1
#include <linux/videodev.h>
+#endif
+#include <media/v4l2-common.h>
#define VIDEO_NUM_DEVICES 256
#define VIDEO_NAME "video4linux"
@@ -41,7 +58,8 @@
static ssize_t show_name(struct class_device *cd, char *buf)
{
- struct video_device *vfd = container_of(cd, struct video_device, class_dev);
+ struct video_device *vfd = container_of(cd, struct video_device,
+ class_dev);
return sprintf(buf,"%.*s\n",(int)sizeof(vfd->name),vfd->name);
}
@@ -62,7 +80,8 @@ void video_device_release(struct video_device *vfd)
static void video_release(struct class_device *cd)
{
- struct video_device *vfd = container_of(cd, struct video_device, class_dev);
+ struct video_device *vfd = container_of(cd, struct video_device,
+ class_dev);
#if 1
/* needed until all drivers are fixed */
@@ -90,7 +109,7 @@ struct video_device* video_devdata(struct file *file)
}
/*
- * Open a video device.
+ * Open a video device - FIXME: Obsoleted
*/
static int video_open(struct inode *inode, struct file *file)
{
@@ -130,6 +149,7 @@ static int video_open(struct inode *inode, struct file *file)
* helper function -- handles userspace copying for ioctl arguments
*/
+#ifdef __OLD_VIDIOC_
static unsigned int
video_fix_command(unsigned int cmd)
{
@@ -155,7 +175,11 @@ video_fix_command(unsigned int cmd)
}
return cmd;
}
+#endif
+/*
+ * Obsolete usercopy function - Should be removed soon
+ */
int
video_usercopy(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg,
@@ -166,8 +190,15 @@ video_usercopy(struct inode *inode, struct file *file,
void *mbuf = NULL;
void *parg = NULL;
int err = -EINVAL;
+ int is_ext_ctrl;
+ size_t ctrls_size = 0;
+ void __user *user_ptr = NULL;
+#ifdef __OLD_VIDIOC_
cmd = video_fix_command(cmd);
+#endif
+ is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
+ cmd == VIDIOC_TRY_EXT_CTRLS);
/* Copy arguments into temp kernel buffer */
switch (_IOC_DIR(cmd)) {
@@ -193,14 +224,43 @@ video_usercopy(struct inode *inode, struct file *file,
goto out;
break;
}
+ if (is_ext_ctrl) {
+ struct v4l2_ext_controls *p = parg;
+
+ /* In case of an error, tell the caller that it wasn't
+ a specific control that caused it. */
+ p->error_idx = p->count;
+ user_ptr = (void __user *)p->controls;
+ if (p->count) {
+ ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
+ /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
+ mbuf = kmalloc(ctrls_size, GFP_KERNEL);
+ err = -ENOMEM;
+ if (NULL == mbuf)
+ goto out_ext_ctrl;
+ err = -EFAULT;
+ if (copy_from_user(mbuf, user_ptr, ctrls_size))
+ goto out_ext_ctrl;
+ p->controls = mbuf;
+ }
+ }
/* call driver */
err = func(inode, file, cmd, parg);
if (err == -ENOIOCTLCMD)
err = -EINVAL;
+ if (is_ext_ctrl) {
+ struct v4l2_ext_controls *p = parg;
+
+ p->controls = (void *)user_ptr;
+ if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
+ err = -EFAULT;
+ goto out_ext_ctrl;
+ }
if (err < 0)
goto out;
+out_ext_ctrl:
/* Copy results into user buffer */
switch (_IOC_DIR(cmd))
{
@@ -218,6 +278,7 @@ out:
/*
* open/release helper functions -- handle exclusive opens
+ * Should be removed soon
*/
int video_exclusive_open(struct inode *inode, struct file *file)
{
@@ -242,6 +303,1184 @@ int video_exclusive_release(struct inode *inode, struct file *file)
return 0;
}
+static char *v4l2_memory_names[] = {
+ [V4L2_MEMORY_MMAP] = "mmap",
+ [V4L2_MEMORY_USERPTR] = "userptr",
+ [V4L2_MEMORY_OVERLAY] = "overlay",
+};
+
+
+/* FIXME: Those stuff are replicated also on v4l2-common.c */
+static char *v4l2_type_names_FIXME[] = {
+ [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap",
+ [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over",
+ [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out",
+ [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap",
+ [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out",
+ [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out",
+ [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-capture",
+ [V4L2_BUF_TYPE_PRIVATE] = "private",
+};
+
+static char *v4l2_field_names_FIXME[] = {
+ [V4L2_FIELD_ANY] = "any",
+ [V4L2_FIELD_NONE] = "none",
+ [V4L2_FIELD_TOP] = "top",
+ [V4L2_FIELD_BOTTOM] = "bottom",
+ [V4L2_FIELD_INTERLACED] = "interlaced",
+ [V4L2_FIELD_SEQ_TB] = "seq-tb",
+ [V4L2_FIELD_SEQ_BT] = "seq-bt",
+ [V4L2_FIELD_ALTERNATE] = "alternate",
+};
+
+#define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown"
+
+static void dbgbuf(unsigned int cmd, struct video_device *vfd,
+ struct v4l2_buffer *p)
+{
+ struct v4l2_timecode *tc=&p->timecode;
+
+ dbgarg (cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, "
+ "bytesused=%d, flags=0x%08d, "
+ "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx\n",
+ (p->timestamp.tv_sec/3600),
+ (int)(p->timestamp.tv_sec/60)%60,
+ (int)(p->timestamp.tv_sec%60),
+ p->timestamp.tv_usec,
+ p->index,
+ prt_names(p->type,v4l2_type_names_FIXME),
+ p->bytesused,p->flags,
+ p->field,p->sequence,
+ prt_names(p->memory,v4l2_memory_names),
+ p->m.userptr);
+ dbgarg2 ("timecode= %02d:%02d:%02d type=%d, "
+ "flags=0x%08d, frames=%d, userbits=0x%08x\n",
+ tc->hours,tc->minutes,tc->seconds,
+ tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits);
+}
+
+static inline void dbgrect(struct video_device *vfd, char *s,
+ struct v4l2_rect *r)
+{
+ dbgarg2 ("%sRect start at %dx%d, size= %dx%d\n", s, r->left, r->top,
+ r->width, r->height);
+};
+
+static inline void v4l_print_pix_fmt (struct video_device *vfd,
+ struct v4l2_pix_format *fmt)
+{
+ dbgarg2 ("width=%d, height=%d, format=0x%08x, field=%s, "
+ "bytesperline=%d sizeimage=%d, colorspace=%d\n",
+ fmt->width,fmt->height,fmt->pixelformat,
+ prt_names(fmt->field,v4l2_field_names_FIXME),
+ fmt->bytesperline,fmt->sizeimage,fmt->colorspace);
+};
+
+
+static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type)
+{
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if (vfd->vidioc_try_fmt_cap)
+ return (0);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ if (vfd->vidioc_try_fmt_overlay)
+ return (0);
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (vfd->vidioc_try_fmt_vbi)
+ return (0);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ if (vfd->vidioc_try_fmt_vbi_output)
+ return (0);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ if (vfd->vidioc_try_fmt_vbi_capture)
+ return (0);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ if (vfd->vidioc_try_fmt_video_output)
+ return (0);
+ break;
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ if (vfd->vidioc_try_fmt_vbi_output)
+ return (0);
+ break;
+ case V4L2_BUF_TYPE_PRIVATE:
+ if (vfd->vidioc_try_fmt_type_private)
+ return (0);
+ break;
+ }
+ return (-EINVAL);
+}
+
+static int __video_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ struct video_device *vfd = video_devdata(file);
+ void *fh = file->private_data;
+ int ret = -EINVAL;
+
+ if ( (vfd->debug & V4L2_DEBUG_IOCTL) &&
+ !(vfd->debug | V4L2_DEBUG_IOCTL_ARG)) {
+ v4l_print_ioctl(vfd->name, cmd);
+ }
+
+ switch(cmd) {
+ /* --- capabilities ------------------------------------------ */
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *cap = (struct v4l2_capability*)arg;
+ memset(cap, 0, sizeof(*cap));
+
+ if (!vfd->vidioc_querycap)
+ break;
+
+ ret=vfd->vidioc_querycap(file, fh, cap);
+ if (!ret)
+ dbgarg (cmd, "driver=%s, card=%s, bus=%s, "
+ "version=0x%08x, "
+ "capabilities=0x%08x\n",
+ cap->driver,cap->card,cap->bus_info,
+ cap->version,
+ cap->capabilities);
+ break;
+ }
+
+ /* --- priority ------------------------------------------ */
+ case VIDIOC_G_PRIORITY:
+ {
+ enum v4l2_priority *p=arg;
+
+ if (!vfd->vidioc_g_priority)
+ break;
+ ret=vfd->vidioc_g_priority(file, fh, p);
+ if (!ret)
+ dbgarg(cmd, "priority is %d\n", *p);
+ break;
+ }
+ case VIDIOC_S_PRIORITY:
+ {
+ enum v4l2_priority *p=arg;
+
+ if (!vfd->vidioc_s_priority)
+ break;
+ dbgarg(cmd, "setting priority to %d\n", *p);
+ ret=vfd->vidioc_s_priority(file, fh, *p);
+ break;
+ }
+
+ /* --- capture ioctls ---------------------------------------- */
+ case VIDIOC_ENUM_FMT:
+ {
+ struct v4l2_fmtdesc *f = arg;
+ enum v4l2_buf_type type;
+ unsigned int index;
+
+ index = f->index;
+ type = f->type;
+ memset(f,0,sizeof(*f));
+ f->index = index;
+ f->type = type;
+
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if (vfd->vidioc_enum_fmt_cap)
+ ret=vfd->vidioc_enum_fmt_cap(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ if (vfd->vidioc_enum_fmt_overlay)
+ ret=vfd->vidioc_enum_fmt_overlay(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (vfd->vidioc_enum_fmt_vbi)
+ ret=vfd->vidioc_enum_fmt_vbi(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ if (vfd->vidioc_enum_fmt_vbi_output)
+ ret=vfd->vidioc_enum_fmt_vbi_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ if (vfd->vidioc_enum_fmt_vbi_capture)
+ ret=vfd->vidioc_enum_fmt_vbi_capture(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ if (vfd->vidioc_enum_fmt_video_output)
+ ret=vfd->vidioc_enum_fmt_video_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ if (vfd->vidioc_enum_fmt_vbi_output)
+ ret=vfd->vidioc_enum_fmt_vbi_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_PRIVATE:
+ if (vfd->vidioc_enum_fmt_type_private)
+ ret=vfd->vidioc_enum_fmt_type_private(file,
+ fh, f);
+ break;
+ }
+ if (!ret)
+ dbgarg (cmd, "index=%d, type=%d, flags=%d, "
+ "description=%s,"
+ " pixelformat=0x%8x\n",
+ f->index, f->type, f->flags,
+ f->description,
+ f->pixelformat);
+
+ break;
+ }
+ case VIDIOC_G_FMT:
+ {
+ struct v4l2_format *f = (struct v4l2_format *)arg;
+ enum v4l2_buf_type type=f->type;
+
+ memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
+ f->type=type;
+
+ /* FIXME: Should be one dump per type */
+ dbgarg (cmd, "type=%s\n", prt_names(type,
+ v4l2_type_names_FIXME));
+
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if (vfd->vidioc_g_fmt_cap)
+ ret=vfd->vidioc_g_fmt_cap(file, fh, f);
+ if (!ret)
+ v4l_print_pix_fmt(vfd,&f->fmt.pix);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ if (vfd->vidioc_g_fmt_overlay)
+ ret=vfd->vidioc_g_fmt_overlay(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (vfd->vidioc_g_fmt_vbi)
+ ret=vfd->vidioc_g_fmt_vbi(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ if (vfd->vidioc_g_fmt_vbi_output)
+ ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ if (vfd->vidioc_g_fmt_vbi_capture)
+ ret=vfd->vidioc_g_fmt_vbi_capture(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ if (vfd->vidioc_g_fmt_video_output)
+ ret=vfd->vidioc_g_fmt_video_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ if (vfd->vidioc_g_fmt_vbi_output)
+ ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_PRIVATE:
+ if (vfd->vidioc_g_fmt_type_private)
+ ret=vfd->vidioc_g_fmt_type_private(file,
+ fh, f);
+ break;
+ }
+
+ break;
+ }
+ case VIDIOC_S_FMT:
+ {
+ struct v4l2_format *f = (struct v4l2_format *)arg;
+
+ /* FIXME: Should be one dump per type */
+ dbgarg (cmd, "type=%s\n", prt_names(f->type,
+ v4l2_type_names_FIXME));
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ v4l_print_pix_fmt(vfd,&f->fmt.pix);
+ if (vfd->vidioc_s_fmt_cap)
+ ret=vfd->vidioc_s_fmt_cap(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ if (vfd->vidioc_s_fmt_overlay)
+ ret=vfd->vidioc_s_fmt_overlay(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (vfd->vidioc_s_fmt_vbi)
+ ret=vfd->vidioc_s_fmt_vbi(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ if (vfd->vidioc_s_fmt_vbi_output)
+ ret=vfd->vidioc_s_fmt_vbi_output(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ if (vfd->vidioc_s_fmt_vbi_capture)
+ ret=vfd->vidioc_s_fmt_vbi_capture(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ if (vfd->vidioc_s_fmt_video_output)
+ ret=vfd->vidioc_s_fmt_video_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ if (vfd->vidioc_s_fmt_vbi_output)
+ ret=vfd->vidioc_s_fmt_vbi_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_PRIVATE:
+ if (vfd->vidioc_s_fmt_type_private)
+ ret=vfd->vidioc_s_fmt_type_private(file,
+ fh, f);
+ break;
+ }
+ break;
+ }
+ case VIDIOC_TRY_FMT:
+ {
+ struct v4l2_format *f = (struct v4l2_format *)arg;
+
+ /* FIXME: Should be one dump per type */
+ dbgarg (cmd, "type=%s\n", prt_names(f->type,
+ v4l2_type_names_FIXME));
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if (vfd->vidioc_try_fmt_cap)
+ ret=vfd->vidioc_try_fmt_cap(file, fh, f);
+ if (!ret)
+ v4l_print_pix_fmt(vfd,&f->fmt.pix);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ if (vfd->vidioc_try_fmt_overlay)
+ ret=vfd->vidioc_try_fmt_overlay(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (vfd->vidioc_try_fmt_vbi)
+ ret=vfd->vidioc_try_fmt_vbi(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ if (vfd->vidioc_try_fmt_vbi_output)
+ ret=vfd->vidioc_try_fmt_vbi_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ if (vfd->vidioc_try_fmt_vbi_capture)
+ ret=vfd->vidioc_try_fmt_vbi_capture(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ if (vfd->vidioc_try_fmt_video_output)
+ ret=vfd->vidioc_try_fmt_video_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ if (vfd->vidioc_try_fmt_vbi_output)
+ ret=vfd->vidioc_try_fmt_vbi_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_PRIVATE:
+ if (vfd->vidioc_try_fmt_type_private)
+ ret=vfd->vidioc_try_fmt_type_private(file,
+ fh, f);
+ break;
+ }
+
+ break;
+ }
+ /* FIXME: Those buf reqs could be handled here,
+ with some changes on videobuf to allow its header to be included at
+ videodev2.h or being merged at videodev2.
+ */
+ case VIDIOC_REQBUFS:
+ {
+ struct v4l2_requestbuffers *p=arg;
+
+ if (!vfd->vidioc_reqbufs)
+ break;
+ ret = check_fmt (vfd, p->type);
+ if (ret)
+ break;
+
+ ret=vfd->vidioc_reqbufs(file, fh, p);
+ dbgarg (cmd, "count=%d, type=%s, memory=%s\n",
+ p->count,
+ prt_names(p->type,v4l2_type_names_FIXME),
+ prt_names(p->memory,v4l2_memory_names));
+ break;
+ }
+ case VIDIOC_QUERYBUF:
+ {
+ struct v4l2_buffer *p=arg;
+
+ if (!vfd->vidioc_querybuf)
+ break;
+ ret = check_fmt (vfd, p->type);
+ if (ret)
+ break;
+
+ ret=vfd->vidioc_querybuf(file, fh, p);
+ if (!ret)
+ dbgbuf(cmd,vfd,p);
+ break;
+ }
+ case VIDIOC_QBUF:
+ {
+ struct v4l2_buffer *p=arg;
+
+ if (!vfd->vidioc_qbuf)
+ break;
+ ret = check_fmt (vfd, p->type);
+ if (ret)
+ break;
+
+ ret=vfd->vidioc_qbuf(file, fh, p);
+ if (!ret)
+ dbgbuf(cmd,vfd,p);
+ break;
+ }
+ case VIDIOC_DQBUF:
+ {
+ struct v4l2_buffer *p=arg;
+ if (!vfd->vidioc_qbuf)
+ break;
+ ret = check_fmt (vfd, p->type);
+ if (ret)
+ break;
+
+ ret=vfd->vidioc_qbuf(file, fh, p);
+ if (!ret)
+ dbgbuf(cmd,vfd,p);
+ break;
+ }
+ case VIDIOC_OVERLAY:
+ {
+ int *i = arg;
+
+ if (!vfd->vidioc_overlay)
+ break;
+ dbgarg (cmd, "value=%d\n",*i);
+ ret=vfd->vidioc_overlay(file, fh, *i);
+ break;
+ }
+#ifdef HAVE_V4L1
+ /* --- streaming capture ------------------------------------- */
+ case VIDIOCGMBUF:
+ {
+ struct video_mbuf *p=arg;
+
+ memset(p,0,sizeof(p));
+
+ if (!vfd->vidiocgmbuf)
+ break;
+ ret=vfd->vidiocgmbuf(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "size=%d, frames=%d, offsets=0x%08lx\n",
+ p->size, p->frames,
+ (unsigned long)p->offsets);
+ break;
+ }
+#endif
+ case VIDIOC_G_FBUF:
+ {
+ struct v4l2_framebuffer *p=arg;
+ if (!vfd->vidioc_g_fbuf)
+ break;
+ ret=vfd->vidioc_g_fbuf(file, fh, arg);
+ if (!ret) {
+ dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
+ p->capability,p->flags,
+ (unsigned long)p->base);
+ v4l_print_pix_fmt (vfd, &p->fmt);
+ }
+ break;
+ }
+ case VIDIOC_S_FBUF:
+ {
+ struct v4l2_framebuffer *p=arg;
+ if (!vfd->vidioc_s_fbuf)
+ break;
+
+ dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
+ p->capability,p->flags,(unsigned long)p->base);
+ v4l_print_pix_fmt (vfd, &p->fmt);
+ ret=vfd->vidioc_s_fbuf(file, fh, arg);
+
+ break;
+ }
+ case VIDIOC_STREAMON:
+ {
+ enum v4l2_buf_type i = *(int *)arg;
+ if (!vfd->vidioc_streamon)
+ break;
+ dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME));
+ ret=vfd->vidioc_streamon(file, fh,i);
+ break;
+ }
+ case VIDIOC_STREAMOFF:
+ {
+ enum v4l2_buf_type i = *(int *)arg;
+
+ if (!vfd->vidioc_streamoff)
+ break;
+ dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME));
+ ret=vfd->vidioc_streamoff(file, fh, i);
+ break;
+ }
+ /* ---------- tv norms ---------- */
+ case VIDIOC_ENUMSTD:
+ {
+ struct v4l2_standard *p = arg;
+ unsigned int index = p->index;
+
+ if (!vfd->tvnormsize) {
+ printk (KERN_WARNING "%s: no TV norms defined!\n",
+ vfd->name);
+ break;
+ }
+
+ if (index<=0 || index >= vfd->tvnormsize) {
+ ret=-EINVAL;
+ break;
+ }
+ v4l2_video_std_construct(p, vfd->tvnorms[p->index].id,
+ vfd->tvnorms[p->index].name);
+ p->index = index;
+
+ dbgarg (cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, "
+ "framelines=%d\n", p->index,
+ (unsigned long long)p->id, p->name,
+ p->frameperiod.numerator,
+ p->frameperiod.denominator,
+ p->framelines);
+
+ ret=0;
+ break;
+ }
+ case VIDIOC_G_STD:
+ {
+ v4l2_std_id *id = arg;
+
+ *id = vfd->current_norm;
+
+ dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
+
+ ret=0;
+ break;
+ }
+ case VIDIOC_S_STD:
+ {
+ v4l2_std_id *id = arg;
+ unsigned int i;
+
+ if (!vfd->tvnormsize) {
+ printk (KERN_WARNING "%s: no TV norms defined!\n",
+ vfd->name);
+ break;
+ }
+
+ dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
+
+ /* First search for exact match */
+ for (i = 0; i < vfd->tvnormsize; i++)
+ if (*id == vfd->tvnorms[i].id)
+ break;
+ /* Then for a generic video std that contains desired std */
+ if (i == vfd->tvnormsize)
+ for (i = 0; i < vfd->tvnormsize; i++)
+ if (*id & vfd->tvnorms[i].id)
+ break;
+ if (i == vfd->tvnormsize) {
+ break;
+ }
+
+ /* Calls the specific handler */
+ if (vfd->vidioc_s_std)
+ ret=vfd->vidioc_s_std(file, fh, i);
+ else
+ ret=-EINVAL;
+
+ /* Updates standard information */
+ if (!ret)
+ vfd->current_norm=*id;
+
+ break;
+ }
+ case VIDIOC_QUERYSTD:
+ {
+ v4l2_std_id *p=arg;
+
+ if (!vfd->vidioc_querystd)
+ break;
+ ret=vfd->vidioc_querystd(file, fh, arg);
+ if (!ret)
+ dbgarg (cmd, "detected std=%Lu\n",
+ (unsigned long long)*p);
+ break;
+ }
+ /* ------ input switching ---------- */
+ /* FIXME: Inputs can be handled inside videodev2 */
+ case VIDIOC_ENUMINPUT:
+ {
+ struct v4l2_input *p=arg;
+ int i=p->index;
+
+ if (!vfd->vidioc_enum_input)
+ break;
+ memset(p, 0, sizeof(*p));
+ p->index=i;
+
+ ret=vfd->vidioc_enum_input(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "index=%d, name=%s, type=%d, "
+ "audioset=%d, "
+ "tuner=%d, std=%Ld, status=%d\n",
+ p->index,p->name,p->type,p->audioset,
+ p->tuner,
+ (unsigned long long)p->std,
+ p->status);
+ break;
+ }
+ case VIDIOC_G_INPUT:
+ {
+ unsigned int *i = arg;
+
+ if (!vfd->vidioc_g_input)
+ break;
+ ret=vfd->vidioc_g_input(file, fh, i);
+ if (!ret)
+ dbgarg (cmd, "value=%d\n",*i);
+ break;
+ }
+ case VIDIOC_S_INPUT:
+ {
+ unsigned int *i = arg;
+
+ if (!vfd->vidioc_s_input)
+ break;
+ dbgarg (cmd, "value=%d\n",*i);
+ ret=vfd->vidioc_s_input(file, fh, *i);
+ break;
+ }
+
+ /* ------ output switching ---------- */
+ case VIDIOC_G_OUTPUT:
+ {
+ unsigned int *i = arg;
+
+ if (!vfd->vidioc_g_output)
+ break;
+ ret=vfd->vidioc_g_output(file, fh, i);
+ if (!ret)
+ dbgarg (cmd, "value=%d\n",*i);
+ break;
+ }
+ case VIDIOC_S_OUTPUT:
+ {
+ unsigned int *i = arg;
+
+ if (!vfd->vidioc_s_output)
+ break;
+ dbgarg (cmd, "value=%d\n",*i);
+ ret=vfd->vidioc_s_output(file, fh, *i);
+ break;
+ }
+
+ /* --- controls ---------------------------------------------- */
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *p=arg;
+
+ if (!vfd->vidioc_queryctrl)
+ break;
+ ret=vfd->vidioc_queryctrl(file, fh, p);
+
+ if (!ret)
+ dbgarg (cmd, "id=%d, type=%d, name=%s, "
+ "min/max=%d/%d,"
+ " step=%d, default=%d, flags=0x%08x\n",
+ p->id,p->type,p->name,p->minimum,
+ p->maximum,p->step,p->default_value,
+ p->flags);
+ break;
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *p = arg;
+
+ if (!vfd->vidioc_g_ctrl)
+ break;
+ dbgarg(cmd, "Enum for index=%d\n", p->id);
+
+ ret=vfd->vidioc_g_ctrl(file, fh, p);
+ if (!ret)
+ dbgarg2 ( "id=%d, value=%d\n", p->id, p->value);
+ break;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *p = arg;
+
+ if (!vfd->vidioc_s_ctrl)
+ break;
+ dbgarg (cmd, "id=%d, value=%d\n", p->id, p->value);
+
+ ret=vfd->vidioc_s_ctrl(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *p = arg;
+
+ if (vfd->vidioc_g_ext_ctrls) {
+ dbgarg(cmd, "count=%d\n", p->count);
+
+ ret=vfd->vidioc_g_ext_ctrls(file, fh, p);
+ }
+ break;
+ }
+ case VIDIOC_S_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *p = arg;
+
+ if (vfd->vidioc_s_ext_ctrls) {
+ dbgarg(cmd, "count=%d\n", p->count);
+
+ ret=vfd->vidioc_s_ext_ctrls(file, fh, p);
+ }
+ break;
+ }
+ case VIDIOC_TRY_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *p = arg;
+
+ if (vfd->vidioc_try_ext_ctrls) {
+ dbgarg(cmd, "count=%d\n", p->count);
+
+ ret=vfd->vidioc_try_ext_ctrls(file, fh, p);
+ }
+ break;
+ }
+ case VIDIOC_QUERYMENU:
+ {
+ struct v4l2_querymenu *p=arg;
+ if (!vfd->vidioc_querymenu)
+ break;
+ ret=vfd->vidioc_querymenu(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "id=%d, index=%d, name=%s\n",
+ p->id,p->index,p->name);
+ break;
+ }
+ /* --- audio ---------------------------------------------- */
+ case VIDIOC_ENUMAUDIO:
+ {
+ struct v4l2_audio *p=arg;
+
+ if (!vfd->vidioc_enumaudio)
+ break;
+ dbgarg(cmd, "Enum for index=%d\n", p->index);
+ ret=vfd->vidioc_enumaudio(file, fh, p);
+ if (!ret)
+ dbgarg2("index=%d, name=%s, capability=%d, "
+ "mode=%d\n",p->index,p->name,
+ p->capability, p->mode);
+ break;
+ }
+ case VIDIOC_G_AUDIO:
+ {
+ struct v4l2_audio *p=arg;
+
+ if (!vfd->vidioc_g_audio)
+ break;
+ dbgarg(cmd, "Get for index=%d\n", p->index);
+ ret=vfd->vidioc_g_audio(file, fh, p);
+ if (!ret)
+ dbgarg2("index=%d, name=%s, capability=%d, "
+ "mode=%d\n",p->index,
+ p->name,p->capability, p->mode);
+ break;
+ }
+ case VIDIOC_S_AUDIO:
+ {
+ struct v4l2_audio *p=arg;
+
+ if (!vfd->vidioc_s_audio)
+ break;
+ dbgarg(cmd, "index=%d, name=%s, capability=%d, "
+ "mode=%d\n", p->index, p->name,
+ p->capability, p->mode);
+ ret=vfd->vidioc_s_audio(file, fh, p);
+ break;
+ }
+ case VIDIOC_ENUMAUDOUT:
+ {
+ struct v4l2_audioout *p=arg;
+
+ if (!vfd->vidioc_enumaudout)
+ break;
+ dbgarg(cmd, "Enum for index=%d\n", p->index);
+ ret=vfd->vidioc_enumaudout(file, fh, p);
+ if (!ret)
+ dbgarg2("index=%d, name=%s, capability=%d, "
+ "mode=%d\n", p->index, p->name,
+ p->capability,p->mode);
+ break;
+ }
+ case VIDIOC_G_AUDOUT:
+ {
+ struct v4l2_audioout *p=arg;
+
+ if (!vfd->vidioc_g_audout)
+ break;
+ dbgarg(cmd, "Enum for index=%d\n", p->index);
+ ret=vfd->vidioc_g_audout(file, fh, p);
+ if (!ret)
+ dbgarg2("index=%d, name=%s, capability=%d, "
+ "mode=%d\n", p->index, p->name,
+ p->capability,p->mode);
+ break;
+ }
+ case VIDIOC_S_AUDOUT:
+ {
+ struct v4l2_audioout *p=arg;
+
+ if (!vfd->vidioc_s_audout)
+ break;
+ dbgarg(cmd, "index=%d, name=%s, capability=%d, "
+ "mode=%d\n", p->index, p->name,
+ p->capability,p->mode);
+
+ ret=vfd->vidioc_s_audout(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_MODULATOR:
+ {
+ struct v4l2_modulator *p=arg;
+ if (!vfd->vidioc_g_modulator)
+ break;
+ ret=vfd->vidioc_g_modulator(file, fh, p);
+ if (!ret)
+ dbgarg(cmd, "index=%d, name=%s, "
+ "capability=%d, rangelow=%d,"
+ " rangehigh=%d, txsubchans=%d\n",
+ p->index, p->name,p->capability,
+ p->rangelow, p->rangehigh,
+ p->txsubchans);
+ break;
+ }
+ case VIDIOC_S_MODULATOR:
+ {
+ struct v4l2_modulator *p=arg;
+ if (!vfd->vidioc_s_modulator)
+ break;
+ dbgarg(cmd, "index=%d, name=%s, capability=%d, "
+ "rangelow=%d, rangehigh=%d, txsubchans=%d\n",
+ p->index, p->name,p->capability,p->rangelow,
+ p->rangehigh,p->txsubchans);
+ ret=vfd->vidioc_s_modulator(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_CROP:
+ {
+ struct v4l2_crop *p=arg;
+ if (!vfd->vidioc_g_crop)
+ break;
+ ret=vfd->vidioc_g_crop(file, fh, p);
+ if (!ret) {
+ dbgarg(cmd, "type=%d\n", p->type);
+ dbgrect(vfd, "", &p->c);
+ }
+ break;
+ }
+ case VIDIOC_S_CROP:
+ {
+ struct v4l2_crop *p=arg;
+ if (!vfd->vidioc_s_crop)
+ break;
+ dbgarg(cmd, "type=%d\n", p->type);
+ dbgrect(vfd, "", &p->c);
+ ret=vfd->vidioc_s_crop(file, fh, p);
+ break;
+ }
+ case VIDIOC_CROPCAP:
+ {
+ struct v4l2_cropcap *p=arg;
+ /*FIXME: Should also show v4l2_fract pixelaspect */
+ if (!vfd->vidioc_cropcap)
+ break;
+ dbgarg(cmd, "type=%d\n", p->type);
+ dbgrect(vfd, "bounds ", &p->bounds);
+ dbgrect(vfd, "defrect ", &p->defrect);
+ ret=vfd->vidioc_cropcap(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_MPEGCOMP:
+ {
+ struct v4l2_mpeg_compression *p=arg;
+
+ /*FIXME: Several fields not shown */
+ if (!vfd->vidioc_g_mpegcomp)
+ break;
+ ret=vfd->vidioc_g_mpegcomp(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "ts_pid_pmt=%d, ts_pid_audio=%d,"
+ " ts_pid_video=%d, ts_pid_pcr=%d, "
+ "ps_size=%d, au_sample_rate=%d, "
+ "au_pesid=%c, vi_frame_rate=%d, "
+ "vi_frames_per_gop=%d, "
+ "vi_bframes_count=%d, vi_pesid=%c\n",
+ p->ts_pid_pmt,p->ts_pid_audio,
+ p->ts_pid_video,p->ts_pid_pcr,
+ p->ps_size, p->au_sample_rate,
+ p->au_pesid, p->vi_frame_rate,
+ p->vi_frames_per_gop,
+ p->vi_bframes_count, p->vi_pesid);
+ break;
+ }
+ case VIDIOC_S_MPEGCOMP:
+ {
+ struct v4l2_mpeg_compression *p=arg;
+ /*FIXME: Several fields not shown */
+ if (!vfd->vidioc_s_mpegcomp)
+ break;
+ dbgarg (cmd, "ts_pid_pmt=%d, ts_pid_audio=%d, "
+ "ts_pid_video=%d, ts_pid_pcr=%d, ps_size=%d, "
+ "au_sample_rate=%d, au_pesid=%c, "
+ "vi_frame_rate=%d, vi_frames_per_gop=%d, "
+ "vi_bframes_count=%d, vi_pesid=%c\n",
+ p->ts_pid_pmt,p->ts_pid_audio, p->ts_pid_video,
+ p->ts_pid_pcr, p->ps_size, p->au_sample_rate,
+ p->au_pesid, p->vi_frame_rate,
+ p->vi_frames_per_gop, p->vi_bframes_count,
+ p->vi_pesid);
+ ret=vfd->vidioc_s_mpegcomp(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_JPEGCOMP:
+ {
+ struct v4l2_jpegcompression *p=arg;
+ if (!vfd->vidioc_g_jpegcomp)
+ break;
+ ret=vfd->vidioc_g_jpegcomp(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "quality=%d, APPn=%d, "
+ "APP_len=%d, COM_len=%d, "
+ "jpeg_markers=%d\n",
+ p->quality,p->APPn,p->APP_len,
+ p->COM_len,p->jpeg_markers);
+ break;
+ }
+ case VIDIOC_S_JPEGCOMP:
+ {
+ struct v4l2_jpegcompression *p=arg;
+ if (!vfd->vidioc_g_jpegcomp)
+ break;
+ dbgarg (cmd, "quality=%d, APPn=%d, APP_len=%d, "
+ "COM_len=%d, jpeg_markers=%d\n",
+ p->quality,p->APPn,p->APP_len,
+ p->COM_len,p->jpeg_markers);
+ ret=vfd->vidioc_s_jpegcomp(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_PARM:
+ {
+ struct v4l2_streamparm *p=arg;
+ if (!vfd->vidioc_g_parm)
+ break;
+ ret=vfd->vidioc_g_parm(file, fh, p);
+ dbgarg (cmd, "type=%d\n", p->type);
+ break;
+ }
+ case VIDIOC_S_PARM:
+ {
+ struct v4l2_streamparm *p=arg;
+ if (!vfd->vidioc_s_parm)
+ break;
+ dbgarg (cmd, "type=%d\n", p->type);
+ ret=vfd->vidioc_s_parm(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_TUNER:
+ {
+ struct v4l2_tuner *p=arg;
+ if (!vfd->vidioc_g_tuner)
+ break;
+ ret=vfd->vidioc_g_tuner(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "index=%d, name=%s, type=%d, "
+ "capability=%d, rangelow=%d, "
+ "rangehigh=%d, signal=%d, afc=%d, "
+ "rxsubchans=%d, audmode=%d\n",
+ p->index, p->name, p->type,
+ p->capability, p->rangelow,
+ p->rangehigh, p->rxsubchans,
+ p->audmode, p->signal, p->afc);
+ break;
+ }
+ case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *p=arg;
+ if (!vfd->vidioc_s_tuner)
+ break;
+ dbgarg (cmd, "index=%d, name=%s, type=%d, "
+ "capability=%d, rangelow=%d, rangehigh=%d, "
+ "signal=%d, afc=%d, rxsubchans=%d, "
+ "audmode=%d\n",p->index, p->name, p->type,
+ p->capability, p->rangelow,p->rangehigh,
+ p->rxsubchans, p->audmode, p->signal,
+ p->afc);
+ ret=vfd->vidioc_s_tuner(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_FREQUENCY:
+ {
+ struct v4l2_frequency *p=arg;
+ if (!vfd->vidioc_g_frequency)
+ break;
+ ret=vfd->vidioc_g_frequency(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
+ p->tuner,p->type,p->frequency);
+ break;
+ }
+ case VIDIOC_S_FREQUENCY:
+ {
+ struct v4l2_frequency *p=arg;
+ if (!vfd->vidioc_s_frequency)
+ break;
+ dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
+ p->tuner,p->type,p->frequency);
+ ret=vfd->vidioc_s_frequency(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_SLICED_VBI_CAP:
+ {
+ struct v4l2_sliced_vbi_cap *p=arg;
+ if (!vfd->vidioc_g_sliced_vbi_cap)
+ break;
+ ret=vfd->vidioc_g_sliced_vbi_cap(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "service_set=%d\n", p->service_set);
+ break;
+ }
+ case VIDIOC_LOG_STATUS:
+ {
+ if (!vfd->vidioc_log_status)
+ break;
+ ret=vfd->vidioc_log_status(file, fh);
+ break;
+ }
+
+ /* --- Others --------------------------------------------- */
+
+ default:
+ ret=v4l_compat_translate_ioctl(inode,file,cmd,arg,__video_do_ioctl);
+ }
+
+ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
+ if (ret<0) {
+ printk ("%s: err:\n", vfd->name);
+ v4l_print_ioctl(vfd->name, cmd);
+ }
+ }
+
+ return ret;
+}
+
+int video_ioctl2 (struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ char sbuf[128];
+ void *mbuf = NULL;
+ void *parg = NULL;
+ int err = -EINVAL;
+ int is_ext_ctrl;
+ size_t ctrls_size = 0;
+ void __user *user_ptr = NULL;
+
+#ifdef __OLD_VIDIOC_
+ cmd = video_fix_command(cmd);
+#endif
+ is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
+ cmd == VIDIOC_TRY_EXT_CTRLS);
+
+ /* Copy arguments into temp kernel buffer */
+ switch (_IOC_DIR(cmd)) {
+ case _IOC_NONE:
+ parg = NULL;
+ break;
+ case _IOC_READ:
+ case _IOC_WRITE:
+ case (_IOC_WRITE | _IOC_READ):
+ if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+ parg = sbuf;
+ } else {
+ /* too big to allocate from stack */
+ mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
+ if (NULL == mbuf)
+ return -ENOMEM;
+ parg = mbuf;
+ }
+
+ err = -EFAULT;
+ if (_IOC_DIR(cmd) & _IOC_WRITE)
+ if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
+ goto out;
+ break;
+ }
+
+ if (is_ext_ctrl) {
+ struct v4l2_ext_controls *p = parg;
+
+ /* In case of an error, tell the caller that it wasn't
+ a specific control that caused it. */
+ p->error_idx = p->count;
+ user_ptr = (void __user *)p->controls;
+ if (p->count) {
+ ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
+ /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
+ mbuf = kmalloc(ctrls_size, GFP_KERNEL);
+ err = -ENOMEM;
+ if (NULL == mbuf)
+ goto out_ext_ctrl;
+ err = -EFAULT;
+ if (copy_from_user(mbuf, user_ptr, ctrls_size))
+ goto out_ext_ctrl;
+ p->controls = mbuf;
+ }
+ }
+
+ /* Handles IOCTL */
+ err = __video_do_ioctl(inode, file, cmd, parg);
+ if (err == -ENOIOCTLCMD)
+ err = -EINVAL;
+ if (is_ext_ctrl) {
+ struct v4l2_ext_controls *p = parg;
+
+ p->controls = (void *)user_ptr;
+ if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
+ err = -EFAULT;
+ goto out_ext_ctrl;
+ }
+ if (err < 0)
+ goto out;
+
+out_ext_ctrl:
+ /* Copy results into user buffer */
+ switch (_IOC_DIR(cmd))
+ {
+ case _IOC_READ:
+ case (_IOC_WRITE | _IOC_READ):
+ if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
+ err = -EFAULT;
+ break;
+ }
+
+out:
+ kfree(mbuf);
+ return err;
+}
+
+
static struct file_operations video_fops;
/**
@@ -371,7 +1610,9 @@ void video_unregister_device(struct video_device *vfd)
mutex_unlock(&videodev_lock);
}
-
+/*
+ * Video fs operations
+ */
static struct file_operations video_fops=
{
.owner = THIS_MODULE,
@@ -387,7 +1628,7 @@ static int __init videodev_init(void)
{
int ret;
- printk(KERN_INFO "Linux video capture interface: v1.00\n");
+ printk(KERN_INFO "Linux video capture interface: v2.00\n");
if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) {
printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR);
return -EIO;
@@ -418,11 +1659,12 @@ EXPORT_SYMBOL(video_devdata);
EXPORT_SYMBOL(video_usercopy);
EXPORT_SYMBOL(video_exclusive_open);
EXPORT_SYMBOL(video_exclusive_release);
+EXPORT_SYMBOL(video_ioctl2);
EXPORT_SYMBOL(video_device_alloc);
EXPORT_SYMBOL(video_device_release);
-MODULE_AUTHOR("Alan Cox");
-MODULE_DESCRIPTION("Device registrar for Video4Linux drivers");
+MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index a8c1014..268e69f 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -40,7 +40,7 @@
#include <linux/i2c-algo-sgi.h>
#include <linux/videodev.h>
-#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
#include <linux/video_decoder.h>
#include <linux/mutex.h>
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 779db26..41d23c8 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -48,34 +48,15 @@
#include "font.h"
-#ifndef kzalloc
-#define kzalloc(size, flags) \
-({ \
- void *__ret = kmalloc(size, flags); \
- if (__ret) \
- memset(__ret, 0, size); \
- __ret; \
-})
-#endif
-
-MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
-MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
-MODULE_LICENSE("Dual BSD/GPL");
-
#define VIVI_MAJOR_VERSION 0
#define VIVI_MINOR_VERSION 4
#define VIVI_RELEASE 0
#define VIVI_VERSION KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
-static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
-module_param(video_nr, int, 0);
-
-static int debug = 0;
-module_param(debug, int, 0);
-
-static unsigned int vid_limit = 16;
-module_param(vid_limit,int,0644);
-MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
+/* Declare static vars that will be used as parameters */
+static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
+static struct video_device vivi; /* Video device */
+static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
/* supported controls */
static struct v4l2_queryctrl vivi_qctrl[] = {
@@ -129,10 +110,10 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
static int qctl_regs[ARRAY_SIZE(vivi_qctrl)];
-#define dprintk(level,fmt, arg...) \
- do { \
- if (debug >= (level)) \
- printk(KERN_DEBUG "vivi: " fmt , ## arg); \
+#define dprintk(level,fmt, arg...) \
+ do { \
+ if (vivi.debug >= (level)) \
+ printk(KERN_DEBUG "vivi: " fmt , ## arg); \
} while (0)
/* ------------------------------------------------------------------
@@ -190,7 +171,7 @@ struct vivi_dev {
/* various device info */
unsigned int resources;
- struct video_device video_dev;
+ struct video_device vfd;
struct vivi_dmaqueue vidq;
@@ -248,7 +229,8 @@ static u8 bars[8][3] = {
#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
#define TSTAMP_MIN_X 64
-void prep_to_addr(struct sg_to_addr to_addr[],struct videobuf_buffer *vb)
+static void prep_to_addr(struct sg_to_addr to_addr[],
+ struct videobuf_buffer *vb)
{
int i, pos=0;
@@ -259,7 +241,7 @@ void prep_to_addr(struct sg_to_addr to_addr[],struct videobuf_buffer *vb)
}
}
-inline int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
+static int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
{
int p1=0,p2=pages-1,p3=pages/2;
@@ -280,8 +262,8 @@ inline int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
return (p1);
}
-void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
- int hmax, int line, char *timestr)
+static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
+ int hmax, int line, char *timestr)
{
int w,i,j,pos=inipos,pgpos,oldpg,y;
char *p,*s,*basep;
@@ -491,7 +473,7 @@ static void vivi_thread_tick(struct vivi_dmaqueue *dma_q)
dprintk(1,"%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
}
-void vivi_sleep(struct vivi_dmaqueue *dma_q)
+static void vivi_sleep(struct vivi_dmaqueue *dma_q)
{
int timeout;
DECLARE_WAITQUEUE(wait, current);
@@ -526,7 +508,7 @@ void vivi_sleep(struct vivi_dmaqueue *dma_q)
try_to_freeze();
}
-int vivi_thread(void *data)
+static int vivi_thread(void *data)
{
struct vivi_dmaqueue *dma_q=data;
@@ -542,7 +524,7 @@ int vivi_thread(void *data)
return 0;
}
-int vivi_start_thread(struct vivi_dmaqueue *dma_q)
+static int vivi_start_thread(struct vivi_dmaqueue *dma_q)
{
dma_q->frame=0;
dma_q->ini_jiffies=jiffies;
@@ -560,7 +542,7 @@ int vivi_start_thread(struct vivi_dmaqueue *dma_q)
return 0;
}
-void vivi_stop_thread(struct vivi_dmaqueue *dma_q)
+static void vivi_stop_thread(struct vivi_dmaqueue *dma_q)
{
dprintk(1,"%s\n",__FUNCTION__);
/* shutdown control thread */
@@ -666,8 +648,7 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
return 0;
}
-void
-free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
+static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
{
dprintk(1,"%s\n",__FUNCTION__);
@@ -791,8 +772,8 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb
free_buffer(vq,buf);
}
-int vivi_map_sg (void *dev, struct scatterlist *sg, int nents,
- int direction)
+static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents,
+ int direction)
{
int i;
@@ -808,15 +789,15 @@ int vivi_map_sg (void *dev, struct scatterlist *sg, int nents,
return nents;
}
-int vivi_unmap_sg(void *dev,struct scatterlist *sglist,int nr_pages,
- int direction)
+static int vivi_unmap_sg(void *dev,struct scatterlist *sglist,int nr_pages,
+ int direction)
{
dprintk(1,"%s\n",__FUNCTION__);
return 0;
}
-int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist,int nr_pages,
- int direction)
+static int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist, int nr_pages,
+ int direction)
{
// dprintk(1,"%s\n",__FUNCTION__);
@@ -840,7 +821,80 @@ static struct videobuf_queue_ops vivi_video_qops = {
IOCTL handling
------------------------------------------------------------------*/
-static int vivi_try_fmt(struct vivi_dev *dev, struct vivi_fh *fh,
+
+static int res_get(struct vivi_dev *dev, struct vivi_fh *fh)
+{
+ /* is it free? */
+ down(&dev->lock);
+ if (dev->resources) {
+ /* no, someone else uses it */
+ up(&dev->lock);
+ return 0;
+ }
+ /* it's free, grab it */
+ dev->resources =1;
+ dprintk(1,"res: get\n");
+ up(&dev->lock);
+ return 1;
+}
+
+static int res_locked(struct vivi_dev *dev)
+{
+ return (dev->resources);
+}
+
+static void res_free(struct vivi_dev *dev, struct vivi_fh *fh)
+{
+ down(&dev->lock);
+ dev->resources = 0;
+ dprintk(1,"res: put\n");
+ up(&dev->lock);
+}
+
+/* ------------------------------------------------------------------
+ IOCTL vidioc handling
+ ------------------------------------------------------------------*/
+static int vidioc_querycap (struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strcpy(cap->driver, "vivi");
+ strcpy(cap->card, "vivi");
+ cap->version = VIVI_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
+ return 0;
+}
+
+static int vidioc_enum_fmt_cap (struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index > 0)
+ return -EINVAL;
+
+ strlcpy(f->description,format.name,sizeof(f->description));
+ f->pixelformat = format.fourcc;
+ return 0;
+}
+
+static int vidioc_g_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct vivi_fh *fh=priv;
+
+ f->fmt.pix.width = fh->width;
+ f->fmt.pix.height = fh->height;
+ f->fmt.pix.field = fh->vb_vidq.field;
+ f->fmt.pix.pixelformat = fh->fmt->fourcc;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fh->fmt->depth) >> 3;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+ return (0);
+}
+
+static int vidioc_try_fmt_cap (struct file *file, void *priv,
struct v4l2_format *f)
{
struct vivi_fmt *fmt;
@@ -848,7 +902,8 @@ static int vivi_try_fmt(struct vivi_dev *dev, struct vivi_fh *fh,
unsigned int maxw, maxh;
if (format.fourcc != f->fmt.pix.pixelformat) {
- dprintk(1,"Fourcc format invalid.\n");
+ dprintk(1,"Fourcc format (0x%08x) invalid. Driver accepts "
+ "only 0x%08x\n",f->fmt.pix.pixelformat,format.fourcc);
return -EINVAL;
}
fmt=&format;
@@ -884,356 +939,196 @@ static int vivi_try_fmt(struct vivi_dev *dev, struct vivi_fh *fh,
return 0;
}
-static int res_get(struct vivi_dev *dev, struct vivi_fh *fh)
+/*FIXME: This seems to be generic enough to be at videodev2 */
+static int vidioc_s_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
{
- /* is it free? */
- down(&dev->lock);
- if (dev->resources) {
- /* no, someone else uses it */
- up(&dev->lock);
- return 0;
- }
- /* it's free, grab it */
- dev->resources =1;
- dprintk(1,"res: get\n");
- up(&dev->lock);
- return 1;
+ struct vivi_fh *fh=priv;
+ int ret = vidioc_try_fmt_cap(file,fh,f);
+ if (ret < 0)
+ return (ret);
+
+ fh->fmt = &format;
+ fh->width = f->fmt.pix.width;
+ fh->height = f->fmt.pix.height;
+ fh->vb_vidq.field = f->fmt.pix.field;
+ fh->type = f->type;
+
+ return (0);
}
-static inline int res_locked(struct vivi_dev *dev)
+static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
{
- return (dev->resources);
-}
+ struct vivi_fh *fh=priv;
-static void res_free(struct vivi_dev *dev, struct vivi_fh *fh)
-{
- down(&dev->lock);
- dev->resources = 0;
- dprintk(1,"res: put\n");
- up(&dev->lock);
+ return (videobuf_reqbufs(&fh->vb_vidq, p));
}
-static int vivi_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg)
+static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
{
- struct vivi_fh *fh = file->private_data;
- struct vivi_dev *dev = fh->dev;
- int ret=0;
+ struct vivi_fh *fh=priv;
- if (debug) {
- if (_IOC_DIR(cmd) & _IOC_WRITE)
- v4l_printk_ioctl_arg("vivi(w)",cmd, arg);
- else if (!_IOC_DIR(cmd) & _IOC_READ) {
- v4l_print_ioctl("vivi", cmd);
- }
- }
+ return (videobuf_querybuf(&fh->vb_vidq, p));
+}
- switch(cmd) {
- /* --- capabilities ------------------------------------------ */
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *cap = (struct v4l2_capability*)arg;
-
- memset(cap, 0, sizeof(*cap));
-
- strcpy(cap->driver, "vivi");
- strcpy(cap->card, "vivi");
- cap->version = VIVI_VERSION;
- cap->capabilities =
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_STREAMING |
- V4L2_CAP_READWRITE;
- break;
- }
- /* --- capture ioctls ---------------------------------------- */
- case VIDIOC_ENUM_FMT:
- {
- struct v4l2_fmtdesc *f = arg;
- enum v4l2_buf_type type;
- unsigned int index;
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct vivi_fh *fh=priv;
- index = f->index;
- type = f->type;
+ return (videobuf_qbuf(&fh->vb_vidq, p));
+}
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct vivi_fh *fh=priv;
- switch (type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (index > 0){
- ret=-EINVAL;
- break;
- }
- memset(f,0,sizeof(*f));
+ return (videobuf_dqbuf(&fh->vb_vidq, p,
+ file->f_flags & O_NONBLOCK));
+}
- f->index = index;
- f->type = type;
- strlcpy(f->description,format.name,sizeof(f->description));
- f->pixelformat = format.fourcc;
- break;
- default:
- ret=-EINVAL;
- }
- break;
+#ifdef HAVE_V4L1
+static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+ struct vivi_fh *fh=priv;
+ struct videobuf_queue *q=&fh->vb_vidq;
+ struct v4l2_requestbuffers req;
+ unsigned int i, ret;
+
+ req.type = q->type;
+ req.count = 8;
+ req.memory = V4L2_MEMORY_MMAP;
+ ret = videobuf_reqbufs(q,&req);
+ if (ret < 0)
+ return (ret);
+
+ mbuf->frames = req.count;
+ mbuf->size = 0;
+ for (i = 0; i < mbuf->frames; i++) {
+ mbuf->offsets[i] = q->bufs[i]->boff;
+ mbuf->size += q->bufs[i]->bsize;
}
- case VIDIOC_G_FMT:
- {
- struct v4l2_format *f = (struct v4l2_format *)arg;
+ return (0);
+}
+#endif
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct vivi_fh *fh=priv;
+ struct vivi_dev *dev = fh->dev;
- memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
- f->fmt.pix.width = fh->width;
- f->fmt.pix.height = fh->height;
- f->fmt.pix.field = fh->vb_vidq.field;
- f->fmt.pix.pixelformat = fh->fmt->fourcc;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fh->fmt->depth) >> 3;
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
- break;
- }
- case VIDIOC_S_FMT:
- {
- struct v4l2_format *f = arg;
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (i != fh->type)
+ return -EINVAL;
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- dprintk(1,"Only capture supported.\n");
- ret=-EINVAL;
- break;
- }
+ if (!res_get(dev,fh))
+ return -EBUSY;
+ return (videobuf_streamon(&fh->vb_vidq));
+}
- ret = vivi_try_fmt(dev,fh,f);
- if (ret < 0)
- break;
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct vivi_fh *fh=priv;
+ struct vivi_dev *dev = fh->dev;
- fh->fmt = &format;
- fh->width = f->fmt.pix.width;
- fh->height = f->fmt.pix.height;
- fh->vb_vidq.field = f->fmt.pix.field;
- fh->type = f->type;
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (i != fh->type)
+ return -EINVAL;
- break;
- }
- case VIDIOC_TRY_FMT:
- {
- struct v4l2_format *f = arg;
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
+ videobuf_streamoff(&fh->vb_vidq);
+ res_free(dev,fh);
- ret=vivi_try_fmt(dev,fh,f);
- break;
- }
- case VIDIOC_REQBUFS:
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
- ret=videobuf_reqbufs(&fh->vb_vidq, arg);
- break;
- case VIDIOC_QUERYBUF:
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
- ret=videobuf_querybuf(&fh->vb_vidq, arg);
- break;
- case VIDIOC_QBUF:
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
- ret=videobuf_qbuf(&fh->vb_vidq, arg);
- break;
- case VIDIOC_DQBUF:
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
- ret=videobuf_dqbuf(&fh->vb_vidq, arg,
- file->f_flags & O_NONBLOCK);
- break;
-#ifdef HAVE_V4L1
- /* --- streaming capture ------------------------------------- */
- case VIDIOCGMBUF:
- {
- struct video_mbuf *mbuf = arg;
- struct videobuf_queue *q=&fh->vb_vidq;
- struct v4l2_requestbuffers req;
- unsigned int i;
-
- memset(&req,0,sizeof(req));
- req.type = q->type;
- req.count = 8;
- req.memory = V4L2_MEMORY_MMAP;
- ret = videobuf_reqbufs(q,&req);
- if (ret < 0)
- break;
- memset(mbuf,0,sizeof(*mbuf));
- mbuf->frames = req.count;
- mbuf->size = 0;
- for (i = 0; i < mbuf->frames; i++) {
- mbuf->offsets[i] = q->bufs[i]->boff;
- mbuf->size += q->bufs[i]->bsize;
- }
- break;
- }
-#endif
- case VIDIOC_STREAMON:
- {
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (!res_get(dev,fh))
- return -EBUSY;
- ret=videobuf_streamon(&fh->vb_vidq);
- break;
- }
- case VIDIOC_STREAMOFF:
+ return (0);
+}
+
+static struct v4l2_tvnorm tvnorms[] = {
{
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
- ret = videobuf_streamoff(&fh->vb_vidq);
- if (ret < 0)
- break;
- res_free(dev,fh);
- break;
+ .name = "NTSC-M",
+ .id = V4L2_STD_NTSC_M,
}
- /* ---------- tv norms ---------- */
- case VIDIOC_ENUMSTD:
- {
- struct v4l2_standard *e = arg;
+};
- if (e->index>0) {
- ret=-EINVAL;
- break;
- }
- ret = v4l2_video_std_construct(e, V4L2_STD_NTSC_M, "NTSC-M");
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id a)
+{
- /* Allows vivi to use different fps from video std */
- e->frameperiod.numerator = WAKE_NUMERATOR;
- e->frameperiod.denominator = WAKE_DENOMINATOR;
+ return 0;
+}
- break;
- }
- case VIDIOC_G_STD:
- {
- v4l2_std_id *id = arg;
+/* only one input in this sample driver */
+static int vidioc_enum_input (struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ if (inp->index != 0)
+ return -EINVAL;
- *id = V4L2_STD_NTSC_M;
- break;
- }
- case VIDIOC_S_STD:
- {
- break;
- }
- /* ------ input switching ---------- */
- case VIDIOC_ENUMINPUT:
- { /* only one input in this sample driver */
- struct v4l2_input *inp = arg;
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ inp->std = V4L2_STD_NTSC_M;
+ strcpy(inp->name,"Camera");
- if (inp->index != 0) {
- ret=-EINVAL;
- break;
- }
- memset(inp, 0, sizeof(*inp));
+ return (0);
+}
- inp->index = 0;
- inp->type = V4L2_INPUT_TYPE_CAMERA;
- inp->std = V4L2_STD_NTSC_M;
- strcpy(inp->name,"Camera");
- break;
- }
- case VIDIOC_G_INPUT:
- {
- unsigned int *i = arg;
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
- *i = 0;
- break;
- }
- case VIDIOC_S_INPUT:
- {
- unsigned int *i = arg;
+ return (0);
+}
+static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+{
+ if (i > 0)
+ return -EINVAL;
- if (*i > 0)
- ret=-EINVAL;
- break;
- }
+ return (0);
+}
/* --- controls ---------------------------------------------- */
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *qc = arg;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
- if (qc->id && qc->id == vivi_qctrl[i].id) {
- memcpy(qc, &(vivi_qctrl[i]),
- sizeof(*qc));
- break;
- }
+static int vidioc_queryctrl (struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
- ret=-EINVAL;
- break;
- }
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl = arg;
- int i;
+ for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+ if (qc->id && qc->id == vivi_qctrl[i].id) {
+ memcpy(qc, &(vivi_qctrl[i]),
+ sizeof(*qc));
+ return (0);
+ }
- for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
- if (ctrl->id == vivi_qctrl[i].id) {
- ctrl->value=qctl_regs[i];
- break;
- }
+ return -EINVAL;
+}
- ret=-EINVAL;
- break;
- }
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl = arg;
- int i;
- for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
- if (ctrl->id == vivi_qctrl[i].id) {
- if (ctrl->value <
- vivi_qctrl[i].minimum
- || ctrl->value >
- vivi_qctrl[i].maximum) {
- ret=-ERANGE;
- break;
- }
- qctl_regs[i]=ctrl->value;
- break;
- }
- ret=-EINVAL;
- break;
- }
- default:
- ret=v4l_compat_translate_ioctl(inode,file,cmd,arg,vivi_do_ioctl);
- }
+static int vidioc_g_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int i;
- if (debug) {
- if (ret<0) {
- v4l_print_ioctl("vivi(err)", cmd);
- dprintk(1,"errcode=%d\n",ret);
- } else if (_IOC_DIR(cmd) & _IOC_READ)
- v4l_printk_ioctl_arg("vivi(r)",cmd, arg);
- }
+ for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+ if (ctrl->id == vivi_qctrl[i].id) {
+ ctrl->value=qctl_regs[i];
+ return (0);
+ }
- return ret;
+ return -EINVAL;
}
-
-static int vivi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int vidioc_s_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
{
- return video_usercopy(inode, file, cmd, arg, vivi_do_ioctl);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+ if (ctrl->id == vivi_qctrl[i].id) {
+ if (ctrl->value <
+ vivi_qctrl[i].minimum
+ || ctrl->value >
+ vivi_qctrl[i].maximum) {
+ return (-ERANGE);
+ }
+ qctl_regs[i]=ctrl->value;
+ return (0);
+ }
+ return -EINVAL;
}
/* ------------------------------------------------------------------
@@ -1255,7 +1150,7 @@ static int vivi_open(struct inode *inode, struct file *file)
list_for_each(list,&vivi_devlist) {
h = list_entry(list, struct vivi_dev, vivi_devlist);
- if (h->video_dev.minor == minor) {
+ if (h->vfd.minor == minor) {
dev = h;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
}
@@ -1264,6 +1159,7 @@ static int vivi_open(struct inode *inode, struct file *file)
return -ENODEV;
+
/* If more than one user, mutex should be added */
dev->users++;
@@ -1279,6 +1175,7 @@ static int vivi_open(struct inode *inode, struct file *file)
file->private_data = fh;
fh->dev = dev;
+
fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fh->fmt = &format;
fh->width = 640;
@@ -1314,7 +1211,7 @@ static int vivi_open(struct inode *inode, struct file *file)
static ssize_t
vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{
- struct vivi_fh *fh = file->private_data;
+ struct vivi_fh *fh = file->private_data;
if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) {
if (res_locked(fh->dev))
@@ -1328,8 +1225,8 @@ vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
static unsigned int
vivi_poll(struct file *file, struct poll_table_struct *wait)
{
- struct vivi_fh *fh = file->private_data;
- struct vivi_buffer *buf;
+ struct vivi_fh *fh = file->private_data;
+ struct vivi_buffer *buf;
dprintk(1,"%s\n",__FUNCTION__);
@@ -1358,8 +1255,8 @@ vivi_poll(struct file *file, struct poll_table_struct *wait)
static int vivi_release(struct inode *inode, struct file *file)
{
- struct vivi_fh *fh = file->private_data;
- struct vivi_dev *dev = fh->dev;
+ struct vivi_fh *fh = file->private_data;
+ struct vivi_dev *dev = fh->dev;
struct vivi_dmaqueue *vidq = &dev->vidq;
int minor = iminor(inode);
@@ -1379,7 +1276,7 @@ static int vivi_release(struct inode *inode, struct file *file)
static int
vivi_mmap(struct file *file, struct vm_area_struct * vma)
{
- struct vivi_fh *fh = file->private_data;
+ struct vivi_fh *fh = file->private_data;
int ret;
dprintk (1,"mmap called, vma=0x%08lx\n",(unsigned long)vma);
@@ -1400,20 +1297,44 @@ static struct file_operations vivi_fops = {
.release = vivi_release,
.read = vivi_read,
.poll = vivi_poll,
- .ioctl = vivi_ioctl,
+ .ioctl = video_ioctl2, /* V4L2 ioctl handler */
.mmap = vivi_mmap,
.llseek = no_llseek,
};
static struct video_device vivi = {
- .name = "VTM Virtual Video Capture Board",
+ .name = "vivi",
.type = VID_TYPE_CAPTURE,
.hardware = 0,
.fops = &vivi_fops,
.minor = -1,
// .release = video_device_release,
+
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
+ .vidioc_g_fmt_cap = vidioc_g_fmt_cap,
+ .vidioc_try_fmt_cap = vidioc_try_fmt_cap,
+ .vidioc_s_fmt_cap = vidioc_s_fmt_cap,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+#ifdef HAVE_V4L1
+ .vidiocgmbuf = vidiocgmbuf,
+#endif
+ .tvnorms = tvnorms,
+ .tvnormsize = ARRAY_SIZE(tvnorms),
};
-/* ------------------------------------------------------------------
+/* -----------------------------------------------------------------
Initialization and module stuff
------------------------------------------------------------------*/
@@ -1457,3 +1378,16 @@ static void __exit vivi_exit(void)
module_init(vivi_init);
module_exit(vivi_exit);
+
+MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
+MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
+MODULE_LICENSE("Dual BSD/GPL");
+
+module_param(video_nr, int, 0);
+
+module_param_named(debug,vivi.debug, int, 0644);
+MODULE_PARM_DESC(debug,"activates debug info");
+
+module_param(vid_limit,int,0644);
+MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
+
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c
index 40b205b..1eca7e6 100644
--- a/drivers/media/video/vpx3220.c
+++ b/drivers/media/video/vpx3220.c
@@ -34,6 +34,7 @@
#define I2C_NAME(x) (x)->name
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/video_decoder.h>
#define I2C_VPX3220 0x86
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index 80ef8a1..4bdc886 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -58,6 +58,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/parport.h>
//#define DEBUG // Undef me for production
diff --git a/drivers/media/video/zc0301/Kconfig b/drivers/media/video/zc0301/Kconfig
index 115833e..a859a69 100644
--- a/drivers/media/video/zc0301/Kconfig
+++ b/drivers/media/video/zc0301/Kconfig
@@ -1,9 +1,9 @@
config USB_ZC0301
- tristate "USB ZC0301 Image Processor and Control Chip support"
+ tristate "USB ZC0301[P] Image Processor and Control Chip support"
depends on USB && VIDEO_V4L1
---help---
- Say Y here if you want support for cameras based on the ZC0301
- Image Processor and Control Chip.
+ Say Y here if you want support for cameras based on the ZC0301 or
+ ZC0301P Image Processors and Control Chips.
See <file:Documentation/video4linux/zc0301.txt> for more info.
diff --git a/drivers/media/video/zc0301/Makefile b/drivers/media/video/zc0301/Makefile
index d749199..d9e6d97 100644
--- a/drivers/media/video/zc0301/Makefile
+++ b/drivers/media/video/zc0301/Makefile
@@ -1,3 +1,3 @@
-zc0301-objs := zc0301_core.o zc0301_pas202bcb.o
+zc0301-objs := zc0301_core.o zc0301_pb0330.o zc0301_pas202bcb.o
obj-$(CONFIG_USB_ZC0301) += zc0301.o
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
index 0fad397..1b2be2d 100644
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ b/drivers/media/video/zc0301/zc0301_core.c
@@ -1,5 +1,5 @@
/***************************************************************************
- * Video4Linux2 driver for ZC0301 Image Processor and Control Chip *
+ * Video4Linux2 driver for ZC0301[P] Image Processor and Control Chip *
* *
* Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
@@ -47,13 +47,13 @@
/*****************************************************************************/
-#define ZC0301_MODULE_NAME "V4L2 driver for ZC0301 " \
+#define ZC0301_MODULE_NAME "V4L2 driver for ZC0301[P] " \
"Image Processor and Control Chip"
#define ZC0301_MODULE_AUTHOR "(C) 2006 Luca Risolia"
#define ZC0301_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define ZC0301_MODULE_LICENSE "GPL"
-#define ZC0301_MODULE_VERSION "1:1.03"
-#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 3)
+#define ZC0301_MODULE_VERSION "1:1.05"
+#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 5)
/*****************************************************************************/
@@ -427,10 +427,11 @@ resubmit_urb:
static int zc0301_start_transfer(struct zc0301_device* cam)
{
struct usb_device *udev = cam->usbdev;
+ struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
+ usb_ifnum_to_if(udev, 0),
+ ZC0301_ALTERNATE_SETTING);
+ const unsigned int psz = altsetting->endpoint[0].desc.wMaxPacketSize;
struct urb* urb;
- const unsigned int wMaxPacketSize[] = {0, 128, 192, 256, 384,
- 512, 768, 1023};
- const unsigned int psz = wMaxPacketSize[ZC0301_ALTERNATE_SETTING];
s8 i, j;
int err = 0;
@@ -1772,11 +1773,9 @@ static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_G_CTRL:
return zc0301_vidioc_g_ctrl(cam, arg);
- case VIDIOC_S_CTRL_OLD:
case VIDIOC_S_CTRL:
return zc0301_vidioc_s_ctrl(cam, arg);
- case VIDIOC_CROPCAP_OLD:
case VIDIOC_CROPCAP:
return zc0301_vidioc_cropcap(cam, arg);
@@ -1823,7 +1822,6 @@ static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_G_PARM:
return zc0301_vidioc_g_parm(cam, arg);
- case VIDIOC_S_PARM_OLD:
case VIDIOC_S_PARM:
return zc0301_vidioc_s_parm(cam, arg);
@@ -1914,7 +1912,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
mutex_init(&cam->dev_mutex);
- DBG(2, "ZC0301 Image Processor and Control Chip detected "
+ DBG(2, "ZC0301[P] Image Processor and Control Chip detected "
"(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
for (i = 0; zc0301_sensor_table[i]; i++) {
@@ -1936,7 +1934,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
cam->state |= DEV_MISCONFIGURED;
}
- strcpy(cam->v4ldev->name, "ZC0301 PC Camera");
+ strcpy(cam->v4ldev->name, "ZC0301[P] PC Camera");
cam->v4ldev->owner = THIS_MODULE;
cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
cam->v4ldev->hardware = 0;
diff --git a/drivers/media/video/zc0301/zc0301_pas202bcb.c b/drivers/media/video/zc0301/zc0301_pas202bcb.c
index eaadf02..ecfd39a 100644
--- a/drivers/media/video/zc0301/zc0301_pas202bcb.c
+++ b/drivers/media/video/zc0301/zc0301_pas202bcb.c
@@ -1,10 +1,10 @@
/***************************************************************************
- * Plug-in for PAS202BCB image sensor connected to the ZC030! Image *
+ * Plug-in for PAS202BCB image sensor connected to the ZC0301[P] Image *
* Processor and Control Chip *
* *
* Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
- * Initialization values of the ZC0301 have been taken from the SPCA5XX *
+ * Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
* driver maintained by Michel Xhaard <mxhaard@magic.fr> *
* *
* This program is free software; you can redistribute it and/or modify *
diff --git a/drivers/media/video/zc0301/zc0301_pb0330.c b/drivers/media/video/zc0301/zc0301_pb0330.c
new file mode 100644
index 0000000..ed8542e
--- /dev/null
+++ b/drivers/media/video/zc0301/zc0301_pb0330.c
@@ -0,0 +1,187 @@
+/***************************************************************************
+ * Plug-in for PB-0330 image sensor connected to the ZC0301[P] Image *
+ * Processor and Control Chip *
+ * *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * *
+ * Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
+ * driver maintained by Michel Xhaard <mxhaard@magic.fr> *
+ * *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. *
+ ***************************************************************************/
+
+#include <linux/delay.h>
+#include "zc0301_sensor.h"
+
+
+static struct zc0301_sensor pb0330;
+
+
+static int pb0330_init(struct zc0301_device* cam)
+{
+ int err = 0;
+
+ err += zc0301_write_reg(cam, 0x0000, 0x01);
+ err += zc0301_write_reg(cam, 0x0008, 0x03);
+ err += zc0301_write_reg(cam, 0x0010, 0x0A);
+ err += zc0301_write_reg(cam, 0x0002, 0x00);
+ err += zc0301_write_reg(cam, 0x0003, 0x02);
+ err += zc0301_write_reg(cam, 0x0004, 0x80);
+ err += zc0301_write_reg(cam, 0x0005, 0x01);
+ err += zc0301_write_reg(cam, 0x0006, 0xE0);
+ err += zc0301_write_reg(cam, 0x0001, 0x01);
+ err += zc0301_write_reg(cam, 0x0012, 0x05);
+ err += zc0301_write_reg(cam, 0x0012, 0x07);
+ err += zc0301_write_reg(cam, 0x0098, 0x00);
+ err += zc0301_write_reg(cam, 0x009A, 0x00);
+ err += zc0301_write_reg(cam, 0x011A, 0x00);
+ err += zc0301_write_reg(cam, 0x011C, 0x00);
+ err += zc0301_write_reg(cam, 0x0012, 0x05);
+
+ err += zc0301_i2c_write(cam, 0x01, 0x0006);
+ err += zc0301_i2c_write(cam, 0x02, 0x0011);
+ err += zc0301_i2c_write(cam, 0x03, 0x01E7);
+ err += zc0301_i2c_write(cam, 0x04, 0x0287);
+ err += zc0301_i2c_write(cam, 0x06, 0x0003);
+ err += zc0301_i2c_write(cam, 0x07, 0x3002);
+ err += zc0301_i2c_write(cam, 0x20, 0x1100);
+ err += zc0301_i2c_write(cam, 0x2F, 0xF7B0);
+ err += zc0301_i2c_write(cam, 0x30, 0x0005);
+ err += zc0301_i2c_write(cam, 0x31, 0x0000);
+ err += zc0301_i2c_write(cam, 0x34, 0x0100);
+ err += zc0301_i2c_write(cam, 0x35, 0x0060);
+ err += zc0301_i2c_write(cam, 0x3D, 0x068F);
+ err += zc0301_i2c_write(cam, 0x40, 0x01E0);
+ err += zc0301_i2c_write(cam, 0x58, 0x0078);
+ err += zc0301_i2c_write(cam, 0x62, 0x0411);
+
+ err += zc0301_write_reg(cam, 0x0087, 0x10);
+ err += zc0301_write_reg(cam, 0x0101, 0x37);
+ err += zc0301_write_reg(cam, 0x0012, 0x05);
+ err += zc0301_write_reg(cam, 0x0100, 0x0D);
+ err += zc0301_write_reg(cam, 0x0189, 0x06);
+ err += zc0301_write_reg(cam, 0x01AD, 0x00);
+ err += zc0301_write_reg(cam, 0x01C5, 0x03);
+ err += zc0301_write_reg(cam, 0x01CB, 0x13);
+ err += zc0301_write_reg(cam, 0x0250, 0x08);
+ err += zc0301_write_reg(cam, 0x0301, 0x08);
+ err += zc0301_write_reg(cam, 0x01A8, 0x60);
+ err += zc0301_write_reg(cam, 0x018D, 0x6C);
+ err += zc0301_write_reg(cam, 0x01AD, 0x09);
+ err += zc0301_write_reg(cam, 0x01AE, 0x15);
+ err += zc0301_write_reg(cam, 0x010A, 0x50);
+ err += zc0301_write_reg(cam, 0x010B, 0xF8);
+ err += zc0301_write_reg(cam, 0x010C, 0xF8);
+ err += zc0301_write_reg(cam, 0x010D, 0xF8);
+ err += zc0301_write_reg(cam, 0x010E, 0x50);
+ err += zc0301_write_reg(cam, 0x010F, 0xF8);
+ err += zc0301_write_reg(cam, 0x0110, 0xF8);
+ err += zc0301_write_reg(cam, 0x0111, 0xF8);
+ err += zc0301_write_reg(cam, 0x0112, 0x50);
+ err += zc0301_write_reg(cam, 0x0008, 0x03);
+ err += zc0301_write_reg(cam, 0x01C6, 0x08);
+ err += zc0301_write_reg(cam, 0x01CB, 0x0F);
+ err += zc0301_write_reg(cam, 0x010A, 0x50);
+ err += zc0301_write_reg(cam, 0x010B, 0xF8);
+ err += zc0301_write_reg(cam, 0x010C, 0xF8);
+ err += zc0301_write_reg(cam, 0x010D, 0xF8);
+ err += zc0301_write_reg(cam, 0x010E, 0x50);
+ err += zc0301_write_reg(cam, 0x010F, 0xF8);
+ err += zc0301_write_reg(cam, 0x0110, 0xF8);
+ err += zc0301_write_reg(cam, 0x0111, 0xF8);
+ err += zc0301_write_reg(cam, 0x0112, 0x50);
+ err += zc0301_write_reg(cam, 0x0180, 0x00);
+ err += zc0301_write_reg(cam, 0x0019, 0x00);
+
+ err += zc0301_i2c_write(cam, 0x05, 0x0066);
+ err += zc0301_i2c_write(cam, 0x09, 0x02B2);
+ err += zc0301_i2c_write(cam, 0x10, 0x0002);
+
+ err += zc0301_write_reg(cam, 0x011D, 0x60);
+ err += zc0301_write_reg(cam, 0x0190, 0x00);
+ err += zc0301_write_reg(cam, 0x0191, 0x07);
+ err += zc0301_write_reg(cam, 0x0192, 0x8C);
+ err += zc0301_write_reg(cam, 0x0195, 0x00);
+ err += zc0301_write_reg(cam, 0x0196, 0x00);
+ err += zc0301_write_reg(cam, 0x0197, 0x8A);
+ err += zc0301_write_reg(cam, 0x018C, 0x10);
+ err += zc0301_write_reg(cam, 0x018F, 0x20);
+ err += zc0301_write_reg(cam, 0x01A9, 0x14);
+ err += zc0301_write_reg(cam, 0x01AA, 0x24);
+ err += zc0301_write_reg(cam, 0x001D, 0xD7);
+ err += zc0301_write_reg(cam, 0x001E, 0xF0);
+ err += zc0301_write_reg(cam, 0x001F, 0xF8);
+ err += zc0301_write_reg(cam, 0x0020, 0xFF);
+ err += zc0301_write_reg(cam, 0x01AD, 0x09);
+ err += zc0301_write_reg(cam, 0x01AE, 0x15);
+ err += zc0301_write_reg(cam, 0x0180, 0x40);
+ err += zc0301_write_reg(cam, 0x0180, 0x42);
+
+ msleep(100);
+
+ return err;
+}
+
+
+static struct zc0301_sensor pb0330 = {
+ .name = "PB-0330",
+ .init = &pb0330_init,
+ .cropcap = {
+ .bounds = {
+ .left = 0,
+ .top = 0,
+ .width = 640,
+ .height = 480,
+ },
+ .defrect = {
+ .left = 0,
+ .top = 0,
+ .width = 640,
+ .height = 480,
+ },
+ },
+ .pix_format = {
+ .width = 640,
+ .height = 480,
+ .pixelformat = V4L2_PIX_FMT_JPEG,
+ .priv = 8,
+ },
+};
+
+
+int zc0301_probe_pb0330(struct zc0301_device* cam)
+{
+ int r0, err = 0;
+
+ err += zc0301_write_reg(cam, 0x0000, 0x01);
+ err += zc0301_write_reg(cam, 0x0010, 0x0a);
+ err += zc0301_write_reg(cam, 0x0001, 0x01);
+ err += zc0301_write_reg(cam, 0x0012, 0x03);
+ err += zc0301_write_reg(cam, 0x0012, 0x01);
+
+ msleep(10);
+
+ r0 = zc0301_i2c_read(cam, 0x00, 2);
+
+ if (r0 < 0 || err)
+ return -EIO;
+
+ if (r0 != 0x8243)
+ return -ENODEV;
+
+ zc0301_attach_sensor(cam, &pb0330);
+
+ return 0;
+}
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
index 1f95c28..4363a91 100644
--- a/drivers/media/video/zc0301/zc0301_sensor.h
+++ b/drivers/media/video/zc0301/zc0301_sensor.h
@@ -1,5 +1,5 @@
/***************************************************************************
- * API for image sensors connected to the ZC030! Image Processor and *
+ * API for image sensors connected to the ZC0301 Image Processor and *
* Control Chip *
* *
* Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
@@ -35,11 +35,13 @@ struct zc0301_sensor;
/*****************************************************************************/
extern int zc0301_probe_pas202bcb(struct zc0301_device* cam);
+extern int zc0301_probe_pb0330(struct zc0301_device* cam);
#define ZC0301_SENSOR_TABLE \
/* Weak detections must go at the end of the list */ \
static int (*zc0301_sensor_table[])(struct zc0301_device*) = { \
&zc0301_probe_pas202bcb, \
+ &zc0301_probe_pb0330, \
NULL, \
};
@@ -58,14 +60,28 @@ zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor);
#define ZC0301_ID_TABLE \
static const struct usb_device_id zc0301_id_table[] = { \
- { ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), }, \
+ { ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), }, /* ICM105 */ \
{ ZC0301_USB_DEVICE(0x041e, 0x401c, 0xff), }, /* PAS106 */ \
- { ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131B */ \
+ { ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131 */ \
+ { ZC0301_USB_DEVICE(0x041e, 0x401f, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x041e, 0x4022, 0xff), }, \
{ ZC0301_USB_DEVICE(0x041e, 0x4034, 0xff), }, /* PAS106 */ \
{ ZC0301_USB_DEVICE(0x041e, 0x4035, 0xff), }, /* PAS106 */ \
- { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202BCB */ \
+ { ZC0301_USB_DEVICE(0x041e, 0x4036, 0xff), }, /* HV7131 */ \
+ { ZC0301_USB_DEVICE(0x041e, 0x403a, 0xff), }, /* HV7131 */ \
+ { ZC0301_USB_DEVICE(0x0458, 0x7007, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x0458, 0x700C, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x0458, 0x700f, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
+ { ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
{ ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), }, \
- { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130D */ \
+ { ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */ \
+ { ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */ \
+ { ZC0301_USB_DEVICE(0x10fd, 0x0128, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x10fd, 0x804e, 0xff), }, /* TAS5130 */ \
{ } \
};
diff --git a/drivers/media/video/zoran.h b/drivers/media/video/zoran.h
index 0166f55..ffcda95 100644
--- a/drivers/media/video/zoran.h
+++ b/drivers/media/video/zoran.h
@@ -159,7 +159,7 @@ Private IOCTL to set up for displaying MJPEG
#define BUZ_MAX_FRAME 256 /* Must be a power of 2 */
#define BUZ_MASK_FRAME 255 /* Must be BUZ_MAX_FRAME-1 */
-#define BUZ_MAX_INPUT 8
+#define BUZ_MAX_INPUT 16
#if VIDEO_MAX_FRAME <= 32
# define V4L_MAX_FRAME 32
@@ -191,6 +191,9 @@ enum card_type {
/* Iomega */
BUZ,
+ /* AverMedia */
+ AVS6EYES,
+
/* total number of cards */
NUM_CARDS
};
@@ -379,6 +382,9 @@ struct card_info {
/* is the /GWS line conected? */
u8 gws_not_connected;
+ /* avs6eyes mux setting */
+ u8 input_mux;
+
void (*init) (struct zoran * zr);
};
diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
index 0a85c9e..958c1e6 100644
--- a/drivers/media/video/zoran_card.c
+++ b/drivers/media/video/zoran_card.c
@@ -27,6 +27,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <linux/delay.h>
+
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -38,6 +40,7 @@
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/spinlock.h>
#include <linux/sem.h>
#include <linux/kmod.h>
@@ -93,6 +96,11 @@ module_param(default_input, int, 0);
MODULE_PARM_DESC(default_input,
"Default input (0=Composite, 1=S-Video, 2=Internal)");
+static int default_mux = 1; /* 6 Eyes input selection */
+module_param(default_mux, int, 0);
+MODULE_PARM_DESC(default_mux,
+ "Default 6 Eyes mux setting (Input selection)");
+
static int default_norm = 0; /* 0=PAL, 1=NTSC 2=SECAM */
module_param(default_norm, int, 0);
MODULE_PARM_DESC(default_norm, "Default norm (0=PAL, 1=NTSC, 2=SECAM)");
@@ -301,6 +309,30 @@ lml33_init (struct zoran *zr)
GPIO(zr, 2, 1); // Set Composite input/output
}
+static void
+avs6eyes_init (struct zoran *zr)
+{
+ // AverMedia 6-Eyes original driver by Christer Weinigel
+
+ // Lifted straight from Christer's old driver and
+ // modified slightly by Martin Samuelsson.
+
+ int mux = default_mux; /* 1 = BT866, 7 = VID1 */
+
+ GPIO(zr, 4, 1); /* Bt866 SLEEP on */
+ udelay(2);
+
+ GPIO(zr, 0, 1); /* ZR36060 /RESET on */
+ GPIO(zr, 1, 0); /* ZR36060 /SLEEP on */
+ GPIO(zr, 2, mux & 1); /* MUX S0 */
+ GPIO(zr, 3, 0); /* /FRAME on */
+ GPIO(zr, 4, 0); /* Bt866 SLEEP off */
+ GPIO(zr, 5, mux & 2); /* MUX S1 */
+ GPIO(zr, 6, 0); /* ? */
+ GPIO(zr, 7, mux & 4); /* MUX S2 */
+
+}
+
static char *
i2cid_to_modulename (u16 i2c_id)
{
@@ -391,6 +423,14 @@ static struct tvnorm f60sqpixel_dc10 = { 780, 640, 0, 716, 525, 480, 12 };
static struct tvnorm f50ccir601_lm33r10 = { 864, 720, 74+54, 804, 625, 576, 18 };
static struct tvnorm f60ccir601_lm33r10 = { 858, 720, 56+54, 788, 525, 480, 16 };
+/* FIXME: The ks0127 seem incapable of swapping U and V, too, which is why I
+ * copy Maxim's left shift hack for the 6 Eyes.
+ *
+ * Christer's driver used the unshifted norms, though...
+ * /Sam */
+static struct tvnorm f50ccir601_avs6eyes = { 864, 720, 74, 804, 625, 576, 18 };
+static struct tvnorm f60ccir601_avs6eyes = { 858, 720, 56, 788, 525, 480, 16 };
+
static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
{
.type = DC10_old,
@@ -419,6 +459,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.gpcs = { -1, 0 },
.vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
.gws_not_connected = 0,
+ .input_mux = 0,
.init = &dc10_init,
}, {
.type = DC10_new,
@@ -445,6 +486,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.gpcs = { -1, 1},
.vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 },
.gws_not_connected = 0,
+ .input_mux = 0,
.init = &dc10plus_init,
}, {
.type = DC10plus,
@@ -474,6 +516,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.gpcs = { -1, 1 },
.vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 },
.gws_not_connected = 0,
+ .input_mux = 0,
.init = &dc10plus_init,
}, {
.type = DC30,
@@ -502,6 +545,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.gpcs = { -1, 0 },
.vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
.gws_not_connected = 0,
+ .input_mux = 0,
.init = &dc10_init,
}, {
.type = DC30plus,
@@ -532,6 +576,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.gpcs = { -1, 0 },
.vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
.gws_not_connected = 0,
+ .input_mux = 0,
.init = &dc10_init,
}, {
.type = LML33,
@@ -558,6 +603,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.gpcs = { 3, 1 },
.vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
.gws_not_connected = 1,
+ .input_mux = 0,
.init = &lml33_init,
}, {
.type = LML33R10,
@@ -586,6 +632,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.gpcs = { 3, 1 },
.vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
.gws_not_connected = 1,
+ .input_mux = 0,
.init = &lml33_init,
}, {
.type = BUZ,
@@ -614,8 +661,49 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.gpcs = { 3, 1 },
.vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
.gws_not_connected = 1,
+ .input_mux = 0,
.init = &buz_init,
+ }, {
+ .type = AVS6EYES,
+ .name = "6-Eyes",
+ /* AverMedia chose not to brand the 6-Eyes. Thus it
+ can't be autodetected, and requires card=x. */
+ .vendor_id = -1,
+ .device_id = -1,
+ .i2c_decoder = I2C_DRIVERID_KS0127,
+ .i2c_encoder = I2C_DRIVERID_BT866,
+ .video_codec = CODEC_TYPE_ZR36060,
+
+ .inputs = 10,
+ .input = {
+ { 0, "Composite 1" },
+ { 1, "Composite 2" },
+ { 2, "Composite 3" },
+ { 4, "Composite 4" },
+ { 5, "Composite 5" },
+ { 6, "Composite 6" },
+ { 8, "S-Video 1" },
+ { 9, "S-Video 2" },
+ {10, "S-Video 3" },
+ {15, "YCbCr" }
+ },
+ .norms = 2,
+ .tvn = {
+ &f50ccir601_avs6eyes,
+ &f60ccir601_avs6eyes,
+ NULL
+ },
+ .jpeg_int = ZR36057_ISR_GIRQ1,
+ .vsync_int = ZR36057_ISR_GIRQ0,
+ .gpio = { 1, 0, 3, -1, -1, -1, -1, -1 },// Validity unknown /Sam
+ .gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, // Validity unknown /Sam
+ .gpcs = { 3, 1 }, // Validity unknown /Sam
+ .vfe_pol = { 1, 0, 0, 0, 0, 1, 0, 0 }, // Validity unknown /Sam
+ .gws_not_connected = 1,
+ .input_mux = 1,
+ .init = &avs6eyes_init,
}
+
};
/*
diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c
index c690b2e..02168d9 100644
--- a/drivers/media/video/zoran_device.c
+++ b/drivers/media/video/zoran_device.c
@@ -536,7 +536,7 @@ zr36057_overlay (struct zoran *zr,
* All error messages are internal driver checking only! */
/* video display top and bottom registers */
- reg = (u32) zr->buffer.base +
+ reg = (long) zr->buffer.base +
zr->overlay_settings.x *
((zr->overlay_settings.format->depth + 7) / 8) +
zr->overlay_settings.y *
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index b5a576a..9711f62 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -73,6 +73,7 @@
)
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include "videocodec.h"
#include <asm/io.h>
@@ -2047,7 +2048,7 @@ zoran_do_ioctl (struct inode *inode,
dprintk(3, KERN_DEBUG "%s: VIDIOCGCAP\n", ZR_DEVNAME(zr));
memset(vcap, 0, sizeof(struct video_capability));
- strncpy(vcap->name, ZR_DEVNAME(zr), sizeof(vcap->name));
+ strncpy(vcap->name, ZR_DEVNAME(zr), sizeof(vcap->name)-1);
vcap->type = ZORAN_VID_TYPE;
vcap->channels = zr->card.inputs;
@@ -2689,8 +2690,8 @@ zoran_do_ioctl (struct inode *inode,
dprintk(3, KERN_DEBUG "%s: VIDIOC_QUERYCAP\n", ZR_DEVNAME(zr));
memset(cap, 0, sizeof(*cap));
- strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card));
- strncpy(cap->driver, "zoran", sizeof(cap->driver));
+ strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)-1);
+ strncpy(cap->driver, "zoran", sizeof(cap->driver)-1);
snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
pci_name(zr->pci_dev));
cap->version =
@@ -2742,7 +2743,7 @@ zoran_do_ioctl (struct inode *inode,
memset(fmt, 0, sizeof(*fmt));
fmt->index = index;
fmt->type = type;
- strncpy(fmt->description, zoran_formats[i].name, 31);
+ strncpy(fmt->description, zoran_formats[i].name, sizeof(fmt->description)-1);
fmt->pixelformat = zoran_formats[i].fourcc;
if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED)
fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
@@ -3566,16 +3567,16 @@ zoran_do_ioctl (struct inode *inode,
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- strncpy(ctrl->name, "Brightness", 31);
+ strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)-1);
break;
case V4L2_CID_CONTRAST:
- strncpy(ctrl->name, "Contrast", 31);
+ strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)-1);
break;
case V4L2_CID_SATURATION:
- strncpy(ctrl->name, "Saturation", 31);
+ strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)-1);
break;
case V4L2_CID_HUE:
- strncpy(ctrl->name, "Hue", 31);
+ strncpy(ctrl->name, "Hue", sizeof(ctrl->name)-1);
break;
}
@@ -3693,7 +3694,7 @@ zoran_do_ioctl (struct inode *inode,
&caps);
if (caps.flags & VIDEO_DECODER_AUTO) {
std->id = V4L2_STD_ALL;
- strncpy(std->name, "Autodetect", 31);
+ strncpy(std->name, "Autodetect", sizeof(std->name)-1);
return 0;
} else
return -EINVAL;
@@ -3701,21 +3702,21 @@ zoran_do_ioctl (struct inode *inode,
switch (std->index) {
case 0:
std->id = V4L2_STD_PAL;
- strncpy(std->name, "PAL", 31);
+ strncpy(std->name, "PAL", sizeof(std->name)-1);
std->frameperiod.numerator = 1;
std->frameperiod.denominator = 25;
std->framelines = zr->card.tvn[0]->Ht;
break;
case 1:
std->id = V4L2_STD_NTSC;
- strncpy(std->name, "NTSC", 31);
+ strncpy(std->name, "NTSC", sizeof(std->name)-1);
std->frameperiod.numerator = 1001;
std->frameperiod.denominator = 30000;
std->framelines = zr->card.tvn[1]->Ht;
break;
case 2:
std->id = V4L2_STD_SECAM;
- strncpy(std->name, "SECAM", 31);
+ strncpy(std->name, "SECAM", sizeof(std->name)-1);
std->frameperiod.numerator = 1;
std->frameperiod.denominator = 25;
std->framelines = zr->card.tvn[2]->Ht;
@@ -3871,7 +3872,7 @@ zoran_do_ioctl (struct inode *inode,
memset(outp, 0, sizeof(*outp));
outp->index = 0;
outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY;
- strncpy(outp->name, "Autodetect", 31);
+ strncpy(outp->name, "Autodetect", sizeof(outp->name)-1);
return 0;
}
diff --git a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran_procfs.c
index a00fae9..f4ffe79 100644
--- a/drivers/media/video/zoran_procfs.c
+++ b/drivers/media/video/zoran_procfs.c
@@ -43,6 +43,7 @@
#include <linux/seq_file.h>
#include <linux/ctype.h>
+#include <linux/poll.h>
#include <asm/io.h>
#include "videocodec.h"
diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c
index 26a230b..4a35caf 100644
--- a/drivers/misc/ibmasm/ibmasmfs.c
+++ b/drivers/misc/ibmasm/ibmasmfs.c
@@ -90,10 +90,11 @@ static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root);
static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent);
-static struct super_block *ibmasmfs_get_super(struct file_system_type *fst,
- int flags, const char *name, void *data)
+static int ibmasmfs_get_super(struct file_system_type *fst,
+ int flags, const char *name, void *data,
+ struct vfsmount *mnt)
{
- return get_sb_single(fst, flags, data, ibmasmfs_fill_super);
+ return get_sb_single(fst, flags, data, ibmasmfs_fill_super, mnt);
}
static struct super_operations ibmasmfs_s_ops = {
diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c
index 88f0eef..3228516 100644
--- a/drivers/mmc/at91_mci.c
+++ b/drivers/mmc/at91_mci.c
@@ -81,13 +81,6 @@
#undef SUPPORT_4WIRE
-#ifdef CONFIG_MMC_DEBUG
-#define DBG(fmt...) \
- printk(fmt)
-#else
-#define DBG(fmt...) do { } while (0)
-#endif
-
static struct clk *mci_clk;
#define FL_SENT_COMMAND (1 << 0)
@@ -202,50 +195,50 @@ static void at91mci_pre_dma_read(struct at91mci_host *host)
struct mmc_command *cmd;
struct mmc_data *data;
- DBG("pre dma read\n");
+ pr_debug("pre dma read\n");
cmd = host->cmd;
if (!cmd) {
- DBG("no command\n");
+ pr_debug("no command\n");
return;
}
data = cmd->data;
if (!data) {
- DBG("no data\n");
+ pr_debug("no data\n");
return;
}
for (i = 0; i < 2; i++) {
/* nothing left to transfer */
if (host->transfer_index >= data->sg_len) {
- DBG("Nothing left to transfer (index = %d)\n", host->transfer_index);
+ pr_debug("Nothing left to transfer (index = %d)\n", host->transfer_index);
break;
}
/* Check to see if this needs filling */
if (i == 0) {
if (at91_mci_read(AT91_PDC_RCR) != 0) {
- DBG("Transfer active in current\n");
+ pr_debug("Transfer active in current\n");
continue;
}
}
else {
if (at91_mci_read(AT91_PDC_RNCR) != 0) {
- DBG("Transfer active in next\n");
+ pr_debug("Transfer active in next\n");
continue;
}
}
/* Setup the next transfer */
- DBG("Using transfer index %d\n", host->transfer_index);
+ pr_debug("Using transfer index %d\n", host->transfer_index);
sg = &data->sg[host->transfer_index++];
- DBG("sg = %p\n", sg);
+ pr_debug("sg = %p\n", sg);
sg->dma_address = dma_map_page(NULL, sg->page, sg->offset, sg->length, DMA_FROM_DEVICE);
- DBG("dma address = %08X, length = %d\n", sg->dma_address, sg->length);
+ pr_debug("dma address = %08X, length = %d\n", sg->dma_address, sg->length);
if (i == 0) {
at91_mci_write(AT91_PDC_RPR, sg->dma_address);
@@ -257,7 +250,7 @@ static void at91mci_pre_dma_read(struct at91mci_host *host)
}
}
- DBG("pre dma read done\n");
+ pr_debug("pre dma read done\n");
}
/*
@@ -268,17 +261,17 @@ static void at91mci_post_dma_read(struct at91mci_host *host)
struct mmc_command *cmd;
struct mmc_data *data;
- DBG("post dma read\n");
+ pr_debug("post dma read\n");
cmd = host->cmd;
if (!cmd) {
- DBG("no command\n");
+ pr_debug("no command\n");
return;
}
data = cmd->data;
if (!data) {
- DBG("no data\n");
+ pr_debug("no data\n");
return;
}
@@ -289,17 +282,17 @@ static void at91mci_post_dma_read(struct at91mci_host *host)
struct scatterlist *sg;
- DBG("finishing index %d\n", host->in_use_index);
+ pr_debug("finishing index %d\n", host->in_use_index);
sg = &data->sg[host->in_use_index++];
- DBG("Unmapping page %08X\n", sg->dma_address);
+ pr_debug("Unmapping page %08X\n", sg->dma_address);
dma_unmap_page(NULL, sg->dma_address, sg->length, DMA_FROM_DEVICE);
/* Swap the contents of the buffer */
buffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
- DBG("buffer = %p, length = %d\n", buffer, sg->length);
+ pr_debug("buffer = %p, length = %d\n", buffer, sg->length);
data->bytes_xfered += sg->length;
@@ -320,7 +313,7 @@ static void at91mci_post_dma_read(struct at91mci_host *host)
at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
}
- DBG("post dma read done\n");
+ pr_debug("post dma read done\n");
}
/*
@@ -331,7 +324,7 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host)
struct mmc_command *cmd;
struct mmc_data *data;
- DBG("Handling the transmit\n");
+ pr_debug("Handling the transmit\n");
/* Disable the transfer */
at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
@@ -387,12 +380,12 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_
/* Not sure if this is needed */
#if 0
if ((at91_mci_read(AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) {
- DBG("Clearing timeout\n");
+ pr_debug("Clearing timeout\n");
at91_mci_write(AT91_MCI_ARGR, 0);
at91_mci_write(AT91_MCI_CMDR, AT91_MCI_OPDCMD);
while (!(at91_mci_read(AT91_MCI_SR) & AT91_MCI_CMDRDY)) {
/* spin */
- DBG("Clearing: SR = %08X\n", at91_mci_read(AT91_MCI_SR));
+ pr_debug("Clearing: SR = %08X\n", at91_mci_read(AT91_MCI_SR));
}
}
#endif
@@ -411,7 +404,7 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_
}
if (data) {
- block_length = 1 << data->blksz_bits;
+ block_length = data->blksz;
blocks = data->blocks;
/* always set data start - also set direction flag for read */
@@ -439,7 +432,7 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_
/*
* Set the arguments and send the command
*/
- DBG("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08lX)\n",
+ pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08lX)\n",
cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(AT91_MCI_MR));
if (!data) {
@@ -491,7 +484,7 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_
at91mci_sg_to_dma(host, data);
- DBG("Transmitting %d bytes\n", host->total_length);
+ pr_debug("Transmitting %d bytes\n", host->total_length);
at91_mci_write(AT91_PDC_TPR, host->physical_address);
at91_mci_write(AT91_PDC_TCR, host->total_length / 4);
@@ -525,7 +518,7 @@ static void at91mci_process_command(struct at91mci_host *host, struct mmc_comman
ier = at91_mci_send_command(host, cmd);
- DBG("setting ier to %08X\n", ier);
+ pr_debug("setting ier to %08X\n", ier);
/* Stop on errors or the required value */
at91_mci_write(AT91_MCI_IER, 0xffff0000 | ier);
@@ -570,7 +563,7 @@ static void at91mci_completed_command(struct at91mci_host *host)
status = at91_mci_read(AT91_MCI_SR);
- DBG("Status = %08X [%08X %08X %08X %08X]\n",
+ pr_debug("Status = %08X [%08X %08X %08X %08X]\n",
status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
if (status & (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE |
@@ -590,7 +583,7 @@ static void at91mci_completed_command(struct at91mci_host *host)
else
cmd->error = MMC_ERR_FAILED;
- DBG("Error detected and set to %d (cmd = %d, retries = %d)\n",
+ pr_debug("Error detected and set to %d (cmd = %d, retries = %d)\n",
cmd->error, cmd->opcode, cmd->retries);
}
}
@@ -621,10 +614,7 @@ static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
struct at91mci_host *host = mmc_priv(mmc);
unsigned long at91_master_clock = clk_get_rate(mci_clk);
- if (host)
- host->bus_mode = ios->bus_mode;
- else
- printk("MMC: No host for bus_mode\n");
+ host->bus_mode = ios->bus_mode;
if (ios->clock == 0) {
/* Disable the MCI controller */
@@ -640,15 +630,15 @@ static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
else
clkdiv = (at91_master_clock / ios->clock) / 2;
- DBG("clkdiv = %d. mcck = %ld\n", clkdiv,
+ pr_debug("clkdiv = %d. mcck = %ld\n", clkdiv,
at91_master_clock / (2 * (clkdiv + 1)));
}
if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) {
- DBG("MMC: Setting controller bus width to 4\n");
+ pr_debug("MMC: Setting controller bus width to 4\n");
at91_mci_write(AT91_MCI_SDCR, at91_mci_read(AT91_MCI_SDCR) | AT91_MCI_SDCBUS);
}
else {
- DBG("MMC: Setting controller bus width to 1\n");
+ pr_debug("MMC: Setting controller bus width to 1\n");
at91_mci_write(AT91_MCI_SDCR, at91_mci_read(AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
}
@@ -656,7 +646,7 @@ static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
at91_mci_write(AT91_MCI_MR, (at91_mci_read(AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv);
/* maybe switch power to the card */
- if (host && host->board->vcc_pin) {
+ if (host->board->vcc_pin) {
switch (ios->power_mode) {
case MMC_POWER_OFF:
at91_set_gpio_output(host->board->vcc_pin, 0);
@@ -679,11 +669,8 @@ static irqreturn_t at91_mci_irq(int irq, void *devid, struct pt_regs *regs)
unsigned int int_status;
- if (host == NULL)
- return IRQ_HANDLED;
-
int_status = at91_mci_read(AT91_MCI_SR);
- DBG("MCI irq: status = %08X, %08lX, %08lX\n", int_status, at91_mci_read(AT91_MCI_IMR),
+ pr_debug("MCI irq: status = %08X, %08lX, %08lX\n", int_status, at91_mci_read(AT91_MCI_IMR),
int_status & at91_mci_read(AT91_MCI_IMR));
if ((int_status & at91_mci_read(AT91_MCI_IMR)) & 0xffff0000)
@@ -692,75 +679,75 @@ static irqreturn_t at91_mci_irq(int irq, void *devid, struct pt_regs *regs)
int_status &= at91_mci_read(AT91_MCI_IMR);
if (int_status & AT91_MCI_UNRE)
- DBG("MMC: Underrun error\n");
+ pr_debug("MMC: Underrun error\n");
if (int_status & AT91_MCI_OVRE)
- DBG("MMC: Overrun error\n");
+ pr_debug("MMC: Overrun error\n");
if (int_status & AT91_MCI_DTOE)
- DBG("MMC: Data timeout\n");
+ pr_debug("MMC: Data timeout\n");
if (int_status & AT91_MCI_DCRCE)
- DBG("MMC: CRC error in data\n");
+ pr_debug("MMC: CRC error in data\n");
if (int_status & AT91_MCI_RTOE)
- DBG("MMC: Response timeout\n");
+ pr_debug("MMC: Response timeout\n");
if (int_status & AT91_MCI_RENDE)
- DBG("MMC: Response end bit error\n");
+ pr_debug("MMC: Response end bit error\n");
if (int_status & AT91_MCI_RCRCE)
- DBG("MMC: Response CRC error\n");
+ pr_debug("MMC: Response CRC error\n");
if (int_status & AT91_MCI_RDIRE)
- DBG("MMC: Response direction error\n");
+ pr_debug("MMC: Response direction error\n");
if (int_status & AT91_MCI_RINDE)
- DBG("MMC: Response index error\n");
+ pr_debug("MMC: Response index error\n");
/* Only continue processing if no errors */
if (!completed) {
if (int_status & AT91_MCI_TXBUFE) {
- DBG("TX buffer empty\n");
+ pr_debug("TX buffer empty\n");
at91_mci_handle_transmitted(host);
}
if (int_status & AT91_MCI_RXBUFF) {
- DBG("RX buffer full\n");
+ pr_debug("RX buffer full\n");
at91_mci_write(AT91_MCI_IER, AT91_MCI_CMDRDY);
}
if (int_status & AT91_MCI_ENDTX) {
- DBG("Transmit has ended\n");
+ pr_debug("Transmit has ended\n");
}
if (int_status & AT91_MCI_ENDRX) {
- DBG("Receive has ended\n");
+ pr_debug("Receive has ended\n");
at91mci_post_dma_read(host);
}
if (int_status & AT91_MCI_NOTBUSY) {
- DBG("Card is ready\n");
+ pr_debug("Card is ready\n");
at91_mci_write(AT91_MCI_IER, AT91_MCI_CMDRDY);
}
if (int_status & AT91_MCI_DTIP) {
- DBG("Data transfer in progress\n");
+ pr_debug("Data transfer in progress\n");
}
if (int_status & AT91_MCI_BLKE) {
- DBG("Block transfer has ended\n");
+ pr_debug("Block transfer has ended\n");
}
if (int_status & AT91_MCI_TXRDY) {
- DBG("Ready to transmit\n");
+ pr_debug("Ready to transmit\n");
}
if (int_status & AT91_MCI_RXRDY) {
- DBG("Ready to receive\n");
+ pr_debug("Ready to receive\n");
}
if (int_status & AT91_MCI_CMDRDY) {
- DBG("Command ready\n");
+ pr_debug("Command ready\n");
completed = 1;
}
}
at91_mci_write(AT91_MCI_IDR, int_status);
if (completed) {
- DBG("Completed command\n");
+ pr_debug("Completed command\n");
at91_mci_write(AT91_MCI_IDR, 0xffffffff);
at91mci_completed_command(host);
}
@@ -779,10 +766,10 @@ static irqreturn_t at91_mmc_det_irq(int irq, void *_host, struct pt_regs *regs)
*/
if (present != host->present) {
host->present = present;
- DBG("%s: card %s\n", mmc_hostname(host->mmc),
+ pr_debug("%s: card %s\n", mmc_hostname(host->mmc),
present ? "insert" : "remove");
if (!present) {
- DBG("****** Resetting SD-card bus width ******\n");
+ pr_debug("****** Resetting SD-card bus width ******\n");
at91_mci_write(AT91_MCI_SDCR, 0);
}
mmc_detect_change(host->mmc, msecs_to_jiffies(100));
@@ -822,13 +809,13 @@ static int at91_mci_probe(struct platform_device *pdev)
struct at91mci_host *host;
int ret;
- DBG("Probe MCI devices\n");
+ pr_debug("Probe MCI devices\n");
at91_mci_disable();
at91_mci_enable();
mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
if (!mmc) {
- DBG("Failed to allocate mmc host\n");
+ pr_debug("Failed to allocate mmc host\n");
return -ENOMEM;
}
@@ -854,8 +841,9 @@ static int at91_mci_probe(struct platform_device *pdev)
* Get Clock
*/
mci_clk = clk_get(&pdev->dev, "mci_clk");
- if (!mci_clk) {
+ if (IS_ERR(mci_clk)) {
printk(KERN_ERR "AT91 MMC: no clock defined.\n");
+ mmc_free_host(mmc);
return -ENODEV;
}
clk_enable(mci_clk); /* Enable the peripheral clock */
@@ -865,7 +853,10 @@ static int at91_mci_probe(struct platform_device *pdev)
*/
ret = request_irq(AT91_ID_MCI, at91_mci_irq, SA_SHIRQ, DRIVER_NAME, host);
if (ret) {
- DBG("Failed to request MCI interrupt\n");
+ printk(KERN_ERR "Failed to request MCI interrupt\n");
+ clk_disable(mci_clk);
+ clk_put(mci_clk);
+ mmc_free_host(mmc);
return ret;
}
@@ -886,12 +877,12 @@ static int at91_mci_probe(struct platform_device *pdev)
*/
if (host->board->det_pin) {
ret = request_irq(host->board->det_pin, at91_mmc_det_irq,
- SA_SAMPLE_RANDOM, DRIVER_NAME, host);
+ 0, DRIVER_NAME, host);
if (ret)
- DBG("couldn't allocate MMC detect irq\n");
+ printk(KERN_ERR "couldn't allocate MMC detect irq\n");
}
- DBG(KERN_INFO "Added MCI driver\n");
+ pr_debug(KERN_INFO "Added MCI driver\n");
return 0;
}
@@ -924,7 +915,7 @@ static int at91_mci_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
- DBG("Removed\n");
+ pr_debug("MCI Removed\n");
return 0;
}
diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c
index a4eb1d0..5c62f4e 100644
--- a/drivers/mmc/imxmmc.c
+++ b/drivers/mmc/imxmmc.c
@@ -228,7 +228,7 @@ static int imxmci_busy_wait_for_status(struct imxmci_host *host,
static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
{
unsigned int nob = data->blocks;
- unsigned int blksz = 1 << data->blksz_bits;
+ unsigned int blksz = data->blksz;
unsigned int datasz = nob * blksz;
int i;
diff --git a/drivers/mmc/omap.c b/drivers/mmc/omap.c
index becb3c6..c25244b 100644
--- a/drivers/mmc/omap.c
+++ b/drivers/mmc/omap.c
@@ -584,10 +584,10 @@ mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data)
int sync_dev = 0;
data_addr = io_v2p((u32) host->base) + OMAP_MMC_REG_DATA;
- frame = 1 << data->blksz_bits;
+ frame = data->blksz;
count = sg_dma_len(sg);
- if ((data->blocks == 1) && (count > (1 << data->blksz_bits)))
+ if ((data->blocks == 1) && (count > data->blksz))
count = frame;
host->dma_len = count;
@@ -776,7 +776,7 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
}
- block_size = 1 << data->blksz_bits;
+ block_size = data->blksz;
OMAP_MMC_WRITE(host->base, NBLK, data->blocks - 1);
OMAP_MMC_WRITE(host->base, BLEN, block_size - 1);
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 6bfcdbc..8e9100b 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -268,7 +268,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
}
DBG("blksz %04x blks %04x flags %08x\n",
- 1 << data->blksz_bits, data->blocks, data->flags);
+ data->blksz, data->blocks, data->flags);
DBG("tsac %d ms nsac %d clk\n",
data->timeout_ns / 1000000, data->timeout_clks);
@@ -282,7 +282,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE);
- writew(1 << data->blksz_bits, host->ioaddr + SDHCI_BLOCK_SIZE);
+ writew(data->blksz, host->ioaddr + SDHCI_BLOCK_SIZE);
writew(data->blocks, host->ioaddr + SDHCI_BLOCK_COUNT);
if (host->flags & SDHCI_USE_DMA) {
@@ -294,7 +294,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
writel(sg_dma_address(data->sg), host->ioaddr + SDHCI_DMA_ADDRESS);
} else {
- host->size = (1 << data->blksz_bits) * data->blocks;
+ host->size = data->blksz * data->blocks;
host->cur_sg = data->sg;
host->num_sg = data->sg_len;
@@ -335,7 +335,7 @@ static void sdhci_finish_data(struct sdhci_host *host)
blocks = 0;
else
blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT);
- data->bytes_xfered = (1 << data->blksz_bits) * (data->blocks - blocks);
+ data->bytes_xfered = data->blksz * (data->blocks - blocks);
if ((data->error == MMC_ERR_NONE) && blocks) {
printk(KERN_ERR "%s: Controller signalled completion even "
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index 1b1cb00..157eda5 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -1031,8 +1031,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
return 1;
}
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL) {
+ if (skb_padto(skb, ETH_ZLEN)) {
netif_wake_queue(dev);
return 0;
}
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 46d8c01..0cdc830 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -401,6 +401,11 @@ static void cp_clean_rings (struct cp_private *cp);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void cp_poll_controller(struct net_device *dev);
#endif
+static int cp_get_eeprom_len(struct net_device *dev);
+static int cp_get_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 *data);
+static int cp_set_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 *data);
static struct pci_device_id cp_pci_tbl[] = {
{ PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139,
@@ -792,7 +797,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
entry = cp->tx_head;
eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
if (dev->features & NETIF_F_TSO)
- mss = skb_shinfo(skb)->tso_size;
+ mss = skb_shinfo(skb)->gso_size;
if (skb_shinfo(skb)->nr_frags == 0) {
struct cp_desc *txd = &cp->tx_ring[entry];
@@ -1577,6 +1582,9 @@ static struct ethtool_ops cp_ethtool_ops = {
.get_strings = cp_get_strings,
.get_ethtool_stats = cp_get_ethtool_stats,
.get_perm_addr = ethtool_op_get_perm_addr,
+ .get_eeprom_len = cp_get_eeprom_len,
+ .get_eeprom = cp_get_eeprom,
+ .set_eeprom = cp_set_eeprom,
};
static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
@@ -1612,24 +1620,32 @@ static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
#define eeprom_delay() readl(ee_addr)
/* The EEPROM commands include the alway-set leading bit. */
+#define EE_EXTEND_CMD (4)
#define EE_WRITE_CMD (5)
#define EE_READ_CMD (6)
#define EE_ERASE_CMD (7)
-static int read_eeprom (void __iomem *ioaddr, int location, int addr_len)
-{
- int i;
- unsigned retval = 0;
- void __iomem *ee_addr = ioaddr + Cfg9346;
- int read_cmd = location | (EE_READ_CMD << addr_len);
+#define EE_EWDS_ADDR (0)
+#define EE_WRAL_ADDR (1)
+#define EE_ERAL_ADDR (2)
+#define EE_EWEN_ADDR (3)
+
+#define CP_EEPROM_MAGIC PCI_DEVICE_ID_REALTEK_8139
+static void eeprom_cmd_start(void __iomem *ee_addr)
+{
writeb (EE_ENB & ~EE_CS, ee_addr);
writeb (EE_ENB, ee_addr);
eeprom_delay ();
+}
- /* Shift the read command bits out. */
- for (i = 4 + addr_len; i >= 0; i--) {
- int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+static void eeprom_cmd(void __iomem *ee_addr, int cmd, int cmd_len)
+{
+ int i;
+
+ /* Shift the command bits out. */
+ for (i = cmd_len - 1; i >= 0; i--) {
+ int dataval = (cmd & (1 << i)) ? EE_DATA_WRITE : 0;
writeb (EE_ENB | dataval, ee_addr);
eeprom_delay ();
writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
@@ -1637,6 +1653,33 @@ static int read_eeprom (void __iomem *ioaddr, int location, int addr_len)
}
writeb (EE_ENB, ee_addr);
eeprom_delay ();
+}
+
+static void eeprom_cmd_end(void __iomem *ee_addr)
+{
+ writeb (~EE_CS, ee_addr);
+ eeprom_delay ();
+}
+
+static void eeprom_extend_cmd(void __iomem *ee_addr, int extend_cmd,
+ int addr_len)
+{
+ int cmd = (EE_EXTEND_CMD << addr_len) | (extend_cmd << (addr_len - 2));
+
+ eeprom_cmd_start(ee_addr);
+ eeprom_cmd(ee_addr, cmd, 3 + addr_len);
+ eeprom_cmd_end(ee_addr);
+}
+
+static u16 read_eeprom (void __iomem *ioaddr, int location, int addr_len)
+{
+ int i;
+ u16 retval = 0;
+ void __iomem *ee_addr = ioaddr + Cfg9346;
+ int read_cmd = location | (EE_READ_CMD << addr_len);
+
+ eeprom_cmd_start(ee_addr);
+ eeprom_cmd(ee_addr, read_cmd, 3 + addr_len);
for (i = 16; i > 0; i--) {
writeb (EE_ENB | EE_SHIFT_CLK, ee_addr);
@@ -1648,13 +1691,125 @@ static int read_eeprom (void __iomem *ioaddr, int location, int addr_len)
eeprom_delay ();
}
- /* Terminate the EEPROM access. */
- writeb (~EE_CS, ee_addr);
- eeprom_delay ();
+ eeprom_cmd_end(ee_addr);
return retval;
}
+static void write_eeprom(void __iomem *ioaddr, int location, u16 val,
+ int addr_len)
+{
+ int i;
+ void __iomem *ee_addr = ioaddr + Cfg9346;
+ int write_cmd = location | (EE_WRITE_CMD << addr_len);
+
+ eeprom_extend_cmd(ee_addr, EE_EWEN_ADDR, addr_len);
+
+ eeprom_cmd_start(ee_addr);
+ eeprom_cmd(ee_addr, write_cmd, 3 + addr_len);
+ eeprom_cmd(ee_addr, val, 16);
+ eeprom_cmd_end(ee_addr);
+
+ eeprom_cmd_start(ee_addr);
+ for (i = 0; i < 20000; i++)
+ if (readb(ee_addr) & EE_DATA_READ)
+ break;
+ eeprom_cmd_end(ee_addr);
+
+ eeprom_extend_cmd(ee_addr, EE_EWDS_ADDR, addr_len);
+}
+
+static int cp_get_eeprom_len(struct net_device *dev)
+{
+ struct cp_private *cp = netdev_priv(dev);
+ int size;
+
+ spin_lock_irq(&cp->lock);
+ size = read_eeprom(cp->regs, 0, 8) == 0x8129 ? 256 : 128;
+ spin_unlock_irq(&cp->lock);
+
+ return size;
+}
+
+static int cp_get_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ struct cp_private *cp = netdev_priv(dev);
+ unsigned int addr_len;
+ u16 val;
+ u32 offset = eeprom->offset >> 1;
+ u32 len = eeprom->len;
+ u32 i = 0;
+
+ eeprom->magic = CP_EEPROM_MAGIC;
+
+ spin_lock_irq(&cp->lock);
+
+ addr_len = read_eeprom(cp->regs, 0, 8) == 0x8129 ? 8 : 6;
+
+ if (eeprom->offset & 1) {
+ val = read_eeprom(cp->regs, offset, addr_len);
+ data[i++] = (u8)(val >> 8);
+ offset++;
+ }
+
+ while (i < len - 1) {
+ val = read_eeprom(cp->regs, offset, addr_len);
+ data[i++] = (u8)val;
+ data[i++] = (u8)(val >> 8);
+ offset++;
+ }
+
+ if (i < len) {
+ val = read_eeprom(cp->regs, offset, addr_len);
+ data[i] = (u8)val;
+ }
+
+ spin_unlock_irq(&cp->lock);
+ return 0;
+}
+
+static int cp_set_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ struct cp_private *cp = netdev_priv(dev);
+ unsigned int addr_len;
+ u16 val;
+ u32 offset = eeprom->offset >> 1;
+ u32 len = eeprom->len;
+ u32 i = 0;
+
+ if (eeprom->magic != CP_EEPROM_MAGIC)
+ return -EINVAL;
+
+ spin_lock_irq(&cp->lock);
+
+ addr_len = read_eeprom(cp->regs, 0, 8) == 0x8129 ? 8 : 6;
+
+ if (eeprom->offset & 1) {
+ val = read_eeprom(cp->regs, offset, addr_len) & 0xff;
+ val |= (u16)data[i++] << 8;
+ write_eeprom(cp->regs, offset, val, addr_len);
+ offset++;
+ }
+
+ while (i < len - 1) {
+ val = (u16)data[i++];
+ val |= (u16)data[i++] << 8;
+ write_eeprom(cp->regs, offset, val, addr_len);
+ offset++;
+ }
+
+ if (i < len) {
+ val = read_eeprom(cp->regs, offset, addr_len) & 0xff00;
+ val |= (u16)data[i];
+ write_eeprom(cp->regs, offset, val, addr_len);
+ }
+
+ spin_unlock_irq(&cp->lock);
+ return 0;
+}
+
/* Put the board into D3cold state and wait for WakeUp signal */
static void cp_set_d3_state (struct cp_private *cp)
{
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index da0c878..8a9f7d6 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -1070,8 +1070,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb->len, (unsigned int)skb->data));
if (skb->len < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index f870274..86be96a 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -275,12 +275,14 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
int send_length = skb->len, output_page;
unsigned long flags;
+ char buf[ETH_ZLEN];
+ char *data = skb->data;
if (skb->len < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
- return 0;
+ memset(buf, 0, ETH_ZLEN); /* more efficient than doing just the needed bits */
+ memcpy(buf, data, skb->len);
send_length = ETH_ZLEN;
+ data = buf;
}
/* Mask interrupts from the ethercard.
@@ -347,7 +349,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
* trigger the send later, upon receiving a Tx done interrupt.
*/
- ei_block_output(dev, send_length, skb->data, output_page);
+ ei_block_output(dev, send_length, data, output_page);
if (! ei_local->txing)
{
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 0c6b45a..3918990 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -854,6 +854,17 @@ config SMC9194
<file:Documentation/networking/net-modules.txt>. The module
will be called smc9194.
+config NET_NETX
+ tristate "NetX Ethernet support"
+ select MII
+ depends on NET_ETHERNET && ARCH_NETX
+ help
+ This is support for the Hilscher netX builtin Ethernet ports
+
+ To compile this driver as a module, choose M here and read
+ <file:Documentation/networking/net-modules.txt>. The module
+ will be called netx-eth.
+
config DM9000
tristate "DM9000 support"
depends on (ARM || MIPS) && NET_ETHERNET
@@ -1376,8 +1387,8 @@ config APRICOT
called apricot.
config B44
- tristate "Broadcom 4400 ethernet support (EXPERIMENTAL)"
- depends on NET_PCI && PCI && EXPERIMENTAL
+ tristate "Broadcom 4400 ethernet support"
+ depends on NET_PCI && PCI
select MII
help
If you have a network (Ethernet) controller of this type, say Y and
@@ -2190,7 +2201,7 @@ config BNX2
config SPIDER_NET
tristate "Spider Gigabit Ethernet driver"
- depends on PCI && PPC_CELL
+ depends on PCI && PPC_IBM_CELL_BLADE
select FW_LOADER
help
This driver supports the Gigabit Ethernet chips present on the
@@ -2198,11 +2209,11 @@ config SPIDER_NET
config GIANFAR
tristate "Gianfar Ethernet"
- depends on 85xx || 83xx
+ depends on 85xx || 83xx || PPC_86xx
select PHYLIB
help
- This driver supports the Gigabit TSEC on the MPC85xx
- family of chips, and the FEC on the 8540
+ This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx,
+ and MPC86xx family of chips, and the FEC on the 8540.
config GFAR_NAPI
bool "NAPI Support"
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 1eced32..c91e951 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -187,6 +187,7 @@ obj-$(CONFIG_MACSONIC) += macsonic.o
obj-$(CONFIG_MACMACE) += macmace.o
obj-$(CONFIG_MAC89x0) += mac89x0.o
obj-$(CONFIG_TUN) += tun.o
+obj-$(CONFIG_NET_NETX) += netx-eth.o
obj-$(CONFIG_DL2K) += dl2k.o
obj-$(CONFIG_R8169) += r8169.o
obj-$(CONFIG_AMD8111_ETH) += amd8111e.o
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index 79bb56b..71165ac 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -573,8 +573,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
if (len < ETH_ZLEN) {
len = ETH_ZLEN;
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
}
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index d1b6b1f..a9bb7a4 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -607,8 +607,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* FIXME: is the 79C960 new enough to do its own padding right ? */
if (skb->len < ETH_ZLEN)
{
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
len = ETH_ZLEN;
}
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index 5503dc8..613005a 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -43,7 +43,9 @@
#define DRV_VERSION "1.0"
static struct net_device *at91_dev;
-static struct clk *ether_clk;
+
+static struct timer_list check_timer;
+#define LINK_POLL_INTERVAL (HZ)
/* ..................................................................... */
@@ -143,7 +145,7 @@ static void read_phy(unsigned char phy_addr, unsigned char address, unsigned int
* MAC accordingly.
* If no link or auto-negotiation is busy, then no changes are made.
*/
-static void update_linkspeed(struct net_device *dev)
+static void update_linkspeed(struct net_device *dev, int silent)
{
struct at91_private *lp = (struct at91_private *) dev->priv;
unsigned int bmsr, bmcr, lpa, mac_cfg;
@@ -151,7 +153,8 @@ static void update_linkspeed(struct net_device *dev)
if (!mii_link_ok(&lp->mii)) { /* no link */
netif_carrier_off(dev);
- printk(KERN_INFO "%s: Link down.\n", dev->name);
+ if (!silent)
+ printk(KERN_INFO "%s: Link down.\n", dev->name);
return;
}
@@ -186,7 +189,8 @@ static void update_linkspeed(struct net_device *dev)
}
at91_emac_write(AT91_EMAC_CFG, mac_cfg);
- printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
+ if (!silent)
+ printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
netif_carrier_on(dev);
}
@@ -226,7 +230,7 @@ static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id, struct pt_regs
goto done;
}
- update_linkspeed(dev);
+ update_linkspeed(dev, 0);
done:
disable_mdi();
@@ -243,14 +247,17 @@ static void enable_phyirq(struct net_device *dev)
unsigned int dsintr, irq_number;
int status;
- if (lp->phy_type == MII_RTL8201_ID) /* RTL8201 does not have an interrupt */
- return;
- if (lp->phy_type == MII_DP83847_ID) /* DP83847 does not have an interrupt */
- return;
- if (lp->phy_type == MII_AC101L_ID) /* AC101L interrupt not supported yet */
+ irq_number = lp->board_data.phy_irq_pin;
+ if (!irq_number) {
+ /*
+ * PHY doesn't have an IRQ pin (RTL8201, DP83847, AC101L),
+ * or board does not have it connected.
+ */
+ check_timer.expires = jiffies + LINK_POLL_INTERVAL;
+ add_timer(&check_timer);
return;
+ }
- irq_number = lp->board_data.phy_irq_pin;
status = request_irq(irq_number, at91ether_phy_interrupt, 0, dev->name, dev);
if (status) {
printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status);
@@ -292,12 +299,11 @@ static void disable_phyirq(struct net_device *dev)
unsigned int dsintr;
unsigned int irq_number;
- if (lp->phy_type == MII_RTL8201_ID) /* RTL8201 does not have an interrupt */
- return;
- if (lp->phy_type == MII_DP83847_ID) /* DP83847 does not have an interrupt */
- return;
- if (lp->phy_type == MII_AC101L_ID) /* AC101L interrupt not supported yet */
+ irq_number = lp->board_data.phy_irq_pin;
+ if (!irq_number) {
+ del_timer_sync(&check_timer);
return;
+ }
spin_lock_irq(&lp->lock);
enable_mdi();
@@ -326,7 +332,6 @@ static void disable_phyirq(struct net_device *dev)
disable_mdi();
spin_unlock_irq(&lp->lock);
- irq_number = lp->board_data.phy_irq_pin;
free_irq(irq_number, dev); /* Free interrupt handler */
}
@@ -355,6 +360,18 @@ static void reset_phy(struct net_device *dev)
}
#endif
+static void at91ether_check_link(unsigned long dev_id)
+{
+ struct net_device *dev = (struct net_device *) dev_id;
+
+ enable_mdi();
+ update_linkspeed(dev, 1);
+ disable_mdi();
+
+ check_timer.expires = jiffies + LINK_POLL_INTERVAL;
+ add_timer(&check_timer);
+}
+
/* ......................... ADDRESS MANAGEMENT ........................ */
/*
@@ -501,7 +518,7 @@ static int hash_get_index(__u8 *addr)
hash_index |= (bitval << j);
}
- return hash_index;
+ return hash_index;
}
/*
@@ -557,10 +574,8 @@ static void at91ether_set_rx_mode(struct net_device *dev)
at91_emac_write(AT91_EMAC_CFG, cfg);
}
-
/* ......................... ETHTOOL SUPPORT ........................... */
-
static int mdio_read(struct net_device *dev, int phy_id, int location)
{
unsigned int value;
@@ -642,6 +657,22 @@ static struct ethtool_ops at91ether_ethtool_ops = {
.get_link = ethtool_op_get_link,
};
+static int at91ether_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct at91_private *lp = (struct at91_private *) dev->priv;
+ int res;
+
+ if (!netif_running(dev))
+ return -EINVAL;
+
+ spin_lock_irq(&lp->lock);
+ enable_mdi();
+ res = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL);
+ disable_mdi();
+ spin_unlock_irq(&lp->lock);
+
+ return res;
+}
/* ................................ MAC ................................ */
@@ -685,10 +716,10 @@ static int at91ether_open(struct net_device *dev)
struct at91_private *lp = (struct at91_private *) dev->priv;
unsigned long ctl;
- if (!is_valid_ether_addr(dev->dev_addr))
- return -EADDRNOTAVAIL;
+ if (!is_valid_ether_addr(dev->dev_addr))
+ return -EADDRNOTAVAIL;
- clk_enable(ether_clk); /* Re-enable Peripheral clock */
+ clk_enable(lp->ether_clk); /* Re-enable Peripheral clock */
/* Clear internal statistics */
ctl = at91_emac_read(AT91_EMAC_CTL);
@@ -708,7 +739,7 @@ static int at91ether_open(struct net_device *dev)
/* Determine current link speed */
spin_lock_irq(&lp->lock);
enable_mdi();
- update_linkspeed(dev);
+ update_linkspeed(dev, 0);
disable_mdi();
spin_unlock_irq(&lp->lock);
@@ -722,6 +753,7 @@ static int at91ether_open(struct net_device *dev)
*/
static int at91ether_close(struct net_device *dev)
{
+ struct at91_private *lp = (struct at91_private *) dev->priv;
unsigned long ctl;
/* Disable Receiver and Transmitter */
@@ -738,7 +770,7 @@ static int at91ether_close(struct net_device *dev)
netif_stop_queue(dev);
- clk_disable(ether_clk); /* Disable Peripheral clock */
+ clk_disable(lp->ether_clk); /* Disable Peripheral clock */
return 0;
}
@@ -870,7 +902,7 @@ static irqreturn_t at91ether_interrupt(int irq, void *dev_id, struct pt_regs *re
if (intstatus & AT91_EMAC_RCOM) /* Receive complete */
at91ether_rx(dev);
- if (intstatus & AT91_EMAC_TCOM) { /* Transmit complete */
+ if (intstatus & AT91_EMAC_TCOM) { /* Transmit complete */
/* The TCOM bit is set even if the transmission failed. */
if (intstatus & (AT91_EMAC_TUND | AT91_EMAC_RTRY))
lp->stats.tx_errors += 1;
@@ -899,7 +931,8 @@ static irqreturn_t at91ether_interrupt(int irq, void *dev_id, struct pt_regs *re
/*
* Initialize the ethernet interface
*/
-static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_address, struct platform_device *pdev)
+static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_address,
+ struct platform_device *pdev, struct clk *ether_clk)
{
struct at91_eth_data *board_data = pdev->dev.platform_data;
struct net_device *dev;
@@ -933,6 +966,7 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
return -ENOMEM;
}
lp->board_data = *board_data;
+ lp->ether_clk = ether_clk;
platform_set_drvdata(pdev, dev);
spin_lock_init(&lp->lock);
@@ -945,6 +979,7 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
dev->set_multicast_list = at91ether_set_rx_mode;
dev->set_mac_address = set_mac_address;
dev->ethtool_ops = &at91ether_ethtool_ops;
+ dev->do_ioctl = at91ether_ioctl;
SET_NETDEV_DEV(dev, &pdev->dev);
@@ -975,6 +1010,9 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
lp->mii.dev = dev; /* Support for ethtool */
lp->mii.mdio_read = mdio_read;
lp->mii.mdio_write = mdio_write;
+ lp->mii.phy_id = phy_address;
+ lp->mii.phy_id_mask = 0x1f;
+ lp->mii.reg_num_mask = 0x1f;
lp->phy_type = phy_type; /* Type of PHY connected */
lp->phy_address = phy_address; /* MDI address of PHY */
@@ -992,11 +1030,18 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
/* Determine current link speed */
spin_lock_irq(&lp->lock);
enable_mdi();
- update_linkspeed(dev);
+ update_linkspeed(dev, 0);
disable_mdi();
spin_unlock_irq(&lp->lock);
netif_carrier_off(dev); /* will be enabled in open() */
+ /* If board has no PHY IRQ, use a timer to poll the PHY */
+ if (!lp->board_data.phy_irq_pin) {
+ init_timer(&check_timer);
+ check_timer.data = (unsigned long)dev;
+ check_timer.function = at91ether_check_link;
+ }
+
/* Display ethernet banner */
printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%02x:%02x:%02x:%02x:%02x:%02x)\n",
dev->name, (uint) dev->base_addr, dev->irq,
@@ -1005,7 +1050,7 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID))
- printk(KERN_INFO "%s: Davicom 9196 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)");
+ printk(KERN_INFO "%s: Davicom 9161 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)");
else if (phy_type == MII_LXT971A_ID)
printk(KERN_INFO "%s: Intel LXT971A PHY\n", dev->name);
else if (phy_type == MII_RTL8201_ID)
@@ -1031,9 +1076,10 @@ static int __init at91ether_probe(struct platform_device *pdev)
int detected = -1;
unsigned long phy_id;
unsigned short phy_address = 0;
+ struct clk *ether_clk;
ether_clk = clk_get(&pdev->dev, "ether_clk");
- if (!ether_clk) {
+ if (IS_ERR(ether_clk)) {
printk(KERN_ERR "at91_ether: no clock defined\n");
return -ENODEV;
}
@@ -1056,7 +1102,7 @@ static int __init at91ether_probe(struct platform_device *pdev)
case MII_DP83847_ID: /* National Semiconductor DP83847: */
case MII_AC101L_ID: /* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */
case MII_KS8721_ID: /* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
- detected = at91ether_setup(phy_id, phy_address, pdev);
+ detected = at91ether_setup(phy_id, phy_address, pdev, ether_clk);
break;
}
@@ -1075,17 +1121,61 @@ static int __devexit at91ether_remove(struct platform_device *pdev)
unregister_netdev(at91_dev);
free_irq(at91_dev->irq, at91_dev);
dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys);
- clk_put(ether_clk);
+ clk_put(lp->ether_clk);
free_netdev(at91_dev);
at91_dev = NULL;
return 0;
}
+#ifdef CONFIG_PM
+
+static int at91ether_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ struct at91_private *lp = (struct at91_private *) at91_dev->priv;
+ struct net_device *net_dev = platform_get_drvdata(pdev);
+ int phy_irq = lp->board_data.phy_irq_pin;
+
+ if (netif_running(net_dev)) {
+ if (phy_irq)
+ disable_irq(phy_irq);
+
+ netif_stop_queue(net_dev);
+ netif_device_detach(net_dev);
+
+ clk_disable(lp->ether_clk);
+ }
+ return 0;
+}
+
+static int at91ether_resume(struct platform_device *pdev)
+{
+ struct at91_private *lp = (struct at91_private *) at91_dev->priv;
+ struct net_device *net_dev = platform_get_drvdata(pdev);
+ int phy_irq = lp->board_data.phy_irq_pin;
+
+ if (netif_running(net_dev)) {
+ clk_enable(lp->ether_clk);
+
+ netif_device_attach(net_dev);
+ netif_start_queue(net_dev);
+
+ if (phy_irq)
+ enable_irq(phy_irq);
+ }
+ return 0;
+}
+
+#else
+#define at91ether_suspend NULL
+#define at91ether_resume NULL
+#endif
+
static struct platform_driver at91ether_driver = {
.probe = at91ether_probe,
.remove = __devexit_p(at91ether_remove),
- /* FIXME: support suspend and resume */
+ .suspend = at91ether_suspend,
+ .resume = at91ether_resume,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
diff --git a/drivers/net/arm/at91_ether.h b/drivers/net/arm/at91_ether.h
index 9885735..d1e72e0 100644
--- a/drivers/net/arm/at91_ether.h
+++ b/drivers/net/arm/at91_ether.h
@@ -80,6 +80,7 @@ struct at91_private
struct net_device_stats stats;
struct mii_if_info mii; /* ethtool support */
struct at91_eth_data board_data; /* board-specific configuration */
+ struct clk *ether_clk; /* clock */
/* PHY */
unsigned long phy_type; /* type of PHY (PHY_ID) */
diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
index 36475eb..312955d 100644
--- a/drivers/net/arm/ether1.c
+++ b/drivers/net/arm/ether1.c
@@ -700,8 +700,7 @@ ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
}
if (skb->len < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
goto out;
}
diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c
index f1d5b10..0810741 100644
--- a/drivers/net/arm/ether3.c
+++ b/drivers/net/arm/ether3.c
@@ -518,8 +518,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
length = (length + 1) & ~1;
if (length != skb->len) {
- skb = skb_padto(skb, length);
- if (skb == NULL)
+ if (skb_padto(skb, length))
goto out;
}
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index 442b2cb..91783a8 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -804,8 +804,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
++len;
if (len > skb->len) {
- skb = skb_padto(skb, len);
- if (skb == NULL)
+ if (skb_padto(skb, len))
return 0;
}
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index d8233e0..a7e4ba5 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -29,8 +29,8 @@
#define DRV_MODULE_NAME "b44"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.00"
-#define DRV_MODULE_RELDATE "Apr 7, 2006"
+#define DRV_MODULE_VERSION "1.01"
+#define DRV_MODULE_RELDATE "Jun 16, 2006"
#define B44_DEF_MSG_ENABLE \
(NETIF_MSG_DRV | \
@@ -75,6 +75,15 @@
/* minimum number of free TX descriptors required to wake up TX process */
#define B44_TX_WAKEUP_THRESH (B44_TX_RING_SIZE / 4)
+/* b44 internal pattern match filter info */
+#define B44_PATTERN_BASE 0x400
+#define B44_PATTERN_SIZE 0x80
+#define B44_PMASK_BASE 0x600
+#define B44_PMASK_SIZE 0x10
+#define B44_MAX_PATTERNS 16
+#define B44_ETHIPV6UDP_HLEN 62
+#define B44_ETHIPV4UDP_HLEN 42
+
static char version[] __devinitdata =
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
@@ -101,7 +110,7 @@ MODULE_DEVICE_TABLE(pci, b44_pci_tbl);
static void b44_halt(struct b44 *);
static void b44_init_rings(struct b44 *);
-static void b44_init_hw(struct b44 *);
+static void b44_init_hw(struct b44 *, int);
static int dma_desc_align_mask;
static int dma_desc_sync_size;
@@ -873,7 +882,7 @@ static int b44_poll(struct net_device *netdev, int *budget)
spin_lock_irq(&bp->lock);
b44_halt(bp);
b44_init_rings(bp);
- b44_init_hw(bp);
+ b44_init_hw(bp, 1);
netif_wake_queue(bp->dev);
spin_unlock_irq(&bp->lock);
done = 1;
@@ -942,7 +951,7 @@ static void b44_tx_timeout(struct net_device *dev)
b44_halt(bp);
b44_init_rings(bp);
- b44_init_hw(bp);
+ b44_init_hw(bp, 1);
spin_unlock_irq(&bp->lock);
@@ -1059,7 +1068,7 @@ static int b44_change_mtu(struct net_device *dev, int new_mtu)
b44_halt(bp);
dev->mtu = new_mtu;
b44_init_rings(bp);
- b44_init_hw(bp);
+ b44_init_hw(bp, 1);
spin_unlock_irq(&bp->lock);
b44_enable_ints(bp);
@@ -1356,13 +1365,15 @@ static int b44_set_mac_addr(struct net_device *dev, void *p)
* packet processing. Invoked with bp->lock held.
*/
static void __b44_set_rx_mode(struct net_device *);
-static void b44_init_hw(struct b44 *bp)
+static void b44_init_hw(struct b44 *bp, int full_reset)
{
u32 val;
b44_chip_reset(bp);
- b44_phy_reset(bp);
- b44_setup_phy(bp);
+ if (full_reset) {
+ b44_phy_reset(bp);
+ b44_setup_phy(bp);
+ }
/* Enable CRC32, set proper LED modes and power on PHY */
bw32(bp, B44_MAC_CTRL, MAC_CTRL_CRC32_ENAB | MAC_CTRL_PHY_LEDCTRL);
@@ -1376,16 +1387,21 @@ static void b44_init_hw(struct b44 *bp)
bw32(bp, B44_TXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN);
bw32(bp, B44_TX_WMARK, 56); /* XXX magic */
- bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE);
- bw32(bp, B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset);
- bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
- (bp->rx_offset << DMARX_CTRL_ROSHIFT)));
- bw32(bp, B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset);
+ if (full_reset) {
+ bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE);
+ bw32(bp, B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset);
+ bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
+ (bp->rx_offset << DMARX_CTRL_ROSHIFT)));
+ bw32(bp, B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset);
- bw32(bp, B44_DMARX_PTR, bp->rx_pending);
- bp->rx_prod = bp->rx_pending;
+ bw32(bp, B44_DMARX_PTR, bp->rx_pending);
+ bp->rx_prod = bp->rx_pending;
- bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ);
+ bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ);
+ } else {
+ bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
+ (bp->rx_offset << DMARX_CTRL_ROSHIFT)));
+ }
val = br32(bp, B44_ENET_CTRL);
bw32(bp, B44_ENET_CTRL, (val | ENET_CTRL_ENABLE));
@@ -1401,7 +1417,7 @@ static int b44_open(struct net_device *dev)
goto out;
b44_init_rings(bp);
- b44_init_hw(bp);
+ b44_init_hw(bp, 1);
b44_check_phy(bp);
@@ -1450,6 +1466,140 @@ static void b44_poll_controller(struct net_device *dev)
}
#endif
+static void bwfilter_table(struct b44 *bp, u8 *pp, u32 bytes, u32 table_offset)
+{
+ u32 i;
+ u32 *pattern = (u32 *) pp;
+
+ for (i = 0; i < bytes; i += sizeof(u32)) {
+ bw32(bp, B44_FILT_ADDR, table_offset + i);
+ bw32(bp, B44_FILT_DATA, pattern[i / sizeof(u32)]);
+ }
+}
+
+static int b44_magic_pattern(u8 *macaddr, u8 *ppattern, u8 *pmask, int offset)
+{
+ int magicsync = 6;
+ int k, j, len = offset;
+ int ethaddr_bytes = ETH_ALEN;
+
+ memset(ppattern + offset, 0xff, magicsync);
+ for (j = 0; j < magicsync; j++)
+ set_bit(len++, (unsigned long *) pmask);
+
+ for (j = 0; j < B44_MAX_PATTERNS; j++) {
+ if ((B44_PATTERN_SIZE - len) >= ETH_ALEN)
+ ethaddr_bytes = ETH_ALEN;
+ else
+ ethaddr_bytes = B44_PATTERN_SIZE - len;
+ if (ethaddr_bytes <=0)
+ break;
+ for (k = 0; k< ethaddr_bytes; k++) {
+ ppattern[offset + magicsync +
+ (j * ETH_ALEN) + k] = macaddr[k];
+ len++;
+ set_bit(len, (unsigned long *) pmask);
+ }
+ }
+ return len - 1;
+}
+
+/* Setup magic packet patterns in the b44 WOL
+ * pattern matching filter.
+ */
+static void b44_setup_pseudo_magicp(struct b44 *bp)
+{
+
+ u32 val;
+ int plen0, plen1, plen2;
+ u8 *pwol_pattern;
+ u8 pwol_mask[B44_PMASK_SIZE];
+
+ pwol_pattern = kmalloc(B44_PATTERN_SIZE, GFP_KERNEL);
+ if (!pwol_pattern) {
+ printk(KERN_ERR PFX "Memory not available for WOL\n");
+ return;
+ }
+
+ /* Ipv4 magic packet pattern - pattern 0.*/
+ memset(pwol_pattern, 0, B44_PATTERN_SIZE);
+ memset(pwol_mask, 0, B44_PMASK_SIZE);
+ plen0 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
+ B44_ETHIPV4UDP_HLEN);
+
+ bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE, B44_PATTERN_BASE);
+ bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE, B44_PMASK_BASE);
+
+ /* Raw ethernet II magic packet pattern - pattern 1 */
+ memset(pwol_pattern, 0, B44_PATTERN_SIZE);
+ memset(pwol_mask, 0, B44_PMASK_SIZE);
+ plen1 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
+ ETH_HLEN);
+
+ bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE,
+ B44_PATTERN_BASE + B44_PATTERN_SIZE);
+ bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE,
+ B44_PMASK_BASE + B44_PMASK_SIZE);
+
+ /* Ipv6 magic packet pattern - pattern 2 */
+ memset(pwol_pattern, 0, B44_PATTERN_SIZE);
+ memset(pwol_mask, 0, B44_PMASK_SIZE);
+ plen2 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
+ B44_ETHIPV6UDP_HLEN);
+
+ bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE,
+ B44_PATTERN_BASE + B44_PATTERN_SIZE + B44_PATTERN_SIZE);
+ bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE,
+ B44_PMASK_BASE + B44_PMASK_SIZE + B44_PMASK_SIZE);
+
+ kfree(pwol_pattern);
+
+ /* set these pattern's lengths: one less than each real length */
+ val = plen0 | (plen1 << 8) | (plen2 << 16) | WKUP_LEN_ENABLE_THREE;
+ bw32(bp, B44_WKUP_LEN, val);
+
+ /* enable wakeup pattern matching */
+ val = br32(bp, B44_DEVCTRL);
+ bw32(bp, B44_DEVCTRL, val | DEVCTRL_PFE);
+
+}
+
+static void b44_setup_wol(struct b44 *bp)
+{
+ u32 val;
+ u16 pmval;
+
+ bw32(bp, B44_RXCONFIG, RXCONFIG_ALLMULTI);
+
+ if (bp->flags & B44_FLAG_B0_ANDLATER) {
+
+ bw32(bp, B44_WKUP_LEN, WKUP_LEN_DISABLE);
+
+ val = bp->dev->dev_addr[2] << 24 |
+ bp->dev->dev_addr[3] << 16 |
+ bp->dev->dev_addr[4] << 8 |
+ bp->dev->dev_addr[5];
+ bw32(bp, B44_ADDR_LO, val);
+
+ val = bp->dev->dev_addr[0] << 8 |
+ bp->dev->dev_addr[1];
+ bw32(bp, B44_ADDR_HI, val);
+
+ val = br32(bp, B44_DEVCTRL);
+ bw32(bp, B44_DEVCTRL, val | DEVCTRL_MPM | DEVCTRL_PFE);
+
+ } else {
+ b44_setup_pseudo_magicp(bp);
+ }
+
+ val = br32(bp, B44_SBTMSLOW);
+ bw32(bp, B44_SBTMSLOW, val | SBTMSLOW_PE);
+
+ pci_read_config_word(bp->pdev, SSB_PMCSR, &pmval);
+ pci_write_config_word(bp->pdev, SSB_PMCSR, pmval | SSB_PE);
+
+}
+
static int b44_close(struct net_device *dev)
{
struct b44 *bp = netdev_priv(dev);
@@ -1475,6 +1625,11 @@ static int b44_close(struct net_device *dev)
netif_poll_enable(dev);
+ if (bp->flags & B44_FLAG_WOL_ENABLE) {
+ b44_init_hw(bp, 0);
+ b44_setup_wol(bp);
+ }
+
b44_free_consistent(bp);
return 0;
@@ -1620,8 +1775,6 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct b44 *bp = netdev_priv(dev);
- if (!netif_running(dev))
- return -EAGAIN;
cmd->supported = (SUPPORTED_Autoneg);
cmd->supported |= (SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
@@ -1649,6 +1802,12 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
XCVR_INTERNAL : XCVR_EXTERNAL;
cmd->autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ?
AUTONEG_DISABLE : AUTONEG_ENABLE;
+ if (cmd->autoneg == AUTONEG_ENABLE)
+ cmd->advertising |= ADVERTISED_Autoneg;
+ if (!netif_running(dev)){
+ cmd->speed = 0;
+ cmd->duplex = 0xff;
+ }
cmd->maxtxpkt = 0;
cmd->maxrxpkt = 0;
return 0;
@@ -1658,9 +1817,6 @@ static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct b44 *bp = netdev_priv(dev);
- if (!netif_running(dev))
- return -EAGAIN;
-
/* We do not support gigabit. */
if (cmd->autoneg == AUTONEG_ENABLE) {
if (cmd->advertising &
@@ -1677,28 +1833,39 @@ static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
spin_lock_irq(&bp->lock);
if (cmd->autoneg == AUTONEG_ENABLE) {
- bp->flags &= ~B44_FLAG_FORCE_LINK;
- bp->flags &= ~(B44_FLAG_ADV_10HALF |
+ bp->flags &= ~(B44_FLAG_FORCE_LINK |
+ B44_FLAG_100_BASE_T |
+ B44_FLAG_FULL_DUPLEX |
+ B44_FLAG_ADV_10HALF |
B44_FLAG_ADV_10FULL |
B44_FLAG_ADV_100HALF |
B44_FLAG_ADV_100FULL);
- if (cmd->advertising & ADVERTISE_10HALF)
- bp->flags |= B44_FLAG_ADV_10HALF;
- if (cmd->advertising & ADVERTISE_10FULL)
- bp->flags |= B44_FLAG_ADV_10FULL;
- if (cmd->advertising & ADVERTISE_100HALF)
- bp->flags |= B44_FLAG_ADV_100HALF;
- if (cmd->advertising & ADVERTISE_100FULL)
- bp->flags |= B44_FLAG_ADV_100FULL;
+ if (cmd->advertising == 0) {
+ bp->flags |= (B44_FLAG_ADV_10HALF |
+ B44_FLAG_ADV_10FULL |
+ B44_FLAG_ADV_100HALF |
+ B44_FLAG_ADV_100FULL);
+ } else {
+ if (cmd->advertising & ADVERTISED_10baseT_Half)
+ bp->flags |= B44_FLAG_ADV_10HALF;
+ if (cmd->advertising & ADVERTISED_10baseT_Full)
+ bp->flags |= B44_FLAG_ADV_10FULL;
+ if (cmd->advertising & ADVERTISED_100baseT_Half)
+ bp->flags |= B44_FLAG_ADV_100HALF;
+ if (cmd->advertising & ADVERTISED_100baseT_Full)
+ bp->flags |= B44_FLAG_ADV_100FULL;
+ }
} else {
bp->flags |= B44_FLAG_FORCE_LINK;
+ bp->flags &= ~(B44_FLAG_100_BASE_T | B44_FLAG_FULL_DUPLEX);
if (cmd->speed == SPEED_100)
bp->flags |= B44_FLAG_100_BASE_T;
if (cmd->duplex == DUPLEX_FULL)
bp->flags |= B44_FLAG_FULL_DUPLEX;
}
- b44_setup_phy(bp);
+ if (netif_running(dev))
+ b44_setup_phy(bp);
spin_unlock_irq(&bp->lock);
@@ -1734,7 +1901,7 @@ static int b44_set_ringparam(struct net_device *dev,
b44_halt(bp);
b44_init_rings(bp);
- b44_init_hw(bp);
+ b44_init_hw(bp, 1);
netif_wake_queue(bp->dev);
spin_unlock_irq(&bp->lock);
@@ -1777,7 +1944,7 @@ static int b44_set_pauseparam(struct net_device *dev,
if (bp->flags & B44_FLAG_PAUSE_AUTO) {
b44_halt(bp);
b44_init_rings(bp);
- b44_init_hw(bp);
+ b44_init_hw(bp, 1);
} else {
__b44_set_flow_ctrl(bp, bp->flags);
}
@@ -1819,12 +1986,40 @@ static void b44_get_ethtool_stats(struct net_device *dev,
spin_unlock_irq(&bp->lock);
}
+static void b44_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct b44 *bp = netdev_priv(dev);
+
+ wol->supported = WAKE_MAGIC;
+ if (bp->flags & B44_FLAG_WOL_ENABLE)
+ wol->wolopts = WAKE_MAGIC;
+ else
+ wol->wolopts = 0;
+ memset(&wol->sopass, 0, sizeof(wol->sopass));
+}
+
+static int b44_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct b44 *bp = netdev_priv(dev);
+
+ spin_lock_irq(&bp->lock);
+ if (wol->wolopts & WAKE_MAGIC)
+ bp->flags |= B44_FLAG_WOL_ENABLE;
+ else
+ bp->flags &= ~B44_FLAG_WOL_ENABLE;
+ spin_unlock_irq(&bp->lock);
+
+ return 0;
+}
+
static struct ethtool_ops b44_ethtool_ops = {
.get_drvinfo = b44_get_drvinfo,
.get_settings = b44_get_settings,
.set_settings = b44_set_settings,
.nway_reset = b44_nway_reset,
.get_link = ethtool_op_get_link,
+ .get_wol = b44_get_wol,
+ .set_wol = b44_set_wol,
.get_ringparam = b44_get_ringparam,
.set_ringparam = b44_set_ringparam,
.get_pauseparam = b44_get_pauseparam,
@@ -1903,6 +2098,10 @@ static int __devinit b44_get_invariants(struct b44 *bp)
/* XXX - really required?
bp->flags |= B44_FLAG_BUGGY_TXPTR;
*/
+
+ if (ssb_get_core_rev(bp) >= 7)
+ bp->flags |= B44_FLAG_B0_ANDLATER;
+
out:
return err;
}
@@ -2103,6 +2302,10 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state)
spin_unlock_irq(&bp->lock);
free_irq(dev->irq, dev);
+ if (bp->flags & B44_FLAG_WOL_ENABLE) {
+ b44_init_hw(bp, 0);
+ b44_setup_wol(bp);
+ }
pci_disable_device(pdev);
return 0;
}
@@ -2125,7 +2328,7 @@ static int b44_resume(struct pci_dev *pdev)
spin_lock_irq(&bp->lock);
b44_init_rings(bp);
- b44_init_hw(bp);
+ b44_init_hw(bp, 1);
netif_device_attach(bp->dev);
spin_unlock_irq(&bp->lock);
diff --git a/drivers/net/b44.h b/drivers/net/b44.h
index b178662..4944507 100644
--- a/drivers/net/b44.h
+++ b/drivers/net/b44.h
@@ -24,6 +24,9 @@
#define WKUP_LEN_P3_MASK 0x7f000000 /* Pattern 3 */
#define WKUP_LEN_P3_SHIFT 24
#define WKUP_LEN_D3 0x80000000
+#define WKUP_LEN_DISABLE 0x80808080
+#define WKUP_LEN_ENABLE_TWO 0x80800000
+#define WKUP_LEN_ENABLE_THREE 0x80000000
#define B44_ISTAT 0x0020UL /* Interrupt Status */
#define ISTAT_LS 0x00000020 /* Link Change (B0 only) */
#define ISTAT_PME 0x00000040 /* Power Management Event */
@@ -264,6 +267,8 @@
#define SBIDHIGH_VC_SHIFT 16
/* SSB PCI config space registers. */
+#define SSB_PMCSR 0x44
+#define SSB_PE 0x100
#define SSB_BAR0_WIN 0x80
#define SSB_BAR1_WIN 0x84
#define SSB_SPROM_CONTROL 0x88
@@ -420,6 +425,7 @@ struct b44 {
u32 dma_offset;
u32 flags;
+#define B44_FLAG_B0_ANDLATER 0x00000001
#define B44_FLAG_BUGGY_TXPTR 0x00000002
#define B44_FLAG_REORDER_BUG 0x00000004
#define B44_FLAG_PAUSE_AUTO 0x00008000
@@ -435,6 +441,7 @@ struct b44 {
#define B44_FLAG_INTERNAL_PHY 0x10000000
#define B44_FLAG_RX_RING_HACK 0x20000000
#define B44_FLAG_TX_RING_HACK 0x40000000
+#define B44_FLAG_WOL_ENABLE 0x80000000
u32 rx_offset;
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 702d546..7635736 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -1640,7 +1640,7 @@ bnx2_tx_int(struct bnx2 *bp)
skb = tx_buf->skb;
#ifdef BCM_TSO
/* partial BD completions possible with TSO packets */
- if (skb_shinfo(skb)->tso_size) {
+ if (skb_shinfo(skb)->gso_size) {
u16 last_idx, last_ring_idx;
last_idx = sw_cons +
@@ -4428,7 +4428,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
(TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
}
#ifdef BCM_TSO
- if ((mss = skb_shinfo(skb)->tso_size) &&
+ if ((mss = skb_shinfo(skb)->gso_size) &&
(skb->len > (bp->dev->mtu + ETH_HLEN))) {
u32 tcp_opt_len, ip_tcp_len;
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index 39f36aa..565a54f 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -2915,8 +2915,7 @@ static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
static int ring;
- skb = skb_padto(skb, cp->min_frame_size);
- if (!skb)
+ if (skb_padto(skb, cp->min_frame_size))
return 0;
/* XXX: we need some higher-level QoS hooks to steer packets to
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index 4391bf4..53efff6 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -1418,7 +1418,7 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct cpl_tx_pkt *cpl;
#ifdef NETIF_F_TSO
- if (skb_shinfo(skb)->tso_size) {
+ if (skb_shinfo(skb)->gso_size) {
int eth_type;
struct cpl_tx_pkt_lso *hdr;
@@ -1433,7 +1433,7 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
hdr->ip_hdr_words = skb->nh.iph->ihl;
hdr->tcp_hdr_words = skb->h.th->doff;
hdr->eth_type_mss = htons(MK_ETH_TYPE_MSS(eth_type,
- skb_shinfo(skb)->tso_size));
+ skb_shinfo(skb)->gso_size));
hdr->len = htonl(skb->len - sizeof(*hdr));
cpl = (struct cpl_tx_pkt *)hdr;
sge->stats.tx_lso_pkts++;
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index f130bda..d3d958e 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -885,8 +885,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
len = skblen;
if (len < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
len = ETH_ZLEN;
}
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index 0941d40..e946c43d 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -938,11 +938,8 @@ static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->len < 1)
goto out;
- if (skb->len < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
- goto out;
- }
+ if (skb_padto(skb, ETH_ZLEN))
+ goto out;
netif_stop_queue(dev);
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index a373ccb..32b7d44 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -2394,7 +2394,7 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
int err;
- if (skb_shinfo(skb)->tso_size) {
+ if (skb_shinfo(skb)->gso_size) {
if (skb_header_cloned(skb)) {
err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
if (err)
@@ -2402,7 +2402,7 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
}
hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
- mss = skb_shinfo(skb)->tso_size;
+ mss = skb_shinfo(skb)->gso_size;
if (skb->protocol == htons(ETH_P_IP)) {
skb->nh.iph->tot_len = 0;
skb->nh.iph->check = 0;
@@ -2519,7 +2519,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
* tso gets written back prematurely before the data is fully
* DMA'd to the controller */
if (!skb->data_len && tx_ring->last_tx_tso &&
- !skb_shinfo(skb)->tso_size) {
+ !skb_shinfo(skb)->gso_size) {
tx_ring->last_tx_tso = 0;
size -= 4;
}
@@ -2757,7 +2757,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
}
#ifdef NETIF_F_TSO
- mss = skb_shinfo(skb)->tso_size;
+ mss = skb_shinfo(skb)->gso_size;
/* The controller does a simple calculation to
* make sure there is enough room in the FIFO before
* initiating the DMA for each buffer. The calc is:
@@ -2807,7 +2807,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
#ifdef NETIF_F_TSO
/* Controller Erratum workaround */
if (!skb->data_len && tx_ring->last_tx_tso &&
- !skb_shinfo(skb)->tso_size)
+ !skb_shinfo(skb)->gso_size)
count++;
#endif
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index a806dfe..e70f172 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -1154,8 +1154,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: entering eepro_send_packet routine.\n", dev->name);
if (length < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 82bd356..a74b207 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -677,8 +677,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev)
#endif
if (buf->len < ETH_ZLEN) {
- buf = skb_padto(buf, ETH_ZLEN);
- if (buf == NULL)
+ if (skb_padto(buf, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 8d680ce..724d7dc 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -1027,11 +1027,8 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
u32 ctrl_word;
unsigned long flags;
- if (skb->len < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
- return 0;
- }
+ if (skb_padto(skb, ETH_ZLEN))
+ return 0;
/* Caution: the write order is important here, set the field with the
"ownership" bit last. */
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index b67545b..4bf76f8 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -1064,8 +1064,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
unsigned long flags;
if (length < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 62b38a4..21be4fa 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -1495,8 +1495,8 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
np->tx_skbuff[nr] = skb;
#ifdef NETIF_F_TSO
- if (skb_shinfo(skb)->tso_size)
- tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT);
+ if (skb_shinfo(skb)->gso_size)
+ tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
else
#endif
tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
@@ -2076,7 +2076,7 @@ static void nv_set_multicast(struct net_device *dev)
spin_unlock_irq(&np->lock);
}
-void nv_update_pause(struct net_device *dev, u32 pause_flags)
+static void nv_update_pause(struct net_device *dev, u32 pause_flags)
{
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 247c8ca..dd1dc32 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -1487,11 +1487,8 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev)
if (skb->len <= 0)
return 0;
- if (skb->len < ETH_ZLEN && lp->chip == HP100_CHIPID_SHASTA) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
- return 0;
- }
+ if (lp->chip == HP100_CHIPID_SHASTA && skb_padto(skb, ETH_ZLEN))
+ return 0;
/* Get Tx ring tail pointer */
if (lp->txrtail->next == lp->txrhead) {
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 666346f..4c2e727 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -61,7 +61,7 @@
#undef DEBUG
#define ibmveth_printk(fmt, args...) \
- printk(KERN_INFO "%s: " fmt, __FILE__, ## args)
+ printk(KERN_DEBUG "%s: " fmt, __FILE__, ## args)
#define ibmveth_error_printk(fmt, args...) \
printk(KERN_ERR "(%s:%3.3d ua:%x) ERROR: " fmt, __FILE__, __LINE__ , adapter->vdev->unit_address, ## args)
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index ae71ed5..e76e6e7 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -145,7 +145,7 @@ static inline struct sk_buff * ioc3_alloc_skb(unsigned long length,
static inline unsigned long ioc3_map(void *ptr, unsigned long vdev)
{
#ifdef CONFIG_SGI_IP27
- vdev <<= 58; /* Shift to PCI64_ATTR_VIRTUAL */
+ vdev <<= 57; /* Shift to PCI64_ATTR_VIRTUAL */
return vdev | (0xaUL << PCI64_ATTR_TARG_SHFT) | PCI64_ATTR_PREF |
((unsigned long)ptr & TO_PHYS_MASK);
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 844fa74..2a0d538 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -1105,7 +1105,7 @@ static int stir421x_patch_device(struct irda_usb_cb *self)
return ret;
/* We get a patch from userspace */
- IRDA_MESSAGE("%s(): Received firmware %s (%u bytes)\n",
+ IRDA_MESSAGE("%s(): Received firmware %s (%zu bytes)\n",
__FUNCTION__, stir421x_fw_name, fw->size);
ret = -EINVAL;
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index f0f04be..93394d7 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -69,6 +69,7 @@
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/ethtool.h>
+#include <linux/if_ether.h>
#include <asm/abs_addr.h>
#include <asm/iseries/mf.h>
@@ -1035,11 +1036,22 @@ static struct ethtool_ops ops = {
.get_link = veth_get_link,
};
-static struct net_device * __init veth_probe_one(int vlan, struct device *vdev)
+static struct net_device * __init veth_probe_one(int vlan,
+ struct vio_dev *vio_dev)
{
struct net_device *dev;
struct veth_port *port;
+ struct device *vdev = &vio_dev->dev;
int i, rc;
+ const unsigned char *mac_addr;
+
+ mac_addr = vio_get_attribute(vio_dev, "local-mac-address", NULL);
+ if (mac_addr == NULL)
+ mac_addr = vio_get_attribute(vio_dev, "mac-address", NULL);
+ if (mac_addr == NULL) {
+ veth_error("Unable to fetch MAC address from device tree.\n");
+ return NULL;
+ }
dev = alloc_etherdev(sizeof (struct veth_port));
if (! dev) {
@@ -1064,16 +1076,11 @@ static struct net_device * __init veth_probe_one(int vlan, struct device *vdev)
}
port->dev = vdev;
- dev->dev_addr[0] = 0x02;
- dev->dev_addr[1] = 0x01;
- dev->dev_addr[2] = 0xff;
- dev->dev_addr[3] = vlan;
- dev->dev_addr[4] = 0xff;
- dev->dev_addr[5] = this_lp;
+ memcpy(dev->dev_addr, mac_addr, ETH_ALEN);
dev->mtu = VETH_MAX_MTU;
- memcpy(&port->mac_addr, dev->dev_addr, 6);
+ memcpy(&port->mac_addr, mac_addr, ETH_ALEN);
dev->open = veth_open;
dev->hard_start_xmit = veth_start_xmit;
@@ -1608,7 +1615,7 @@ static int veth_probe(struct vio_dev *vdev, const struct vio_device_id *id)
struct net_device *dev;
struct veth_port *port;
- dev = veth_probe_one(i, &vdev->dev);
+ dev = veth_probe_one(i, vdev);
if (dev == NULL) {
veth_remove(vdev);
return 1;
@@ -1641,7 +1648,7 @@ static int veth_probe(struct vio_dev *vdev, const struct vio_device_id *id)
* support.
*/
static struct vio_device_id veth_device_table[] __devinitdata = {
- { "vlan", "" },
+ { "network", "IBM,iSeries-l-lan" },
{ "", "" }
};
MODULE_DEVICE_TABLE(vio, veth_device_table);
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index 57006fb..8bb32f9 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -1173,7 +1173,7 @@ ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb)
uint16_t ipcse, tucse, mss;
int err;
- if(likely(skb_shinfo(skb)->tso_size)) {
+ if(likely(skb_shinfo(skb)->gso_size)) {
if (skb_header_cloned(skb)) {
err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
if (err)
@@ -1181,7 +1181,7 @@ ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb)
}
hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
- mss = skb_shinfo(skb)->tso_size;
+ mss = skb_shinfo(skb)->gso_size;
skb->nh.iph->tot_len = 0;
skb->nh.iph->check = 0;
skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr,
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index bb5ad47..c1c3452 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -968,8 +968,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* The old LANCE chips doesn't automatically pad buffers to min. size. */
if (chip_table[lp->chip_version].flags & LANCE_MUST_PAD) {
if (skb->len < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
goto out;
lp->tx_ring[entry].length = -ETH_ZLEN;
}
diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c
index 957888d..1ab0944 100644
--- a/drivers/net/lasi_82596.c
+++ b/drivers/net/lasi_82596.c
@@ -1083,8 +1083,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb->len, skb->data));
if (length < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index b79d6e8..43fef7d 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -74,7 +74,7 @@ static void emulate_large_send_offload(struct sk_buff *skb)
struct iphdr *iph = skb->nh.iph;
struct tcphdr *th = (struct tcphdr*)(skb->nh.raw + (iph->ihl * 4));
unsigned int doffset = (iph->ihl + th->doff) * 4;
- unsigned int mtu = skb_shinfo(skb)->tso_size + doffset;
+ unsigned int mtu = skb_shinfo(skb)->gso_size + doffset;
unsigned int offset = 0;
u32 seq = ntohl(th->seq);
u16 id = ntohs(iph->id);
@@ -139,7 +139,7 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
#endif
#ifdef LOOPBACK_TSO
- if (skb_shinfo(skb)->tso_size) {
+ if (skb_shinfo(skb)->gso_size) {
BUG_ON(skb->protocol != htons(ETH_P_IP));
BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP);
diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c
index 94d5ea1..bf3f343 100644
--- a/drivers/net/lp486e.c
+++ b/drivers/net/lp486e.c
@@ -877,8 +877,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
length = skb->len;
if (length < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index e1feb58..dbdf189 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -1879,7 +1879,7 @@ again:
#ifdef NETIF_F_TSO
if (skb->len > (dev->mtu + ETH_HLEN)) {
- mss = skb_shinfo(skb)->tso_size;
+ mss = skb_shinfo(skb)->gso_size;
if (mss != 0)
max_segments = MYRI10GE_MAX_SEND_DESC_TSO;
}
@@ -1939,8 +1939,7 @@ again:
/* pad frames to at least ETH_ZLEN bytes */
if (unlikely(skb->len < ETH_ZLEN)) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL) {
+ if (skb_padto(skb, ETH_ZLEN)) {
/* The packet is gone, so we must
* return 0 */
mgp->stats.tx_dropped += 1;
@@ -2113,14 +2112,14 @@ abort_linearize:
}
idx = (idx + 1) & tx->mask;
} while (idx != last_idx);
- if (skb_shinfo(skb)->tso_size) {
+ if (skb_shinfo(skb)->gso_size) {
printk(KERN_ERR
"myri10ge: %s: TSO but wanted to linearize?!?!?\n",
mgp->dev->name);
goto drop;
}
- if (skb_linearize(skb, GFP_ATOMIC))
+ if (skb_linearize(skb))
goto drop;
mgp->tx_linearized++;
@@ -2251,12 +2250,6 @@ static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp)
}
cap = pci_find_ext_capability(bridge, PCI_EXT_CAP_ID_ERR);
- /* nvidia ext cap is not always linked in ext cap chain */
- if (!cap
- && bridge->vendor == PCI_VENDOR_ID_NVIDIA
- && bridge->device == PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_PCIE)
- cap = 0x160;
-
if (!cap)
return;
@@ -2732,8 +2725,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Save configuration space to be restored if the
* nic resets due to a parity error */
myri10ge_save_state(mgp);
- /* Restore state immediately since pci_save_msi_state disables MSI */
- myri10ge_restore_state(mgp);
/* Setup the watchdog timer */
setup_timer(&mgp->watchdog_timer, myri10ge_watchdog_timer,
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 6c86dca6..d9f616f 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -1,10 +1,10 @@
-/* myri_sbus.h: MyriCOM MyriNET SBUS card driver.
+/* myri_sbus.c: MyriCOM MyriNET SBUS card driver.
*
- * Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996, 1999, 2006 David S. Miller (davem@davemloft.net)
*/
static char version[] =
- "myri_sbus.c:v1.9 12/Sep/99 David S. Miller (davem@redhat.com)\n";
+ "myri_sbus.c:v2.0 June 23, 2006 David S. Miller (davem@davemloft.net)\n";
#include <linux/module.h>
#include <linux/config.h>
@@ -81,10 +81,6 @@ static char version[] =
#define DHDR(x)
#endif
-#ifdef MODULE
-static struct myri_eth *root_myri_dev;
-#endif
-
static void myri_reset_off(void __iomem *lp, void __iomem *cregs)
{
/* Clear IRQ mask. */
@@ -896,8 +892,9 @@ static void dump_eeprom(struct myri_eth *mp)
}
#endif
-static int __init myri_ether_init(struct sbus_dev *sdev, int num)
+static int __init myri_ether_init(struct sbus_dev *sdev)
{
+ static int num;
static unsigned version_printed;
struct net_device *dev;
struct myri_eth *mp;
@@ -913,6 +910,9 @@ static int __init myri_ether_init(struct sbus_dev *sdev, int num)
if (version_printed++ == 0)
printk(version);
+ SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+
mp = (struct myri_eth *) dev->priv;
spin_lock_init(&mp->irq_lock);
mp->myri_sdev = sdev;
@@ -1092,10 +1092,9 @@ static int __init myri_ether_init(struct sbus_dev *sdev, int num)
goto err_free_irq;
}
-#ifdef MODULE
- mp->next_module = root_myri_dev;
- root_myri_dev = mp;
-#endif
+ dev_set_drvdata(&sdev->ofdev.dev, mp);
+
+ num++;
printk("%s: MyriCOM MyriNET Ethernet ", dev->name);
@@ -1114,61 +1113,68 @@ err:
return -ENODEV;
}
-static int __init myri_sbus_match(struct sbus_dev *sdev)
-{
- char *name = sdev->prom_name;
- if (!strcmp(name, "MYRICOM,mlanai") ||
- !strcmp(name, "myri"))
- return 1;
+static int __devinit myri_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+{
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
- return 0;
+ return myri_ether_init(sdev);
}
-static int __init myri_sbus_probe(void)
+static int __devexit myri_sbus_remove(struct of_device *dev)
{
- struct sbus_bus *bus;
- struct sbus_dev *sdev = NULL;
- static int called;
- int cards = 0, v;
+ struct myri_eth *mp = dev_get_drvdata(&dev->dev);
+ struct net_device *net_dev = mp->dev;
-#ifdef MODULE
- root_myri_dev = NULL;
-#endif
+ unregister_netdevice(net_dev);
- if (called)
- return -ENODEV;
- called++;
-
- for_each_sbus(bus) {
- for_each_sbusdev(sdev, bus) {
- if (myri_sbus_match(sdev)) {
- cards++;
- DET(("Found myricom myrinet as %s\n", sdev->prom_name));
- if ((v = myri_ether_init(sdev, (cards - 1))))
- return v;
- }
- }
+ free_irq(net_dev->irq, net_dev);
+
+ if (mp->eeprom.cpuvers < CPUVERS_4_0) {
+ sbus_iounmap(mp->regs, mp->reg_size);
+ } else {
+ sbus_iounmap(mp->cregs, PAGE_SIZE);
+ sbus_iounmap(mp->lregs, (256 * 1024));
+ sbus_iounmap(mp->lanai, (512 * 1024));
}
- if (!cards)
- return -ENODEV;
+
+ free_netdev(net_dev);
+
+ dev_set_drvdata(&dev->dev, NULL);
+
return 0;
}
-static void __exit myri_sbus_cleanup(void)
+static struct of_device_id myri_sbus_match[] = {
+ {
+ .name = "MYRICOM,mlanai",
+ },
+ {
+ .name = "myri",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, myri_sbus_match);
+
+static struct of_platform_driver myri_sbus_driver = {
+ .name = "myri",
+ .match_table = myri_sbus_match,
+ .probe = myri_sbus_probe,
+ .remove = __devexit_p(myri_sbus_remove),
+};
+
+static int __init myri_sbus_init(void)
+{
+ return of_register_driver(&myri_sbus_driver, &sbus_bus_type);
+}
+
+static void __exit myri_sbus_exit(void)
{
-#ifdef MODULE
- while (root_myri_dev) {
- struct myri_eth *next = root_myri_dev->next_module;
-
- unregister_netdev(root_myri_dev->dev);
- /* this will also free the co-allocated 'root_myri_dev' */
- free_netdev(root_myri_dev->dev);
- root_myri_dev = next;
- }
-#endif /* MODULE */
+ of_unregister_driver(&myri_sbus_driver);
}
-module_init(myri_sbus_probe);
-module_exit(myri_sbus_cleanup);
+module_init(myri_sbus_init);
+module_exit(myri_sbus_exit);
+
MODULE_LICENSE("GPL");
diff --git a/drivers/net/myri_sbus.h b/drivers/net/myri_sbus.h
index 47722f7..2f69ef7 100644
--- a/drivers/net/myri_sbus.h
+++ b/drivers/net/myri_sbus.h
@@ -290,7 +290,6 @@ struct myri_eth {
unsigned int reg_size; /* Size of register space. */
unsigned int shmem_base; /* Offset to shared ram. */
struct sbus_dev *myri_sdev; /* Our SBUS device struct. */
- struct myri_eth *next_module; /* Next in adapter chain. */
};
/* We use this to acquire receive skb's that we can DMA directly into. */
diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c
new file mode 100644
index 0000000..b92430c
--- /dev/null
+++ b/drivers/net/netx-eth.c
@@ -0,0 +1,516 @@
+/*
+ * drivers/net/netx-eth.c
+ *
+ * Copyright (c) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/mii.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/netx-regs.h>
+#include <asm/arch/pfifo.h>
+#include <asm/arch/xc.h>
+#include <asm/arch/eth.h>
+
+/* XC Fifo Offsets */
+#define EMPTY_PTR_FIFO(xcno) (0 + ((xcno) << 3)) /* Index of the empty pointer FIFO */
+#define IND_FIFO_PORT_HI(xcno) (1 + ((xcno) << 3)) /* Index of the FIFO where received */
+ /* Data packages are indicated by XC */
+#define IND_FIFO_PORT_LO(xcno) (2 + ((xcno) << 3)) /* Index of the FIFO where received */
+ /* Data packages are indicated by XC */
+#define REQ_FIFO_PORT_HI(xcno) (3 + ((xcno) << 3)) /* Index of the FIFO where Data packages */
+ /* have to be indicated by ARM which */
+ /* shall be sent */
+#define REQ_FIFO_PORT_LO(xcno) (4 + ((xcno) << 3)) /* Index of the FIFO where Data packages */
+ /* have to be indicated by ARM which shall */
+ /* be sent */
+#define CON_FIFO_PORT_HI(xcno) (5 + ((xcno) << 3)) /* Index of the FIFO where sent Data packages */
+ /* are confirmed */
+#define CON_FIFO_PORT_LO(xcno) (6 + ((xcno) << 3)) /* Index of the FIFO where sent Data */
+ /* packages are confirmed */
+#define PFIFO_MASK(xcno) (0x7f << (xcno*8))
+
+#define FIFO_PTR_FRAMELEN_SHIFT 0
+#define FIFO_PTR_FRAMELEN_MASK (0x7ff << 0)
+#define FIFO_PTR_FRAMELEN(len) (((len) << 0) & FIFO_PTR_FRAMELEN_MASK)
+#define FIFO_PTR_TIMETRIG (1<<11)
+#define FIFO_PTR_MULTI_REQ
+#define FIFO_PTR_ORIGIN (1<<14)
+#define FIFO_PTR_VLAN (1<<15)
+#define FIFO_PTR_FRAMENO_SHIFT 16
+#define FIFO_PTR_FRAMENO_MASK (0x3f << 16)
+#define FIFO_PTR_FRAMENO(no) (((no) << 16) & FIFO_PTR_FRAMENO_MASK)
+#define FIFO_PTR_SEGMENT_SHIFT 22
+#define FIFO_PTR_SEGMENT_MASK (0xf << 22)
+#define FIFO_PTR_SEGMENT(seg) (((seg) & 0xf) << 22)
+#define FIFO_PTR_ERROR_SHIFT 28
+#define FIFO_PTR_ERROR_MASK (0xf << 28)
+
+#define ISR_LINK_STATUS_CHANGE (1<<4)
+#define ISR_IND_LO (1<<3)
+#define ISR_CON_LO (1<<2)
+#define ISR_IND_HI (1<<1)
+#define ISR_CON_HI (1<<0)
+
+#define ETH_MAC_LOCAL_CONFIG 0x1560
+#define ETH_MAC_4321 0x1564
+#define ETH_MAC_65 0x1568
+
+#define MAC_TRAFFIC_CLASS_ARRANGEMENT_SHIFT 16
+#define MAC_TRAFFIC_CLASS_ARRANGEMENT_MASK (0xf<<MAC_TRAFFIC_CLASS_ARRANGEMENT_SHIFT)
+#define MAC_TRAFFIC_CLASS_ARRANGEMENT(x) (((x)<<MAC_TRAFFIC_CLASS_ARRANGEMENT_SHIFT) & MAC_TRAFFIC_CLASS_ARRANGEMENT_MASK)
+#define LOCAL_CONFIG_LINK_STATUS_IRQ_EN (1<<24)
+#define LOCAL_CONFIG_CON_LO_IRQ_EN (1<<23)
+#define LOCAL_CONFIG_CON_HI_IRQ_EN (1<<22)
+#define LOCAL_CONFIG_IND_LO_IRQ_EN (1<<21)
+#define LOCAL_CONFIG_IND_HI_IRQ_EN (1<<20)
+
+#define CARDNAME "netx-eth"
+
+/* LSB must be zero */
+#define INTERNAL_PHY_ADR 0x1c
+
+struct netx_eth_priv {
+ void __iomem *sram_base, *xpec_base, *xmac_base;
+ int id;
+ struct net_device_stats stats;
+ struct mii_if_info mii;
+ u32 msg_enable;
+ struct xc *xc;
+ spinlock_t lock;
+};
+
+static void netx_eth_set_multicast_list(struct net_device *ndev)
+{
+ /* implement me */
+}
+
+static int
+netx_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct netx_eth_priv *priv = netdev_priv(ndev);
+ unsigned char *buf = skb->data;
+ unsigned int len = skb->len;
+
+ spin_lock_irq(&priv->lock);
+ memcpy_toio(priv->sram_base + 1560, (void *)buf, len);
+ if (len < 60) {
+ memset_io(priv->sram_base + 1560 + len, 0, 60 - len);
+ len = 60;
+ }
+
+ pfifo_push(REQ_FIFO_PORT_LO(priv->id),
+ FIFO_PTR_SEGMENT(priv->id) |
+ FIFO_PTR_FRAMENO(1) |
+ FIFO_PTR_FRAMELEN(len));
+
+ ndev->trans_start = jiffies;
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += skb->len;
+
+ netif_stop_queue(ndev);
+ spin_unlock_irq(&priv->lock);
+ dev_kfree_skb(skb);
+
+ return 0;
+}
+
+static void netx_eth_receive(struct net_device *ndev)
+{
+ struct netx_eth_priv *priv = netdev_priv(ndev);
+ unsigned int val, frameno, seg, len;
+ unsigned char *data;
+ struct sk_buff *skb;
+
+ val = pfifo_pop(IND_FIFO_PORT_LO(priv->id));
+
+ frameno = (val & FIFO_PTR_FRAMENO_MASK) >> FIFO_PTR_FRAMENO_SHIFT;
+ seg = (val & FIFO_PTR_SEGMENT_MASK) >> FIFO_PTR_SEGMENT_SHIFT;
+ len = (val & FIFO_PTR_FRAMELEN_MASK) >> FIFO_PTR_FRAMELEN_SHIFT;
+
+ skb = dev_alloc_skb(len);
+ if (unlikely(skb == NULL)) {
+ printk(KERN_NOTICE "%s: Low memory, packet dropped.\n",
+ ndev->name);
+ priv->stats.rx_dropped++;
+ return;
+ }
+
+ data = skb_put(skb, len);
+
+ memcpy_fromio(data, priv->sram_base + frameno * 1560, len);
+
+ pfifo_push(EMPTY_PTR_FIFO(priv->id),
+ FIFO_PTR_SEGMENT(seg) | FIFO_PTR_FRAMENO(frameno));
+
+ ndev->last_rx = jiffies;
+ skb->dev = ndev;
+ skb->protocol = eth_type_trans(skb, ndev);
+ netif_rx(skb);
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += len;
+}
+
+static irqreturn_t
+netx_eth_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct net_device *ndev = dev_id;
+ struct netx_eth_priv *priv = netdev_priv(ndev);
+ int status;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ status = readl(NETX_PFIFO_XPEC_ISR(priv->id));
+ while (status) {
+ int fill_level;
+ writel(status, NETX_PFIFO_XPEC_ISR(priv->id));
+
+ if ((status & ISR_CON_HI) || (status & ISR_IND_HI))
+ printk("%s: unexpected status: 0x%08x\n",
+ __FUNCTION__, status);
+
+ fill_level =
+ readl(NETX_PFIFO_FILL_LEVEL(IND_FIFO_PORT_LO(priv->id)));
+ while (fill_level--)
+ netx_eth_receive(ndev);
+
+ if (status & ISR_CON_LO)
+ netif_wake_queue(ndev);
+
+ if (status & ISR_LINK_STATUS_CHANGE)
+ mii_check_media(&priv->mii, netif_msg_link(priv), 1);
+
+ status = readl(NETX_PFIFO_XPEC_ISR(priv->id));
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static struct net_device_stats *netx_eth_query_statistics(struct net_device *ndev)
+{
+ struct netx_eth_priv *priv = netdev_priv(ndev);
+ return &priv->stats;
+}
+
+static int netx_eth_open(struct net_device *ndev)
+{
+ struct netx_eth_priv *priv = netdev_priv(ndev);
+
+ if (request_irq
+ (ndev->irq, &netx_eth_interrupt, SA_SHIRQ, ndev->name, ndev))
+ return -EAGAIN;
+
+ writel(ndev->dev_addr[0] |
+ ndev->dev_addr[1]<<8 |
+ ndev->dev_addr[2]<<16 |
+ ndev->dev_addr[3]<<24,
+ priv->xpec_base + NETX_XPEC_RAM_START_OFS + ETH_MAC_4321);
+ writel(ndev->dev_addr[4] |
+ ndev->dev_addr[5]<<8,
+ priv->xpec_base + NETX_XPEC_RAM_START_OFS + ETH_MAC_65);
+
+ writel(LOCAL_CONFIG_LINK_STATUS_IRQ_EN |
+ LOCAL_CONFIG_CON_LO_IRQ_EN |
+ LOCAL_CONFIG_CON_HI_IRQ_EN |
+ LOCAL_CONFIG_IND_LO_IRQ_EN |
+ LOCAL_CONFIG_IND_HI_IRQ_EN,
+ priv->xpec_base + NETX_XPEC_RAM_START_OFS +
+ ETH_MAC_LOCAL_CONFIG);
+
+ mii_check_media(&priv->mii, netif_msg_link(priv), 1);
+ netif_start_queue(ndev);
+
+ return 0;
+}
+
+static int netx_eth_close(struct net_device *ndev)
+{
+ struct netx_eth_priv *priv = netdev_priv(ndev);
+
+ netif_stop_queue(ndev);
+
+ writel(0,
+ priv->xpec_base + NETX_XPEC_RAM_START_OFS + ETH_MAC_LOCAL_CONFIG);
+
+ free_irq(ndev->irq, ndev);
+
+ return 0;
+}
+
+static void netx_eth_timeout(struct net_device *ndev)
+{
+ struct netx_eth_priv *priv = netdev_priv(ndev);
+ int i;
+
+ printk(KERN_ERR "%s: transmit timed out, resetting\n", ndev->name);
+
+ spin_lock_irq(&priv->lock);
+
+ xc_reset(priv->xc);
+ xc_start(priv->xc);
+
+ for (i=2; i<=18; i++)
+ pfifo_push(EMPTY_PTR_FIFO(priv->id),
+ FIFO_PTR_FRAMENO(i) | FIFO_PTR_SEGMENT(priv->id));
+
+ spin_unlock_irq(&priv->lock);
+
+ netif_wake_queue(ndev);
+}
+
+static int
+netx_eth_phy_read(struct net_device *ndev, int phy_id, int reg)
+{
+ unsigned int val;
+
+ val = MIIMU_SNRDY | MIIMU_PREAMBLE | MIIMU_PHYADDR(phy_id) |
+ MIIMU_REGADDR(reg) | MIIMU_PHY_NRES;
+
+ writel(val, NETX_MIIMU);
+ while (readl(NETX_MIIMU) & MIIMU_SNRDY);
+
+ return readl(NETX_MIIMU) >> 16;
+
+}
+
+static void
+netx_eth_phy_write(struct net_device *ndev, int phy_id, int reg, int value)
+{
+ unsigned int val;
+
+ val = MIIMU_SNRDY | MIIMU_PREAMBLE | MIIMU_PHYADDR(phy_id) |
+ MIIMU_REGADDR(reg) | MIIMU_PHY_NRES | MIIMU_OPMODE_WRITE |
+ MIIMU_DATA(value);
+
+ writel(val, NETX_MIIMU);
+ while (readl(NETX_MIIMU) & MIIMU_SNRDY);
+}
+
+static int netx_eth_enable(struct net_device *ndev)
+{
+ struct netx_eth_priv *priv = netdev_priv(ndev);
+ unsigned int mac4321, mac65;
+ int running, i;
+
+ ether_setup(ndev);
+
+ ndev->open = netx_eth_open;
+ ndev->stop = netx_eth_close;
+ ndev->hard_start_xmit = netx_eth_hard_start_xmit;
+ ndev->tx_timeout = netx_eth_timeout;
+ ndev->watchdog_timeo = msecs_to_jiffies(5000);
+ ndev->get_stats = netx_eth_query_statistics;
+ ndev->set_multicast_list = netx_eth_set_multicast_list;
+
+ priv->msg_enable = NETIF_MSG_LINK;
+ priv->mii.phy_id_mask = 0x1f;
+ priv->mii.reg_num_mask = 0x1f;
+ priv->mii.force_media = 0;
+ priv->mii.full_duplex = 0;
+ priv->mii.dev = ndev;
+ priv->mii.mdio_read = netx_eth_phy_read;
+ priv->mii.mdio_write = netx_eth_phy_write;
+ priv->mii.phy_id = INTERNAL_PHY_ADR + priv->id;
+
+ running = xc_running(priv->xc);
+ xc_stop(priv->xc);
+
+ /* if the xc engine is already running, assume the bootloader has
+ * loaded the firmware for us
+ */
+ if (running) {
+ /* get Node Address from hardware */
+ mac4321 = readl(priv->xpec_base +
+ NETX_XPEC_RAM_START_OFS + ETH_MAC_4321);
+ mac65 = readl(priv->xpec_base +
+ NETX_XPEC_RAM_START_OFS + ETH_MAC_65);
+
+ ndev->dev_addr[0] = mac4321 & 0xff;
+ ndev->dev_addr[1] = (mac4321 >> 8) & 0xff;
+ ndev->dev_addr[2] = (mac4321 >> 16) & 0xff;
+ ndev->dev_addr[3] = (mac4321 >> 24) & 0xff;
+ ndev->dev_addr[4] = mac65 & 0xff;
+ ndev->dev_addr[5] = (mac65 >> 8) & 0xff;
+ } else {
+ if (xc_request_firmware(priv->xc)) {
+ printk(CARDNAME ": requesting firmware failed\n");
+ return -ENODEV;
+ }
+ }
+
+ xc_reset(priv->xc);
+ xc_start(priv->xc);
+
+ if (!is_valid_ether_addr(ndev->dev_addr))
+ printk("%s: Invalid ethernet MAC address. Please "
+ "set using ifconfig\n", ndev->name);
+
+ for (i=2; i<=18; i++)
+ pfifo_push(EMPTY_PTR_FIFO(priv->id),
+ FIFO_PTR_FRAMENO(i) | FIFO_PTR_SEGMENT(priv->id));
+
+ return register_netdev(ndev);
+
+}
+
+static int netx_eth_drv_probe(struct platform_device *pdev)
+{
+ struct netx_eth_priv *priv;
+ struct net_device *ndev;
+ struct netxeth_platform_data *pdata;
+ int ret;
+
+ ndev = alloc_etherdev(sizeof (struct netx_eth_priv));
+ if (!ndev) {
+ printk("%s: could not allocate device.\n", CARDNAME);
+ ret = -ENOMEM;
+ goto exit;
+ }
+ SET_MODULE_OWNER(ndev);
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+
+ platform_set_drvdata(pdev, ndev);
+
+ priv = netdev_priv(ndev);
+
+ pdata = (struct netxeth_platform_data *)pdev->dev.platform_data;
+ priv->xc = request_xc(pdata->xcno, &pdev->dev);
+ if (!priv->xc) {
+ dev_err(&pdev->dev, "unable to request xc engine\n");
+ ret = -ENODEV;
+ goto exit_free_netdev;
+ }
+
+ ndev->irq = priv->xc->irq;
+ priv->id = pdev->id;
+ priv->xpec_base = priv->xc->xpec_base;
+ priv->xmac_base = priv->xc->xmac_base;
+ priv->sram_base = priv->xc->sram_base;
+
+ ret = pfifo_request(PFIFO_MASK(priv->id));
+ if (ret) {
+ printk("unable to request PFIFO\n");
+ goto exit_free_xc;
+ }
+
+ ret = netx_eth_enable(ndev);
+ if (ret)
+ goto exit_free_pfifo;
+
+ return 0;
+exit_free_pfifo:
+ pfifo_free(PFIFO_MASK(priv->id));
+exit_free_xc:
+ free_xc(priv->xc);
+exit_free_netdev:
+ platform_set_drvdata(pdev, NULL);
+ free_netdev(ndev);
+exit:
+ return ret;
+}
+
+static int netx_eth_drv_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = dev_get_drvdata(&pdev->dev);
+ struct netx_eth_priv *priv = netdev_priv(ndev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ unregister_netdev(ndev);
+ xc_stop(priv->xc);
+ free_xc(priv->xc);
+ free_netdev(ndev);
+ pfifo_free(PFIFO_MASK(priv->id));
+
+ return 0;
+}
+
+static int netx_eth_drv_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ dev_err(&pdev->dev, "suspend not implemented\n");
+ return 0;
+}
+
+static int netx_eth_drv_resume(struct platform_device *pdev)
+{
+ dev_err(&pdev->dev, "resume not implemented\n");
+ return 0;
+}
+
+static struct platform_driver netx_eth_driver = {
+ .probe = netx_eth_drv_probe,
+ .remove = netx_eth_drv_remove,
+ .suspend = netx_eth_drv_suspend,
+ .resume = netx_eth_drv_resume,
+ .driver = {
+ .name = CARDNAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init netx_eth_init(void)
+{
+ unsigned int phy_control, val;
+
+ printk("NetX Ethernet driver\n");
+
+ phy_control = PHY_CONTROL_PHY_ADDRESS(INTERNAL_PHY_ADR>>1) |
+ PHY_CONTROL_PHY1_MODE(PHY_MODE_ALL) |
+ PHY_CONTROL_PHY1_AUTOMDIX |
+ PHY_CONTROL_PHY1_EN |
+ PHY_CONTROL_PHY0_MODE(PHY_MODE_ALL) |
+ PHY_CONTROL_PHY0_AUTOMDIX |
+ PHY_CONTROL_PHY0_EN |
+ PHY_CONTROL_CLK_XLATIN;
+
+ val = readl(NETX_SYSTEM_IOC_ACCESS_KEY);
+ writel(val, NETX_SYSTEM_IOC_ACCESS_KEY);
+
+ writel(phy_control | PHY_CONTROL_RESET, NETX_SYSTEM_PHY_CONTROL);
+ udelay(100);
+
+ val = readl(NETX_SYSTEM_IOC_ACCESS_KEY);
+ writel(val, NETX_SYSTEM_IOC_ACCESS_KEY);
+
+ writel(phy_control, NETX_SYSTEM_PHY_CONTROL);
+
+ return platform_driver_register(&netx_eth_driver);
+}
+
+static void __exit netx_eth_cleanup(void)
+{
+ platform_driver_unregister(&netx_eth_driver);
+}
+
+module_init(netx_eth_init);
+module_exit(netx_eth_cleanup);
+
+MODULE_AUTHOR("Sascha Hauer, Pengutronix");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 09b1176..ea93b8f1 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -831,8 +831,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN)
{
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 71f4505..9bae77c 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -1359,7 +1359,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev)
kio_addr_t ioaddr = dev->base_addr;
int okay;
unsigned freespace;
- unsigned pktlen = skb? skb->len : 0;
+ unsigned pktlen = skb->len;
DEBUG(1, "do_start_xmit(skb=%p, dev=%p) len=%u\n",
skb, dev, pktlen);
@@ -1374,8 +1374,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
if (pktlen < ETH_ZLEN)
{
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
pktlen = ETH_ZLEN;
}
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index cda3e53..2ba6d3a 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -44,6 +44,11 @@ config CICADA_PHY
depends on PHYLIB
---help---
Currently supports the cis8204
+config VITESSE_PHY
+ tristate "Drivers for the Vitesse PHYs"
+ depends on PHYLIB
+ ---help---
+ Currently supports the vsc8244
config SMSC_PHY
tristate "Drivers for SMSC PHYs"
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index d961413..a00e619 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_CICADA_PHY) += cicada.o
obj-$(CONFIG_LXT_PHY) += lxt.o
obj-$(CONFIG_QSEMI_PHY) += qsemi.o
obj-$(CONFIG_SMSC_PHY) += smsc.o
+obj-$(CONFIG_VITESSE_PHY) += vitesse.o
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
new file mode 100644
index 0000000..ffd215d
--- /dev/null
+++ b/drivers/net/phy/vitesse.c
@@ -0,0 +1,112 @@
+/*
+ * Driver for Vitesse PHYs
+ *
+ * Author: Kriston Carson
+ *
+ * Copyright (c) 2005 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+/* Vitesse Extended Control Register 1 */
+#define MII_VSC8244_EXT_CON1 0x17
+#define MII_VSC8244_EXTCON1_INIT 0x0000
+
+/* Vitesse Interrupt Mask Register */
+#define MII_VSC8244_IMASK 0x19
+#define MII_VSC8244_IMASK_IEN 0x8000
+#define MII_VSC8244_IMASK_SPEED 0x4000
+#define MII_VSC8244_IMASK_LINK 0x2000
+#define MII_VSC8244_IMASK_DUPLEX 0x1000
+#define MII_VSC8244_IMASK_MASK 0xf000
+
+/* Vitesse Interrupt Status Register */
+#define MII_VSC8244_ISTAT 0x1a
+#define MII_VSC8244_ISTAT_STATUS 0x8000
+#define MII_VSC8244_ISTAT_SPEED 0x4000
+#define MII_VSC8244_ISTAT_LINK 0x2000
+#define MII_VSC8244_ISTAT_DUPLEX 0x1000
+
+/* Vitesse Auxiliary Control/Status Register */
+#define MII_VSC8244_AUX_CONSTAT 0x1c
+#define MII_VSC8244_AUXCONSTAT_INIT 0x0004
+#define MII_VSC8244_AUXCONSTAT_DUPLEX 0x0020
+#define MII_VSC8244_AUXCONSTAT_SPEED 0x0018
+#define MII_VSC8244_AUXCONSTAT_GBIT 0x0010
+#define MII_VSC8244_AUXCONSTAT_100 0x0008
+
+MODULE_DESCRIPTION("Vitesse PHY driver");
+MODULE_AUTHOR("Kriston Carson");
+MODULE_LICENSE("GPL");
+
+static int vsc824x_config_init(struct phy_device *phydev)
+{
+ int err;
+
+ err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT,
+ MII_VSC8244_AUXCONSTAT_INIT);
+ if (err < 0)
+ return err;
+
+ err = phy_write(phydev, MII_VSC8244_EXT_CON1,
+ MII_VSC8244_EXTCON1_INIT);
+ return err;
+}
+
+static int vsc824x_ack_interrupt(struct phy_device *phydev)
+{
+ int err = phy_read(phydev, MII_VSC8244_ISTAT);
+
+ return (err < 0) ? err : 0;
+}
+
+static int vsc824x_config_intr(struct phy_device *phydev)
+{
+ int err;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+ err = phy_write(phydev, MII_VSC8244_IMASK,
+ MII_VSC8244_IMASK_MASK);
+ else
+ err = phy_write(phydev, MII_VSC8244_IMASK, 0);
+ return err;
+}
+
+/* Vitesse 824x */
+static struct phy_driver vsc8244_driver = {
+ .phy_id = 0x000fc6c2,
+ .name = "Vitesse VSC8244",
+ .phy_id_mask = 0x000fffc0,
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_init = &vsc824x_config_init,
+ .config_aneg = &genphy_config_aneg,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &vsc824x_ack_interrupt,
+ .config_intr = &vsc824x_config_intr,
+ .driver = { .owner = THIS_MODULE,},
+};
+
+static int __init vsc8244_init(void)
+{
+ return phy_driver_register(&vsc8244_driver);
+}
+
+static void __exit vsc8244_exit(void)
+{
+ phy_driver_unregister(&vsc8244_driver);
+}
+
+module_init(vsc8244_init);
+module_exit(vsc8244_exit);
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 9945cc6..12d1cb2 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -2172,7 +2172,7 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
static inline u32 rtl8169_tso_csum(struct sk_buff *skb, struct net_device *dev)
{
if (dev->features & NETIF_F_TSO) {
- u32 mss = skb_shinfo(skb)->tso_size;
+ u32 mss = skb_shinfo(skb)->gso_size;
if (mss)
return LargeSend | ((mss & MSSMask) << MSSShift);
@@ -2222,8 +2222,7 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
len = skb->len;
if (unlikely(len < ETH_ZLEN)) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (!skb)
+ if (skb_padto(skb, ETH_ZLEN))
goto err_update_stats;
len = ETH_ZLEN;
}
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index cac9fdd..3defe5d 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -2627,6 +2627,50 @@ no_rx:
#endif
/**
+ * s2io_netpoll - Rx interrupt service handler for netpoll support
+ * @dev : pointer to the device structure.
+ * Description:
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void s2io_netpoll(struct net_device *dev)
+{
+ nic_t *nic = dev->priv;
+ mac_info_t *mac_control;
+ struct config_param *config;
+ XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ u64 val64;
+ int i;
+
+ disable_irq(dev->irq);
+
+ atomic_inc(&nic->isr_cnt);
+ mac_control = &nic->mac_control;
+ config = &nic->config;
+
+ val64 = readq(&bar0->rx_traffic_int);
+ writeq(val64, &bar0->rx_traffic_int);
+
+ for (i = 0; i < config->rx_ring_num; i++)
+ rx_intr_handler(&mac_control->rings[i]);
+
+ for (i = 0; i < config->rx_ring_num; i++) {
+ if (fill_rx_buffers(nic, i) == -ENOMEM) {
+ DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
+ DBG_PRINT(ERR_DBG, " in Rx Netpoll!!\n");
+ break;
+ }
+ }
+ atomic_dec(&nic->isr_cnt);
+ enable_irq(dev->irq);
+ return;
+}
+#endif
+
+/**
* rx_intr_handler - Rx interrupt handler
* @nic: device private variable.
* Description:
@@ -3915,8 +3959,8 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
txdp->Control_1 = 0;
txdp->Control_2 = 0;
#ifdef NETIF_F_TSO
- mss = skb_shinfo(skb)->tso_size;
- if (mss) {
+ mss = skb_shinfo(skb)->gso_size;
+ if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV4) {
txdp->Control_1 |= TXD_TCP_LSO_EN;
txdp->Control_1 |= TXD_TCP_LSO_MSS(mss);
}
@@ -3936,10 +3980,10 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
}
frg_len = skb->len - skb->data_len;
- if (skb_shinfo(skb)->ufo_size) {
+ if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4) {
int ufo_size;
- ufo_size = skb_shinfo(skb)->ufo_size;
+ ufo_size = skb_shinfo(skb)->gso_size;
ufo_size &= ~7;
txdp->Control_1 |= TXD_UFO_EN;
txdp->Control_1 |= TXD_UFO_MSS(ufo_size);
@@ -3965,7 +4009,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
txdp->Host_Control = (unsigned long) skb;
txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len);
- if (skb_shinfo(skb)->ufo_size)
+ if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
txdp->Control_1 |= TXD_UFO_EN;
frg_cnt = skb_shinfo(skb)->nr_frags;
@@ -3980,12 +4024,12 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
(sp->pdev, frag->page, frag->page_offset,
frag->size, PCI_DMA_TODEVICE);
txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size);
- if (skb_shinfo(skb)->ufo_size)
+ if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
txdp->Control_1 |= TXD_UFO_EN;
}
txdp->Control_1 |= TXD_GATHER_CODE_LAST;
- if (skb_shinfo(skb)->ufo_size)
+ if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
frg_cnt++; /* as Txd0 was used for inband header */
tx_fifo = mac_control->tx_FIFO_start[queue];
@@ -3999,7 +4043,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
if (mss)
val64 |= TX_FIFO_SPECIAL_FUNC;
#endif
- if (skb_shinfo(skb)->ufo_size)
+ if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
val64 |= TX_FIFO_SPECIAL_FUNC;
writeq(val64, &tx_fifo->List_Control);
@@ -6967,6 +7011,10 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
dev->weight = 32;
#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = s2io_netpoll;
+#endif
+
dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
if (sp->high_dma_flag == TRUE)
dev->features |= NETIF_F_HIGHDMA;
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index bcef03f..efd0f23 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -396,8 +396,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
unsigned char *buf;
if (length < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index 31dd3f0..df39f34 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -1156,8 +1156,7 @@ static int sis190_start_xmit(struct sk_buff *skb, struct net_device *dev)
dma_addr_t mapping;
if (unlikely(skb->len < ETH_ZLEN)) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (!skb) {
+ if (skb_padto(skb, ETH_ZLEN)) {
tp->stats.tx_dropped++;
goto out;
}
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
index 38a26df..f3efbd1 100644
--- a/drivers/net/sk98lin/skge.c
+++ b/drivers/net/sk98lin/skge.c
@@ -1525,7 +1525,7 @@ struct sk_buff *pMessage) /* pointer to send-message */
** This is to resolve faulty padding by the HW with 0xaa bytes.
*/
if (BytesSend < C_LEN_ETHERNET_MINSIZE) {
- if ((pMessage = skb_padto(pMessage, C_LEN_ETHERNET_MINSIZE)) == NULL) {
+ if (skb_padto(pMessage, C_LEN_ETHERNET_MINSIZE)) {
spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
return 0;
}
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 536dd1c..19a4a16 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -2310,8 +2310,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
u64 map;
unsigned long flags;
- skb = skb_padto(skb, ETH_ZLEN);
- if (!skb)
+ if (skb_padto(skb, ETH_ZLEN))
return NETDEV_TX_OK;
if (!spin_trylock_irqsave(&skge->tx_lock, flags))
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index fba1e4d4..d357787 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -1160,7 +1160,7 @@ static unsigned tx_le_req(const struct sk_buff *skb)
count = sizeof(dma_addr_t) / sizeof(u32);
count += skb_shinfo(skb)->nr_frags * count;
- if (skb_shinfo(skb)->tso_size)
+ if (skb_shinfo(skb)->gso_size)
++count;
if (skb->ip_summed == CHECKSUM_HW)
@@ -1232,7 +1232,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
}
/* Check for TCP Segmentation Offload */
- mss = skb_shinfo(skb)->tso_size;
+ mss = skb_shinfo(skb)->gso_size;
if (mss != 0) {
/* just drop the packet if non-linear expansion fails */
if (skb_header_cloned(skb) &&
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index 6cf16f3..8b0321f 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -523,8 +523,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de
length = skb->len;
if (length < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL) {
+ if (skb_padto(skb, ETH_ZLEN)) {
netif_wake_queue(dev);
return 0;
}
diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c
index 90b818a..cab0dd9 100644
--- a/drivers/net/sonic.c
+++ b/drivers/net/sonic.c
@@ -231,8 +231,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
length = skb->len;
if (length < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 9b7805b..c158eed 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -1349,8 +1349,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
#if defined(ZEROCOPY) && defined(HAS_BROKEN_FIRMWARE)
if (skb->ip_summed == CHECKSUM_HW) {
- skb = skb_padto(skb, (skb->len + PADDING_MASK) & ~PADDING_MASK);
- if (skb == NULL)
+ if (skb_padto(skb, (skb->len + PADDING_MASK) & ~PADDING_MASK))
return NETDEV_TX_OK;
}
#endif /* ZEROCOPY && HAS_BROKEN_FIRMWARE */
diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
index d4c0002..a2fad50 100644
--- a/drivers/net/sun3lance.c
+++ b/drivers/net/sun3lance.c
@@ -55,7 +55,7 @@ static char *version = "sun3lance.c: v1.2 1/12/2001 Sam Creasey (sammy@sammy.ne
/* sun3/60 addr/irq for the lance chip. If your sun is different,
change this. */
#define LANCE_OBIO 0x120000
-#define LANCE_IRQ IRQ3
+#define LANCE_IRQ IRQ_AUTO_3
/* Debug level:
* 0 = silent, print only serious errors
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index cfaf47c..7127f0f 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -72,8 +72,6 @@ MODULE_LICENSE("GPL");
#define DIRQ(x)
#endif
-static struct bigmac *root_bigmac_dev;
-
#define DEFAULT_JAMSIZE 4 /* Toe jam */
#define QEC_RESET_TRIES 200
@@ -491,7 +489,7 @@ static void bigmac_tcvr_init(struct bigmac *bp)
}
}
-static int bigmac_init(struct bigmac *, int);
+static int bigmac_init_hw(struct bigmac *, int);
static int try_next_permutation(struct bigmac *bp, void __iomem *tregs)
{
@@ -551,7 +549,7 @@ static void bigmac_timer(unsigned long data)
if (ret == -1) {
printk(KERN_ERR "%s: Link down, cable problem?\n",
bp->dev->name);
- ret = bigmac_init(bp, 0);
+ ret = bigmac_init_hw(bp, 0);
if (ret) {
printk(KERN_ERR "%s: Error, cannot re-init the "
"BigMAC.\n", bp->dev->name);
@@ -621,7 +619,7 @@ static void bigmac_begin_auto_negotiation(struct bigmac *bp)
add_timer(&bp->bigmac_timer);
}
-static int bigmac_init(struct bigmac *bp, int from_irq)
+static int bigmac_init_hw(struct bigmac *bp, int from_irq)
{
void __iomem *gregs = bp->gregs;
void __iomem *cregs = bp->creg;
@@ -752,7 +750,7 @@ static void bigmac_is_medium_rare(struct bigmac *bp, u32 qec_status, u32 bmac_st
}
printk(" RESET\n");
- bigmac_init(bp, 1);
+ bigmac_init_hw(bp, 1);
}
/* BigMAC transmit complete service routines. */
@@ -926,7 +924,7 @@ static int bigmac_open(struct net_device *dev)
return ret;
}
init_timer(&bp->bigmac_timer);
- ret = bigmac_init(bp, 0);
+ ret = bigmac_init_hw(bp, 0);
if (ret)
free_irq(dev->irq, bp);
return ret;
@@ -950,7 +948,7 @@ static void bigmac_tx_timeout(struct net_device *dev)
{
struct bigmac *bp = (struct bigmac *) dev->priv;
- bigmac_init(bp, 0);
+ bigmac_init_hw(bp, 0);
netif_wake_queue(dev);
}
@@ -1104,6 +1102,8 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev)
bp->qec_sdev = qec_sdev;
bp->bigmac_sdev = qec_sdev->child;
+ SET_NETDEV_DEV(dev, &bp->bigmac_sdev->ofdev.dev);
+
spin_lock_init(&bp->lock);
/* Verify the registers we expect, are actually there. */
@@ -1226,11 +1226,7 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev)
goto fail_and_cleanup;
}
- /* Put us into the list of instances attached for later driver
- * exit.
- */
- bp->next_module = root_bigmac_dev;
- root_bigmac_dev = bp;
+ dev_set_drvdata(&bp->bigmac_sdev->ofdev.dev, bp);
printk(KERN_INFO "%s: BigMAC 100baseT Ethernet ", dev->name);
for (i = 0; i < 6; i++)
@@ -1266,69 +1262,68 @@ fail_and_cleanup:
/* QEC can be the parent of either QuadEthernet or
* a BigMAC. We want the latter.
*/
-static int __init bigmac_match(struct sbus_dev *sdev)
+static int __devinit bigmac_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct sbus_dev *child = sdev->child;
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+ struct device_node *dp = dev->node;
- if (strcmp(sdev->prom_name, "qec") != 0)
- return 0;
+ if (!strcmp(dp->name, "be"))
+ sdev = sdev->parent;
- if (child == NULL)
- return 0;
-
- if (strcmp(child->prom_name, "be") != 0)
- return 0;
-
- return 1;
+ return bigmac_ether_init(sdev);
}
-static int __init bigmac_probe(void)
+static int __devexit bigmac_sbus_remove(struct of_device *dev)
{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev = NULL;
- static int called;
- int cards = 0, v;
-
- root_bigmac_dev = NULL;
-
- if (called)
- return -ENODEV;
- called++;
-
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- if (bigmac_match(sdev)) {
- cards++;
- if ((v = bigmac_ether_init(sdev)))
- return v;
- }
- }
- }
- if (!cards)
- return -ENODEV;
+ struct bigmac *bp = dev_get_drvdata(&dev->dev);
+ struct net_device *net_dev = bp->dev;
+
+ unregister_netdevice(net_dev);
+
+ sbus_iounmap(bp->gregs, GLOB_REG_SIZE);
+ sbus_iounmap(bp->creg, CREG_REG_SIZE);
+ sbus_iounmap(bp->bregs, BMAC_REG_SIZE);
+ sbus_iounmap(bp->tregs, TCVR_REG_SIZE);
+ sbus_free_consistent(bp->bigmac_sdev,
+ PAGE_SIZE,
+ bp->bmac_block,
+ bp->bblock_dvma);
+
+ free_netdev(net_dev);
+
+ dev_set_drvdata(&dev->dev, NULL);
+
return 0;
}
-static void __exit bigmac_cleanup(void)
-{
- while (root_bigmac_dev) {
- struct bigmac *bp = root_bigmac_dev;
- struct bigmac *bp_nxt = root_bigmac_dev->next_module;
+static struct of_device_id bigmac_sbus_match[] = {
+ {
+ .name = "qec",
+ },
+ {
+ .name = "be",
+ },
+ {},
+};
- sbus_iounmap(bp->gregs, GLOB_REG_SIZE);
- sbus_iounmap(bp->creg, CREG_REG_SIZE);
- sbus_iounmap(bp->bregs, BMAC_REG_SIZE);
- sbus_iounmap(bp->tregs, TCVR_REG_SIZE);
- sbus_free_consistent(bp->bigmac_sdev,
- PAGE_SIZE,
- bp->bmac_block,
- bp->bblock_dvma);
+MODULE_DEVICE_TABLE(of, bigmac_sbus_match);
- unregister_netdev(bp->dev);
- free_netdev(bp->dev);
- root_bigmac_dev = bp_nxt;
- }
+static struct of_platform_driver bigmac_sbus_driver = {
+ .name = "sunbmac",
+ .match_table = bigmac_sbus_match,
+ .probe = bigmac_sbus_probe,
+ .remove = __devexit_p(bigmac_sbus_remove),
+};
+
+static int __init bigmac_init(void)
+{
+ return of_register_driver(&bigmac_sbus_driver, &sbus_bus_type);
+}
+
+static void __exit bigmac_exit(void)
+{
+ of_unregister_driver(&bigmac_sbus_driver);
}
-module_init(bigmac_probe);
-module_exit(bigmac_cleanup);
+module_init(bigmac_init);
+module_exit(bigmac_exit);
diff --git a/drivers/net/sunbmac.h b/drivers/net/sunbmac.h
index b0dbc51..b563d3c 100644
--- a/drivers/net/sunbmac.h
+++ b/drivers/net/sunbmac.h
@@ -332,7 +332,6 @@ struct bigmac {
struct sbus_dev *qec_sdev;
struct sbus_dev *bigmac_sdev;
struct net_device *dev;
- struct bigmac *next_module;
};
/* We use this to acquire receive skb's that we can DMA directly into. */
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index 61eec46..f13b2a1 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -94,11 +94,13 @@
Version LK1.10 (Philippe De Muyter phdm@macqel.be):
- Make 'unblock interface after Tx underrun' work
+ Version LK1.11 (Pedro Alejandro Lopez-Valencia palopezv at gmail.com):
+ - Add support for IC Plus Corporation IP100A chipset
*/
#define DRV_NAME "sundance"
-#define DRV_VERSION "1.01+LK1.10"
-#define DRV_RELDATE "28-Oct-2005"
+#define DRV_VERSION "1.01+LK1.11"
+#define DRV_RELDATE "14-Jun-2006"
/* The user-configurable values.
@@ -287,6 +289,7 @@ static struct pci_device_id sundance_pci_tbl[] = {
{0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3},
{0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
{0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+ {0x13F0, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
{0,}
};
MODULE_DEVICE_TABLE(pci, sundance_pci_tbl);
@@ -305,6 +308,7 @@ static const struct pci_id_info pci_id_tbl[] = {
{"D-Link DFE-530TXS FAST Ethernet Adapter"},
{"D-Link DL10050-based FAST Ethernet Adapter"},
{"Sundance Technology Alta"},
+ {"IC Plus Corporation IP100A FAST Ethernet Adapter"},
{NULL,}, /* 0 terminated list. */
};
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 38cd30c..5248670 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -2880,17 +2880,20 @@ static int __devinit gem_get_device_address(struct gem *gp)
#if defined(__sparc__)
struct pci_dev *pdev = gp->pdev;
struct pcidev_cookie *pcp = pdev->sysdata;
- int node = -1;
+ int use_idprom = 1;
if (pcp != NULL) {
- node = pcp->prom_node;
- if (prom_getproplen(node, "local-mac-address") == 6)
- prom_getproperty(node, "local-mac-address",
- dev->dev_addr, 6);
- else
- node = -1;
+ unsigned char *addr;
+ int len;
+
+ addr = of_get_property(pcp->prom_node, "local-mac-address",
+ &len);
+ if (addr && len == 6) {
+ use_idprom = 0;
+ memcpy(dev->dev_addr, addr, 6);
+ }
}
- if (node == -1)
+ if (use_idprom)
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
#elif defined(CONFIG_PPC_PMAC)
unsigned char *addr;
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index bd5d266..c33ead3 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -1,9 +1,9 @@
-/* $Id: sunhme.c,v 1.124 2002/01/15 06:25:51 davem Exp $
- * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
+/* sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
* auto carrier detecting ethernet driver. Also known as the
* "Happy Meal Ethernet" found on SunSwift SBUS cards.
*
- * Copyright (C) 1996, 1998, 1999, 2002, 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996, 1998, 1999, 2002, 2003,
+ 2006 David S. Miller (davem@davemloft.net)
*
* Changes :
* 2000/11/11 Willy Tarreau <willy AT meta-x.org>
@@ -40,15 +40,13 @@
#include <asm/dma.h>
#include <asm/byteorder.h>
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
#include <asm/idprom.h>
#include <asm/sbus.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
#include <asm/auxio.h>
-#ifndef __sparc_v9__
-#include <asm/io-unit.h>
-#endif
#endif
#include <asm/uaccess.h>
@@ -57,7 +55,7 @@
#ifdef CONFIG_PCI
#include <linux/pci.h>
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
#include <asm/pbm.h>
#endif
#endif
@@ -65,9 +63,9 @@
#include "sunhme.h"
#define DRV_NAME "sunhme"
-#define DRV_VERSION "2.02"
-#define DRV_RELDATE "8/24/03"
-#define DRV_AUTHOR "David S. Miller (davem@redhat.com)"
+#define DRV_VERSION "3.00"
+#define DRV_RELDATE "June 23, 2006"
+#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)"
static char version[] =
DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
@@ -83,8 +81,6 @@ static int macaddr[6];
module_param_array(macaddr, int, NULL, 0);
MODULE_PARM_DESC(macaddr, "Happy Meal MAC address to set");
-static struct happy_meal *root_happy_dev;
-
#ifdef CONFIG_SBUS
static struct quattro *qfe_sbus_list;
#endif
@@ -181,26 +177,6 @@ static __inline__ void tx_dump_ring(struct happy_meal *hp)
#define DEFAULT_IPG2 4 /* For all modes */
#define DEFAULT_JAMSIZE 4 /* Toe jam */
-#if defined(CONFIG_PCI) && defined(MODULE)
-/* This happy_pci_ids is declared __initdata because it is only used
- as an advisory to depmod. If this is ported to the new PCI interface
- where it could be referenced at any time due to hot plugging,
- the __initdata reference should be removed. */
-
-static struct pci_device_id happymeal_pci_ids[] = {
- {
- .vendor = PCI_VENDOR_ID_SUN,
- .device = PCI_DEVICE_ID_SUN_HAPPYMEAL,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },
- { } /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(pci, happymeal_pci_ids);
-
-#endif
-
/* NOTE: In the descriptor writes one _must_ write the address
* member _first_. The card must not be allowed to see
* the updated descriptor flags until the address is
@@ -1610,7 +1586,7 @@ static int happy_meal_init(struct happy_meal *hp)
HMD(("happy_meal_init: old[%08x] bursts<",
hme_read32(hp, gregs + GREG_CFG)));
-#ifndef __sparc__
+#ifndef CONFIG_SPARC
/* It is always PCI and can handle 64byte bursts. */
hme_write32(hp, gregs + GREG_CFG, GREG_CFG_BURST64);
#else
@@ -1647,7 +1623,7 @@ static int happy_meal_init(struct happy_meal *hp)
HMD(("XXX>"));
hme_write32(hp, gregs + GREG_CFG, 0);
}
-#endif /* __sparc__ */
+#endif /* CONFIG_SPARC */
/* Turn off interrupts we do not want to hear. */
HMD((", enable global interrupts, "));
@@ -2592,14 +2568,10 @@ static void __init quattro_apply_ranges(struct quattro *qp, struct happy_meal *h
*/
static struct quattro * __init quattro_sbus_find(struct sbus_dev *goal_sdev)
{
- struct sbus_bus *sbus;
struct sbus_dev *sdev;
struct quattro *qp;
int i;
- if (qfe_sbus_list == NULL)
- goto found;
-
for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
for (i = 0, sdev = qp->quattro_dev;
(sdev != NULL) && (i < 4);
@@ -2608,17 +2580,7 @@ static struct quattro * __init quattro_sbus_find(struct sbus_dev *goal_sdev)
return qp;
}
}
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- if (sdev == goal_sdev)
- goto found;
- }
- }
-
- /* Cannot find quattro parent, fail. */
- return NULL;
-found:
qp = kmalloc(sizeof(struct quattro), GFP_KERNEL);
if (qp != NULL) {
int i;
@@ -2655,6 +2617,17 @@ static void __init quattro_sbus_register_irqs(void)
}
}
}
+
+static void __devexit quattro_sbus_free_irqs(void)
+{
+ struct quattro *qp;
+
+ for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
+ struct sbus_dev *sdev = qp->quattro_dev;
+
+ free_irq(sdev->irqs[0], qp);
+ }
+}
#endif /* CONFIG_SBUS */
#ifdef CONFIG_PCI
@@ -2689,8 +2662,9 @@ static struct quattro * __init quattro_pci_find(struct pci_dev *pdev)
#endif /* CONFIG_PCI */
#ifdef CONFIG_SBUS
-static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
+static int __init happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe)
{
+ struct device_node *dp = sdev->ofdev.node;
struct quattro *qp = NULL;
struct happy_meal *hp;
struct net_device *dev;
@@ -2713,6 +2687,7 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
if (!dev)
goto err_out;
SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
if (hme_version_printed++ == 0)
printk(KERN_INFO "%s", version);
@@ -2728,13 +2703,16 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
for (i = 0; i < 6; i++)
dev->dev_addr[i] = macaddr[i];
macaddr[5]++;
- } else if (qfe_slot != -1 &&
- prom_getproplen(sdev->prom_node,
- "local-mac-address") == 6) {
- prom_getproperty(sdev->prom_node, "local-mac-address",
- dev->dev_addr, 6);
} else {
- memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
+ unsigned char *addr;
+ int len;
+
+ addr = of_get_property(dp, "local-mac-address", &len);
+
+ if (qfe_slot != -1 && addr && len == 6)
+ memcpy(dev->dev_addr, addr, 6);
+ else
+ memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
}
hp = dev->priv;
@@ -2745,9 +2723,8 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
err = -ENODEV;
if (sdev->num_registers != 5) {
- printk(KERN_ERR "happymeal: Device does not have 5 regs, it has %d.\n",
+ printk(KERN_ERR "happymeal: Device needs 5 regs, has %d.\n",
sdev->num_registers);
- printk(KERN_ERR "happymeal: Would you like that for here or to go?\n");
goto err_out_free_netdev;
}
@@ -2761,39 +2738,39 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
hp->gregs = sbus_ioremap(&sdev->resource[0], 0,
GREG_REG_SIZE, "HME Global Regs");
if (!hp->gregs) {
- printk(KERN_ERR "happymeal: Cannot map Happy Meal global registers.\n");
+ printk(KERN_ERR "happymeal: Cannot map global registers.\n");
goto err_out_free_netdev;
}
hp->etxregs = sbus_ioremap(&sdev->resource[1], 0,
ETX_REG_SIZE, "HME TX Regs");
if (!hp->etxregs) {
- printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Transmit registers.\n");
+ printk(KERN_ERR "happymeal: Cannot map MAC TX registers.\n");
goto err_out_iounmap;
}
hp->erxregs = sbus_ioremap(&sdev->resource[2], 0,
ERX_REG_SIZE, "HME RX Regs");
if (!hp->erxregs) {
- printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Receive registers.\n");
+ printk(KERN_ERR "happymeal: Cannot map MAC RX registers.\n");
goto err_out_iounmap;
}
hp->bigmacregs = sbus_ioremap(&sdev->resource[3], 0,
BMAC_REG_SIZE, "HME BIGMAC Regs");
if (!hp->bigmacregs) {
- printk(KERN_ERR "happymeal: Cannot map Happy Meal BIGMAC registers.\n");
+ printk(KERN_ERR "happymeal: Cannot map BIGMAC registers.\n");
goto err_out_iounmap;
}
hp->tcvregs = sbus_ioremap(&sdev->resource[4], 0,
TCVR_REG_SIZE, "HME Tranceiver Regs");
if (!hp->tcvregs) {
- printk(KERN_ERR "happymeal: Cannot map Happy Meal Tranceiver registers.\n");
+ printk(KERN_ERR "happymeal: Cannot map TCVR registers.\n");
goto err_out_iounmap;
}
- hp->hm_revision = prom_getintdefault(sdev->prom_node, "hm-rev", 0xff);
+ hp->hm_revision = of_getintprop_default(dp, "hm-rev", 0xff);
if (hp->hm_revision == 0xff)
hp->hm_revision = 0xa0;
@@ -2807,8 +2784,8 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
hp->happy_flags |= HFLAG_QUATTRO;
/* Get the supported DVMA burst sizes from our Happy SBUS. */
- hp->happy_bursts = prom_getintdefault(sdev->bus->prom_node,
- "burst-sizes", 0x00);
+ hp->happy_bursts = of_getintprop_default(sdev->bus->ofdev.node,
+ "burst-sizes", 0x00);
hp->happy_block = sbus_alloc_consistent(hp->happy_dev,
PAGE_SIZE,
@@ -2871,6 +2848,8 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
goto err_out_free_consistent;
}
+ dev_set_drvdata(&sdev->ofdev.dev, hp);
+
if (qfe_slot != -1)
printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
dev->name, qfe_slot);
@@ -2883,12 +2862,6 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
dev->dev_addr[i], i == 5 ? ' ' : ':');
printk("\n");
- /* We are home free at this point, link us in to the happy
- * device list.
- */
- hp->next_module = root_happy_dev;
- root_happy_dev = hp;
-
return 0;
err_out_free_consistent:
@@ -2918,7 +2891,7 @@ err_out:
#endif
#ifdef CONFIG_PCI
-#ifndef __sparc__
+#ifndef CONFIG_SPARC
static int is_quattro_p(struct pci_dev *pdev)
{
struct pci_dev *busdev = pdev->bus->self;
@@ -3006,14 +2979,14 @@ static void get_hme_mac_nonsparc(struct pci_dev *pdev, unsigned char *dev_addr)
get_random_bytes(&dev_addr[3], 3);
return;
}
-#endif /* !(__sparc__) */
+#endif /* !(CONFIG_SPARC) */
-static int __init happy_meal_pci_init(struct pci_dev *pdev)
+static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct quattro *qp = NULL;
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
struct pcidev_cookie *pcp;
- int node;
#endif
struct happy_meal *hp;
struct net_device *dev;
@@ -3024,15 +2997,14 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
int err;
/* Now make sure pci_dev cookie is there. */
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
pcp = pdev->sysdata;
- if (pcp == NULL || pcp->prom_node == -1) {
+ if (pcp == NULL) {
printk(KERN_ERR "happymeal(PCI): Some PCI device info missing\n");
return -ENODEV;
}
- node = pcp->prom_node;
- prom_getstring(node, "name", prom_name, sizeof(prom_name));
+ strcpy(prom_name, pcp->prom_node->name);
#else
if (is_quattro_p(pdev))
strcpy(prom_name, "SUNW,qfe");
@@ -3103,11 +3075,15 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
dev->dev_addr[i] = macaddr[i];
macaddr[5]++;
} else {
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
+ unsigned char *addr;
+ int len;
+
if (qfe_slot != -1 &&
- prom_getproplen(node, "local-mac-address") == 6) {
- prom_getproperty(node, "local-mac-address",
- dev->dev_addr, 6);
+ (addr = of_get_property(pcp->prom_node,
+ "local-mac-address", &len)) != NULL
+ && len == 6) {
+ memcpy(dev->dev_addr, addr, 6);
} else {
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
}
@@ -3123,8 +3099,8 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
hp->bigmacregs = (hpreg_base + 0x6000UL);
hp->tcvregs = (hpreg_base + 0x7000UL);
-#ifdef __sparc__
- hp->hm_revision = prom_getintdefault(node, "hm-rev", 0xff);
+#ifdef CONFIG_SPARC
+ hp->hm_revision = of_getintprop_default(pcp->prom_node, "hm-rev", 0xff);
if (hp->hm_revision == 0xff) {
unsigned char prev;
@@ -3148,7 +3124,7 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
/* And of course, indicate this is PCI. */
hp->happy_flags |= HFLAG_PCI;
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
/* Assume PCI happy meals can handle all burst sizes. */
hp->happy_bursts = DMA_BURSTBITS;
#endif
@@ -3211,6 +3187,8 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
goto err_out_iounmap;
}
+ dev_set_drvdata(&pdev->dev, hp);
+
if (!qfe_slot) {
struct pci_dev *qpdev = qp->quattro_dev;
@@ -3240,12 +3218,6 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
printk("\n");
- /* We are home free at this point, link us in to the happy
- * device list.
- */
- hp->next_module = root_happy_dev;
- root_happy_dev = hp;
-
return 0;
err_out_iounmap:
@@ -3263,136 +3235,146 @@ err_out_clear_quattro:
err_out:
return err;
}
-#endif
-#ifdef CONFIG_SBUS
-static int __init happy_meal_sbus_probe(void)
+static void __devexit happy_meal_pci_remove(struct pci_dev *pdev)
{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev;
- int cards = 0;
- char model[128];
-
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- char *name = sdev->prom_name;
-
- if (!strcmp(name, "SUNW,hme")) {
- cards++;
- prom_getstring(sdev->prom_node, "model",
- model, sizeof(model));
- if (!strcmp(model, "SUNW,sbus-qfe"))
- happy_meal_sbus_init(sdev, 1);
- else
- happy_meal_sbus_init(sdev, 0);
- } else if (!strcmp(name, "qfe") ||
- !strcmp(name, "SUNW,qfe")) {
- cards++;
- happy_meal_sbus_init(sdev, 1);
- }
- }
- }
- if (cards != 0)
- quattro_sbus_register_irqs();
- return cards;
+ struct happy_meal *hp = dev_get_drvdata(&pdev->dev);
+ struct net_device *net_dev = hp->dev;
+
+ unregister_netdev(net_dev);
+
+ pci_free_consistent(hp->happy_dev,
+ PAGE_SIZE,
+ hp->happy_block,
+ hp->hblock_dvma);
+ iounmap(hp->gregs);
+ pci_release_regions(hp->happy_dev);
+
+ free_netdev(net_dev);
+
+ dev_set_drvdata(&pdev->dev, NULL);
}
-#endif
-#ifdef CONFIG_PCI
-static int __init happy_meal_pci_probe(void)
+static struct pci_device_id happymeal_pci_ids[] = {
+ {
+ .vendor = PCI_VENDOR_ID_SUN,
+ .device = PCI_DEVICE_ID_SUN_HAPPYMEAL,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(pci, happymeal_pci_ids);
+
+static struct pci_driver hme_pci_driver = {
+ .name = "hme",
+ .id_table = happymeal_pci_ids,
+ .probe = happy_meal_pci_probe,
+ .remove = __devexit_p(happy_meal_pci_remove),
+};
+
+static int __init happy_meal_pci_init(void)
{
- struct pci_dev *pdev = NULL;
- int cards = 0;
+ return pci_module_init(&hme_pci_driver);
+}
- while ((pdev = pci_find_device(PCI_VENDOR_ID_SUN,
- PCI_DEVICE_ID_SUN_HAPPYMEAL, pdev)) != NULL) {
- if (pci_enable_device(pdev))
- continue;
- pci_set_master(pdev);
- cards++;
- happy_meal_pci_init(pdev);
+static void happy_meal_pci_exit(void)
+{
+ pci_unregister_driver(&hme_pci_driver);
+
+ while (qfe_pci_list) {
+ struct quattro *qfe = qfe_pci_list;
+ struct quattro *next = qfe->next;
+
+ kfree(qfe);
+
+ qfe_pci_list = next;
}
- return cards;
}
+
#endif
-static int __init happy_meal_probe(void)
+#ifdef CONFIG_SBUS
+static int __devinit hme_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
- static int called = 0;
- int cards;
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+ struct device_node *dp = dev->node;
+ char *model = of_get_property(dp, "model", NULL);
+ int is_qfe = (match->data != NULL);
- root_happy_dev = NULL;
+ if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe"))
+ is_qfe = 1;
- if (called)
- return -ENODEV;
- called++;
+ return happy_meal_sbus_probe_one(sdev, is_qfe);
+}
+
+static int __devexit hme_sbus_remove(struct of_device *dev)
+{
+ struct happy_meal *hp = dev_get_drvdata(&dev->dev);
+ struct net_device *net_dev = hp->dev;
+
+ unregister_netdevice(net_dev);
+
+ /* XXX qfe parent interrupt... */
+
+ sbus_iounmap(hp->gregs, GREG_REG_SIZE);
+ sbus_iounmap(hp->etxregs, ETX_REG_SIZE);
+ sbus_iounmap(hp->erxregs, ERX_REG_SIZE);
+ sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE);
+ sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE);
+ sbus_free_consistent(hp->happy_dev,
+ PAGE_SIZE,
+ hp->happy_block,
+ hp->hblock_dvma);
+
+ free_netdev(net_dev);
+
+ dev_set_drvdata(&dev->dev, NULL);
- cards = 0;
-#ifdef CONFIG_SBUS
- cards += happy_meal_sbus_probe();
-#endif
-#ifdef CONFIG_PCI
- cards += happy_meal_pci_probe();
-#endif
- if (!cards)
- return -ENODEV;
return 0;
}
+static struct of_device_id hme_sbus_match[] = {
+ {
+ .name = "SUNW,hme",
+ },
+ {
+ .name = "SUNW,qfe",
+ .data = (void *) 1,
+ },
+ {
+ .name = "qfe",
+ .data = (void *) 1,
+ },
+ {},
+};
-static void __exit happy_meal_cleanup_module(void)
-{
-#ifdef CONFIG_SBUS
- struct quattro *last_seen_qfe = NULL;
-#endif
+MODULE_DEVICE_TABLE(of, hme_sbus_match);
- while (root_happy_dev) {
- struct happy_meal *hp = root_happy_dev;
- struct happy_meal *next = root_happy_dev->next_module;
- struct net_device *dev = hp->dev;
+static struct of_platform_driver hme_sbus_driver = {
+ .name = "hme",
+ .match_table = hme_sbus_match,
+ .probe = hme_sbus_probe,
+ .remove = __devexit_p(hme_sbus_remove),
+};
- /* Unregister netdev before unmapping registers as this
- * call can end up trying to access those registers.
- */
- unregister_netdev(dev);
+static int __init happy_meal_sbus_init(void)
+{
+ int err;
-#ifdef CONFIG_SBUS
- if (!(hp->happy_flags & HFLAG_PCI)) {
- if (hp->happy_flags & HFLAG_QUATTRO) {
- if (hp->qfe_parent != last_seen_qfe) {
- free_irq(dev->irq, hp->qfe_parent);
- last_seen_qfe = hp->qfe_parent;
- }
- }
+ err = of_register_driver(&hme_sbus_driver, &sbus_bus_type);
+ if (!err)
+ quattro_sbus_register_irqs();
- sbus_iounmap(hp->gregs, GREG_REG_SIZE);
- sbus_iounmap(hp->etxregs, ETX_REG_SIZE);
- sbus_iounmap(hp->erxregs, ERX_REG_SIZE);
- sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE);
- sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE);
- sbus_free_consistent(hp->happy_dev,
- PAGE_SIZE,
- hp->happy_block,
- hp->hblock_dvma);
- }
-#endif
-#ifdef CONFIG_PCI
- if ((hp->happy_flags & HFLAG_PCI)) {
- pci_free_consistent(hp->happy_dev,
- PAGE_SIZE,
- hp->happy_block,
- hp->hblock_dvma);
- iounmap(hp->gregs);
- pci_release_regions(hp->happy_dev);
- }
-#endif
- free_netdev(dev);
+ return err;
+}
- root_happy_dev = next;
- }
+static void happy_meal_sbus_exit(void)
+{
+ of_unregister_driver(&hme_sbus_driver);
+ quattro_sbus_free_irqs();
- /* Now cleanup the quattro lists. */
-#ifdef CONFIG_SBUS
while (qfe_sbus_list) {
struct quattro *qfe = qfe_sbus_list;
struct quattro *next = qfe->next;
@@ -3401,18 +3383,39 @@ static void __exit happy_meal_cleanup_module(void)
qfe_sbus_list = next;
}
+}
#endif
-#ifdef CONFIG_PCI
- while (qfe_pci_list) {
- struct quattro *qfe = qfe_pci_list;
- struct quattro *next = qfe->next;
- kfree(qfe);
+static int __init happy_meal_probe(void)
+{
+ int err = 0;
- qfe_pci_list = next;
+#ifdef CONFIG_SBUS
+ err = happy_meal_sbus_init();
+#endif
+#ifdef CONFIG_PCI
+ if (!err) {
+ err = happy_meal_pci_init();
+#ifdef CONFIG_SBUS
+ if (err)
+ happy_meal_sbus_exit();
+#endif
}
#endif
+
+ return err;
+}
+
+
+static void __exit happy_meal_exit(void)
+{
+#ifdef CONFIG_SBUS
+ happy_meal_sbus_exit();
+#endif
+#ifdef CONFIG_PCI
+ happy_meal_pci_exit();
+#endif
}
module_init(happy_meal_probe);
-module_exit(happy_meal_cleanup_module);
+module_exit(happy_meal_exit);
diff --git a/drivers/net/sunhme.h b/drivers/net/sunhme.h
index 34e9f95..9b7ccae 100644
--- a/drivers/net/sunhme.h
+++ b/drivers/net/sunhme.h
@@ -461,7 +461,6 @@ struct happy_meal {
struct net_device *dev; /* Backpointer */
struct quattro *qfe_parent; /* For Quattro cards */
int qfe_ent; /* Which instance on quattro */
- struct happy_meal *next_module;
};
/* Here are the happy flags. */
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 6381243..2c239ab 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -266,7 +266,6 @@ struct lance_private {
char *name;
dma_addr_t init_block_dvma;
struct net_device *dev; /* Backpointer */
- struct lance_private *next_module;
struct sbus_dev *sdev;
struct timer_list multicast_timer;
};
@@ -298,8 +297,6 @@ int sparc_lance_debug = 2;
#define LANCE_ADDR(x) ((long)(x) & ~0xff000000)
-static struct lance_private *root_lance_dev;
-
/* Load the CSR registers */
static void load_csrs(struct lance_private *lp)
{
@@ -1327,9 +1324,9 @@ static struct ethtool_ops sparc_lance_ethtool_ops = {
.get_link = sparc_lance_get_link,
};
-static int __init sparc_lance_init(struct sbus_dev *sdev,
- struct sbus_dma *ledma,
- struct sbus_dev *lebuffer)
+static int __init sparc_lance_probe_one(struct sbus_dev *sdev,
+ struct sbus_dma *ledma,
+ struct sbus_dev *lebuffer)
{
static unsigned version_printed;
struct net_device *dev;
@@ -1473,6 +1470,7 @@ no_link_test:
lp->dev = dev;
SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
dev->open = &lance_open;
dev->stop = &lance_close;
dev->hard_start_xmit = &lance_start_xmit;
@@ -1500,8 +1498,7 @@ no_link_test:
goto fail;
}
- lp->next_module = root_lance_dev;
- root_lance_dev = lp;
+ dev_set_drvdata(&sdev->ofdev.dev, lp);
printk(KERN_INFO "%s: LANCE ", dev->name);
@@ -1536,88 +1533,112 @@ static inline struct sbus_dma *find_ledma(struct sbus_dev *sdev)
#include <asm/machines.h>
/* Find all the lance cards on the system and initialize them */
-static int __init sparc_lance_probe(void)
+static struct sbus_dev sun4_sdev;
+static int __init sparc_lance_init(void)
{
- static struct sbus_dev sdev;
- static int called;
-
- root_lance_dev = NULL;
-
- if (called)
- return -ENODEV;
- called++;
-
if ((idprom->id_machtype == (SM_SUN4|SM_4_330)) ||
(idprom->id_machtype == (SM_SUN4|SM_4_470))) {
- memset(&sdev, 0, sizeof(sdev));
- sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr;
- sdev.irqs[0] = 6;
- return sparc_lance_init(&sdev, NULL, NULL);
+ memset(&sun4_sdev, 0, sizeof(sdev));
+ sun4_sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr;
+ sun4_sdev.irqs[0] = 6;
+ return sparc_lance_probe_one(&sun4_sdev, NULL, NULL);
}
return -ENODEV;
}
-#else /* !CONFIG_SUN4 */
-
-/* Find all the lance cards on the system and initialize them */
-static int __init sparc_lance_probe(void)
+static int __exit sunlance_sun4_remove(void)
{
- struct sbus_bus *bus;
- struct sbus_dev *sdev = NULL;
- struct sbus_dma *ledma = NULL;
- static int called;
- int cards = 0, v;
-
- root_lance_dev = NULL;
-
- if (called)
- return -ENODEV;
- called++;
-
- for_each_sbus (bus) {
- for_each_sbusdev (sdev, bus) {
- if (strcmp(sdev->prom_name, "le") == 0) {
- cards++;
- if ((v = sparc_lance_init(sdev, NULL, NULL)))
- return v;
- continue;
- }
- if (strcmp(sdev->prom_name, "ledma") == 0) {
- cards++;
- ledma = find_ledma(sdev);
- if ((v = sparc_lance_init(sdev->child,
- ledma, NULL)))
- return v;
- continue;
- }
- if (strcmp(sdev->prom_name, "lebuffer") == 0){
- cards++;
- if ((v = sparc_lance_init(sdev->child,
- NULL, sdev)))
- return v;
- continue;
- }
- } /* for each sbusdev */
- } /* for each sbus */
- if (!cards)
- return -ENODEV;
+ struct lance_private *lp = dev_get_drvdata(&sun4_sdev->dev);
+ struct net_device *net_dev = lp->dev;
+
+ unregister_netdevice(net_dev);
+
+ lance_free_hwresources(root_lance_dev);
+
+ free_netdev(net_dev);
+
+ dev_set_drvdata(&sun4_sdev->dev, NULL);
+
return 0;
}
-#endif /* !CONFIG_SUN4 */
-static void __exit sparc_lance_cleanup(void)
+#else /* !CONFIG_SUN4 */
+
+static int __devinit sunlance_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct lance_private *lp;
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+ struct device_node *dp = dev->node;
+ int err;
+
+ if (!strcmp(dp->name, "le")) {
+ err = sparc_lance_probe_one(sdev, NULL, NULL);
+ } else if (!strcmp(dp->name, "ledma")) {
+ struct sbus_dma *ledma = find_ledma(sdev);
- while (root_lance_dev) {
- lp = root_lance_dev->next_module;
+ err = sparc_lance_probe_one(sdev->child, ledma, NULL);
+ } else {
+ BUG_ON(strcmp(dp->name, "lebuffer"));
- unregister_netdev(root_lance_dev->dev);
- lance_free_hwresources(root_lance_dev);
- free_netdev(root_lance_dev->dev);
- root_lance_dev = lp;
+ err = sparc_lance_probe_one(sdev->child, NULL, sdev);
}
+
+ return err;
+}
+
+static int __devexit sunlance_sbus_remove(struct of_device *dev)
+{
+ struct lance_private *lp = dev_get_drvdata(&dev->dev);
+ struct net_device *net_dev = lp->dev;
+
+ unregister_netdevice(net_dev);
+
+ lance_free_hwresources(lp);
+
+ free_netdev(net_dev);
+
+ dev_set_drvdata(&dev->dev, NULL);
+
+ return 0;
+}
+
+static struct of_device_id sunlance_sbus_match[] = {
+ {
+ .name = "le",
+ },
+ {
+ .name = "ledma",
+ },
+ {
+ .name = "lebuffer",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, sunlance_sbus_match);
+
+static struct of_platform_driver sunlance_sbus_driver = {
+ .name = "sunlance",
+ .match_table = sunlance_sbus_match,
+ .probe = sunlance_sbus_probe,
+ .remove = __devexit_p(sunlance_sbus_remove),
+};
+
+
+/* Find all the lance cards on the system and initialize them */
+static int __init sparc_lance_init(void)
+{
+ return of_register_driver(&sunlance_sbus_driver, &sbus_bus_type);
+}
+#endif /* !CONFIG_SUN4 */
+
+static void __exit sparc_lance_exit(void)
+{
+#ifdef CONFIG_SUN4
+ sunlance_sun4_remove();
+#else
+ of_unregister_driver(&sunlance_sbus_driver);
+#endif
}
-module_init(sparc_lance_probe);
-module_exit(sparc_lance_cleanup);
+module_init(sparc_lance_init);
+module_exit(sparc_lance_exit);
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index 1f2323b..9da6d5b 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -1,10 +1,9 @@
-/* $Id: sunqe.c,v 1.55 2002/01/15 06:48:55 davem Exp $
- * sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver.
+/* sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver.
* Once again I am out to prove that every ethernet
* controller out there can be most efficiently programmed
* if you make it look like a LANCE.
*
- * Copyright (C) 1996, 1999, 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996, 1999, 2003, 2006 David S. Miller (davem@davemloft.net)
*/
#include <linux/module.h>
@@ -41,9 +40,9 @@
#include "sunqe.h"
#define DRV_NAME "sunqe"
-#define DRV_VERSION "3.0"
-#define DRV_RELDATE "8/24/03"
-#define DRV_AUTHOR "David S. Miller (davem@redhat.com)"
+#define DRV_VERSION "4.0"
+#define DRV_RELDATE "June 23, 2006"
+#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)"
static char version[] =
DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
@@ -755,298 +754,269 @@ static inline void qec_init_once(struct sunqec *qecp, struct sbus_dev *qsdev)
qecp->gregs + GLOB_RSIZE);
}
-/* Four QE's per QEC card. */
-static int __init qec_ether_init(struct net_device *dev, struct sbus_dev *sdev)
+static u8 __init qec_get_burst(struct device_node *dp)
{
- static unsigned version_printed;
- struct net_device *qe_devs[4];
- struct sunqe *qeps[4];
- struct sbus_dev *qesdevs[4];
- struct sbus_dev *child;
- struct sunqec *qecp = NULL;
u8 bsizes, bsizes_more;
- int i, j, res = -ENOMEM;
- for (i = 0; i < 4; i++) {
- qe_devs[i] = alloc_etherdev(sizeof(struct sunqe));
- if (!qe_devs[i])
- goto out;
- }
+ /* Find and set the burst sizes for the QEC, since it
+ * does the actual dma for all 4 channels.
+ */
+ bsizes = of_getintprop_default(dp, "burst-sizes", 0xff);
+ bsizes &= 0xff;
+ bsizes_more = of_getintprop_default(dp->parent, "burst-sizes", 0xff);
- if (version_printed++ == 0)
- printk(KERN_INFO "%s", version);
+ if (bsizes_more != 0xff)
+ bsizes &= bsizes_more;
+ if (bsizes == 0xff || (bsizes & DMA_BURST16) == 0 ||
+ (bsizes & DMA_BURST32)==0)
+ bsizes = (DMA_BURST32 - 1);
- for (i = 0; i < 4; i++) {
- qeps[i] = (struct sunqe *) qe_devs[i]->priv;
- for (j = 0; j < 6; j++)
- qe_devs[i]->dev_addr[j] = idprom->id_ethaddr[j];
- qeps[i]->channel = i;
- spin_lock_init(&qeps[i]->lock);
- }
+ return bsizes;
+}
- qecp = kmalloc(sizeof(struct sunqec), GFP_KERNEL);
- if (qecp == NULL)
- goto out1;
- qecp->qec_sdev = sdev;
+static struct sunqec * __init get_qec(struct sbus_dev *child_sdev)
+{
+ struct sbus_dev *qec_sdev = child_sdev->parent;
+ struct sunqec *qecp;
- for (i = 0; i < 4; i++) {
- qecp->qes[i] = qeps[i];
- qeps[i]->dev = qe_devs[i];
- qeps[i]->parent = qecp;
+ for (qecp = root_qec_dev; qecp; qecp = qecp->next_module) {
+ if (qecp->qec_sdev == qec_sdev)
+ break;
}
+ if (!qecp) {
+ qecp = kzalloc(sizeof(struct sunqec), GFP_KERNEL);
+ if (qecp) {
+ u32 ctrl;
+
+ qecp->qec_sdev = qec_sdev;
+ qecp->gregs = sbus_ioremap(&qec_sdev->resource[0], 0,
+ GLOB_REG_SIZE,
+ "QEC Global Registers");
+ if (!qecp->gregs)
+ goto fail;
+
+ /* Make sure the QEC is in MACE mode. */
+ ctrl = sbus_readl(qecp->gregs + GLOB_CTRL);
+ ctrl &= 0xf0000000;
+ if (ctrl != GLOB_CTRL_MMODE) {
+ printk(KERN_ERR "qec: Not in MACE mode!\n");
+ goto fail;
+ }
- res = -ENODEV;
+ if (qec_global_reset(qecp->gregs))
+ goto fail;
- for (i = 0, child = sdev->child; i < 4; i++, child = child->next) {
- /* Link in channel */
- j = prom_getintdefault(child->prom_node, "channel#", -1);
- if (j == -1)
- goto out2;
- qesdevs[j] = child;
- }
+ qecp->qec_bursts = qec_get_burst(qec_sdev->ofdev.node);
- for (i = 0; i < 4; i++)
- qeps[i]->qe_sdev = qesdevs[i];
+ qec_init_once(qecp, qec_sdev);
- /* Now map in the registers, QEC globals first. */
- qecp->gregs = sbus_ioremap(&sdev->resource[0], 0,
- GLOB_REG_SIZE, "QEC Global Registers");
- if (!qecp->gregs) {
- printk(KERN_ERR "QuadEther: Cannot map QEC global registers.\n");
- goto out2;
- }
+ if (request_irq(qec_sdev->irqs[0], &qec_interrupt,
+ SA_SHIRQ, "qec", (void *) qecp)) {
+ printk(KERN_ERR "qec: Can't register irq.\n");
+ goto fail;
+ }
- /* Make sure the QEC is in MACE mode. */
- if ((sbus_readl(qecp->gregs + GLOB_CTRL) & 0xf0000000) != GLOB_CTRL_MMODE) {
- printk(KERN_ERR "QuadEther: AIEEE, QEC is not in MACE mode!\n");
- goto out3;
+ qecp->next_module = root_qec_dev;
+ root_qec_dev = qecp;
+ }
}
- /* Reset the QEC. */
- if (qec_global_reset(qecp->gregs))
- goto out3;
+ return qecp;
- /* Find and set the burst sizes for the QEC, since it does
- * the actual dma for all 4 channels.
- */
- bsizes = prom_getintdefault(sdev->prom_node, "burst-sizes", 0xff);
- bsizes &= 0xff;
- bsizes_more = prom_getintdefault(sdev->bus->prom_node, "burst-sizes", 0xff);
+fail:
+ if (qecp->gregs)
+ sbus_iounmap(qecp->gregs, GLOB_REG_SIZE);
+ kfree(qecp);
+ return NULL;
+}
- if (bsizes_more != 0xff)
- bsizes &= bsizes_more;
- if (bsizes == 0xff || (bsizes & DMA_BURST16) == 0 ||
- (bsizes & DMA_BURST32)==0)
- bsizes = (DMA_BURST32 - 1);
+static int __init qec_ether_init(struct sbus_dev *sdev)
+{
+ static unsigned version_printed;
+ struct net_device *dev;
+ struct sunqe *qe;
+ struct sunqec *qecp;
+ int i, res;
- qecp->qec_bursts = bsizes;
+ if (version_printed++ == 0)
+ printk(KERN_INFO "%s", version);
- /* Perform one time QEC initialization, we never touch the QEC
- * globals again after this.
- */
- qec_init_once(qecp, sdev);
-
- for (i = 0; i < 4; i++) {
- struct sunqe *qe = qeps[i];
- /* Map in QEC per-channel control registers. */
- qe->qcregs = sbus_ioremap(&qe->qe_sdev->resource[0], 0,
- CREG_REG_SIZE, "QEC Channel Registers");
- if (!qe->qcregs) {
- printk(KERN_ERR "QuadEther: Cannot map QE %d's channel registers.\n", i);
- goto out4;
- }
+ dev = alloc_etherdev(sizeof(struct sunqe));
+ if (!dev)
+ return -ENOMEM;
- /* Map in per-channel AMD MACE registers. */
- qe->mregs = sbus_ioremap(&qe->qe_sdev->resource[1], 0,
- MREGS_REG_SIZE, "QE MACE Registers");
- if (!qe->mregs) {
- printk(KERN_ERR "QuadEther: Cannot map QE %d's MACE registers.\n", i);
- goto out4;
- }
+ qe = netdev_priv(dev);
- qe->qe_block = sbus_alloc_consistent(qe->qe_sdev,
- PAGE_SIZE,
- &qe->qblock_dvma);
- qe->buffers = sbus_alloc_consistent(qe->qe_sdev,
- sizeof(struct sunqe_buffers),
- &qe->buffers_dvma);
- if (qe->qe_block == NULL || qe->qblock_dvma == 0 ||
- qe->buffers == NULL || qe->buffers_dvma == 0) {
- goto out4;
+ i = of_getintprop_default(sdev->ofdev.node, "channel#", -1);
+ if (i == -1) {
+ struct sbus_dev *td = sdev->parent->child;
+ i = 0;
+ while (td != sdev) {
+ td = td->next;
+ i++;
}
-
- /* Stop this QE. */
- qe_stop(qe);
}
+ qe->channel = i;
+ spin_lock_init(&qe->lock);
+
+ res = -ENODEV;
+ qecp = get_qec(sdev);
+ if (!qecp)
+ goto fail;
- for (i = 0; i < 4; i++) {
- SET_MODULE_OWNER(qe_devs[i]);
- qe_devs[i]->open = qe_open;
- qe_devs[i]->stop = qe_close;
- qe_devs[i]->hard_start_xmit = qe_start_xmit;
- qe_devs[i]->get_stats = qe_get_stats;
- qe_devs[i]->set_multicast_list = qe_set_multicast;
- qe_devs[i]->tx_timeout = qe_tx_timeout;
- qe_devs[i]->watchdog_timeo = 5*HZ;
- qe_devs[i]->irq = sdev->irqs[0];
- qe_devs[i]->dma = 0;
- qe_devs[i]->ethtool_ops = &qe_ethtool_ops;
- }
+ qecp->qes[qe->channel] = qe;
+ qe->dev = dev;
+ qe->parent = qecp;
+ qe->qe_sdev = sdev;
- /* QEC receives interrupts from each QE, then it sends the actual
- * IRQ to the cpu itself. Since QEC is the single point of
- * interrupt for all QE channels we register the IRQ handler
- * for it now.
- */
- if (request_irq(sdev->irqs[0], &qec_interrupt,
- SA_SHIRQ, "QuadEther", (void *) qecp)) {
- printk(KERN_ERR "QuadEther: Can't register QEC master irq handler.\n");
- res = -EAGAIN;
- goto out4;
+ res = -ENOMEM;
+ qe->qcregs = sbus_ioremap(&qe->qe_sdev->resource[0], 0,
+ CREG_REG_SIZE, "QEC Channel Registers");
+ if (!qe->qcregs) {
+ printk(KERN_ERR "qe: Cannot map channel registers.\n");
+ goto fail;
}
- for (i = 0; i < 4; i++) {
- if (register_netdev(qe_devs[i]) != 0)
- goto out5;
+ qe->mregs = sbus_ioremap(&qe->qe_sdev->resource[1], 0,
+ MREGS_REG_SIZE, "QE MACE Registers");
+ if (!qe->mregs) {
+ printk(KERN_ERR "qe: Cannot map MACE registers.\n");
+ goto fail;
}
- /* Report the QE channels. */
- for (i = 0; i < 4; i++) {
- printk(KERN_INFO "%s: QuadEthernet channel[%d] ", qe_devs[i]->name, i);
- for (j = 0; j < 6; j++)
- printk ("%2.2x%c",
- qe_devs[i]->dev_addr[j],
- j == 5 ? ' ': ':');
- printk("\n");
- }
+ qe->qe_block = sbus_alloc_consistent(qe->qe_sdev,
+ PAGE_SIZE,
+ &qe->qblock_dvma);
+ qe->buffers = sbus_alloc_consistent(qe->qe_sdev,
+ sizeof(struct sunqe_buffers),
+ &qe->buffers_dvma);
+ if (qe->qe_block == NULL || qe->qblock_dvma == 0 ||
+ qe->buffers == NULL || qe->buffers_dvma == 0)
+ goto fail;
+
+ /* Stop this QE. */
+ qe_stop(qe);
+
+ SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+
+ dev->open = qe_open;
+ dev->stop = qe_close;
+ dev->hard_start_xmit = qe_start_xmit;
+ dev->get_stats = qe_get_stats;
+ dev->set_multicast_list = qe_set_multicast;
+ dev->tx_timeout = qe_tx_timeout;
+ dev->watchdog_timeo = 5*HZ;
+ dev->irq = sdev->irqs[0];
+ dev->dma = 0;
+ dev->ethtool_ops = &qe_ethtool_ops;
+
+ res = register_netdev(dev);
+ if (res)
+ goto fail;
+
+ dev_set_drvdata(&sdev->ofdev.dev, qe);
+
+ printk(KERN_INFO "%s: qe channel[%d] ", dev->name, qe->channel);
+ for (i = 0; i < 6; i++)
+ printk ("%2.2x%c",
+ dev->dev_addr[i],
+ i == 5 ? ' ': ':');
+ printk("\n");
- /* We are home free at this point, link the qe's into
- * the master list for later driver exit.
- */
- qecp->next_module = root_qec_dev;
- root_qec_dev = qecp;
return 0;
-out5:
- while (i--)
- unregister_netdev(qe_devs[i]);
- free_irq(sdev->irqs[0], (void *)qecp);
-out4:
- for (i = 0; i < 4; i++) {
- struct sunqe *qe = (struct sunqe *)qe_devs[i]->priv;
-
- if (qe->qcregs)
- sbus_iounmap(qe->qcregs, CREG_REG_SIZE);
- if (qe->mregs)
- sbus_iounmap(qe->mregs, MREGS_REG_SIZE);
- if (qe->qe_block)
- sbus_free_consistent(qe->qe_sdev,
- PAGE_SIZE,
- qe->qe_block,
- qe->qblock_dvma);
- if (qe->buffers)
- sbus_free_consistent(qe->qe_sdev,
- sizeof(struct sunqe_buffers),
- qe->buffers,
- qe->buffers_dvma);
- }
-out3:
- sbus_iounmap(qecp->gregs, GLOB_REG_SIZE);
-out2:
- kfree(qecp);
-out1:
- i = 4;
-out:
- while (i--)
- free_netdev(qe_devs[i]);
+fail:
+ if (qe->qcregs)
+ sbus_iounmap(qe->qcregs, CREG_REG_SIZE);
+ if (qe->mregs)
+ sbus_iounmap(qe->mregs, MREGS_REG_SIZE);
+ if (qe->qe_block)
+ sbus_free_consistent(qe->qe_sdev,
+ PAGE_SIZE,
+ qe->qe_block,
+ qe->qblock_dvma);
+ if (qe->buffers)
+ sbus_free_consistent(qe->qe_sdev,
+ sizeof(struct sunqe_buffers),
+ qe->buffers,
+ qe->buffers_dvma);
+
+ free_netdev(dev);
+
return res;
}
-static int __init qec_match(struct sbus_dev *sdev)
+static int __devinit qec_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct sbus_dev *sibling;
- int i;
-
- if (strcmp(sdev->prom_name, "qec") != 0)
- return 0;
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
- /* QEC can be parent of either QuadEthernet or BigMAC
- * children. Do not confuse this with qfe/SUNW,qfe
- * which is a quad-happymeal card and handled by
- * a different driver.
- */
- sibling = sdev->child;
- for (i = 0; i < 4; i++) {
- if (sibling == NULL)
- return 0;
- if (strcmp(sibling->prom_name, "qe") != 0)
- return 0;
- sibling = sibling->next;
- }
- return 1;
+ return qec_ether_init(sdev);
}
-static int __init qec_probe(void)
+static int __devexit qec_sbus_remove(struct of_device *dev)
{
- struct net_device *dev = NULL;
- struct sbus_bus *bus;
- struct sbus_dev *sdev = NULL;
- static int called;
- int cards = 0, v;
-
- root_qec_dev = NULL;
-
- if (called)
- return -ENODEV;
- called++;
-
- for_each_sbus(bus) {
- for_each_sbusdev(sdev, bus) {
- if (cards)
- dev = NULL;
-
- if (qec_match(sdev)) {
- cards++;
- if ((v = qec_ether_init(dev, sdev)))
- return v;
- }
- }
- }
- if (!cards)
- return -ENODEV;
+ struct sunqe *qp = dev_get_drvdata(&dev->dev);
+ struct net_device *net_dev = qp->dev;
+
+ unregister_netdevice(net_dev);
+
+ sbus_iounmap(qp->qcregs, CREG_REG_SIZE);
+ sbus_iounmap(qp->mregs, MREGS_REG_SIZE);
+ sbus_free_consistent(qp->qe_sdev,
+ PAGE_SIZE,
+ qp->qe_block,
+ qp->qblock_dvma);
+ sbus_free_consistent(qp->qe_sdev,
+ sizeof(struct sunqe_buffers),
+ qp->buffers,
+ qp->buffers_dvma);
+
+ free_netdev(net_dev);
+
+ dev_set_drvdata(&dev->dev, NULL);
+
return 0;
}
-static void __exit qec_cleanup(void)
+static struct of_device_id qec_sbus_match[] = {
+ {
+ .name = "qe",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, qec_sbus_match);
+
+static struct of_platform_driver qec_sbus_driver = {
+ .name = "qec",
+ .match_table = qec_sbus_match,
+ .probe = qec_sbus_probe,
+ .remove = __devexit_p(qec_sbus_remove),
+};
+
+static int __init qec_init(void)
+{
+ return of_register_driver(&qec_sbus_driver, &sbus_bus_type);
+}
+
+static void __exit qec_exit(void)
{
- struct sunqec *next_qec;
- int i;
+ of_unregister_driver(&qec_sbus_driver);
while (root_qec_dev) {
- next_qec = root_qec_dev->next_module;
-
- /* Release all four QE channels, then the QEC itself. */
- for (i = 0; i < 4; i++) {
- unregister_netdev(root_qec_dev->qes[i]->dev);
- sbus_iounmap(root_qec_dev->qes[i]->qcregs, CREG_REG_SIZE);
- sbus_iounmap(root_qec_dev->qes[i]->mregs, MREGS_REG_SIZE);
- sbus_free_consistent(root_qec_dev->qes[i]->qe_sdev,
- PAGE_SIZE,
- root_qec_dev->qes[i]->qe_block,
- root_qec_dev->qes[i]->qblock_dvma);
- sbus_free_consistent(root_qec_dev->qes[i]->qe_sdev,
- sizeof(struct sunqe_buffers),
- root_qec_dev->qes[i]->buffers,
- root_qec_dev->qes[i]->buffers_dvma);
- free_netdev(root_qec_dev->qes[i]->dev);
- }
- free_irq(root_qec_dev->qec_sdev->irqs[0], (void *)root_qec_dev);
+ struct sunqec *next = root_qec_dev->next_module;
+
+ free_irq(root_qec_dev->qec_sdev->irqs[0],
+ (void *) root_qec_dev);
sbus_iounmap(root_qec_dev->gregs, GLOB_REG_SIZE);
+
kfree(root_qec_dev);
- root_qec_dev = next_qec;
+
+ root_qec_dev = next;
}
}
-module_init(qec_probe);
-module_exit(qec_cleanup);
+module_init(qec_init);
+module_exit(qec_exit);
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index b2ddd45..35f9316 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -3780,7 +3780,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
#if TG3_TSO_SUPPORT != 0
mss = 0;
if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
- (mss = skb_shinfo(skb)->tso_size) != 0) {
+ (mss = skb_shinfo(skb)->gso_size) != 0) {
int tcp_opt_len, ip_tcp_len;
if (skb_header_cloned(skb) &&
@@ -3905,7 +3905,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
#if TG3_TSO_SUPPORT != 0
mss = 0;
if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
- (mss = skb_shinfo(skb)->tso_size) != 0) {
+ (mss = skb_shinfo(skb)->gso_size) != 0) {
int tcp_opt_len, ip_tcp_len;
if (skb_header_cloned(skb) &&
@@ -10549,11 +10549,13 @@ static int __devinit tg3_get_macaddr_sparc(struct tg3 *tp)
struct pcidev_cookie *pcp = pdev->sysdata;
if (pcp != NULL) {
- int node = pcp->prom_node;
+ unsigned char *addr;
+ int len;
- if (prom_getproplen(node, "local-mac-address") == 6) {
- prom_getproperty(node, "local-mac-address",
- dev->dev_addr, 6);
+ addr = of_get_property(pcp->prom_node, "local-mac-address",
+ &len);
+ if (addr && len == 6) {
+ memcpy(dev->dev_addr, addr, 6);
memcpy(dev->perm_addr, dev->dev_addr, 6);
return 0;
}
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index 23032a7..c3cb8d2 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -217,7 +217,7 @@ static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device
dev = alloc_trdev(sizeof(struct olympic_private)) ;
if (!dev) {
i = -ENOMEM;
- goto op_free_dev;
+ goto op_release_dev;
}
olympic_priv = dev->priv ;
@@ -282,8 +282,8 @@ op_free_iomap:
if (olympic_priv->olympic_lap)
iounmap(olympic_priv->olympic_lap);
-op_free_dev:
free_netdev(dev);
+op_release_dev:
pci_release_regions(pdev);
op_disable_dev:
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index cabdf89..e0de667 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -1550,10 +1550,14 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
dev->dev_addr[i] = last_phys_addr[i];
dev->dev_addr[i] = last_phys_addr[i] + 1;
#if defined(__sparc__)
- if ((pcp != NULL) && prom_getproplen(pcp->prom_node,
- "local-mac-address") == 6) {
- prom_getproperty(pcp->prom_node, "local-mac-address",
- dev->dev_addr, 6);
+ if (pcp) {
+ unsigned char *addr;
+ int len;
+
+ addr = of_get_property(pcp->prom_node,
+ "local-mac-address", &len);
+ if (addr && len == 6)
+ memcpy(dev->dev_addr, addr, 6);
}
#endif
#if defined(__i386__) || defined(__x86_64__) /* Patch up x86 BIOS bug. */
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index a1ed2d9..6c62d5c 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -490,6 +490,9 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr)
err = -EINVAL;
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
/* Set dev type */
if (ifr->ifr_flags & IFF_TUN) {
/* TUN device */
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index d9258d4..e49e8b5 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -340,7 +340,7 @@ enum state_values {
#endif
#if defined(NETIF_F_TSO)
-#define skb_tso_size(x) (skb_shinfo(x)->tso_size)
+#define skb_tso_size(x) (skb_shinfo(x)->gso_size)
#define TSO_NUM_DESCRIPTORS 2
#define TSO_OFFLOAD_ON TYPHOON_OFFLOAD_TCP_SEGMENT
#else
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index fdc2103..c80a4f1 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -1284,11 +1284,8 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
/* Calculate the next Tx descriptor entry. */
entry = rp->cur_tx % TX_RING_SIZE;
- if (skb->len < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
- return 0;
- }
+ if (skb_padto(skb, ETH_ZLEN))
+ return 0;
rp->tx_skbuff[entry] = skb;
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 2eb6b5f..09e05fe 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -248,6 +248,7 @@ static void velocity_free_rd_ring(struct velocity_info *vptr);
static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *);
static int velocity_soft_reset(struct velocity_info *vptr);
static void mii_init(struct velocity_info *vptr, u32 mii_status);
+static u32 velocity_get_link(struct net_device *dev);
static u32 velocity_get_opt_media_mode(struct velocity_info *vptr);
static void velocity_print_link_status(struct velocity_info *vptr);
static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs);
@@ -798,6 +799,9 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
if (ret < 0)
goto err_iounmap;
+ if (velocity_get_link(dev))
+ netif_carrier_off(dev);
+
velocity_print_info(vptr);
pci_set_drvdata(pdev, dev);
@@ -1653,8 +1657,10 @@ static void velocity_error(struct velocity_info *vptr, int status)
if (linked) {
vptr->mii_status &= ~VELOCITY_LINK_FAIL;
+ netif_carrier_on(vptr->dev);
} else {
vptr->mii_status |= VELOCITY_LINK_FAIL;
+ netif_carrier_off(vptr->dev);
}
velocity_print_link_status(vptr);
diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c
index 43d854a..b60ef02 100644
--- a/drivers/net/wan/c101.c
+++ b/drivers/net/wan/c101.c
@@ -326,21 +326,21 @@ static int __init c101_run(unsigned long irq, unsigned long winbase)
if (request_irq(irq, sca_intr, 0, devname, card)) {
printk(KERN_ERR "c101: could not allocate IRQ\n");
c101_destroy_card(card);
- return(-EBUSY);
+ return -EBUSY;
}
card->irq = irq;
if (!request_mem_region(winbase, C101_MAPPED_RAM_SIZE, devname)) {
printk(KERN_ERR "c101: could not request RAM window\n");
c101_destroy_card(card);
- return(-EBUSY);
+ return -EBUSY;
}
card->phy_winbase = winbase;
card->win0base = ioremap(winbase, C101_MAPPED_RAM_SIZE);
if (!card->win0base) {
printk(KERN_ERR "c101: could not map I/O address\n");
c101_destroy_card(card);
- return -EBUSY;
+ return -EFAULT;
}
card->tx_ring_buffers = TX_RING_BUFFERS;
diff --git a/drivers/net/wan/hdlc_generic.c b/drivers/net/wan/hdlc_generic.c
index 46cef8f..57f9538 100644
--- a/drivers/net/wan/hdlc_generic.c
+++ b/drivers/net/wan/hdlc_generic.c
@@ -259,7 +259,7 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}
}
-static void hdlc_setup(struct net_device *dev)
+void hdlc_setup(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
@@ -288,26 +288,6 @@ struct net_device *alloc_hdlcdev(void *priv)
return dev;
}
-int register_hdlc_device(struct net_device *dev)
-{
- int result = dev_alloc_name(dev, "hdlc%d");
- if (result < 0)
- return result;
-
- result = register_netdev(dev);
- if (result != 0)
- return -EIO;
-
-#if 0
- if (netif_carrier_ok(dev))
- netif_carrier_off(dev); /* no carrier until DCD goes up */
-#endif
-
- return 0;
-}
-
-
-
void unregister_hdlc_device(struct net_device *dev)
{
rtnl_lock();
@@ -326,8 +306,8 @@ EXPORT_SYMBOL(hdlc_open);
EXPORT_SYMBOL(hdlc_close);
EXPORT_SYMBOL(hdlc_set_carrier);
EXPORT_SYMBOL(hdlc_ioctl);
+EXPORT_SYMBOL(hdlc_setup);
EXPORT_SYMBOL(alloc_hdlcdev);
-EXPORT_SYMBOL(register_hdlc_device);
EXPORT_SYMBOL(unregister_hdlc_device);
static struct packet_type hdlc_packet_type = {
diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c
index cd32751..b7d88db 100644
--- a/drivers/net/wan/n2.c
+++ b/drivers/net/wan/n2.c
@@ -387,6 +387,11 @@ static int __init n2_run(unsigned long io, unsigned long irq,
}
card->phy_winbase = winbase;
card->winbase = ioremap(winbase, USE_WINDOWSIZE);
+ if (!card->winbase) {
+ printk(KERN_ERR "n2: ioremap() failed\n");
+ n2_destroy_card(card);
+ return -EFAULT;
+ }
outb(0, io + N2_PCR);
outb(winbase >> 12, io + N2_BAR);
diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c
index f485a97..670e8bd 100644
--- a/drivers/net/wan/pci200syn.c
+++ b/drivers/net/wan/pci200syn.c
@@ -354,6 +354,7 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
card->rambase == NULL) {
printk(KERN_ERR "pci200syn: ioremap() failed\n");
pci200_pci_remove_one(pdev);
+ return -EFAULT;
}
/* Reset PLX */
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
index 22e7940..7628c2d 100644
--- a/drivers/net/wan/sdla.c
+++ b/drivers/net/wan/sdla.c
@@ -60,9 +60,9 @@
static const char* version = "SDLA driver v0.30, 12 Sep 1996, mike.mclagan@linux.org";
-static unsigned int valid_port[] __initdata = { 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390};
+static unsigned int valid_port[] = { 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390};
-static unsigned int valid_mem[] __initdata = {
+static unsigned int valid_mem[] = {
0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000,
0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000,
0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000,
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
index 29a756d..437e0e9 100644
--- a/drivers/net/wan/wanxl.c
+++ b/drivers/net/wan/wanxl.c
@@ -634,7 +634,13 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev,
/* set up PLX mapping */
plx_phy = pci_resource_start(pdev, 0);
+
card->plx = ioremap_nocache(plx_phy, 0x70);
+ if (!card->plx) {
+ printk(KERN_ERR "wanxl: ioremap() failed\n");
+ wanxl_pci_remove_one(pdev);
+ return -EFAULT;
+ }
#if RESET_WHILE_LOADING
wanxl_reset(card);
@@ -700,6 +706,12 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev,
}
mem = ioremap_nocache(mem_phy, PDM_OFFSET + sizeof(firmware));
+ if (!mem) {
+ printk(KERN_ERR "wanxl: ioremap() failed\n");
+ wanxl_pci_remove_one(pdev);
+ return -EFAULT;
+ }
+
for (i = 0; i < sizeof(firmware); i += 4)
writel(htonl(*(u32*)(firmware + i)), mem + PDM_OFFSET + i);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index e66fdb1..d8f917c 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -636,6 +636,17 @@ struct bcm43xx_key {
u8 algorithm;
};
+/* Driver initialization status. */
+enum {
+ BCM43xx_STAT_UNINIT, /* Uninitialized. */
+ BCM43xx_STAT_INITIALIZING, /* init_board() in progress. */
+ BCM43xx_STAT_INITIALIZED, /* Fully operational. */
+ BCM43xx_STAT_SHUTTINGDOWN, /* free_board() in progress. */
+ BCM43xx_STAT_RESTARTING, /* controller_restart() called. */
+};
+#define bcm43xx_status(bcm) atomic_read(&(bcm)->init_status)
+#define bcm43xx_set_status(bcm, stat) atomic_set(&(bcm)->init_status, (stat))
+
struct bcm43xx_private {
struct ieee80211_device *ieee;
struct ieee80211softmac_device *softmac;
@@ -646,18 +657,17 @@ struct bcm43xx_private {
void __iomem *mmio_addr;
- /* Do not use the lock directly. Use the bcm43xx_lock* helper
- * functions, to be MMIO-safe. */
- spinlock_t _lock;
+ /* Locking, see "theory of locking" text below. */
+ spinlock_t irq_lock;
+ struct mutex mutex;
- /* Driver status flags. */
- u32 initialized:1, /* init_board() succeed */
- was_initialized:1, /* for PCI suspend/resume. */
- shutting_down:1, /* free_board() in progress */
+ /* Driver initialization status BCM43xx_STAT_*** */
+ atomic_t init_status;
+
+ u16 was_initialized:1, /* for PCI suspend/resume. */
__using_pio:1, /* Internal, use bcm43xx_using_pio(). */
bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */
reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */
- powersaving:1, /* TRUE if we are in PowerSaving mode. FALSE otherwise. */
short_preamble:1, /* TRUE, if short preamble is enabled. */
firmware_norelease:1; /* Do not release the firmware. Used on suspend. */
@@ -721,7 +731,7 @@ struct bcm43xx_private {
struct tasklet_struct isr_tasklet;
/* Periodic tasks */
- struct timer_list periodic_tasks;
+ struct work_struct periodic_work;
unsigned int periodic_state;
struct work_struct restart_work;
@@ -746,21 +756,55 @@ struct bcm43xx_private {
#endif
};
-/* bcm43xx_(un)lock() protect struct bcm43xx_private.
- * Note that _NO_ MMIO writes are allowed. If you want to
- * write to the device through MMIO in the critical section, use
- * the *_mmio lock functions.
- * MMIO read-access is allowed, though.
- */
-#define bcm43xx_lock(bcm, flags) spin_lock_irqsave(&(bcm)->_lock, flags)
-#define bcm43xx_unlock(bcm, flags) spin_unlock_irqrestore(&(bcm)->_lock, flags)
-/* bcm43xx_(un)lock_mmio() protect struct bcm43xx_private and MMIO.
- * MMIO write-access to the device is allowed.
- * All MMIO writes are flushed on unlock, so it is guaranteed to not
- * interfere with other threads writing MMIO registers.
+
+/* *** THEORY OF LOCKING ***
+ *
+ * We have two different locks in the bcm43xx driver.
+ * => bcm->mutex: General sleeping mutex. Protects struct bcm43xx_private
+ * and the device registers.
+ * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency.
+ *
+ * We have three types of helper function pairs to utilize these locks.
+ * (Always use the helper functions.)
+ * 1) bcm43xx_{un}lock_noirq():
+ * Takes bcm->mutex. Does _not_ protect against IRQ concurrency,
+ * so it is almost always unsafe, if device IRQs are enabled.
+ * So only use this, if device IRQs are masked.
+ * Locking may sleep.
+ * You can sleep within the critical section.
+ * 2) bcm43xx_{un}lock_irqonly():
+ * Takes bcm->irq_lock. Does _not_ protect against
+ * bcm43xx_lock_noirq() critical sections.
+ * Does only protect against the IRQ handler path and other
+ * irqonly() critical sections.
+ * Locking does not sleep.
+ * You must not sleep within the critical section.
+ * 3) bcm43xx_{un}lock_irqsafe():
+ * This is the cummulative lock and takes both, mutex and irq_lock.
+ * Protects against noirq() and irqonly() critical sections (and
+ * the IRQ handler path).
+ * Locking may sleep.
+ * You must not sleep within the critical section.
*/
-#define bcm43xx_lock_mmio(bcm, flags) bcm43xx_lock(bcm, flags)
-#define bcm43xx_unlock_mmio(bcm, flags) do { mmiowb(); bcm43xx_unlock(bcm, flags); } while (0)
+
+/* Lock type 1 */
+#define bcm43xx_lock_noirq(bcm) mutex_lock(&(bcm)->mutex)
+#define bcm43xx_unlock_noirq(bcm) mutex_unlock(&(bcm)->mutex)
+/* Lock type 2 */
+#define bcm43xx_lock_irqonly(bcm, flags) \
+ spin_lock_irqsave(&(bcm)->irq_lock, flags)
+#define bcm43xx_unlock_irqonly(bcm, flags) \
+ spin_unlock_irqrestore(&(bcm)->irq_lock, flags)
+/* Lock type 3 */
+#define bcm43xx_lock_irqsafe(bcm, flags) do { \
+ bcm43xx_lock_noirq(bcm); \
+ bcm43xx_lock_irqonly(bcm, flags); \
+ } while (0)
+#define bcm43xx_unlock_irqsafe(bcm, flags) do { \
+ bcm43xx_unlock_irqonly(bcm, flags); \
+ bcm43xx_unlock_noirq(bcm); \
+ } while (0)
+
static inline
struct bcm43xx_private * bcm43xx_priv(struct net_device *dev)
@@ -843,16 +887,6 @@ struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm)
return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio);
}
-/* Are we running in init_board() context? */
-static inline
-int bcm43xx_is_initializing(struct bcm43xx_private *bcm)
-{
- if (bcm->initialized)
- return 0;
- if (bcm->shutting_down)
- return 0;
- return 1;
-}
static inline
struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy,
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
index 7497fb1..ce2e40b 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
@@ -77,8 +77,8 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
down(&big_buffer_sem);
- bcm43xx_lock_mmio(bcm, flags);
- if (!bcm->initialized) {
+ bcm43xx_lock_irqsafe(bcm, flags);
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
fappend("Board not initialized.\n");
goto out;
}
@@ -121,7 +121,7 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
fappend("\n");
out:
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
up(&big_buffer_sem);
return res;
@@ -159,8 +159,8 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
unsigned long flags;
down(&big_buffer_sem);
- bcm43xx_lock_mmio(bcm, flags);
- if (!bcm->initialized) {
+ bcm43xx_lock_irqsafe(bcm, flags);
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
fappend("Board not initialized.\n");
goto out;
}
@@ -169,7 +169,7 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags);
out:
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
up(&big_buffer_sem);
return res;
@@ -188,8 +188,8 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
u64 tsf;
down(&big_buffer_sem);
- bcm43xx_lock_mmio(bcm, flags);
- if (!bcm->initialized) {
+ bcm43xx_lock_irqsafe(bcm, flags);
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
fappend("Board not initialized.\n");
goto out;
}
@@ -199,7 +199,7 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
(unsigned int)(tsf & 0xFFFFFFFFULL));
out:
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
up(&big_buffer_sem);
return res;
@@ -221,8 +221,8 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
res = -EFAULT;
goto out_up;
}
- bcm43xx_lock_mmio(bcm, flags);
- if (!bcm->initialized) {
+ bcm43xx_lock_irqsafe(bcm, flags);
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
res = -EFAULT;
goto out_unlock;
@@ -233,10 +233,11 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
goto out_unlock;
}
bcm43xx_tsf_write(bcm, tsf);
+ mmiowb();
res = buf_size;
out_unlock:
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
out_up:
up(&big_buffer_sem);
return res;
@@ -257,7 +258,7 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
int i, cnt, j = 0;
down(&big_buffer_sem);
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
fappend("Last %d logged xmitstatus blobs (Latest first):\n\n",
BCM43xx_NR_LOGGED_XMITSTATUS);
@@ -293,14 +294,14 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
}
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
if (*ppos == pos) {
/* Done. Drop the copied data. */
e->xmitstatus_printing = 0;
}
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
up(&big_buffer_sem);
return res;
}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
index 4b2c02c0..ec80692 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
@@ -51,12 +51,12 @@ static void bcm43xx_led_blink(unsigned long d)
struct bcm43xx_private *bcm = led->bcm;
unsigned long flags;
- bcm43xx_lock_mmio(bcm, flags);
+ bcm43xx_lock_irqonly(bcm, flags);
if (led->blink_interval) {
bcm43xx_led_changestate(led);
mod_timer(&led->blink_timer, jiffies + led->blink_interval);
}
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqonly(bcm, flags);
}
static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 736dde9..085d785 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -498,20 +498,31 @@ static inline u32 bcm43xx_interrupt_disable(struct bcm43xx_private *bcm, u32 mas
return old_mask;
}
+/* Synchronize IRQ top- and bottom-half.
+ * IRQs must be masked before calling this.
+ * This must not be called with the irq_lock held.
+ */
+static void bcm43xx_synchronize_irq(struct bcm43xx_private *bcm)
+{
+ synchronize_irq(bcm->irq);
+ tasklet_disable(&bcm->isr_tasklet);
+}
+
/* Make sure we don't receive more data from the device. */
static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate)
{
- u32 old;
unsigned long flags;
+ u32 old;
- bcm43xx_lock_mmio(bcm, flags);
- if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) {
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_lock_irqonly(bcm, flags);
+ if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) {
+ bcm43xx_unlock_irqonly(bcm, flags);
return -EBUSY;
}
old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
- tasklet_disable(&bcm->isr_tasklet);
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqonly(bcm, flags);
+ bcm43xx_synchronize_irq(bcm);
+
if (oldstate)
*oldstate = old;
@@ -1389,7 +1400,7 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
#endif
}
- if (bcm->shutting_down) {
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_SHUTTINGDOWN) {
bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
& ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002));
@@ -1709,7 +1720,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
# define bcmirq_handled(irq) do { /* nothing */ } while (0)
#endif /* CONFIG_BCM43XX_DEBUG*/
- bcm43xx_lock_mmio(bcm, flags);
+ bcm43xx_lock_irqonly(bcm, flags);
reason = bcm->irq_reason;
dma_reason[0] = bcm->dma_reason[0];
dma_reason[1] = bcm->dma_reason[1];
@@ -1734,7 +1745,8 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
dma_reason[0], dma_reason[1],
dma_reason[2], dma_reason[3]);
bcm43xx_controller_restart(bcm, "DMA error");
- bcm43xx_unlock_mmio(bcm, flags);
+ mmiowb();
+ bcm43xx_unlock_irqonly(bcm, flags);
return;
}
if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) |
@@ -1821,7 +1833,8 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
if (!modparam_noleds)
bcm43xx_leds_update(bcm, activity);
bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
- bcm43xx_unlock_mmio(bcm, flags);
+ mmiowb();
+ bcm43xx_unlock_irqonly(bcm, flags);
}
static void pio_irq_workaround(struct bcm43xx_private *bcm,
@@ -1870,7 +1883,7 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
if (!bcm)
return IRQ_NONE;
- spin_lock(&bcm->_lock);
+ spin_lock(&bcm->irq_lock);
reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
if (reason == 0xffffffff) {
@@ -1899,7 +1912,7 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
* completely, but some careful work is needed to fix this. I think it
* is best to stay with this cheap workaround for now... .
*/
- if (likely(bcm->initialized)) {
+ if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
/* disable all IRQs. They are enabled again in the bottom half. */
bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
/* save the reason code and call our bottom half. */
@@ -1909,7 +1922,7 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
out:
mmiowb();
- spin_unlock(&bcm->_lock);
+ spin_unlock(&bcm->irq_lock);
return ret;
}
@@ -2133,6 +2146,13 @@ out:
return err;
}
+#ifdef CONFIG_BCM947XX
+static struct pci_device_id bcm43xx_47xx_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },
+ { 0 }
+};
+#endif
+
static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
{
int res;
@@ -2142,11 +2162,15 @@ static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
bcm->irq = bcm->pci_dev->irq;
#ifdef CONFIG_BCM947XX
if (bcm->pci_dev->bus->number == 0) {
- struct pci_dev *d = NULL;
- /* FIXME: we will probably need more device IDs here... */
- d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL);
- if (d != NULL) {
- bcm->irq = d->irq;
+ struct pci_dev *d;
+ struct pci_device_id *id;
+ for (id = bcm43xx_47xx_ids; id->vendor; id++) {
+ d = pci_get_device(id->vendor, id->device, NULL);
+ if (d != NULL) {
+ bcm->irq = d->irq;
+ pci_dev_put(d);
+ break;
+ }
}
}
#endif
@@ -3106,15 +3130,10 @@ static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
//TODO for APHY (temperature?)
}
-static void bcm43xx_periodic_task_handler(unsigned long d)
+static void do_periodic_work(struct bcm43xx_private *bcm)
{
- struct bcm43xx_private *bcm = (struct bcm43xx_private *)d;
- unsigned long flags;
unsigned int state;
- bcm43xx_lock_mmio(bcm, flags);
-
- assert(bcm->initialized);
state = bcm->periodic_state;
if (state % 8 == 0)
bcm43xx_periodic_every120sec(bcm);
@@ -3122,29 +3141,93 @@ static void bcm43xx_periodic_task_handler(unsigned long d)
bcm43xx_periodic_every60sec(bcm);
if (state % 2 == 0)
bcm43xx_periodic_every30sec(bcm);
- bcm43xx_periodic_every15sec(bcm);
+ if (state % 1 == 0)
+ bcm43xx_periodic_every15sec(bcm);
bcm->periodic_state = state + 1;
- mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15));
+ schedule_delayed_work(&bcm->periodic_work, HZ * 15);
+}
+
+/* Estimate a "Badness" value based on the periodic work
+ * state-machine state. "Badness" is worse (bigger), if the
+ * periodic work will take longer.
+ */
+static int estimate_periodic_work_badness(unsigned int state)
+{
+ int badness = 0;
+
+ if (state % 8 == 0) /* every 120 sec */
+ badness += 10;
+ if (state % 4 == 0) /* every 60 sec */
+ badness += 5;
+ if (state % 2 == 0) /* every 30 sec */
+ badness += 1;
+ if (state % 1 == 0) /* every 15 sec */
+ badness += 1;
- bcm43xx_unlock_mmio(bcm, flags);
+#define BADNESS_LIMIT 4
+ return badness;
+}
+
+static void bcm43xx_periodic_work_handler(void *d)
+{
+ struct bcm43xx_private *bcm = d;
+ unsigned long flags;
+ u32 savedirqs = 0;
+ int badness;
+
+ badness = estimate_periodic_work_badness(bcm->periodic_state);
+ if (badness > BADNESS_LIMIT) {
+ /* Periodic work will take a long time, so we want it to
+ * be preemtible.
+ */
+ bcm43xx_lock_irqonly(bcm, flags);
+ netif_stop_queue(bcm->net_dev);
+ if (bcm43xx_using_pio(bcm))
+ bcm43xx_pio_freeze_txqueues(bcm);
+ savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+ bcm43xx_unlock_irqonly(bcm, flags);
+ bcm43xx_lock_noirq(bcm);
+ bcm43xx_synchronize_irq(bcm);
+ } else {
+ /* Periodic work should take short time, so we want low
+ * locking overhead.
+ */
+ bcm43xx_lock_irqsafe(bcm, flags);
+ }
+
+ do_periodic_work(bcm);
+
+ if (badness > BADNESS_LIMIT) {
+ bcm43xx_lock_irqonly(bcm, flags);
+ if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
+ tasklet_enable(&bcm->isr_tasklet);
+ bcm43xx_interrupt_enable(bcm, savedirqs);
+ if (bcm43xx_using_pio(bcm))
+ bcm43xx_pio_thaw_txqueues(bcm);
+ }
+ netif_wake_queue(bcm->net_dev);
+ mmiowb();
+ bcm43xx_unlock_irqonly(bcm, flags);
+ bcm43xx_unlock_noirq(bcm);
+ } else {
+ mmiowb();
+ bcm43xx_unlock_irqsafe(bcm, flags);
+ }
}
static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
{
- del_timer_sync(&bcm->periodic_tasks);
+ cancel_rearming_delayed_work(&bcm->periodic_work);
}
static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
{
- struct timer_list *timer = &(bcm->periodic_tasks);
+ struct work_struct *work = &(bcm->periodic_work);
- assert(bcm->initialized);
- setup_timer(timer,
- bcm43xx_periodic_task_handler,
- (unsigned long)bcm);
- timer->expires = jiffies;
- add_timer(timer);
+ assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
+ INIT_WORK(work, bcm43xx_periodic_work_handler, bcm);
+ schedule_work(work);
}
static void bcm43xx_security_init(struct bcm43xx_private *bcm)
@@ -3158,16 +3241,12 @@ static void bcm43xx_security_init(struct bcm43xx_private *bcm)
static void bcm43xx_free_board(struct bcm43xx_private *bcm)
{
int i, err;
- unsigned long flags;
+ bcm43xx_lock_noirq(bcm);
bcm43xx_sysfs_unregister(bcm);
-
bcm43xx_periodic_tasks_delete(bcm);
- bcm43xx_lock(bcm, flags);
- bcm->initialized = 0;
- bcm->shutting_down = 1;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN);
for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
if (!bcm->core_80211[i].available)
@@ -3182,23 +3261,19 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm)
bcm43xx_pctl_set_crystal(bcm, 0);
- bcm43xx_lock(bcm, flags);
- bcm->shutting_down = 0;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
+ bcm43xx_unlock_noirq(bcm);
}
static int bcm43xx_init_board(struct bcm43xx_private *bcm)
{
int i, err;
int connect_phy;
- unsigned long flags;
might_sleep();
- bcm43xx_lock(bcm, flags);
- bcm->initialized = 0;
- bcm->shutting_down = 0;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_lock_noirq(bcm);
+ bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
err = bcm43xx_pctl_set_crystal(bcm, 1);
if (err)
@@ -3265,9 +3340,7 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm)
}
/* Initialization of the board is done. Flag it as such. */
- bcm43xx_lock(bcm, flags);
- bcm->initialized = 1;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
bcm43xx_periodic_tasks_setup(bcm);
bcm43xx_sysfs_register(bcm);
@@ -3278,6 +3351,8 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm)
assert(err == 0);
out:
+ bcm43xx_unlock_noirq(bcm);
+
return err;
err_80211_unwind:
@@ -3534,8 +3609,8 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
struct bcm43xx_radioinfo *radio;
unsigned long flags;
- bcm43xx_lock_mmio(bcm, flags);
- if (bcm->initialized) {
+ bcm43xx_lock_irqsafe(bcm, flags);
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
bcm43xx_mac_suspend(bcm);
bcm43xx_radio_selectchannel(bcm, channel, 0);
bcm43xx_mac_enable(bcm);
@@ -3543,7 +3618,7 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
radio = bcm43xx_current_radio(bcm);
radio->initial_channel = channel;
}
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
}
/* set_security() callback in struct ieee80211_device */
@@ -3557,7 +3632,7 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
dprintk(KERN_INFO PFX "set security called");
- bcm43xx_lock_mmio(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
if (sec->flags & (1<<keyidx)) {
@@ -3587,7 +3662,8 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
dprintk(", .encrypt = %d", sec->encrypt);
}
dprintk("\n");
- if (bcm->initialized && !bcm->ieee->host_encrypt) {
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED &&
+ !bcm->ieee->host_encrypt) {
if (secinfo->enabled) {
/* upload WEP keys to hardware */
char null_address[6] = { 0 };
@@ -3621,7 +3697,7 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
} else
bcm43xx_clear_keys(bcm);
}
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
}
/* hard_start_xmit() callback in struct ieee80211_device */
@@ -3633,10 +3709,10 @@ static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb,
int err = -ENODEV;
unsigned long flags;
- bcm43xx_lock_mmio(bcm, flags);
- if (likely(bcm->initialized))
+ bcm43xx_lock_irqonly(bcm, flags);
+ if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED))
err = bcm43xx_tx(bcm, txb);
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqonly(bcm, flags);
return err;
}
@@ -3651,9 +3727,9 @@ static void bcm43xx_net_tx_timeout(struct net_device *net_dev)
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
unsigned long flags;
- bcm43xx_lock_mmio(bcm, flags);
+ bcm43xx_lock_irqonly(bcm, flags);
bcm43xx_controller_restart(bcm, "TX timeout");
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqonly(bcm, flags);
}
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -3678,9 +3754,11 @@ static int bcm43xx_net_open(struct net_device *net_dev)
static int bcm43xx_net_stop(struct net_device *net_dev)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+ int err;
ieee80211softmac_stop(net_dev);
- bcm43xx_disable_interrupts_sync(bcm, NULL);
+ err = bcm43xx_disable_interrupts_sync(bcm, NULL);
+ assert(!err);
bcm43xx_free_board(bcm);
return 0;
@@ -3692,6 +3770,7 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm,
{
int err;
+ bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
bcm->ieee = netdev_priv(net_dev);
bcm->softmac = ieee80211_priv(net_dev);
bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
@@ -3700,7 +3779,8 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm,
bcm->pci_dev = pci_dev;
bcm->net_dev = net_dev;
bcm->bad_frames_preempt = modparam_bad_frames_preempt;
- spin_lock_init(&bcm->_lock);
+ spin_lock_init(&bcm->irq_lock);
+ mutex_init(&bcm->mutex);
tasklet_init(&bcm->isr_tasklet,
(void (*)(unsigned long))bcm43xx_interrupt_tasklet,
(unsigned long)bcm);
@@ -3831,7 +3911,7 @@ static void bcm43xx_chip_reset(void *_bcm)
struct net_device *net_dev = bcm->net_dev;
struct pci_dev *pci_dev = bcm->pci_dev;
int err;
- int was_initialized = bcm->initialized;
+ int was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
netif_stop_queue(bcm->net_dev);
tasklet_disable(&bcm->isr_tasklet);
@@ -3866,6 +3946,7 @@ failure:
*/
void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
{
+ bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING);
bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
@@ -3884,11 +3965,11 @@ static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state)
dprintk(KERN_INFO PFX "Suspending...\n");
- bcm43xx_lock(bcm, flags);
- bcm->was_initialized = bcm->initialized;
- if (bcm->initialized)
+ bcm43xx_lock_irqsafe(bcm, flags);
+ bcm->was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
+ if (bcm->was_initialized)
try_to_shutdown = 1;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
netif_device_detach(net_dev);
if (try_to_shutdown) {
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
index b0abac5..f8200de 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -1410,7 +1410,10 @@ static inline
u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control)
{
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+ u16 ret;
+ unsigned long flags;
+ local_irq_save(flags);
if (phy->connected) {
bcm43xx_phy_write(bcm, 0x15, 0xE300);
control <<= 8;
@@ -1430,8 +1433,10 @@ u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control)
bcm43xx_phy_write(bcm, 0x0015, control | 0xFFE0);
udelay(8);
}
+ ret = bcm43xx_phy_read(bcm, 0x002D);
+ local_irq_restore(flags);
- return bcm43xx_phy_read(bcm, 0x002D);
+ return ret;
}
static u32 bcm43xx_phy_lo_g_singledeviation(struct bcm43xx_private *bcm, u16 control)
@@ -1648,7 +1653,7 @@ void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm,
void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm)
{
static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 };
- const int is_initializing = bcm43xx_is_initializing(bcm);
+ const int is_initializing = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZING);
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
u16 h, i, oldi = 0, j;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
index 0aa1bd2..574085c 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
@@ -262,8 +262,10 @@ static void tx_tasklet(unsigned long d)
int err;
u16 txctl;
- bcm43xx_lock_mmio(bcm, flags);
+ bcm43xx_lock_irqonly(bcm, flags);
+ if (queue->tx_frozen)
+ goto out_unlock;
txctl = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL);
if (txctl & BCM43xx_PIO_TXCTL_SUSPEND)
goto out_unlock;
@@ -298,7 +300,7 @@ static void tx_tasklet(unsigned long d)
continue;
}
out_unlock:
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqonly(bcm, flags);
}
static void setup_txqueues(struct bcm43xx_pioqueue *queue)
@@ -374,7 +376,6 @@ static void cancel_transfers(struct bcm43xx_pioqueue *queue)
struct bcm43xx_pio_txpacket *packet, *tmp_packet;
netif_tx_disable(queue->bcm->net_dev);
- assert(queue->bcm->shutting_down);
tasklet_disable(&queue->txtask);
list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
@@ -634,5 +635,40 @@ void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue)
bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL)
& ~BCM43xx_PIO_TXCTL_SUSPEND);
bcm43xx_power_saving_ctl_bits(queue->bcm, -1, -1);
- tasklet_schedule(&queue->txtask);
+ if (!list_empty(&queue->txqueue))
+ tasklet_schedule(&queue->txtask);
+}
+
+void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm)
+{
+ struct bcm43xx_pio *pio;
+
+ assert(bcm43xx_using_pio(bcm));
+ pio = bcm43xx_current_pio(bcm);
+ pio->queue0->tx_frozen = 1;
+ pio->queue1->tx_frozen = 1;
+ pio->queue2->tx_frozen = 1;
+ pio->queue3->tx_frozen = 1;
}
+
+void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm)
+{
+ struct bcm43xx_pio *pio;
+
+ assert(bcm43xx_using_pio(bcm));
+ pio = bcm43xx_current_pio(bcm);
+ pio->queue0->tx_frozen = 0;
+ pio->queue1->tx_frozen = 0;
+ pio->queue2->tx_frozen = 0;
+ pio->queue3->tx_frozen = 0;
+ if (!list_empty(&pio->queue0->txqueue))
+ tasklet_schedule(&pio->queue0->txtask);
+ if (!list_empty(&pio->queue1->txqueue))
+ tasklet_schedule(&pio->queue1->txtask);
+ if (!list_empty(&pio->queue2->txqueue))
+ tasklet_schedule(&pio->queue2->txtask);
+ if (!list_empty(&pio->queue3->txqueue))
+ tasklet_schedule(&pio->queue3->txtask);
+}
+
+
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
index dfc7820..bc78a3c 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
@@ -54,6 +54,7 @@ struct bcm43xx_pioqueue {
u16 mmio_base;
u8 tx_suspended:1,
+ tx_frozen:1,
need_workarounds:1; /* Workarounds needed for core.rev < 3 */
/* Adjusted size of the device internal TX buffer. */
@@ -108,8 +109,12 @@ void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
struct bcm43xx_xmitstatus *status);
void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue);
+/* Suspend a TX queue on hardware level. */
void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue);
void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue);
+/* Suspend (freeze) the TX tasklet (software level). */
+void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm);
+void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm);
#else /* CONFIG_BCM43XX_PIO */
@@ -145,6 +150,14 @@ static inline
void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue)
{
}
+static inline
+void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm)
+{
+}
+static inline
+void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm)
+{
+}
#endif /* CONFIG_BCM43XX_PIO */
#endif /* BCM43xx_PIO_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
index b438f48..6a23bdc 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
@@ -120,12 +120,12 @@ static ssize_t bcm43xx_attr_sprom_show(struct device *dev,
GFP_KERNEL);
if (!sprom)
return -ENOMEM;
- bcm43xx_lock_mmio(bcm, flags);
- assert(bcm->initialized);
+ bcm43xx_lock_irqsafe(bcm, flags);
err = bcm43xx_sprom_read(bcm, sprom);
if (!err)
err = sprom2hex(sprom, buf, PAGE_SIZE);
- bcm43xx_unlock_mmio(bcm, flags);
+ mmiowb();
+ bcm43xx_unlock_irqsafe(bcm, flags);
kfree(sprom);
return err;
@@ -150,10 +150,10 @@ static ssize_t bcm43xx_attr_sprom_store(struct device *dev,
err = hex2sprom(sprom, buf, count);
if (err)
goto out_kfree;
- bcm43xx_lock_mmio(bcm, flags);
- assert(bcm->initialized);
+ bcm43xx_lock_irqsafe(bcm, flags);
err = bcm43xx_sprom_write(bcm, sprom);
- bcm43xx_unlock_mmio(bcm, flags);
+ mmiowb();
+ bcm43xx_unlock_irqsafe(bcm, flags);
out_kfree:
kfree(sprom);
@@ -170,15 +170,13 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
char *buf)
{
struct bcm43xx_private *bcm = dev_to_bcm(dev);
- unsigned long flags;
int err;
ssize_t count = 0;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- bcm43xx_lock(bcm, flags);
- assert(bcm->initialized);
+ bcm43xx_lock_noirq(bcm);
switch (bcm43xx_current_radio(bcm)->interfmode) {
case BCM43xx_RADIO_INTERFMODE_NONE:
@@ -195,7 +193,7 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
}
err = 0;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_noirq(bcm);
return err ? err : count;
@@ -231,16 +229,15 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev,
return -EINVAL;
}
- bcm43xx_lock_mmio(bcm, flags);
- assert(bcm->initialized);
+ bcm43xx_lock_irqsafe(bcm, flags);
err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
if (err) {
printk(KERN_ERR PFX "Interference Mitigation not "
"supported by device\n");
}
-
- bcm43xx_unlock_mmio(bcm, flags);
+ mmiowb();
+ bcm43xx_unlock_irqsafe(bcm, flags);
return err ? err : count;
}
@@ -254,15 +251,13 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev,
char *buf)
{
struct bcm43xx_private *bcm = dev_to_bcm(dev);
- unsigned long flags;
int err;
ssize_t count;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- bcm43xx_lock(bcm, flags);
- assert(bcm->initialized);
+ bcm43xx_lock_noirq(bcm);
if (bcm->short_preamble)
count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
@@ -270,7 +265,7 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev,
count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
err = 0;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_noirq(bcm);
return err ? err : count;
}
@@ -290,13 +285,12 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
value = get_boolean(buf, count);
if (value < 0)
return value;
- bcm43xx_lock(bcm, flags);
- assert(bcm->initialized);
+ bcm43xx_lock_irqsafe(bcm, flags);
bcm->short_preamble = !!value;
err = 0;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return err ? err : count;
}
@@ -310,7 +304,7 @@ int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
struct device *dev = &bcm->pci_dev->dev;
int err;
- assert(bcm->initialized);
+ assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
err = device_create_file(dev, &dev_attr_sprom);
if (err)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index b450639..c35cb3a 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -55,13 +55,13 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev,
char *extra)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
- unsigned long flags;
int i;
+ unsigned long flags;
struct bcm43xx_phyinfo *phy;
char suffix[7] = { 0 };
int have_a = 0, have_b = 0, have_g = 0;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
for (i = 0; i < bcm->nr_80211_available; i++) {
phy = &(bcm->core_80211_ext[i].phy);
switch (phy->type) {
@@ -77,7 +77,7 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev,
assert(0);
}
}
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
i = 0;
if (have_a) {
@@ -111,7 +111,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
int freq;
int err = -EINVAL;
- bcm43xx_lock_mmio(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
channel = data->freq.m;
freq = bcm43xx_channel_to_freq(bcm, channel);
@@ -121,7 +121,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
}
if (!bcm43xx_is_valid_channel(bcm, channel))
goto out_unlock;
- if (bcm->initialized) {
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
//ieee80211softmac_disassoc(softmac, $REASON);
bcm43xx_mac_suspend(bcm);
err = bcm43xx_radio_selectchannel(bcm, channel, 0);
@@ -131,7 +131,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
err = 0;
}
out_unlock:
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return err;
}
@@ -147,11 +147,10 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
int err = -ENODEV;
u16 channel;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
radio = bcm43xx_current_radio(bcm);
channel = radio->channel;
if (channel == 0xFF) {
- assert(!bcm->initialized);
channel = radio->initial_channel;
if (channel == 0xFF)
goto out_unlock;
@@ -163,7 +162,7 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
err = 0;
out_unlock:
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return err;
}
@@ -181,13 +180,13 @@ static int bcm43xx_wx_set_mode(struct net_device *net_dev,
if (mode == IW_MODE_AUTO)
mode = BCM43xx_INITIAL_IWMODE;
- bcm43xx_lock_mmio(bcm, flags);
- if (bcm->initialized) {
+ bcm43xx_lock_irqsafe(bcm, flags);
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
if (bcm->ieee->iw_mode != mode)
bcm43xx_set_iwmode(bcm, mode);
} else
bcm->ieee->iw_mode = mode;
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return 0;
}
@@ -200,9 +199,9 @@ static int bcm43xx_wx_get_mode(struct net_device *net_dev,
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
unsigned long flags;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
data->mode = bcm->ieee->iw_mode;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return 0;
}
@@ -255,7 +254,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
IW_ENC_CAPA_CIPHER_TKIP |
IW_ENC_CAPA_CIPHER_CCMP;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
phy = bcm43xx_current_phy(bcm);
range->num_bitrates = 0;
@@ -302,7 +301,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
}
range->num_frequency = j;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return 0;
}
@@ -313,14 +312,13 @@ static int bcm43xx_wx_set_nick(struct net_device *net_dev,
char *extra)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
- unsigned long flags;
size_t len;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_noirq(bcm);
len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
memcpy(bcm->nick, extra, len);
bcm->nick[len] = '\0';
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_noirq(bcm);
return 0;
}
@@ -331,15 +329,14 @@ static int bcm43xx_wx_get_nick(struct net_device *net_dev,
char *extra)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
- unsigned long flags;
size_t len;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_noirq(bcm);
len = strlen(bcm->nick) + 1;
memcpy(extra, bcm->nick, len);
data->data.length = (__u16)len;
data->data.flags = 1;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_noirq(bcm);
return 0;
}
@@ -353,7 +350,7 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev,
unsigned long flags;
int err = -EINVAL;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
if (data->rts.disabled) {
bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
err = 0;
@@ -364,7 +361,7 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev,
err = 0;
}
}
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return err;
}
@@ -377,11 +374,11 @@ static int bcm43xx_wx_get_rts(struct net_device *net_dev,
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
unsigned long flags;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
data->rts.value = bcm->rts_threshold;
data->rts.fixed = 0;
data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return 0;
}
@@ -395,7 +392,7 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev,
unsigned long flags;
int err = -EINVAL;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
if (data->frag.disabled) {
bcm->ieee->fts = MAX_FRAG_THRESHOLD;
err = 0;
@@ -406,7 +403,7 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev,
err = 0;
}
}
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return err;
}
@@ -419,11 +416,11 @@ static int bcm43xx_wx_get_frag(struct net_device *net_dev,
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
unsigned long flags;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
data->frag.value = bcm->ieee->fts;
data->frag.fixed = 0;
data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return 0;
}
@@ -445,8 +442,8 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
return -EOPNOTSUPP;
}
- bcm43xx_lock_mmio(bcm, flags);
- if (!bcm->initialized)
+ bcm43xx_lock_irqsafe(bcm, flags);
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
goto out_unlock;
radio = bcm43xx_current_radio(bcm);
phy = bcm43xx_current_phy(bcm);
@@ -469,7 +466,7 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
err = 0;
out_unlock:
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return err;
}
@@ -484,8 +481,8 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
unsigned long flags;
int err = -ENODEV;
- bcm43xx_lock(bcm, flags);
- if (!bcm->initialized)
+ bcm43xx_lock_irqsafe(bcm, flags);
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
goto out_unlock;
radio = bcm43xx_current_radio(bcm);
/* desired dBm value is in Q5.2 */
@@ -496,7 +493,7 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
err = 0;
out_unlock:
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return err;
}
@@ -583,8 +580,8 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
return -EINVAL;
}
- bcm43xx_lock_mmio(bcm, flags);
- if (bcm->initialized) {
+ bcm43xx_lock_irqsafe(bcm, flags);
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
if (err) {
printk(KERN_ERR PFX "Interference Mitigation not "
@@ -598,7 +595,7 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
} else
bcm43xx_current_radio(bcm)->interfmode = mode;
}
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return err;
}
@@ -612,9 +609,9 @@ static int bcm43xx_wx_get_interfmode(struct net_device *net_dev,
unsigned long flags;
int mode;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
mode = bcm43xx_current_radio(bcm)->interfmode;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
switch (mode) {
case BCM43xx_RADIO_INTERFMODE_NONE:
@@ -644,9 +641,9 @@ static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev,
int on;
on = *((int *)extra);
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
bcm->short_preamble = !!on;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return 0;
}
@@ -660,9 +657,9 @@ static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev,
unsigned long flags;
int on;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
on = bcm->short_preamble;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
if (on)
strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
@@ -684,11 +681,11 @@ static int bcm43xx_wx_set_swencryption(struct net_device *net_dev,
on = *((int *)extra);
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
bcm->ieee->host_encrypt = !!on;
bcm->ieee->host_decrypt = !!on;
bcm->ieee->host_build_iv = !on;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return 0;
}
@@ -702,9 +699,9 @@ static int bcm43xx_wx_get_swencryption(struct net_device *net_dev,
unsigned long flags;
int on;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
on = bcm->ieee->host_encrypt;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
if (on)
strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
@@ -767,11 +764,11 @@ static int bcm43xx_wx_sprom_read(struct net_device *net_dev,
if (!sprom)
goto out;
- bcm43xx_lock_mmio(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
err = -ENODEV;
- if (bcm->initialized)
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
err = bcm43xx_sprom_read(bcm, sprom);
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
if (!err)
data->data.length = sprom2hex(sprom, extra);
kfree(sprom);
@@ -812,11 +809,11 @@ static int bcm43xx_wx_sprom_write(struct net_device *net_dev,
if (err)
goto out_kfree;
- bcm43xx_lock_mmio(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
err = -ENODEV;
- if (bcm->initialized)
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
err = bcm43xx_sprom_write(bcm, sprom);
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
out_kfree:
kfree(sprom);
out:
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 39f82f2..081a899 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -533,7 +533,7 @@ static inline void ipw_clear_bit(struct ipw_priv *priv, u32 reg, u32 mask)
ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask);
}
-static inline void ipw_enable_interrupts(struct ipw_priv *priv)
+static inline void __ipw_enable_interrupts(struct ipw_priv *priv)
{
if (priv->status & STATUS_INT_ENABLED)
return;
@@ -541,7 +541,7 @@ static inline void ipw_enable_interrupts(struct ipw_priv *priv)
ipw_write32(priv, IPW_INTA_MASK_R, IPW_INTA_MASK_ALL);
}
-static inline void ipw_disable_interrupts(struct ipw_priv *priv)
+static inline void __ipw_disable_interrupts(struct ipw_priv *priv)
{
if (!(priv->status & STATUS_INT_ENABLED))
return;
@@ -549,6 +549,24 @@ static inline void ipw_disable_interrupts(struct ipw_priv *priv)
ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);
}
+static inline void ipw_enable_interrupts(struct ipw_priv *priv)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->irq_lock, flags);
+ __ipw_enable_interrupts(priv);
+ spin_unlock_irqrestore(&priv->irq_lock, flags);
+}
+
+static inline void ipw_disable_interrupts(struct ipw_priv *priv)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->irq_lock, flags);
+ __ipw_disable_interrupts(priv);
+ spin_unlock_irqrestore(&priv->irq_lock, flags);
+}
+
#ifdef CONFIG_IPW2200_DEBUG
static char *ipw_error_desc(u32 val)
{
@@ -1856,7 +1874,7 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
unsigned long flags;
int rc = 0;
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&priv->irq_lock, flags);
inta = ipw_read32(priv, IPW_INTA_RW);
inta_mask = ipw_read32(priv, IPW_INTA_MASK_R);
@@ -1865,6 +1883,10 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
/* Add any cached INTA values that need to be handled */
inta |= priv->isr_inta;
+ spin_unlock_irqrestore(&priv->irq_lock, flags);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
/* handle all the justifications for the interrupt */
if (inta & IPW_INTA_BIT_RX_TRANSFER) {
ipw_rx(priv);
@@ -1993,10 +2015,10 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
IPW_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled);
}
+ spin_unlock_irqrestore(&priv->lock, flags);
+
/* enable all interrupts */
ipw_enable_interrupts(priv);
-
- spin_unlock_irqrestore(&priv->lock, flags);
}
#define IPW_CMD(x) case IPW_CMD_ ## x : return #x
@@ -10460,7 +10482,7 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs)
if (!priv)
return IRQ_NONE;
- spin_lock(&priv->lock);
+ spin_lock(&priv->irq_lock);
if (!(priv->status & STATUS_INT_ENABLED)) {
/* Shared IRQ */
@@ -10482,7 +10504,7 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs)
}
/* tell the device to stop sending interrupts */
- ipw_disable_interrupts(priv);
+ __ipw_disable_interrupts(priv);
/* ack current interrupts */
inta &= (IPW_INTA_MASK_ALL & inta_mask);
@@ -10493,11 +10515,11 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs)
tasklet_schedule(&priv->irq_tasklet);
- spin_unlock(&priv->lock);
+ spin_unlock(&priv->irq_lock);
return IRQ_HANDLED;
none:
- spin_unlock(&priv->lock);
+ spin_unlock(&priv->irq_lock);
return IRQ_NONE;
}
@@ -11477,6 +11499,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
#ifdef CONFIG_IPW2200_DEBUG
ipw_debug_level = debug;
#endif
+ spin_lock_init(&priv->irq_lock);
spin_lock_init(&priv->lock);
for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++)
INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h
index 6044c0b..ea12ad6 100644
--- a/drivers/net/wireless/ipw2200.h
+++ b/drivers/net/wireless/ipw2200.h
@@ -1173,6 +1173,7 @@ struct ipw_priv {
struct ieee80211_device *ieee;
spinlock_t lock;
+ spinlock_t irq_lock;
struct mutex mutex;
/* basic pci-network driver stuff */
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 879eb42..a915fe6 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -924,8 +924,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN)
{
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index dade4b9..5b69befd 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -1695,8 +1695,8 @@ static int wv_frequency_list(unsigned long ioaddr, /* I/O port of the card */
/* Look in the table if the frequency is allowed */
if (table[9 - (freq / 16)] & (1 << (freq % 16))) {
/* Compute approximate channel number */
- while ((((channel_bands[c] >> 1) - 24) < freq) &&
- (c < NELS(channel_bands)))
+ while ((c < NELS(channel_bands)) &&
+ (((channel_bands[c] >> 1) - 24) < freq))
c++;
list[i].i = c; /* Set the list index */
@@ -2903,6 +2903,7 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev)
{
net_local *lp = (net_local *) dev->priv;
unsigned long flags;
+ char data[ETH_ZLEN];
#ifdef DEBUG_TX_TRACE
printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
@@ -2937,15 +2938,16 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev)
* able to detect collisions, therefore in theory we don't really
* need to pad. Jean II */
if (skb->len < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
- return 0;
+ memset(data, 0, ETH_ZLEN);
+ memcpy(data, skb->data, skb->len);
+ /* Write packet on the card */
+ if(wv_packet_write(dev, data, ETH_ZLEN))
+ return 1; /* We failed */
}
-
- /* Write packet on the card */
- if(wv_packet_write(dev, skb->data, skb->len))
+ else if(wv_packet_write(dev, skb->data, skb->len))
return 1; /* We failed */
+
dev_kfree_skb(skb);
#ifdef DEBUG_TX_TRACE
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index f7724eb..561250f 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -3194,11 +3194,8 @@ wavelan_packet_xmit(struct sk_buff * skb,
* and we don't have the Ethernet specific requirement of beeing
* able to detect collisions, therefore in theory we don't really
* need to pad. Jean II */
- if (skb->len < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
- return 0;
- }
+ if (skb_padto(skb, ETH_ZLEN))
+ return 0;
wv_packet_write(dev, skb->data, skb->len);
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index fd0f43b..ecec8e5 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -862,13 +862,11 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Fix GX chipset errata. */
if (cacheline_end > 24 || cacheline_end == 0) {
len = skb->len + 32 - cacheline_end + 1;
- if (len != skb->len)
- skb = skb_padto(skb, len);
- }
- if (skb == NULL) {
- yp->tx_skbuff[entry] = NULL;
- netif_wake_queue(dev);
- return 0;
+ if (skb_padto(skb, len)) {
+ yp->tx_skbuff[entry] = NULL;
+ netif_wake_queue(dev);
+ return 0;
+ }
}
}
yp->tx_skbuff[entry] = skb;
diff --git a/drivers/net/znet.c b/drivers/net/znet.c
index 3ac047b..a7c089d 100644
--- a/drivers/net/znet.c
+++ b/drivers/net/znet.c
@@ -544,8 +544,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: ZNet_send_packet.\n", dev->name);
if (length < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index b2e8e49..43e521e 100644
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -108,10 +108,10 @@ static int module_load_notify(struct notifier_block * self, unsigned long val, v
return 0;
/* FIXME: should we process all CPU buffers ? */
- down(&buffer_sem);
+ mutex_lock(&buffer_mutex);
add_event_entry(ESCAPE_CODE);
add_event_entry(MODULE_LOADED_CODE);
- up(&buffer_sem);
+ mutex_unlock(&buffer_mutex);
#endif
return 0;
}
@@ -501,7 +501,7 @@ void sync_buffer(int cpu)
sync_buffer_state state = sb_buffer_start;
unsigned long available;
- down(&buffer_sem);
+ mutex_lock(&buffer_mutex);
add_cpu_switch(cpu);
@@ -550,5 +550,5 @@ void sync_buffer(int cpu)
mark_done(cpu);
- up(&buffer_sem);
+ mutex_unlock(&buffer_mutex);
}
diff --git a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c
index b80318f..04d6417 100644
--- a/drivers/oprofile/event_buffer.c
+++ b/drivers/oprofile/event_buffer.c
@@ -24,7 +24,7 @@
#include "event_buffer.h"
#include "oprofile_stats.h"
-DECLARE_MUTEX(buffer_sem);
+DEFINE_MUTEX(buffer_mutex);
static unsigned long buffer_opened;
static DECLARE_WAIT_QUEUE_HEAD(buffer_wait);
@@ -32,7 +32,7 @@ static unsigned long * event_buffer;
static unsigned long buffer_size;
static unsigned long buffer_watershed;
static size_t buffer_pos;
-/* atomic_t because wait_event checks it outside of buffer_sem */
+/* atomic_t because wait_event checks it outside of buffer_mutex */
static atomic_t buffer_ready = ATOMIC_INIT(0);
/* Add an entry to the event buffer. When we
@@ -60,10 +60,10 @@ void add_event_entry(unsigned long value)
*/
void wake_up_buffer_waiter(void)
{
- down(&buffer_sem);
+ mutex_lock(&buffer_mutex);
atomic_set(&buffer_ready, 1);
wake_up(&buffer_wait);
- up(&buffer_sem);
+ mutex_unlock(&buffer_mutex);
}
@@ -162,7 +162,7 @@ static ssize_t event_buffer_read(struct file * file, char __user * buf,
if (!atomic_read(&buffer_ready))
return -EAGAIN;
- down(&buffer_sem);
+ mutex_lock(&buffer_mutex);
atomic_set(&buffer_ready, 0);
@@ -177,7 +177,7 @@ static ssize_t event_buffer_read(struct file * file, char __user * buf,
buffer_pos = 0;
out:
- up(&buffer_sem);
+ mutex_unlock(&buffer_mutex);
return retval;
}
diff --git a/drivers/oprofile/event_buffer.h b/drivers/oprofile/event_buffer.h
index 0180236..9241627 100644
--- a/drivers/oprofile/event_buffer.h
+++ b/drivers/oprofile/event_buffer.h
@@ -11,7 +11,7 @@
#define EVENT_BUFFER_H
#include <linux/types.h>
-#include <asm/semaphore.h>
+#include <asm/mutex.h>
int alloc_event_buffer(void);
@@ -46,6 +46,6 @@ extern struct file_operations event_buffer_fops;
/* mutex between sync_cpu_buffers() and the
* file reading code.
*/
-extern struct semaphore buffer_sem;
+extern struct mutex buffer_mutex;
#endif /* EVENT_BUFFER_H */
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c
index b3f1cd6..e5162a6 100644
--- a/drivers/oprofile/oprof.c
+++ b/drivers/oprofile/oprof.c
@@ -12,7 +12,7 @@
#include <linux/init.h>
#include <linux/oprofile.h>
#include <linux/moduleparam.h>
-#include <asm/semaphore.h>
+#include <asm/mutex.h>
#include "oprof.h"
#include "event_buffer.h"
@@ -25,7 +25,7 @@ struct oprofile_operations oprofile_ops;
unsigned long oprofile_started;
unsigned long backtrace_depth;
static unsigned long is_setup;
-static DECLARE_MUTEX(start_sem);
+static DEFINE_MUTEX(start_mutex);
/* timer
0 - use performance monitoring hardware if available
@@ -37,7 +37,7 @@ int oprofile_setup(void)
{
int err;
- down(&start_sem);
+ mutex_lock(&start_mutex);
if ((err = alloc_cpu_buffers()))
goto out;
@@ -57,7 +57,7 @@ int oprofile_setup(void)
goto out3;
is_setup = 1;
- up(&start_sem);
+ mutex_unlock(&start_mutex);
return 0;
out3:
@@ -68,7 +68,7 @@ out2:
out1:
free_cpu_buffers();
out:
- up(&start_sem);
+ mutex_unlock(&start_mutex);
return err;
}
@@ -78,7 +78,7 @@ int oprofile_start(void)
{
int err = -EINVAL;
- down(&start_sem);
+ mutex_lock(&start_mutex);
if (!is_setup)
goto out;
@@ -95,7 +95,7 @@ int oprofile_start(void)
oprofile_started = 1;
out:
- up(&start_sem);
+ mutex_unlock(&start_mutex);
return err;
}
@@ -103,7 +103,7 @@ out:
/* echo 0>/dev/oprofile/enable */
void oprofile_stop(void)
{
- down(&start_sem);
+ mutex_lock(&start_mutex);
if (!oprofile_started)
goto out;
oprofile_ops.stop();
@@ -111,20 +111,20 @@ void oprofile_stop(void)
/* wake up the daemon to read what remains */
wake_up_buffer_waiter();
out:
- up(&start_sem);
+ mutex_unlock(&start_mutex);
}
void oprofile_shutdown(void)
{
- down(&start_sem);
+ mutex_lock(&start_mutex);
sync_stop();
if (oprofile_ops.shutdown)
oprofile_ops.shutdown();
is_setup = 0;
free_event_buffer();
free_cpu_buffers();
- up(&start_sem);
+ mutex_unlock(&start_mutex);
}
@@ -132,7 +132,7 @@ int oprofile_set_backtrace(unsigned long val)
{
int err = 0;
- down(&start_sem);
+ mutex_lock(&start_mutex);
if (oprofile_started) {
err = -EBUSY;
@@ -147,7 +147,7 @@ int oprofile_set_backtrace(unsigned long val)
backtrace_depth = val;
out:
- up(&start_sem);
+ mutex_unlock(&start_mutex);
return err;
}
diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c
index b62da9b..71c2da2 100644
--- a/drivers/oprofile/oprofilefs.c
+++ b/drivers/oprofile/oprofilefs.c
@@ -272,10 +272,10 @@ static int oprofilefs_fill_super(struct super_block * sb, void * data, int silen
}
-static struct super_block *oprofilefs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int oprofilefs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, oprofilefs_fill_super);
+ return get_sb_single(fs_type, flags, data, oprofilefs_fill_super, mnt);
}
diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig
index 6c8452e..c7fa28a 100644
--- a/drivers/parport/Kconfig
+++ b/drivers/parport/Kconfig
@@ -85,11 +85,6 @@ config PARPORT_PC_PCMCIA
config PARPORT_NOT_PC
bool
-config PARPORT_ARC
- tristate "Archimedes hardware"
- depends on ARM && PARPORT
- select PARPORT_NOT_PC
-
config PARPORT_IP32
tristate "SGI IP32 builtin port (EXPERIMENTAL)"
depends on SGI_IP32 && PARPORT && EXPERIMENTAL
@@ -141,6 +136,18 @@ config PARPORT_SUNBPP
found on many Sun machines. Note that many of the newer Ultras
actually have pc style hardware instead.
+config PARPORT_AX88796
+ tristate "AX88796 Parallel Port"
+ depends on PARPORT
+ select PARPORT_NOT_PC
+ help
+ Say Y here if you need support for the parallel port hardware on
+ the AX88796 network controller chip. This code is also available
+ as a module (say M), called parport_ax88796.
+
+ The driver is not dependant on the AX88796 network driver, and
+ should not interfere with the networking functions of the chip.
+
config PARPORT_1284
bool "IEEE 1284 transfer modes"
depends on PARPORT
diff --git a/drivers/parport/Makefile b/drivers/parport/Makefile
index a19de35..696b8d4 100644
--- a/drivers/parport/Makefile
+++ b/drivers/parport/Makefile
@@ -17,4 +17,5 @@ obj-$(CONFIG_PARPORT_MFC3) += parport_mfc3.o
obj-$(CONFIG_PARPORT_ATARI) += parport_atari.o
obj-$(CONFIG_PARPORT_SUNBPP) += parport_sunbpp.o
obj-$(CONFIG_PARPORT_GSC) += parport_gsc.o
-obj-$(CONFIG_PARPORT_IP32) += parport_ip32.o
+obj-$(CONFIG_PARPORT_AX88796) += parport_ax88796.o
+obj-$(CONFIG_PARPORT_IP32) += parport_ip32.o \ No newline at end of file
diff --git a/drivers/parport/daisy.c b/drivers/parport/daisy.c
index 9ee6732..fd41e28 100644
--- a/drivers/parport/daisy.c
+++ b/drivers/parport/daisy.c
@@ -283,7 +283,7 @@ void parport_close (struct pardevice *dev)
*
* This tries to locate a device on the given parallel port,
* multiplexor port and daisy chain address, and returns its
- * device number or -NXIO if no device with those coordinates
+ * device number or %-ENXIO if no device with those coordinates
* exists.
**/
diff --git a/drivers/parport/parport_arc.c b/drivers/parport/parport_arc.c
deleted file mode 100644
index b35bb4f..0000000
--- a/drivers/parport/parport_arc.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/* Low-level parallel port routines for Archimedes onboard hardware
- *
- * Author: Phil Blundell <philb@gnu.org>
- */
-
-/* This driver is for the parallel port hardware found on Acorn's old
- * range of Archimedes machines. The A5000 and newer systems have PC-style
- * I/O hardware and should use the parport_pc driver instead.
- *
- * The Acorn printer port hardware is very simple. There is a single 8-bit
- * write-only latch for the data port and control/status bits are handled
- * with various auxilliary input and output lines. The port is not
- * bidirectional, does not support any modes other than SPP, and has only
- * a subset of the standard printer control lines connected.
- */
-
-#include <linux/threads.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/parport.h>
-
-#include <asm/ptrace.h>
-#include <asm/io.h>
-#include <asm/arch/oldlatches.h>
-#include <asm/arch/irqs.h>
-
-#define DATA_ADDRESS 0x3350010
-
-/* This is equivalent to the above and only used for request_region. */
-#define PORT_BASE 0x80000000 | ((DATA_ADDRESS - IO_BASE) >> 2)
-
-/* The hardware can't read from the data latch, so we must use a soft
- copy. */
-static unsigned char data_copy;
-
-/* These are pretty simple. We know the irq is never shared and the
- kernel does all the magic that's required. */
-static void arc_enable_irq(struct parport *p)
-{
- enable_irq(p->irq);
-}
-
-static void arc_disable_irq(struct parport *p)
-{
- disable_irq(p->irq);
-}
-
-static void arc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- parport_generic_irq(irq, (struct parport *) dev_id, regs);
-}
-
-static void arc_write_data(struct parport *p, unsigned char data)
-{
- data_copy = data;
- outb_t(data, DATA_LATCH);
-}
-
-static unsigned char arc_read_data(struct parport *p)
-{
- return data_copy;
-}
-
-static struct parport_operations parport_arc_ops =
-{
- .write_data = arc_write_data,
- .read_data = arc_read_data,
-
- .write_control = arc_write_control,
- .read_control = arc_read_control,
- .frob_control = arc_frob_control,
-
- .read_status = arc_read_status,
-
- .enable_irq = arc_enable_irq,
- .disable_irq = arc_disable_irq,
-
- .data_forward = arc_data_forward,
- .data_reverse = arc_data_reverse,
-
- .init_state = arc_init_state,
- .save_state = arc_save_state,
- .restore_state = arc_restore_state,
-
- .epp_write_data = parport_ieee1284_epp_write_data,
- .epp_read_data = parport_ieee1284_epp_read_data,
- .epp_write_addr = parport_ieee1284_epp_write_addr,
- .epp_read_addr = parport_ieee1284_epp_read_addr,
-
- .ecp_write_data = parport_ieee1284_ecp_write_data,
- .ecp_read_data = parport_ieee1284_ecp_read_data,
- .ecp_write_addr = parport_ieee1284_ecp_write_addr,
-
- .compat_write_data = parport_ieee1284_write_compat,
- .nibble_read_data = parport_ieee1284_read_nibble,
- .byte_read_data = parport_ieee1284_read_byte,
-
- .owner = THIS_MODULE,
-};
-
-/* --- Initialisation code -------------------------------- */
-
-static int parport_arc_init(void)
-{
- /* Archimedes hardware provides only one port, at a fixed address */
- struct parport *p;
- struct resource res;
- char *fake_name = "parport probe");
-
- res = request_region(PORT_BASE, 1, fake_name);
- if (res == NULL)
- return 0;
-
- p = parport_register_port (PORT_BASE, IRQ_PRINTERACK,
- PARPORT_DMA_NONE, &parport_arc_ops);
-
- if (!p) {
- release_region(PORT_BASE, 1);
- return 0;
- }
-
- p->modes = PARPORT_MODE_ARCSPP;
- p->size = 1;
- rename_region(res, p->name);
-
- printk(KERN_INFO "%s: Archimedes on-board port, using irq %d\n",
- p->irq);
-
- /* Tell the high-level drivers about the port. */
- parport_announce_port (p);
-
- return 1;
-}
-
-module_init(parport_arc_init)
diff --git a/drivers/parport/parport_ax88796.c b/drivers/parport/parport_ax88796.c
new file mode 100644
index 0000000..4baa719
--- /dev/null
+++ b/drivers/parport/parport_ax88796.c
@@ -0,0 +1,443 @@
+/* linux/drivers/parport/parport_ax88796.c
+ *
+ * (c) 2005,2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/parport.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#define AX_SPR_BUSY (1<<7)
+#define AX_SPR_ACK (1<<6)
+#define AX_SPR_PE (1<<5)
+#define AX_SPR_SLCT (1<<4)
+#define AX_SPR_ERR (1<<3)
+
+#define AX_CPR_nDOE (1<<5)
+#define AX_CPR_SLCTIN (1<<3)
+#define AX_CPR_nINIT (1<<2)
+#define AX_CPR_ATFD (1<<1)
+#define AX_CPR_STRB (1<<0)
+
+struct ax_drvdata {
+ struct parport *parport;
+ struct parport_state suspend;
+
+ struct device *dev;
+ struct resource *io;
+
+ unsigned char irq_enabled;
+
+ void __iomem *base;
+ void __iomem *spp_data;
+ void __iomem *spp_spr;
+ void __iomem *spp_cpr;
+};
+
+static inline struct ax_drvdata *pp_to_drv(struct parport *p)
+{
+ return p->private_data;
+}
+
+static unsigned char
+parport_ax88796_read_data(struct parport *p)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+
+ return readb(dd->spp_data);
+}
+
+static void
+parport_ax88796_write_data(struct parport *p, unsigned char data)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+
+ writeb(data, dd->spp_data);
+}
+
+static unsigned char
+parport_ax88796_read_control(struct parport *p)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+ unsigned int cpr = readb(dd->spp_cpr);
+ unsigned int ret = 0;
+
+ if (!(cpr & AX_CPR_STRB))
+ ret |= PARPORT_CONTROL_STROBE;
+
+ if (!(cpr & AX_CPR_ATFD))
+ ret |= PARPORT_CONTROL_AUTOFD;
+
+ if (cpr & AX_CPR_nINIT)
+ ret |= PARPORT_CONTROL_INIT;
+
+ if (!(cpr & AX_CPR_SLCTIN))
+ ret |= PARPORT_CONTROL_SELECT;
+
+ return ret;
+}
+
+static void
+parport_ax88796_write_control(struct parport *p, unsigned char control)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+ unsigned int cpr = readb(dd->spp_cpr);
+
+ cpr &= AX_CPR_nDOE;
+
+ if (!(control & PARPORT_CONTROL_STROBE))
+ cpr |= AX_CPR_STRB;
+
+ if (!(control & PARPORT_CONTROL_AUTOFD))
+ cpr |= AX_CPR_ATFD;
+
+ if (control & PARPORT_CONTROL_INIT)
+ cpr |= AX_CPR_nINIT;
+
+ if (!(control & PARPORT_CONTROL_SELECT))
+ cpr |= AX_CPR_SLCTIN;
+
+ dev_dbg(dd->dev, "write_control: ctrl=%02x, cpr=%02x\n", control, cpr);
+ writeb(cpr, dd->spp_cpr);
+
+ if (parport_ax88796_read_control(p) != control) {
+ dev_err(dd->dev, "write_control: read != set (%02x, %02x)\n",
+ parport_ax88796_read_control(p), control);
+ }
+}
+
+static unsigned char
+parport_ax88796_read_status(struct parport *p)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+ unsigned int status = readb(dd->spp_spr);
+ unsigned int ret = 0;
+
+ if (status & AX_SPR_BUSY)
+ ret |= PARPORT_STATUS_BUSY;
+
+ if (status & AX_SPR_ACK)
+ ret |= PARPORT_STATUS_ACK;
+
+ if (status & AX_SPR_ERR)
+ ret |= PARPORT_STATUS_ERROR;
+
+ if (status & AX_SPR_SLCT)
+ ret |= PARPORT_STATUS_SELECT;
+
+ if (status & AX_SPR_PE)
+ ret |= PARPORT_STATUS_PAPEROUT;
+
+ return ret;
+}
+
+static unsigned char
+parport_ax88796_frob_control(struct parport *p, unsigned char mask,
+ unsigned char val)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+ unsigned char old = parport_ax88796_read_control(p);
+
+ dev_dbg(dd->dev, "frob: mask=%02x, val=%02x, old=%02x\n",
+ mask, val, old);
+
+ parport_ax88796_write_control(p, (old & ~mask) | val);
+ return old;
+}
+
+static void
+parport_ax88796_enable_irq(struct parport *p)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+ unsigned long flags;
+
+ local_irq_save(flags);
+ if (!dd->irq_enabled) {
+ enable_irq(p->irq);
+ dd->irq_enabled = 1;
+ }
+ local_irq_restore(flags);
+}
+
+static void
+parport_ax88796_disable_irq(struct parport *p)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+ unsigned long flags;
+
+ local_irq_save(flags);
+ if (dd->irq_enabled) {
+ disable_irq(p->irq);
+ dd->irq_enabled = 0;
+ }
+ local_irq_restore(flags);
+}
+
+static void
+parport_ax88796_data_forward(struct parport *p)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+ void __iomem *cpr = dd->spp_cpr;
+
+ writeb((readb(cpr) & ~AX_CPR_nDOE), cpr);
+}
+
+static void
+parport_ax88796_data_reverse(struct parport *p)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+ void __iomem *cpr = dd->spp_cpr;
+
+ writeb(readb(cpr) | AX_CPR_nDOE, cpr);
+}
+
+static void
+parport_ax88796_init_state(struct pardevice *d, struct parport_state *s)
+{
+ struct ax_drvdata *dd = pp_to_drv(d->port);
+
+ memset(s, 0, sizeof(struct parport_state));
+
+ dev_dbg(dd->dev, "init_state: %p: state=%p\n", d, s);
+ s->u.ax88796.cpr = readb(dd->spp_cpr);
+}
+
+static void
+parport_ax88796_save_state(struct parport *p, struct parport_state *s)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+
+ dev_dbg(dd->dev, "save_state: %p: state=%p\n", p, s);
+ s->u.ax88796.cpr = readb(dd->spp_cpr);
+}
+
+static void
+parport_ax88796_restore_state(struct parport *p, struct parport_state *s)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+
+ dev_dbg(dd->dev, "restore_state: %p: state=%p\n", p, s);
+ writeb(s->u.ax88796.cpr, dd->spp_cpr);
+}
+
+static irqreturn_t
+parport_ax88796_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ parport_generic_irq(irq, dev_id, regs);
+ return IRQ_HANDLED;
+}
+
+
+static struct parport_operations parport_ax88796_ops = {
+ .write_data = parport_ax88796_write_data,
+ .read_data = parport_ax88796_read_data,
+
+ .write_control = parport_ax88796_write_control,
+ .read_control = parport_ax88796_read_control,
+ .frob_control = parport_ax88796_frob_control,
+
+ .read_status = parport_ax88796_read_status,
+
+ .enable_irq = parport_ax88796_enable_irq,
+ .disable_irq = parport_ax88796_disable_irq,
+
+ .data_forward = parport_ax88796_data_forward,
+ .data_reverse = parport_ax88796_data_reverse,
+
+ .init_state = parport_ax88796_init_state,
+ .save_state = parport_ax88796_save_state,
+ .restore_state = parport_ax88796_restore_state,
+
+ .epp_write_data = parport_ieee1284_epp_write_data,
+ .epp_read_data = parport_ieee1284_epp_read_data,
+ .epp_write_addr = parport_ieee1284_epp_write_addr,
+ .epp_read_addr = parport_ieee1284_epp_read_addr,
+
+ .ecp_write_data = parport_ieee1284_ecp_write_data,
+ .ecp_read_data = parport_ieee1284_ecp_read_data,
+ .ecp_write_addr = parport_ieee1284_ecp_write_addr,
+
+ .compat_write_data = parport_ieee1284_write_compat,
+ .nibble_read_data = parport_ieee1284_read_nibble,
+ .byte_read_data = parport_ieee1284_read_byte,
+
+ .owner = THIS_MODULE,
+};
+
+static int parport_ax88796_probe(struct platform_device *pdev)
+{
+ struct device *_dev = &pdev->dev;
+ struct ax_drvdata *dd;
+ struct parport *pp = NULL;
+ struct resource *res;
+ unsigned long size;
+ int spacing;
+ int irq;
+ int ret;
+
+ dd = kzalloc(sizeof(struct ax_drvdata), GFP_KERNEL);
+ if (dd == NULL) {
+ dev_err(_dev, "no memory for private data\n");
+ return -ENOMEM;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(_dev, "no MEM specified\n");
+ ret = -ENXIO;
+ goto exit_mem;
+ }
+
+ size = (res->end - res->start) + 1;
+ spacing = size / 3;
+
+ dd->io = request_mem_region(res->start, size, pdev->name);
+ if (dd->io == NULL) {
+ dev_err(_dev, "cannot reserve memory\n");
+ ret = -ENXIO;
+ goto exit_mem;
+ }
+
+ dd->base = ioremap(res->start, size);
+ if (dd->base == NULL) {
+ dev_err(_dev, "cannot ioremap region\n");
+ ret = -ENXIO;
+ goto exit_res;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0)
+ irq = PARPORT_IRQ_NONE;
+
+ pp = parport_register_port((unsigned long)dd->base, irq,
+ PARPORT_DMA_NONE,
+ &parport_ax88796_ops);
+
+ if (pp == NULL) {
+ dev_err(_dev, "failed to register parallel port\n");
+ ret = -ENOMEM;
+ goto exit_unmap;
+ }
+
+ pp->private_data = dd;
+ dd->parport = pp;
+ dd->dev = _dev;
+
+ dd->spp_data = dd->base;
+ dd->spp_spr = dd->base + (spacing * 1);
+ dd->spp_cpr = dd->base + (spacing * 2);
+
+ /* initialise the port controls */
+ writeb(AX_CPR_STRB, dd->spp_cpr);
+
+ if (irq >= 0) {
+ /* request irq */
+ ret = request_irq(irq, parport_ax88796_interrupt,
+ SA_TRIGGER_FALLING, pdev->name, pp);
+
+ if (ret < 0)
+ goto exit_port;
+
+ dd->irq_enabled = 1;
+ }
+
+ platform_set_drvdata(pdev, pp);
+
+ dev_info(_dev, "attached parallel port driver\n");
+ parport_announce_port(pp);
+
+ return 0;
+
+ exit_port:
+ parport_remove_port(pp);
+ exit_unmap:
+ iounmap(dd->base);
+ exit_res:
+ release_resource(dd->io);
+ kfree(dd->io);
+ exit_mem:
+ kfree(dd);
+ return ret;
+}
+
+static int parport_ax88796_remove(struct platform_device *pdev)
+{
+ struct parport *p = platform_get_drvdata(pdev);
+ struct ax_drvdata *dd = pp_to_drv(p);
+
+ free_irq(p->irq, p);
+ parport_remove_port(p);
+ iounmap(dd->base);
+ release_resource(dd->io);
+ kfree(dd->io);
+ kfree(dd);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int parport_ax88796_suspend(struct platform_device *dev,
+ pm_message_t state)
+{
+ struct parport *p = platform_get_drvdata(dev);
+ struct ax_drvdata *dd = pp_to_drv(p);
+
+ parport_ax88796_save_state(p, &dd->suspend);
+ writeb(AX_CPR_nDOE | AX_CPR_STRB, dd->spp_cpr);
+ return 0;
+}
+
+static int parport_ax88796_resume(struct platform_device *dev)
+{
+ struct parport *p = platform_get_drvdata(dev);
+ struct ax_drvdata *dd = pp_to_drv(p);
+
+ parport_ax88796_restore_state(p, &dd->suspend);
+ return 0;
+}
+
+#else
+#define parport_ax88796_suspend NULL
+#define parport_ax88796_resume NULL
+#endif
+
+static struct platform_driver axdrv = {
+ .driver = {
+ .name = "ax88796-pp",
+ .owner = THIS_MODULE,
+ },
+ .probe = parport_ax88796_probe,
+ .remove = parport_ax88796_remove,
+ .suspend = parport_ax88796_suspend,
+ .resume = parport_ax88796_resume,
+};
+
+static int __init parport_ax88796_init(void)
+{
+ return platform_driver_register(&axdrv);
+}
+
+static void __exit parport_ax88796_exit(void)
+{
+ platform_driver_unregister(&axdrv);
+}
+
+module_init(parport_ax88796_init)
+module_exit(parport_ax88796_exit)
+
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("AX88796 Parport parallel port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c
index 36a1556..69a4bbd 100644
--- a/drivers/parport/parport_sunbpp.c
+++ b/drivers/parport/parport_sunbpp.c
@@ -1,5 +1,4 @@
-/* $Id: parport_sunbpp.c,v 1.12 2001/05/26 03:01:42 davem Exp $
- * Parallel-port routines for Sun architecture
+/* parport_sunbpp.c: Parallel-port routines for SBUS
*
* Author: Derrick J. Brashear <shadow@dementia.org>
*
@@ -14,6 +13,9 @@
* Gus Baldauf (gbaldauf@ix.netcom.com)
* Peter Zaitcev
* Tom Dyas
+ *
+ * Updated to new SBUS device framework: David S. Miller <davem@davemloft.net>
+ *
*/
#include <linux/string.h>
@@ -287,14 +289,7 @@ static struct parport_operations parport_sunbpp_ops =
.owner = THIS_MODULE,
};
-typedef struct {
- struct list_head list;
- struct parport *port;
-} Node;
-/* no locks, everything's serialized */
-static LIST_HEAD(port_list);
-
-static int __init init_one_port(struct sbus_dev *sdev)
+static int __devinit init_one_port(struct sbus_dev *sdev)
{
struct parport *p;
/* at least in theory there may be a "we don't dma" case */
@@ -303,109 +298,120 @@ static int __init init_one_port(struct sbus_dev *sdev)
int irq, dma, err = 0, size;
struct bpp_regs __iomem *regs;
unsigned char value_tcr;
- Node *node;
-
- dprintk((KERN_DEBUG "init_one_port(%p): ranges, alloc_io, ", sdev));
- node = kmalloc(sizeof(Node), GFP_KERNEL);
- if (!node)
- goto out0;
irq = sdev->irqs[0];
base = sbus_ioremap(&sdev->resource[0], 0,
sdev->reg_addrs[0].reg_size,
"sunbpp");
if (!base)
- goto out1;
+ return -ENODEV;
size = sdev->reg_addrs[0].reg_size;
dma = PARPORT_DMA_NONE;
- dprintk(("alloc(ppops), "));
- ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL);
+ ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL);
if (!ops)
- goto out2;
+ goto out_unmap;
memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations));
dprintk(("register_port\n"));
if (!(p = parport_register_port((unsigned long)base, irq, dma, ops)))
- goto out3;
+ goto out_free_ops;
p->size = size;
- dprintk((KERN_DEBUG "init_one_port: request_irq(%08x:%p:%x:%s:%p) ",
- p->irq, parport_sunbpp_interrupt, SA_SHIRQ, p->name, p));
if ((err = request_irq(p->irq, parport_sunbpp_interrupt,
SA_SHIRQ, p->name, p)) != 0) {
- dprintk(("ERROR %d\n", err));
- goto out4;
+ goto out_put_port;
}
- dprintk(("OK\n"));
+
parport_sunbpp_enable_irq(p);
regs = (struct bpp_regs __iomem *)p->base;
- dprintk((KERN_DEBUG "forward\n"));
+
value_tcr = sbus_readb(&regs->p_tcr);
value_tcr &= ~P_TCR_DIR;
sbus_writeb(value_tcr, &regs->p_tcr);
printk(KERN_INFO "%s: sunbpp at 0x%lx\n", p->name, p->base);
- node->port = p;
- list_add(&node->list, &port_list);
- parport_announce_port (p);
- return 1;
+ dev_set_drvdata(&sdev->ofdev.dev, p);
+
+ parport_announce_port(p);
+
+ return 0;
-out4:
+out_put_port:
parport_put_port(p);
-out3:
+
+out_free_ops:
kfree(ops);
-out2:
+
+out_unmap:
sbus_iounmap(base, size);
-out1:
- kfree(node);
-out0:
+
return err;
}
-static int __init parport_sunbpp_init(void)
+static int __devinit bpp_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev;
- int count = 0;
-
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- if (!strcmp(sdev->prom_name, "SUNW,bpp"))
- count += init_one_port(sdev);
- }
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+
+ return init_one_port(sdev);
+}
+
+static int __devexit bpp_remove(struct of_device *dev)
+{
+ struct parport *p = dev_get_drvdata(&dev->dev);
+ struct parport_operations *ops = p->ops;
+
+ parport_remove_port(p);
+
+ if (p->irq != PARPORT_IRQ_NONE) {
+ parport_sunbpp_disable_irq(p);
+ free_irq(p->irq, p);
}
- return count ? 0 : -ENODEV;
+
+ sbus_iounmap((void __iomem *) p->base, p->size);
+ parport_put_port(p);
+ kfree(ops);
+
+ dev_set_drvdata(&dev->dev, NULL);
+
+ return 0;
+}
+
+static struct of_device_id bpp_match[] = {
+ {
+ .name = "SUNW,bpp",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, qec_sbus_match);
+
+static struct of_platform_driver bpp_sbus_driver = {
+ .name = "bpp",
+ .match_table = bpp_match,
+ .probe = bpp_probe,
+ .remove = __devexit_p(bpp_remove),
+};
+
+static int __init parport_sunbpp_init(void)
+{
+ return of_register_driver(&bpp_sbus_driver, &sbus_bus_type);
}
static void __exit parport_sunbpp_exit(void)
{
- while (!list_empty(&port_list)) {
- Node *node = list_entry(port_list.next, Node, list);
- struct parport *p = node->port;
- struct parport_operations *ops = p->ops;
- parport_remove_port(p);
-
- if (p->irq != PARPORT_IRQ_NONE) {
- parport_sunbpp_disable_irq(p);
- free_irq(p->irq, p);
- }
- sbus_iounmap((void __iomem *)p->base, p->size);
- parport_put_port(p);
- kfree (ops);
- list_del(&node->list);
- kfree (node);
- }
+ of_unregister_driver(&bpp_sbus_driver);
}
MODULE_AUTHOR("Derrick J Brashear");
MODULE_DESCRIPTION("Parport Driver for Sparc bidirectional Port");
MODULE_SUPPORTED_DEVICE("Sparc Bidirectional Parallel Port");
+MODULE_VERSION("2.0");
MODULE_LICENSE("GPL");
module_init(parport_sunbpp_init)
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index bbbfd79..2cb22c8 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -218,7 +218,7 @@ static void free_port (struct parport *port)
* parport_get_port - increment a port's reference count
* @port: the port
*
- * This ensure's that a struct parport pointer remains valid
+ * This ensures that a struct parport pointer remains valid
* until the matching parport_put_port() call.
**/
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 6707df9..f2d152b 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -26,7 +26,11 @@ obj-$(CONFIG_PPC32) += setup-irq.o
obj-$(CONFIG_PPC64) += setup-bus.o
obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
obj-$(CONFIG_X86_VISWS) += setup-irq.o
-obj-$(CONFIG_PCI_MSI) += msi.o
+
+msiobj-y := msi.o msi-apic.o
+msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o
+msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o
+obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
#
# ACPI Related PCI FW Functions
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index eed67d9..7230926 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -81,9 +81,9 @@ void __devinit pci_bus_add_device(struct pci_dev *dev)
{
device_add(&dev->dev);
- spin_lock(&pci_bus_lock);
+ down_write(&pci_bus_sem);
list_add_tail(&dev->global_list, &pci_devices);
- spin_unlock(&pci_bus_lock);
+ up_write(&pci_bus_sem);
pci_proc_attach_device(dev);
pci_create_sysfs_dev_files(dev);
@@ -125,10 +125,10 @@ void __devinit pci_bus_add_devices(struct pci_bus *bus)
*/
if (dev->subordinate) {
if (list_empty(&dev->subordinate->node)) {
- spin_lock(&pci_bus_lock);
+ down_write(&pci_bus_sem);
list_add_tail(&dev->subordinate->node,
&dev->bus->children);
- spin_unlock(&pci_bus_lock);
+ up_write(&pci_bus_sem);
}
pci_bus_add_devices(dev->subordinate);
@@ -168,7 +168,7 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
struct list_head *next;
bus = top;
- spin_lock(&pci_bus_lock);
+ down_read(&pci_bus_sem);
next = top->devices.next;
for (;;) {
if (next == &bus->devices) {
@@ -180,22 +180,19 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
continue;
}
dev = list_entry(next, struct pci_dev, bus_list);
- pci_dev_get(dev);
if (dev->subordinate) {
/* this is a pci-pci bridge, do its devices next */
next = dev->subordinate->devices.next;
bus = dev->subordinate;
} else
next = dev->bus_list.next;
- spin_unlock(&pci_bus_lock);
- /* Run device routines with the bus unlocked */
+ /* Run device routines with the device locked */
+ down(&dev->dev.sem);
cb(dev, userdata);
-
- spin_lock(&pci_bus_lock);
- pci_dev_put(dev);
+ up(&dev->dev.sem);
}
- spin_unlock(&pci_bus_lock);
+ up_read(&pci_bus_sem);
}
EXPORT_SYMBOL_GPL(pci_walk_bus);
diff --git a/drivers/pci/msi-altix.c b/drivers/pci/msi-altix.c
new file mode 100644
index 0000000..bed4183
--- /dev/null
+++ b/drivers/pci/msi-altix.c
@@ -0,0 +1,210 @@
+/*
+ * 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) 2006 Silicon Graphics, Inc. All Rights Reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/cpumask.h>
+
+#include <asm/sn/addrs.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/pcibus_provider_defs.h>
+#include <asm/sn/pcidev.h>
+#include <asm/sn/nodepda.h>
+
+#include "msi.h"
+
+struct sn_msi_info {
+ u64 pci_addr;
+ struct sn_irq_info *sn_irq_info;
+};
+
+static struct sn_msi_info *sn_msi_info;
+
+static void
+sn_msi_teardown(unsigned int vector)
+{
+ nasid_t nasid;
+ int widget;
+ struct pci_dev *pdev;
+ struct pcidev_info *sn_pdev;
+ struct sn_irq_info *sn_irq_info;
+ struct pcibus_bussoft *bussoft;
+ struct sn_pcibus_provider *provider;
+
+ sn_irq_info = sn_msi_info[vector].sn_irq_info;
+ if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
+ return;
+
+ sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
+ pdev = sn_pdev->pdi_linux_pcidev;
+ provider = SN_PCIDEV_BUSPROVIDER(pdev);
+
+ (*provider->dma_unmap)(pdev,
+ sn_msi_info[vector].pci_addr,
+ PCI_DMA_FROMDEVICE);
+ sn_msi_info[vector].pci_addr = 0;
+
+ bussoft = SN_PCIDEV_BUSSOFT(pdev);
+ nasid = NASID_GET(bussoft->bs_base);
+ widget = (nasid & 1) ?
+ TIO_SWIN_WIDGETNUM(bussoft->bs_base) :
+ SWIN_WIDGETNUM(bussoft->bs_base);
+
+ sn_intr_free(nasid, widget, sn_irq_info);
+ sn_msi_info[vector].sn_irq_info = NULL;
+
+ return;
+}
+
+int
+sn_msi_setup(struct pci_dev *pdev, unsigned int vector,
+ u32 *addr_hi, u32 *addr_lo, u32 *data)
+{
+ int widget;
+ int status;
+ nasid_t nasid;
+ u64 bus_addr;
+ struct sn_irq_info *sn_irq_info;
+ struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev);
+ struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
+
+ if (bussoft == NULL)
+ return -EINVAL;
+
+ if (provider == NULL || provider->dma_map_consistent == NULL)
+ return -EINVAL;
+
+ /*
+ * Set up the vector plumbing. Let the prom (via sn_intr_alloc)
+ * decide which cpu to direct this msi at by default.
+ */
+
+ nasid = NASID_GET(bussoft->bs_base);
+ widget = (nasid & 1) ?
+ TIO_SWIN_WIDGETNUM(bussoft->bs_base) :
+ SWIN_WIDGETNUM(bussoft->bs_base);
+
+ sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
+ if (! sn_irq_info)
+ return -ENOMEM;
+
+ status = sn_intr_alloc(nasid, widget, sn_irq_info, vector, -1, -1);
+ if (status) {
+ kfree(sn_irq_info);
+ return -ENOMEM;
+ }
+
+ sn_irq_info->irq_int_bit = -1; /* mark this as an MSI irq */
+ sn_irq_fixup(pdev, sn_irq_info);
+
+ /* Prom probably should fill these in, but doesn't ... */
+ sn_irq_info->irq_bridge_type = bussoft->bs_asic_type;
+ sn_irq_info->irq_bridge = (void *)bussoft->bs_base;
+
+ /*
+ * Map the xio address into bus space
+ */
+ bus_addr = (*provider->dma_map_consistent)(pdev,
+ sn_irq_info->irq_xtalkaddr,
+ sizeof(sn_irq_info->irq_xtalkaddr),
+ SN_DMA_MSI|SN_DMA_ADDR_XIO);
+ if (! bus_addr) {
+ sn_intr_free(nasid, widget, sn_irq_info);
+ kfree(sn_irq_info);
+ return -ENOMEM;
+ }
+
+ sn_msi_info[vector].sn_irq_info = sn_irq_info;
+ sn_msi_info[vector].pci_addr = bus_addr;
+
+ *addr_hi = (u32)(bus_addr >> 32);
+ *addr_lo = (u32)(bus_addr & 0x00000000ffffffff);
+
+ /*
+ * In the SN platform, bit 16 is a "send vector" bit which
+ * must be present in order to move the vector through the system.
+ */
+ *data = 0x100 + (unsigned int)vector;
+
+#ifdef CONFIG_SMP
+ set_irq_affinity_info((vector & 0xff), sn_irq_info->irq_cpuid, 0);
+#endif
+
+ return 0;
+}
+
+static void
+sn_msi_target(unsigned int vector, unsigned int cpu,
+ u32 *addr_hi, u32 *addr_lo)
+{
+ int slice;
+ nasid_t nasid;
+ u64 bus_addr;
+ struct pci_dev *pdev;
+ struct pcidev_info *sn_pdev;
+ struct sn_irq_info *sn_irq_info;
+ struct sn_irq_info *new_irq_info;
+ struct sn_pcibus_provider *provider;
+
+ sn_irq_info = sn_msi_info[vector].sn_irq_info;
+ if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
+ return;
+
+ /*
+ * Release XIO resources for the old MSI PCI address
+ */
+
+ sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
+ pdev = sn_pdev->pdi_linux_pcidev;
+ provider = SN_PCIDEV_BUSPROVIDER(pdev);
+
+ bus_addr = (u64)(*addr_hi) << 32 | (u64)(*addr_lo);
+ (*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE);
+ sn_msi_info[vector].pci_addr = 0;
+
+ nasid = cpuid_to_nasid(cpu);
+ slice = cpuid_to_slice(cpu);
+
+ new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice);
+ sn_msi_info[vector].sn_irq_info = new_irq_info;
+ if (new_irq_info == NULL)
+ return;
+
+ /*
+ * Map the xio address into bus space
+ */
+
+ bus_addr = (*provider->dma_map_consistent)(pdev,
+ new_irq_info->irq_xtalkaddr,
+ sizeof(new_irq_info->irq_xtalkaddr),
+ SN_DMA_MSI|SN_DMA_ADDR_XIO);
+
+ sn_msi_info[vector].pci_addr = bus_addr;
+ *addr_hi = (u32)(bus_addr >> 32);
+ *addr_lo = (u32)(bus_addr & 0x00000000ffffffff);
+}
+
+struct msi_ops sn_msi_ops = {
+ .setup = sn_msi_setup,
+ .teardown = sn_msi_teardown,
+#ifdef CONFIG_SMP
+ .target = sn_msi_target,
+#endif
+};
+
+int
+sn_msi_init(void)
+{
+ sn_msi_info =
+ kzalloc(sizeof(struct sn_msi_info) * NR_VECTORS, GFP_KERNEL);
+ if (! sn_msi_info)
+ return -ENOMEM;
+
+ msi_register(&sn_msi_ops);
+ return 0;
+}
diff --git a/drivers/pci/msi-apic.c b/drivers/pci/msi-apic.c
new file mode 100644
index 0000000..0eb5fe9
--- /dev/null
+++ b/drivers/pci/msi-apic.c
@@ -0,0 +1,100 @@
+/*
+ * MSI hooks for standard x86 apic
+ */
+
+#include <linux/pci.h>
+#include <linux/irq.h>
+
+#include "msi.h"
+
+/*
+ * Shifts for APIC-based data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT 0
+#define MSI_DATA_VECTOR(v) (((u8)v) << MSI_DATA_VECTOR_SHIFT)
+
+#define MSI_DATA_DELIVERY_SHIFT 8
+#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_SHIFT)
+#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_SHIFT)
+
+#define MSI_DATA_LEVEL_SHIFT 14
+#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT)
+#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT)
+
+#define MSI_DATA_TRIGGER_SHIFT 15
+#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT)
+#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT)
+
+/*
+ * Shift/mask fields for APIC-based bus address
+ */
+
+#define MSI_ADDR_HEADER 0xfee00000
+
+#define MSI_ADDR_DESTID_MASK 0xfff0000f
+#define MSI_ADDR_DESTID_CPU(cpu) ((cpu) << MSI_TARGET_CPU_SHIFT)
+
+#define MSI_ADDR_DESTMODE_SHIFT 2
+#define MSI_ADDR_DESTMODE_PHYS (0 << MSI_ADDR_DESTMODE_SHIFT)
+#define MSI_ADDR_DESTMODE_LOGIC (1 << MSI_ADDR_DESTMODE_SHIFT)
+
+#define MSI_ADDR_REDIRECTION_SHIFT 3
+#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT)
+#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT)
+
+
+static void
+msi_target_apic(unsigned int vector,
+ unsigned int dest_cpu,
+ u32 *address_hi, /* in/out */
+ u32 *address_lo) /* in/out */
+{
+ u32 addr = *address_lo;
+
+ addr &= MSI_ADDR_DESTID_MASK;
+ addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu));
+
+ *address_lo = addr;
+}
+
+static int
+msi_setup_apic(struct pci_dev *pdev, /* unused in generic */
+ unsigned int vector,
+ u32 *address_hi,
+ u32 *address_lo,
+ u32 *data)
+{
+ unsigned long dest_phys_id;
+
+ dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
+
+ *address_hi = 0;
+ *address_lo = MSI_ADDR_HEADER |
+ MSI_ADDR_DESTMODE_PHYS |
+ MSI_ADDR_REDIRECTION_CPU |
+ MSI_ADDR_DESTID_CPU(dest_phys_id);
+
+ *data = MSI_DATA_TRIGGER_EDGE |
+ MSI_DATA_LEVEL_ASSERT |
+ MSI_DATA_DELIVERY_FIXED |
+ MSI_DATA_VECTOR(vector);
+
+ return 0;
+}
+
+static void
+msi_teardown_apic(unsigned int vector)
+{
+ return; /* no-op */
+}
+
+/*
+ * Generic ops used on most IA archs/platforms. Set with msi_register()
+ */
+
+struct msi_ops msi_apic_ops = {
+ .setup = msi_setup_apic,
+ .teardown = msi_teardown_apic,
+ .target = msi_target_apic,
+};
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 9855c4c..7f84292 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -23,8 +23,6 @@
#include "pci.h"
#include "msi.h"
-#define MSI_TARGET_CPU first_cpu(cpu_online_map)
-
static DEFINE_SPINLOCK(msi_lock);
static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
static kmem_cache_t* msi_cachep;
@@ -37,9 +35,17 @@ static int nr_msix_devices;
#ifndef CONFIG_X86_IO_APIC
int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};
-u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
#endif
+static struct msi_ops *msi_ops;
+
+int
+msi_register(struct msi_ops *ops)
+{
+ msi_ops = ops;
+ return 0;
+}
+
static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags)
{
memset(p, 0, NR_IRQS * sizeof(struct msi_desc));
@@ -92,7 +98,7 @@ static void msi_set_mask_bit(unsigned int vector, int flag)
static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
{
struct msi_desc *entry;
- struct msg_address address;
+ u32 address_hi, address_lo;
unsigned int irq = vector;
unsigned int dest_cpu = first_cpu(cpu_mask);
@@ -108,28 +114,36 @@ static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
if (!pos)
return;
+ pci_read_config_dword(entry->dev, msi_upper_address_reg(pos),
+ &address_hi);
pci_read_config_dword(entry->dev, msi_lower_address_reg(pos),
- &address.lo_address.value);
- address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
- address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
- MSI_TARGET_CPU_SHIFT);
- entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
+ &address_lo);
+
+ msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+
+ pci_write_config_dword(entry->dev, msi_upper_address_reg(pos),
+ address_hi);
pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
- address.lo_address.value);
+ address_lo);
set_native_irq_info(irq, cpu_mask);
break;
}
case PCI_CAP_ID_MSIX:
{
- int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
-
- address.lo_address.value = readl(entry->mask_base + offset);
- address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
- address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
- MSI_TARGET_CPU_SHIFT);
- entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
- writel(address.lo_address.value, entry->mask_base + offset);
+ int offset_hi =
+ entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+ PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET;
+ int offset_lo =
+ entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+ PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+
+ address_hi = readl(entry->mask_base + offset_hi);
+ address_lo = readl(entry->mask_base + offset_lo);
+
+ msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+
+ writel(address_hi, entry->mask_base + offset_hi);
+ writel(address_lo, entry->mask_base + offset_lo);
set_native_irq_info(irq, cpu_mask);
break;
}
@@ -251,30 +265,6 @@ static struct hw_interrupt_type msi_irq_wo_maskbit_type = {
.set_affinity = set_msi_affinity
};
-static void msi_data_init(struct msg_data *msi_data,
- unsigned int vector)
-{
- memset(msi_data, 0, sizeof(struct msg_data));
- msi_data->vector = (u8)vector;
- msi_data->delivery_mode = MSI_DELIVERY_MODE;
- msi_data->level = MSI_LEVEL_MODE;
- msi_data->trigger = MSI_TRIGGER_MODE;
-}
-
-static void msi_address_init(struct msg_address *msi_address)
-{
- unsigned int dest_id;
- unsigned long dest_phys_id = cpu_physical_id(MSI_TARGET_CPU);
-
- memset(msi_address, 0, sizeof(struct msg_address));
- msi_address->hi_address = (u32)0;
- dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT);
- msi_address->lo_address.u.dest_mode = MSI_PHYSICAL_MODE;
- msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE;
- msi_address->lo_address.u.dest_id = dest_id;
- msi_address->lo_address.value |= (dest_phys_id << MSI_TARGET_CPU_SHIFT);
-}
-
static int msi_free_vector(struct pci_dev* dev, int vector, int reassign);
static int assign_msi_vector(void)
{
@@ -369,13 +359,29 @@ static int msi_init(void)
return status;
}
+ status = msi_arch_init();
+ if (status < 0) {
+ pci_msi_enable = 0;
+ printk(KERN_WARNING
+ "PCI: MSI arch init failed. MSI disabled.\n");
+ return status;
+ }
+
+ if (! msi_ops) {
+ printk(KERN_WARNING
+ "PCI: MSI ops not registered. MSI disabled.\n");
+ status = -EINVAL;
+ return status;
+ }
+
+ last_alloc_vector = assign_irq_vector(AUTO_ASSIGN);
status = msi_cache_init();
if (status < 0) {
pci_msi_enable = 0;
printk(KERN_WARNING "PCI: MSI cache init failed\n");
return status;
}
- last_alloc_vector = assign_irq_vector(AUTO_ASSIGN);
+
if (last_alloc_vector < 0) {
pci_msi_enable = 0;
printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n");
@@ -442,9 +448,11 @@ static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
/* Set enabled bits to single MSI & enable MSI_enable bit */
msi_enable(control, 1);
pci_write_config_word(dev, msi_control_reg(pos), control);
+ dev->msi_enabled = 1;
} else {
msix_enable(control);
pci_write_config_word(dev, msi_control_reg(pos), control);
+ dev->msix_enabled = 1;
}
if (pci_find_capability(dev, PCI_CAP_ID_EXP)) {
/* PCI Express Endpoint device detected */
@@ -461,9 +469,11 @@ void disable_msi_mode(struct pci_dev *dev, int pos, int type)
/* Set enabled bits to single MSI & enable MSI_enable bit */
msi_disable(control);
pci_write_config_word(dev, msi_control_reg(pos), control);
+ dev->msi_enabled = 0;
} else {
msix_disable(control);
pci_write_config_word(dev, msi_control_reg(pos), control);
+ dev->msix_enabled = 0;
}
if (pci_find_capability(dev, PCI_CAP_ID_EXP)) {
/* PCI Express Endpoint device detected */
@@ -538,7 +548,6 @@ int pci_save_msi_state(struct pci_dev *dev)
pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, &cap[i++]);
if (control & PCI_MSI_FLAGS_MASKBIT)
pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, &cap[i++]);
- disable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
save_state->cap_nr = PCI_CAP_ID_MSI;
pci_add_saved_cap(dev, save_state);
return 0;
@@ -575,6 +584,8 @@ void pci_restore_msi_state(struct pci_dev *dev)
int pci_save_msix_state(struct pci_dev *dev)
{
int pos;
+ int temp;
+ int vector, head, tail = 0;
u16 control;
struct pci_cap_saved_state *save_state;
@@ -582,6 +593,7 @@ int pci_save_msix_state(struct pci_dev *dev)
if (pos <= 0 || dev->no_msi)
return 0;
+ /* save the capability */
pci_read_config_word(dev, msi_control_reg(pos), &control);
if (!(control & PCI_MSIX_FLAGS_ENABLE))
return 0;
@@ -593,7 +605,38 @@ int pci_save_msix_state(struct pci_dev *dev)
}
*((u16 *)&save_state->data[0]) = control;
- disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
+ /* save the table */
+ temp = dev->irq;
+ if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
+ kfree(save_state);
+ return -EINVAL;
+ }
+
+ vector = head = dev->irq;
+ while (head != tail) {
+ int j;
+ void __iomem *base;
+ struct msi_desc *entry;
+
+ entry = msi_desc[vector];
+ base = entry->mask_base;
+ j = entry->msi_attrib.entry_nr;
+
+ entry->address_lo_save =
+ readl(base + j * PCI_MSIX_ENTRY_SIZE +
+ PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+ entry->address_hi_save =
+ readl(base + j * PCI_MSIX_ENTRY_SIZE +
+ PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+ entry->data_save =
+ readl(base + j * PCI_MSIX_ENTRY_SIZE +
+ PCI_MSIX_ENTRY_DATA_OFFSET);
+
+ tail = msi_desc[vector]->link.tail;
+ vector = tail;
+ }
+ dev->irq = temp;
+
save_state->cap_nr = PCI_CAP_ID_MSIX;
pci_add_saved_cap(dev, save_state);
return 0;
@@ -606,8 +649,6 @@ void pci_restore_msix_state(struct pci_dev *dev)
int vector, head, tail = 0;
void __iomem *base;
int j;
- struct msg_address address;
- struct msg_data data;
struct msi_desc *entry;
int temp;
struct pci_cap_saved_state *save_state;
@@ -633,20 +674,13 @@ void pci_restore_msix_state(struct pci_dev *dev)
base = entry->mask_base;
j = entry->msi_attrib.entry_nr;
- msi_address_init(&address);
- msi_data_init(&data, vector);
-
- address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
- address.lo_address.value |= entry->msi_attrib.current_cpu <<
- MSI_TARGET_CPU_SHIFT;
-
- writel(address.lo_address.value,
+ writel(entry->address_lo_save,
base + j * PCI_MSIX_ENTRY_SIZE +
PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
- writel(address.hi_address,
+ writel(entry->address_hi_save,
base + j * PCI_MSIX_ENTRY_SIZE +
PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
- writel(*(u32*)&data,
+ writel(entry->data_save,
base + j * PCI_MSIX_ENTRY_SIZE +
PCI_MSIX_ENTRY_DATA_OFFSET);
@@ -660,30 +694,32 @@ void pci_restore_msix_state(struct pci_dev *dev)
}
#endif
-static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry)
+static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry)
{
- struct msg_address address;
- struct msg_data data;
+ int status;
+ u32 address_hi;
+ u32 address_lo;
+ u32 data;
int pos, vector = dev->irq;
u16 control;
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
pci_read_config_word(dev, msi_control_reg(pos), &control);
+
/* Configure MSI capability structure */
- msi_address_init(&address);
- msi_data_init(&data, vector);
- entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >>
- MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
- pci_write_config_dword(dev, msi_lower_address_reg(pos),
- address.lo_address.value);
+ status = msi_ops->setup(dev, vector, &address_hi, &address_lo, &data);
+ if (status < 0)
+ return status;
+
+ pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo);
if (is_64bit_address(control)) {
pci_write_config_dword(dev,
- msi_upper_address_reg(pos), address.hi_address);
+ msi_upper_address_reg(pos), address_hi);
pci_write_config_word(dev,
- msi_data_reg(pos, 1), *((u32*)&data));
+ msi_data_reg(pos, 1), data);
} else
pci_write_config_word(dev,
- msi_data_reg(pos, 0), *((u32*)&data));
+ msi_data_reg(pos, 0), data);
if (entry->msi_attrib.maskbit) {
unsigned int maskbits, temp;
/* All MSIs are unmasked by default, Mask them all */
@@ -697,6 +733,8 @@ static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry)
msi_mask_bits_reg(pos, is_64bit_address(control)),
maskbits);
}
+
+ return 0;
}
/**
@@ -710,6 +748,7 @@ static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry)
**/
static int msi_capability_init(struct pci_dev *dev)
{
+ int status;
struct msi_desc *entry;
int pos, vector;
u16 control;
@@ -742,7 +781,12 @@ static int msi_capability_init(struct pci_dev *dev)
/* Replace with MSI handler */
irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
/* Configure MSI capability structure */
- msi_register_init(dev, entry);
+ status = msi_register_init(dev, entry);
+ if (status != 0) {
+ dev->irq = entry->msi_attrib.default_vector;
+ kmem_cache_free(msi_cachep, entry);
+ return status;
+ }
attach_msi_entry(entry, vector);
/* Set MSI enabled bits */
@@ -765,8 +809,10 @@ static int msix_capability_init(struct pci_dev *dev,
struct msix_entry *entries, int nvec)
{
struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
- struct msg_address address;
- struct msg_data data;
+ u32 address_hi;
+ u32 address_lo;
+ u32 data;
+ int status;
int vector, pos, i, j, nr_entries, temp = 0;
unsigned long phys_addr;
u32 table_offset;
@@ -822,18 +868,20 @@ static int msix_capability_init(struct pci_dev *dev,
/* Replace with MSI-X handler */
irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
/* Configure MSI-X capability structure */
- msi_address_init(&address);
- msi_data_init(&data, vector);
- entry->msi_attrib.current_cpu =
- ((address.lo_address.u.dest_id >>
- MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
- writel(address.lo_address.value,
+ status = msi_ops->setup(dev, vector,
+ &address_hi,
+ &address_lo,
+ &data);
+ if (status < 0)
+ break;
+
+ writel(address_lo,
base + j * PCI_MSIX_ENTRY_SIZE +
PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
- writel(address.hi_address,
+ writel(address_hi,
base + j * PCI_MSIX_ENTRY_SIZE +
PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
- writel(*(u32*)&data,
+ writel(data,
base + j * PCI_MSIX_ENTRY_SIZE +
PCI_MSIX_ENTRY_DATA_OFFSET);
attach_msi_entry(entry, vector);
@@ -865,6 +913,7 @@ static int msix_capability_init(struct pci_dev *dev,
**/
int pci_enable_msi(struct pci_dev* dev)
{
+ struct pci_bus *bus;
int pos, temp, status = -EINVAL;
u16 control;
@@ -874,8 +923,9 @@ int pci_enable_msi(struct pci_dev* dev)
if (dev->no_msi)
return status;
- if (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
- return -EINVAL;
+ for (bus = dev->bus; bus; bus = bus->parent)
+ if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
+ return -EINVAL;
temp = dev->irq;
@@ -887,23 +937,23 @@ int pci_enable_msi(struct pci_dev* dev)
if (!pos)
return -EINVAL;
- pci_read_config_word(dev, msi_control_reg(pos), &control);
- if (control & PCI_MSI_FLAGS_ENABLE)
- return 0; /* Already in MSI mode */
-
if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
/* Lookup Sucess */
unsigned long flags;
+ pci_read_config_word(dev, msi_control_reg(pos), &control);
+ if (control & PCI_MSI_FLAGS_ENABLE)
+ return 0; /* Already in MSI mode */
spin_lock_irqsave(&msi_lock, flags);
if (!vector_irq[dev->irq]) {
msi_desc[dev->irq]->msi_attrib.state = 0;
vector_irq[dev->irq] = -1;
nr_released_vectors--;
spin_unlock_irqrestore(&msi_lock, flags);
- msi_register_init(dev, msi_desc[dev->irq]);
- enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
- return 0;
+ status = msi_register_init(dev, msi_desc[dev->irq]);
+ if (status == 0)
+ enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
+ return status;
}
spin_unlock_irqrestore(&msi_lock, flags);
dev->irq = temp;
@@ -980,6 +1030,8 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign)
void __iomem *base;
unsigned long flags;
+ msi_ops->teardown(vector);
+
spin_lock_irqsave(&msi_lock, flags);
entry = msi_desc[vector];
if (!entry || entry->dev != dev) {
@@ -1008,33 +1060,8 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign)
entry_nr * PCI_MSIX_ENTRY_SIZE +
PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
- if (head == vector) {
- /*
- * Detect last MSI-X vector to be released.
- * Release the MSI-X memory-mapped table.
- */
-#if 0
- int pos, nr_entries;
- unsigned long phys_addr;
- u32 table_offset;
- u16 control;
- u8 bir;
-
- pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- pci_read_config_word(dev, msi_control_reg(pos),
- &control);
- nr_entries = multi_msix_capable(control);
- pci_read_config_dword(dev, msix_table_offset_reg(pos),
- &table_offset);
- bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
- table_offset &= ~PCI_MSIX_FLAGS_BIRMASK;
- phys_addr = pci_resource_start(dev, bir) + table_offset;
-/*
- * FIXME! and what did you want to do with phys_addr?
- */
-#endif
+ if (head == vector)
iounmap(base);
- }
}
return 0;
@@ -1108,6 +1135,7 @@ static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec)
**/
int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
{
+ struct pci_bus *bus;
int status, pos, nr_entries, free_vectors;
int i, j, temp;
u16 control;
@@ -1116,6 +1144,13 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
if (!pci_msi_enable || !dev || !entries)
return -EINVAL;
+ if (dev->no_msi)
+ return -EINVAL;
+
+ for (bus = dev->bus; bus; bus = bus->parent)
+ if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
+ return -EINVAL;
+
status = msi_init();
if (status < 0)
return status;
@@ -1300,24 +1335,6 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev)
}
msi_free_vector(dev, vector, 0);
if (warning) {
- /* Force to release the MSI-X memory-mapped table */
-#if 0
- unsigned long phys_addr;
- u32 table_offset;
- u16 control;
- u8 bir;
-
- pci_read_config_word(dev, msi_control_reg(pos),
- &control);
- pci_read_config_dword(dev, msix_table_offset_reg(pos),
- &table_offset);
- bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
- table_offset &= ~PCI_MSIX_FLAGS_BIRMASK;
- phys_addr = pci_resource_start(dev, bir) + table_offset;
-/*
- * FIXME! and what did you want to do with phys_addr?
- */
-#endif
iounmap(base);
printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
"called without free_irq() on all MSI-X vectors\n",
diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h
index 4ac52d4..56951c3 100644
--- a/drivers/pci/msi.h
+++ b/drivers/pci/msi.h
@@ -6,6 +6,68 @@
#ifndef MSI_H
#define MSI_H
+/*
+ * MSI operation vector. Used by the msi core code (drivers/pci/msi.c)
+ * to abstract platform-specific tasks relating to MSI address generation
+ * and resource management.
+ */
+struct msi_ops {
+ /**
+ * setup - generate an MSI bus address and data for a given vector
+ * @pdev: PCI device context (in)
+ * @vector: vector allocated by the msi core (in)
+ * @addr_hi: upper 32 bits of PCI bus MSI address (out)
+ * @addr_lo: lower 32 bits of PCI bus MSI address (out)
+ * @data: MSI data payload (out)
+ *
+ * Description: The setup op is used to generate a PCI bus addres and
+ * data which the msi core will program into the card MSI capability
+ * registers. The setup routine is responsible for picking an initial
+ * cpu to target the MSI at. The setup routine is responsible for
+ * examining pdev to determine the MSI capabilities of the card and
+ * generating a suitable address/data. The setup routine is
+ * responsible for allocating and tracking any system resources it
+ * needs to route the MSI to the cpu it picks, and for associating
+ * those resources with the passed in vector.
+ *
+ * Returns 0 if the MSI address/data was successfully setup.
+ **/
+
+ int (*setup) (struct pci_dev *pdev, unsigned int vector,
+ u32 *addr_hi, u32 *addr_lo, u32 *data);
+
+ /**
+ * teardown - release resources allocated by setup
+ * @vector: vector context for resources (in)
+ *
+ * Description: The teardown op is used to release any resources
+ * that were allocated in the setup routine associated with the passed
+ * in vector.
+ **/
+
+ void (*teardown) (unsigned int vector);
+
+ /**
+ * target - retarget an MSI at a different cpu
+ * @vector: vector context for resources (in)
+ * @cpu: new cpu to direct vector at (in)
+ * @addr_hi: new value of PCI bus upper 32 bits (in/out)
+ * @addr_lo: new value of PCI bus lower 32 bits (in/out)
+ *
+ * Description: The target op is used to redirect an MSI vector
+ * at a different cpu. addr_hi/addr_lo coming in are the existing
+ * values that the MSI core has programmed into the card. The
+ * target code is responsible for freeing any resources (if any)
+ * associated with the old address, and generating a new PCI bus
+ * addr_hi/addr_lo that will redirect the vector at the indicated cpu.
+ **/
+
+ void (*target) (unsigned int vector, unsigned int cpu,
+ u32 *addr_hi, u32 *addr_lo);
+};
+
+extern int msi_register(struct msi_ops *ops);
+
#include <asm/msi.h>
/*
@@ -63,67 +125,6 @@ extern int pci_vector_resources(int last, int nr_released);
#define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK)
#define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK)
-/*
- * MSI Defined Data Structures
- */
-#define MSI_ADDRESS_HEADER 0xfee
-#define MSI_ADDRESS_HEADER_SHIFT 12
-#define MSI_ADDRESS_HEADER_MASK 0xfff000
-#define MSI_ADDRESS_DEST_ID_MASK 0xfff0000f
-#define MSI_TARGET_CPU_MASK 0xff
-#define MSI_DELIVERY_MODE 0
-#define MSI_LEVEL_MODE 1 /* Edge always assert */
-#define MSI_TRIGGER_MODE 0 /* MSI is edge sensitive */
-#define MSI_PHYSICAL_MODE 0
-#define MSI_LOGICAL_MODE 1
-#define MSI_REDIRECTION_HINT_MODE 0
-
-struct msg_data {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- __u32 vector : 8;
- __u32 delivery_mode : 3; /* 000b: FIXED | 001b: lowest prior */
- __u32 reserved_1 : 3;
- __u32 level : 1; /* 0: deassert | 1: assert */
- __u32 trigger : 1; /* 0: edge | 1: level */
- __u32 reserved_2 : 16;
-#elif defined(__BIG_ENDIAN_BITFIELD)
- __u32 reserved_2 : 16;
- __u32 trigger : 1; /* 0: edge | 1: level */
- __u32 level : 1; /* 0: deassert | 1: assert */
- __u32 reserved_1 : 3;
- __u32 delivery_mode : 3; /* 000b: FIXED | 001b: lowest prior */
- __u32 vector : 8;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-} __attribute__ ((packed));
-
-struct msg_address {
- union {
- struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- __u32 reserved_1 : 2;
- __u32 dest_mode : 1; /*0:physic | 1:logic */
- __u32 redirection_hint: 1; /*0: dedicated CPU
- 1: lowest priority */
- __u32 reserved_2 : 4;
- __u32 dest_id : 24; /* Destination ID */
-#elif defined(__BIG_ENDIAN_BITFIELD)
- __u32 dest_id : 24; /* Destination ID */
- __u32 reserved_2 : 4;
- __u32 redirection_hint: 1; /*0: dedicated CPU
- 1: lowest priority */
- __u32 dest_mode : 1; /*0:physic | 1:logic */
- __u32 reserved_1 : 2;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
- }u;
- __u32 value;
- }lo_address;
- __u32 hi_address;
-} __attribute__ ((packed));
-
struct msi_desc {
struct {
__u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */
@@ -132,7 +133,7 @@ struct msi_desc {
__u8 reserved: 1; /* reserved */
__u8 entry_nr; /* specific enabled entry */
__u8 default_vector; /* default pre-assigned vector */
- __u8 current_cpu; /* current destination cpu */
+ __u8 unused; /* formerly unused destination cpu*/
}msi_attrib;
struct {
@@ -142,6 +143,14 @@ struct msi_desc {
void __iomem *mask_base;
struct pci_dev *dev;
+
+#ifdef CONFIG_PM
+ /* PM save area for MSIX address/data */
+
+ u32 address_hi_save;
+ u32 address_lo_save;
+ u32 data_save;
+#endif
};
#endif /* MSI_H */
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index c2ecae5..bb7456c 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -267,7 +267,7 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
/* ACPI bus type */
-static int pci_acpi_find_device(struct device *dev, acpi_handle *handle)
+static int acpi_pci_find_device(struct device *dev, acpi_handle *handle)
{
struct pci_dev * pci_dev;
acpi_integer addr;
@@ -281,7 +281,7 @@ static int pci_acpi_find_device(struct device *dev, acpi_handle *handle)
return 0;
}
-static int pci_acpi_find_root_bridge(struct device *dev, acpi_handle *handle)
+static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle)
{
int num;
unsigned int seg, bus;
@@ -299,21 +299,21 @@ static int pci_acpi_find_root_bridge(struct device *dev, acpi_handle *handle)
return 0;
}
-static struct acpi_bus_type pci_acpi_bus = {
+static struct acpi_bus_type acpi_pci_bus = {
.bus = &pci_bus_type,
- .find_device = pci_acpi_find_device,
- .find_bridge = pci_acpi_find_root_bridge,
+ .find_device = acpi_pci_find_device,
+ .find_bridge = acpi_pci_find_root_bridge,
};
-static int __init pci_acpi_init(void)
+static int __init acpi_pci_init(void)
{
int ret;
- ret = register_acpi_bus_type(&pci_acpi_bus);
+ ret = register_acpi_bus_type(&acpi_pci_bus);
if (ret)
return 0;
platform_pci_choose_state = acpi_pci_choose_state;
platform_pci_set_power_state = acpi_pci_set_power_state;
return 0;
}
-arch_initcall(pci_acpi_init);
+arch_initcall(acpi_pci_init);
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 56ac2bc..bc405c0 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -43,6 +43,29 @@ pci_config_attr(subsystem_vendor, "0x%04x\n");
pci_config_attr(subsystem_device, "0x%04x\n");
pci_config_attr(class, "0x%06x\n");
pci_config_attr(irq, "%u\n");
+pci_config_attr(is_enabled, "%u\n");
+
+static ssize_t broken_parity_status_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ return sprintf (buf, "%u\n", pdev->broken_parity_status);
+}
+
+static ssize_t broken_parity_status_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ ssize_t consumed = -EINVAL;
+
+ if ((count > 0) && (*buf == '0' || *buf == '1')) {
+ pdev->broken_parity_status = *buf == '1' ? 1 : 0;
+ consumed = count;
+ }
+ return consumed;
+}
static ssize_t local_cpus_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -90,6 +113,25 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
(u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8),
(u8)(pci_dev->class));
}
+static ssize_t
+is_enabled_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ /* this can crash the machine when done on the "wrong" device */
+ if (!capable(CAP_SYS_ADMIN))
+ return count;
+
+ if (*buf == '0')
+ pci_disable_device(pdev);
+
+ if (*buf == '1')
+ pci_enable_device(pdev);
+
+ return count;
+}
+
struct device_attribute pci_dev_attrs[] = {
__ATTR_RO(resource),
@@ -101,6 +143,9 @@ struct device_attribute pci_dev_attrs[] = {
__ATTR_RO(irq),
__ATTR_RO(local_cpus),
__ATTR_RO(modalias),
+ __ATTR(enable, 0600, is_enabled_show, is_enabled_store),
+ __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR),
+ broken_parity_status_show,broken_parity_status_store),
__ATTR_NULL,
};
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index fde41cc..d408a3c 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -517,7 +517,12 @@ pci_enable_device_bars(struct pci_dev *dev, int bars)
int
pci_enable_device(struct pci_dev *dev)
{
- int err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1);
+ int err;
+
+ if (dev->is_enabled)
+ return 0;
+
+ err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1);
if (err)
return err;
pci_fixup_device(pci_fixup_enable, dev);
@@ -546,7 +551,14 @@ void
pci_disable_device(struct pci_dev *dev)
{
u16 pci_command;
-
+
+ if (dev->msi_enabled)
+ disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI),
+ PCI_CAP_ID_MSI);
+ if (dev->msix_enabled)
+ disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI),
+ PCI_CAP_ID_MSIX);
+
pci_read_config_word(dev, PCI_COMMAND, &pci_command);
if (pci_command & PCI_COMMAND_MASTER) {
pci_command &= ~PCI_COMMAND_MASTER;
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 30630cb..29bdeca 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -40,7 +40,7 @@ extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int
extern void pci_remove_legacy_files(struct pci_bus *bus);
/* Lock for read/write access to pci device and bus lists */
-extern spinlock_t pci_bus_lock;
+extern struct rw_semaphore pci_bus_sem;
#ifdef CONFIG_X86_IO_APIC
extern int pci_msi_quirk;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index a10ed9d..f89dbc3 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -180,25 +180,31 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
res->flags |= pci_calc_resource_flags(l);
if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
== (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
- pci_read_config_dword(dev, reg+4, &l);
+ u32 szhi, lhi;
+ pci_read_config_dword(dev, reg+4, &lhi);
+ pci_write_config_dword(dev, reg+4, ~0);
+ pci_read_config_dword(dev, reg+4, &szhi);
+ pci_write_config_dword(dev, reg+4, lhi);
+ szhi = pci_size(lhi, szhi, 0xffffffff);
next++;
#if BITS_PER_LONG == 64
- res->start |= ((unsigned long) l) << 32;
+ res->start |= ((unsigned long) lhi) << 32;
res->end = res->start + sz;
- pci_write_config_dword(dev, reg+4, ~0);
- pci_read_config_dword(dev, reg+4, &sz);
- pci_write_config_dword(dev, reg+4, l);
- sz = pci_size(l, sz, 0xffffffff);
- if (sz) {
+ if (szhi) {
/* This BAR needs > 4GB? Wow. */
- res->end |= (unsigned long)sz<<32;
+ res->end |= (unsigned long)szhi<<32;
}
#else
- if (l) {
- printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", pci_name(dev));
+ if (szhi) {
+ printk(KERN_ERR "PCI: Unable to handle 64-bit BAR for device %s\n", pci_name(dev));
res->start = 0;
res->flags = 0;
- continue;
+ } else if (lhi) {
+ /* 64-bit wide address, treat as disabled */
+ pci_write_config_dword(dev, reg, l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK);
+ pci_write_config_dword(dev, reg+4, 0);
+ res->start = 0;
+ res->end = sz;
}
#endif
}
@@ -377,9 +383,9 @@ struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_de
child = pci_alloc_child_bus(parent, dev, busnr);
if (child) {
- spin_lock(&pci_bus_lock);
+ down_write(&pci_bus_sem);
list_add_tail(&child->node, &parent->children);
- spin_unlock(&pci_bus_lock);
+ up_write(&pci_bus_sem);
}
return child;
}
@@ -838,9 +844,9 @@ void __devinit pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
* and the bus list for fixup functions, etc.
*/
INIT_LIST_HEAD(&dev->global_list);
- spin_lock(&pci_bus_lock);
+ down_write(&pci_bus_sem);
list_add_tail(&dev->bus_list, &bus->devices);
- spin_unlock(&pci_bus_lock);
+ up_write(&pci_bus_sem);
}
struct pci_dev * __devinit
@@ -975,9 +981,10 @@ struct pci_bus * __devinit pci_create_bus(struct device *parent,
pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus);
goto err_out;
}
- spin_lock(&pci_bus_lock);
+
+ down_write(&pci_bus_sem);
list_add_tail(&b->node, &pci_root_buses);
- spin_unlock(&pci_bus_lock);
+ up_write(&pci_bus_sem);
memset(dev, 0, sizeof(*dev));
dev->parent = parent;
@@ -1017,9 +1024,9 @@ class_dev_create_file_err:
class_dev_reg_err:
device_unregister(dev);
dev_reg_err:
- spin_lock(&pci_bus_lock);
+ down_write(&pci_bus_sem);
list_del(&b->node);
- spin_unlock(&pci_bus_lock);
+ up_write(&pci_bus_sem);
err_out:
kfree(dev);
kfree(b);
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index d378478..4364d79 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -24,6 +24,17 @@
#include <linux/acpi.h>
#include "pci.h"
+/* The Mellanox Tavor device gives false positive parity errors
+ * Mark this device with a broken_parity_status, to allow
+ * PCI scanning code to "skip" this now blacklisted device.
+ */
+static void __devinit quirk_mellanox_tavor(struct pci_dev *dev)
+{
+ dev->broken_parity_status = 1; /* This device gives false positives */
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX,PCI_DEVICE_ID_MELLANOX_TAVOR,quirk_mellanox_tavor);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX,PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE,quirk_mellanox_tavor);
+
/* Deal with broken BIOS'es that neglect to enable passive release,
which can cause problems in combination with the 82441FX/PPro MTRRs */
static void __devinit quirk_passive_release(struct pci_dev *dev)
@@ -878,27 +889,30 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_e
* when a PCI-Soundcard is added. The BIOS only gives Options
* "Disabled" and "AUTO". This Quirk Sets the corresponding
* Register-Value to enable the Soundcard.
+ *
+ * FIXME: Presently this quirk will run on anything that has an 8237
+ * which isn't correct, we need to check DMI tables or something in
+ * order to make sure it only runs on the MSI-K8T-Neo2Fir. Because it
+ * runs everywhere at present we suppress the printk output in most
+ * irrelevant cases.
*/
static void __init k8t_sound_hostbridge(struct pci_dev *dev)
{
unsigned char val;
- printk(KERN_INFO "PCI: Quirk-MSI-K8T Soundcard On\n");
pci_read_config_byte(dev, 0x50, &val);
if (val == 0x88 || val == 0xc8) {
+ /* Assume it's probably a MSI-K8T-Neo2Fir */
+ printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, attempting to turn soundcard ON\n");
pci_write_config_byte(dev, 0x50, val & (~0x40));
/* Verify the Change for Status output */
pci_read_config_byte(dev, 0x50, &val);
if (val & 0x40)
- printk(KERN_INFO "PCI: MSI-K8T soundcard still off\n");
+ printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard still off\n");
else
- printk(KERN_INFO "PCI: MSI-K8T soundcard on\n");
- } else {
- printk(KERN_INFO "PCI: Unexpected Value in PCI-Register: "
- "no Change!\n");
+ printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard on\n");
}
-
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge);
@@ -1485,6 +1499,25 @@ static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io);
+/* Under some circumstances, AER is not linked with extended capabilities.
+ * Force it to be linked by setting the corresponding control bit in the
+ * config space.
+ */
+static void __devinit quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev)
+{
+ uint8_t b;
+ if (pci_read_config_byte(dev, 0xf41, &b) == 0) {
+ if (!(b & 0x20)) {
+ pci_write_config_byte(dev, 0xf41, b | 0x20);
+ printk(KERN_INFO
+ "PCI: Linking AER extended capability on %s\n",
+ pci_name(dev));
+ }
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
+ quirk_nvidia_ck804_pcie_aer_ext_cap);
+
EXPORT_SYMBOL(pcie_mch_quirk);
#ifdef CONFIG_HOTPLUG
EXPORT_SYMBOL(pci_fixup_device);
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 1a6bf9d..99ffbd4 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -22,18 +22,18 @@ static void pci_destroy_dev(struct pci_dev *dev)
pci_proc_detach_device(dev);
pci_remove_sysfs_dev_files(dev);
device_unregister(&dev->dev);
- spin_lock(&pci_bus_lock);
+ down_write(&pci_bus_sem);
list_del(&dev->global_list);
dev->global_list.next = dev->global_list.prev = NULL;
- spin_unlock(&pci_bus_lock);
+ up_write(&pci_bus_sem);
}
/* Remove the device from the device lists, and prevent any further
* list accesses from this device */
- spin_lock(&pci_bus_lock);
+ down_write(&pci_bus_sem);
list_del(&dev->bus_list);
dev->bus_list.next = dev->bus_list.prev = NULL;
- spin_unlock(&pci_bus_lock);
+ up_write(&pci_bus_sem);
pci_free_resources(dev);
pci_dev_put(dev);
@@ -62,9 +62,9 @@ void pci_remove_bus(struct pci_bus *pci_bus)
{
pci_proc_detach_bus(pci_bus);
- spin_lock(&pci_bus_lock);
+ down_write(&pci_bus_sem);
list_del(&pci_bus->node);
- spin_unlock(&pci_bus_lock);
+ up_write(&pci_bus_sem);
pci_remove_legacy_files(pci_bus);
class_device_remove_file(&pci_bus->class_dev,
&class_device_attr_cpuaffinity);
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index ce7dd6e..622b3f8 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -13,7 +13,7 @@
#include <linux/interrupt.h>
#include "pci.h"
-DEFINE_SPINLOCK(pci_bus_lock);
+DECLARE_RWSEM(pci_bus_sem);
static struct pci_bus * __devinit
pci_do_find_bus(struct pci_bus* bus, unsigned char busnr)
@@ -72,11 +72,11 @@ pci_find_next_bus(const struct pci_bus *from)
struct pci_bus *b = NULL;
WARN_ON(in_interrupt());
- spin_lock(&pci_bus_lock);
+ down_read(&pci_bus_sem);
n = from ? from->node.next : pci_root_buses.next;
if (n != &pci_root_buses)
b = pci_bus_b(n);
- spin_unlock(&pci_bus_lock);
+ up_read(&pci_bus_sem);
return b;
}
@@ -124,7 +124,7 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn)
struct pci_dev *dev;
WARN_ON(in_interrupt());
- spin_lock(&pci_bus_lock);
+ down_read(&pci_bus_sem);
list_for_each(tmp, &bus->devices) {
dev = pci_dev_b(tmp);
@@ -135,7 +135,7 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn)
dev = NULL;
out:
pci_dev_get(dev);
- spin_unlock(&pci_bus_lock);
+ up_read(&pci_bus_sem);
return dev;
}
@@ -167,7 +167,7 @@ static struct pci_dev * pci_find_subsys(unsigned int vendor,
struct pci_dev *dev;
WARN_ON(in_interrupt());
- spin_lock(&pci_bus_lock);
+ down_read(&pci_bus_sem);
n = from ? from->global_list.next : pci_devices.next;
while (n && (n != &pci_devices)) {
@@ -181,7 +181,7 @@ static struct pci_dev * pci_find_subsys(unsigned int vendor,
}
dev = NULL;
exit:
- spin_unlock(&pci_bus_lock);
+ up_read(&pci_bus_sem);
return dev;
}
@@ -232,7 +232,7 @@ pci_get_subsys(unsigned int vendor, unsigned int device,
struct pci_dev *dev;
WARN_ON(in_interrupt());
- spin_lock(&pci_bus_lock);
+ down_read(&pci_bus_sem);
n = from ? from->global_list.next : pci_devices.next;
while (n && (n != &pci_devices)) {
@@ -247,7 +247,7 @@ pci_get_subsys(unsigned int vendor, unsigned int device,
dev = NULL;
exit:
dev = pci_dev_get(dev);
- spin_unlock(&pci_bus_lock);
+ up_read(&pci_bus_sem);
pci_dev_put(from);
return dev;
}
@@ -292,7 +292,7 @@ pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct p
struct pci_dev *dev;
WARN_ON(in_interrupt());
- spin_lock(&pci_bus_lock);
+ down_read(&pci_bus_sem);
n = from ? from->global_list.prev : pci_devices.prev;
while (n && (n != &pci_devices)) {
@@ -304,7 +304,7 @@ pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct p
}
dev = NULL;
exit:
- spin_unlock(&pci_bus_lock);
+ up_read(&pci_bus_sem);
return dev;
}
@@ -328,7 +328,7 @@ struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from)
struct pci_dev *dev;
WARN_ON(in_interrupt());
- spin_lock(&pci_bus_lock);
+ down_read(&pci_bus_sem);
n = from ? from->global_list.next : pci_devices.next;
while (n && (n != &pci_devices)) {
@@ -340,7 +340,7 @@ struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from)
dev = NULL;
exit:
dev = pci_dev_get(dev);
- spin_unlock(&pci_bus_lock);
+ up_read(&pci_bus_sem);
pci_dev_put(from);
return dev;
}
@@ -362,7 +362,7 @@ int pci_dev_present(const struct pci_device_id *ids)
int found = 0;
WARN_ON(in_interrupt());
- spin_lock(&pci_bus_lock);
+ down_read(&pci_bus_sem);
while (ids->vendor || ids->subvendor || ids->class_mask) {
list_for_each_entry(dev, &pci_devices, global_list) {
if (pci_match_one_device(ids, dev)) {
@@ -372,8 +372,8 @@ int pci_dev_present(const struct pci_device_id *ids)
}
ids++;
}
-exit:
- spin_unlock(&pci_bus_lock);
+exit:
+ up_read(&pci_bus_sem);
return found;
}
EXPORT_SYMBOL(pci_dev_present);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 28ce3a7..35086e8 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -55,9 +55,10 @@ pbus_assign_resources_sorted(struct pci_bus *bus)
list_for_each_entry(dev, &bus->devices, bus_list) {
u16 class = dev->class >> 8;
- /* Don't touch classless devices and host bridges. */
+ /* Don't touch classless devices or host bridges or ioapics. */
if (class == PCI_CLASS_NOT_DEFINED ||
- class == PCI_CLASS_BRIDGE_HOST)
+ class == PCI_CLASS_BRIDGE_HOST ||
+ class == PCI_CLASS_SYSTEM_PIC)
continue;
pdev_sort_resources(dev, &head);
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index ea9277b..577f4b5 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -155,6 +155,46 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
return ret;
}
+#ifdef CONFIG_EMBEDDED
+int pci_assign_resource_fixed(struct pci_dev *dev, int resno)
+{
+ struct pci_bus *bus = dev->bus;
+ struct resource *res = dev->resource + resno;
+ unsigned int type_mask;
+ int i, ret = -EBUSY;
+
+ type_mask = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH;
+
+ for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
+ struct resource *r = bus->resource[i];
+ if (!r)
+ continue;
+
+ /* type_mask must match */
+ if ((res->flags ^ r->flags) & type_mask)
+ continue;
+
+ ret = request_resource(r, res);
+
+ if (ret == 0)
+ break;
+ }
+
+ if (ret) {
+ printk(KERN_ERR "PCI: Failed to allocate %s resource "
+ "#%d:%llx@%llx for %s\n",
+ res->flags & IORESOURCE_IO ? "I/O" : "mem",
+ resno, (unsigned long long)(res->end - res->start + 1),
+ (unsigned long long)res->start, pci_name(dev));
+ } else if (resno < PCI_BRIDGE_RESOURCES) {
+ pci_update_resource(dev, res, resno);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pci_assign_resource_fixed);
+#endif
+
/* Sort resources by alignment */
void __devinit
pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c
index bb19c64..0b4adcb 100644
--- a/drivers/pnp/card.c
+++ b/drivers/pnp/card.c
@@ -60,30 +60,34 @@ static void card_remove_first(struct pnp_dev * dev)
card_remove(dev);
}
-static int card_probe(struct pnp_card * card, struct pnp_card_driver * drv)
+static int card_probe(struct pnp_card *card, struct pnp_card_driver *drv)
{
- const struct pnp_card_device_id *id = match_card(drv,card);
- if (id) {
- struct pnp_card_link * clink = pnp_alloc(sizeof(struct pnp_card_link));
- if (!clink)
- return 0;
- clink->card = card;
- clink->driver = drv;
- clink->pm_state = PMSG_ON;
- if (drv->probe) {
- if (drv->probe(clink, id)>=0)
- return 1;
- else {
- struct pnp_dev * dev;
- card_for_each_dev(card, dev) {
- if (dev->card_link == clink)
- pnp_release_card_device(dev);
- }
- kfree(clink);
- }
- } else
- return 1;
+ const struct pnp_card_device_id *id;
+ struct pnp_card_link *clink;
+ struct pnp_dev *dev;
+
+ if (!drv->probe)
+ return 0;
+ id = match_card(drv,card);
+ if (!id)
+ return 0;
+
+ clink = pnp_alloc(sizeof(*clink));
+ if (!clink)
+ return 0;
+ clink->card = card;
+ clink->driver = drv;
+ clink->pm_state = PMSG_ON;
+
+ if (drv->probe(clink, id) >= 0)
+ return 1;
+
+ /* Recovery */
+ card_for_each_dev(card, dev) {
+ if (dev->card_link == clink)
+ pnp_release_card_device(dev);
}
+ kfree(clink);
return 0;
}
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 407b4ea..3a4a644 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -36,13 +36,13 @@ static int irq_flags(int triggering, int polarity)
{
int flag;
if (triggering == ACPI_LEVEL_SENSITIVE) {
- if(polarity == ACPI_ACTIVE_LOW)
+ if (polarity == ACPI_ACTIVE_LOW)
flag = IORESOURCE_IRQ_LOWLEVEL;
else
flag = IORESOURCE_IRQ_HIGHLEVEL;
}
else {
- if(polarity == ACPI_ACTIVE_LOW)
+ if (polarity == ACPI_ACTIVE_LOW)
flag = IORESOURCE_IRQ_LOWEDGE;
else
flag = IORESOURCE_IRQ_HIGHEDGE;
@@ -57,7 +57,7 @@ static void decode_irq_flags(int flag, int *triggering, int *polarity)
*triggering = ACPI_LEVEL_SENSITIVE;
*polarity = ACPI_ACTIVE_LOW;
break;
- case IORESOURCE_IRQ_HIGHLEVEL:
+ case IORESOURCE_IRQ_HIGHLEVEL:
*triggering = ACPI_LEVEL_SENSITIVE;
*polarity = ACPI_ACTIVE_HIGH;
break;
@@ -73,7 +73,7 @@ static void decode_irq_flags(int flag, int *triggering, int *polarity)
}
static void
-pnpacpi_parse_allocated_irqresource(struct pnp_resource_table * res, u32 gsi,
+pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res, u32 gsi,
int triggering, int polarity)
{
int i = 0;
@@ -101,7 +101,7 @@ pnpacpi_parse_allocated_irqresource(struct pnp_resource_table * res, u32 gsi,
}
static void
-pnpacpi_parse_allocated_dmaresource(struct pnp_resource_table * res, u32 dma)
+pnpacpi_parse_allocated_dmaresource(struct pnp_resource_table *res, u32 dma)
{
int i = 0;
while (i < PNP_MAX_DMA &&
@@ -119,8 +119,8 @@ pnpacpi_parse_allocated_dmaresource(struct pnp_resource_table * res, u32 dma)
}
static void
-pnpacpi_parse_allocated_ioresource(struct pnp_resource_table * res,
- u32 io, u32 len)
+pnpacpi_parse_allocated_ioresource(struct pnp_resource_table *res,
+ u64 io, u64 len)
{
int i = 0;
while (!(res->port_resource[i].flags & IORESOURCE_UNSET) &&
@@ -138,7 +138,7 @@ pnpacpi_parse_allocated_ioresource(struct pnp_resource_table * res,
}
static void
-pnpacpi_parse_allocated_memresource(struct pnp_resource_table * res,
+pnpacpi_parse_allocated_memresource(struct pnp_resource_table *res,
u64 mem, u64 len)
{
int i = 0;
@@ -156,11 +156,32 @@ pnpacpi_parse_allocated_memresource(struct pnp_resource_table * res,
}
}
+static void
+pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res_table,
+ struct acpi_resource *res)
+{
+ struct acpi_resource_address64 addr, *p = &addr;
+ acpi_status status;
+
+ status = acpi_resource_to_address64(res, p);
+ if (!ACPI_SUCCESS(status)) {
+ pnp_warn("PnPACPI: failed to convert resource type %d",
+ res->type);
+ return;
+ }
+
+ if (p->resource_type == ACPI_MEMORY_RANGE)
+ pnpacpi_parse_allocated_memresource(res_table,
+ p->minimum, p->address_length);
+ else if (p->resource_type == ACPI_IO_RANGE)
+ pnpacpi_parse_allocated_ioresource(res_table,
+ p->minimum, p->address_length);
+}
static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
void *data)
{
- struct pnp_resource_table * res_table = (struct pnp_resource_table *)data;
+ struct pnp_resource_table *res_table = (struct pnp_resource_table *)data;
int i;
switch (res->type) {
@@ -221,19 +242,9 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
res->data.fixed_memory32.address_length);
break;
case ACPI_RESOURCE_TYPE_ADDRESS16:
- pnpacpi_parse_allocated_memresource(res_table,
- res->data.address16.minimum,
- res->data.address16.address_length);
- break;
case ACPI_RESOURCE_TYPE_ADDRESS32:
- pnpacpi_parse_allocated_memresource(res_table,
- res->data.address32.minimum,
- res->data.address32.address_length);
- break;
case ACPI_RESOURCE_TYPE_ADDRESS64:
- pnpacpi_parse_allocated_memresource(res_table,
- res->data.address64.minimum,
- res->data.address64.address_length);
+ pnpacpi_parse_allocated_address_space(res_table, res);
break;
case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
@@ -255,11 +266,11 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
pnp_warn("PnPACPI: unknown resource type %d", res->type);
return AE_ERROR;
}
-
+
return AE_OK;
}
-acpi_status pnpacpi_parse_allocated_resource(acpi_handle handle, struct pnp_resource_table * res)
+acpi_status pnpacpi_parse_allocated_resource(acpi_handle handle, struct pnp_resource_table *res)
{
/* Blank the resource table values */
pnp_init_resource_table(res);
@@ -317,17 +328,17 @@ static void pnpacpi_parse_dma_option(struct pnp_option *option, struct acpi_reso
pnp_err("Invalid DMA transfer type");
}
- pnp_register_dma_resource(option,dma);
+ pnp_register_dma_resource(option, dma);
return;
}
-
+
static void pnpacpi_parse_irq_option(struct pnp_option *option,
struct acpi_resource_irq *p)
{
int i;
- struct pnp_irq * irq;
-
+ struct pnp_irq *irq;
+
if (p->interrupt_count == 0)
return;
irq = kcalloc(1, sizeof(struct pnp_irq), GFP_KERNEL);
@@ -347,7 +358,7 @@ static void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
struct acpi_resource_extended_irq *p)
{
int i;
- struct pnp_irq * irq;
+ struct pnp_irq *irq;
if (p->interrupt_count == 0)
return;
@@ -368,7 +379,7 @@ static void
pnpacpi_parse_port_option(struct pnp_option *option,
struct acpi_resource_io *io)
{
- struct pnp_port * port;
+ struct pnp_port *port;
if (io->address_length == 0)
return;
@@ -381,7 +392,7 @@ pnpacpi_parse_port_option(struct pnp_option *option,
port->size = io->address_length;
port->flags = ACPI_DECODE_16 == io->io_decode ?
PNP_PORT_FLAG_16BITADDR : 0;
- pnp_register_port_resource(option,port);
+ pnp_register_port_resource(option, port);
return;
}
@@ -389,7 +400,7 @@ static void
pnpacpi_parse_fixed_port_option(struct pnp_option *option,
struct acpi_resource_fixed_io *io)
{
- struct pnp_port * port;
+ struct pnp_port *port;
if (io->address_length == 0)
return;
@@ -400,7 +411,7 @@ pnpacpi_parse_fixed_port_option(struct pnp_option *option,
port->size = io->address_length;
port->align = 0;
port->flags = PNP_PORT_FLAG_FIXED;
- pnp_register_port_resource(option,port);
+ pnp_register_port_resource(option, port);
return;
}
@@ -408,7 +419,7 @@ static void
pnpacpi_parse_mem24_option(struct pnp_option *option,
struct acpi_resource_memory24 *p)
{
- struct pnp_mem * mem;
+ struct pnp_mem *mem;
if (p->address_length == 0)
return;
@@ -423,7 +434,7 @@ pnpacpi_parse_mem24_option(struct pnp_option *option,
mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
IORESOURCE_MEM_WRITEABLE : 0;
- pnp_register_mem_resource(option,mem);
+ pnp_register_mem_resource(option, mem);
return;
}
@@ -431,7 +442,7 @@ static void
pnpacpi_parse_mem32_option(struct pnp_option *option,
struct acpi_resource_memory32 *p)
{
- struct pnp_mem * mem;
+ struct pnp_mem *mem;
if (p->address_length == 0)
return;
@@ -446,7 +457,7 @@ pnpacpi_parse_mem32_option(struct pnp_option *option,
mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
IORESOURCE_MEM_WRITEABLE : 0;
- pnp_register_mem_resource(option,mem);
+ pnp_register_mem_resource(option, mem);
return;
}
@@ -454,7 +465,7 @@ static void
pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
struct acpi_resource_fixed_memory32 *p)
{
- struct pnp_mem * mem;
+ struct pnp_mem *mem;
if (p->address_length == 0)
return;
@@ -468,7 +479,7 @@ pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
IORESOURCE_MEM_WRITEABLE : 0;
- pnp_register_mem_resource(option,mem);
+ pnp_register_mem_resource(option, mem);
return;
}
@@ -477,8 +488,8 @@ pnpacpi_parse_address_option(struct pnp_option *option, struct acpi_resource *r)
{
struct acpi_resource_address64 addr, *p = &addr;
acpi_status status;
- struct pnp_mem * mem;
- struct pnp_port * port;
+ struct pnp_mem *mem;
+ struct pnp_port *port;
status = acpi_resource_to_address64(r, p);
if (!ACPI_SUCCESS(status)) {
@@ -498,7 +509,7 @@ pnpacpi_parse_address_option(struct pnp_option *option, struct acpi_resource *r)
mem->align = 0;
mem->flags = (p->info.mem.write_protect ==
ACPI_READ_WRITE_MEMORY) ? IORESOURCE_MEM_WRITEABLE : 0;
- pnp_register_mem_resource(option,mem);
+ pnp_register_mem_resource(option, mem);
} else if (p->resource_type == ACPI_IO_RANGE) {
port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
@@ -507,7 +518,7 @@ pnpacpi_parse_address_option(struct pnp_option *option, struct acpi_resource *r)
port->size = p->address_length;
port->align = 0;
port->flags = PNP_PORT_FLAG_FIXED;
- pnp_register_port_resource(option,port);
+ pnp_register_port_resource(option, port);
}
}
@@ -531,7 +542,7 @@ static acpi_status pnpacpi_option_resource(struct acpi_resource *res,
break;
case ACPI_RESOURCE_TYPE_DMA:
- pnpacpi_parse_dma_option(option, &res->data.dma);
+ pnpacpi_parse_dma_option(option, &res->data.dma);
break;
case ACPI_RESOURCE_TYPE_START_DEPENDENT:
@@ -539,7 +550,7 @@ static acpi_status pnpacpi_option_resource(struct acpi_resource *res,
case ACPI_GOOD_CONFIGURATION:
priority = PNP_RES_PRIORITY_PREFERRED;
break;
-
+
case ACPI_ACCEPTABLE_CONFIGURATION:
priority = PNP_RES_PRIORITY_ACCEPTABLE;
break;
@@ -555,7 +566,7 @@ static acpi_status pnpacpi_option_resource(struct acpi_resource *res,
option = pnp_register_dependent_option(dev, priority);
if (!option)
return AE_ERROR;
- parse_data->option = option;
+ parse_data->option = option;
break;
case ACPI_RESOURCE_TYPE_END_DEPENDENT:
@@ -615,7 +626,7 @@ static acpi_status pnpacpi_option_resource(struct acpi_resource *res,
pnp_warn("PnPACPI: unknown resource type %d", res->type);
return AE_ERROR;
}
-
+
return AE_OK;
}
@@ -636,13 +647,8 @@ acpi_status pnpacpi_parse_resource_option_data(acpi_handle handle,
return status;
}
-/*
- * Set resource
- */
-static acpi_status pnpacpi_count_resources(struct acpi_resource *res,
- void *data)
+static int pnpacpi_supported_resource(struct acpi_resource *res)
{
- int *res_cnt = (int *)data;
switch (res->type) {
case ACPI_RESOURCE_TYPE_IRQ:
case ACPI_RESOURCE_TYPE_DMA:
@@ -655,43 +661,32 @@ static acpi_status pnpacpi_count_resources(struct acpi_resource *res,
case ACPI_RESOURCE_TYPE_ADDRESS32:
case ACPI_RESOURCE_TYPE_ADDRESS64:
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
- (*res_cnt) ++;
- case ACPI_RESOURCE_TYPE_START_DEPENDENT:
- case ACPI_RESOURCE_TYPE_END_DEPENDENT:
- case ACPI_RESOURCE_TYPE_VENDOR:
- case ACPI_RESOURCE_TYPE_END_TAG:
- case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
- default:
- return AE_OK;
+ return 1;
}
- return AE_OK;
+ return 0;
}
-static acpi_status pnpacpi_type_resources(struct acpi_resource *res,
+/*
+ * Set resource
+ */
+static acpi_status pnpacpi_count_resources(struct acpi_resource *res,
void *data)
{
- struct acpi_resource **resource = (struct acpi_resource **)data;
- switch (res->type) {
- case ACPI_RESOURCE_TYPE_IRQ:
- case ACPI_RESOURCE_TYPE_DMA:
- case ACPI_RESOURCE_TYPE_IO:
- case ACPI_RESOURCE_TYPE_FIXED_IO:
- case ACPI_RESOURCE_TYPE_MEMORY24:
- case ACPI_RESOURCE_TYPE_MEMORY32:
- case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
- case ACPI_RESOURCE_TYPE_ADDRESS16:
- case ACPI_RESOURCE_TYPE_ADDRESS32:
- case ACPI_RESOURCE_TYPE_ADDRESS64:
- case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+ int *res_cnt = (int *)data;
+
+ if (pnpacpi_supported_resource(res))
+ (*res_cnt)++;
+ return AE_OK;
+}
+
+static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data)
+{
+ struct acpi_resource **resource = (struct acpi_resource **)data;
+
+ if (pnpacpi_supported_resource(res)) {
(*resource)->type = res->type;
+ (*resource)->length = sizeof(struct acpi_resource);
(*resource)++;
- case ACPI_RESOURCE_TYPE_START_DEPENDENT:
- case ACPI_RESOURCE_TYPE_END_DEPENDENT:
- case ACPI_RESOURCE_TYPE_VENDOR:
- case ACPI_RESOURCE_TYPE_END_TAG:
- case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
- default:
- return AE_OK;
}
return AE_OK;
@@ -735,11 +730,8 @@ static void pnpacpi_encode_irq(struct acpi_resource *resource,
struct resource *p)
{
int triggering, polarity;
-
- decode_irq_flags(p->flags & IORESOURCE_BITS, &triggering,
- &polarity);
- resource->type = ACPI_RESOURCE_TYPE_IRQ;
- resource->length = sizeof(struct acpi_resource);
+
+ decode_irq_flags(p->flags & IORESOURCE_BITS, &triggering, &polarity);
resource->data.irq.triggering = triggering;
resource->data.irq.polarity = polarity;
if (triggering == ACPI_EDGE_SENSITIVE)
@@ -754,11 +746,8 @@ static void pnpacpi_encode_ext_irq(struct acpi_resource *resource,
struct resource *p)
{
int triggering, polarity;
-
- decode_irq_flags(p->flags & IORESOURCE_BITS, &triggering,
- &polarity);
- resource->type = ACPI_RESOURCE_TYPE_EXTENDED_IRQ;
- resource->length = sizeof(struct acpi_resource);
+
+ decode_irq_flags(p->flags & IORESOURCE_BITS, &triggering, &polarity);
resource->data.extended_irq.producer_consumer = ACPI_CONSUMER;
resource->data.extended_irq.triggering = triggering;
resource->data.extended_irq.polarity = polarity;
@@ -773,8 +762,6 @@ static void pnpacpi_encode_ext_irq(struct acpi_resource *resource,
static void pnpacpi_encode_dma(struct acpi_resource *resource,
struct resource *p)
{
- resource->type = ACPI_RESOURCE_TYPE_DMA;
- resource->length = sizeof(struct acpi_resource);
/* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */
if (p->flags & IORESOURCE_DMA_COMPATIBLE)
resource->data.dma.type = ACPI_COMPATIBILITY;
@@ -798,8 +785,6 @@ static void pnpacpi_encode_dma(struct acpi_resource *resource,
static void pnpacpi_encode_io(struct acpi_resource *resource,
struct resource *p)
{
- resource->type = ACPI_RESOURCE_TYPE_IO;
- resource->length = sizeof(struct acpi_resource);
/* Note: pnp_assign_port will copy pnp_port->flags into p->flags */
resource->data.io.io_decode = (p->flags & PNP_PORT_FLAG_16BITADDR)?
ACPI_DECODE_16 : ACPI_DECODE_10;
@@ -812,8 +797,6 @@ static void pnpacpi_encode_io(struct acpi_resource *resource,
static void pnpacpi_encode_fixed_io(struct acpi_resource *resource,
struct resource *p)
{
- resource->type = ACPI_RESOURCE_TYPE_FIXED_IO;
- resource->length = sizeof(struct acpi_resource);
resource->data.fixed_io.address = p->start;
resource->data.fixed_io.address_length = p->end - p->start + 1;
}
@@ -821,8 +804,6 @@ static void pnpacpi_encode_fixed_io(struct acpi_resource *resource,
static void pnpacpi_encode_mem24(struct acpi_resource *resource,
struct resource *p)
{
- resource->type = ACPI_RESOURCE_TYPE_MEMORY24;
- resource->length = sizeof(struct acpi_resource);
/* Note: pnp_assign_mem will copy pnp_mem->flags into p->flags */
resource->data.memory24.write_protect =
(p->flags & IORESOURCE_MEM_WRITEABLE) ?
@@ -836,8 +817,6 @@ static void pnpacpi_encode_mem24(struct acpi_resource *resource,
static void pnpacpi_encode_mem32(struct acpi_resource *resource,
struct resource *p)
{
- resource->type = ACPI_RESOURCE_TYPE_MEMORY32;
- resource->length = sizeof(struct acpi_resource);
resource->data.memory32.write_protect =
(p->flags & IORESOURCE_MEM_WRITEABLE) ?
ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
@@ -850,8 +829,6 @@ static void pnpacpi_encode_mem32(struct acpi_resource *resource,
static void pnpacpi_encode_fixed_mem32(struct acpi_resource *resource,
struct resource *p)
{
- resource->type = ACPI_RESOURCE_TYPE_FIXED_MEMORY32;
- resource->length = sizeof(struct acpi_resource);
resource->data.fixed_memory32.write_protect =
(p->flags & IORESOURCE_MEM_WRITEABLE) ?
ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
@@ -882,37 +859,37 @@ int pnpacpi_encode_resources(struct pnp_resource_table *res_table,
pnp_dbg("Encode dma");
pnpacpi_encode_dma(resource,
&res_table->dma_resource[dma]);
- dma ++;
+ dma++;
break;
case ACPI_RESOURCE_TYPE_IO:
pnp_dbg("Encode io");
pnpacpi_encode_io(resource,
&res_table->port_resource[port]);
- port ++;
+ port++;
break;
case ACPI_RESOURCE_TYPE_FIXED_IO:
pnp_dbg("Encode fixed io");
pnpacpi_encode_fixed_io(resource,
&res_table->port_resource[port]);
- port ++;
+ port++;
break;
case ACPI_RESOURCE_TYPE_MEMORY24:
pnp_dbg("Encode mem24");
pnpacpi_encode_mem24(resource,
&res_table->mem_resource[mem]);
- mem ++;
+ mem++;
break;
case ACPI_RESOURCE_TYPE_MEMORY32:
pnp_dbg("Encode mem32");
pnpacpi_encode_mem32(resource,
&res_table->mem_resource[mem]);
- mem ++;
+ mem++;
break;
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
pnp_dbg("Encode fixed mem32");
pnpacpi_encode_fixed_mem32(resource,
&res_table->mem_resource[mem]);
- mem ++;
+ mem++;
break;
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
pnp_dbg("Encode ext irq");
@@ -933,8 +910,8 @@ int pnpacpi_encode_resources(struct pnp_resource_table *res_table,
pnp_warn("unknown resource type %d", resource->type);
return -EINVAL;
}
- resource ++;
- i ++;
+ resource++;
+ i++;
}
return 0;
}
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 65d090d..bccff40 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -73,6 +73,13 @@ config RTC_INTF_DEV
This driver can also be built as a module. If so, the module
will be called rtc-dev.
+config RTC_INTF_DEV_UIE_EMUL
+ bool "RTC UIE emulation on dev interface"
+ depends on RTC_INTF_DEV
+ help
+ Provides an emulation for RTC_UIE if the underlaying rtc chip
+ driver did not provide RTC_UIE ioctls.
+
comment "RTC drivers"
depends on RTC_CLASS
@@ -86,6 +93,34 @@ config RTC_DRV_X1205
This driver can also be built as a module. If so, the module
will be called rtc-x1205.
+config RTC_DRV_DS1307
+ tristate "Dallas/Maxim DS1307 and similar I2C RTC chips"
+ depends on RTC_CLASS && I2C
+ help
+ If you say yes here you get support for various compatible RTC
+ chips (often with battery backup) connected with I2C. This driver
+ should handle DS1307, DS1337, DS1338, DS1339, DS1340, ST M41T00,
+ and probably other chips. In some cases the RTC must already
+ have been initialized (by manufacturing or a bootloader).
+
+ The first seven registers on these chips hold an RTC, and other
+ registers may add features such as NVRAM, a trickle charger for
+ the RTC/NVRAM backup power, and alarms. This driver may not
+ expose all those available chip features.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ds1307.
+
+config RTC_DRV_DS1553
+ tristate "Dallas DS1553"
+ depends on RTC_CLASS
+ help
+ If you say yes here you get support for the
+ Dallas DS1553 timekeeping chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ds1553.
+
config RTC_DRV_DS1672
tristate "Dallas/Maxim DS1672"
depends on RTC_CLASS && I2C
@@ -96,6 +131,16 @@ config RTC_DRV_DS1672
This driver can also be built as a module. If so, the module
will be called rtc-ds1672.
+config RTC_DRV_DS1742
+ tristate "Dallas DS1742"
+ depends on RTC_CLASS
+ help
+ If you say yes here you get support for the
+ Dallas DS1742 timekeeping chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ds1742.
+
config RTC_DRV_PCF8563
tristate "Philips PCF8563/Epson RTC8564"
depends on RTC_CLASS && I2C
@@ -107,6 +152,16 @@ config RTC_DRV_PCF8563
This driver can also be built as a module. If so, the module
will be called rtc-pcf8563.
+config RTC_DRV_PCF8583
+ tristate "Philips PCF8583"
+ depends on RTC_CLASS && I2C
+ help
+ If you say yes here you get support for the
+ Philips PCF8583 RTC chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-pcf8583.
+
config RTC_DRV_RS5C372
tristate "Ricoh RS5C372A/B"
depends on RTC_CLASS && I2C
@@ -157,6 +212,22 @@ config RTC_DRV_VR41XX
To compile this driver as a module, choose M here: the
module will be called rtc-vr41xx.
+config RTC_DRV_PL031
+ tristate "ARM AMBA PL031 RTC"
+ depends on RTC_CLASS && ARM_AMBA
+ help
+ If you say Y here you will get access to ARM AMBA
+ PrimeCell PL031 UART found on certain ARM SOCs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rtc-pl031.
+
+config RTC_DRV_AT91
+ tristate "AT91RM9200"
+ depends on RTC_CLASS && ARCH_AT91RM9200
+ help
+ Driver for the Atmel AT91RM9200's internal RTC (Realtime Clock).
+
config RTC_DRV_TEST
tristate "Test driver/device"
depends on RTC_CLASS
@@ -172,4 +243,24 @@ config RTC_DRV_TEST
This driver can also be built as a module. If so, the module
will be called rtc-test.
+config RTC_DRV_MAX6902
+ tristate "Maxim 6902"
+ depends on RTC_CLASS && SPI
+ help
+ If you say yes here you will get support for the
+ Maxim MAX6902 spi RTC chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-max6902.
+
+config RTC_DRV_V3020
+ tristate "EM Microelectronic V3020"
+ depends on RTC_CLASS
+ help
+ If you say yes here you will get support for the
+ EM Microelectronic v3020 RTC chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-v3020.
+
endmenu
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index a9ca0f1..900d210 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -13,10 +13,18 @@ obj-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
+obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
+obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
+obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
+obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
+obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
+obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
+obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
+obj-$(CONFIG_RTC_DRV_AT91) += rtc-at91.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 413c7d5..5396bee 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -69,6 +69,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
rtc->id = id;
rtc->ops = ops;
rtc->owner = owner;
+ rtc->max_user_freq = 64;
rtc->class_dev.dev = dev;
rtc->class_dev.class = rtc_class;
rtc->class_dev.release = rtc_device_release;
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 56e4907..579cd66 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -229,6 +229,9 @@ int rtc_irq_set_state(struct class_device *class_dev, struct rtc_task *task, int
unsigned long flags;
struct rtc_device *rtc = to_rtc_device(class_dev);
+ if (rtc->ops->irq_set_state == NULL)
+ return -ENXIO;
+
spin_lock_irqsave(&rtc->irq_task_lock, flags);
if (rtc->irq_task != task)
err = -ENXIO;
@@ -243,25 +246,12 @@ EXPORT_SYMBOL_GPL(rtc_irq_set_state);
int rtc_irq_set_freq(struct class_device *class_dev, struct rtc_task *task, int freq)
{
- int err = 0, tmp = 0;
+ int err = 0;
unsigned long flags;
struct rtc_device *rtc = to_rtc_device(class_dev);
- /* allowed range is 2-8192 */
- if (freq < 2 || freq > 8192)
- return -EINVAL;
-/*
- FIXME: this does not belong here, will move where appropriate
- at a later stage. It cannot hurt right now, trust me :)
- if ((freq > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE)))
- return -EACCES;
-*/
- /* check if freq is a power of 2 */
- while (freq > (1 << tmp))
- tmp++;
-
- if (freq != (1 << tmp))
- return -EINVAL;
+ if (rtc->ops->irq_set_freq == NULL)
+ return -ENXIO;
spin_lock_irqsave(&rtc->irq_task_lock, flags);
if (rtc->irq_task != task)
diff --git a/drivers/rtc/rtc-at91.c b/drivers/rtc/rtc-at91.c
new file mode 100644
index 0000000..b676f44
--- /dev/null
+++ b/drivers/rtc/rtc-at91.c
@@ -0,0 +1,407 @@
+/*
+ * Real Time Clock interface for Linux on Atmel AT91RM9200
+ *
+ * Copyright (C) 2002 Rick Bronson
+ *
+ * Converted to RTC class model by Andrew Victor
+ *
+ * Ported to Linux 2.6 by Steven Scholz
+ * Based on s3c2410-rtc.c Simtec Electronics
+ *
+ * Based on sa1100-rtc.c by Nils Faerber
+ * Based on rtc.c by Paul Gortmaker
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/completion.h>
+
+#include <asm/uaccess.h>
+#include <asm/rtc.h>
+
+#include <asm/mach/time.h>
+
+
+#define AT91_RTC_FREQ 1
+#define AT91_RTC_EPOCH 1900UL /* just like arch/arm/common/rtctime.c */
+
+static DECLARE_COMPLETION(at91_rtc_updated);
+static unsigned int at91_alarm_year = AT91_RTC_EPOCH;
+
+/*
+ * Decode time/date into rtc_time structure
+ */
+static void at91_rtc_decodetime(unsigned int timereg, unsigned int calreg,
+ struct rtc_time *tm)
+{
+ unsigned int time, date;
+
+ /* must read twice in case it changes */
+ do {
+ time = at91_sys_read(timereg);
+ date = at91_sys_read(calreg);
+ } while ((time != at91_sys_read(timereg)) ||
+ (date != at91_sys_read(calreg)));
+
+ tm->tm_sec = BCD2BIN((time & AT91_RTC_SEC) >> 0);
+ tm->tm_min = BCD2BIN((time & AT91_RTC_MIN) >> 8);
+ tm->tm_hour = BCD2BIN((time & AT91_RTC_HOUR) >> 16);
+
+ /*
+ * The Calendar Alarm register does not have a field for
+ * the year - so these will return an invalid value. When an
+ * alarm is set, at91_alarm_year wille store the current year.
+ */
+ tm->tm_year = BCD2BIN(date & AT91_RTC_CENT) * 100; /* century */
+ tm->tm_year += BCD2BIN((date & AT91_RTC_YEAR) >> 8); /* year */
+
+ tm->tm_wday = BCD2BIN((date & AT91_RTC_DAY) >> 21) - 1; /* day of the week [0-6], Sunday=0 */
+ tm->tm_mon = BCD2BIN((date & AT91_RTC_MONTH) >> 16) - 1;
+ tm->tm_mday = BCD2BIN((date & AT91_RTC_DATE) >> 24);
+}
+
+/*
+ * Read current time and date in RTC
+ */
+static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm)
+{
+ at91_rtc_decodetime(AT91_RTC_TIMR, AT91_RTC_CALR, tm);
+ tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
+ tm->tm_year = tm->tm_year - 1900;
+
+ pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+ 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return 0;
+}
+
+/*
+ * Set current time and date in RTC
+ */
+static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
+{
+ unsigned long cr;
+
+ pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+ 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ /* Stop Time/Calendar from counting */
+ cr = at91_sys_read(AT91_RTC_CR);
+ at91_sys_write(AT91_RTC_CR, cr | AT91_RTC_UPDCAL | AT91_RTC_UPDTIM);
+
+ at91_sys_write(AT91_RTC_IER, AT91_RTC_ACKUPD);
+ wait_for_completion(&at91_rtc_updated); /* wait for ACKUPD interrupt */
+ at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD);
+
+ at91_sys_write(AT91_RTC_TIMR,
+ BIN2BCD(tm->tm_sec) << 0
+ | BIN2BCD(tm->tm_min) << 8
+ | BIN2BCD(tm->tm_hour) << 16);
+
+ at91_sys_write(AT91_RTC_CALR,
+ BIN2BCD((tm->tm_year + 1900) / 100) /* century */
+ | BIN2BCD(tm->tm_year % 100) << 8 /* year */
+ | BIN2BCD(tm->tm_mon + 1) << 16 /* tm_mon starts at zero */
+ | BIN2BCD(tm->tm_wday + 1) << 21 /* day of the week [0-6], Sunday=0 */
+ | BIN2BCD(tm->tm_mday) << 24);
+
+ /* Restart Time/Calendar */
+ cr = at91_sys_read(AT91_RTC_CR);
+ at91_sys_write(AT91_RTC_CR, cr & ~(AT91_RTC_UPDCAL | AT91_RTC_UPDTIM));
+
+ return 0;
+}
+
+/*
+ * Read alarm time and date in RTC
+ */
+static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct rtc_time *tm = &alrm->time;
+
+ at91_rtc_decodetime(AT91_RTC_TIMALR, AT91_RTC_CALALR, tm);
+ tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
+ tm->tm_year = at91_alarm_year - 1900;
+
+ pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+ 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return 0;
+}
+
+/*
+ * Set alarm time and date in RTC
+ */
+static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct rtc_time tm;
+
+ at91_rtc_decodetime(AT91_RTC_TIMR, AT91_RTC_CALR, &tm);
+
+ at91_alarm_year = tm.tm_year;
+
+ tm.tm_hour = alrm->time.tm_hour;
+ tm.tm_min = alrm->time.tm_min;
+ tm.tm_sec = alrm->time.tm_sec;
+
+ at91_sys_write(AT91_RTC_TIMALR,
+ BIN2BCD(tm.tm_sec) << 0
+ | BIN2BCD(tm.tm_min) << 8
+ | BIN2BCD(tm.tm_hour) << 16
+ | AT91_RTC_HOUREN | AT91_RTC_MINEN | AT91_RTC_SECEN);
+ at91_sys_write(AT91_RTC_CALALR,
+ BIN2BCD(tm.tm_mon + 1) << 16 /* tm_mon starts at zero */
+ | BIN2BCD(tm.tm_mday) << 24
+ | AT91_RTC_DATEEN | AT91_RTC_MTHEN);
+
+ pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+ at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
+ tm.tm_min, tm.tm_sec);
+
+ return 0;
+}
+
+/*
+ * Handle commands from user-space
+ */
+static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret = 0;
+
+ pr_debug("%s(): cmd=%08x, arg=%08lx.\n", __FUNCTION__, cmd, arg);
+
+ switch (cmd) {
+ case RTC_AIE_OFF: /* alarm off */
+ at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM);
+ break;
+ case RTC_AIE_ON: /* alarm on */
+ at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM);
+ break;
+ case RTC_UIE_OFF: /* update off */
+ case RTC_PIE_OFF: /* periodic off */
+ at91_sys_write(AT91_RTC_IDR, AT91_RTC_SECEV);
+ break;
+ case RTC_UIE_ON: /* update on */
+ case RTC_PIE_ON: /* periodic on */
+ at91_sys_write(AT91_RTC_IER, AT91_RTC_SECEV);
+ break;
+ case RTC_IRQP_READ: /* read periodic alarm frequency */
+ ret = put_user(AT91_RTC_FREQ, (unsigned long *) arg);
+ break;
+ case RTC_IRQP_SET: /* set periodic alarm frequency */
+ if (arg != AT91_RTC_FREQ)
+ ret = -EINVAL;
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Provide additional RTC information in /proc/driver/rtc
+ */
+static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+ unsigned long imr = at91_sys_read(AT91_RTC_IMR);
+
+ seq_printf(seq, "alarm_IRQ\t: %s\n",
+ (imr & AT91_RTC_ALARM) ? "yes" : "no");
+ seq_printf(seq, "update_IRQ\t: %s\n",
+ (imr & AT91_RTC_ACKUPD) ? "yes" : "no");
+ seq_printf(seq, "periodic_IRQ\t: %s\n",
+ (imr & AT91_RTC_SECEV) ? "yes" : "no");
+ seq_printf(seq, "periodic_freq\t: %ld\n",
+ (unsigned long) AT91_RTC_FREQ);
+
+ return 0;
+}
+
+/*
+ * IRQ handler for the RTC
+ */
+static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ struct platform_device *pdev = dev_id;
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+ unsigned int rtsr;
+ unsigned long events = 0;
+
+ rtsr = at91_sys_read(AT91_RTC_SR) & at91_sys_read(AT91_RTC_IMR);
+ if (rtsr) { /* this interrupt is shared! Is it ours? */
+ if (rtsr & AT91_RTC_ALARM)
+ events |= (RTC_AF | RTC_IRQF);
+ if (rtsr & AT91_RTC_SECEV)
+ events |= (RTC_UF | RTC_IRQF);
+ if (rtsr & AT91_RTC_ACKUPD)
+ complete(&at91_rtc_updated);
+
+ at91_sys_write(AT91_RTC_SCCR, rtsr); /* clear status reg */
+
+ rtc_update_irq(&rtc->class_dev, 1, events);
+
+ pr_debug("%s(): num=%ld, events=0x%02lx\n", __FUNCTION__,
+ events >> 8, events & 0x000000FF);
+
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE; /* not handled */
+}
+
+static struct rtc_class_ops at91_rtc_ops = {
+ .ioctl = at91_rtc_ioctl,
+ .read_time = at91_rtc_readtime,
+ .set_time = at91_rtc_settime,
+ .read_alarm = at91_rtc_readalarm,
+ .set_alarm = at91_rtc_setalarm,
+ .proc = at91_rtc_proc,
+};
+
+/*
+ * Initialize and install RTC driver
+ */
+static int __init at91_rtc_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc;
+ int ret;
+
+ at91_sys_write(AT91_RTC_CR, 0);
+ at91_sys_write(AT91_RTC_MR, 0); /* 24 hour mode */
+
+ /* Disable all interrupts */
+ at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
+ AT91_RTC_SECEV | AT91_RTC_TIMEV |
+ AT91_RTC_CALEV);
+
+ ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt,
+ SA_SHIRQ, "at91_rtc", pdev);
+ if (ret) {
+ printk(KERN_ERR "at91_rtc: IRQ %d already in use.\n",
+ AT91_ID_SYS);
+ return ret;
+ }
+
+ rtc = rtc_device_register(pdev->name, &pdev->dev,
+ &at91_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ free_irq(AT91_ID_SYS, pdev);
+ return PTR_ERR(rtc);
+ }
+ platform_set_drvdata(pdev, rtc);
+
+ printk(KERN_INFO "AT91 Real Time Clock driver.\n");
+ return 0;
+}
+
+/*
+ * Disable and remove the RTC driver
+ */
+static int __devexit at91_rtc_remove(struct platform_device *pdev)
+{
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+
+ /* Disable all interrupts */
+ at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
+ AT91_RTC_SECEV | AT91_RTC_TIMEV |
+ AT91_RTC_CALEV);
+ free_irq(AT91_ID_SYS, pdev);
+
+ rtc_device_unregister(rtc);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+/* AT91RM9200 RTC Power management control */
+
+static struct timespec at91_rtc_delta;
+
+static int at91_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct rtc_time tm;
+ struct timespec time;
+
+ time.tv_nsec = 0;
+
+ /* calculate time delta for suspend */
+ at91_rtc_readtime(&pdev->dev, &tm);
+ rtc_tm_to_time(&tm, &time.tv_sec);
+ save_time_delta(&at91_rtc_delta, &time);
+
+ pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+ 1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+ return 0;
+}
+
+static int at91_rtc_resume(struct platform_device *pdev)
+{
+ struct rtc_time tm;
+ struct timespec time;
+
+ time.tv_nsec = 0;
+
+ at91_rtc_readtime(&pdev->dev, &tm);
+ rtc_tm_to_time(&tm, &time.tv_sec);
+ restore_time_delta(&at91_rtc_delta, &time);
+
+ pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+ 1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+ return 0;
+}
+#else
+#define at91_rtc_suspend NULL
+#define at91_rtc_resume NULL
+#endif
+
+static struct platform_driver at91_rtc_driver = {
+ .probe = at91_rtc_probe,
+ .remove = at91_rtc_remove,
+ .suspend = at91_rtc_suspend,
+ .resume = at91_rtc_resume,
+ .driver = {
+ .name = "at91_rtc",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init at91_rtc_init(void)
+{
+ return platform_driver_register(&at91_rtc_driver);
+}
+
+static void __exit at91_rtc_exit(void)
+{
+ platform_driver_unregister(&at91_rtc_driver);
+}
+
+module_init(at91_rtc_init);
+module_exit(at91_rtc_exit);
+
+MODULE_AUTHOR("Rick Bronson");
+MODULE_DESCRIPTION("RTC driver for Atmel AT91RM9200");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index 2011567..61a5825 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -48,6 +48,93 @@ static int rtc_dev_open(struct inode *inode, struct file *file)
return err;
}
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+/*
+ * Routine to poll RTC seconds field for change as often as possible,
+ * after first RTC_UIE use timer to reduce polling
+ */
+static void rtc_uie_task(void *data)
+{
+ struct rtc_device *rtc = data;
+ struct rtc_time tm;
+ int num = 0;
+ int err;
+
+ err = rtc_read_time(&rtc->class_dev, &tm);
+ spin_lock_irq(&rtc->irq_lock);
+ if (rtc->stop_uie_polling || err) {
+ rtc->uie_task_active = 0;
+ } else if (rtc->oldsecs != tm.tm_sec) {
+ num = (tm.tm_sec + 60 - rtc->oldsecs) % 60;
+ rtc->oldsecs = tm.tm_sec;
+ rtc->uie_timer.expires = jiffies + HZ - (HZ/10);
+ rtc->uie_timer_active = 1;
+ rtc->uie_task_active = 0;
+ add_timer(&rtc->uie_timer);
+ } else if (schedule_work(&rtc->uie_task) == 0) {
+ rtc->uie_task_active = 0;
+ }
+ spin_unlock_irq(&rtc->irq_lock);
+ if (num)
+ rtc_update_irq(&rtc->class_dev, num, RTC_UF | RTC_IRQF);
+}
+
+static void rtc_uie_timer(unsigned long data)
+{
+ struct rtc_device *rtc = (struct rtc_device *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rtc->irq_lock, flags);
+ rtc->uie_timer_active = 0;
+ rtc->uie_task_active = 1;
+ if ((schedule_work(&rtc->uie_task) == 0))
+ rtc->uie_task_active = 0;
+ spin_unlock_irqrestore(&rtc->irq_lock, flags);
+}
+
+static void clear_uie(struct rtc_device *rtc)
+{
+ spin_lock_irq(&rtc->irq_lock);
+ if (rtc->irq_active) {
+ rtc->stop_uie_polling = 1;
+ if (rtc->uie_timer_active) {
+ spin_unlock_irq(&rtc->irq_lock);
+ del_timer_sync(&rtc->uie_timer);
+ spin_lock_irq(&rtc->irq_lock);
+ rtc->uie_timer_active = 0;
+ }
+ if (rtc->uie_task_active) {
+ spin_unlock_irq(&rtc->irq_lock);
+ flush_scheduled_work();
+ spin_lock_irq(&rtc->irq_lock);
+ }
+ rtc->irq_active = 0;
+ }
+ spin_unlock_irq(&rtc->irq_lock);
+}
+
+static int set_uie(struct rtc_device *rtc)
+{
+ struct rtc_time tm;
+ int err;
+
+ err = rtc_read_time(&rtc->class_dev, &tm);
+ if (err)
+ return err;
+ spin_lock_irq(&rtc->irq_lock);
+ if (!rtc->irq_active) {
+ rtc->irq_active = 1;
+ rtc->stop_uie_polling = 0;
+ rtc->oldsecs = tm.tm_sec;
+ rtc->uie_task_active = 1;
+ if (schedule_work(&rtc->uie_task) == 0)
+ rtc->uie_task_active = 0;
+ }
+ rtc->irq_data = 0;
+ spin_unlock_irq(&rtc->irq_lock);
+ return 0;
+}
+#endif /* CONFIG_RTC_INTF_DEV_UIE_EMUL */
static ssize_t
rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
@@ -127,6 +214,28 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
struct rtc_wkalrm alarm;
void __user *uarg = (void __user *) arg;
+ /* check that the calles has appropriate permissions
+ * for certain ioctls. doing this check here is useful
+ * to avoid duplicate code in each driver.
+ */
+ switch (cmd) {
+ case RTC_EPOCH_SET:
+ case RTC_SET_TIME:
+ if (!capable(CAP_SYS_TIME))
+ return -EACCES;
+ break;
+
+ case RTC_IRQP_SET:
+ if (arg > rtc->max_user_freq && !capable(CAP_SYS_RESOURCE))
+ return -EACCES;
+ break;
+
+ case RTC_PIE_ON:
+ if (!capable(CAP_SYS_RESOURCE))
+ return -EACCES;
+ break;
+ }
+
/* avoid conflicting IRQ users */
if (cmd == RTC_PIE_ON || cmd == RTC_PIE_OFF || cmd == RTC_IRQP_SET) {
spin_lock(&rtc->irq_task_lock);
@@ -185,9 +294,6 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
break;
case RTC_SET_TIME:
- if (!capable(CAP_SYS_TIME))
- return -EACCES;
-
if (copy_from_user(&tm, uarg, sizeof(tm)))
return -EFAULT;
@@ -203,10 +309,6 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
err = -EINVAL;
break;
}
- if (!capable(CAP_SYS_TIME)) {
- err = -EACCES;
- break;
- }
rtc_epoch = arg;
err = 0;
#endif
@@ -232,6 +334,14 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
break;
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+ case RTC_UIE_OFF:
+ clear_uie(rtc);
+ return 0;
+
+ case RTC_UIE_ON:
+ return set_uie(rtc);
+#endif
default:
err = -ENOTTY;
break;
@@ -244,6 +354,9 @@ static int rtc_dev_release(struct inode *inode, struct file *file)
{
struct rtc_device *rtc = to_rtc_device(file->private_data);
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+ clear_uie(rtc);
+#endif
if (rtc->ops->release)
rtc->ops->release(rtc->class_dev.dev);
@@ -284,6 +397,10 @@ static int rtc_dev_add_device(struct class_device *class_dev,
mutex_init(&rtc->char_lock);
spin_lock_init(&rtc->irq_lock);
init_waitqueue_head(&rtc->irq_queue);
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+ INIT_WORK(&rtc->uie_task, rtc_uie_task, rtc);
+ setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc);
+#endif
cdev_init(&rtc->char_dev, &rtc_dev_fops);
rtc->char_dev.owner = rtc->owner;
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
new file mode 100644
index 0000000..e8afb93
--- /dev/null
+++ b/drivers/rtc/rtc-ds1307.c
@@ -0,0 +1,388 @@
+/*
+ * rtc-ds1307.c - RTC driver for some mostly-compatible I2C chips.
+ *
+ * Copyright (C) 2005 James Chapman (ds1337 core)
+ * Copyright (C) 2006 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/string.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+
+
+/* We can't determine type by probing, but if we expect pre-Linux code
+ * to have set the chip up as a clock (turning on the oscillator and
+ * setting the date and time), Linux can ignore the non-clock features.
+ * That's a natural job for a factory or repair bench.
+ *
+ * If the I2C "force" mechanism is used, we assume the chip is a ds1337.
+ * (Much better would be board-specific tables of I2C devices, along with
+ * the platform_data drivers would use to sort such issues out.)
+ */
+enum ds_type {
+ unknown = 0,
+ ds_1307, /* or ds1338, ... */
+ ds_1337, /* or ds1339, ... */
+ ds_1340, /* or st m41t00, ... */
+ // rs5c372 too? different address...
+};
+
+static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+
+
+
+/* RTC registers don't differ much, except for the century flag */
+#define DS1307_REG_SECS 0x00 /* 00-59 */
+# define DS1307_BIT_CH 0x80
+#define DS1307_REG_MIN 0x01 /* 00-59 */
+#define DS1307_REG_HOUR 0x02 /* 00-23, or 1-12{am,pm} */
+# define DS1340_BIT_CENTURY_EN 0x80 /* in REG_HOUR */
+# define DS1340_BIT_CENTURY 0x40 /* in REG_HOUR */
+#define DS1307_REG_WDAY 0x03 /* 01-07 */
+#define DS1307_REG_MDAY 0x04 /* 01-31 */
+#define DS1307_REG_MONTH 0x05 /* 01-12 */
+# define DS1337_BIT_CENTURY 0x80 /* in REG_MONTH */
+#define DS1307_REG_YEAR 0x06 /* 00-99 */
+
+/* Other registers (control, status, alarms, trickle charge, NVRAM, etc)
+ * start at 7, and they differ a lot. Only control and status matter for RTC;
+ * be careful using them.
+ */
+#define DS1307_REG_CONTROL 0x07
+# define DS1307_BIT_OUT 0x80
+# define DS1307_BIT_SQWE 0x10
+# define DS1307_BIT_RS1 0x02
+# define DS1307_BIT_RS0 0x01
+#define DS1337_REG_CONTROL 0x0e
+# define DS1337_BIT_nEOSC 0x80
+# define DS1337_BIT_RS2 0x10
+# define DS1337_BIT_RS1 0x08
+# define DS1337_BIT_INTCN 0x04
+# define DS1337_BIT_A2IE 0x02
+# define DS1337_BIT_A1IE 0x01
+#define DS1337_REG_STATUS 0x0f
+# define DS1337_BIT_OSF 0x80
+# define DS1337_BIT_A2I 0x02
+# define DS1337_BIT_A1I 0x01
+#define DS1339_REG_TRICKLE 0x10
+
+
+
+struct ds1307 {
+ u8 reg_addr;
+ u8 regs[8];
+ enum ds_type type;
+ struct i2c_msg msg[2];
+ struct i2c_client client;
+ struct rtc_device *rtc;
+};
+
+
+static int ds1307_get_time(struct device *dev, struct rtc_time *t)
+{
+ struct ds1307 *ds1307 = dev_get_drvdata(dev);
+ int tmp;
+
+ /* read the RTC registers all at once */
+ ds1307->msg[1].flags = I2C_M_RD;
+ ds1307->msg[1].len = 7;
+
+ tmp = i2c_transfer(ds1307->client.adapter, ds1307->msg, 2);
+ if (tmp != 2) {
+ dev_err(dev, "%s error %d\n", "read", tmp);
+ return -EIO;
+ }
+
+ dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
+ "read",
+ ds1307->regs[0], ds1307->regs[1],
+ ds1307->regs[2], ds1307->regs[3],
+ ds1307->regs[4], ds1307->regs[5],
+ ds1307->regs[6]);
+
+ t->tm_sec = BCD2BIN(ds1307->regs[DS1307_REG_SECS] & 0x7f);
+ t->tm_min = BCD2BIN(ds1307->regs[DS1307_REG_MIN] & 0x7f);
+ tmp = ds1307->regs[DS1307_REG_HOUR] & 0x3f;
+ t->tm_hour = BCD2BIN(tmp);
+ t->tm_wday = BCD2BIN(ds1307->regs[DS1307_REG_WDAY] & 0x07) - 1;
+ t->tm_mday = BCD2BIN(ds1307->regs[DS1307_REG_MDAY] & 0x3f);
+ tmp = ds1307->regs[DS1307_REG_MONTH] & 0x1f;
+ t->tm_mon = BCD2BIN(tmp) - 1;
+
+ /* assume 20YY not 19YY, and ignore DS1337_BIT_CENTURY */
+ t->tm_year = BCD2BIN(ds1307->regs[DS1307_REG_YEAR]) + 100;
+
+ dev_dbg(dev, "%s secs=%d, mins=%d, "
+ "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+ "read", t->tm_sec, t->tm_min,
+ t->tm_hour, t->tm_mday,
+ t->tm_mon, t->tm_year, t->tm_wday);
+
+ return 0;
+}
+
+static int ds1307_set_time(struct device *dev, struct rtc_time *t)
+{
+ struct ds1307 *ds1307 = dev_get_drvdata(dev);
+ int result;
+ int tmp;
+ u8 *buf = ds1307->regs;
+
+ dev_dbg(dev, "%s secs=%d, mins=%d, "
+ "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+ "write", dt->tm_sec, dt->tm_min,
+ dt->tm_hour, dt->tm_mday,
+ dt->tm_mon, dt->tm_year, dt->tm_wday);
+
+ *buf++ = 0; /* first register addr */
+ buf[DS1307_REG_SECS] = BIN2BCD(t->tm_sec);
+ buf[DS1307_REG_MIN] = BIN2BCD(t->tm_min);
+ buf[DS1307_REG_HOUR] = BIN2BCD(t->tm_hour);
+ buf[DS1307_REG_WDAY] = BIN2BCD(t->tm_wday + 1);
+ buf[DS1307_REG_MDAY] = BIN2BCD(t->tm_mday);
+ buf[DS1307_REG_MONTH] = BIN2BCD(t->tm_mon + 1);
+
+ /* assume 20YY not 19YY */
+ tmp = t->tm_year - 100;
+ buf[DS1307_REG_YEAR] = BIN2BCD(tmp);
+
+ if (ds1307->type == ds_1337)
+ buf[DS1307_REG_MONTH] |= DS1337_BIT_CENTURY;
+ else if (ds1307->type == ds_1340)
+ buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN
+ | DS1340_BIT_CENTURY;
+
+ ds1307->msg[1].flags = 0;
+ ds1307->msg[1].len = 8;
+
+ dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
+ "write", buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5], buf[6]);
+
+ result = i2c_transfer(ds1307->client.adapter, &ds1307->msg[1], 1);
+ if (result != 1) {
+ dev_err(dev, "%s error %d\n", "write", tmp);
+ return -EIO;
+ }
+ return 0;
+}
+
+static struct rtc_class_ops ds13xx_rtc_ops = {
+ .read_time = ds1307_get_time,
+ .set_time = ds1307_set_time,
+};
+
+static struct i2c_driver ds1307_driver;
+
+static int __devinit
+ds1307_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct ds1307 *ds1307;
+ int err = -ENODEV;
+ struct i2c_client *client;
+ int tmp;
+
+ if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ client = &ds1307->client;
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &ds1307_driver;
+ client->flags = 0;
+
+ i2c_set_clientdata(client, ds1307);
+
+ ds1307->msg[0].addr = client->addr;
+ ds1307->msg[0].flags = 0;
+ ds1307->msg[0].len = 1;
+ ds1307->msg[0].buf = &ds1307->reg_addr;
+
+ ds1307->msg[1].addr = client->addr;
+ ds1307->msg[1].flags = I2C_M_RD;
+ ds1307->msg[1].len = sizeof(ds1307->regs);
+ ds1307->msg[1].buf = ds1307->regs;
+
+ /* HACK: "force" implies "needs ds1337-style-oscillator setup" */
+ if (kind >= 0) {
+ ds1307->type = ds_1337;
+
+ ds1307->reg_addr = DS1337_REG_CONTROL;
+ ds1307->msg[1].len = 2;
+
+ tmp = i2c_transfer(client->adapter, ds1307->msg, 2);
+ if (tmp != 2) {
+ pr_debug("read error %d\n", tmp);
+ err = -EIO;
+ goto exit_free;
+ }
+
+ ds1307->reg_addr = 0;
+ ds1307->msg[1].len = sizeof(ds1307->regs);
+
+ /* oscillator is off; need to turn it on */
+ if ((ds1307->regs[0] & DS1337_BIT_nEOSC)
+ || (ds1307->regs[1] & DS1337_BIT_OSF)) {
+ printk(KERN_ERR "no ds1337 oscillator code\n");
+ goto exit_free;
+ }
+ } else
+ ds1307->type = ds_1307;
+
+read_rtc:
+ /* read RTC registers */
+
+ tmp = i2c_transfer(client->adapter, ds1307->msg, 2);
+ if (tmp != 2) {
+ pr_debug("read error %d\n", tmp);
+ err = -EIO;
+ goto exit_free;
+ }
+
+ /* minimal sanity checking; some chips (like DS1340) don't
+ * specify the extra bits as must-be-zero, but there are
+ * still a few values that are clearly out-of-range.
+ */
+ tmp = ds1307->regs[DS1307_REG_SECS];
+ if (tmp & DS1307_BIT_CH) {
+ if (ds1307->type && ds1307->type != ds_1307) {
+ pr_debug("not a ds1307?\n");
+ goto exit_free;
+ }
+ ds1307->type = ds_1307;
+
+ /* this partial initialization should work for ds1307,
+ * ds1338, ds1340, st m41t00, and more.
+ */
+ dev_warn(&client->dev, "oscillator started; SET TIME!\n");
+ i2c_smbus_write_byte_data(client, 0, 0);
+ goto read_rtc;
+ }
+ tmp = BCD2BIN(tmp & 0x7f);
+ if (tmp > 60)
+ goto exit_free;
+ tmp = BCD2BIN(ds1307->regs[DS1307_REG_MIN] & 0x7f);
+ if (tmp > 60)
+ goto exit_free;
+
+ tmp = BCD2BIN(ds1307->regs[DS1307_REG_MDAY] & 0x3f);
+ if (tmp == 0 || tmp > 31)
+ goto exit_free;
+
+ tmp = BCD2BIN(ds1307->regs[DS1307_REG_MONTH] & 0x1f);
+ if (tmp == 0 || tmp > 12)
+ goto exit_free;
+
+ /* force into in 24 hour mode (most chips) or
+ * disable century bit (ds1340)
+ */
+ tmp = ds1307->regs[DS1307_REG_HOUR];
+ if (tmp & (1 << 6)) {
+ if (tmp & (1 << 5))
+ tmp = BCD2BIN(tmp & 0x1f) + 12;
+ else
+ tmp = BCD2BIN(tmp);
+ i2c_smbus_write_byte_data(client,
+ DS1307_REG_HOUR,
+ BIN2BCD(tmp));
+ }
+
+ /* FIXME chips like 1337 can generate alarm irqs too; those are
+ * worth exposing through the API (especially when the irq is
+ * wakeup-capable).
+ */
+
+ switch (ds1307->type) {
+ case unknown:
+ strlcpy(client->name, "unknown", I2C_NAME_SIZE);
+ break;
+ case ds_1307:
+ strlcpy(client->name, "ds1307", I2C_NAME_SIZE);
+ break;
+ case ds_1337:
+ strlcpy(client->name, "ds1337", I2C_NAME_SIZE);
+ break;
+ case ds_1340:
+ strlcpy(client->name, "ds1340", I2C_NAME_SIZE);
+ break;
+ }
+
+ /* Tell the I2C layer a new client has arrived */
+ if ((err = i2c_attach_client(client)))
+ goto exit_free;
+
+ ds1307->rtc = rtc_device_register(client->name, &client->dev,
+ &ds13xx_rtc_ops, THIS_MODULE);
+ if (IS_ERR(ds1307->rtc)) {
+ err = PTR_ERR(ds1307->rtc);
+ dev_err(&client->dev,
+ "unable to register the class device\n");
+ goto exit_detach;
+ }
+
+ return 0;
+
+exit_detach:
+ i2c_detach_client(client);
+exit_free:
+ kfree(ds1307);
+exit:
+ return err;
+}
+
+static int __devinit
+ds1307_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+ return 0;
+ return i2c_probe(adapter, &addr_data, ds1307_detect);
+}
+
+static int __devexit ds1307_detach_client(struct i2c_client *client)
+{
+ int err;
+ struct ds1307 *ds1307 = i2c_get_clientdata(client);
+
+ rtc_device_unregister(ds1307->rtc);
+ if ((err = i2c_detach_client(client)))
+ return err;
+ kfree(ds1307);
+ return 0;
+}
+
+static struct i2c_driver ds1307_driver = {
+ .driver = {
+ .name = "ds1307",
+ .owner = THIS_MODULE,
+ },
+ .attach_adapter = ds1307_attach_adapter,
+ .detach_client = __devexit_p(ds1307_detach_client),
+};
+
+static int __init ds1307_init(void)
+{
+ return i2c_add_driver(&ds1307_driver);
+}
+module_init(ds1307_init);
+
+static void __exit ds1307_exit(void)
+{
+ i2c_del_driver(&ds1307_driver);
+}
+module_exit(ds1307_exit);
+
+MODULE_DESCRIPTION("RTC driver for DS1307 and similar chips");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
new file mode 100644
index 0000000..ecafbad
--- /dev/null
+++ b/drivers/rtc/rtc-ds1553.c
@@ -0,0 +1,414 @@
+/*
+ * An rtc driver for the Dallas DS1553
+ *
+ * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bcd.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#define DRV_VERSION "0.1"
+
+#define RTC_REG_SIZE 0x2000
+#define RTC_OFFSET 0x1ff0
+
+#define RTC_FLAGS (RTC_OFFSET + 0)
+#define RTC_SECONDS_ALARM (RTC_OFFSET + 2)
+#define RTC_MINUTES_ALARM (RTC_OFFSET + 3)
+#define RTC_HOURS_ALARM (RTC_OFFSET + 4)
+#define RTC_DATE_ALARM (RTC_OFFSET + 5)
+#define RTC_INTERRUPTS (RTC_OFFSET + 6)
+#define RTC_WATCHDOG (RTC_OFFSET + 7)
+#define RTC_CONTROL (RTC_OFFSET + 8)
+#define RTC_CENTURY (RTC_OFFSET + 8)
+#define RTC_SECONDS (RTC_OFFSET + 9)
+#define RTC_MINUTES (RTC_OFFSET + 10)
+#define RTC_HOURS (RTC_OFFSET + 11)
+#define RTC_DAY (RTC_OFFSET + 12)
+#define RTC_DATE (RTC_OFFSET + 13)
+#define RTC_MONTH (RTC_OFFSET + 14)
+#define RTC_YEAR (RTC_OFFSET + 15)
+
+#define RTC_CENTURY_MASK 0x3f
+#define RTC_SECONDS_MASK 0x7f
+#define RTC_DAY_MASK 0x07
+
+/* Bits in the Control/Century register */
+#define RTC_WRITE 0x80
+#define RTC_READ 0x40
+
+/* Bits in the Seconds register */
+#define RTC_STOP 0x80
+
+/* Bits in the Flags register */
+#define RTC_FLAGS_AF 0x40
+#define RTC_FLAGS_BLF 0x10
+
+/* Bits in the Interrupts register */
+#define RTC_INTS_AE 0x80
+
+struct rtc_plat_data {
+ struct rtc_device *rtc;
+ void __iomem *ioaddr;
+ unsigned long baseaddr;
+ unsigned long last_jiffies;
+ int irq;
+ unsigned int irqen;
+ int alrm_sec;
+ int alrm_min;
+ int alrm_hour;
+ int alrm_mday;
+};
+
+static int ds1553_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ u8 century;
+
+ century = BIN2BCD((tm->tm_year + 1900) / 100);
+
+ writeb(RTC_WRITE, pdata->ioaddr + RTC_CONTROL);
+
+ writeb(BIN2BCD(tm->tm_year % 100), ioaddr + RTC_YEAR);
+ writeb(BIN2BCD(tm->tm_mon + 1), ioaddr + RTC_MONTH);
+ writeb(BIN2BCD(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY);
+ writeb(BIN2BCD(tm->tm_mday), ioaddr + RTC_DATE);
+ writeb(BIN2BCD(tm->tm_hour), ioaddr + RTC_HOURS);
+ writeb(BIN2BCD(tm->tm_min), ioaddr + RTC_MINUTES);
+ writeb(BIN2BCD(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS);
+
+ /* RTC_CENTURY and RTC_CONTROL share same register */
+ writeb(RTC_WRITE | (century & RTC_CENTURY_MASK), ioaddr + RTC_CENTURY);
+ writeb(century & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL);
+ return 0;
+}
+
+static int ds1553_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ unsigned int year, month, day, hour, minute, second, week;
+ unsigned int century;
+
+ /* give enough time to update RTC in case of continuous read */
+ if (pdata->last_jiffies == jiffies)
+ msleep(1);
+ pdata->last_jiffies = jiffies;
+ writeb(RTC_READ, ioaddr + RTC_CONTROL);
+ second = readb(ioaddr + RTC_SECONDS) & RTC_SECONDS_MASK;
+ minute = readb(ioaddr + RTC_MINUTES);
+ hour = readb(ioaddr + RTC_HOURS);
+ day = readb(ioaddr + RTC_DATE);
+ week = readb(ioaddr + RTC_DAY) & RTC_DAY_MASK;
+ month = readb(ioaddr + RTC_MONTH);
+ year = readb(ioaddr + RTC_YEAR);
+ century = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK;
+ writeb(0, ioaddr + RTC_CONTROL);
+ tm->tm_sec = BCD2BIN(second);
+ tm->tm_min = BCD2BIN(minute);
+ tm->tm_hour = BCD2BIN(hour);
+ tm->tm_mday = BCD2BIN(day);
+ tm->tm_wday = BCD2BIN(week);
+ tm->tm_mon = BCD2BIN(month) - 1;
+ /* year is 1900 + tm->tm_year */
+ tm->tm_year = BCD2BIN(year) + BCD2BIN(century) * 100 - 1900;
+
+ if (rtc_valid_tm(tm) < 0) {
+ dev_err(dev, "retrieved date/time is not valid.\n");
+ rtc_time_to_tm(0, tm);
+ }
+ return 0;
+}
+
+static void ds1553_rtc_update_alarm(struct rtc_plat_data *pdata)
+{
+ void __iomem *ioaddr = pdata->ioaddr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdata->rtc->irq_lock, flags);
+ writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_mday),
+ ioaddr + RTC_DATE_ALARM);
+ writeb(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_hour),
+ ioaddr + RTC_HOURS_ALARM);
+ writeb(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_min),
+ ioaddr + RTC_MINUTES_ALARM);
+ writeb(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_sec),
+ ioaddr + RTC_SECONDS_ALARM);
+ writeb(pdata->irqen ? RTC_INTS_AE : 0, ioaddr + RTC_INTERRUPTS);
+ readb(ioaddr + RTC_FLAGS); /* clear interrupts */
+ spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags);
+}
+
+static int ds1553_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq < 0)
+ return -EINVAL;
+ pdata->alrm_mday = alrm->time.tm_mday;
+ pdata->alrm_hour = alrm->time.tm_hour;
+ pdata->alrm_min = alrm->time.tm_min;
+ pdata->alrm_sec = alrm->time.tm_sec;
+ if (alrm->enabled)
+ pdata->irqen |= RTC_AF;
+ ds1553_rtc_update_alarm(pdata);
+ return 0;
+}
+
+static int ds1553_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq < 0)
+ return -EINVAL;
+ alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday;
+ alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour;
+ alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min;
+ alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec;
+ alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0;
+ return 0;
+}
+
+static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ struct platform_device *pdev = dev_id;
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ unsigned long events = RTC_IRQF;
+
+ /* read and clear interrupt */
+ if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF))
+ return IRQ_NONE;
+ if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80)
+ events |= RTC_UF;
+ else
+ events |= RTC_AF;
+ rtc_update_irq(&pdata->rtc->class_dev, 1, events);
+ return IRQ_HANDLED;
+}
+
+static void ds1553_rtc_release(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq >= 0) {
+ pdata->irqen = 0;
+ ds1553_rtc_update_alarm(pdata);
+ }
+}
+
+static int ds1553_rtc_ioctl(struct device *dev, unsigned int cmd,
+ unsigned long arg)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq < 0)
+ return -ENOIOCTLCMD;
+ switch (cmd) {
+ case RTC_AIE_OFF:
+ pdata->irqen &= ~RTC_AF;
+ ds1553_rtc_update_alarm(pdata);
+ break;
+ case RTC_AIE_ON:
+ pdata->irqen |= RTC_AF;
+ ds1553_rtc_update_alarm(pdata);
+ break;
+ case RTC_UIE_OFF:
+ pdata->irqen &= ~RTC_UF;
+ ds1553_rtc_update_alarm(pdata);
+ break;
+ case RTC_UIE_ON:
+ pdata->irqen |= RTC_UF;
+ ds1553_rtc_update_alarm(pdata);
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static struct rtc_class_ops ds1553_rtc_ops = {
+ .read_time = ds1553_rtc_read_time,
+ .set_time = ds1553_rtc_set_time,
+ .read_alarm = ds1553_rtc_read_alarm,
+ .set_alarm = ds1553_rtc_set_alarm,
+ .release = ds1553_rtc_release,
+ .ioctl = ds1553_rtc_ioctl,
+};
+
+static ssize_t ds1553_nvram_read(struct kobject *kobj, char *buf,
+ loff_t pos, size_t size)
+{
+ struct platform_device *pdev =
+ to_platform_device(container_of(kobj, struct device, kobj));
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ ssize_t count;
+
+ for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+ *buf++ = readb(ioaddr + pos++);
+ return count;
+}
+
+static ssize_t ds1553_nvram_write(struct kobject *kobj, char *buf,
+ loff_t pos, size_t size)
+{
+ struct platform_device *pdev =
+ to_platform_device(container_of(kobj, struct device, kobj));
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ ssize_t count;
+
+ for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+ writeb(*buf++, ioaddr + pos++);
+ return count;
+}
+
+static struct bin_attribute ds1553_nvram_attr = {
+ .attr = {
+ .name = "nvram",
+ .mode = S_IRUGO | S_IWUGO,
+ .owner = THIS_MODULE,
+ },
+ .size = RTC_OFFSET,
+ .read = ds1553_nvram_read,
+ .write = ds1553_nvram_write,
+};
+
+static int __init ds1553_rtc_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc;
+ struct resource *res;
+ unsigned int cen, sec;
+ struct rtc_plat_data *pdata = NULL;
+ void __iomem *ioaddr = NULL;
+ int ret = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+ pdata->irq = -1;
+ if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) {
+ ret = -EBUSY;
+ goto out;
+ }
+ pdata->baseaddr = res->start;
+ ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE);
+ if (!ioaddr) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ pdata->ioaddr = ioaddr;
+ pdata->irq = platform_get_irq(pdev, 0);
+
+ /* turn RTC on if it was not on */
+ sec = readb(ioaddr + RTC_SECONDS);
+ if (sec & RTC_STOP) {
+ sec &= RTC_SECONDS_MASK;
+ cen = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK;
+ writeb(RTC_WRITE, ioaddr + RTC_CONTROL);
+ writeb(sec, ioaddr + RTC_SECONDS);
+ writeb(cen & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL);
+ }
+ if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_BLF)
+ dev_warn(&pdev->dev, "voltage-low detected.\n");
+
+ if (pdata->irq >= 0) {
+ writeb(0, ioaddr + RTC_INTERRUPTS);
+ if (request_irq(pdata->irq, ds1553_rtc_interrupt, SA_SHIRQ,
+ pdev->name, pdev) < 0) {
+ dev_warn(&pdev->dev, "interrupt not available.\n");
+ pdata->irq = -1;
+ }
+ }
+
+ rtc = rtc_device_register(pdev->name, &pdev->dev,
+ &ds1553_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ ret = PTR_ERR(rtc);
+ goto out;
+ }
+ pdata->rtc = rtc;
+ pdata->last_jiffies = jiffies;
+ platform_set_drvdata(pdev, pdata);
+ sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
+ return 0;
+ out:
+ if (pdata->irq >= 0)
+ free_irq(pdata->irq, pdev);
+ if (ioaddr)
+ iounmap(ioaddr);
+ if (pdata->baseaddr)
+ release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+ kfree(pdata);
+ return ret;
+}
+
+static int __devexit ds1553_rtc_remove(struct platform_device *pdev)
+{
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ sysfs_remove_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
+ rtc_device_unregister(pdata->rtc);
+ if (pdata->irq >= 0) {
+ writeb(0, pdata->ioaddr + RTC_INTERRUPTS);
+ free_irq(pdata->irq, pdev);
+ }
+ iounmap(pdata->ioaddr);
+ release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+ kfree(pdata);
+ return 0;
+}
+
+static struct platform_driver ds1553_rtc_driver = {
+ .probe = ds1553_rtc_probe,
+ .remove = __devexit_p(ds1553_rtc_remove),
+ .driver = {
+ .name = "ds1553",
+ .owner = THIS_MODULE,
+ },
+};
+
+static __init int ds1553_init(void)
+{
+ return platform_driver_register(&ds1553_rtc_driver);
+}
+
+static __exit void ds1553_exit(void)
+{
+ return platform_driver_unregister(&ds1553_rtc_driver);
+}
+
+module_init(ds1553_init);
+module_exit(ds1553_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("Dallas DS1553 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
new file mode 100644
index 0000000..8e47e5a
--- /dev/null
+++ b/drivers/rtc/rtc-ds1742.c
@@ -0,0 +1,259 @@
+/*
+ * An rtc driver for the Dallas DS1742
+ *
+ * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bcd.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#define DRV_VERSION "0.1"
+
+#define RTC_REG_SIZE 0x800
+#define RTC_OFFSET 0x7f8
+
+#define RTC_CONTROL (RTC_OFFSET + 0)
+#define RTC_CENTURY (RTC_OFFSET + 0)
+#define RTC_SECONDS (RTC_OFFSET + 1)
+#define RTC_MINUTES (RTC_OFFSET + 2)
+#define RTC_HOURS (RTC_OFFSET + 3)
+#define RTC_DAY (RTC_OFFSET + 4)
+#define RTC_DATE (RTC_OFFSET + 5)
+#define RTC_MONTH (RTC_OFFSET + 6)
+#define RTC_YEAR (RTC_OFFSET + 7)
+
+#define RTC_CENTURY_MASK 0x3f
+#define RTC_SECONDS_MASK 0x7f
+#define RTC_DAY_MASK 0x07
+
+/* Bits in the Control/Century register */
+#define RTC_WRITE 0x80
+#define RTC_READ 0x40
+
+/* Bits in the Seconds register */
+#define RTC_STOP 0x80
+
+/* Bits in the Day register */
+#define RTC_BATT_FLAG 0x80
+
+struct rtc_plat_data {
+ struct rtc_device *rtc;
+ void __iomem *ioaddr;
+ unsigned long baseaddr;
+ unsigned long last_jiffies;
+};
+
+static int ds1742_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ u8 century;
+
+ century = BIN2BCD((tm->tm_year + 1900) / 100);
+
+ writeb(RTC_WRITE, ioaddr + RTC_CONTROL);
+
+ writeb(BIN2BCD(tm->tm_year % 100), ioaddr + RTC_YEAR);
+ writeb(BIN2BCD(tm->tm_mon + 1), ioaddr + RTC_MONTH);
+ writeb(BIN2BCD(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY);
+ writeb(BIN2BCD(tm->tm_mday), ioaddr + RTC_DATE);
+ writeb(BIN2BCD(tm->tm_hour), ioaddr + RTC_HOURS);
+ writeb(BIN2BCD(tm->tm_min), ioaddr + RTC_MINUTES);
+ writeb(BIN2BCD(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS);
+
+ /* RTC_CENTURY and RTC_CONTROL share same register */
+ writeb(RTC_WRITE | (century & RTC_CENTURY_MASK), ioaddr + RTC_CENTURY);
+ writeb(century & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL);
+ return 0;
+}
+
+static int ds1742_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ unsigned int year, month, day, hour, minute, second, week;
+ unsigned int century;
+
+ /* give enough time to update RTC in case of continuous read */
+ if (pdata->last_jiffies == jiffies)
+ msleep(1);
+ pdata->last_jiffies = jiffies;
+ writeb(RTC_READ, ioaddr + RTC_CONTROL);
+ second = readb(ioaddr + RTC_SECONDS) & RTC_SECONDS_MASK;
+ minute = readb(ioaddr + RTC_MINUTES);
+ hour = readb(ioaddr + RTC_HOURS);
+ day = readb(ioaddr + RTC_DATE);
+ week = readb(ioaddr + RTC_DAY) & RTC_DAY_MASK;
+ month = readb(ioaddr + RTC_MONTH);
+ year = readb(ioaddr + RTC_YEAR);
+ century = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK;
+ writeb(0, ioaddr + RTC_CONTROL);
+ tm->tm_sec = BCD2BIN(second);
+ tm->tm_min = BCD2BIN(minute);
+ tm->tm_hour = BCD2BIN(hour);
+ tm->tm_mday = BCD2BIN(day);
+ tm->tm_wday = BCD2BIN(week);
+ tm->tm_mon = BCD2BIN(month) - 1;
+ /* year is 1900 + tm->tm_year */
+ tm->tm_year = BCD2BIN(year) + BCD2BIN(century) * 100 - 1900;
+
+ if (rtc_valid_tm(tm) < 0) {
+ dev_err(dev, "retrieved date/time is not valid.\n");
+ rtc_time_to_tm(0, tm);
+ }
+ return 0;
+}
+
+static struct rtc_class_ops ds1742_rtc_ops = {
+ .read_time = ds1742_rtc_read_time,
+ .set_time = ds1742_rtc_set_time,
+};
+
+static ssize_t ds1742_nvram_read(struct kobject *kobj, char *buf,
+ loff_t pos, size_t size)
+{
+ struct platform_device *pdev =
+ to_platform_device(container_of(kobj, struct device, kobj));
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ ssize_t count;
+
+ for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+ *buf++ = readb(ioaddr + pos++);
+ return count;
+}
+
+static ssize_t ds1742_nvram_write(struct kobject *kobj, char *buf,
+ loff_t pos, size_t size)
+{
+ struct platform_device *pdev =
+ to_platform_device(container_of(kobj, struct device, kobj));
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ ssize_t count;
+
+ for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+ writeb(*buf++, ioaddr + pos++);
+ return count;
+}
+
+static struct bin_attribute ds1742_nvram_attr = {
+ .attr = {
+ .name = "nvram",
+ .mode = S_IRUGO | S_IWUGO,
+ .owner = THIS_MODULE,
+ },
+ .size = RTC_OFFSET,
+ .read = ds1742_nvram_read,
+ .write = ds1742_nvram_write,
+};
+
+static int __init ds1742_rtc_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc;
+ struct resource *res;
+ unsigned int cen, sec;
+ struct rtc_plat_data *pdata = NULL;
+ void __iomem *ioaddr = NULL;
+ int ret = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+ if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) {
+ ret = -EBUSY;
+ goto out;
+ }
+ pdata->baseaddr = res->start;
+ ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE);
+ if (!ioaddr) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ pdata->ioaddr = ioaddr;
+
+ /* turn RTC on if it was not on */
+ sec = readb(ioaddr + RTC_SECONDS);
+ if (sec & RTC_STOP) {
+ sec &= RTC_SECONDS_MASK;
+ cen = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK;
+ writeb(RTC_WRITE, ioaddr + RTC_CONTROL);
+ writeb(sec, ioaddr + RTC_SECONDS);
+ writeb(cen & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL);
+ }
+ if (readb(ioaddr + RTC_DAY) & RTC_BATT_FLAG)
+ dev_warn(&pdev->dev, "voltage-low detected.\n");
+
+ rtc = rtc_device_register(pdev->name, &pdev->dev,
+ &ds1742_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ ret = PTR_ERR(rtc);
+ goto out;
+ }
+ pdata->rtc = rtc;
+ pdata->last_jiffies = jiffies;
+ platform_set_drvdata(pdev, pdata);
+ sysfs_create_bin_file(&pdev->dev.kobj, &ds1742_nvram_attr);
+ return 0;
+ out:
+ if (ioaddr)
+ iounmap(ioaddr);
+ if (pdata->baseaddr)
+ release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+ kfree(pdata);
+ return ret;
+}
+
+static int __devexit ds1742_rtc_remove(struct platform_device *pdev)
+{
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ sysfs_remove_bin_file(&pdev->dev.kobj, &ds1742_nvram_attr);
+ rtc_device_unregister(pdata->rtc);
+ iounmap(pdata->ioaddr);
+ release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+ kfree(pdata);
+ return 0;
+}
+
+static struct platform_driver ds1742_rtc_driver = {
+ .probe = ds1742_rtc_probe,
+ .remove = __devexit_p(ds1742_rtc_remove),
+ .driver = {
+ .name = "ds1742",
+ .owner = THIS_MODULE,
+ },
+};
+
+static __init int ds1742_init(void)
+{
+ return platform_driver_register(&ds1742_rtc_driver);
+}
+
+static __exit void ds1742_exit(void)
+{
+ return platform_driver_unregister(&ds1742_rtc_driver);
+}
+
+module_init(ds1742_init);
+module_exit(ds1742_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("Dallas DS1742 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
index cfedc1d..9812120 100644
--- a/drivers/rtc/rtc-lib.c
+++ b/drivers/rtc/rtc-lib.c
@@ -18,9 +18,19 @@ static const unsigned char rtc_days_in_month[] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
+static const unsigned short rtc_ydays[2][13] = {
+ /* Normal years */
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+ /* Leap years */
+ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+};
+
#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
+/*
+ * The number of days in the month.
+ */
int rtc_month_days(unsigned int month, unsigned int year)
{
return rtc_days_in_month[month] + (LEAP_YEAR(year) && month == 1);
@@ -28,6 +38,15 @@ int rtc_month_days(unsigned int month, unsigned int year)
EXPORT_SYMBOL(rtc_month_days);
/*
+ * The number of days since January 1. (0 to 365)
+ */
+int rtc_year_days(unsigned int day, unsigned int month, unsigned int year)
+{
+ return rtc_ydays[LEAP_YEAR(year)][month] + day-1;
+}
+EXPORT_SYMBOL(rtc_year_days);
+
+/*
* Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
*/
void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c
new file mode 100644
index 0000000..2c97395
--- /dev/null
+++ b/drivers/rtc/rtc-max6902.c
@@ -0,0 +1,286 @@
+/* drivers/char/max6902.c
+ *
+ * Copyright (C) 2006 8D Technologies inc.
+ * Copyright (C) 2004 Compulab 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.
+ *
+ * Driver for MAX6902 spi RTC
+ *
+ * Changelog:
+ *
+ * 24-May-2006: Raphael Assenat <raph@8d.com>
+ * - Major rework
+ * Converted to rtc_device and uses the SPI layer.
+ *
+ * ??-???-2005: Someone at Compulab
+ * - Initial driver creation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+#include <linux/bcd.h>
+#include <linux/delay.h>
+
+#define MAX6902_REG_SECONDS 0x01
+#define MAX6902_REG_MINUTES 0x03
+#define MAX6902_REG_HOURS 0x05
+#define MAX6902_REG_DATE 0x07
+#define MAX6902_REG_MONTH 0x09
+#define MAX6902_REG_DAY 0x0B
+#define MAX6902_REG_YEAR 0x0D
+#define MAX6902_REG_CONTROL 0x0F
+#define MAX6902_REG_CENTURY 0x13
+
+#undef MAX6902_DEBUG
+
+struct max6902 {
+ struct rtc_device *rtc;
+ u8 buf[9]; /* Burst read cmd + 8 registers */
+ u8 tx_buf[2];
+ u8 rx_buf[2];
+};
+
+static void max6902_set_reg(struct device *dev, unsigned char address,
+ unsigned char data)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ unsigned char buf[2];
+
+ /* MSB must be '0' to write */
+ buf[0] = address & 0x7f;
+ buf[1] = data;
+
+ spi_write(spi, buf, 2);
+}
+
+static int max6902_get_reg(struct device *dev, unsigned char address,
+ unsigned char *data)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct max6902 *chip = dev_get_drvdata(dev);
+ struct spi_message message;
+ struct spi_transfer xfer;
+ int status;
+
+ if (!data)
+ return -EINVAL;
+
+ /* Build our spi message */
+ spi_message_init(&message);
+ memset(&xfer, 0, sizeof(xfer));
+ xfer.len = 2;
+ /* Can tx_buf and rx_buf be equal? The doc in spi.h is not sure... */
+ xfer.tx_buf = chip->tx_buf;
+ xfer.rx_buf = chip->rx_buf;
+
+ /* Set MSB to indicate read */
+ chip->tx_buf[0] = address | 0x80;
+
+ spi_message_add_tail(&xfer, &message);
+
+ /* do the i/o */
+ status = spi_sync(spi, &message);
+ if (status == 0)
+ status = message.status;
+ else
+ return status;
+
+ *data = chip->rx_buf[1];
+
+ return status;
+}
+
+static int max6902_get_datetime(struct device *dev, struct rtc_time *dt)
+{
+ unsigned char tmp;
+ int century;
+ int err;
+ struct spi_device *spi = to_spi_device(dev);
+ struct max6902 *chip = dev_get_drvdata(dev);
+ struct spi_message message;
+ struct spi_transfer xfer;
+ int status;
+
+ err = max6902_get_reg(dev, MAX6902_REG_CENTURY, &tmp);
+ if (err)
+ return err;
+
+ /* build the message */
+ spi_message_init(&message);
+ memset(&xfer, 0, sizeof(xfer));
+ xfer.len = 1 + 7; /* Burst read command + 7 registers */
+ xfer.tx_buf = chip->buf;
+ xfer.rx_buf = chip->buf;
+ chip->buf[0] = 0xbf; /* Burst read */
+ spi_message_add_tail(&xfer, &message);
+
+ /* do the i/o */
+ status = spi_sync(spi, &message);
+ if (status == 0)
+ status = message.status;
+ else
+ return status;
+
+ /* The chip sends data in this order:
+ * Seconds, Minutes, Hours, Date, Month, Day, Year */
+ dt->tm_sec = BCD2BIN(chip->buf[1]);
+ dt->tm_min = BCD2BIN(chip->buf[2]);
+ dt->tm_hour = BCD2BIN(chip->buf[3]);
+ dt->tm_mday = BCD2BIN(chip->buf[4]);
+ dt->tm_mon = BCD2BIN(chip->buf[5] - 1);
+ dt->tm_wday = BCD2BIN(chip->buf[6]);
+ dt->tm_year = BCD2BIN(chip->buf[7]);
+
+ century = BCD2BIN(tmp) * 100;
+
+ dt->tm_year += century;
+ dt->tm_year -= 1900;
+
+#ifdef MAX6902_DEBUG
+ printk("\n%s : Read RTC values\n",__FUNCTION__);
+ printk("tm_hour: %i\n",dt->tm_hour);
+ printk("tm_min : %i\n",dt->tm_min);
+ printk("tm_sec : %i\n",dt->tm_sec);
+ printk("tm_year: %i\n",dt->tm_year);
+ printk("tm_mon : %i\n",dt->tm_mon);
+ printk("tm_mday: %i\n",dt->tm_mday);
+ printk("tm_wday: %i\n",dt->tm_wday);
+#endif
+
+ return 0;
+}
+
+static int max6902_set_datetime(struct device *dev, struct rtc_time *dt)
+{
+ dt->tm_year = dt->tm_year+1900;
+
+#ifdef MAX6902_DEBUG
+ printk("\n%s : Setting RTC values\n",__FUNCTION__);
+ printk("tm_sec : %i\n",dt->tm_sec);
+ printk("tm_min : %i\n",dt->tm_min);
+ printk("tm_hour: %i\n",dt->tm_hour);
+ printk("tm_mday: %i\n",dt->tm_mday);
+ printk("tm_wday: %i\n",dt->tm_wday);
+ printk("tm_year: %i\n",dt->tm_year);
+#endif
+
+ /* Remove write protection */
+ max6902_set_reg(dev, 0xF, 0);
+
+ max6902_set_reg(dev, 0x01, BIN2BCD(dt->tm_sec));
+ max6902_set_reg(dev, 0x03, BIN2BCD(dt->tm_min));
+ max6902_set_reg(dev, 0x05, BIN2BCD(dt->tm_hour));
+
+ max6902_set_reg(dev, 0x07, BIN2BCD(dt->tm_mday));
+ max6902_set_reg(dev, 0x09, BIN2BCD(dt->tm_mon+1));
+ max6902_set_reg(dev, 0x0B, BIN2BCD(dt->tm_wday));
+ max6902_set_reg(dev, 0x0D, BIN2BCD(dt->tm_year%100));
+ max6902_set_reg(dev, 0x13, BIN2BCD(dt->tm_year/100));
+
+ /* Compulab used a delay here. However, the datasheet
+ * does not mention a delay being required anywhere... */
+ /* delay(2000); */
+
+ /* Write protect */
+ max6902_set_reg(dev, 0xF, 0x80);
+
+ return 0;
+}
+
+static int max6902_read_time(struct device *dev, struct rtc_time *tm)
+{
+ return max6902_get_datetime(dev, tm);
+}
+
+static int max6902_set_time(struct device *dev, struct rtc_time *tm)
+{
+ return max6902_set_datetime(dev, tm);
+}
+
+static struct rtc_class_ops max6902_rtc_ops = {
+ .read_time = max6902_read_time,
+ .set_time = max6902_set_time,
+};
+
+static int __devinit max6902_probe(struct spi_device *spi)
+{
+ struct rtc_device *rtc;
+ unsigned char tmp;
+ struct max6902 *chip;
+ int res;
+
+ rtc = rtc_device_register("max6902",
+ &spi->dev, &max6902_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
+
+ spi->mode = SPI_MODE_3;
+ spi->bits_per_word = 8;
+ spi_setup(spi);
+
+ chip = kzalloc(sizeof *chip, GFP_KERNEL);
+ if (!chip) {
+ rtc_device_unregister(rtc);
+ return -ENOMEM;
+ }
+ chip->rtc = rtc;
+ dev_set_drvdata(&spi->dev, chip);
+
+ res = max6902_get_reg(&spi->dev, MAX6902_REG_SECONDS, &tmp);
+ if (res) {
+ rtc_device_unregister(rtc);
+ return res;
+ }
+
+ return 0;
+}
+
+static int __devexit max6902_remove(struct spi_device *spi)
+{
+ struct max6902 *chip = platform_get_drvdata(spi);
+ struct rtc_device *rtc = chip->rtc;
+
+ if (rtc)
+ rtc_device_unregister(rtc);
+
+ kfree(chip);
+
+ return 0;
+}
+
+static struct spi_driver max6902_driver = {
+ .driver = {
+ .name = "max6902",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = max6902_probe,
+ .remove = __devexit_p(max6902_remove),
+};
+
+static __init int max6902_init(void)
+{
+ printk("max6902 spi driver\n");
+ return spi_register_driver(&max6902_driver);
+}
+module_init(max6902_init);
+
+static __exit void max6902_exit(void)
+{
+ spi_unregister_driver(&max6902_driver);
+}
+module_exit(max6902_exit);
+
+MODULE_DESCRIPTION ("max6902 spi RTC driver");
+MODULE_AUTHOR ("Raphael Assenat");
+MODULE_LICENSE ("GPL");
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
new file mode 100644
index 0000000..b235a30
--- /dev/null
+++ b/drivers/rtc/rtc-pcf8583.c
@@ -0,0 +1,394 @@
+/*
+ * drivers/rtc/rtc-pcf8583.c
+ *
+ * Copyright (C) 2000 Russell King
+ *
+ * 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.
+ *
+ * Driver for PCF8583 RTC & RAM chip
+ *
+ * Converted to the generic RTC susbsystem by G. Liakhovetski (2006)
+ */
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/mc146818rtc.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/bcd.h>
+
+struct rtc_mem {
+ unsigned int loc;
+ unsigned int nr;
+ unsigned char *data;
+};
+
+struct pcf8583 {
+ struct i2c_client client;
+ struct rtc_device *rtc;
+ unsigned char ctrl;
+};
+
+#define CTRL_STOP 0x80
+#define CTRL_HOLD 0x40
+#define CTRL_32KHZ 0x00
+#define CTRL_MASK 0x08
+#define CTRL_ALARMEN 0x04
+#define CTRL_ALARM 0x02
+#define CTRL_TIMER 0x01
+
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+
+/* Module parameters */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver pcf8583_driver;
+
+#define get_ctrl(x) ((struct pcf8583 *)i2c_get_clientdata(x))->ctrl
+#define set_ctrl(x, v) get_ctrl(x) = v
+
+#define CMOS_YEAR (64 + 128)
+#define CMOS_CHECKSUM (63)
+
+static int pcf8583_get_datetime(struct i2c_client *client, struct rtc_time *dt)
+{
+ unsigned char buf[8], addr[1] = { 1 };
+ struct i2c_msg msgs[2] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = addr,
+ }, {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = 6,
+ .buf = buf,
+ }
+ };
+ int ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ ret = i2c_transfer(client->adapter, msgs, 2);
+ if (ret == 2) {
+ dt->tm_year = buf[4] >> 6;
+ dt->tm_wday = buf[5] >> 5;
+
+ buf[4] &= 0x3f;
+ buf[5] &= 0x1f;
+
+ dt->tm_sec = BCD_TO_BIN(buf[1]);
+ dt->tm_min = BCD_TO_BIN(buf[2]);
+ dt->tm_hour = BCD_TO_BIN(buf[3]);
+ dt->tm_mday = BCD_TO_BIN(buf[4]);
+ dt->tm_mon = BCD_TO_BIN(buf[5]);
+ }
+
+ return ret == 2 ? 0 : -EIO;
+}
+
+static int pcf8583_set_datetime(struct i2c_client *client, struct rtc_time *dt, int datetoo)
+{
+ unsigned char buf[8];
+ int ret, len = 6;
+
+ buf[0] = 0;
+ buf[1] = get_ctrl(client) | 0x80;
+ buf[2] = 0;
+ buf[3] = BIN_TO_BCD(dt->tm_sec);
+ buf[4] = BIN_TO_BCD(dt->tm_min);
+ buf[5] = BIN_TO_BCD(dt->tm_hour);
+
+ if (datetoo) {
+ len = 8;
+ buf[6] = BIN_TO_BCD(dt->tm_mday) | (dt->tm_year << 6);
+ buf[7] = BIN_TO_BCD(dt->tm_mon) | (dt->tm_wday << 5);
+ }
+
+ ret = i2c_master_send(client, (char *)buf, len);
+ if (ret != len)
+ return -EIO;
+
+ buf[1] = get_ctrl(client);
+ ret = i2c_master_send(client, (char *)buf, 2);
+
+ return ret == 2 ? 0 : -EIO;
+}
+
+static int pcf8583_get_ctrl(struct i2c_client *client, unsigned char *ctrl)
+{
+ *ctrl = get_ctrl(client);
+ return 0;
+}
+
+static int pcf8583_set_ctrl(struct i2c_client *client, unsigned char *ctrl)
+{
+ unsigned char buf[2];
+
+ buf[0] = 0;
+ buf[1] = *ctrl;
+ set_ctrl(client, *ctrl);
+
+ return i2c_master_send(client, (char *)buf, 2);
+}
+
+static int pcf8583_read_mem(struct i2c_client *client, struct rtc_mem *mem)
+{
+ unsigned char addr[1];
+ struct i2c_msg msgs[2] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = addr,
+ }, {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = mem->nr,
+ .buf = mem->data,
+ }
+ };
+
+ if (mem->loc < 8)
+ return -EINVAL;
+
+ addr[0] = mem->loc;
+
+ return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
+}
+
+static int pcf8583_write_mem(struct i2c_client *client, struct rtc_mem *mem)
+{
+ unsigned char addr[1];
+ struct i2c_msg msgs[2] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = addr,
+ }, {
+ .addr = client->addr,
+ .flags = I2C_M_NOSTART,
+ .len = mem->nr,
+ .buf = mem->data,
+ }
+ };
+
+ if (mem->loc < 8)
+ return -EINVAL;
+
+ addr[0] = mem->loc;
+
+ return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
+}
+
+static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned char ctrl, year[2];
+ struct rtc_mem mem = { CMOS_YEAR, sizeof(year), year };
+ int real_year, year_offset, err;
+
+ /*
+ * Ensure that the RTC is running.
+ */
+ pcf8583_get_ctrl(client, &ctrl);
+ if (ctrl & (CTRL_STOP | CTRL_HOLD)) {
+ unsigned char new_ctrl = ctrl & ~(CTRL_STOP | CTRL_HOLD);
+
+ printk(KERN_WARNING "RTC: resetting control %02x -> %02x\n",
+ ctrl, new_ctrl);
+
+ if ((err = pcf8583_set_ctrl(client, &new_ctrl)) < 0)
+ return err;
+ }
+
+ if (pcf8583_get_datetime(client, tm) ||
+ pcf8583_read_mem(client, &mem))
+ return -EIO;
+
+ real_year = year[0];
+
+ /*
+ * The RTC year holds the LSB two bits of the current
+ * year, which should reflect the LSB two bits of the
+ * CMOS copy of the year. Any difference indicates
+ * that we have to correct the CMOS version.
+ */
+ year_offset = tm->tm_year - (real_year & 3);
+ if (year_offset < 0)
+ /*
+ * RTC year wrapped. Adjust it appropriately.
+ */
+ year_offset += 4;
+
+ tm->tm_year = real_year + year_offset + year[1] * 100;
+
+ return 0;
+}
+
+static int pcf8583_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned char year[2], chk;
+ struct rtc_mem cmos_year = { CMOS_YEAR, sizeof(year), year };
+ struct rtc_mem cmos_check = { CMOS_CHECKSUM, 1, &chk };
+ int ret;
+
+ /*
+ * The RTC's own 2-bit year must reflect the least
+ * significant two bits of the CMOS year.
+ */
+
+ ret = pcf8583_set_datetime(client, tm, 1);
+ if (ret)
+ return ret;
+
+ ret = pcf8583_read_mem(client, &cmos_check);
+ if (ret)
+ return ret;
+
+ ret = pcf8583_read_mem(client, &cmos_year);
+ if (ret)
+ return ret;
+
+ chk -= year[1] + year[0];
+
+ year[1] = tm->tm_year / 100;
+ year[0] = tm->tm_year % 100;
+
+ chk += year[1] + year[0];
+
+ ret = pcf8583_write_mem(client, &cmos_year);
+
+ if (ret)
+ return ret;
+
+ ret = pcf8583_write_mem(client, &cmos_check);
+
+ return ret;
+}
+
+static struct rtc_class_ops pcf8583_rtc_ops = {
+ .read_time = pcf8583_rtc_read_time,
+ .set_time = pcf8583_rtc_set_time,
+};
+
+static int pcf8583_probe(struct i2c_adapter *adap, int addr, int kind);
+
+static int pcf8583_attach(struct i2c_adapter *adap)
+{
+ return i2c_probe(adap, &addr_data, pcf8583_probe);
+}
+
+static int pcf8583_detach(struct i2c_client *client)
+{
+ int err;
+ struct pcf8583 *pcf = i2c_get_clientdata(client);
+ struct rtc_device *rtc = pcf->rtc;
+
+ if (rtc)
+ rtc_device_unregister(rtc);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(pcf);
+ return 0;
+}
+
+static struct i2c_driver pcf8583_driver = {
+ .driver = {
+ .name = "pcf8583",
+ },
+ .id = I2C_DRIVERID_PCF8583,
+ .attach_adapter = pcf8583_attach,
+ .detach_client = pcf8583_detach,
+};
+
+static int pcf8583_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+ struct pcf8583 *pcf;
+ struct i2c_client *client;
+ struct rtc_device *rtc;
+ unsigned char buf[1], ad[1] = { 0 };
+ int err;
+ struct i2c_msg msgs[2] = {
+ {
+ .addr = addr,
+ .flags = 0,
+ .len = 1,
+ .buf = ad,
+ }, {
+ .addr = addr,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = buf,
+ }
+ };
+
+ pcf = kzalloc(sizeof(*pcf), GFP_KERNEL);
+ if (!pcf)
+ return -ENOMEM;
+
+ client = &pcf->client;
+
+ client->addr = addr;
+ client->adapter = adap;
+ client->driver = &pcf8583_driver;
+
+ strlcpy(client->name, pcf8583_driver.driver.name, I2C_NAME_SIZE);
+
+ if (i2c_transfer(client->adapter, msgs, 2) != 2) {
+ err = -EIO;
+ goto exit_kfree;
+ }
+
+ err = i2c_attach_client(client);
+
+ if (err)
+ goto exit_kfree;
+
+ rtc = rtc_device_register(pcf8583_driver.driver.name, &client->dev,
+ &pcf8583_rtc_ops, THIS_MODULE);
+
+ if (IS_ERR(rtc)) {
+ err = PTR_ERR(rtc);
+ goto exit_detach;
+ }
+
+ pcf->rtc = rtc;
+ i2c_set_clientdata(client, pcf);
+ set_ctrl(client, buf[0]);
+
+ return 0;
+
+exit_detach:
+ i2c_detach_client(client);
+
+exit_kfree:
+ kfree(pcf);
+
+ return err;
+}
+
+static __init int pcf8583_init(void)
+{
+ return i2c_add_driver(&pcf8583_driver);
+}
+
+static __exit void pcf8583_exit(void)
+{
+ i2c_del_driver(&pcf8583_driver);
+}
+
+module_init(pcf8583_init);
+module_exit(pcf8583_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("PCF8583 I2C RTC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
new file mode 100644
index 0000000..ee53863
--- /dev/null
+++ b/drivers/rtc/rtc-pl031.c
@@ -0,0 +1,233 @@
+/*
+ * drivers/rtc/rtc-pl031.c
+ *
+ * Real Time Clock interface for ARM AMBA PrimeCell 031 RTC
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2006 (c) MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/pm.h>
+
+#include <linux/amba/bus.h>
+
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/rtc.h>
+
+/*
+ * Register definitions
+ */
+#define RTC_DR 0x00 /* Data read register */
+#define RTC_MR 0x04 /* Match register */
+#define RTC_LR 0x08 /* Data load register */
+#define RTC_CR 0x0c /* Control register */
+#define RTC_IMSC 0x10 /* Interrupt mask and set register */
+#define RTC_RIS 0x14 /* Raw interrupt status register */
+#define RTC_MIS 0x18 /* Masked interrupt status register */
+#define RTC_ICR 0x1c /* Interrupt clear register */
+
+struct pl031_local {
+ struct rtc_device *rtc;
+ void __iomem *base;
+};
+
+static irqreturn_t pl031_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct rtc_device *rtc = dev_id;
+
+ rtc_update_irq(&rtc->class_dev, 1, RTC_AF);
+
+ return IRQ_HANDLED;
+}
+
+static int pl031_open(struct device *dev)
+{
+ /*
+ * We request IRQ in pl031_probe, so nothing to do here...
+ */
+ return 0;
+}
+
+static void pl031_release(struct device *dev)
+{
+}
+
+static int pl031_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+
+ switch (cmd) {
+ case RTC_AIE_OFF:
+ __raw_writel(1, ldata->base + RTC_MIS);
+ return 0;
+ case RTC_AIE_ON:
+ __raw_writel(0, ldata->base + RTC_MIS);
+ return 0;
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static int pl031_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+
+ rtc_time_to_tm(__raw_readl(ldata->base + RTC_DR), tm);
+
+ return 0;
+}
+
+static int pl031_set_time(struct device *dev, struct rtc_time *tm)
+{
+ unsigned long time;
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+
+ rtc_tm_to_time(tm, &time);
+ __raw_writel(time, ldata->base + RTC_LR);
+
+ return 0;
+}
+
+static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+
+ rtc_time_to_tm(__raw_readl(ldata->base + RTC_MR), &alarm->time);
+ alarm->pending = __raw_readl(ldata->base + RTC_RIS);
+ alarm->enabled = __raw_readl(ldata->base + RTC_IMSC);
+
+ return 0;
+}
+
+static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+ unsigned long time;
+
+ rtc_tm_to_time(&alarm->time, &time);
+
+ __raw_writel(time, ldata->base + RTC_MR);
+ __raw_writel(!alarm->enabled, ldata->base + RTC_MIS);
+
+ return 0;
+}
+
+static struct rtc_class_ops pl031_ops = {
+ .open = pl031_open,
+ .release = pl031_release,
+ .ioctl = pl031_ioctl,
+ .read_time = pl031_read_time,
+ .set_time = pl031_set_time,
+ .read_alarm = pl031_read_alarm,
+ .set_alarm = pl031_set_alarm,
+};
+
+static int pl031_remove(struct amba_device *adev)
+{
+ struct pl031_local *ldata = dev_get_drvdata(&adev->dev);
+
+ if (ldata) {
+ dev_set_drvdata(&adev->dev, NULL);
+ free_irq(adev->irq[0], ldata->rtc);
+ rtc_device_unregister(ldata->rtc);
+ iounmap(ldata->base);
+ kfree(ldata);
+ }
+
+ return 0;
+}
+
+static int pl031_probe(struct amba_device *adev, void *id)
+{
+ int ret;
+ struct pl031_local *ldata;
+
+
+ ldata = kmalloc(sizeof(struct pl031_local), GFP_KERNEL);
+ if (!ldata) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ dev_set_drvdata(&adev->dev, ldata);
+
+ ldata->base = ioremap(adev->res.start,
+ adev->res.end - adev->res.start + 1);
+ if (!ldata->base) {
+ ret = -ENOMEM;
+ goto out_no_remap;
+ }
+
+ if (request_irq(adev->irq[0], pl031_interrupt, SA_INTERRUPT,
+ "rtc-pl031", ldata->rtc)) {
+ ret = -EIO;
+ goto out_no_irq;
+ }
+
+ ldata->rtc = rtc_device_register("pl031", &adev->dev, &pl031_ops,
+ THIS_MODULE);
+ if (IS_ERR(ldata->rtc)) {
+ ret = PTR_ERR(ldata->rtc);
+ goto out_no_rtc;
+ }
+
+ return 0;
+
+out_no_rtc:
+ free_irq(adev->irq[0], ldata->rtc);
+out_no_irq:
+ iounmap(ldata->base);
+out_no_remap:
+ dev_set_drvdata(&adev->dev, NULL);
+ kfree(ldata);
+out:
+ return ret;
+}
+
+static struct amba_id pl031_ids[] __initdata = {
+ {
+ .id = 0x00041031,
+ .mask = 0x000fffff, },
+ {0, 0},
+};
+
+static struct amba_driver pl031_driver = {
+ .drv = {
+ .name = "rtc-pl031",
+ },
+ .id_table = pl031_ids,
+ .probe = pl031_probe,
+ .remove = pl031_remove,
+};
+
+static int __init pl031_init(void)
+{
+ return amba_driver_register(&pl031_driver);
+}
+
+static void __exit pl031_exit(void)
+{
+ amba_driver_unregister(&pl031_driver);
+}
+
+module_init(pl031_init);
+module_exit(pl031_exit);
+
+MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net");
+MODULE_DESCRIPTION("ARM AMBA PL031 RTC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index a997529..ab486fb 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -229,8 +229,6 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd,
spin_unlock_irq(&sa1100_rtc_lock);
return 0;
case RTC_PIE_ON:
- if ((rtc_freq > 64) && !capable(CAP_SYS_RESOURCE))
- return -EACCES;
spin_lock_irq(&sa1100_rtc_lock);
OSMR1 = TIMER_FREQ/rtc_freq + OSCR;
OIER |= OIER_E1;
@@ -242,8 +240,6 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd,
case RTC_IRQP_SET:
if (arg < 1 || arg > TIMER_FREQ)
return -EINVAL;
- if ((arg > 64) && (!capable(CAP_SYS_RESOURCE)))
- return -EACCES;
rtc_freq = arg;
return 0;
}
diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c
new file mode 100644
index 0000000..a40f400
--- /dev/null
+++ b/drivers/rtc/rtc-v3020.c
@@ -0,0 +1,264 @@
+/* drivers/rtc/rtc-v3020.c
+ *
+ * Copyright (C) 2006 8D Technologies inc.
+ * Copyright (C) 2004 Compulab 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.
+ *
+ * Driver for the V3020 RTC
+ *
+ * Changelog:
+ *
+ * 10-May-2006: Raphael Assenat <raph@8d.com>
+ * - Converted to platform driver
+ * - Use the generic rtc class
+ *
+ * ??-???-2004: Someone at Compulab
+ * - Initial driver creation.
+ *
+ */
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/types.h>
+#include <linux/bcd.h>
+#include <linux/rtc-v3020.h>
+
+#include <asm/io.h>
+
+#undef DEBUG
+
+struct v3020 {
+ void __iomem *ioaddress;
+ int leftshift;
+ struct rtc_device *rtc;
+};
+
+static void v3020_set_reg(struct v3020 *chip, unsigned char address,
+ unsigned char data)
+{
+ int i;
+ unsigned char tmp;
+
+ tmp = address;
+ for (i = 0; i < 4; i++) {
+ writel((tmp & 1) << chip->leftshift, chip->ioaddress);
+ tmp >>= 1;
+ }
+
+ /* Commands dont have data */
+ if (!V3020_IS_COMMAND(address)) {
+ for (i = 0; i < 8; i++) {
+ writel((data & 1) << chip->leftshift, chip->ioaddress);
+ data >>= 1;
+ }
+ }
+}
+
+static unsigned char v3020_get_reg(struct v3020 *chip, unsigned char address)
+{
+ unsigned int data=0;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ writel((address & 1) << chip->leftshift, chip->ioaddress);
+ address >>= 1;
+ }
+
+ for (i = 0; i < 8; i++) {
+ data >>= 1;
+ if (readl(chip->ioaddress) & (1 << chip->leftshift))
+ data |= 0x80;
+ }
+
+ return data;
+}
+
+static int v3020_read_time(struct device *dev, struct rtc_time *dt)
+{
+ struct v3020 *chip = dev_get_drvdata(dev);
+ int tmp;
+
+ /* Copy the current time to ram... */
+ v3020_set_reg(chip, V3020_CMD_CLOCK2RAM, 0);
+
+ /* ...and then read constant values. */
+ tmp = v3020_get_reg(chip, V3020_SECONDS);
+ dt->tm_sec = BCD2BIN(tmp);
+ tmp = v3020_get_reg(chip, V3020_MINUTES);
+ dt->tm_min = BCD2BIN(tmp);
+ tmp = v3020_get_reg(chip, V3020_HOURS);
+ dt->tm_hour = BCD2BIN(tmp);
+ tmp = v3020_get_reg(chip, V3020_MONTH_DAY);
+ dt->tm_mday = BCD2BIN(tmp);
+ tmp = v3020_get_reg(chip, V3020_MONTH);
+ dt->tm_mon = BCD2BIN(tmp);
+ tmp = v3020_get_reg(chip, V3020_WEEK_DAY);
+ dt->tm_wday = BCD2BIN(tmp);
+ tmp = v3020_get_reg(chip, V3020_YEAR);
+ dt->tm_year = BCD2BIN(tmp)+100;
+
+#ifdef DEBUG
+ printk("\n%s : Read RTC values\n",__FUNCTION__);
+ printk("tm_hour: %i\n",dt->tm_hour);
+ printk("tm_min : %i\n",dt->tm_min);
+ printk("tm_sec : %i\n",dt->tm_sec);
+ printk("tm_year: %i\n",dt->tm_year);
+ printk("tm_mon : %i\n",dt->tm_mon);
+ printk("tm_mday: %i\n",dt->tm_mday);
+ printk("tm_wday: %i\n",dt->tm_wday);
+#endif
+
+ return 0;
+}
+
+
+static int v3020_set_time(struct device *dev, struct rtc_time *dt)
+{
+ struct v3020 *chip = dev_get_drvdata(dev);
+
+#ifdef DEBUG
+ printk("\n%s : Setting RTC values\n",__FUNCTION__);
+ printk("tm_sec : %i\n",dt->tm_sec);
+ printk("tm_min : %i\n",dt->tm_min);
+ printk("tm_hour: %i\n",dt->tm_hour);
+ printk("tm_mday: %i\n",dt->tm_mday);
+ printk("tm_wday: %i\n",dt->tm_wday);
+ printk("tm_year: %i\n",dt->tm_year);
+#endif
+
+ /* Write all the values to ram... */
+ v3020_set_reg(chip, V3020_SECONDS, BIN2BCD(dt->tm_sec));
+ v3020_set_reg(chip, V3020_MINUTES, BIN2BCD(dt->tm_min));
+ v3020_set_reg(chip, V3020_HOURS, BIN2BCD(dt->tm_hour));
+ v3020_set_reg(chip, V3020_MONTH_DAY, BIN2BCD(dt->tm_mday));
+ v3020_set_reg(chip, V3020_MONTH, BIN2BCD(dt->tm_mon));
+ v3020_set_reg(chip, V3020_WEEK_DAY, BIN2BCD(dt->tm_wday));
+ v3020_set_reg(chip, V3020_YEAR, BIN2BCD(dt->tm_year % 100));
+
+ /* ...and set the clock. */
+ v3020_set_reg(chip, V3020_CMD_RAM2CLOCK, 0);
+
+ /* Compulab used this delay here. I dont know why,
+ * the datasheet does not specify a delay. */
+ /*mdelay(5);*/
+
+ return 0;
+}
+
+static struct rtc_class_ops v3020_rtc_ops = {
+ .read_time = v3020_read_time,
+ .set_time = v3020_set_time,
+};
+
+static int rtc_probe(struct platform_device *pdev)
+{
+ struct v3020_platform_data *pdata = pdev->dev.platform_data;
+ struct v3020 *chip;
+ struct rtc_device *rtc;
+ int retval = -EBUSY;
+ int i;
+ int temp;
+
+ if (pdev->num_resources != 1)
+ return -EBUSY;
+
+ if (pdev->resource[0].flags != IORESOURCE_MEM)
+ return -EBUSY;
+
+ if (pdev == NULL)
+ return -EBUSY;
+
+ chip = kzalloc(sizeof *chip, GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->leftshift = pdata->leftshift;
+ chip->ioaddress = ioremap(pdev->resource[0].start, 1);
+ if (chip->ioaddress == NULL)
+ goto err_chip;
+
+ /* Make sure the v3020 expects a communication cycle
+ * by reading 8 times */
+ for (i = 0; i < 8; i++)
+ temp = readl(chip->ioaddress);
+
+ /* Test chip by doing a write/read sequence
+ * to the chip ram */
+ v3020_set_reg(chip, V3020_SECONDS, 0x33);
+ if(v3020_get_reg(chip, V3020_SECONDS) != 0x33) {
+ retval = -ENODEV;
+ goto err_io;
+ }
+
+ /* Make sure frequency measurment mode, test modes, and lock
+ * are all disabled */
+ v3020_set_reg(chip, V3020_STATUS_0, 0x0);
+
+ dev_info(&pdev->dev, "Chip available at physical address 0x%p,"
+ "data connected to D%d\n",
+ (void*)pdev->resource[0].start,
+ chip->leftshift);
+
+ platform_set_drvdata(pdev, chip);
+
+ rtc = rtc_device_register("v3020",
+ &pdev->dev, &v3020_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ retval = PTR_ERR(rtc);
+ goto err_io;
+ }
+ chip->rtc = rtc;
+
+ return 0;
+
+err_io:
+ iounmap(chip->ioaddress);
+err_chip:
+ kfree(chip);
+
+ return retval;
+}
+
+static int rtc_remove(struct platform_device *dev)
+{
+ struct v3020 *chip = platform_get_drvdata(dev);
+ struct rtc_device *rtc = chip->rtc;
+
+ if (rtc)
+ rtc_device_unregister(rtc);
+
+ iounmap(chip->ioaddress);
+ kfree(chip);
+
+ return 0;
+}
+
+static struct platform_driver rtc_device_driver = {
+ .probe = rtc_probe,
+ .remove = rtc_remove,
+ .driver = {
+ .name = "v3020",
+ .owner = THIS_MODULE,
+ },
+};
+
+static __init int v3020_init(void)
+{
+ return platform_driver_register(&rtc_device_driver);
+}
+
+static __exit void v3020_exit(void)
+{
+ platform_driver_unregister(&rtc_device_driver);
+}
+
+module_init(v3020_init);
+module_exit(v3020_exit);
+
+MODULE_DESCRIPTION("V3020 RTC");
+MODULE_AUTHOR("Raphael Assenat");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c
index 277596c..33e0292 100644
--- a/drivers/rtc/rtc-vr41xx.c
+++ b/drivers/rtc/rtc-vr41xx.c
@@ -81,7 +81,6 @@ MODULE_LICENSE("GPL");
#define RTC_FREQUENCY 32768
#define MAX_PERIODIC_RATE 6553
-#define MAX_USER_PERIODIC_RATE 64
static void __iomem *rtc1_base;
static void __iomem *rtc2_base;
@@ -240,9 +239,6 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
if (arg > MAX_PERIODIC_RATE)
return -EINVAL;
- if (arg > MAX_USER_PERIODIC_RATE && capable(CAP_SYS_RESOURCE) == 0)
- return -EACCES;
-
periodic_frequency = arg;
count = RTC_FREQUENCY;
@@ -263,10 +259,6 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
/* Doesn't support before 1900 */
if (arg < 1900)
return -EINVAL;
-
- if (capable(CAP_SYS_TIME) == 0)
- return -EACCES;
-
epoch = arg;
break;
default:
diff --git a/drivers/s390/char/sclp_quiesce.c b/drivers/s390/char/sclp_quiesce.c
index 56fa691..a4c53c1 100644
--- a/drivers/s390/char/sclp_quiesce.c
+++ b/drivers/s390/char/sclp_quiesce.c
@@ -13,6 +13,7 @@
#include <linux/cpumask.h>
#include <linux/smp.h>
#include <linux/init.h>
+#include <linux/reboot.h>
#include <asm/atomic.h>
#include <asm/ptrace.h>
#include <asm/sigp.h>
@@ -66,8 +67,6 @@ do_machine_quiesce(void)
}
#endif
-extern void ctrl_alt_del(void);
-
/* Handler for quiesce event. Start shutdown procedure. */
static void
sclp_quiesce_handler(struct evbuf_header *evbuf)
diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
index 0bab60a2..38aad83 100644
--- a/drivers/s390/net/qeth_eddp.c
+++ b/drivers/s390/net/qeth_eddp.c
@@ -420,7 +420,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
}
tcph = eddp->skb->h.th;
while (eddp->skb_offset < eddp->skb->len) {
- data_len = min((int)skb_shinfo(eddp->skb)->tso_size,
+ data_len = min((int)skb_shinfo(eddp->skb)->gso_size,
(int)(eddp->skb->len - eddp->skb_offset));
/* prepare qdio hdr */
if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2){
@@ -515,20 +515,20 @@ qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb,
QETH_DBF_TEXT(trace, 5, "eddpcanp");
/* can we put multiple skbs in one page? */
- skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->tso_size + hdr_len);
+ skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->gso_size + hdr_len);
if (skbs_per_page > 1){
- ctx->num_pages = (skb_shinfo(skb)->tso_segs + 1) /
+ ctx->num_pages = (skb_shinfo(skb)->gso_segs + 1) /
skbs_per_page + 1;
ctx->elements_per_skb = 1;
} else {
/* no -> how many elements per skb? */
- ctx->elements_per_skb = (skb_shinfo(skb)->tso_size + hdr_len +
+ ctx->elements_per_skb = (skb_shinfo(skb)->gso_size + hdr_len +
PAGE_SIZE) >> PAGE_SHIFT;
ctx->num_pages = ctx->elements_per_skb *
- (skb_shinfo(skb)->tso_segs + 1);
+ (skb_shinfo(skb)->gso_segs + 1);
}
ctx->num_elements = ctx->elements_per_skb *
- (skb_shinfo(skb)->tso_segs + 1);
+ (skb_shinfo(skb)->gso_segs + 1);
}
static inline struct qeth_eddp_context *
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index 9e671a4..56009d7 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -4417,7 +4417,7 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
struct qeth_eddp_context *ctx = NULL;
int tx_bytes = skb->len;
unsigned short nr_frags = skb_shinfo(skb)->nr_frags;
- unsigned short tso_size = skb_shinfo(skb)->tso_size;
+ unsigned short tso_size = skb_shinfo(skb)->gso_size;
int rc;
QETH_DBF_TEXT(trace, 6, "sendpkt");
@@ -4453,7 +4453,7 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
queue = card->qdio.out_qs
[qeth_get_priority_queue(card, skb, ipv, cast_type)];
- if (skb_shinfo(skb)->tso_size)
+ if (skb_shinfo(skb)->gso_size)
large_send = card->options.large_send;
/*are we able to do TSO ? If so ,prepare and send it from here */
diff --git a/drivers/s390/net/qeth_tso.h b/drivers/s390/net/qeth_tso.h
index 24ef40c..593f298 100644
--- a/drivers/s390/net/qeth_tso.h
+++ b/drivers/s390/net/qeth_tso.h
@@ -51,7 +51,7 @@ qeth_tso_fill_header(struct qeth_card *card, struct sk_buff *skb)
hdr->ext.hdr_version = 1;
hdr->ext.hdr_len = 28;
/*insert non-fix values */
- hdr->ext.mss = skb_shinfo(skb)->tso_size;
+ hdr->ext.mss = skb_shinfo(skb)->gso_size;
hdr->ext.dg_hdr_len = (__u16)(iph->ihl*4 + tcph->doff*4);
hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len -
sizeof(struct qeth_hdr_tso));
diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c
index d89f83f..1cc706e 100644
--- a/drivers/sbus/char/bbc_envctrl.c
+++ b/drivers/sbus/char/bbc_envctrl.c
@@ -575,9 +575,9 @@ int bbc_envctrl_init(void)
int devidx = 0;
while ((echild = bbc_i2c_getdev(devidx++)) != NULL) {
- if (!strcmp(echild->prom_name, "temperature"))
+ if (!strcmp(echild->prom_node->name, "temperature"))
attach_one_temp(echild, temp_index++);
- if (!strcmp(echild->prom_name, "fan-control"))
+ if (!strcmp(echild->prom_node->name, "fan-control"))
attach_one_fan(echild, fan_index++);
}
if (temp_index != 0 && fan_index != 0) {
diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c
index 3e156e0..7363437 100644
--- a/drivers/sbus/char/bbc_i2c.c
+++ b/drivers/sbus/char/bbc_i2c.c
@@ -423,7 +423,7 @@ static int __init bbc_present(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "bbc"))
+ if (!strcmp(edev->prom_node->name, "bbc"))
return 1;
}
}
@@ -446,7 +446,7 @@ static int __init bbc_i2c_init(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "i2c")) {
+ if (!strcmp(edev->prom_node->name, "i2c")) {
if (!attach_one_i2c(edev, index))
index++;
}
diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c
index c3a51d1..d92bc88 100644
--- a/drivers/sbus/char/display7seg.c
+++ b/drivers/sbus/char/display7seg.c
@@ -184,7 +184,7 @@ static int __init d7s_init(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, D7S_OBPNAME))
+ if (!strcmp(edev->prom_node->name, D7S_OBPNAME))
goto ebus_done;
}
}
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
index 19e8edd..cf97e9e 100644
--- a/drivers/sbus/char/envctrl.c
+++ b/drivers/sbus/char/envctrl.c
@@ -768,16 +768,14 @@ static void envctrl_set_mon(struct i2c_child_t *pchild,
* decoding tables, monitor type, optional properties.
* Return: None.
*/
-static void envctrl_init_adc(struct i2c_child_t *pchild, int node)
+static void envctrl_init_adc(struct i2c_child_t *pchild, struct device_node *dp)
{
- char chnls_desc[CHANNEL_DESC_SZ];
int i = 0, len;
- char *pos = chnls_desc;
+ char *pos;
+ unsigned int *pval;
/* Firmware describe channels into a stream separated by a '\0'. */
- len = prom_getproperty(node, "channels-description", chnls_desc,
- CHANNEL_DESC_SZ);
- chnls_desc[CHANNEL_DESC_SZ - 1] = '\0';
+ pos = of_get_property(dp, "channels-description", &len);
while (len > 0) {
int l = strlen(pos) + 1;
@@ -787,10 +785,13 @@ static void envctrl_init_adc(struct i2c_child_t *pchild, int node)
}
/* Get optional properties. */
- len = prom_getproperty(node, "warning-temp", (char *)&warning_temperature,
- sizeof(warning_temperature));
- len = prom_getproperty(node, "shutdown-temp", (char *)&shutdown_temperature,
- sizeof(shutdown_temperature));
+ pval = of_get_property(dp, "warning-temp", NULL);
+ if (pval)
+ warning_temperature = *pval;
+
+ pval = of_get_property(dp, "shutdown-temp", NULL);
+ if (pval)
+ shutdown_temperature = *pval;
}
/* Function Description: Initialize child device monitoring fan status.
@@ -864,21 +865,18 @@ static void envctrl_init_voltage_status(struct i2c_child_t *pchild)
static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
struct i2c_child_t *pchild)
{
- int node, len, i, tbls_size = 0;
-
- node = edev_child->prom_node;
+ int len, i, tbls_size = 0;
+ struct device_node *dp = edev_child->prom_node;
+ void *pval;
/* Get device address. */
- len = prom_getproperty(node, "reg",
- (char *) &(pchild->addr),
- sizeof(pchild->addr));
+ pval = of_get_property(dp, "reg", &len);
+ memcpy(&pchild->addr, pval, len);
/* Get tables property. Read firmware temperature tables. */
- len = prom_getproperty(node, "translation",
- (char *) pchild->tblprop_array,
- (PCF8584_MAX_CHANNELS *
- sizeof(struct pcf8584_tblprop)));
- if (len > 0) {
+ pval = of_get_property(dp, "translation", &len);
+ if (pval && len > 0) {
+ memcpy(pchild->tblprop_array, pval, len);
pchild->total_tbls = len / sizeof(struct pcf8584_tblprop);
for (i = 0; i < pchild->total_tbls; i++) {
if ((pchild->tblprop_array[i].size + pchild->tblprop_array[i].offset) > tbls_size) {
@@ -891,12 +889,12 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
printk("envctrl: Failed to allocate table.\n");
return;
}
- len = prom_getproperty(node, "tables",
- (char *) pchild->tables, tbls_size);
- if (len <= 0) {
+ pval = of_get_property(dp, "tables", &len);
+ if (!pval || len <= 0) {
printk("envctrl: Failed to get table.\n");
return;
}
+ memcpy(pchild->tables, pval, len);
}
/* SPARCengine ASM Reference Manual (ref. SMI doc 805-7581-04)
@@ -907,12 +905,11 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
* 'NULL' monitor type.
*/
if (ENVCTRL_CPCI_IGNORED_NODE == pchild->addr) {
+ struct device_node *root_node;
int len;
- char prop[56];
- len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop));
- if (0 < len && (0 == strncmp(prop, "SUNW,UltraSPARC-IIi-cEngine", len)))
- {
+ root_node = of_find_node_by_path("/");
+ if (!strcmp(root_node->name, "SUNW,UltraSPARC-IIi-cEngine")) {
for (len = 0; len < PCF8584_MAX_CHANNELS; ++len) {
pchild->mon_type[len] = ENVCTRL_NOMON;
}
@@ -921,16 +918,14 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
}
/* Get the monitor channels. */
- len = prom_getproperty(node, "channels-in-use",
- (char *) pchild->chnl_array,
- (PCF8584_MAX_CHANNELS *
- sizeof(struct pcf8584_channel)));
+ pval = of_get_property(dp, "channels-in-use", &len);
+ memcpy(pchild->chnl_array, pval, len);
pchild->total_chnls = len / sizeof(struct pcf8584_channel);
for (i = 0; i < pchild->total_chnls; i++) {
switch (pchild->chnl_array[i].type) {
case PCF8584_TEMP_TYPE:
- envctrl_init_adc(pchild, node);
+ envctrl_init_adc(pchild, dp);
break;
case PCF8584_GLOBALADDR_TYPE:
@@ -945,7 +940,7 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
case PCF8584_VOLTAGE_TYPE:
if (pchild->i2ctype == I2C_ADC) {
- envctrl_init_adc(pchild,node);
+ envctrl_init_adc(pchild,dp);
} else {
envctrl_init_voltage_status(pchild);
}
@@ -1046,7 +1041,7 @@ static int __init envctrl_init(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "bbc")) {
+ if (!strcmp(edev->prom_node->name, "bbc")) {
/* If we find a boot-bus controller node,
* then this envctrl driver is not for us.
*/
@@ -1060,14 +1055,14 @@ static int __init envctrl_init(void)
*/
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "i2c")) {
+ if (!strcmp(edev->prom_node->name, "i2c")) {
i2c = ioremap(edev->resource[0].start, 0x2);
for_each_edevchild(edev, edev_child) {
- if (!strcmp("gpio", edev_child->prom_name)) {
+ if (!strcmp("gpio", edev_child->prom_node->name)) {
i2c_childlist[i].i2ctype = I2C_GPIO;
envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++]));
}
- if (!strcmp("adc", edev_child->prom_name)) {
+ if (!strcmp("adc", edev_child->prom_node->name)) {
i2c_childlist[i].i2ctype = I2C_ADC;
envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++]));
}
diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c
index 2beb3dd..31b8a5f 100644
--- a/drivers/sbus/char/flash.c
+++ b/drivers/sbus/char/flash.c
@@ -71,7 +71,6 @@ flash_mmap(struct file *file, struct vm_area_struct *vma)
if (vma->vm_end - (vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT)) > size)
size = vma->vm_end - (vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT));
- vma->vm_flags |= (VM_SHM | VM_LOCKED);
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
if (io_remap_pfn_range(vma, vma->vm_start, addr, size, vma->vm_page_prot))
@@ -192,9 +191,11 @@ static int __init flash_init(void)
}
if (!sdev) {
#ifdef CONFIG_PCI
+ struct linux_prom_registers *ebus_regs;
+
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "flashprom"))
+ if (!strcmp(edev->prom_node->name, "flashprom"))
goto ebus_done;
}
}
@@ -202,23 +203,23 @@ static int __init flash_init(void)
if (!edev)
return -ENODEV;
- len = prom_getproperty(edev->prom_node, "reg", (void *)regs, sizeof(regs));
- if ((len % sizeof(regs[0])) != 0) {
+ ebus_regs = of_get_property(edev->prom_node, "reg", &len);
+ if (!ebus_regs || (len % sizeof(regs[0])) != 0) {
printk("flash: Strange reg property size %d\n", len);
return -ENODEV;
}
- nregs = len / sizeof(regs[0]);
+ nregs = len / sizeof(ebus_regs[0]);
flash.read_base = edev->resource[0].start;
- flash.read_size = regs[0].reg_size;
+ flash.read_size = ebus_regs[0].reg_size;
if (nregs == 1) {
flash.write_base = edev->resource[0].start;
- flash.write_size = regs[0].reg_size;
+ flash.write_size = ebus_regs[0].reg_size;
} else if (nregs == 2) {
flash.write_base = edev->resource[1].start;
- flash.write_size = regs[1].reg_size;
+ flash.write_size = ebus_regs[1].reg_size;
} else {
printk("flash: Strange number of regs %d\n", nregs);
return -ENODEV;
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
index 239e108..cf5b476 100644
--- a/drivers/sbus/char/openprom.c
+++ b/drivers/sbus/char/openprom.c
@@ -243,8 +243,8 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
((int *) opp->oprom_array)[1]);
pcp = pdev->sysdata;
- if (pcp != NULL && pcp->prom_node != -1 && pcp->prom_node) {
- node = pcp->prom_node;
+ if (pcp != NULL) {
+ node = pcp->prom_node->node;
data->current_node = node;
*((int *)opp->oprom_array) = node;
opp->oprom_size = sizeof(int);
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
index dfdd6be..ddcd330 100644
--- a/drivers/sbus/char/vfc_dev.c
+++ b/drivers/sbus/char/vfc_dev.c
@@ -623,7 +623,7 @@ static int vfc_mmap(struct file *file, struct vm_area_struct *vma)
map_size = sizeof(struct vfc_regs);
vma->vm_flags |=
- (VM_SHM | VM_LOCKED | VM_IO | VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE);
+ (VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE);
map_offset = (unsigned int) (long)dev->phys_regs;
ret = io_remap_pfn_range(vma, vma->vm_start,
MK_IOSPACE_PFN(dev->which_io,
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
index 5d30a3e..387a6aa 100644
--- a/drivers/sbus/sbus.c
+++ b/drivers/sbus/sbus.c
@@ -1,7 +1,6 @@
-/* $Id: sbus.c,v 1.100 2002/01/24 15:36:24 davem Exp $
- * sbus.c: SBus support routines.
+/* sbus.c: SBus support routines.
*
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 2006 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
@@ -14,237 +13,76 @@
#include <asm/sbus.h>
#include <asm/dma.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
#include <asm/bpp.h>
#include <asm/irq.h>
-struct sbus_bus *sbus_root = NULL;
+struct sbus_bus *sbus_root;
-static struct linux_prom_irqs irqs[PROMINTR_MAX] __initdata = { { 0 } };
-#ifdef CONFIG_SPARC32
-static int interrupts[PROMINTR_MAX] __initdata = { 0 };
-#endif
-
-#ifdef CONFIG_PCI
-extern int pcic_present(void);
-#endif
-
-/* Perhaps when I figure out more about the iommu we'll put a
- * device registration routine here that probe_sbus() calls to
- * setup the iommu for each Sbus.
- */
-
-/* We call this for each SBus device, and fill the structure based
- * upon the prom device tree. We return the start of memory after
- * the things we have allocated.
- */
-
-/* #define DEBUG_FILL */
-
-static void __init fill_sbus_device(int prom_node, struct sbus_dev *sdev)
+static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
{
- unsigned long address, base;
+ unsigned long base;
+ void *pval;
int len;
- sdev->prom_node = prom_node;
- prom_getstring(prom_node, "name",
- sdev->prom_name, sizeof(sdev->prom_name));
- address = prom_getint(prom_node, "address");
- len = prom_getproperty(prom_node, "reg",
- (char *) sdev->reg_addrs,
- sizeof(sdev->reg_addrs));
- if (len == -1) {
- sdev->num_registers = 0;
- goto no_regs;
- }
+ sdev->prom_node = dp->node;
+ strcpy(sdev->prom_name, dp->name);
- if (len % sizeof(struct linux_prom_registers)) {
- prom_printf("fill_sbus_device: proplen for regs of %s "
- " was %d, need multiple of %d\n",
- sdev->prom_name, len,
- (int) sizeof(struct linux_prom_registers));
- prom_halt();
- }
- if (len > (sizeof(struct linux_prom_registers) * PROMREG_MAX)) {
- prom_printf("fill_sbus_device: Too many register properties "
- "for device %s, len=%d\n",
- sdev->prom_name, len);
- prom_halt();
- }
- sdev->num_registers = len / sizeof(struct linux_prom_registers);
- sdev->ranges_applied = 0;
+ pval = of_get_property(dp, "reg", &len);
+ sdev->num_registers = 0;
+ if (pval) {
+ memcpy(sdev->reg_addrs, pval, len);
- base = (unsigned long) sdev->reg_addrs[0].phys_addr;
+ sdev->num_registers =
+ len / sizeof(struct linux_prom_registers);
- /* Compute the slot number. */
- if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m) {
- sdev->slot = sbus_dev_slot(base);
- } else {
- sdev->slot = sdev->reg_addrs[0].which_io;
- }
+ base = (unsigned long) sdev->reg_addrs[0].phys_addr;
-no_regs:
- len = prom_getproperty(prom_node, "ranges",
- (char *)sdev->device_ranges,
- sizeof(sdev->device_ranges));
- if (len == -1) {
- sdev->num_device_ranges = 0;
- goto no_ranges;
- }
- if (len % sizeof(struct linux_prom_ranges)) {
- prom_printf("fill_sbus_device: proplen for ranges of %s "
- " was %d, need multiple of %d\n",
- sdev->prom_name, len,
- (int) sizeof(struct linux_prom_ranges));
- prom_halt();
- }
- if (len > (sizeof(struct linux_prom_ranges) * PROMREG_MAX)) {
- prom_printf("fill_sbus_device: Too many range properties "
- "for device %s, len=%d\n",
- sdev->prom_name, len);
- prom_halt();
+ /* Compute the slot number. */
+ if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m)
+ sdev->slot = sbus_dev_slot(base);
+ else
+ sdev->slot = sdev->reg_addrs[0].which_io;
}
- sdev->num_device_ranges =
- len / sizeof(struct linux_prom_ranges);
-
-no_ranges:
- /* XXX Unfortunately, IRQ issues are very arch specific.
- * XXX Pull this crud out into an arch specific area
- * XXX at some point. -DaveM
- */
-#ifdef CONFIG_SPARC64
- len = prom_getproperty(prom_node, "interrupts",
- (char *) irqs, sizeof(irqs));
- if (len == -1 || len == 0) {
- sdev->irqs[0] = 0;
- sdev->num_irqs = 0;
- } else {
- unsigned int pri = irqs[0].pri;
-
- sdev->num_irqs = 1;
- if (pri < 0x20)
- pri += sdev->slot * 8;
-
- sdev->irqs[0] = sbus_build_irq(sdev->bus, pri);
+
+ pval = of_get_property(dp, "ranges", &len);
+ sdev->num_device_ranges = 0;
+ if (pval) {
+ memcpy(sdev->device_ranges, pval, len);
+ sdev->num_device_ranges =
+ len / sizeof(struct linux_prom_ranges);
}
-#endif /* CONFIG_SPARC64 */
-
-#ifdef CONFIG_SPARC32
- len = prom_getproperty(prom_node, "intr",
- (char *)irqs, sizeof(irqs));
- if (len != -1) {
- sdev->num_irqs = len / 8;
- if (sdev->num_irqs == 0) {
- sdev->irqs[0] = 0;
- } else if (sparc_cpu_model == sun4d) {
- extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq);
-
- for (len = 0; len < sdev->num_irqs; len++)
- sdev->irqs[len] = sun4d_build_irq(sdev, irqs[len].pri);
- } else {
- for (len = 0; len < sdev->num_irqs; len++)
- sdev->irqs[len] = irqs[len].pri;
- }
- } else {
- /* No "intr" node found-- check for "interrupts" node.
- * This node contains SBus interrupt levels, not IPLs
- * as in "intr", and no vector values. We convert
- * SBus interrupt levels to PILs (platform specific).
- */
- len = prom_getproperty(prom_node, "interrupts",
- (char *)interrupts, sizeof(interrupts));
- if (len == -1) {
- sdev->irqs[0] = 0;
- sdev->num_irqs = 0;
- } else {
- sdev->num_irqs = len / sizeof(int);
- for (len = 0; len < sdev->num_irqs; len++) {
- sdev->irqs[len] = sbint_to_irq(sdev, interrupts[len]);
- }
- }
- }
-#endif /* CONFIG_SPARC32 */
-}
-/* This routine gets called from whoever needs the sbus first, to scan
- * the SBus device tree. Currently it just prints out the devices
- * found on the bus and builds trees of SBUS structs and attached
- * devices.
- */
+ sbus_fill_device_irq(sdev);
-extern void iommu_init(int iommu_node, struct sbus_bus *sbus);
-extern void iounit_init(int sbi_node, int iounit_node, struct sbus_bus *sbus);
-void sun4_init(void);
-#ifdef CONFIG_SUN_AUXIO
-extern void auxio_probe(void);
-#endif
-
-static void __init sbus_do_child_siblings(int start_node,
- struct sbus_dev *child,
- struct sbus_dev *parent,
- struct sbus_bus *sbus)
-{
- struct sbus_dev *this_dev = child;
- int this_node = start_node;
-
- /* Child already filled in, just need to traverse siblings. */
- child->child = NULL;
- child->parent = parent;
- while((this_node = prom_getsibling(this_node)) != 0) {
- this_dev->next = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
- this_dev = this_dev->next;
- this_dev->next = NULL;
- this_dev->parent = parent;
-
- this_dev->bus = sbus;
- fill_sbus_device(this_node, this_dev);
-
- if(prom_getchild(this_node)) {
- this_dev->child = kmalloc(sizeof(struct sbus_dev),
- GFP_ATOMIC);
- this_dev->child->bus = sbus;
- this_dev->child->next = NULL;
- fill_sbus_device(prom_getchild(this_node), this_dev->child);
- sbus_do_child_siblings(prom_getchild(this_node),
- this_dev->child, this_dev, sbus);
- } else {
- this_dev->child = NULL;
- }
- }
-}
+ sdev->ofdev.node = dp;
+ if (sdev->parent)
+ sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev;
+ else
+ sdev->ofdev.dev.parent = &sdev->bus->ofdev.dev;
+ sdev->ofdev.dev.bus = &sbus_bus_type;
+ strcpy(sdev->ofdev.dev.bus_id, dp->path_component_name);
-/*
- * XXX This functions appears to be a distorted version of
- * prom_sbus_ranges_init(), with all sun4d stuff cut away.
- * Ask DaveM what is going on here, how is sun4d supposed to work... XXX
- */
-/* added back sun4d patch from Thomas Bogendoerfer - should be OK (crn) */
+ if (of_device_register(&sdev->ofdev) != 0)
+ printk(KERN_DEBUG "sbus: device registration error for %s!\n",
+ sdev->ofdev.dev.bus_id);
+}
-static void __init sbus_bus_ranges_init(int parent_node, struct sbus_bus *sbus)
+static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus)
{
+ void *pval;
int len;
- len = prom_getproperty(sbus->prom_node, "ranges",
- (char *) sbus->sbus_ranges,
- sizeof(sbus->sbus_ranges));
- if (len == -1 || len == 0) {
- sbus->num_sbus_ranges = 0;
- return;
- }
- sbus->num_sbus_ranges = len / sizeof(struct linux_prom_ranges);
-#ifdef CONFIG_SPARC32
- if (sparc_cpu_model == sun4d) {
- struct linux_prom_ranges iounit_ranges[PROMREG_MAX];
- int num_iounit_ranges;
-
- len = prom_getproperty(parent_node, "ranges",
- (char *) iounit_ranges,
- sizeof (iounit_ranges));
- if (len != -1) {
- num_iounit_ranges = (len/sizeof(struct linux_prom_ranges));
- prom_adjust_ranges (sbus->sbus_ranges, sbus->num_sbus_ranges, iounit_ranges, num_iounit_ranges);
- }
+ pval = of_get_property(dp, "ranges", &len);
+ sbus->num_sbus_ranges = 0;
+ if (pval) {
+ memcpy(sbus->sbus_ranges, pval, len);
+ sbus->num_sbus_ranges =
+ len / sizeof(struct linux_prom_ranges);
+
+ sbus_arch_bus_ranges_init(dp->parent, sbus);
}
-#endif
}
static void __init __apply_ranges_to_regs(struct linux_prom_ranges *ranges,
@@ -322,241 +160,127 @@ static void __init sbus_fixup_all_regs(struct sbus_dev *first_sdev)
}
}
-extern void register_proc_sparc_ioport(void);
-extern void firetruck_init(void);
+/* We preserve the "probe order" of these bus and device lists to give
+ * the same ordering as the old code.
+ */
+static void __init sbus_insert(struct sbus_bus *sbus, struct sbus_bus **root)
+{
+ while (*root)
+ root = &(*root)->next;
+ *root = sbus;
+ sbus->next = NULL;
+}
-#ifdef CONFIG_SUN4
-extern void sun4_dvma_init(void);
-#endif
+static void __init sdev_insert(struct sbus_dev *sdev, struct sbus_dev **root)
+{
+ while (*root)
+ root = &(*root)->next;
+ *root = sdev;
+ sdev->next = NULL;
+}
-static int __init sbus_init(void)
+static void __init walk_children(struct device_node *dp, struct sbus_dev *parent, struct sbus_bus *sbus)
{
- int nd, this_sbus, sbus_devs, topnd, iommund;
- unsigned int sbus_clock;
- struct sbus_bus *sbus;
- struct sbus_dev *this_dev;
- int num_sbus = 0; /* How many did we find? */
+ dp = dp->child;
+ while (dp) {
+ struct sbus_dev *sdev;
-#ifdef CONFIG_SPARC32
- register_proc_sparc_ioport();
-#endif
+ sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
+ if (sdev) {
+ sdev_insert(sdev, &parent->child);
-#ifdef CONFIG_SUN4
- sun4_dvma_init();
- return 0;
-#endif
-
- topnd = prom_getchild(prom_root_node);
-
- /* Finding the first sbus is a special case... */
- iommund = 0;
- if(sparc_cpu_model == sun4u) {
- nd = prom_searchsiblings(topnd, "sbus");
- if(nd == 0) {
-#ifdef CONFIG_PCI
- if (!pcic_present()) {
- prom_printf("Neither SBUS nor PCI found.\n");
- prom_halt();
- } else {
-#ifdef CONFIG_SPARC64
- firetruck_init();
-#endif
- }
- return 0;
-#else
- prom_printf("YEEE, UltraSparc sbus not found\n");
- prom_halt();
-#endif
- }
- } else if(sparc_cpu_model == sun4d) {
- if((iommund = prom_searchsiblings(topnd, "io-unit")) == 0 ||
- (nd = prom_getchild(iommund)) == 0 ||
- (nd = prom_searchsiblings(nd, "sbi")) == 0) {
- panic("sbi not found");
- }
- } else if((nd = prom_searchsiblings(topnd, "sbus")) == 0) {
- if((iommund = prom_searchsiblings(topnd, "iommu")) == 0 ||
- (nd = prom_getchild(iommund)) == 0 ||
- (nd = prom_searchsiblings(nd, "sbus")) == 0) {
-#ifdef CONFIG_PCI
- if (!pcic_present()) {
- prom_printf("Neither SBUS nor PCI found.\n");
- prom_halt();
- }
- return 0;
-#else
- /* No reason to run further - the data access trap will occur. */
- panic("sbus not found");
-#endif
+ sdev->bus = sbus;
+ sdev->parent = parent;
+
+ fill_sbus_device(dp, sdev);
+
+ walk_children(dp, sdev, sbus);
}
+ dp = dp->sibling;
}
+}
- /* Ok, we've found the first one, allocate first SBus struct
- * and place in chain.
- */
- sbus = sbus_root = kmalloc(sizeof(struct sbus_bus), GFP_ATOMIC);
- sbus->next = NULL;
- sbus->prom_node = nd;
- this_sbus = nd;
+static void __init build_one_sbus(struct device_node *dp, int num_sbus)
+{
+ struct sbus_bus *sbus;
+ unsigned int sbus_clock;
+ struct device_node *dev_dp;
- if(iommund && sparc_cpu_model != sun4u && sparc_cpu_model != sun4d)
- iommu_init(iommund, sbus);
+ sbus = kzalloc(sizeof(struct sbus_bus), GFP_ATOMIC);
+ if (!sbus)
+ return;
- /* Loop until we find no more SBUS's */
- while(this_sbus) {
-#ifdef CONFIG_SPARC64
- /* IOMMU hides inside SBUS/SYSIO prom node on Ultra. */
- if(sparc_cpu_model == sun4u) {
- extern void sbus_iommu_init(int prom_node, struct sbus_bus *sbus);
+ sbus_insert(sbus, &sbus_root);
+ sbus->prom_node = dp->node;
- sbus_iommu_init(this_sbus, sbus);
- }
-#endif /* CONFIG_SPARC64 */
-
-#ifdef CONFIG_SPARC32
- if (sparc_cpu_model == sun4d)
- iounit_init(this_sbus, iommund, sbus);
-#endif /* CONFIG_SPARC32 */
- printk("sbus%d: ", num_sbus);
- sbus_clock = prom_getint(this_sbus, "clock-frequency");
- if(sbus_clock == -1)
- sbus_clock = (25*1000*1000);
- printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000),
- (int) (((sbus_clock/1000)%1000 != 0) ?
- (((sbus_clock/1000)%1000) + 1000) : 0));
-
- prom_getstring(this_sbus, "name",
- sbus->prom_name, sizeof(sbus->prom_name));
- sbus->clock_freq = sbus_clock;
-#ifdef CONFIG_SPARC32
- if (sparc_cpu_model == sun4d) {
- sbus->devid = prom_getint(iommund, "device-id");
- sbus->board = prom_getint(iommund, "board#");
- }
-#endif
-
- sbus_bus_ranges_init(iommund, sbus);
-
- sbus_devs = prom_getchild(this_sbus);
- if (!sbus_devs) {
- sbus->devices = NULL;
- goto next_bus;
- }
+ sbus_setup_iommu(sbus, dp);
- sbus->devices = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
-
- this_dev = sbus->devices;
- this_dev->next = NULL;
-
- this_dev->bus = sbus;
- this_dev->parent = NULL;
- fill_sbus_device(sbus_devs, this_dev);
-
- /* Should we traverse for children? */
- if(prom_getchild(sbus_devs)) {
- /* Allocate device node */
- this_dev->child = kmalloc(sizeof(struct sbus_dev),
- GFP_ATOMIC);
- /* Fill it */
- this_dev->child->bus = sbus;
- this_dev->child->next = NULL;
- fill_sbus_device(prom_getchild(sbus_devs),
- this_dev->child);
- sbus_do_child_siblings(prom_getchild(sbus_devs),
- this_dev->child,
- this_dev,
- sbus);
- } else {
- this_dev->child = NULL;
- }
+ printk("sbus%d: ", num_sbus);
- while((sbus_devs = prom_getsibling(sbus_devs)) != 0) {
- /* Allocate device node */
- this_dev->next = kmalloc(sizeof(struct sbus_dev),
- GFP_ATOMIC);
- this_dev = this_dev->next;
- this_dev->next = NULL;
-
- /* Fill it */
- this_dev->bus = sbus;
- this_dev->parent = NULL;
- fill_sbus_device(sbus_devs, this_dev);
-
- /* Is there a child node hanging off of us? */
- if(prom_getchild(sbus_devs)) {
- /* Get new device struct */
- this_dev->child = kmalloc(sizeof(struct sbus_dev),
- GFP_ATOMIC);
- /* Fill it */
- this_dev->child->bus = sbus;
- this_dev->child->next = NULL;
- fill_sbus_device(prom_getchild(sbus_devs),
- this_dev->child);
- sbus_do_child_siblings(prom_getchild(sbus_devs),
- this_dev->child,
- this_dev,
- sbus);
- } else {
- this_dev->child = NULL;
- }
+ sbus_clock = of_getintprop_default(dp, "clock-frequency",
+ (25*1000*1000));
+ sbus->clock_freq = sbus_clock;
+
+ printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000),
+ (int) (((sbus_clock/1000)%1000 != 0) ?
+ (((sbus_clock/1000)%1000) + 1000) : 0));
+
+ strcpy(sbus->prom_name, dp->name);
+
+ sbus_setup_arch_props(sbus, dp);
+
+ sbus_bus_ranges_init(dp, sbus);
+
+ sbus->ofdev.node = dp;
+ sbus->ofdev.dev.parent = NULL;
+ sbus->ofdev.dev.bus = &sbus_bus_type;
+ strcpy(sbus->ofdev.dev.bus_id, dp->path_component_name);
+
+ if (of_device_register(&sbus->ofdev) != 0)
+ printk(KERN_DEBUG "sbus: device registration error for %s!\n",
+ sbus->ofdev.dev.bus_id);
+
+ dev_dp = dp->child;
+ while (dev_dp) {
+ struct sbus_dev *sdev;
+
+ sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
+ if (sdev) {
+ sdev_insert(sdev, &sbus->devices);
+
+ sdev->bus = sbus;
+ sdev->parent = NULL;
+ fill_sbus_device(dev_dp, sdev);
+
+ walk_children(dev_dp, sdev, sbus);
}
+ dev_dp = dev_dp->sibling;
+ }
- /* Walk all devices and apply parent ranges. */
- sbus_fixup_all_regs(sbus->devices);
+ sbus_fixup_all_regs(sbus->devices);
- dvma_init(sbus);
- next_bus:
+ dvma_init(sbus);
+}
+
+static int __init sbus_init(void)
+{
+ struct device_node *dp;
+ const char *sbus_name = "sbus";
+ int num_sbus = 0;
+
+ if (sbus_arch_preinit())
+ return 0;
+
+ if (sparc_cpu_model == sun4d)
+ sbus_name = "sbi";
+
+ for_each_node_by_name(dp, sbus_name) {
+ build_one_sbus(dp, num_sbus);
num_sbus++;
- if(sparc_cpu_model == sun4u) {
- this_sbus = prom_getsibling(this_sbus);
- if(!this_sbus)
- break;
- this_sbus = prom_searchsiblings(this_sbus, "sbus");
- } else if(sparc_cpu_model == sun4d) {
- iommund = prom_getsibling(iommund);
- if(!iommund)
- break;
- iommund = prom_searchsiblings(iommund, "io-unit");
- if(!iommund)
- break;
- this_sbus = prom_searchsiblings(prom_getchild(iommund), "sbi");
- } else {
- this_sbus = prom_getsibling(this_sbus);
- if(!this_sbus)
- break;
- this_sbus = prom_searchsiblings(this_sbus, "sbus");
- }
- if(this_sbus) {
- sbus->next = kmalloc(sizeof(struct sbus_bus), GFP_ATOMIC);
- sbus = sbus->next;
- sbus->next = NULL;
- sbus->prom_node = this_sbus;
- } else {
- break;
- }
- } /* while(this_sbus) */
- if (sparc_cpu_model == sun4d) {
- extern void sun4d_init_sbi_irq(void);
- sun4d_init_sbi_irq();
- }
-
-#ifdef CONFIG_SPARC64
- if (sparc_cpu_model == sun4u) {
- firetruck_init();
}
-#endif
-#ifdef CONFIG_SUN_AUXIO
- if (sparc_cpu_model == sun4u)
- auxio_probe ();
-#endif
-#ifdef CONFIG_SPARC64
- if (sparc_cpu_model == sun4u) {
- extern void clock_probe(void);
-
- clock_probe();
- }
-#endif
+
+ sbus_arch_postinit();
return 0;
}
diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h
index d804195..7f22a06 100644
--- a/drivers/scsi/53c700.h
+++ b/drivers/scsi/53c700.h
@@ -474,8 +474,7 @@ NCR_700_readl(struct Scsi_Host *host, __u32 reg)
ioread32(hostdata->base + reg);
#if 1
/* sanity check the register */
- if((reg & 0x3) != 0)
- BUG();
+ BUG_ON((reg & 0x3) != 0);
#endif
return value;
@@ -498,8 +497,7 @@ NCR_700_writel(__u32 value, struct Scsi_Host *host, __u32 reg)
#if 1
/* sanity check the register */
- if((reg & 0x3) != 0)
- BUG();
+ BUG_ON((reg & 0x3) != 0);
#endif
bEBus ? iowrite32be(value, hostdata->base + reg):
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index d8e2fc9..ebd0cf0 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -166,7 +166,7 @@ ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \
CFLAGS_ncr53c8xx.o := $(ncr53c8xx-flags-y) $(ncr53c8xx-flags-m)
zalon7xx-objs := zalon.o ncr53c8xx.o
NCR_Q720_mod-objs := NCR_Q720.o ncr53c8xx.o
-libata-objs := libata-core.o libata-scsi.o libata-bmdma.o
+libata-objs := libata-core.o libata-scsi.o libata-bmdma.o libata-eh.o
oktagon_esp_mod-objs := oktagon_esp.o oktagon_io.o
# Files generated that shall be removed upon make clean
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index ea9e038..83b5c7d 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -396,8 +396,7 @@ static void get_container_name_callback(void *context, struct fib * fibptr)
scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
dprintk((KERN_DEBUG "get_container_name_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies));
- if (fibptr == NULL)
- BUG();
+ BUG_ON(fibptr == NULL);
get_name_reply = (struct aac_get_name_resp *) fib_data(fibptr);
/* Failure is irrelevant, using default value instead */
@@ -956,8 +955,7 @@ static void io_callback(void *context, struct fib * fibptr)
smp_processor_id(), (unsigned long long)lba, jiffies);
}
- if (fibptr == NULL)
- BUG();
+ BUG_ON(fibptr == NULL);
if(scsicmd->use_sg)
pci_unmap_sg(dev->pdev,
@@ -1092,8 +1090,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid)
aac_build_sgraw(scsicmd, &readcmd->sg);
fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(readcmd->sg.count) - 1) * sizeof (struct sgentryraw));
- if (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)))
- BUG();
+ BUG_ON(fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)));
/*
* Now send the Fib to the adapter
*/
@@ -1261,8 +1258,7 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid)
aac_build_sgraw(scsicmd, &writecmd->sg);
fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(writecmd->sg.count) - 1) * sizeof (struct sgentryraw));
- if (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)))
- BUG();
+ BUG_ON(fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)));
/*
* Now send the Fib to the adapter
*/
@@ -1904,8 +1900,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
- if (fibptr == NULL)
- BUG();
+ BUG_ON(fibptr == NULL);
srbreply = (struct aac_srb_reply *) fib_data(fibptr);
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index d2ef17e..3f27419 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -229,8 +229,7 @@ void aac_fib_init(struct fib *fibptr)
static void fib_dealloc(struct fib * fibptr)
{
struct hw_fib *hw_fib = fibptr->hw_fib;
- if(hw_fib->header.StructType != FIB_MAGIC)
- BUG();
+ BUG_ON(hw_fib->header.StructType != FIB_MAGIC);
hw_fib->header.XferState = 0;
}
@@ -530,8 +529,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
}
} else
down(&fibptr->event_wait);
- if(fibptr->done == 0)
- BUG();
+ BUG_ON(fibptr->done == 0);
if((fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)){
return -ETIMEDOUT;
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 2a41963..5ee4755 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -17316,7 +17316,7 @@ AdvWaitEEPCmd(AdvPortAddr iop_base)
/*
* Write the EEPROM from 'cfg_buf'.
*/
-void
+void __init
AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
{
ushort *wbuf;
@@ -17383,7 +17383,7 @@ AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
/*
* Write the EEPROM from 'cfg_buf'.
*/
-void
+void __init
AdvSet38C0800EEPConfig(AdvPortAddr iop_base,
ADVEEP_38C0800_CONFIG *cfg_buf)
{
@@ -17451,7 +17451,7 @@ AdvSet38C0800EEPConfig(AdvPortAddr iop_base,
/*
* Write the EEPROM from 'cfg_buf'.
*/
-void
+void __init
AdvSet38C1600EEPConfig(AdvPortAddr iop_base,
ADVEEP_38C1600_CONFIG *cfg_buf)
{
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index b4f8fb1..4bb77f6 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -48,7 +48,7 @@
#include <asm/io.h>
#define DRV_NAME "ahci"
-#define DRV_VERSION "1.2"
+#define DRV_VERSION "1.3"
enum {
@@ -56,12 +56,15 @@ enum {
AHCI_MAX_SG = 168, /* hardware max is 64K */
AHCI_DMA_BOUNDARY = 0xffffffff,
AHCI_USE_CLUSTERING = 0,
- AHCI_CMD_SLOT_SZ = 32 * 32,
+ AHCI_MAX_CMDS = 32,
+ AHCI_CMD_SZ = 32,
+ AHCI_CMD_SLOT_SZ = AHCI_MAX_CMDS * AHCI_CMD_SZ,
AHCI_RX_FIS_SZ = 256,
- AHCI_CMD_TBL_HDR = 0x80,
AHCI_CMD_TBL_CDB = 0x40,
- AHCI_CMD_TBL_SZ = AHCI_CMD_TBL_HDR + (AHCI_MAX_SG * 16),
- AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_SZ +
+ AHCI_CMD_TBL_HDR_SZ = 0x80,
+ AHCI_CMD_TBL_SZ = AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
+ AHCI_CMD_TBL_AR_SZ = AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
+ AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
AHCI_RX_FIS_SZ,
AHCI_IRQ_ON_SG = (1 << 31),
AHCI_CMD_ATAPI = (1 << 5),
@@ -71,8 +74,10 @@ enum {
AHCI_CMD_CLR_BUSY = (1 << 10),
RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */
+ RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
board_ahci = 0,
+ board_ahci_vt8251 = 1,
/* global controller registers */
HOST_CAP = 0x00, /* host capabilities */
@@ -87,8 +92,9 @@ enum {
HOST_AHCI_EN = (1 << 31), /* AHCI enabled */
/* HOST_CAP bits */
- HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
HOST_CAP_CLO = (1 << 24), /* Command List Override support */
+ HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
+ HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
/* registers for each SATA port */
PORT_LST_ADDR = 0x00, /* command list DMA addr */
@@ -127,15 +133,17 @@ enum {
PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */
PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */
- PORT_IRQ_FATAL = PORT_IRQ_TF_ERR |
- PORT_IRQ_HBUS_ERR |
- PORT_IRQ_HBUS_DATA_ERR |
- PORT_IRQ_IF_ERR,
- DEF_PORT_IRQ = PORT_IRQ_FATAL | PORT_IRQ_PHYRDY |
- PORT_IRQ_CONNECT | PORT_IRQ_SG_DONE |
- PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_FIS |
- PORT_IRQ_DMAS_FIS | PORT_IRQ_PIOS_FIS |
- PORT_IRQ_D2H_REG_FIS,
+ PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR |
+ PORT_IRQ_IF_ERR |
+ PORT_IRQ_CONNECT |
+ PORT_IRQ_PHYRDY |
+ PORT_IRQ_UNK_FIS,
+ PORT_IRQ_ERROR = PORT_IRQ_FREEZE |
+ PORT_IRQ_TF_ERR |
+ PORT_IRQ_HBUS_DATA_ERR,
+ DEF_PORT_IRQ = PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
+ PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
+ PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
/* PORT_CMD bits */
PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */
@@ -153,6 +161,10 @@ enum {
/* hpriv->flags bits */
AHCI_FLAG_MSI = (1 << 0),
+
+ /* ap->flags bits */
+ AHCI_FLAG_RESET_NEEDS_CLO = (1 << 24),
+ AHCI_FLAG_NO_NCQ = (1 << 25),
};
struct ahci_cmd_hdr {
@@ -181,7 +193,6 @@ struct ahci_port_priv {
dma_addr_t cmd_slot_dma;
void *cmd_tbl;
dma_addr_t cmd_tbl_dma;
- struct ahci_sg *cmd_tbl_sg;
void *rx_fis;
dma_addr_t rx_fis_dma;
};
@@ -191,15 +202,16 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
-static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes);
static void ahci_irq_clear(struct ata_port *ap);
-static void ahci_eng_timeout(struct ata_port *ap);
static int ahci_port_start(struct ata_port *ap);
static void ahci_port_stop(struct ata_port *ap);
static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
static void ahci_qc_prep(struct ata_queued_cmd *qc);
static u8 ahci_check_status(struct ata_port *ap);
-static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
+static void ahci_freeze(struct ata_port *ap);
+static void ahci_thaw(struct ata_port *ap);
+static void ahci_error_handler(struct ata_port *ap);
+static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
static void ahci_remove_one (struct pci_dev *pdev);
static struct scsi_host_template ahci_sht = {
@@ -207,7 +219,8 @@ static struct scsi_host_template ahci_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .can_queue = ATA_DEF_QUEUE,
+ .change_queue_depth = ata_scsi_change_queue_depth,
+ .can_queue = AHCI_MAX_CMDS - 1,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = AHCI_MAX_SG,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
@@ -216,6 +229,7 @@ static struct scsi_host_template ahci_sht = {
.proc_name = DRV_NAME,
.dma_boundary = AHCI_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
};
@@ -228,19 +242,21 @@ static const struct ata_port_operations ahci_ops = {
.tf_read = ahci_tf_read,
- .probe_reset = ahci_probe_reset,
-
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
- .eng_timeout = ahci_eng_timeout,
-
.irq_handler = ahci_interrupt,
.irq_clear = ahci_irq_clear,
.scr_read = ahci_scr_read,
.scr_write = ahci_scr_write,
+ .freeze = ahci_freeze,
+ .thaw = ahci_thaw,
+
+ .error_handler = ahci_error_handler,
+ .post_internal_cmd = ahci_post_internal_cmd,
+
.port_start = ahci_port_start,
.port_stop = ahci_port_stop,
};
@@ -250,7 +266,19 @@ static const struct ata_port_info ahci_port_info[] = {
{
.sht = &ahci_sht,
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+ ATA_FLAG_SKIP_D2H_BSY,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .port_ops = &ahci_ops,
+ },
+ /* board_ahci_vt8251 */
+ {
+ .sht = &ahci_sht,
+ .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+ ATA_FLAG_SKIP_D2H_BSY |
+ AHCI_FLAG_RESET_NEEDS_CLO | AHCI_FLAG_NO_NCQ,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &ahci_ops,
@@ -258,6 +286,7 @@ static const struct ata_port_info ahci_port_info[] = {
};
static const struct pci_device_id ahci_pci_tbl[] = {
+ /* Intel */
{ PCI_VENDOR_ID_INTEL, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_ahci }, /* ICH6 */
{ PCI_VENDOR_ID_INTEL, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
@@ -288,14 +317,39 @@ static const struct pci_device_id ahci_pci_tbl[] = {
board_ahci }, /* ICH8M */
{ PCI_VENDOR_ID_INTEL, 0x282a, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_ahci }, /* ICH8M */
+
+ /* JMicron */
{ 0x197b, 0x2360, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_ahci }, /* JMicron JMB360 */
+ { 0x197b, 0x2361, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* JMicron JMB361 */
{ 0x197b, 0x2363, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_ahci }, /* JMicron JMB363 */
+ { 0x197b, 0x2365, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* JMicron JMB365 */
+ { 0x197b, 0x2366, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* JMicron JMB366 */
+
+ /* ATI */
{ PCI_VENDOR_ID_ATI, 0x4380, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_ahci }, /* ATI SB600 non-raid */
{ PCI_VENDOR_ID_ATI, 0x4381, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_ahci }, /* ATI SB600 raid */
+
+ /* VIA */
+ { PCI_VENDOR_ID_VIA, 0x3349, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci_vt8251 }, /* VIA VT8251 */
+
+ /* NVIDIA */
+ { PCI_VENDOR_ID_NVIDIA, 0x044c, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* MCP65 */
+ { PCI_VENDOR_ID_NVIDIA, 0x044d, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* MCP65 */
+ { PCI_VENDOR_ID_NVIDIA, 0x044e, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* MCP65 */
+ { PCI_VENDOR_ID_NVIDIA, 0x044f, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* MCP65 */
+
{ } /* terminate list */
};
@@ -374,8 +428,6 @@ static int ahci_port_start(struct ata_port *ap)
pp->cmd_tbl = mem;
pp->cmd_tbl_dma = mem_dma;
- pp->cmd_tbl_sg = mem + AHCI_CMD_TBL_HDR;
-
ap->private_data = pp;
if (hpriv->cap & HOST_CAP_64)
@@ -508,46 +560,71 @@ static unsigned int ahci_dev_classify(struct ata_port *ap)
return ata_dev_classify(&tf);
}
-static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, u32 opts)
+static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
+ u32 opts)
{
- pp->cmd_slot[0].opts = cpu_to_le32(opts);
- pp->cmd_slot[0].status = 0;
- pp->cmd_slot[0].tbl_addr = cpu_to_le32(pp->cmd_tbl_dma & 0xffffffff);
- pp->cmd_slot[0].tbl_addr_hi = cpu_to_le32((pp->cmd_tbl_dma >> 16) >> 16);
+ dma_addr_t cmd_tbl_dma;
+
+ cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
+
+ pp->cmd_slot[tag].opts = cpu_to_le32(opts);
+ pp->cmd_slot[tag].status = 0;
+ pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
+ pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
}
-static int ahci_poll_register(void __iomem *reg, u32 mask, u32 val,
- unsigned long interval_msec,
- unsigned long timeout_msec)
+static int ahci_clo(struct ata_port *ap)
{
- unsigned long timeout;
+ void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+ struct ahci_host_priv *hpriv = ap->host_set->private_data;
u32 tmp;
- timeout = jiffies + (timeout_msec * HZ) / 1000;
- do {
- tmp = readl(reg);
- if ((tmp & mask) == val)
- return 0;
- msleep(interval_msec);
- } while (time_before(jiffies, timeout));
+ if (!(hpriv->cap & HOST_CAP_CLO))
+ return -EOPNOTSUPP;
- return -1;
+ tmp = readl(port_mmio + PORT_CMD);
+ tmp |= PORT_CMD_CLO;
+ writel(tmp, port_mmio + PORT_CMD);
+
+ tmp = ata_wait_register(port_mmio + PORT_CMD,
+ PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
+ if (tmp & PORT_CMD_CLO)
+ return -EIO;
+
+ return 0;
}
-static int ahci_softreset(struct ata_port *ap, int verbose, unsigned int *class)
+static int ahci_prereset(struct ata_port *ap)
+{
+ if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) &&
+ (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) {
+ /* ATA_BUSY hasn't cleared, so send a CLO */
+ ahci_clo(ap);
+ }
+
+ return ata_std_prereset(ap);
+}
+
+static int ahci_softreset(struct ata_port *ap, unsigned int *class)
{
- struct ahci_host_priv *hpriv = ap->host_set->private_data;
struct ahci_port_priv *pp = ap->private_data;
void __iomem *mmio = ap->host_set->mmio_base;
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
const u32 cmd_fis_len = 5; /* five dwords */
const char *reason = NULL;
struct ata_taskfile tf;
+ u32 tmp;
u8 *fis;
int rc;
DPRINTK("ENTER\n");
+ if (ata_port_offline(ap)) {
+ DPRINTK("PHY reports no device\n");
+ *class = ATA_DEV_NONE;
+ return 0;
+ }
+
/* prepare for SRST (AHCI-1.1 10.4.1) */
rc = ahci_stop_engine(ap);
if (rc) {
@@ -558,23 +635,13 @@ static int ahci_softreset(struct ata_port *ap, int verbose, unsigned int *class)
/* check BUSY/DRQ, perform Command List Override if necessary */
ahci_tf_read(ap, &tf);
if (tf.command & (ATA_BUSY | ATA_DRQ)) {
- u32 tmp;
+ rc = ahci_clo(ap);
- if (!(hpriv->cap & HOST_CAP_CLO)) {
- rc = -EIO;
- reason = "port busy but no CLO";
+ if (rc == -EOPNOTSUPP) {
+ reason = "port busy but CLO unavailable";
goto fail_restart;
- }
-
- tmp = readl(port_mmio + PORT_CMD);
- tmp |= PORT_CMD_CLO;
- writel(tmp, port_mmio + PORT_CMD);
- readl(port_mmio + PORT_CMD); /* flush */
-
- if (ahci_poll_register(port_mmio + PORT_CMD, PORT_CMD_CLO, 0x0,
- 1, 500)) {
- rc = -EIO;
- reason = "CLO failed";
+ } else if (rc) {
+ reason = "port busy but CLO failed";
goto fail_restart;
}
}
@@ -582,20 +649,21 @@ static int ahci_softreset(struct ata_port *ap, int verbose, unsigned int *class)
/* restart engine */
ahci_start_engine(ap);
- ata_tf_init(ap, &tf, 0);
+ ata_tf_init(ap->device, &tf);
fis = pp->cmd_tbl;
/* issue the first D2H Register FIS */
- ahci_fill_cmd_slot(pp, cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
+ ahci_fill_cmd_slot(pp, 0,
+ cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
tf.ctl |= ATA_SRST;
ata_tf_to_fis(&tf, fis, 0);
fis[1] &= ~(1 << 7); /* turn off Command FIS bit */
writel(1, port_mmio + PORT_CMD_ISSUE);
- readl(port_mmio + PORT_CMD_ISSUE); /* flush */
- if (ahci_poll_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x0, 1, 500)) {
+ tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500);
+ if (tmp & 0x1) {
rc = -EIO;
reason = "1st FIS failed";
goto fail;
@@ -605,7 +673,7 @@ static int ahci_softreset(struct ata_port *ap, int verbose, unsigned int *class)
msleep(1);
/* issue the second D2H Register FIS */
- ahci_fill_cmd_slot(pp, cmd_fis_len);
+ ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
tf.ctl &= ~ATA_SRST;
ata_tf_to_fis(&tf, fis, 0);
@@ -625,7 +693,7 @@ static int ahci_softreset(struct ata_port *ap, int verbose, unsigned int *class)
msleep(150);
*class = ATA_DEV_NONE;
- if (sata_dev_present(ap)) {
+ if (ata_port_online(ap)) {
if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
rc = -EIO;
reason = "device not ready";
@@ -640,25 +708,31 @@ static int ahci_softreset(struct ata_port *ap, int verbose, unsigned int *class)
fail_restart:
ahci_start_engine(ap);
fail:
- if (verbose)
- printk(KERN_ERR "ata%u: softreset failed (%s)\n",
- ap->id, reason);
- else
- DPRINTK("EXIT, rc=%d reason=\"%s\"\n", rc, reason);
+ ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
return rc;
}
-static int ahci_hardreset(struct ata_port *ap, int verbose, unsigned int *class)
+static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
{
+ struct ahci_port_priv *pp = ap->private_data;
+ u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+ struct ata_taskfile tf;
int rc;
DPRINTK("ENTER\n");
ahci_stop_engine(ap);
- rc = sata_std_hardreset(ap, verbose, class);
+
+ /* clear D2H reception area to properly wait for D2H FIS */
+ ata_tf_init(ap->device, &tf);
+ tf.command = 0xff;
+ ata_tf_to_fis(&tf, d2h_fis, 0);
+
+ rc = sata_std_hardreset(ap, class);
+
ahci_start_engine(ap);
- if (rc == 0)
+ if (rc == 0 && ata_port_online(ap))
*class = ahci_dev_classify(ap);
if (*class == ATA_DEV_UNKNOWN)
*class = ATA_DEV_NONE;
@@ -686,13 +760,6 @@ static void ahci_postreset(struct ata_port *ap, unsigned int *class)
}
}
-static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes)
-{
- return ata_drive_probe_reset(ap, ata_std_probeinit,
- ahci_softreset, ahci_hardreset,
- ahci_postreset, classes);
-}
-
static u8 ahci_check_status(struct ata_port *ap)
{
void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
@@ -708,9 +775,8 @@ static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
ata_tf_from_fis(d2h_fis, tf);
}
-static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc)
+static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
{
- struct ahci_port_priv *pp = qc->ap->private_data;
struct scatterlist *sg;
struct ahci_sg *ahci_sg;
unsigned int n_sg = 0;
@@ -720,7 +786,7 @@ static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc)
/*
* Next, the S/G list.
*/
- ahci_sg = pp->cmd_tbl_sg;
+ ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
ata_for_each_sg(sg, qc) {
dma_addr_t addr = sg_dma_address(sg);
u32 sg_len = sg_dma_len(sg);
@@ -741,6 +807,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
struct ahci_port_priv *pp = ap->private_data;
int is_atapi = is_atapi_taskfile(&qc->tf);
+ void *cmd_tbl;
u32 opts;
const u32 cmd_fis_len = 5; /* five dwords */
unsigned int n_elem;
@@ -749,16 +816,17 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
* Fill in command table information. First, the header,
* a SATA Register - Host to Device command FIS.
*/
- ata_tf_to_fis(&qc->tf, pp->cmd_tbl, 0);
+ cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
+
+ ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
if (is_atapi) {
- memset(pp->cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
- memcpy(pp->cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb,
- qc->dev->cdb_len);
+ memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
+ memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
}
n_elem = 0;
if (qc->flags & ATA_QCFLAG_DMAMAP)
- n_elem = ahci_fill_sg(qc);
+ n_elem = ahci_fill_sg(qc, cmd_tbl);
/*
* Fill in command slot information.
@@ -769,112 +837,122 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
if (is_atapi)
opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
- ahci_fill_cmd_slot(pp, opts);
+ ahci_fill_cmd_slot(pp, qc->tag, opts);
}
-static void ahci_restart_port(struct ata_port *ap, u32 irq_stat)
+static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
{
- void __iomem *mmio = ap->host_set->mmio_base;
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
- u32 tmp;
+ struct ahci_port_priv *pp = ap->private_data;
+ struct ata_eh_info *ehi = &ap->eh_info;
+ unsigned int err_mask = 0, action = 0;
+ struct ata_queued_cmd *qc;
+ u32 serror;
- if ((ap->device[0].class != ATA_DEV_ATAPI) ||
- ((irq_stat & PORT_IRQ_TF_ERR) == 0))
- printk(KERN_WARNING "ata%u: port reset, "
- "p_is %x is %x pis %x cmd %x tf %x ss %x se %x\n",
- ap->id,
- irq_stat,
- readl(mmio + HOST_IRQ_STAT),
- readl(port_mmio + PORT_IRQ_STAT),
- readl(port_mmio + PORT_CMD),
- readl(port_mmio + PORT_TFDATA),
- readl(port_mmio + PORT_SCR_STAT),
- readl(port_mmio + PORT_SCR_ERR));
-
- /* stop DMA */
- ahci_stop_engine(ap);
+ ata_ehi_clear_desc(ehi);
- /* clear SATA phy error, if any */
- tmp = readl(port_mmio + PORT_SCR_ERR);
- writel(tmp, port_mmio + PORT_SCR_ERR);
+ /* AHCI needs SError cleared; otherwise, it might lock up */
+ serror = ahci_scr_read(ap, SCR_ERROR);
+ ahci_scr_write(ap, SCR_ERROR, serror);
- /* if DRQ/BSY is set, device needs to be reset.
- * if so, issue COMRESET
- */
- tmp = readl(port_mmio + PORT_TFDATA);
- if (tmp & (ATA_BUSY | ATA_DRQ)) {
- writel(0x301, port_mmio + PORT_SCR_CTL);
- readl(port_mmio + PORT_SCR_CTL); /* flush */
- udelay(10);
- writel(0x300, port_mmio + PORT_SCR_CTL);
- readl(port_mmio + PORT_SCR_CTL); /* flush */
+ /* analyze @irq_stat */
+ ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
+
+ if (irq_stat & PORT_IRQ_TF_ERR)
+ err_mask |= AC_ERR_DEV;
+
+ if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
+ err_mask |= AC_ERR_HOST_BUS;
+ action |= ATA_EH_SOFTRESET;
}
- /* re-start DMA */
- ahci_start_engine(ap);
-}
+ if (irq_stat & PORT_IRQ_IF_ERR) {
+ err_mask |= AC_ERR_ATA_BUS;
+ action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(ehi, ", interface fatal error");
+ }
-static void ahci_eng_timeout(struct ata_port *ap)
-{
- struct ata_host_set *host_set = ap->host_set;
- void __iomem *mmio = host_set->mmio_base;
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
- struct ata_queued_cmd *qc;
- unsigned long flags;
+ if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
+ ata_ehi_hotplugged(ehi);
+ ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ?
+ "connection status changed" : "PHY RDY changed");
+ }
+
+ if (irq_stat & PORT_IRQ_UNK_FIS) {
+ u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
- printk(KERN_WARNING "ata%u: handling error/timeout\n", ap->id);
+ err_mask |= AC_ERR_HSM;
+ action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x",
+ unk[0], unk[1], unk[2], unk[3]);
+ }
- spin_lock_irqsave(&host_set->lock, flags);
+ /* okay, let's hand over to EH */
+ ehi->serror |= serror;
+ ehi->action |= action;
- ahci_restart_port(ap, readl(port_mmio + PORT_IRQ_STAT));
qc = ata_qc_from_tag(ap, ap->active_tag);
- qc->err_mask |= AC_ERR_TIMEOUT;
-
- spin_unlock_irqrestore(&host_set->lock, flags);
+ if (qc)
+ qc->err_mask |= err_mask;
+ else
+ ehi->err_mask |= err_mask;
- ata_eh_qc_complete(qc);
+ if (irq_stat & PORT_IRQ_FREEZE)
+ ata_port_freeze(ap);
+ else
+ ata_port_abort(ap);
}
-static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
+static void ahci_host_intr(struct ata_port *ap)
{
void __iomem *mmio = ap->host_set->mmio_base;
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
- u32 status, serr, ci;
-
- serr = readl(port_mmio + PORT_SCR_ERR);
- writel(serr, port_mmio + PORT_SCR_ERR);
+ struct ata_eh_info *ehi = &ap->eh_info;
+ u32 status, qc_active;
+ int rc;
status = readl(port_mmio + PORT_IRQ_STAT);
writel(status, port_mmio + PORT_IRQ_STAT);
- ci = readl(port_mmio + PORT_CMD_ISSUE);
- if (likely((ci & 0x1) == 0)) {
- if (qc) {
- WARN_ON(qc->err_mask);
- ata_qc_complete(qc);
- qc = NULL;
- }
+ if (unlikely(status & PORT_IRQ_ERROR)) {
+ ahci_error_intr(ap, status);
+ return;
}
- if (status & PORT_IRQ_FATAL) {
- unsigned int err_mask;
- if (status & PORT_IRQ_TF_ERR)
- err_mask = AC_ERR_DEV;
- else if (status & PORT_IRQ_IF_ERR)
- err_mask = AC_ERR_ATA_BUS;
- else
- err_mask = AC_ERR_HOST_BUS;
-
- /* command processing has stopped due to error; restart */
- ahci_restart_port(ap, status);
-
- if (qc) {
- qc->err_mask |= err_mask;
- ata_qc_complete(qc);
- }
+ if (ap->sactive)
+ qc_active = readl(port_mmio + PORT_SCR_ACT);
+ else
+ qc_active = readl(port_mmio + PORT_CMD_ISSUE);
+
+ rc = ata_qc_complete_multiple(ap, qc_active, NULL);
+ if (rc > 0)
+ return;
+ if (rc < 0) {
+ ehi->err_mask |= AC_ERR_HSM;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ata_port_freeze(ap);
+ return;
+ }
+
+ /* hmmm... a spurious interupt */
+
+ /* some devices send D2H reg with I bit set during NCQ command phase */
+ if (ap->sactive && status & PORT_IRQ_D2H_REG_FIS)
+ return;
+
+ /* ignore interim PIO setup fis interrupts */
+ if (ata_tag_valid(ap->active_tag)) {
+ struct ata_queued_cmd *qc =
+ ata_qc_from_tag(ap, ap->active_tag);
+
+ if (qc && qc->tf.protocol == ATA_PROT_PIO &&
+ (status & PORT_IRQ_PIOS_FIS))
+ return;
}
- return 1;
+ if (ata_ratelimit())
+ ata_port_printk(ap, KERN_INFO, "spurious interrupt "
+ "(irq_stat 0x%x active_tag %d sactive 0x%x)\n",
+ status, ap->active_tag, ap->sactive);
}
static void ahci_irq_clear(struct ata_port *ap)
@@ -882,7 +960,7 @@ static void ahci_irq_clear(struct ata_port *ap)
/* TODO */
}
-static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t ahci_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
{
struct ata_host_set *host_set = dev_instance;
struct ahci_host_priv *hpriv;
@@ -911,14 +989,7 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *
ap = host_set->ports[i];
if (ap) {
- struct ata_queued_cmd *qc;
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (!ahci_host_intr(ap, qc))
- if (ata_ratelimit())
- dev_printk(KERN_WARNING, host_set->dev,
- "unhandled interrupt on port %u\n",
- i);
-
+ ahci_host_intr(ap);
VPRINTK("port %u\n", i);
} else {
VPRINTK("port %u (no irq)\n", i);
@@ -935,7 +1006,7 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *
handled = 1;
}
- spin_unlock(&host_set->lock);
+ spin_unlock(&host_set->lock);
VPRINTK("EXIT\n");
@@ -947,12 +1018,65 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
- writel(1, port_mmio + PORT_CMD_ISSUE);
+ if (qc->tf.protocol == ATA_PROT_NCQ)
+ writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
+ writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
readl(port_mmio + PORT_CMD_ISSUE); /* flush */
return 0;
}
+static void ahci_freeze(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->host_set->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+
+ /* turn IRQ off */
+ writel(0, port_mmio + PORT_IRQ_MASK);
+}
+
+static void ahci_thaw(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->host_set->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+ u32 tmp;
+
+ /* clear IRQ */
+ tmp = readl(port_mmio + PORT_IRQ_STAT);
+ writel(tmp, port_mmio + PORT_IRQ_STAT);
+ writel(1 << ap->id, mmio + HOST_IRQ_STAT);
+
+ /* turn IRQ back on */
+ writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
+}
+
+static void ahci_error_handler(struct ata_port *ap)
+{
+ if (!(ap->flags & ATA_FLAG_FROZEN)) {
+ /* restart engine */
+ ahci_stop_engine(ap);
+ ahci_start_engine(ap);
+ }
+
+ /* perform recovery */
+ ata_do_eh(ap, ahci_prereset, ahci_softreset, ahci_hardreset,
+ ahci_postreset);
+}
+
+static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ if (qc->flags & ATA_QCFLAG_FAILED)
+ qc->err_mask |= AC_ERR_OTHER;
+
+ if (qc->err_mask) {
+ /* make DMA engine forget about the failed command */
+ ahci_stop_engine(ap);
+ ahci_start_engine(ap);
+ }
+}
+
static void ahci_setup_port(struct ata_ioports *port, unsigned long base,
unsigned int port_idx)
{
@@ -1097,9 +1221,6 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent)
writel(tmp, port_mmio + PORT_IRQ_STAT);
writel(1 << i, mmio + HOST_IRQ_STAT);
-
- /* set irq mask (enables interrupts) */
- writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
}
tmp = readl(mmio + HOST_CTL);
@@ -1197,6 +1318,8 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
VPRINTK("ENTER\n");
+ WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
+
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -1264,6 +1387,10 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
goto err_out_hpriv;
+ if (!(probe_ent->host_flags & AHCI_FLAG_NO_NCQ) &&
+ (hpriv->cap & HOST_CAP_NCQ))
+ probe_ent->host_flags |= ATA_FLAG_NCQ;
+
ahci_print_info(probe_ent);
/* FIXME: check ata_device_add return value */
@@ -1295,21 +1422,17 @@ static void ahci_remove_one (struct pci_dev *pdev)
struct device *dev = pci_dev_to_dev(pdev);
struct ata_host_set *host_set = dev_get_drvdata(dev);
struct ahci_host_priv *hpriv = host_set->private_data;
- struct ata_port *ap;
unsigned int i;
int have_msi;
- for (i = 0; i < host_set->n_ports; i++) {
- ap = host_set->ports[i];
-
- scsi_remove_host(ap->host);
- }
+ for (i = 0; i < host_set->n_ports; i++)
+ ata_port_detach(host_set->ports[i]);
have_msi = hpriv->flags & AHCI_FLAG_MSI;
free_irq(host_set->irq, host_set);
for (i = 0; i < host_set->n_ports; i++) {
- ap = host_set->ports[i];
+ struct ata_port *ap = host_set->ports[i];
ata_scsi_release(ap->host);
scsi_host_put(ap->host);
diff --git a/drivers/scsi/arm/queue.c b/drivers/scsi/arm/queue.c
index b10750b..8caa590 100644
--- a/drivers/scsi/arm/queue.c
+++ b/drivers/scsi/arm/queue.c
@@ -118,8 +118,7 @@ int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
list_del(l);
q = list_entry(l, QE_t, list);
- if (BAD_MAGIC(q, QUEUE_MAGIC_FREE))
- BUG();
+ BUG_ON(BAD_MAGIC(q, QUEUE_MAGIC_FREE));
SET_MAGIC(q, QUEUE_MAGIC_USED);
q->SCpnt = SCpnt;
@@ -144,8 +143,7 @@ static Scsi_Cmnd *__queue_remove(Queue_t *queue, struct list_head *ent)
*/
list_del(ent);
q = list_entry(ent, QE_t, list);
- if (BAD_MAGIC(q, QUEUE_MAGIC_USED))
- BUG();
+ BUG_ON(BAD_MAGIC(q, QUEUE_MAGIC_USED));
SET_MAGIC(q, QUEUE_MAGIC_FREE);
list_add(ent, &queue->free);
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index 6dc8814..521b718 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -93,7 +93,7 @@
#include <linux/libata.h>
#define DRV_NAME "ata_piix"
-#define DRV_VERSION "1.05"
+#define DRV_VERSION "1.10"
enum {
PIIX_IOCFG = 0x54, /* IDE I/O configuration register */
@@ -146,11 +146,10 @@ struct piix_map_db {
static int piix_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent);
-
-static int piix_pata_probe_reset(struct ata_port *ap, unsigned int *classes);
-static int piix_sata_probe_reset(struct ata_port *ap, unsigned int *classes);
static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev);
static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev);
+static void piix_pata_error_handler(struct ata_port *ap);
+static void piix_sata_error_handler(struct ata_port *ap);
static unsigned int in_module_init = 1;
@@ -159,6 +158,7 @@ static const struct pci_device_id piix_pci_tbl[] = {
{ 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix4_pata },
{ 0x8086, 0x24db, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
{ 0x8086, 0x25a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
+ { 0x8086, 0x27df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
#endif
/* NOTE: The following PCI ids must be kept in sync with the
@@ -218,6 +218,7 @@ static struct scsi_host_template piix_sht = {
.proc_name = DRV_NAME,
.dma_boundary = ATA_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
@@ -227,6 +228,7 @@ static const struct ata_port_operations piix_pata_ops = {
.port_disable = ata_port_disable,
.set_piomode = piix_set_piomode,
.set_dmamode = piix_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -234,16 +236,18 @@ static const struct ata_port_operations piix_pata_ops = {
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
- .probe_reset = piix_pata_probe_reset,
-
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
- .eng_timeout = ata_eng_timeout,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = piix_pata_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
@@ -262,16 +266,18 @@ static const struct ata_port_operations piix_sata_ops = {
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
- .probe_reset = piix_sata_probe_reset,
-
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
- .eng_timeout = ata_eng_timeout,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = piix_sata_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
@@ -455,59 +461,51 @@ cbl40:
}
/**
- * piix_pata_probeinit - probeinit for PATA host controller
+ * piix_pata_prereset - prereset for PATA host controller
* @ap: Target port
*
- * Probeinit including cable detection.
- *
- * LOCKING:
- * None (inherited from caller).
- */
-static void piix_pata_probeinit(struct ata_port *ap)
-{
- piix_pata_cbl_detect(ap);
- ata_std_probeinit(ap);
-}
-
-/**
- * piix_pata_probe_reset - Perform reset on PATA port and classify
- * @ap: Port to reset
- * @classes: Resulting classes of attached devices
- *
- * Reset PATA phy and classify attached devices.
+ * Prereset including cable detection.
*
* LOCKING:
* None (inherited from caller).
*/
-static int piix_pata_probe_reset(struct ata_port *ap, unsigned int *classes)
+static int piix_pata_prereset(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->hard_port_no])) {
- printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
+ ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n");
+ ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
return 0;
}
- return ata_drive_probe_reset(ap, piix_pata_probeinit,
- ata_std_softreset, NULL,
- ata_std_postreset, classes);
+ piix_pata_cbl_detect(ap);
+
+ return ata_std_prereset(ap);
+}
+
+static void piix_pata_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, piix_pata_prereset, ata_std_softreset, NULL,
+ ata_std_postreset);
}
/**
- * piix_sata_probe - Probe PCI device for present SATA devices
- * @ap: Port associated with the PCI device we wish to probe
+ * piix_sata_prereset - prereset for SATA host controller
+ * @ap: Target port
*
* Reads and configures SATA PCI device's PCI config register
* Port Configuration and Status (PCS) to determine port and
- * device availability.
+ * device availability. Return -ENODEV to skip reset if no
+ * device is present.
*
* LOCKING:
* None (inherited from caller).
*
* RETURNS:
- * Mask of avaliable devices on the port.
+ * 0 if device is present, -ENODEV otherwise.
*/
-static unsigned int piix_sata_probe (struct ata_port *ap)
+static int piix_sata_prereset(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
const unsigned int *map = ap->host_set->private_data;
@@ -549,29 +547,19 @@ static unsigned int piix_sata_probe (struct ata_port *ap)
DPRINTK("ata%u: LEAVE, pcs=0x%x present_mask=0x%x\n",
ap->id, pcs, present_mask);
- return present_mask;
-}
-
-/**
- * piix_sata_probe_reset - Perform reset on SATA port and classify
- * @ap: Port to reset
- * @classes: Resulting classes of attached devices
- *
- * Reset SATA phy and classify attached devices.
- *
- * LOCKING:
- * None (inherited from caller).
- */
-static int piix_sata_probe_reset(struct ata_port *ap, unsigned int *classes)
-{
- if (!piix_sata_probe(ap)) {
- printk(KERN_INFO "ata%u: SATA port has no device.\n", ap->id);
+ if (!present_mask) {
+ ata_port_printk(ap, KERN_INFO, "SATA port has no device.\n");
+ ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
return 0;
}
- return ata_drive_probe_reset(ap, ata_std_probeinit,
- ata_std_softreset, NULL,
- ata_std_postreset, classes);
+ return ata_std_prereset(ap);
+}
+
+static void piix_sata_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, piix_sata_prereset, ata_std_softreset, NULL,
+ ata_std_postreset);
}
/**
@@ -760,15 +748,15 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev)
pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
pci_read_config_word(pdev, 0x41, &cfg);
/* Only on the original revision: IDE DMA can hang */
- if(rev == 0x00)
+ if (rev == 0x00)
no_piix_dma = 1;
/* On all revisions below 5 PXB bus lock must be disabled for IDE */
- else if(cfg & (1<<14) && rev < 5)
+ else if (cfg & (1<<14) && rev < 5)
no_piix_dma = 2;
}
- if(no_piix_dma)
+ if (no_piix_dma)
dev_printk(KERN_WARNING, &ata_dev->dev, "450NX errata present, disabling IDE DMA.\n");
- if(no_piix_dma == 2)
+ if (no_piix_dma == 2)
dev_printk(KERN_WARNING, &ata_dev->dev, "A BIOS update may resolve this.\n");
return no_piix_dma;
}
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
index 0a3e45d..ddb5124 100644
--- a/drivers/scsi/esp.c
+++ b/drivers/scsi/esp.c
@@ -1,7 +1,6 @@
-/* $Id: esp.c,v 1.101 2002/01/15 06:48:55 davem Exp $
- * esp.c: EnhancedScsiProcessor Sun SCSI driver code.
+/* esp.c: ESP Sun SCSI driver.
*
- * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 1998, 2006 David S. Miller (davem@davemloft.net)
*/
/* TODO:
@@ -185,11 +184,6 @@ enum {
/*5*/ do_intr_end
};
-/* The master ring of all esp hosts we are managing in this driver. */
-static struct esp *espchain;
-static DEFINE_SPINLOCK(espchain_lock);
-static int esps_running = 0;
-
/* Forward declarations. */
static irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
@@ -694,36 +688,6 @@ static void __init esp_bootup_reset(struct esp *esp)
sbus_readb(esp->eregs + ESP_INTRPT);
}
-static void esp_chain_add(struct esp *esp)
-{
- spin_lock_irq(&espchain_lock);
- if (espchain) {
- struct esp *elink = espchain;
- while (elink->next)
- elink = elink->next;
- elink->next = esp;
- } else {
- espchain = esp;
- }
- esp->next = NULL;
- spin_unlock_irq(&espchain_lock);
-}
-
-static void esp_chain_del(struct esp *esp)
-{
- spin_lock_irq(&espchain_lock);
- if (espchain == esp) {
- espchain = esp->next;
- } else {
- struct esp *elink = espchain;
- while (elink->next != esp)
- elink = elink->next;
- elink->next = esp->next;
- }
- esp->next = NULL;
- spin_unlock_irq(&espchain_lock);
-}
-
static int __init esp_find_dvma(struct esp *esp, struct sbus_dev *dma_sdev)
{
struct sbus_dev *sdev = esp->sdev;
@@ -830,19 +794,20 @@ static int __init esp_register_irq(struct esp *esp)
static void __init esp_get_scsi_id(struct esp *esp)
{
struct sbus_dev *sdev = esp->sdev;
+ struct device_node *dp = sdev->ofdev.node;
- esp->scsi_id = prom_getintdefault(esp->prom_node,
- "initiator-id",
- -1);
+ esp->scsi_id = of_getintprop_default(dp,
+ "initiator-id",
+ -1);
if (esp->scsi_id == -1)
- esp->scsi_id = prom_getintdefault(esp->prom_node,
- "scsi-initiator-id",
- -1);
+ esp->scsi_id = of_getintprop_default(dp,
+ "scsi-initiator-id",
+ -1);
if (esp->scsi_id == -1)
esp->scsi_id = (sdev->bus == NULL) ? 7 :
- prom_getintdefault(sdev->bus->prom_node,
- "scsi-initiator-id",
- 7);
+ of_getintprop_default(sdev->bus->ofdev.node,
+ "scsi-initiator-id",
+ 7);
esp->ehost->this_id = esp->scsi_id;
esp->scsi_id_mask = (1 << esp->scsi_id);
@@ -1067,28 +1032,30 @@ static void __init esp_init_swstate(struct esp *esp)
esp->prev_hme_dmacsr = 0xffffffff;
}
-static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_dev *esp_dev,
- struct sbus_dev *espdma, struct sbus_bus *sbus,
- int id, int hme)
+static int __init detect_one_esp(struct scsi_host_template *tpnt,
+ struct device *dev,
+ struct sbus_dev *esp_dev,
+ struct sbus_dev *espdma,
+ struct sbus_bus *sbus,
+ int hme)
{
- struct Scsi_Host *esp_host = scsi_register(tpnt, sizeof(struct esp));
+ static int instance;
+ struct Scsi_Host *esp_host = scsi_host_alloc(tpnt, sizeof(struct esp));
struct esp *esp;
- if (!esp_host) {
- printk("ESP: Cannot register SCSI host\n");
- return -1;
- }
+ if (!esp_host)
+ return -ENOMEM;
+
if (hme)
esp_host->max_id = 16;
esp = (struct esp *) esp_host->hostdata;
esp->ehost = esp_host;
esp->sdev = esp_dev;
- esp->esp_id = id;
+ esp->esp_id = instance;
esp->prom_node = esp_dev->prom_node;
prom_getstring(esp->prom_node, "name", esp->prom_name,
sizeof(esp->prom_name));
- esp_chain_add(esp);
if (esp_find_dvma(esp, espdma) < 0)
goto fail_unlink;
if (esp_map_regs(esp, hme) < 0) {
@@ -1115,8 +1082,19 @@ static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_de
esp_bootup_reset(esp);
+ if (scsi_add_host(esp_host, dev))
+ goto fail_free_irq;
+
+ dev_set_drvdata(&esp_dev->ofdev.dev, esp);
+
+ scsi_scan_host(esp_host);
+ instance++;
+
return 0;
+fail_free_irq:
+ free_irq(esp->ehost->irq, esp);
+
fail_unmap_cmdarea:
sbus_free_consistent(esp->sdev, 16,
(void *) esp->esp_command,
@@ -1129,119 +1107,98 @@ fail_dvma_release:
esp->dma->allocated = 0;
fail_unlink:
- esp_chain_del(esp);
- scsi_unregister(esp_host);
+ scsi_host_put(esp_host);
return -1;
}
/* Detecting ESP chips on the machine. This is the simple and easy
* version.
*/
+static int __devexit esp_remove_common(struct esp *esp)
+{
+ unsigned int irq = esp->ehost->irq;
+
+ scsi_remove_host(esp->ehost);
+
+ ESP_INTSOFF(esp->dregs);
+#if 0
+ esp_reset_dma(esp);
+ esp_reset_esp(esp);
+#endif
+
+ free_irq(irq, esp);
+ sbus_free_consistent(esp->sdev, 16,
+ (void *) esp->esp_command, esp->esp_command_dvma);
+ sbus_iounmap(esp->eregs, ESP_REG_SIZE);
+ esp->dma->allocated = 0;
+
+ scsi_host_put(esp->ehost);
+
+ return 0;
+}
+
#ifdef CONFIG_SUN4
#include <asm/sun4paddr.h>
-static int __init esp_detect(struct scsi_host_template *tpnt)
-{
- static struct sbus_dev esp_dev;
- int esps_in_use = 0;
-
- espchain = NULL;
+static struct sbus_dev sun4_esp_dev;
+static int __init esp_sun4_probe(struct scsi_host_template *tpnt)
+{
if (sun4_esp_physaddr) {
- memset (&esp_dev, 0, sizeof(esp_dev));
- esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr;
- esp_dev.irqs[0] = 4;
- esp_dev.resource[0].start = sun4_esp_physaddr;
- esp_dev.resource[0].end = sun4_esp_physaddr + ESP_REG_SIZE - 1;
- esp_dev.resource[0].flags = IORESOURCE_IO;
-
- if (!detect_one_esp(tpnt, &esp_dev, NULL, NULL, 0, 0))
- esps_in_use++;
- printk("ESP: Total of 1 ESP hosts found, %d actually in use.\n", esps_in_use);
- esps_running = esps_in_use;
+ memset(&sun4_esp_dev, 0, sizeof(esp_dev));
+ sun4_esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr;
+ sun4_esp_dev.irqs[0] = 4;
+ sun4_esp_dev.resource[0].start = sun4_esp_physaddr;
+ sun4_esp_dev.resource[0].end =
+ sun4_esp_physaddr + ESP_REG_SIZE - 1;
+ sun4_esp_dev.resource[0].flags = IORESOURCE_IO;
+
+ return detect_one_esp(tpnt, NULL,
+ &sun4_esp_dev, NULL, NULL, 0);
}
- return esps_in_use;
+ return 0;
}
-#else /* !CONFIG_SUN4 */
-
-static int __init esp_detect(struct scsi_host_template *tpnt)
+static int __devexit esp_sun4_remove(void)
{
- struct sbus_bus *sbus;
- struct sbus_dev *esp_dev, *sbdev_iter;
- int nesps = 0, esps_in_use = 0;
+ struct esp *esp = dev_get_drvdata(&dev->dev);
- espchain = 0;
- if (!sbus_root) {
-#ifdef CONFIG_PCI
- return 0;
-#else
- panic("No SBUS in esp_detect()");
-#endif
- }
- for_each_sbus(sbus) {
- for_each_sbusdev(sbdev_iter, sbus) {
- struct sbus_dev *espdma = NULL;
- int hme = 0;
-
- /* Is it an esp sbus device? */
- esp_dev = sbdev_iter;
- if (strcmp(esp_dev->prom_name, "esp") &&
- strcmp(esp_dev->prom_name, "SUNW,esp")) {
- if (!strcmp(esp_dev->prom_name, "SUNW,fas")) {
- hme = 1;
- espdma = esp_dev;
- } else {
- if (!esp_dev->child ||
- (strcmp(esp_dev->prom_name, "espdma") &&
- strcmp(esp_dev->prom_name, "dma")))
- continue; /* nope... */
- espdma = esp_dev;
- esp_dev = esp_dev->child;
- if (strcmp(esp_dev->prom_name, "esp") &&
- strcmp(esp_dev->prom_name, "SUNW,esp"))
- continue; /* how can this happen? */
- }
- }
-
- if (detect_one_esp(tpnt, esp_dev, espdma, sbus, nesps++, hme) < 0)
- continue;
-
- esps_in_use++;
- } /* for each sbusdev */
- } /* for each sbus */
- printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps,
- esps_in_use);
- esps_running = esps_in_use;
- return esps_in_use;
+ return esp_remove_common(esp);
}
-#endif /* !CONFIG_SUN4 */
+#else /* !CONFIG_SUN4 */
-/*
- */
-static int esp_release(struct Scsi_Host *host)
+static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct esp *esp = (struct esp *) host->hostdata;
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+ struct device_node *dp = dev->node;
+ struct sbus_dev *dma_sdev = NULL;
+ int hme = 0;
+
+ if (dp->parent &&
+ (!strcmp(dp->parent->name, "espdma") ||
+ !strcmp(dp->parent->name, "dma")))
+ dma_sdev = sdev->parent;
+ else if (!strcmp(dp->name, "SUNW,fas")) {
+ dma_sdev = sdev;
+ hme = 1;
+ }
- ESP_INTSOFF(esp->dregs);
-#if 0
- esp_reset_dma(esp);
- esp_reset_esp(esp);
-#endif
+ return detect_one_esp(match->data, &dev->dev,
+ sdev, dma_sdev, sdev->bus, hme);
+}
- free_irq(esp->ehost->irq, esp);
- sbus_free_consistent(esp->sdev, 16,
- (void *) esp->esp_command, esp->esp_command_dvma);
- sbus_iounmap(esp->eregs, ESP_REG_SIZE);
- esp->dma->allocated = 0;
- esp_chain_del(esp);
+static int __devexit esp_sbus_remove(struct of_device *dev)
+{
+ struct esp *esp = dev_get_drvdata(&dev->dev);
- return 0;
+ return esp_remove_common(esp);
}
+#endif /* !CONFIG_SUN4 */
+
/* The info function will return whatever useful
* information the developer sees fit. If not provided, then
* the name field will be used instead.
@@ -1415,18 +1372,11 @@ static int esp_host_info(struct esp *esp, char *ptr, off_t offset, int len)
static int esp_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
int length, int inout)
{
- struct esp *esp;
+ struct esp *esp = (struct esp *) host->hostdata;
if (inout)
return -EINVAL; /* not yet */
- for_each_esp(esp) {
- if (esp->ehost == host)
- break;
- }
- if (!esp)
- return -EINVAL;
-
if (start)
*start = buffer;
@@ -4377,15 +4327,12 @@ static void esp_slave_destroy(struct scsi_device *SDptr)
SDptr->hostdata = NULL;
}
-static struct scsi_host_template driver_template = {
- .proc_name = "esp",
- .proc_info = esp_proc_info,
- .name = "Sun ESP 100/100a/200",
- .detect = esp_detect,
+static struct scsi_host_template esp_template = {
+ .module = THIS_MODULE,
+ .name = "esp",
+ .info = esp_info,
.slave_alloc = esp_slave_alloc,
.slave_destroy = esp_slave_destroy,
- .release = esp_release,
- .info = esp_info,
.queuecommand = esp_queue,
.eh_abort_handler = esp_abort,
.eh_bus_reset_handler = esp_reset,
@@ -4394,12 +4341,58 @@ static struct scsi_host_template driver_template = {
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
.use_clustering = ENABLE_CLUSTERING,
+ .proc_name = "esp",
+ .proc_info = esp_proc_info,
+};
+
+#ifndef CONFIG_SUN4
+static struct of_device_id esp_match[] = {
+ {
+ .name = "SUNW,esp",
+ .data = &esp_template,
+ },
+ {
+ .name = "SUNW,fas",
+ .data = &esp_template,
+ },
+ {
+ .name = "esp",
+ .data = &esp_template,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, esp_match);
+
+static struct of_platform_driver esp_sbus_driver = {
+ .name = "esp",
+ .match_table = esp_match,
+ .probe = esp_sbus_probe,
+ .remove = __devexit_p(esp_sbus_remove),
};
+#endif
+
+static int __init esp_init(void)
+{
+#ifdef CONFIG_SUN4
+ return esp_sun4_probe(&esp_template);
+#else
+ return of_register_driver(&esp_sbus_driver, &sbus_bus_type);
+#endif
+}
-#include "scsi_module.c"
+static void __exit esp_exit(void)
+{
+#ifdef CONFIG_SUN4
+ esp_sun4_remove();
+#else
+ of_unregister_driver(&esp_sbus_driver);
+#endif
+}
-MODULE_DESCRIPTION("EnhancedScsiProcessor Sun SCSI driver");
-MODULE_AUTHOR("David S. Miller (davem@redhat.com)");
+MODULE_DESCRIPTION("ESP Sun SCSI driver");
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
+module_init(esp_init);
+module_exit(esp_exit);
diff --git a/drivers/scsi/esp.h b/drivers/scsi/esp.h
index 73f7d69..a98cda9 100644
--- a/drivers/scsi/esp.h
+++ b/drivers/scsi/esp.h
@@ -403,8 +403,4 @@ struct esp {
#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000))
#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000))
-/* For our interrupt engine. */
-#define for_each_esp(esp) \
- for((esp) = espchain; (esp); (esp) = (esp)->next)
-
#endif /* !(_SPARC_ESP_H) */
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 0c6dc31..115f554 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -2241,8 +2241,7 @@ static int __ibmmca_host_reset(Scsi_Cmnd * cmd)
int host_index;
unsigned long imm_command;
- if (cmd == NULL)
- BUG();
+ BUG_ON(cmd == NULL);
ticks = IM_RESET_DELAY * HZ;
shpnt = cmd->device->host;
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 39b760a..988e6f7 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -600,8 +600,7 @@ static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive)
"issuing a packet command\n");
return ide_do_reset (drive);
}
- if (HWGROUP(drive)->handler != NULL)
- BUG();
+ BUG_ON(HWGROUP(drive)->handler != NULL);
/* Set the interrupt routine */
ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);
/* Send the actual packet */
@@ -691,8 +690,7 @@ static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
set_bit(PC_DMA_OK, &pc->flags);
if (test_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
- if (HWGROUP(drive)->handler != NULL)
- BUG();
+ BUG_ON(HWGROUP(drive)->handler != NULL);
ide_set_handler(drive, &idescsi_transfer_pc,
get_timeout(pc), idescsi_expiry);
/* Issue the packet command */
diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c
index 835dff0..004e1a0 100644
--- a/drivers/scsi/libata-bmdma.c
+++ b/drivers/scsi/libata-bmdma.c
@@ -652,6 +652,151 @@ void ata_bmdma_stop(struct ata_queued_cmd *qc)
ata_altstatus(ap); /* dummy read */
}
+/**
+ * ata_bmdma_freeze - Freeze BMDMA controller port
+ * @ap: port to freeze
+ *
+ * Freeze BMDMA controller port.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+void ata_bmdma_freeze(struct ata_port *ap)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ ap->ctl |= ATA_NIEN;
+ ap->last_ctl = ap->ctl;
+
+ if (ap->flags & ATA_FLAG_MMIO)
+ writeb(ap->ctl, (void __iomem *)ioaddr->ctl_addr);
+ else
+ outb(ap->ctl, ioaddr->ctl_addr);
+}
+
+/**
+ * ata_bmdma_thaw - Thaw BMDMA controller port
+ * @ap: port to thaw
+ *
+ * Thaw BMDMA controller port.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+void ata_bmdma_thaw(struct ata_port *ap)
+{
+ /* clear & re-enable interrupts */
+ ata_chk_status(ap);
+ ap->ops->irq_clear(ap);
+ if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */
+ ata_irq_on(ap);
+}
+
+/**
+ * ata_bmdma_drive_eh - Perform EH with given methods for BMDMA controller
+ * @ap: port to handle error for
+ * @prereset: prereset method (can be NULL)
+ * @softreset: softreset method (can be NULL)
+ * @hardreset: hardreset method (can be NULL)
+ * @postreset: postreset method (can be NULL)
+ *
+ * Handle error for ATA BMDMA controller. It can handle both
+ * PATA and SATA controllers. Many controllers should be able to
+ * use this EH as-is or with some added handling before and
+ * after.
+ *
+ * This function is intended to be used for constructing
+ * ->error_handler callback by low level drivers.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
+ ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+ ata_postreset_fn_t postreset)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_queued_cmd *qc;
+ unsigned long flags;
+ int thaw = 0;
+
+ qc = __ata_qc_from_tag(ap, ap->active_tag);
+ if (qc && !(qc->flags & ATA_QCFLAG_FAILED))
+ qc = NULL;
+
+ /* reset PIO HSM and stop DMA engine */
+ spin_lock_irqsave(ap->lock, flags);
+
+ ap->hsm_task_state = HSM_ST_IDLE;
+
+ if (qc && (qc->tf.protocol == ATA_PROT_DMA ||
+ qc->tf.protocol == ATA_PROT_ATAPI_DMA)) {
+ u8 host_stat;
+
+ host_stat = ata_bmdma_status(ap);
+
+ ata_ehi_push_desc(&ehc->i, "BMDMA stat 0x%x", host_stat);
+
+ /* BMDMA controllers indicate host bus error by
+ * setting DMA_ERR bit and timing out. As it wasn't
+ * really a timeout event, adjust error mask and
+ * cancel frozen state.
+ */
+ if (qc->err_mask == AC_ERR_TIMEOUT && host_stat & ATA_DMA_ERR) {
+ qc->err_mask = AC_ERR_HOST_BUS;
+ thaw = 1;
+ }
+
+ ap->ops->bmdma_stop(qc);
+ }
+
+ ata_altstatus(ap);
+ ata_chk_status(ap);
+ ap->ops->irq_clear(ap);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ if (thaw)
+ ata_eh_thaw_port(ap);
+
+ /* PIO and DMA engines have been stopped, perform recovery */
+ ata_do_eh(ap, prereset, softreset, hardreset, postreset);
+}
+
+/**
+ * ata_bmdma_error_handler - Stock error handler for BMDMA controller
+ * @ap: port to handle error for
+ *
+ * Stock error handler for BMDMA controller.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void ata_bmdma_error_handler(struct ata_port *ap)
+{
+ ata_reset_fn_t hardreset;
+
+ hardreset = NULL;
+ if (sata_scr_valid(ap))
+ hardreset = sata_std_hardreset;
+
+ ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, hardreset,
+ ata_std_postreset);
+}
+
+/**
+ * ata_bmdma_post_internal_cmd - Stock post_internal_cmd for
+ * BMDMA controller
+ * @qc: internal command to clean up
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc)
+{
+ ata_bmdma_stop(qc);
+}
+
#ifdef CONFIG_PCI
static struct ata_probe_ent *
ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
@@ -930,10 +1075,21 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
/* FIXME: check ata_device_add return */
if (legacy_mode) {
- if (legacy_mode & (1 << 0))
+ struct device *dev = &pdev->dev;
+ struct ata_host_set *host_set = NULL;
+
+ if (legacy_mode & (1 << 0)) {
ata_device_add(probe_ent);
- if (legacy_mode & (1 << 1))
+ host_set = dev_get_drvdata(dev);
+ }
+
+ if (legacy_mode & (1 << 1)) {
ata_device_add(probe_ent2);
+ if (host_set) {
+ host_set->next = dev_get_drvdata(dev);
+ dev_set_drvdata(dev, host_set);
+ }
+ }
} else
ata_device_add(probe_ent);
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index de9ba78..6c66877 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -61,22 +61,29 @@
#include "libata.h"
-static unsigned int ata_dev_init_params(struct ata_port *ap,
- struct ata_device *dev,
- u16 heads,
- u16 sectors);
-static void ata_set_mode(struct ata_port *ap);
-static unsigned int ata_dev_set_xfermode(struct ata_port *ap,
- struct ata_device *dev);
-static void ata_dev_xfermask(struct ata_port *ap, struct ata_device *dev);
+/* debounce timing parameters in msecs { interval, duration, timeout } */
+const unsigned long sata_deb_timing_boot[] = { 5, 100, 2000 };
+const unsigned long sata_deb_timing_eh[] = { 25, 500, 2000 };
+const unsigned long sata_deb_timing_before_fsrst[] = { 100, 2000, 5000 };
+
+static unsigned int ata_dev_init_params(struct ata_device *dev,
+ u16 heads, u16 sectors);
+static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
+static void ata_dev_xfermask(struct ata_device *dev);
static unsigned int ata_unique_id = 1;
static struct workqueue_struct *ata_wq;
+struct workqueue_struct *ata_aux_wq;
+
int atapi_enabled = 1;
module_param(atapi_enabled, int, 0444);
MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on)");
+int atapi_dmadir = 0;
+module_param(atapi_dmadir, int, 0444);
+MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)");
+
int libata_fua = 0;
module_param_named(fua, libata_fua, int, 0444);
MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)");
@@ -397,11 +404,22 @@ static const char *ata_mode_string(unsigned int xfer_mask)
return "<n/a>";
}
-static void ata_dev_disable(struct ata_port *ap, struct ata_device *dev)
+static const char *sata_spd_string(unsigned int spd)
{
- if (ata_dev_present(dev)) {
- printk(KERN_WARNING "ata%u: dev %u disabled\n",
- ap->id, dev->devno);
+ static const char * const spd_str[] = {
+ "1.5 Gbps",
+ "3.0 Gbps",
+ };
+
+ if (spd == 0 || (spd - 1) >= ARRAY_SIZE(spd_str))
+ return "<unknown>";
+ return spd_str[spd - 1];
+}
+
+void ata_dev_disable(struct ata_device *dev)
+{
+ if (ata_dev_enabled(dev) && ata_msg_drv(dev->ap)) {
+ ata_dev_printk(dev, KERN_WARNING, "disabled\n");
dev->class++;
}
}
@@ -759,8 +777,11 @@ void ata_std_dev_select (struct ata_port *ap, unsigned int device)
void ata_dev_select(struct ata_port *ap, unsigned int device,
unsigned int wait, unsigned int can_sleep)
{
- VPRINTK("ENTER, ata%u: device %u, wait %u\n",
- ap->id, device, wait);
+ if (ata_msg_probe(ap)) {
+ ata_port_printk(ap, KERN_INFO, "ata_dev_select: ENTER, ata%u: "
+ "device %u, wait %u\n",
+ ap->id, device, wait);
+ }
if (wait)
ata_wait_idle(ap);
@@ -915,9 +936,9 @@ void ata_port_flush_task(struct ata_port *ap)
DPRINTK("ENTER\n");
- spin_lock_irqsave(&ap->host_set->lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
ap->flags |= ATA_FLAG_FLUSH_PORT_TASK;
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
DPRINTK("flush #1\n");
flush_workqueue(ata_wq);
@@ -928,30 +949,31 @@ void ata_port_flush_task(struct ata_port *ap)
* Cancel and flush.
*/
if (!cancel_delayed_work(&ap->port_task)) {
- DPRINTK("flush #2\n");
+ if (ata_msg_ctl(ap))
+ ata_port_printk(ap, KERN_DEBUG, "%s: flush #2\n", __FUNCTION__);
flush_workqueue(ata_wq);
}
- spin_lock_irqsave(&ap->host_set->lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
ap->flags &= ~ATA_FLAG_FLUSH_PORT_TASK;
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
- DPRINTK("EXIT\n");
+ if (ata_msg_ctl(ap))
+ ata_port_printk(ap, KERN_DEBUG, "%s: EXIT\n", __FUNCTION__);
}
void ata_qc_complete_internal(struct ata_queued_cmd *qc)
{
struct completion *waiting = qc->private_data;
- qc->ap->ops->tf_read(qc->ap, &qc->tf);
complete(waiting);
}
/**
* ata_exec_internal - execute libata internal command
- * @ap: Port to which the command is sent
* @dev: Device to which the command is sent
* @tf: Taskfile registers for the command and the result
+ * @cdb: CDB for packet command
* @dma_dir: Data tranfer direction of the command
* @buf: Data buffer of the command
* @buflen: Length of data buffer
@@ -964,25 +986,66 @@ void ata_qc_complete_internal(struct ata_queued_cmd *qc)
*
* LOCKING:
* None. Should be called with kernel context, might sleep.
+ *
+ * RETURNS:
+ * Zero on success, AC_ERR_* mask on failure
*/
-
-static unsigned
-ata_exec_internal(struct ata_port *ap, struct ata_device *dev,
- struct ata_taskfile *tf,
- int dma_dir, void *buf, unsigned int buflen)
+unsigned ata_exec_internal(struct ata_device *dev,
+ struct ata_taskfile *tf, const u8 *cdb,
+ int dma_dir, void *buf, unsigned int buflen)
{
+ struct ata_port *ap = dev->ap;
u8 command = tf->command;
struct ata_queued_cmd *qc;
+ unsigned int tag, preempted_tag;
+ u32 preempted_sactive, preempted_qc_active;
DECLARE_COMPLETION(wait);
unsigned long flags;
unsigned int err_mask;
+ int rc;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ /* no internal command while frozen */
+ if (ap->flags & ATA_FLAG_FROZEN) {
+ spin_unlock_irqrestore(ap->lock, flags);
+ return AC_ERR_SYSTEM;
+ }
- spin_lock_irqsave(&ap->host_set->lock, flags);
+ /* initialize internal qc */
- qc = ata_qc_new_init(ap, dev);
- BUG_ON(qc == NULL);
+ /* XXX: Tag 0 is used for drivers with legacy EH as some
+ * drivers choke if any other tag is given. This breaks
+ * ata_tag_internal() test for those drivers. Don't use new
+ * EH stuff without converting to it.
+ */
+ if (ap->ops->error_handler)
+ tag = ATA_TAG_INTERNAL;
+ else
+ tag = 0;
+
+ if (test_and_set_bit(tag, &ap->qc_allocated))
+ BUG();
+ qc = __ata_qc_from_tag(ap, tag);
+ qc->tag = tag;
+ qc->scsicmd = NULL;
+ qc->ap = ap;
+ qc->dev = dev;
+ ata_qc_reinit(qc);
+
+ preempted_tag = ap->active_tag;
+ preempted_sactive = ap->sactive;
+ preempted_qc_active = ap->qc_active;
+ ap->active_tag = ATA_TAG_POISON;
+ ap->sactive = 0;
+ ap->qc_active = 0;
+
+ /* prepare & issue qc */
qc->tf = *tf;
+ if (cdb)
+ memcpy(qc->cdb, cdb, ATAPI_CDB_LEN);
+ qc->flags |= ATA_QCFLAG_RESULT_TF;
qc->dma_dir = dma_dir;
if (dma_dir != DMA_NONE) {
ata_sg_init_one(qc, buf, buflen);
@@ -994,33 +1057,58 @@ ata_exec_internal(struct ata_port *ap, struct ata_device *dev,
ata_qc_issue(qc);
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ rc = wait_for_completion_timeout(&wait, ATA_TMOUT_INTERNAL);
- if (!wait_for_completion_timeout(&wait, ATA_TMOUT_INTERNAL)) {
- ata_port_flush_task(ap);
+ ata_port_flush_task(ap);
- spin_lock_irqsave(&ap->host_set->lock, flags);
+ if (!rc) {
+ spin_lock_irqsave(ap->lock, flags);
/* We're racing with irq here. If we lose, the
* following test prevents us from completing the qc
- * again. If completion irq occurs after here but
- * before the caller cleans up, it will result in a
- * spurious interrupt. We can live with that.
+ * twice. If we win, the port is frozen and will be
+ * cleaned up by ->post_internal_cmd().
*/
if (qc->flags & ATA_QCFLAG_ACTIVE) {
- qc->err_mask = AC_ERR_TIMEOUT;
- ata_qc_complete(qc);
- printk(KERN_WARNING "ata%u: qc timeout (cmd 0x%x)\n",
- ap->id, command);
+ qc->err_mask |= AC_ERR_TIMEOUT;
+
+ if (ap->ops->error_handler)
+ ata_port_freeze(ap);
+ else
+ ata_qc_complete(qc);
+
+ if (ata_msg_warn(ap))
+ ata_dev_printk(dev, KERN_WARNING,
+ "qc timeout (cmd 0x%x)\n", command);
}
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
}
- *tf = qc->tf;
+ /* do post_internal_cmd */
+ if (ap->ops->post_internal_cmd)
+ ap->ops->post_internal_cmd(qc);
+
+ if (qc->flags & ATA_QCFLAG_FAILED && !qc->err_mask) {
+ if (ata_msg_warn(ap))
+ ata_dev_printk(dev, KERN_WARNING,
+ "zero err_mask for failed "
+ "internal command, assuming AC_ERR_OTHER\n");
+ qc->err_mask |= AC_ERR_OTHER;
+ }
+
+ /* finish up */
+ spin_lock_irqsave(ap->lock, flags);
+
+ *tf = qc->result_tf;
err_mask = qc->err_mask;
ata_qc_free(qc);
+ ap->active_tag = preempted_tag;
+ ap->sactive = preempted_sactive;
+ ap->qc_active = preempted_qc_active;
/* XXX - Some LLDDs (sata_mv) disable port on command failure.
* Until those drivers are fixed, we detect the condition
@@ -1033,11 +1121,13 @@ ata_exec_internal(struct ata_port *ap, struct ata_device *dev,
*
* Kill the following code as soon as those drivers are fixed.
*/
- if (ap->flags & ATA_FLAG_PORT_DISABLED) {
+ if (ap->flags & ATA_FLAG_DISABLED) {
err_mask |= AC_ERR_SYSTEM;
ata_port_probe(ap);
}
+ spin_unlock_irqrestore(ap->lock, flags);
+
return err_mask;
}
@@ -1076,11 +1166,10 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev)
/**
* ata_dev_read_id - Read ID data from the specified device
- * @ap: port on which target device resides
* @dev: target device
* @p_class: pointer to class of the target device (may be changed)
* @post_reset: is this read ID post-reset?
- * @p_id: read IDENTIFY page (newly allocated)
+ * @id: buffer to read IDENTIFY data into
*
* Read ID data from the specified device. ATA_CMD_ID_ATA is
* performed on ATA devices and ATA_CMD_ID_ATAPI on ATAPI
@@ -1093,29 +1182,24 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev)
* RETURNS:
* 0 on success, -errno otherwise.
*/
-static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev,
- unsigned int *p_class, int post_reset, u16 **p_id)
+int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
+ int post_reset, u16 *id)
{
+ struct ata_port *ap = dev->ap;
unsigned int class = *p_class;
struct ata_taskfile tf;
unsigned int err_mask = 0;
- u16 *id;
const char *reason;
int rc;
- DPRINTK("ENTER, host %u, dev %u\n", ap->id, dev->devno);
+ if (ata_msg_ctl(ap))
+ ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
+ __FUNCTION__, ap->id, dev->devno);
ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
- id = kmalloc(sizeof(id[0]) * ATA_ID_WORDS, GFP_KERNEL);
- if (id == NULL) {
- rc = -ENOMEM;
- reason = "out of memory";
- goto err_out;
- }
-
retry:
- ata_tf_init(ap, &tf, dev->devno);
+ ata_tf_init(dev, &tf);
switch (class) {
case ATA_DEV_ATA:
@@ -1132,7 +1216,7 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev,
tf.protocol = ATA_PROT_PIO;
- err_mask = ata_exec_internal(ap, dev, &tf, DMA_FROM_DEVICE,
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
id, sizeof(id[0]) * ATA_ID_WORDS);
if (err_mask) {
rc = -EIO;
@@ -1159,7 +1243,7 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev,
* Some drives were very specific about that exact sequence.
*/
if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) {
- err_mask = ata_dev_init_params(ap, dev, id[3], id[6]);
+ err_mask = ata_dev_init_params(dev, id[3], id[6]);
if (err_mask) {
rc = -EIO;
reason = "INIT_DEV_PARAMS failed";
@@ -1175,25 +1259,45 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev,
}
*p_class = class;
- *p_id = id;
+
return 0;
err_out:
- printk(KERN_WARNING "ata%u: dev %u failed to IDENTIFY (%s)\n",
- ap->id, dev->devno, reason);
- kfree(id);
+ if (ata_msg_warn(ap))
+ ata_dev_printk(dev, KERN_WARNING, "failed to IDENTIFY "
+ "(%s, err_mask=0x%x)\n", reason, err_mask);
return rc;
}
-static inline u8 ata_dev_knobble(const struct ata_port *ap,
- struct ata_device *dev)
+static inline u8 ata_dev_knobble(struct ata_device *dev)
{
- return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
+ return ((dev->ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
+}
+
+static void ata_dev_config_ncq(struct ata_device *dev,
+ char *desc, size_t desc_sz)
+{
+ struct ata_port *ap = dev->ap;
+ int hdepth = 0, ddepth = ata_id_queue_depth(dev->id);
+
+ if (!ata_id_has_ncq(dev->id)) {
+ desc[0] = '\0';
+ return;
+ }
+
+ if (ap->flags & ATA_FLAG_NCQ) {
+ hdepth = min(ap->host->can_queue, ATA_MAX_QUEUE - 1);
+ dev->flags |= ATA_DFLAG_NCQ;
+ }
+
+ if (hdepth >= ddepth)
+ snprintf(desc, desc_sz, "NCQ (depth %d)", ddepth);
+ else
+ snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth);
}
/**
* ata_dev_configure - Configure the specified ATA/ATAPI device
- * @ap: Port on which target device resides
* @dev: Target device to configure
* @print_info: Enable device info printout
*
@@ -1206,30 +1310,33 @@ static inline u8 ata_dev_knobble(const struct ata_port *ap,
* RETURNS:
* 0 on success, -errno otherwise
*/
-static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev,
- int print_info)
+int ata_dev_configure(struct ata_device *dev, int print_info)
{
+ struct ata_port *ap = dev->ap;
const u16 *id = dev->id;
unsigned int xfer_mask;
int i, rc;
- if (!ata_dev_present(dev)) {
- DPRINTK("ENTER/EXIT (host %u, dev %u) -- nodev\n",
- ap->id, dev->devno);
+ if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
+ ata_dev_printk(dev, KERN_INFO, "%s: ENTER/EXIT (host %u, dev %u) -- nodev\n",
+ __FUNCTION__, ap->id, dev->devno);
return 0;
}
- DPRINTK("ENTER, host %u, dev %u\n", ap->id, dev->devno);
+ if (ata_msg_probe(ap))
+ ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
+ __FUNCTION__, ap->id, dev->devno);
/* print device capabilities */
- if (print_info)
- printk(KERN_DEBUG "ata%u: dev %u cfg 49:%04x 82:%04x 83:%04x "
- "84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n",
- ap->id, dev->devno, id[49], id[82], id[83],
- id[84], id[85], id[86], id[87], id[88]);
+ if (ata_msg_probe(ap))
+ ata_dev_printk(dev, KERN_DEBUG, "%s: cfg 49:%04x 82:%04x 83:%04x "
+ "84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n",
+ __FUNCTION__,
+ id[49], id[82], id[83], id[84],
+ id[85], id[86], id[87], id[88]);
/* initialize to-be-configured parameters */
- dev->flags = 0;
+ dev->flags &= ~ATA_DFLAG_CFG_MASK;
dev->max_sectors = 0;
dev->cdb_len = 0;
dev->n_sectors = 0;
@@ -1244,7 +1351,8 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev,
/* find max transfer mode; for printk only */
xfer_mask = ata_id_xfermask(id);
- ata_dump_id(id);
+ if (ata_msg_probe(ap))
+ ata_dump_id(id);
/* ATA-specific feature tests */
if (dev->class == ATA_DEV_ATA) {
@@ -1252,6 +1360,7 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev,
if (ata_id_has_lba(id)) {
const char *lba_desc;
+ char ncq_desc[20];
lba_desc = "LBA";
dev->flags |= ATA_DFLAG_LBA;
@@ -1260,15 +1369,17 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev,
lba_desc = "LBA48";
}
+ /* config NCQ */
+ ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
+
/* print device info to dmesg */
- if (print_info)
- printk(KERN_INFO "ata%u: dev %u ATA-%d, "
- "max %s, %Lu sectors: %s\n",
- ap->id, dev->devno,
- ata_id_major_version(id),
- ata_mode_string(xfer_mask),
- (unsigned long long)dev->n_sectors,
- lba_desc);
+ if (ata_msg_info(ap))
+ ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
+ "max %s, %Lu sectors: %s %s\n",
+ ata_id_major_version(id),
+ ata_mode_string(xfer_mask),
+ (unsigned long long)dev->n_sectors,
+ lba_desc, ncq_desc);
} else {
/* CHS */
@@ -1285,14 +1396,20 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev,
}
/* print device info to dmesg */
- if (print_info)
- printk(KERN_INFO "ata%u: dev %u ATA-%d, "
- "max %s, %Lu sectors: CHS %u/%u/%u\n",
- ap->id, dev->devno,
- ata_id_major_version(id),
- ata_mode_string(xfer_mask),
- (unsigned long long)dev->n_sectors,
- dev->cylinders, dev->heads, dev->sectors);
+ if (ata_msg_info(ap))
+ ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
+ "max %s, %Lu sectors: CHS %u/%u/%u\n",
+ ata_id_major_version(id),
+ ata_mode_string(xfer_mask),
+ (unsigned long long)dev->n_sectors,
+ dev->cylinders, dev->heads, dev->sectors);
+ }
+
+ if (dev->id[59] & 0x100) {
+ dev->multi_count = dev->id[59] & 0xff;
+ if (ata_msg_info(ap))
+ ata_dev_printk(dev, KERN_INFO, "ata%u: dev %u multi count %u\n",
+ ap->id, dev->devno, dev->multi_count);
}
dev->cdb_len = 16;
@@ -1300,18 +1417,28 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev,
/* ATAPI-specific feature tests */
else if (dev->class == ATA_DEV_ATAPI) {
+ char *cdb_intr_string = "";
+
rc = atapi_cdb_len(id);
if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
- printk(KERN_WARNING "ata%u: unsupported CDB len\n", ap->id);
+ if (ata_msg_warn(ap))
+ ata_dev_printk(dev, KERN_WARNING,
+ "unsupported CDB len\n");
rc = -EINVAL;
goto err_out_nosup;
}
dev->cdb_len = (unsigned int) rc;
+ if (ata_id_cdb_intr(dev->id)) {
+ dev->flags |= ATA_DFLAG_CDB_INTR;
+ cdb_intr_string = ", CDB intr";
+ }
+
/* print device info to dmesg */
- if (print_info)
- printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n",
- ap->id, dev->devno, ata_mode_string(xfer_mask));
+ if (ata_msg_info(ap))
+ ata_dev_printk(dev, KERN_INFO, "ATAPI, max %s%s\n",
+ ata_mode_string(xfer_mask),
+ cdb_intr_string);
}
ap->host->max_cmd_len = 0;
@@ -1321,10 +1448,10 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev,
ap->device[i].cdb_len);
/* limit bridge transfers to udma5, 200 sectors */
- if (ata_dev_knobble(ap, dev)) {
- if (print_info)
- printk(KERN_INFO "ata%u(%u): applying bridge limits\n",
- ap->id, dev->devno);
+ if (ata_dev_knobble(dev)) {
+ if (ata_msg_info(ap))
+ ata_dev_printk(dev, KERN_INFO,
+ "applying bridge limits\n");
dev->udma_mask &= ATA_UDMA5;
dev->max_sectors = ATA_MAX_SECTORS;
}
@@ -1332,11 +1459,15 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev,
if (ap->ops->dev_config)
ap->ops->dev_config(ap, dev);
- DPRINTK("EXIT, drv_stat = 0x%x\n", ata_chk_status(ap));
+ if (ata_msg_probe(ap))
+ ata_dev_printk(dev, KERN_DEBUG, "%s: EXIT, drv_stat = 0x%x\n",
+ __FUNCTION__, ata_chk_status(ap));
return 0;
err_out_nosup:
- DPRINTK("EXIT, err\n");
+ if (ata_msg_probe(ap))
+ ata_dev_printk(dev, KERN_DEBUG,
+ "%s: EXIT, err\n", __FUNCTION__);
return rc;
}
@@ -1352,79 +1483,104 @@ err_out_nosup:
* PCI/etc. bus probe sem.
*
* RETURNS:
- * Zero on success, non-zero on error.
+ * Zero on success, negative errno otherwise.
*/
static int ata_bus_probe(struct ata_port *ap)
{
unsigned int classes[ATA_MAX_DEVICES];
- unsigned int i, rc, found = 0;
+ int tries[ATA_MAX_DEVICES];
+ int i, rc, down_xfermask;
+ struct ata_device *dev;
ata_port_probe(ap);
- /* reset and determine device classes */
for (i = 0; i < ATA_MAX_DEVICES; i++)
- classes[i] = ATA_DEV_UNKNOWN;
+ tries[i] = ATA_PROBE_MAX_TRIES;
- if (ap->ops->probe_reset) {
- rc = ap->ops->probe_reset(ap, classes);
- if (rc) {
- printk("ata%u: reset failed (errno=%d)\n", ap->id, rc);
- return rc;
- }
- } else {
- ap->ops->phy_reset(ap);
+ retry:
+ down_xfermask = 0;
- if (!(ap->flags & ATA_FLAG_PORT_DISABLED))
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- classes[i] = ap->device[i].class;
+ /* reset and determine device classes */
+ ap->ops->phy_reset(ap);
- ata_port_probe(ap);
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ dev = &ap->device[i];
+
+ if (!(ap->flags & ATA_FLAG_DISABLED) &&
+ dev->class != ATA_DEV_UNKNOWN)
+ classes[dev->devno] = dev->class;
+ else
+ classes[dev->devno] = ATA_DEV_NONE;
+
+ dev->class = ATA_DEV_UNKNOWN;
}
+ ata_port_probe(ap);
+
+ /* after the reset the device state is PIO 0 and the controller
+ state is undefined. Record the mode */
+
for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (classes[i] == ATA_DEV_UNKNOWN)
- classes[i] = ATA_DEV_NONE;
+ ap->device[i].pio_mode = XFER_PIO_0;
/* read IDENTIFY page and configure devices */
for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ dev = &ap->device[i];
- dev->class = classes[i];
+ if (tries[i])
+ dev->class = classes[i];
- if (!ata_dev_present(dev))
+ if (!ata_dev_enabled(dev))
continue;
- WARN_ON(dev->id != NULL);
- if (ata_dev_read_id(ap, dev, &dev->class, 1, &dev->id)) {
- dev->class = ATA_DEV_NONE;
- continue;
- }
+ rc = ata_dev_read_id(dev, &dev->class, 1, dev->id);
+ if (rc)
+ goto fail;
- if (ata_dev_configure(ap, dev, 1)) {
- ata_dev_disable(ap, dev);
- continue;
- }
+ rc = ata_dev_configure(dev, 1);
+ if (rc)
+ goto fail;
+ }
- found = 1;
+ /* configure transfer mode */
+ rc = ata_set_mode(ap, &dev);
+ if (rc) {
+ down_xfermask = 1;
+ goto fail;
}
- if (!found)
- goto err_out_disable;
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ if (ata_dev_enabled(&ap->device[i]))
+ return 0;
- if (ap->ops->set_mode)
- ap->ops->set_mode(ap);
- else
- ata_set_mode(ap);
+ /* no device present, disable port */
+ ata_port_disable(ap);
+ ap->ops->port_disable(ap);
+ return -ENODEV;
- if (ap->flags & ATA_FLAG_PORT_DISABLED)
- goto err_out_disable;
+ fail:
+ switch (rc) {
+ case -EINVAL:
+ case -ENODEV:
+ tries[dev->devno] = 0;
+ break;
+ case -EIO:
+ sata_down_spd_limit(ap);
+ /* fall through */
+ default:
+ tries[dev->devno]--;
+ if (down_xfermask &&
+ ata_down_xfermask_limit(dev, tries[dev->devno] == 1))
+ tries[dev->devno] = 0;
+ }
- return 0;
+ if (!tries[dev->devno]) {
+ ata_down_xfermask_limit(dev, 1);
+ ata_dev_disable(dev);
+ }
-err_out_disable:
- ap->ops->port_disable(ap);
- return -1;
+ goto retry;
}
/**
@@ -1440,7 +1596,7 @@ err_out_disable:
void ata_port_probe(struct ata_port *ap)
{
- ap->flags &= ~ATA_FLAG_PORT_DISABLED;
+ ap->flags &= ~ATA_FLAG_DISABLED;
}
/**
@@ -1454,27 +1610,21 @@ void ata_port_probe(struct ata_port *ap)
*/
static void sata_print_link_status(struct ata_port *ap)
{
- u32 sstatus, tmp;
- const char *speed;
+ u32 sstatus, scontrol, tmp;
- if (!ap->ops->scr_read)
+ if (sata_scr_read(ap, SCR_STATUS, &sstatus))
return;
+ sata_scr_read(ap, SCR_CONTROL, &scontrol);
- sstatus = scr_read(ap, SCR_STATUS);
-
- if (sata_dev_present(ap)) {
+ if (ata_port_online(ap)) {
tmp = (sstatus >> 4) & 0xf;
- if (tmp & (1 << 0))
- speed = "1.5";
- else if (tmp & (1 << 1))
- speed = "3.0";
- else
- speed = "<unknown>";
- printk(KERN_INFO "ata%u: SATA link up %s Gbps (SStatus %X)\n",
- ap->id, speed, sstatus);
+ ata_port_printk(ap, KERN_INFO,
+ "SATA link up %s (SStatus %X SControl %X)\n",
+ sata_spd_string(tmp), sstatus, scontrol);
} else {
- printk(KERN_INFO "ata%u: SATA link down (SStatus %X)\n",
- ap->id, sstatus);
+ ata_port_printk(ap, KERN_INFO,
+ "SATA link down (SStatus %X SControl %X)\n",
+ sstatus, scontrol);
}
}
@@ -1497,17 +1647,18 @@ void __sata_phy_reset(struct ata_port *ap)
if (ap->flags & ATA_FLAG_SATA_RESET) {
/* issue phy wake/reset */
- scr_write_flush(ap, SCR_CONTROL, 0x301);
+ sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
/* Couldn't find anything in SATA I/II specs, but
* AHCI-1.1 10.4.2 says at least 1 ms. */
mdelay(1);
}
- scr_write_flush(ap, SCR_CONTROL, 0x300); /* phy wake/clear reset */
+ /* phy wake/clear reset */
+ sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
/* wait for phy to become ready, if necessary */
do {
msleep(200);
- sstatus = scr_read(ap, SCR_STATUS);
+ sata_scr_read(ap, SCR_STATUS, &sstatus);
if ((sstatus & 0xf) != 1)
break;
} while (time_before(jiffies, timeout));
@@ -1516,12 +1667,12 @@ void __sata_phy_reset(struct ata_port *ap)
sata_print_link_status(ap);
/* TODO: phy layer with polling, timeouts, etc. */
- if (sata_dev_present(ap))
+ if (!ata_port_offline(ap))
ata_port_probe(ap);
else
ata_port_disable(ap);
- if (ap->flags & ATA_FLAG_PORT_DISABLED)
+ if (ap->flags & ATA_FLAG_DISABLED)
return;
if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
@@ -1546,24 +1697,24 @@ void __sata_phy_reset(struct ata_port *ap)
void sata_phy_reset(struct ata_port *ap)
{
__sata_phy_reset(ap);
- if (ap->flags & ATA_FLAG_PORT_DISABLED)
+ if (ap->flags & ATA_FLAG_DISABLED)
return;
ata_bus_reset(ap);
}
/**
* ata_dev_pair - return other device on cable
- * @ap: port
* @adev: device
*
* Obtain the other device on the same cable, or if none is
* present NULL is returned
*/
-struct ata_device *ata_dev_pair(struct ata_port *ap, struct ata_device *adev)
+struct ata_device *ata_dev_pair(struct ata_device *adev)
{
+ struct ata_port *ap = adev->ap;
struct ata_device *pair = &ap->device[1 - adev->devno];
- if (!ata_dev_present(pair))
+ if (!ata_dev_enabled(pair))
return NULL;
return pair;
}
@@ -1585,7 +1736,122 @@ void ata_port_disable(struct ata_port *ap)
{
ap->device[0].class = ATA_DEV_NONE;
ap->device[1].class = ATA_DEV_NONE;
- ap->flags |= ATA_FLAG_PORT_DISABLED;
+ ap->flags |= ATA_FLAG_DISABLED;
+}
+
+/**
+ * sata_down_spd_limit - adjust SATA spd limit downward
+ * @ap: Port to adjust SATA spd limit for
+ *
+ * Adjust SATA spd limit of @ap downward. Note that this
+ * function only adjusts the limit. The change must be applied
+ * using sata_set_spd().
+ *
+ * LOCKING:
+ * Inherited from caller.
+ *
+ * RETURNS:
+ * 0 on success, negative errno on failure
+ */
+int sata_down_spd_limit(struct ata_port *ap)
+{
+ u32 sstatus, spd, mask;
+ int rc, highbit;
+
+ rc = sata_scr_read(ap, SCR_STATUS, &sstatus);
+ if (rc)
+ return rc;
+
+ mask = ap->sata_spd_limit;
+ if (mask <= 1)
+ return -EINVAL;
+ highbit = fls(mask) - 1;
+ mask &= ~(1 << highbit);
+
+ spd = (sstatus >> 4) & 0xf;
+ if (spd <= 1)
+ return -EINVAL;
+ spd--;
+ mask &= (1 << spd) - 1;
+ if (!mask)
+ return -EINVAL;
+
+ ap->sata_spd_limit = mask;
+
+ ata_port_printk(ap, KERN_WARNING, "limiting SATA link speed to %s\n",
+ sata_spd_string(fls(mask)));
+
+ return 0;
+}
+
+static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol)
+{
+ u32 spd, limit;
+
+ if (ap->sata_spd_limit == UINT_MAX)
+ limit = 0;
+ else
+ limit = fls(ap->sata_spd_limit);
+
+ spd = (*scontrol >> 4) & 0xf;
+ *scontrol = (*scontrol & ~0xf0) | ((limit & 0xf) << 4);
+
+ return spd != limit;
+}
+
+/**
+ * sata_set_spd_needed - is SATA spd configuration needed
+ * @ap: Port in question
+ *
+ * Test whether the spd limit in SControl matches
+ * @ap->sata_spd_limit. This function is used to determine
+ * whether hardreset is necessary to apply SATA spd
+ * configuration.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ *
+ * RETURNS:
+ * 1 if SATA spd configuration is needed, 0 otherwise.
+ */
+int sata_set_spd_needed(struct ata_port *ap)
+{
+ u32 scontrol;
+
+ if (sata_scr_read(ap, SCR_CONTROL, &scontrol))
+ return 0;
+
+ return __sata_set_spd_needed(ap, &scontrol);
+}
+
+/**
+ * sata_set_spd - set SATA spd according to spd limit
+ * @ap: Port to set SATA spd for
+ *
+ * Set SATA spd of @ap according to sata_spd_limit.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ *
+ * RETURNS:
+ * 0 if spd doesn't need to be changed, 1 if spd has been
+ * changed. Negative errno if SCR registers are inaccessible.
+ */
+int sata_set_spd(struct ata_port *ap)
+{
+ u32 scontrol;
+ int rc;
+
+ if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+ return rc;
+
+ if (!__sata_set_spd_needed(ap, &scontrol))
+ return 0;
+
+ if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+ return rc;
+
+ return 1;
}
/*
@@ -1736,151 +2002,196 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
return 0;
}
-static int ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev)
+/**
+ * ata_down_xfermask_limit - adjust dev xfer masks downward
+ * @dev: Device to adjust xfer masks
+ * @force_pio0: Force PIO0
+ *
+ * Adjust xfer masks of @dev downward. Note that this function
+ * does not apply the change. Invoking ata_set_mode() afterwards
+ * will apply the limit.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ *
+ * RETURNS:
+ * 0 on success, negative errno on failure
+ */
+int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0)
+{
+ unsigned long xfer_mask;
+ int highbit;
+
+ xfer_mask = ata_pack_xfermask(dev->pio_mask, dev->mwdma_mask,
+ dev->udma_mask);
+
+ if (!xfer_mask)
+ goto fail;
+ /* don't gear down to MWDMA from UDMA, go directly to PIO */
+ if (xfer_mask & ATA_MASK_UDMA)
+ xfer_mask &= ~ATA_MASK_MWDMA;
+
+ highbit = fls(xfer_mask) - 1;
+ xfer_mask &= ~(1 << highbit);
+ if (force_pio0)
+ xfer_mask &= 1 << ATA_SHIFT_PIO;
+ if (!xfer_mask)
+ goto fail;
+
+ ata_unpack_xfermask(xfer_mask, &dev->pio_mask, &dev->mwdma_mask,
+ &dev->udma_mask);
+
+ ata_dev_printk(dev, KERN_WARNING, "limiting speed to %s\n",
+ ata_mode_string(xfer_mask));
+
+ return 0;
+
+ fail:
+ return -EINVAL;
+}
+
+static int ata_dev_set_mode(struct ata_device *dev)
{
unsigned int err_mask;
int rc;
+ dev->flags &= ~ATA_DFLAG_PIO;
if (dev->xfer_shift == ATA_SHIFT_PIO)
dev->flags |= ATA_DFLAG_PIO;
- err_mask = ata_dev_set_xfermode(ap, dev);
+ err_mask = ata_dev_set_xfermode(dev);
if (err_mask) {
- printk(KERN_ERR
- "ata%u: failed to set xfermode (err_mask=0x%x)\n",
- ap->id, err_mask);
+ ata_dev_printk(dev, KERN_ERR, "failed to set xfermode "
+ "(err_mask=0x%x)\n", err_mask);
return -EIO;
}
- rc = ata_dev_revalidate(ap, dev, 0);
- if (rc) {
- printk(KERN_ERR
- "ata%u: failed to revalidate after set xfermode\n",
- ap->id);
+ rc = ata_dev_revalidate(dev, 0);
+ if (rc)
return rc;
- }
DPRINTK("xfer_shift=%u, xfer_mode=0x%x\n",
dev->xfer_shift, (int)dev->xfer_mode);
- printk(KERN_INFO "ata%u: dev %u configured for %s\n",
- ap->id, dev->devno,
- ata_mode_string(ata_xfer_mode2mask(dev->xfer_mode)));
- return 0;
-}
-
-static int ata_host_set_pio(struct ata_port *ap)
-{
- int i;
-
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
-
- if (!ata_dev_present(dev))
- continue;
-
- if (!dev->pio_mode) {
- printk(KERN_WARNING "ata%u: no PIO support for device %d.\n", ap->id, i);
- return -1;
- }
-
- dev->xfer_mode = dev->pio_mode;
- dev->xfer_shift = ATA_SHIFT_PIO;
- if (ap->ops->set_piomode)
- ap->ops->set_piomode(ap, dev);
- }
-
+ ata_dev_printk(dev, KERN_INFO, "configured for %s\n",
+ ata_mode_string(ata_xfer_mode2mask(dev->xfer_mode)));
return 0;
}
-static void ata_host_set_dma(struct ata_port *ap)
-{
- int i;
-
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
-
- if (!ata_dev_present(dev) || !dev->dma_mode)
- continue;
-
- dev->xfer_mode = dev->dma_mode;
- dev->xfer_shift = ata_xfer_mode2shift(dev->dma_mode);
- if (ap->ops->set_dmamode)
- ap->ops->set_dmamode(ap, dev);
- }
-}
-
/**
* ata_set_mode - Program timings and issue SET FEATURES - XFER
* @ap: port on which timings will be programmed
+ * @r_failed_dev: out paramter for failed device
*
- * Set ATA device disk transfer mode (PIO3, UDMA6, etc.).
+ * Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If
+ * ata_set_mode() fails, pointer to the failing device is
+ * returned in @r_failed_dev.
*
* LOCKING:
* PCI/etc. bus probe sem.
+ *
+ * RETURNS:
+ * 0 on success, negative errno otherwise
*/
-static void ata_set_mode(struct ata_port *ap)
+int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
{
- int i, rc, used_dma = 0;
+ struct ata_device *dev;
+ int i, rc = 0, used_dma = 0, found = 0;
+
+ /* has private set_mode? */
+ if (ap->ops->set_mode) {
+ /* FIXME: make ->set_mode handle no device case and
+ * return error code and failing device on failure.
+ */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ if (ata_dev_enabled(&ap->device[i])) {
+ ap->ops->set_mode(ap);
+ break;
+ }
+ }
+ return 0;
+ }
/* step 1: calculate xfer_mask */
for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
unsigned int pio_mask, dma_mask;
- if (!ata_dev_present(dev))
- continue;
+ dev = &ap->device[i];
- ata_dev_xfermask(ap, dev);
+ if (!ata_dev_enabled(dev))
+ continue;
- /* TODO: let LLDD filter dev->*_mask here */
+ ata_dev_xfermask(dev);
pio_mask = ata_pack_xfermask(dev->pio_mask, 0, 0);
dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
dev->pio_mode = ata_xfer_mask2mode(pio_mask);
dev->dma_mode = ata_xfer_mask2mode(dma_mask);
+ found = 1;
if (dev->dma_mode)
used_dma = 1;
}
+ if (!found)
+ goto out;
/* step 2: always set host PIO timings */
- rc = ata_host_set_pio(ap);
- if (rc)
- goto err_out;
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ dev = &ap->device[i];
+ if (!ata_dev_enabled(dev))
+ continue;
+
+ if (!dev->pio_mode) {
+ ata_dev_printk(dev, KERN_WARNING, "no PIO support\n");
+ rc = -EINVAL;
+ goto out;
+ }
+
+ dev->xfer_mode = dev->pio_mode;
+ dev->xfer_shift = ATA_SHIFT_PIO;
+ if (ap->ops->set_piomode)
+ ap->ops->set_piomode(ap, dev);
+ }
/* step 3: set host DMA timings */
- ata_host_set_dma(ap);
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ dev = &ap->device[i];
+
+ if (!ata_dev_enabled(dev) || !dev->dma_mode)
+ continue;
+
+ dev->xfer_mode = dev->dma_mode;
+ dev->xfer_shift = ata_xfer_mode2shift(dev->dma_mode);
+ if (ap->ops->set_dmamode)
+ ap->ops->set_dmamode(ap, dev);
+ }
/* step 4: update devices' xfer mode */
for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ dev = &ap->device[i];
- if (!ata_dev_present(dev))
+ if (!ata_dev_enabled(dev))
continue;
- if (ata_dev_set_mode(ap, dev))
- goto err_out;
+ rc = ata_dev_set_mode(dev);
+ if (rc)
+ goto out;
}
- /*
- * Record simplex status. If we selected DMA then the other
- * host channels are not permitted to do so.
+ /* Record simplex status. If we selected DMA then the other
+ * host channels are not permitted to do so.
*/
-
if (used_dma && (ap->host_set->flags & ATA_HOST_SIMPLEX))
ap->host_set->simplex_claimed = 1;
- /*
- * Chip specific finalisation
- */
+ /* step5: chip specific finalisation */
if (ap->ops->post_set_mode)
ap->ops->post_set_mode(ap);
- return;
-
-err_out:
- ata_port_disable(ap);
+ out:
+ if (rc)
+ *r_failed_dev = dev;
+ return rc;
}
/**
@@ -1930,8 +2241,8 @@ unsigned int ata_busy_sleep (struct ata_port *ap,
}
if (status & ATA_BUSY)
- printk(KERN_WARNING "ata%u is slow to respond, "
- "please be patient\n", ap->id);
+ ata_port_printk(ap, KERN_WARNING,
+ "port is slow to respond, please be patient\n");
timeout = timer_start + tmout;
while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) {
@@ -1940,8 +2251,8 @@ unsigned int ata_busy_sleep (struct ata_port *ap,
}
if (status & ATA_BUSY) {
- printk(KERN_ERR "ata%u failed to respond (%lu secs)\n",
- ap->id, tmout / HZ);
+ ata_port_printk(ap, KERN_ERR, "port failed to respond "
+ "(%lu secs)\n", tmout / HZ);
return 1;
}
@@ -2033,8 +2344,10 @@ static unsigned int ata_bus_softreset(struct ata_port *ap,
* the bus shows 0xFF because the odd clown forgets the D7
* pulldown resistor.
*/
- if (ata_check_status(ap) == 0xFF)
+ if (ata_check_status(ap) == 0xFF) {
+ ata_port_printk(ap, KERN_ERR, "SRST failed (status 0xFF)\n");
return AC_ERR_OTHER;
+ }
ata_bus_post_reset(ap, devmask);
@@ -2058,7 +2371,7 @@ static unsigned int ata_bus_softreset(struct ata_port *ap,
* Obtains host_set lock.
*
* SIDE EFFECTS:
- * Sets ATA_FLAG_PORT_DISABLED if bus reset fails.
+ * Sets ATA_FLAG_DISABLED if bus reset fails.
*/
void ata_bus_reset(struct ata_port *ap)
@@ -2126,60 +2439,195 @@ void ata_bus_reset(struct ata_port *ap)
return;
err_out:
- printk(KERN_ERR "ata%u: disabling port\n", ap->id);
+ ata_port_printk(ap, KERN_ERR, "disabling port\n");
ap->ops->port_disable(ap);
DPRINTK("EXIT\n");
}
-static int sata_phy_resume(struct ata_port *ap)
+/**
+ * sata_phy_debounce - debounce SATA phy status
+ * @ap: ATA port to debounce SATA phy status for
+ * @params: timing parameters { interval, duratinon, timeout } in msec
+ *
+ * Make sure SStatus of @ap reaches stable state, determined by
+ * holding the same value where DET is not 1 for @duration polled
+ * every @interval, before @timeout. Timeout constraints the
+ * beginning of the stable state. Because, after hot unplugging,
+ * DET gets stuck at 1 on some controllers, this functions waits
+ * until timeout then returns 0 if DET is stable at 1.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int sata_phy_debounce(struct ata_port *ap, const unsigned long *params)
{
- unsigned long timeout = jiffies + (HZ * 5);
- u32 sstatus;
+ unsigned long interval_msec = params[0];
+ unsigned long duration = params[1] * HZ / 1000;
+ unsigned long timeout = jiffies + params[2] * HZ / 1000;
+ unsigned long last_jiffies;
+ u32 last, cur;
+ int rc;
- scr_write_flush(ap, SCR_CONTROL, 0x300);
+ if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
+ return rc;
+ cur &= 0xf;
- /* Wait for phy to become ready, if necessary. */
- do {
- msleep(200);
- sstatus = scr_read(ap, SCR_STATUS);
- if ((sstatus & 0xf) != 1)
- return 0;
- } while (time_before(jiffies, timeout));
+ last = cur;
+ last_jiffies = jiffies;
- return -1;
+ while (1) {
+ msleep(interval_msec);
+ if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
+ return rc;
+ cur &= 0xf;
+
+ /* DET stable? */
+ if (cur == last) {
+ if (cur == 1 && time_before(jiffies, timeout))
+ continue;
+ if (time_after(jiffies, last_jiffies + duration))
+ return 0;
+ continue;
+ }
+
+ /* unstable, start over */
+ last = cur;
+ last_jiffies = jiffies;
+
+ /* check timeout */
+ if (time_after(jiffies, timeout))
+ return -EBUSY;
+ }
}
/**
- * ata_std_probeinit - initialize probing
- * @ap: port to be probed
+ * sata_phy_resume - resume SATA phy
+ * @ap: ATA port to resume SATA phy for
+ * @params: timing parameters { interval, duratinon, timeout } in msec
+ *
+ * Resume SATA phy of @ap and debounce it.
*
- * @ap is about to be probed. Initialize it. This function is
- * to be used as standard callback for ata_drive_probe_reset().
+ * LOCKING:
+ * Kernel thread context (may sleep)
*
- * NOTE!!! Do not use this function as probeinit if a low level
- * driver implements only hardreset. Just pass NULL as probeinit
- * in that case. Using this function is probably okay but doing
- * so makes reset sequence different from the original
- * ->phy_reset implementation and Jeff nervous. :-P
+ * RETURNS:
+ * 0 on success, -errno on failure.
*/
-void ata_std_probeinit(struct ata_port *ap)
+int sata_phy_resume(struct ata_port *ap, const unsigned long *params)
{
- if ((ap->flags & ATA_FLAG_SATA) && ap->ops->scr_read) {
- sata_phy_resume(ap);
- if (sata_dev_present(ap))
- ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+ u32 scontrol;
+ int rc;
+
+ if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+ return rc;
+
+ scontrol = (scontrol & 0x0f0) | 0x300;
+
+ if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+ return rc;
+
+ /* Some PHYs react badly if SStatus is pounded immediately
+ * after resuming. Delay 200ms before debouncing.
+ */
+ msleep(200);
+
+ return sata_phy_debounce(ap, params);
+}
+
+static void ata_wait_spinup(struct ata_port *ap)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ unsigned long end, secs;
+ int rc;
+
+ /* first, debounce phy if SATA */
+ if (ap->cbl == ATA_CBL_SATA) {
+ rc = sata_phy_debounce(ap, sata_deb_timing_eh);
+
+ /* if debounced successfully and offline, no need to wait */
+ if ((rc == 0 || rc == -EOPNOTSUPP) && ata_port_offline(ap))
+ return;
}
+
+ /* okay, let's give the drive time to spin up */
+ end = ehc->i.hotplug_timestamp + ATA_SPINUP_WAIT * HZ / 1000;
+ secs = ((end - jiffies) + HZ - 1) / HZ;
+
+ if (time_after(jiffies, end))
+ return;
+
+ if (secs > 5)
+ ata_port_printk(ap, KERN_INFO, "waiting for device to spin up "
+ "(%lu secs)\n", secs);
+
+ schedule_timeout_uninterruptible(end - jiffies);
+}
+
+/**
+ * ata_std_prereset - prepare for reset
+ * @ap: ATA port to be reset
+ *
+ * @ap is about to be reset. Initialize it.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ata_std_prereset(struct ata_port *ap)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ const unsigned long *timing;
+ int rc;
+
+ /* hotplug? */
+ if (ehc->i.flags & ATA_EHI_HOTPLUGGED) {
+ if (ap->flags & ATA_FLAG_HRST_TO_RESUME)
+ ehc->i.action |= ATA_EH_HARDRESET;
+ if (ap->flags & ATA_FLAG_SKIP_D2H_BSY)
+ ata_wait_spinup(ap);
+ }
+
+ /* if we're about to do hardreset, nothing more to do */
+ if (ehc->i.action & ATA_EH_HARDRESET)
+ return 0;
+
+ /* if SATA, resume phy */
+ if (ap->cbl == ATA_CBL_SATA) {
+ if (ap->flags & ATA_FLAG_LOADING)
+ timing = sata_deb_timing_boot;
+ else
+ timing = sata_deb_timing_eh;
+
+ rc = sata_phy_resume(ap, timing);
+ if (rc && rc != -EOPNOTSUPP) {
+ /* phy resume failed */
+ ata_port_printk(ap, KERN_WARNING, "failed to resume "
+ "link for reset (errno=%d)\n", rc);
+ return rc;
+ }
+ }
+
+ /* Wait for !BSY if the controller can wait for the first D2H
+ * Reg FIS and we don't know that no device is attached.
+ */
+ if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap))
+ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+ return 0;
}
/**
* ata_std_softreset - reset host port via ATA SRST
* @ap: port to reset
- * @verbose: fail verbosely
* @classes: resulting classes of attached devices
*
- * Reset host port using ATA SRST. This function is to be used
- * as standard callback for ata_drive_*_reset() functions.
+ * Reset host port using ATA SRST.
*
* LOCKING:
* Kernel thread context (may sleep)
@@ -2187,7 +2635,7 @@ void ata_std_probeinit(struct ata_port *ap)
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int ata_std_softreset(struct ata_port *ap, int verbose, unsigned int *classes)
+int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
{
unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
unsigned int devmask = 0, err_mask;
@@ -2195,7 +2643,7 @@ int ata_std_softreset(struct ata_port *ap, int verbose, unsigned int *classes)
DPRINTK("ENTER\n");
- if (ap->ops->scr_read && !sata_dev_present(ap)) {
+ if (ata_port_offline(ap)) {
classes[0] = ATA_DEV_NONE;
goto out;
}
@@ -2213,11 +2661,7 @@ int ata_std_softreset(struct ata_port *ap, int verbose, unsigned int *classes)
DPRINTK("about to softreset, devmask=%x\n", devmask);
err_mask = ata_bus_softreset(ap, devmask);
if (err_mask) {
- if (verbose)
- printk(KERN_ERR "ata%u: SRST failed (err_mask=0x%x)\n",
- ap->id, err_mask);
- else
- DPRINTK("EXIT, softreset failed (err_mask=0x%x)\n",
+ ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n",
err_mask);
return -EIO;
}
@@ -2235,12 +2679,9 @@ int ata_std_softreset(struct ata_port *ap, int verbose, unsigned int *classes)
/**
* sata_std_hardreset - reset host port via SATA phy reset
* @ap: port to reset
- * @verbose: fail verbosely
* @class: resulting class of attached device
*
* SATA phy-reset host port using DET bits of SControl register.
- * This function is to be used as standard callback for
- * ata_drive_*_reset().
*
* LOCKING:
* Kernel thread context (may sleep)
@@ -2248,35 +2689,57 @@ int ata_std_softreset(struct ata_port *ap, int verbose, unsigned int *classes)
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int sata_std_hardreset(struct ata_port *ap, int verbose, unsigned int *class)
+int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
{
+ u32 scontrol;
+ int rc;
+
DPRINTK("ENTER\n");
- /* Issue phy wake/reset */
- scr_write_flush(ap, SCR_CONTROL, 0x301);
+ if (sata_set_spd_needed(ap)) {
+ /* SATA spec says nothing about how to reconfigure
+ * spd. To be on the safe side, turn off phy during
+ * reconfiguration. This works for at least ICH7 AHCI
+ * and Sil3124.
+ */
+ if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+ return rc;
- /*
- * Couldn't find anything in SATA I/II specs, but AHCI-1.1
+ scontrol = (scontrol & 0x0f0) | 0x302;
+
+ if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+ return rc;
+
+ sata_set_spd(ap);
+ }
+
+ /* issue phy wake/reset */
+ if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+ return rc;
+
+ scontrol = (scontrol & 0x0f0) | 0x301;
+
+ if ((rc = sata_scr_write_flush(ap, SCR_CONTROL, scontrol)))
+ return rc;
+
+ /* Couldn't find anything in SATA I/II specs, but AHCI-1.1
* 10.4.2 says at least 1 ms.
*/
msleep(1);
- /* Bring phy back */
- sata_phy_resume(ap);
+ /* bring phy back */
+ sata_phy_resume(ap, sata_deb_timing_eh);
/* TODO: phy layer with polling, timeouts, etc. */
- if (!sata_dev_present(ap)) {
+ if (ata_port_offline(ap)) {
*class = ATA_DEV_NONE;
DPRINTK("EXIT, link offline\n");
return 0;
}
if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
- if (verbose)
- printk(KERN_ERR "ata%u: COMRESET failed "
- "(device not ready)\n", ap->id);
- else
- DPRINTK("EXIT, device not ready\n");
+ ata_port_printk(ap, KERN_ERR,
+ "COMRESET failed (device not ready)\n");
return -EIO;
}
@@ -2297,27 +2760,28 @@ int sata_std_hardreset(struct ata_port *ap, int verbose, unsigned int *class)
* the device might have been reset more than once using
* different reset methods before postreset is invoked.
*
- * This function is to be used as standard callback for
- * ata_drive_*_reset().
- *
* LOCKING:
* Kernel thread context (may sleep)
*/
void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
{
- DPRINTK("ENTER\n");
+ u32 serror;
- /* set cable type if it isn't already set */
- if (ap->cbl == ATA_CBL_NONE && ap->flags & ATA_FLAG_SATA)
- ap->cbl = ATA_CBL_SATA;
+ DPRINTK("ENTER\n");
/* print link status */
- if (ap->cbl == ATA_CBL_SATA)
- sata_print_link_status(ap);
+ sata_print_link_status(ap);
+
+ /* clear SError */
+ if (sata_scr_read(ap, SCR_ERROR, &serror) == 0)
+ sata_scr_write(ap, SCR_ERROR, serror);
/* re-enable interrupts */
- if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */
- ata_irq_on(ap);
+ if (!ap->ops->error_handler) {
+ /* FIXME: hack. create a hook instead */
+ if (ap->ioaddr.ctl_addr)
+ ata_irq_on(ap);
+ }
/* is double-select really necessary? */
if (classes[0] != ATA_DEV_NONE)
@@ -2343,126 +2807,7 @@ void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
}
/**
- * ata_std_probe_reset - standard probe reset method
- * @ap: prot to perform probe-reset
- * @classes: resulting classes of attached devices
- *
- * The stock off-the-shelf ->probe_reset method.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- *
- * RETURNS:
- * 0 on success, -errno otherwise.
- */
-int ata_std_probe_reset(struct ata_port *ap, unsigned int *classes)
-{
- ata_reset_fn_t hardreset;
-
- hardreset = NULL;
- if (ap->flags & ATA_FLAG_SATA && ap->ops->scr_read)
- hardreset = sata_std_hardreset;
-
- return ata_drive_probe_reset(ap, ata_std_probeinit,
- ata_std_softreset, hardreset,
- ata_std_postreset, classes);
-}
-
-static int do_probe_reset(struct ata_port *ap, ata_reset_fn_t reset,
- ata_postreset_fn_t postreset,
- unsigned int *classes)
-{
- int i, rc;
-
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- classes[i] = ATA_DEV_UNKNOWN;
-
- rc = reset(ap, 0, classes);
- if (rc)
- return rc;
-
- /* If any class isn't ATA_DEV_UNKNOWN, consider classification
- * is complete and convert all ATA_DEV_UNKNOWN to
- * ATA_DEV_NONE.
- */
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (classes[i] != ATA_DEV_UNKNOWN)
- break;
-
- if (i < ATA_MAX_DEVICES)
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (classes[i] == ATA_DEV_UNKNOWN)
- classes[i] = ATA_DEV_NONE;
-
- if (postreset)
- postreset(ap, classes);
-
- return classes[0] != ATA_DEV_UNKNOWN ? 0 : -ENODEV;
-}
-
-/**
- * ata_drive_probe_reset - Perform probe reset with given methods
- * @ap: port to reset
- * @probeinit: probeinit method (can be NULL)
- * @softreset: softreset method (can be NULL)
- * @hardreset: hardreset method (can be NULL)
- * @postreset: postreset method (can be NULL)
- * @classes: resulting classes of attached devices
- *
- * Reset the specified port and classify attached devices using
- * given methods. This function prefers softreset but tries all
- * possible reset sequences to reset and classify devices. This
- * function is intended to be used for constructing ->probe_reset
- * callback by low level drivers.
- *
- * Reset methods should follow the following rules.
- *
- * - Return 0 on sucess, -errno on failure.
- * - If classification is supported, fill classes[] with
- * recognized class codes.
- * - If classification is not supported, leave classes[] alone.
- * - If verbose is non-zero, print error message on failure;
- * otherwise, shut up.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- *
- * RETURNS:
- * 0 on success, -EINVAL if no reset method is avaliable, -ENODEV
- * if classification fails, and any error code from reset
- * methods.
- */
-int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit,
- ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
- ata_postreset_fn_t postreset, unsigned int *classes)
-{
- int rc = -EINVAL;
-
- if (probeinit)
- probeinit(ap);
-
- if (softreset) {
- rc = do_probe_reset(ap, softreset, postreset, classes);
- if (rc == 0)
- return 0;
- }
-
- if (!hardreset)
- return rc;
-
- rc = do_probe_reset(ap, hardreset, postreset, classes);
- if (rc == 0 || rc != -ENODEV)
- return rc;
-
- if (softreset)
- rc = do_probe_reset(ap, softreset, postreset, classes);
-
- return rc;
-}
-
-/**
* ata_dev_same_device - Determine whether new ID matches configured device
- * @ap: port on which the device to compare against resides
* @dev: device to compare against
* @new_class: class of the new device
* @new_id: IDENTIFY page of the new device
@@ -2477,17 +2822,16 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit,
* RETURNS:
* 1 if @dev matches @new_class and @new_id, 0 otherwise.
*/
-static int ata_dev_same_device(struct ata_port *ap, struct ata_device *dev,
- unsigned int new_class, const u16 *new_id)
+static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
+ const u16 *new_id)
{
const u16 *old_id = dev->id;
unsigned char model[2][41], serial[2][21];
u64 new_n_sectors;
if (dev->class != new_class) {
- printk(KERN_INFO
- "ata%u: dev %u class mismatch %d != %d\n",
- ap->id, dev->devno, dev->class, new_class);
+ ata_dev_printk(dev, KERN_INFO, "class mismatch %d != %d\n",
+ dev->class, new_class);
return 0;
}
@@ -2498,24 +2842,22 @@ static int ata_dev_same_device(struct ata_port *ap, struct ata_device *dev,
new_n_sectors = ata_id_n_sectors(new_id);
if (strcmp(model[0], model[1])) {
- printk(KERN_INFO
- "ata%u: dev %u model number mismatch '%s' != '%s'\n",
- ap->id, dev->devno, model[0], model[1]);
+ ata_dev_printk(dev, KERN_INFO, "model number mismatch "
+ "'%s' != '%s'\n", model[0], model[1]);
return 0;
}
if (strcmp(serial[0], serial[1])) {
- printk(KERN_INFO
- "ata%u: dev %u serial number mismatch '%s' != '%s'\n",
- ap->id, dev->devno, serial[0], serial[1]);
+ ata_dev_printk(dev, KERN_INFO, "serial number mismatch "
+ "'%s' != '%s'\n", serial[0], serial[1]);
return 0;
}
if (dev->class == ATA_DEV_ATA && dev->n_sectors != new_n_sectors) {
- printk(KERN_INFO
- "ata%u: dev %u n_sectors mismatch %llu != %llu\n",
- ap->id, dev->devno, (unsigned long long)dev->n_sectors,
- (unsigned long long)new_n_sectors);
+ ata_dev_printk(dev, KERN_INFO, "n_sectors mismatch "
+ "%llu != %llu\n",
+ (unsigned long long)dev->n_sectors,
+ (unsigned long long)new_n_sectors);
return 0;
}
@@ -2524,7 +2866,6 @@ static int ata_dev_same_device(struct ata_port *ap, struct ata_device *dev,
/**
* ata_dev_revalidate - Revalidate ATA device
- * @ap: port on which the device to revalidate resides
* @dev: device to revalidate
* @post_reset: is this revalidation after reset?
*
@@ -2537,40 +2878,37 @@ static int ata_dev_same_device(struct ata_port *ap, struct ata_device *dev,
* RETURNS:
* 0 on success, negative errno otherwise
*/
-int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev,
- int post_reset)
+int ata_dev_revalidate(struct ata_device *dev, int post_reset)
{
- unsigned int class;
- u16 *id;
+ unsigned int class = dev->class;
+ u16 *id = (void *)dev->ap->sector_buf;
int rc;
- if (!ata_dev_present(dev))
- return -ENODEV;
-
- class = dev->class;
- id = NULL;
+ if (!ata_dev_enabled(dev)) {
+ rc = -ENODEV;
+ goto fail;
+ }
- /* allocate & read ID data */
- rc = ata_dev_read_id(ap, dev, &class, post_reset, &id);
+ /* read ID data */
+ rc = ata_dev_read_id(dev, &class, post_reset, id);
if (rc)
goto fail;
/* is the device still there? */
- if (!ata_dev_same_device(ap, dev, class, id)) {
+ if (!ata_dev_same_device(dev, class, id)) {
rc = -ENODEV;
goto fail;
}
- kfree(dev->id);
- dev->id = id;
+ memcpy(dev->id, id, sizeof(id[0]) * ATA_ID_WORDS);
/* configure device according to the new ID */
- return ata_dev_configure(ap, dev, 0);
+ rc = ata_dev_configure(dev, 0);
+ if (rc == 0)
+ return 0;
fail:
- printk(KERN_ERR "ata%u: dev %u revalidation failed (errno=%d)\n",
- ap->id, dev->devno, rc);
- kfree(id);
+ ata_dev_printk(dev, KERN_ERR, "revalidation failed (errno=%d)\n", rc);
return rc;
}
@@ -2626,6 +2964,14 @@ static int ata_dma_blacklisted(const struct ata_device *dev)
unsigned int nlen, rlen;
int i;
+ /* We don't support polling DMA.
+ * DMA blacklist those ATAPI devices with CDB-intr (and use PIO)
+ * if the LLDD handles only interrupts in the HSM_ST_LAST state.
+ */
+ if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) &&
+ (dev->flags & ATA_DFLAG_CDB_INTR))
+ return 1;
+
ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
sizeof(model_num));
ata_id_string(dev->id, model_rev, ATA_ID_FW_REV_OFS,
@@ -2646,7 +2992,6 @@ static int ata_dma_blacklisted(const struct ata_device *dev)
/**
* ata_dev_xfermask - Compute supported xfermask of the given device
- * @ap: Port on which the device to compute xfermask for resides
* @dev: Device to compute xfermask for
*
* Compute supported xfermask of @dev and store it in
@@ -2661,49 +3006,61 @@ static int ata_dma_blacklisted(const struct ata_device *dev)
* LOCKING:
* None.
*/
-static void ata_dev_xfermask(struct ata_port *ap, struct ata_device *dev)
+static void ata_dev_xfermask(struct ata_device *dev)
{
+ struct ata_port *ap = dev->ap;
struct ata_host_set *hs = ap->host_set;
unsigned long xfer_mask;
int i;
- xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
- ap->udma_mask);
+ xfer_mask = ata_pack_xfermask(ap->pio_mask,
+ ap->mwdma_mask, ap->udma_mask);
+
+ /* Apply cable rule here. Don't apply it early because when
+ * we handle hot plug the cable type can itself change.
+ */
+ if (ap->cbl == ATA_CBL_PATA40)
+ xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA);
/* FIXME: Use port-wide xfermask for now */
for (i = 0; i < ATA_MAX_DEVICES; i++) {
struct ata_device *d = &ap->device[i];
- if (!ata_dev_present(d))
+
+ if (ata_dev_absent(d))
continue;
- xfer_mask &= ata_pack_xfermask(d->pio_mask, d->mwdma_mask,
- d->udma_mask);
+
+ if (ata_dev_disabled(d)) {
+ /* to avoid violating device selection timing */
+ xfer_mask &= ata_pack_xfermask(d->pio_mask,
+ UINT_MAX, UINT_MAX);
+ continue;
+ }
+
+ xfer_mask &= ata_pack_xfermask(d->pio_mask,
+ d->mwdma_mask, d->udma_mask);
xfer_mask &= ata_id_xfermask(d->id);
if (ata_dma_blacklisted(d))
xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
- /* Apply cable rule here. Don't apply it early because when
- we handle hot plug the cable type can itself change */
- if (ap->cbl == ATA_CBL_PATA40)
- xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA);
}
if (ata_dma_blacklisted(dev))
- printk(KERN_WARNING "ata%u: dev %u is on DMA blacklist, "
- "disabling DMA\n", ap->id, dev->devno);
+ ata_dev_printk(dev, KERN_WARNING,
+ "device is on DMA blacklist, disabling DMA\n");
if (hs->flags & ATA_HOST_SIMPLEX) {
if (hs->simplex_claimed)
xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
}
+
if (ap->ops->mode_filter)
xfer_mask = ap->ops->mode_filter(ap, dev, xfer_mask);
- ata_unpack_xfermask(xfer_mask, &dev->pio_mask, &dev->mwdma_mask,
- &dev->udma_mask);
+ ata_unpack_xfermask(xfer_mask, &dev->pio_mask,
+ &dev->mwdma_mask, &dev->udma_mask);
}
/**
* ata_dev_set_xfermode - Issue SET FEATURES - XFER MODE command
- * @ap: Port associated with device @dev
* @dev: Device to which command will be sent
*
* Issue SET FEATURES - XFER MODE command to device @dev
@@ -2716,8 +3073,7 @@ static void ata_dev_xfermask(struct ata_port *ap, struct ata_device *dev)
* 0 on success, AC_ERR_* mask otherwise.
*/
-static unsigned int ata_dev_set_xfermode(struct ata_port *ap,
- struct ata_device *dev)
+static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
{
struct ata_taskfile tf;
unsigned int err_mask;
@@ -2725,14 +3081,14 @@ static unsigned int ata_dev_set_xfermode(struct ata_port *ap,
/* set up set-features taskfile */
DPRINTK("set features - xfer mode\n");
- ata_tf_init(ap, &tf, dev->devno);
+ ata_tf_init(dev, &tf);
tf.command = ATA_CMD_SET_FEATURES;
tf.feature = SETFEATURES_XFER;
tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
tf.protocol = ATA_PROT_NODATA;
tf.nsect = dev->xfer_mode;
- err_mask = ata_exec_internal(ap, dev, &tf, DMA_NONE, NULL, 0);
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
DPRINTK("EXIT, err_mask=%x\n", err_mask);
return err_mask;
@@ -2740,7 +3096,6 @@ static unsigned int ata_dev_set_xfermode(struct ata_port *ap,
/**
* ata_dev_init_params - Issue INIT DEV PARAMS command
- * @ap: Port associated with device @dev
* @dev: Device to which command will be sent
* @heads: Number of heads (taskfile parameter)
* @sectors: Number of sectors (taskfile parameter)
@@ -2751,11 +3106,8 @@ static unsigned int ata_dev_set_xfermode(struct ata_port *ap,
* RETURNS:
* 0 on success, AC_ERR_* mask otherwise.
*/
-
-static unsigned int ata_dev_init_params(struct ata_port *ap,
- struct ata_device *dev,
- u16 heads,
- u16 sectors)
+static unsigned int ata_dev_init_params(struct ata_device *dev,
+ u16 heads, u16 sectors)
{
struct ata_taskfile tf;
unsigned int err_mask;
@@ -2767,14 +3119,14 @@ static unsigned int ata_dev_init_params(struct ata_port *ap,
/* set up init dev params taskfile */
DPRINTK("init dev params \n");
- ata_tf_init(ap, &tf, dev->devno);
+ ata_tf_init(dev, &tf);
tf.command = ATA_CMD_INIT_DEV_PARAMS;
tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
tf.protocol = ATA_PROT_NODATA;
tf.nsect = sectors;
tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */
- err_mask = ata_exec_internal(ap, dev, &tf, DMA_NONE, NULL, 0);
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
DPRINTK("EXIT, err_mask=%x\n", err_mask);
return err_mask;
@@ -2957,6 +3309,7 @@ void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
qc->n_elem = 1;
qc->orig_n_elem = 1;
qc->buf_virt = buf;
+ qc->nbytes = buflen;
sg = qc->__sg;
sg_init_one(sg, buf, buflen);
@@ -3140,134 +3493,6 @@ skip_map:
}
/**
- * ata_poll_qc_complete - turn irq back on and finish qc
- * @qc: Command to complete
- * @err_mask: ATA status register content
- *
- * LOCKING:
- * None. (grabs host lock)
- */
-
-void ata_poll_qc_complete(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- unsigned long flags;
-
- spin_lock_irqsave(&ap->host_set->lock, flags);
- ap->flags &= ~ATA_FLAG_NOINTR;
- ata_irq_on(ap);
- ata_qc_complete(qc);
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
-}
-
-/**
- * ata_pio_poll - poll using PIO, depending on current state
- * @ap: the target ata_port
- *
- * LOCKING:
- * None. (executing in kernel thread context)
- *
- * RETURNS:
- * timeout value to use
- */
-
-static unsigned long ata_pio_poll(struct ata_port *ap)
-{
- struct ata_queued_cmd *qc;
- u8 status;
- unsigned int poll_state = HSM_ST_UNKNOWN;
- unsigned int reg_state = HSM_ST_UNKNOWN;
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
- WARN_ON(qc == NULL);
-
- switch (ap->hsm_task_state) {
- case HSM_ST:
- case HSM_ST_POLL:
- poll_state = HSM_ST_POLL;
- reg_state = HSM_ST;
- break;
- case HSM_ST_LAST:
- case HSM_ST_LAST_POLL:
- poll_state = HSM_ST_LAST_POLL;
- reg_state = HSM_ST_LAST;
- break;
- default:
- BUG();
- break;
- }
-
- status = ata_chk_status(ap);
- if (status & ATA_BUSY) {
- if (time_after(jiffies, ap->pio_task_timeout)) {
- qc->err_mask |= AC_ERR_TIMEOUT;
- ap->hsm_task_state = HSM_ST_TMOUT;
- return 0;
- }
- ap->hsm_task_state = poll_state;
- return ATA_SHORT_PAUSE;
- }
-
- ap->hsm_task_state = reg_state;
- return 0;
-}
-
-/**
- * ata_pio_complete - check if drive is busy or idle
- * @ap: the target ata_port
- *
- * LOCKING:
- * None. (executing in kernel thread context)
- *
- * RETURNS:
- * Non-zero if qc completed, zero otherwise.
- */
-
-static int ata_pio_complete (struct ata_port *ap)
-{
- struct ata_queued_cmd *qc;
- u8 drv_stat;
-
- /*
- * This is purely heuristic. This is a fast path. Sometimes when
- * we enter, BSY will be cleared in a chk-status or two. If not,
- * the drive is probably seeking or something. Snooze for a couple
- * msecs, then chk-status again. If still busy, fall back to
- * HSM_ST_POLL state.
- */
- drv_stat = ata_busy_wait(ap, ATA_BUSY, 10);
- if (drv_stat & ATA_BUSY) {
- msleep(2);
- drv_stat = ata_busy_wait(ap, ATA_BUSY, 10);
- if (drv_stat & ATA_BUSY) {
- ap->hsm_task_state = HSM_ST_LAST_POLL;
- ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO;
- return 0;
- }
- }
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
- WARN_ON(qc == NULL);
-
- drv_stat = ata_wait_idle(ap);
- if (!ata_ok(drv_stat)) {
- qc->err_mask |= __ac_err_mask(drv_stat);
- ap->hsm_task_state = HSM_ST_ERR;
- return 0;
- }
-
- ap->hsm_task_state = HSM_ST_IDLE;
-
- WARN_ON(qc->err_mask);
- ata_poll_qc_complete(qc);
-
- /* another command may start at this point */
-
- return 1;
-}
-
-
-/**
* swap_buf_le16 - swap halves of 16-bit words in place
* @buf: Buffer to swap
* @buf_words: Number of 16-bit words in buffer.
@@ -3291,7 +3516,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
/**
* ata_mmio_data_xfer - Transfer data by MMIO
- * @ap: port to read/write
+ * @adev: device for this I/O
* @buf: data buffer
* @buflen: buffer length
* @write_data: read/write
@@ -3302,9 +3527,10 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
* Inherited from caller.
*/
-static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf,
- unsigned int buflen, int write_data)
+void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
+ unsigned int buflen, int write_data)
{
+ struct ata_port *ap = adev->ap;
unsigned int i;
unsigned int words = buflen >> 1;
u16 *buf16 = (u16 *) buf;
@@ -3336,7 +3562,7 @@ static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf,
/**
* ata_pio_data_xfer - Transfer data by PIO
- * @ap: port to read/write
+ * @adev: device to target
* @buf: data buffer
* @buflen: buffer length
* @write_data: read/write
@@ -3347,9 +3573,10 @@ static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf,
* Inherited from caller.
*/
-static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf,
- unsigned int buflen, int write_data)
+void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
+ unsigned int buflen, int write_data)
{
+ struct ata_port *ap = adev->ap;
unsigned int words = buflen >> 1;
/* Transfer multiple of 2 bytes */
@@ -3374,38 +3601,29 @@ static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf,
}
/**
- * ata_data_xfer - Transfer data from/to the data register.
- * @ap: port to read/write
+ * ata_pio_data_xfer_noirq - Transfer data by PIO
+ * @adev: device to target
* @buf: data buffer
* @buflen: buffer length
- * @do_write: read/write
+ * @write_data: read/write
*
- * Transfer data from/to the device data register.
+ * Transfer data from/to the device data register by PIO. Do the
+ * transfer with interrupts disabled.
*
* LOCKING:
* Inherited from caller.
*/
-static void ata_data_xfer(struct ata_port *ap, unsigned char *buf,
- unsigned int buflen, int do_write)
+void ata_pio_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
+ unsigned int buflen, int write_data)
{
- /* Make the crap hardware pay the costs not the good stuff */
- if (unlikely(ap->flags & ATA_FLAG_IRQ_MASK)) {
- unsigned long flags;
- local_irq_save(flags);
- if (ap->flags & ATA_FLAG_MMIO)
- ata_mmio_data_xfer(ap, buf, buflen, do_write);
- else
- ata_pio_data_xfer(ap, buf, buflen, do_write);
- local_irq_restore(flags);
- } else {
- if (ap->flags & ATA_FLAG_MMIO)
- ata_mmio_data_xfer(ap, buf, buflen, do_write);
- else
- ata_pio_data_xfer(ap, buf, buflen, do_write);
- }
+ unsigned long flags;
+ local_irq_save(flags);
+ ata_pio_data_xfer(adev, buf, buflen, write_data);
+ local_irq_restore(flags);
}
+
/**
* ata_pio_sector - Transfer ATA_SECT_SIZE (512 bytes) of data.
* @qc: Command on going
@@ -3435,7 +3653,24 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
page = nth_page(page, (offset >> PAGE_SHIFT));
offset %= PAGE_SIZE;
- buf = kmap(page) + offset;
+ DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
+
+ if (PageHighMem(page)) {
+ unsigned long flags;
+
+ /* FIXME: use a bounce buffer */
+ local_irq_save(flags);
+ buf = kmap_atomic(page, KM_IRQ0);
+
+ /* do the actual data transfer */
+ ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);
+
+ kunmap_atomic(buf, KM_IRQ0);
+ local_irq_restore(flags);
+ } else {
+ buf = page_address(page);
+ ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);
+ }
qc->cursect++;
qc->cursg_ofs++;
@@ -3444,14 +3679,68 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
qc->cursg++;
qc->cursg_ofs = 0;
}
+}
- DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
+/**
+ * ata_pio_sectors - Transfer one or many 512-byte sectors.
+ * @qc: Command on going
+ *
+ * Transfer one or many ATA_SECT_SIZE of data from/to the
+ * ATA device for the DRQ request.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+static void ata_pio_sectors(struct ata_queued_cmd *qc)
+{
+ if (is_multi_taskfile(&qc->tf)) {
+ /* READ/WRITE MULTIPLE */
+ unsigned int nsect;
- /* do the actual data transfer */
- do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
- ata_data_xfer(ap, buf, ATA_SECT_SIZE, do_write);
+ WARN_ON(qc->dev->multi_count == 0);
- kunmap(page);
+ nsect = min(qc->nsect - qc->cursect, qc->dev->multi_count);
+ while (nsect--)
+ ata_pio_sector(qc);
+ } else
+ ata_pio_sector(qc);
+}
+
+/**
+ * atapi_send_cdb - Write CDB bytes to hardware
+ * @ap: Port to which ATAPI device is attached.
+ * @qc: Taskfile currently active
+ *
+ * When device has indicated its readiness to accept
+ * a CDB, this function is called. Send the CDB.
+ *
+ * LOCKING:
+ * caller.
+ */
+
+static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
+{
+ /* send SCSI cdb */
+ DPRINTK("send cdb\n");
+ WARN_ON(qc->dev->cdb_len < 12);
+
+ ap->ops->data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1);
+ ata_altstatus(ap); /* flush */
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_ATAPI:
+ ap->hsm_task_state = HSM_ST;
+ break;
+ case ATA_PROT_ATAPI_NODATA:
+ ap->hsm_task_state = HSM_ST_LAST;
+ break;
+ case ATA_PROT_ATAPI_DMA:
+ ap->hsm_task_state = HSM_ST_LAST;
+ /* initiate bmdma */
+ ap->ops->bmdma_start(qc);
+ break;
+ }
}
/**
@@ -3492,11 +3781,11 @@ next_sg:
unsigned int i;
if (words) /* warning if bytes > 1 */
- printk(KERN_WARNING "ata%u: %u bytes trailing data\n",
- ap->id, bytes);
+ ata_dev_printk(qc->dev, KERN_WARNING,
+ "%u bytes trailing data\n", bytes);
for (i = 0; i < words; i++)
- ata_data_xfer(ap, (unsigned char*)pad_buf, 2, do_write);
+ ap->ops->data_xfer(qc->dev, (unsigned char*)pad_buf, 2, do_write);
ap->hsm_task_state = HSM_ST_LAST;
return;
@@ -3517,7 +3806,24 @@ next_sg:
/* don't cross page boundaries */
count = min(count, (unsigned int)PAGE_SIZE - offset);
- buf = kmap(page) + offset;
+ DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
+
+ if (PageHighMem(page)) {
+ unsigned long flags;
+
+ /* FIXME: use bounce buffer */
+ local_irq_save(flags);
+ buf = kmap_atomic(page, KM_IRQ0);
+
+ /* do the actual data transfer */
+ ap->ops->data_xfer(qc->dev, buf + offset, count, do_write);
+
+ kunmap_atomic(buf, KM_IRQ0);
+ local_irq_restore(flags);
+ } else {
+ buf = page_address(page);
+ ap->ops->data_xfer(qc->dev, buf + offset, count, do_write);
+ }
bytes -= count;
qc->curbytes += count;
@@ -3528,13 +3834,6 @@ next_sg:
qc->cursg_ofs = 0;
}
- DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
-
- /* do the actual data transfer */
- ata_data_xfer(ap, buf, count, do_write);
-
- kunmap(page);
-
if (bytes)
goto next_sg;
}
@@ -3556,10 +3855,16 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
unsigned int ireason, bc_lo, bc_hi, bytes;
int i_write, do_write = (qc->tf.flags & ATA_TFLAG_WRITE) ? 1 : 0;
- ap->ops->tf_read(ap, &qc->tf);
- ireason = qc->tf.nsect;
- bc_lo = qc->tf.lbam;
- bc_hi = qc->tf.lbah;
+ /* Abuse qc->result_tf for temp storage of intermediate TF
+ * here to save some kernel stack usage.
+ * For normal completion, qc->result_tf is not relevant. For
+ * error, qc->result_tf is later overwritten by ata_qc_complete().
+ * So, the correctness of qc->result_tf is not affected.
+ */
+ ap->ops->tf_read(ap, &qc->result_tf);
+ ireason = qc->result_tf.nsect;
+ bc_lo = qc->result_tf.lbam;
+ bc_hi = qc->result_tf.lbah;
bytes = (bc_hi << 8) | bc_lo;
/* shall be cleared to zero, indicating xfer of data */
@@ -3571,307 +3876,365 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
if (do_write != i_write)
goto err_out;
+ VPRINTK("ata%u: xfering %d bytes\n", ap->id, bytes);
+
__atapi_pio_bytes(qc, bytes);
return;
err_out:
- printk(KERN_INFO "ata%u: dev %u: ATAPI check failed\n",
- ap->id, dev->devno);
+ ata_dev_printk(dev, KERN_INFO, "ATAPI check failed\n");
qc->err_mask |= AC_ERR_HSM;
ap->hsm_task_state = HSM_ST_ERR;
}
/**
- * ata_pio_block - start PIO on a block
+ * ata_hsm_ok_in_wq - Check if the qc can be handled in the workqueue.
* @ap: the target ata_port
+ * @qc: qc on going
*
- * LOCKING:
- * None. (executing in kernel thread context)
+ * RETURNS:
+ * 1 if ok in workqueue, 0 otherwise.
*/
-static void ata_pio_block(struct ata_port *ap)
+static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *qc)
{
- struct ata_queued_cmd *qc;
- u8 status;
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ return 1;
- /*
- * This is purely heuristic. This is a fast path.
- * Sometimes when we enter, BSY will be cleared in
- * a chk-status or two. If not, the drive is probably seeking
- * or something. Snooze for a couple msecs, then
- * chk-status again. If still busy, fall back to
- * HSM_ST_POLL state.
- */
- status = ata_busy_wait(ap, ATA_BUSY, 5);
- if (status & ATA_BUSY) {
- msleep(2);
- status = ata_busy_wait(ap, ATA_BUSY, 10);
- if (status & ATA_BUSY) {
- ap->hsm_task_state = HSM_ST_POLL;
- ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO;
- return;
- }
+ if (ap->hsm_task_state == HSM_ST_FIRST) {
+ if (qc->tf.protocol == ATA_PROT_PIO &&
+ (qc->tf.flags & ATA_TFLAG_WRITE))
+ return 1;
+
+ if (is_atapi_taskfile(&qc->tf) &&
+ !(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+ return 1;
}
- qc = ata_qc_from_tag(ap, ap->active_tag);
- WARN_ON(qc == NULL);
+ return 0;
+}
- /* check error */
- if (status & (ATA_ERR | ATA_DF)) {
- qc->err_mask |= AC_ERR_DEV;
- ap->hsm_task_state = HSM_ST_ERR;
- return;
- }
+/**
+ * ata_hsm_qc_complete - finish a qc running on standard HSM
+ * @qc: Command to complete
+ * @in_wq: 1 if called from workqueue, 0 otherwise
+ *
+ * Finish @qc which is running on standard HSM.
+ *
+ * LOCKING:
+ * If @in_wq is zero, spin_lock_irqsave(host_set lock).
+ * Otherwise, none on entry and grabs host lock.
+ */
+static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
+{
+ struct ata_port *ap = qc->ap;
+ unsigned long flags;
- /* transfer data if any */
- if (is_atapi_taskfile(&qc->tf)) {
- /* DRQ=0 means no more data to transfer */
- if ((status & ATA_DRQ) == 0) {
- ap->hsm_task_state = HSM_ST_LAST;
- return;
- }
+ if (ap->ops->error_handler) {
+ if (in_wq) {
+ spin_lock_irqsave(ap->lock, flags);
- atapi_pio_bytes(qc);
- } else {
- /* handle BSY=0, DRQ=0 as error */
- if ((status & ATA_DRQ) == 0) {
- qc->err_mask |= AC_ERR_HSM;
- ap->hsm_task_state = HSM_ST_ERR;
- return;
- }
+ /* EH might have kicked in while host_set lock
+ * is released.
+ */
+ qc = ata_qc_from_tag(ap, qc->tag);
+ if (qc) {
+ if (likely(!(qc->err_mask & AC_ERR_HSM))) {
+ ata_irq_on(ap);
+ ata_qc_complete(qc);
+ } else
+ ata_port_freeze(ap);
+ }
- ata_pio_sector(qc);
+ spin_unlock_irqrestore(ap->lock, flags);
+ } else {
+ if (likely(!(qc->err_mask & AC_ERR_HSM)))
+ ata_qc_complete(qc);
+ else
+ ata_port_freeze(ap);
+ }
+ } else {
+ if (in_wq) {
+ spin_lock_irqsave(ap->lock, flags);
+ ata_irq_on(ap);
+ ata_qc_complete(qc);
+ spin_unlock_irqrestore(ap->lock, flags);
+ } else
+ ata_qc_complete(qc);
}
ata_altstatus(ap); /* flush */
}
-static void ata_pio_error(struct ata_port *ap)
+/**
+ * ata_hsm_move - move the HSM to the next state.
+ * @ap: the target ata_port
+ * @qc: qc on going
+ * @status: current device status
+ * @in_wq: 1 if called from workqueue, 0 otherwise
+ *
+ * RETURNS:
+ * 1 when poll next status needed, 0 otherwise.
+ */
+int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
+ u8 status, int in_wq)
{
- struct ata_queued_cmd *qc;
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
- WARN_ON(qc == NULL);
+ unsigned long flags = 0;
+ int poll_next;
- if (qc->tf.command != ATA_CMD_PACKET)
- printk(KERN_WARNING "ata%u: PIO error\n", ap->id);
+ WARN_ON((qc->flags & ATA_QCFLAG_ACTIVE) == 0);
- /* make sure qc->err_mask is available to
- * know what's wrong and recover
+ /* Make sure ata_qc_issue_prot() does not throw things
+ * like DMA polling into the workqueue. Notice that
+ * in_wq is not equivalent to (qc->tf.flags & ATA_TFLAG_POLLING).
*/
- WARN_ON(qc->err_mask == 0);
-
- ap->hsm_task_state = HSM_ST_IDLE;
-
- ata_poll_qc_complete(qc);
-}
-
-static void ata_pio_task(void *_data)
-{
- struct ata_port *ap = _data;
- unsigned long timeout;
- int qc_completed;
+ WARN_ON(in_wq != ata_hsm_ok_in_wq(ap, qc));
fsm_start:
- timeout = 0;
- qc_completed = 0;
+ DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n",
+ ap->id, qc->tf.protocol, ap->hsm_task_state, status);
switch (ap->hsm_task_state) {
- case HSM_ST_IDLE:
- return;
+ case HSM_ST_FIRST:
+ /* Send first data block or PACKET CDB */
- case HSM_ST:
- ata_pio_block(ap);
- break;
-
- case HSM_ST_LAST:
- qc_completed = ata_pio_complete(ap);
- break;
-
- case HSM_ST_POLL:
- case HSM_ST_LAST_POLL:
- timeout = ata_pio_poll(ap);
- break;
-
- case HSM_ST_TMOUT:
- case HSM_ST_ERR:
- ata_pio_error(ap);
- return;
- }
-
- if (timeout)
- ata_port_queue_task(ap, ata_pio_task, ap, timeout);
- else if (!qc_completed)
- goto fsm_start;
-}
-
-/**
- * atapi_packet_task - Write CDB bytes to hardware
- * @_data: Port to which ATAPI device is attached.
- *
- * When device has indicated its readiness to accept
- * a CDB, this function is called. Send the CDB.
- * If DMA is to be performed, exit immediately.
- * Otherwise, we are in polling mode, so poll
- * status under operation succeeds or fails.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- */
-
-static void atapi_packet_task(void *_data)
-{
- struct ata_port *ap = _data;
- struct ata_queued_cmd *qc;
- u8 status;
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
- WARN_ON(qc == NULL);
- WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
+ /* If polling, we will stay in the work queue after
+ * sending the data. Otherwise, interrupt handler
+ * takes over after sending the data.
+ */
+ poll_next = (qc->tf.flags & ATA_TFLAG_POLLING);
+
+ /* check device status */
+ if (unlikely((status & ATA_DRQ) == 0)) {
+ /* handle BSY=0, DRQ=0 as error */
+ if (likely(status & (ATA_ERR | ATA_DF)))
+ /* device stops HSM for abort/error */
+ qc->err_mask |= AC_ERR_DEV;
+ else
+ /* HSM violation. Let EH handle this */
+ qc->err_mask |= AC_ERR_HSM;
- /* sleep-wait for BSY to clear */
- DPRINTK("busy wait\n");
- if (ata_busy_sleep(ap, ATA_TMOUT_CDB_QUICK, ATA_TMOUT_CDB)) {
- qc->err_mask |= AC_ERR_TIMEOUT;
- goto err_out;
- }
+ ap->hsm_task_state = HSM_ST_ERR;
+ goto fsm_start;
+ }
- /* make sure DRQ is set */
- status = ata_chk_status(ap);
- if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) {
- qc->err_mask |= AC_ERR_HSM;
- goto err_out;
- }
+ /* Device should not ask for data transfer (DRQ=1)
+ * when it finds something wrong.
+ * We ignore DRQ here and stop the HSM by
+ * changing hsm_task_state to HSM_ST_ERR and
+ * let the EH abort the command or reset the device.
+ */
+ if (unlikely(status & (ATA_ERR | ATA_DF))) {
+ printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n",
+ ap->id, status);
+ qc->err_mask |= AC_ERR_HSM;
+ ap->hsm_task_state = HSM_ST_ERR;
+ goto fsm_start;
+ }
- /* send SCSI cdb */
- DPRINTK("send cdb\n");
- WARN_ON(qc->dev->cdb_len < 12);
+ /* Send the CDB (atapi) or the first data block (ata pio out).
+ * During the state transition, interrupt handler shouldn't
+ * be invoked before the data transfer is complete and
+ * hsm_task_state is changed. Hence, the following locking.
+ */
+ if (in_wq)
+ spin_lock_irqsave(ap->lock, flags);
- if (qc->tf.protocol == ATA_PROT_ATAPI_DMA ||
- qc->tf.protocol == ATA_PROT_ATAPI_NODATA) {
- unsigned long flags;
+ if (qc->tf.protocol == ATA_PROT_PIO) {
+ /* PIO data out protocol.
+ * send first data block.
+ */
- /* Once we're done issuing command and kicking bmdma,
- * irq handler takes over. To not lose irq, we need
- * to clear NOINTR flag before sending cdb, but
- * interrupt handler shouldn't be invoked before we're
- * finished. Hence, the following locking.
+ /* ata_pio_sectors() might change the state
+ * to HSM_ST_LAST. so, the state is changed here
+ * before ata_pio_sectors().
+ */
+ ap->hsm_task_state = HSM_ST;
+ ata_pio_sectors(qc);
+ ata_altstatus(ap); /* flush */
+ } else
+ /* send CDB */
+ atapi_send_cdb(ap, qc);
+
+ if (in_wq)
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* if polling, ata_pio_task() handles the rest.
+ * otherwise, interrupt handler takes over from here.
*/
- spin_lock_irqsave(&ap->host_set->lock, flags);
- ap->flags &= ~ATA_FLAG_NOINTR;
- ata_data_xfer(ap, qc->cdb, qc->dev->cdb_len, 1);
- ata_altstatus(ap); /* flush */
+ break;
- if (qc->tf.protocol == ATA_PROT_ATAPI_DMA)
- ap->ops->bmdma_start(qc); /* initiate bmdma */
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
- } else {
- ata_data_xfer(ap, qc->cdb, qc->dev->cdb_len, 1);
- ata_altstatus(ap); /* flush */
+ case HSM_ST:
+ /* complete command or read/write the data register */
+ if (qc->tf.protocol == ATA_PROT_ATAPI) {
+ /* ATAPI PIO protocol */
+ if ((status & ATA_DRQ) == 0) {
+ /* No more data to transfer or device error.
+ * Device error will be tagged in HSM_ST_LAST.
+ */
+ ap->hsm_task_state = HSM_ST_LAST;
+ goto fsm_start;
+ }
- /* PIO commands are handled by polling */
- ap->hsm_task_state = HSM_ST;
- ata_port_queue_task(ap, ata_pio_task, ap, 0);
- }
+ /* Device should not ask for data transfer (DRQ=1)
+ * when it finds something wrong.
+ * We ignore DRQ here and stop the HSM by
+ * changing hsm_task_state to HSM_ST_ERR and
+ * let the EH abort the command or reset the device.
+ */
+ if (unlikely(status & (ATA_ERR | ATA_DF))) {
+ printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n",
+ ap->id, status);
+ qc->err_mask |= AC_ERR_HSM;
+ ap->hsm_task_state = HSM_ST_ERR;
+ goto fsm_start;
+ }
- return;
+ atapi_pio_bytes(qc);
-err_out:
- ata_poll_qc_complete(qc);
-}
+ if (unlikely(ap->hsm_task_state == HSM_ST_ERR))
+ /* bad ireason reported by device */
+ goto fsm_start;
-/**
- * ata_qc_timeout - Handle timeout of queued command
- * @qc: Command that timed out
- *
- * Some part of the kernel (currently, only the SCSI layer)
- * has noticed that the active command on port @ap has not
- * completed after a specified length of time. Handle this
- * condition by disabling DMA (if necessary) and completing
- * transactions, with error if necessary.
- *
- * This also handles the case of the "lost interrupt", where
- * for some reason (possibly hardware bug, possibly driver bug)
- * an interrupt was not delivered to the driver, even though the
- * transaction completed successfully.
- *
- * LOCKING:
- * Inherited from SCSI layer (none, can sleep)
- */
+ } else {
+ /* ATA PIO protocol */
+ if (unlikely((status & ATA_DRQ) == 0)) {
+ /* handle BSY=0, DRQ=0 as error */
+ if (likely(status & (ATA_ERR | ATA_DF)))
+ /* device stops HSM for abort/error */
+ qc->err_mask |= AC_ERR_DEV;
+ else
+ /* HSM violation. Let EH handle this */
+ qc->err_mask |= AC_ERR_HSM;
+
+ ap->hsm_task_state = HSM_ST_ERR;
+ goto fsm_start;
+ }
-static void ata_qc_timeout(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct ata_host_set *host_set = ap->host_set;
- u8 host_stat = 0, drv_stat;
- unsigned long flags;
+ /* For PIO reads, some devices may ask for
+ * data transfer (DRQ=1) alone with ERR=1.
+ * We respect DRQ here and transfer one
+ * block of junk data before changing the
+ * hsm_task_state to HSM_ST_ERR.
+ *
+ * For PIO writes, ERR=1 DRQ=1 doesn't make
+ * sense since the data block has been
+ * transferred to the device.
+ */
+ if (unlikely(status & (ATA_ERR | ATA_DF))) {
+ /* data might be corrputed */
+ qc->err_mask |= AC_ERR_DEV;
+
+ if (!(qc->tf.flags & ATA_TFLAG_WRITE)) {
+ ata_pio_sectors(qc);
+ ata_altstatus(ap);
+ status = ata_wait_idle(ap);
+ }
+
+ if (status & (ATA_BUSY | ATA_DRQ))
+ qc->err_mask |= AC_ERR_HSM;
+
+ /* ata_pio_sectors() might change the
+ * state to HSM_ST_LAST. so, the state
+ * is changed after ata_pio_sectors().
+ */
+ ap->hsm_task_state = HSM_ST_ERR;
+ goto fsm_start;
+ }
- DPRINTK("ENTER\n");
+ ata_pio_sectors(qc);
- ap->hsm_task_state = HSM_ST_IDLE;
+ if (ap->hsm_task_state == HSM_ST_LAST &&
+ (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
+ /* all data read */
+ ata_altstatus(ap);
+ status = ata_wait_idle(ap);
+ goto fsm_start;
+ }
+ }
- spin_lock_irqsave(&host_set->lock, flags);
+ ata_altstatus(ap); /* flush */
+ poll_next = 1;
+ break;
- switch (qc->tf.protocol) {
+ case HSM_ST_LAST:
+ if (unlikely(!ata_ok(status))) {
+ qc->err_mask |= __ac_err_mask(status);
+ ap->hsm_task_state = HSM_ST_ERR;
+ goto fsm_start;
+ }
- case ATA_PROT_DMA:
- case ATA_PROT_ATAPI_DMA:
- host_stat = ap->ops->bmdma_status(ap);
+ /* no more data to transfer */
+ DPRINTK("ata%u: dev %u command complete, drv_stat 0x%x\n",
+ ap->id, qc->dev->devno, status);
- /* before we do anything else, clear DMA-Start bit */
- ap->ops->bmdma_stop(qc);
+ WARN_ON(qc->err_mask);
- /* fall through */
+ ap->hsm_task_state = HSM_ST_IDLE;
- default:
- ata_altstatus(ap);
- drv_stat = ata_chk_status(ap);
+ /* complete taskfile transaction */
+ ata_hsm_qc_complete(qc, in_wq);
+
+ poll_next = 0;
+ break;
- /* ack bmdma irq events */
- ap->ops->irq_clear(ap);
+ case HSM_ST_ERR:
+ /* make sure qc->err_mask is available to
+ * know what's wrong and recover
+ */
+ WARN_ON(qc->err_mask == 0);
- printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n",
- ap->id, qc->tf.command, drv_stat, host_stat);
+ ap->hsm_task_state = HSM_ST_IDLE;
/* complete taskfile transaction */
- qc->err_mask |= ac_err_mask(drv_stat);
+ ata_hsm_qc_complete(qc, in_wq);
+
+ poll_next = 0;
break;
+ default:
+ poll_next = 0;
+ BUG();
}
- spin_unlock_irqrestore(&host_set->lock, flags);
-
- ata_eh_qc_complete(qc);
-
- DPRINTK("EXIT\n");
+ return poll_next;
}
-/**
- * ata_eng_timeout - Handle timeout of queued command
- * @ap: Port on which timed-out command is active
- *
- * Some part of the kernel (currently, only the SCSI layer)
- * has noticed that the active command on port @ap has not
- * completed after a specified length of time. Handle this
- * condition by disabling DMA (if necessary) and completing
- * transactions, with error if necessary.
- *
- * This also handles the case of the "lost interrupt", where
- * for some reason (possibly hardware bug, possibly driver bug)
- * an interrupt was not delivered to the driver, even though the
- * transaction completed successfully.
- *
- * LOCKING:
- * Inherited from SCSI layer (none, can sleep)
- */
-
-void ata_eng_timeout(struct ata_port *ap)
+static void ata_pio_task(void *_data)
{
- DPRINTK("ENTER\n");
+ struct ata_queued_cmd *qc = _data;
+ struct ata_port *ap = qc->ap;
+ u8 status;
+ int poll_next;
- ata_qc_timeout(ata_qc_from_tag(ap, ap->active_tag));
+fsm_start:
+ WARN_ON(ap->hsm_task_state == HSM_ST_IDLE);
- DPRINTK("EXIT\n");
+ /*
+ * This is purely heuristic. This is a fast path.
+ * Sometimes when we enter, BSY will be cleared in
+ * a chk-status or two. If not, the drive is probably seeking
+ * or something. Snooze for a couple msecs, then
+ * chk-status again. If still busy, queue delayed work.
+ */
+ status = ata_busy_wait(ap, ATA_BUSY, 5);
+ if (status & ATA_BUSY) {
+ msleep(2);
+ status = ata_busy_wait(ap, ATA_BUSY, 10);
+ if (status & ATA_BUSY) {
+ ata_port_queue_task(ap, ata_pio_task, qc, ATA_SHORT_PAUSE);
+ return;
+ }
+ }
+
+ /* move the HSM */
+ poll_next = ata_hsm_move(ap, qc, status, 1);
+
+ /* another command or interrupt handler
+ * may be running at this point.
+ */
+ if (poll_next)
+ goto fsm_start;
}
/**
@@ -3888,9 +4251,14 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
struct ata_queued_cmd *qc = NULL;
unsigned int i;
- for (i = 0; i < ATA_MAX_QUEUE; i++)
- if (!test_and_set_bit(i, &ap->qactive)) {
- qc = ata_qc_from_tag(ap, i);
+ /* no command while frozen */
+ if (unlikely(ap->flags & ATA_FLAG_FROZEN))
+ return NULL;
+
+ /* the last tag is reserved for internal command. */
+ for (i = 0; i < ATA_MAX_QUEUE - 1; i++)
+ if (!test_and_set_bit(i, &ap->qc_allocated)) {
+ qc = __ata_qc_from_tag(ap, i);
break;
}
@@ -3902,16 +4270,15 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
/**
* ata_qc_new_init - Request an available ATA command, and initialize it
- * @ap: Port associated with device @dev
* @dev: Device from whom we request an available command structure
*
* LOCKING:
* None.
*/
-struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
- struct ata_device *dev)
+struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev)
{
+ struct ata_port *ap = dev->ap;
struct ata_queued_cmd *qc;
qc = ata_qc_new(ap);
@@ -3946,36 +4313,153 @@ void ata_qc_free(struct ata_queued_cmd *qc)
qc->flags = 0;
tag = qc->tag;
if (likely(ata_tag_valid(tag))) {
- if (tag == ap->active_tag)
- ap->active_tag = ATA_TAG_POISON;
qc->tag = ATA_TAG_POISON;
- clear_bit(tag, &ap->qactive);
+ clear_bit(tag, &ap->qc_allocated);
}
}
void __ata_qc_complete(struct ata_queued_cmd *qc)
{
+ struct ata_port *ap = qc->ap;
+
WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
if (likely(qc->flags & ATA_QCFLAG_DMAMAP))
ata_sg_clean(qc);
+ /* command should be marked inactive atomically with qc completion */
+ if (qc->tf.protocol == ATA_PROT_NCQ)
+ ap->sactive &= ~(1 << qc->tag);
+ else
+ ap->active_tag = ATA_TAG_POISON;
+
/* atapi: mark qc as inactive to prevent the interrupt handler
* from completing the command twice later, before the error handler
* is called. (when rc != 0 and atapi request sense is needed)
*/
qc->flags &= ~ATA_QCFLAG_ACTIVE;
+ ap->qc_active &= ~(1 << qc->tag);
/* call completion callback */
qc->complete_fn(qc);
}
+/**
+ * ata_qc_complete - Complete an active ATA command
+ * @qc: Command to complete
+ * @err_mask: ATA Status register contents
+ *
+ * Indicate to the mid and upper layers that an ATA
+ * command has completed, with either an ok or not-ok status.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host_set lock)
+ */
+void ata_qc_complete(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ /* XXX: New EH and old EH use different mechanisms to
+ * synchronize EH with regular execution path.
+ *
+ * In new EH, a failed qc is marked with ATA_QCFLAG_FAILED.
+ * Normal execution path is responsible for not accessing a
+ * failed qc. libata core enforces the rule by returning NULL
+ * from ata_qc_from_tag() for failed qcs.
+ *
+ * Old EH depends on ata_qc_complete() nullifying completion
+ * requests if ATA_QCFLAG_EH_SCHEDULED is set. Old EH does
+ * not synchronize with interrupt handler. Only PIO task is
+ * taken care of.
+ */
+ if (ap->ops->error_handler) {
+ WARN_ON(ap->flags & ATA_FLAG_FROZEN);
+
+ if (unlikely(qc->err_mask))
+ qc->flags |= ATA_QCFLAG_FAILED;
+
+ if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) {
+ if (!ata_tag_internal(qc->tag)) {
+ /* always fill result TF for failed qc */
+ ap->ops->tf_read(ap, &qc->result_tf);
+ ata_qc_schedule_eh(qc);
+ return;
+ }
+ }
+
+ /* read result TF if requested */
+ if (qc->flags & ATA_QCFLAG_RESULT_TF)
+ ap->ops->tf_read(ap, &qc->result_tf);
+
+ __ata_qc_complete(qc);
+ } else {
+ if (qc->flags & ATA_QCFLAG_EH_SCHEDULED)
+ return;
+
+ /* read result TF if failed or requested */
+ if (qc->err_mask || qc->flags & ATA_QCFLAG_RESULT_TF)
+ ap->ops->tf_read(ap, &qc->result_tf);
+
+ __ata_qc_complete(qc);
+ }
+}
+
+/**
+ * ata_qc_complete_multiple - Complete multiple qcs successfully
+ * @ap: port in question
+ * @qc_active: new qc_active mask
+ * @finish_qc: LLDD callback invoked before completing a qc
+ *
+ * Complete in-flight commands. This functions is meant to be
+ * called from low-level driver's interrupt routine to complete
+ * requests normally. ap->qc_active and @qc_active is compared
+ * and commands are completed accordingly.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host_set lock)
+ *
+ * RETURNS:
+ * Number of completed commands on success, -errno otherwise.
+ */
+int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active,
+ void (*finish_qc)(struct ata_queued_cmd *))
+{
+ int nr_done = 0;
+ u32 done_mask;
+ int i;
+
+ done_mask = ap->qc_active ^ qc_active;
+
+ if (unlikely(done_mask & qc_active)) {
+ ata_port_printk(ap, KERN_ERR, "illegal qc_active transition "
+ "(%08x->%08x)\n", ap->qc_active, qc_active);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ATA_MAX_QUEUE; i++) {
+ struct ata_queued_cmd *qc;
+
+ if (!(done_mask & (1 << i)))
+ continue;
+
+ if ((qc = ata_qc_from_tag(ap, i))) {
+ if (finish_qc)
+ finish_qc(qc);
+ ata_qc_complete(qc);
+ nr_done++;
+ }
+ }
+
+ return nr_done;
+}
+
static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
switch (qc->tf.protocol) {
+ case ATA_PROT_NCQ:
case ATA_PROT_DMA:
case ATA_PROT_ATAPI_DMA:
return 1;
@@ -4010,8 +4494,22 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- qc->ap->active_tag = qc->tag;
+ /* Make sure only one non-NCQ command is outstanding. The
+ * check is skipped for old EH because it reuses active qc to
+ * request ATAPI sense.
+ */
+ WARN_ON(ap->ops->error_handler && ata_tag_valid(ap->active_tag));
+
+ if (qc->tf.protocol == ATA_PROT_NCQ) {
+ WARN_ON(ap->sactive & (1 << qc->tag));
+ ap->sactive |= 1 << qc->tag;
+ } else {
+ WARN_ON(ap->sactive);
+ ap->active_tag = qc->tag;
+ }
+
qc->flags |= ATA_QCFLAG_ACTIVE;
+ ap->qc_active |= 1 << qc->tag;
if (ata_should_dma_map(qc)) {
if (qc->flags & ATA_QCFLAG_SG) {
@@ -4061,43 +4559,105 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
+ /* Use polling pio if the LLD doesn't handle
+ * interrupt driven pio and atapi CDB interrupt.
+ */
+ if (ap->flags & ATA_FLAG_PIO_POLLING) {
+ switch (qc->tf.protocol) {
+ case ATA_PROT_PIO:
+ case ATA_PROT_ATAPI:
+ case ATA_PROT_ATAPI_NODATA:
+ qc->tf.flags |= ATA_TFLAG_POLLING;
+ break;
+ case ATA_PROT_ATAPI_DMA:
+ if (qc->dev->flags & ATA_DFLAG_CDB_INTR)
+ /* see ata_dma_blacklisted() */
+ BUG();
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* select the device */
ata_dev_select(ap, qc->dev->devno, 1, 0);
+ /* start the command */
switch (qc->tf.protocol) {
case ATA_PROT_NODATA:
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
+
ata_tf_to_host(ap, &qc->tf);
+ ap->hsm_task_state = HSM_ST_LAST;
+
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_port_queue_task(ap, ata_pio_task, qc, 0);
+
break;
case ATA_PROT_DMA:
+ WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING);
+
ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
ap->ops->bmdma_setup(qc); /* set up bmdma */
ap->ops->bmdma_start(qc); /* initiate bmdma */
+ ap->hsm_task_state = HSM_ST_LAST;
break;
- case ATA_PROT_PIO: /* load tf registers, initiate polling pio */
- ata_qc_set_polling(qc);
- ata_tf_to_host(ap, &qc->tf);
- ap->hsm_task_state = HSM_ST;
- ata_port_queue_task(ap, ata_pio_task, ap, 0);
- break;
+ case ATA_PROT_PIO:
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
- case ATA_PROT_ATAPI:
- ata_qc_set_polling(qc);
ata_tf_to_host(ap, &qc->tf);
- ata_port_queue_task(ap, atapi_packet_task, ap, 0);
+
+ if (qc->tf.flags & ATA_TFLAG_WRITE) {
+ /* PIO data out protocol */
+ ap->hsm_task_state = HSM_ST_FIRST;
+ ata_port_queue_task(ap, ata_pio_task, qc, 0);
+
+ /* always send first data block using
+ * the ata_pio_task() codepath.
+ */
+ } else {
+ /* PIO data in protocol */
+ ap->hsm_task_state = HSM_ST;
+
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_port_queue_task(ap, ata_pio_task, qc, 0);
+
+ /* if polling, ata_pio_task() handles the rest.
+ * otherwise, interrupt handler takes over from here.
+ */
+ }
+
break;
+ case ATA_PROT_ATAPI:
case ATA_PROT_ATAPI_NODATA:
- ap->flags |= ATA_FLAG_NOINTR;
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
+
ata_tf_to_host(ap, &qc->tf);
- ata_port_queue_task(ap, atapi_packet_task, ap, 0);
+
+ ap->hsm_task_state = HSM_ST_FIRST;
+
+ /* send cdb by polling if no cdb interrupt */
+ if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
+ (qc->tf.flags & ATA_TFLAG_POLLING))
+ ata_port_queue_task(ap, ata_pio_task, qc, 0);
break;
case ATA_PROT_ATAPI_DMA:
- ap->flags |= ATA_FLAG_NOINTR;
+ WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING);
+
ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
ap->ops->bmdma_setup(qc); /* set up bmdma */
- ata_port_queue_task(ap, atapi_packet_task, ap, 0);
+ ap->hsm_task_state = HSM_ST_FIRST;
+
+ /* send cdb by polling if no cdb interrupt */
+ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+ ata_port_queue_task(ap, ata_pio_task, qc, 0);
break;
default:
@@ -4127,52 +4687,66 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
inline unsigned int ata_host_intr (struct ata_port *ap,
struct ata_queued_cmd *qc)
{
- u8 status, host_stat;
-
- switch (qc->tf.protocol) {
-
- case ATA_PROT_DMA:
- case ATA_PROT_ATAPI_DMA:
- case ATA_PROT_ATAPI:
- /* check status of DMA engine */
- host_stat = ap->ops->bmdma_status(ap);
- VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
-
- /* if it's not our irq... */
- if (!(host_stat & ATA_DMA_INTR))
- goto idle_irq;
+ u8 status, host_stat = 0;
- /* before we do anything else, clear DMA-Start bit */
- ap->ops->bmdma_stop(qc);
+ VPRINTK("ata%u: protocol %d task_state %d\n",
+ ap->id, qc->tf.protocol, ap->hsm_task_state);
- /* fall through */
-
- case ATA_PROT_ATAPI_NODATA:
- case ATA_PROT_NODATA:
- /* check altstatus */
- status = ata_altstatus(ap);
- if (status & ATA_BUSY)
- goto idle_irq;
+ /* Check whether we are expecting interrupt in this state */
+ switch (ap->hsm_task_state) {
+ case HSM_ST_FIRST:
+ /* Some pre-ATAPI-4 devices assert INTRQ
+ * at this state when ready to receive CDB.
+ */
- /* check main status, clearing INTRQ */
- status = ata_chk_status(ap);
- if (unlikely(status & ATA_BUSY))
+ /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
+ * The flag was turned on only for atapi devices.
+ * No need to check is_atapi_taskfile(&qc->tf) again.
+ */
+ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
goto idle_irq;
- DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
- ap->id, qc->tf.protocol, status);
-
- /* ack bmdma irq events */
- ap->ops->irq_clear(ap);
-
- /* complete taskfile transaction */
- qc->err_mask |= ac_err_mask(status);
- ata_qc_complete(qc);
break;
-
+ case HSM_ST_LAST:
+ if (qc->tf.protocol == ATA_PROT_DMA ||
+ qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
+ /* check status of DMA engine */
+ host_stat = ap->ops->bmdma_status(ap);
+ VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
+
+ /* if it's not our irq... */
+ if (!(host_stat & ATA_DMA_INTR))
+ goto idle_irq;
+
+ /* before we do anything else, clear DMA-Start bit */
+ ap->ops->bmdma_stop(qc);
+
+ if (unlikely(host_stat & ATA_DMA_ERR)) {
+ /* error when transfering data to/from memory */
+ qc->err_mask |= AC_ERR_HOST_BUS;
+ ap->hsm_task_state = HSM_ST_ERR;
+ }
+ }
+ break;
+ case HSM_ST:
+ break;
default:
goto idle_irq;
}
+ /* check altstatus */
+ status = ata_altstatus(ap);
+ if (status & ATA_BUSY)
+ goto idle_irq;
+
+ /* check main status, clearing INTRQ */
+ status = ata_chk_status(ap);
+ if (unlikely(status & ATA_BUSY))
+ goto idle_irq;
+
+ /* ack bmdma irq events */
+ ap->ops->irq_clear(ap);
+
+ ata_hsm_move(ap, qc, status, 0);
return 1; /* irq handled */
idle_irq:
@@ -4181,7 +4755,7 @@ idle_irq:
#ifdef ATA_IRQ_TRAP
if ((ap->stats.idle_irq % 1000) == 0) {
ata_irq_ack(ap, 0); /* debug trap */
- printk(KERN_WARNING "ata%d: irq trap\n", ap->id);
+ ata_port_printk(ap, KERN_WARNING, "irq trap\n");
return 1;
}
#endif
@@ -4219,11 +4793,11 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
ap = host_set->ports[i];
if (ap &&
- !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
+ !(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN)) &&
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
(qc->flags & ATA_QCFLAG_ACTIVE))
handled |= ata_host_intr(ap, qc);
}
@@ -4234,32 +4808,168 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
return IRQ_RETVAL(handled);
}
+/**
+ * sata_scr_valid - test whether SCRs are accessible
+ * @ap: ATA port to test SCR accessibility for
+ *
+ * Test whether SCRs are accessible for @ap.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * 1 if SCRs are accessible, 0 otherwise.
+ */
+int sata_scr_valid(struct ata_port *ap)
+{
+ return ap->cbl == ATA_CBL_SATA && ap->ops->scr_read;
+}
+
+/**
+ * sata_scr_read - read SCR register of the specified port
+ * @ap: ATA port to read SCR for
+ * @reg: SCR to read
+ * @val: Place to store read value
+ *
+ * Read SCR register @reg of @ap into *@val. This function is
+ * guaranteed to succeed if the cable type of the port is SATA
+ * and the port implements ->scr_read.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * 0 on success, negative errno on failure.
+ */
+int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
+{
+ if (sata_scr_valid(ap)) {
+ *val = ap->ops->scr_read(ap, reg);
+ return 0;
+ }
+ return -EOPNOTSUPP;
+}
+
+/**
+ * sata_scr_write - write SCR register of the specified port
+ * @ap: ATA port to write SCR for
+ * @reg: SCR to write
+ * @val: value to write
+ *
+ * Write @val to SCR register @reg of @ap. This function is
+ * guaranteed to succeed if the cable type of the port is SATA
+ * and the port implements ->scr_read.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * 0 on success, negative errno on failure.
+ */
+int sata_scr_write(struct ata_port *ap, int reg, u32 val)
+{
+ if (sata_scr_valid(ap)) {
+ ap->ops->scr_write(ap, reg, val);
+ return 0;
+ }
+ return -EOPNOTSUPP;
+}
+
+/**
+ * sata_scr_write_flush - write SCR register of the specified port and flush
+ * @ap: ATA port to write SCR for
+ * @reg: SCR to write
+ * @val: value to write
+ *
+ * This function is identical to sata_scr_write() except that this
+ * function performs flush after writing to the register.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * 0 on success, negative errno on failure.
+ */
+int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
+{
+ if (sata_scr_valid(ap)) {
+ ap->ops->scr_write(ap, reg, val);
+ ap->ops->scr_read(ap, reg);
+ return 0;
+ }
+ return -EOPNOTSUPP;
+}
+
+/**
+ * ata_port_online - test whether the given port is online
+ * @ap: ATA port to test
+ *
+ * Test whether @ap is online. Note that this function returns 0
+ * if online status of @ap cannot be obtained, so
+ * ata_port_online(ap) != !ata_port_offline(ap).
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * 1 if the port online status is available and online.
+ */
+int ata_port_online(struct ata_port *ap)
+{
+ u32 sstatus;
+
+ if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) == 0x3)
+ return 1;
+ return 0;
+}
+
+/**
+ * ata_port_offline - test whether the given port is offline
+ * @ap: ATA port to test
+ *
+ * Test whether @ap is offline. Note that this function returns
+ * 0 if offline status of @ap cannot be obtained, so
+ * ata_port_online(ap) != !ata_port_offline(ap).
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * 1 if the port offline status is available and offline.
+ */
+int ata_port_offline(struct ata_port *ap)
+{
+ u32 sstatus;
+
+ if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) != 0x3)
+ return 1;
+ return 0;
+}
/*
* Execute a 'simple' command, that only consists of the opcode 'cmd' itself,
* without filling any other registers
*/
-static int ata_do_simple_cmd(struct ata_port *ap, struct ata_device *dev,
- u8 cmd)
+static int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
{
struct ata_taskfile tf;
int err;
- ata_tf_init(ap, &tf, dev->devno);
+ ata_tf_init(dev, &tf);
tf.command = cmd;
tf.flags |= ATA_TFLAG_DEVICE;
tf.protocol = ATA_PROT_NODATA;
- err = ata_exec_internal(ap, dev, &tf, DMA_NONE, NULL, 0);
+ err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
if (err)
- printk(KERN_ERR "%s: ata command failed: %d\n",
- __FUNCTION__, err);
+ ata_dev_printk(dev, KERN_ERR, "%s: ata command failed: %d\n",
+ __FUNCTION__, err);
return err;
}
-static int ata_flush_cache(struct ata_port *ap, struct ata_device *dev)
+static int ata_flush_cache(struct ata_device *dev)
{
u8 cmd;
@@ -4271,22 +4981,21 @@ static int ata_flush_cache(struct ata_port *ap, struct ata_device *dev)
else
cmd = ATA_CMD_FLUSH;
- return ata_do_simple_cmd(ap, dev, cmd);
+ return ata_do_simple_cmd(dev, cmd);
}
-static int ata_standby_drive(struct ata_port *ap, struct ata_device *dev)
+static int ata_standby_drive(struct ata_device *dev)
{
- return ata_do_simple_cmd(ap, dev, ATA_CMD_STANDBYNOW1);
+ return ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
}
-static int ata_start_drive(struct ata_port *ap, struct ata_device *dev)
+static int ata_start_drive(struct ata_device *dev)
{
- return ata_do_simple_cmd(ap, dev, ATA_CMD_IDLEIMMEDIATE);
+ return ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE);
}
/**
* ata_device_resume - wakeup a previously suspended devices
- * @ap: port the device is connected to
* @dev: the device to resume
*
* Kick the drive back into action, by sending it an idle immediate
@@ -4294,40 +5003,47 @@ static int ata_start_drive(struct ata_port *ap, struct ata_device *dev)
* and host.
*
*/
-int ata_device_resume(struct ata_port *ap, struct ata_device *dev)
+int ata_device_resume(struct ata_device *dev)
{
+ struct ata_port *ap = dev->ap;
+
if (ap->flags & ATA_FLAG_SUSPENDED) {
+ struct ata_device *failed_dev;
+
ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 200000);
+
ap->flags &= ~ATA_FLAG_SUSPENDED;
- ata_set_mode(ap);
+ while (ata_set_mode(ap, &failed_dev))
+ ata_dev_disable(failed_dev);
}
- if (!ata_dev_present(dev))
+ if (!ata_dev_enabled(dev))
return 0;
if (dev->class == ATA_DEV_ATA)
- ata_start_drive(ap, dev);
+ ata_start_drive(dev);
return 0;
}
/**
* ata_device_suspend - prepare a device for suspend
- * @ap: port the device is connected to
* @dev: the device to suspend
* @state: target power management state
*
* Flush the cache on the drive, if appropriate, then issue a
* standbynow command.
*/
-int ata_device_suspend(struct ata_port *ap, struct ata_device *dev, pm_message_t state)
+int ata_device_suspend(struct ata_device *dev, pm_message_t state)
{
- if (!ata_dev_present(dev))
+ struct ata_port *ap = dev->ap;
+
+ if (!ata_dev_enabled(dev))
return 0;
if (dev->class == ATA_DEV_ATA)
- ata_flush_cache(ap, dev);
+ ata_flush_cache(dev);
if (state.event != PM_EVENT_FREEZE)
- ata_standby_drive(ap, dev);
+ ata_standby_drive(dev);
ap->flags |= ATA_FLAG_SUSPENDED;
return 0;
}
@@ -4415,6 +5131,38 @@ static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister)
}
/**
+ * ata_dev_init - Initialize an ata_device structure
+ * @dev: Device structure to initialize
+ *
+ * Initialize @dev in preparation for probing.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+void ata_dev_init(struct ata_device *dev)
+{
+ struct ata_port *ap = dev->ap;
+ unsigned long flags;
+
+ /* SATA spd limit is bound to the first device */
+ ap->sata_spd_limit = ap->hw_sata_spd_limit;
+
+ /* High bits of dev->flags are used to record warm plug
+ * requests which occur asynchronously. Synchronize using
+ * host_set lock.
+ */
+ spin_lock_irqsave(ap->lock, flags);
+ dev->flags &= ~ATA_DFLAG_INIT_MASK;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ memset((void *)dev + ATA_DEVICE_CLEAR_OFFSET, 0,
+ sizeof(*dev) - ATA_DEVICE_CLEAR_OFFSET);
+ dev->pio_mask = UINT_MAX;
+ dev->mwdma_mask = UINT_MAX;
+ dev->udma_mask = UINT_MAX;
+}
+
+/**
* ata_host_init - Initialize an ata_port structure
* @ap: Structure to initialize
* @host: associated SCSI mid-layer structure
@@ -4428,7 +5176,6 @@ static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister)
* LOCKING:
* Inherited from caller.
*/
-
static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
struct ata_host_set *host_set,
const struct ata_probe_ent *ent, unsigned int port_no)
@@ -4441,7 +5188,8 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
host->unique_id = ata_unique_id++;
host->max_cmd_len = 12;
- ap->flags = ATA_FLAG_PORT_DISABLED;
+ ap->lock = &host_set->lock;
+ ap->flags = ATA_FLAG_DISABLED;
ap->id = host->unique_id;
ap->host = host;
ap->ctl = ATA_DEVCTL_OBS;
@@ -4455,19 +5203,35 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
ap->udma_mask = ent->udma_mask;
ap->flags |= ent->host_flags;
ap->ops = ent->port_ops;
- ap->cbl = ATA_CBL_NONE;
+ ap->hw_sata_spd_limit = UINT_MAX;
ap->active_tag = ATA_TAG_POISON;
ap->last_ctl = 0xFF;
+#if defined(ATA_VERBOSE_DEBUG)
+ /* turn on all debugging levels */
+ ap->msg_enable = 0x00FF;
+#elif defined(ATA_DEBUG)
+ ap->msg_enable = ATA_MSG_DRV | ATA_MSG_INFO | ATA_MSG_CTL | ATA_MSG_WARN | ATA_MSG_ERR;
+#else
+ ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN;
+#endif
+
INIT_WORK(&ap->port_task, NULL, NULL);
+ INIT_WORK(&ap->hotplug_task, ata_scsi_hotplug, ap);
+ INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan, ap);
INIT_LIST_HEAD(&ap->eh_done_q);
+ init_waitqueue_head(&ap->eh_wait_q);
+
+ /* set cable type */
+ ap->cbl = ATA_CBL_NONE;
+ if (ap->flags & ATA_FLAG_SATA)
+ ap->cbl = ATA_CBL_SATA;
for (i = 0; i < ATA_MAX_DEVICES; i++) {
struct ata_device *dev = &ap->device[i];
+ dev->ap = ap;
dev->devno = i;
- dev->pio_mask = UINT_MAX;
- dev->mwdma_mask = UINT_MAX;
- dev->udma_mask = UINT_MAX;
+ ata_dev_init(dev);
}
#ifdef ATA_IRQ_TRAP
@@ -4503,7 +5267,7 @@ static struct ata_port * ata_host_add(const struct ata_probe_ent *ent,
DPRINTK("ENTER\n");
- if (!ent->port_ops->probe_reset &&
+ if (!ent->port_ops->error_handler &&
!(ent->host_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) {
printk(KERN_ERR "ata%u: no reset mechanism available\n",
port_no);
@@ -4516,7 +5280,7 @@ static struct ata_port * ata_host_add(const struct ata_probe_ent *ent,
host->transportt = &ata_scsi_transport_template;
- ap = (struct ata_port *) &host->hostdata[0];
+ ap = ata_shost_to_port(host);
ata_host_init(ap, host, host_set, ent, port_no);
@@ -4549,12 +5313,12 @@ err_out:
* RETURNS:
* Number of ports registered. Zero on error (no ports registered).
*/
-
int ata_device_add(const struct ata_probe_ent *ent)
{
unsigned int count = 0, i;
struct device *dev = ent->dev;
struct ata_host_set *host_set;
+ int rc;
DPRINTK("ENTER\n");
/* alloc a container for our list of ATA ports (buses) */
@@ -4587,18 +5351,18 @@ int ata_device_add(const struct ata_probe_ent *ent)
(ap->pio_mask << ATA_SHIFT_PIO);
/* print per-port info to dmesg */
- printk(KERN_INFO "ata%u: %cATA max %s cmd 0x%lX ctl 0x%lX "
- "bmdma 0x%lX irq %lu\n",
- ap->id,
- ap->flags & ATA_FLAG_SATA ? 'S' : 'P',
- ata_mode_string(xfer_mode_mask),
- ap->ioaddr.cmd_addr,
- ap->ioaddr.ctl_addr,
- ap->ioaddr.bmdma_addr,
- ent->irq);
+ ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%lX "
+ "ctl 0x%lX bmdma 0x%lX irq %lu\n",
+ ap->flags & ATA_FLAG_SATA ? 'S' : 'P',
+ ata_mode_string(xfer_mode_mask),
+ ap->ioaddr.cmd_addr,
+ ap->ioaddr.ctl_addr,
+ ap->ioaddr.bmdma_addr,
+ ent->irq);
ata_chk_status(ap);
host_set->ops->irq_clear(ap);
+ ata_eh_freeze_port(ap); /* freeze port before requesting IRQ */
count++;
}
@@ -4606,41 +5370,72 @@ int ata_device_add(const struct ata_probe_ent *ent)
goto err_free_ret;
/* obtain irq, that is shared between channels */
- if (request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags,
- DRV_NAME, host_set))
+ rc = request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags,
+ DRV_NAME, host_set);
+ if (rc) {
+ dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
+ ent->irq, rc);
goto err_out;
+ }
/* perform each probe synchronously */
DPRINTK("probe begin\n");
for (i = 0; i < count; i++) {
struct ata_port *ap;
+ u32 scontrol;
int rc;
ap = host_set->ports[i];
- DPRINTK("ata%u: bus probe begin\n", ap->id);
- rc = ata_bus_probe(ap);
- DPRINTK("ata%u: bus probe end\n", ap->id);
-
- if (rc) {
- /* FIXME: do something useful here?
- * Current libata behavior will
- * tear down everything when
- * the module is removed
- * or the h/w is unplugged.
- */
+ /* init sata_spd_limit to the current value */
+ if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
+ int spd = (scontrol >> 4) & 0xf;
+ ap->hw_sata_spd_limit &= (1 << spd) - 1;
}
+ ap->sata_spd_limit = ap->hw_sata_spd_limit;
rc = scsi_add_host(ap->host, dev);
if (rc) {
- printk(KERN_ERR "ata%u: scsi_add_host failed\n",
- ap->id);
+ ata_port_printk(ap, KERN_ERR, "scsi_add_host failed\n");
/* FIXME: do something useful here */
/* FIXME: handle unconditional calls to
* scsi_scan_host and ata_host_remove, below,
* at the very least
*/
}
+
+ if (ap->ops->error_handler) {
+ unsigned long flags;
+
+ ata_port_probe(ap);
+
+ /* kick EH for boot probing */
+ spin_lock_irqsave(ap->lock, flags);
+
+ ap->eh_info.probe_mask = (1 << ATA_MAX_DEVICES) - 1;
+ ap->eh_info.action |= ATA_EH_SOFTRESET;
+
+ ap->flags |= ATA_FLAG_LOADING;
+ ata_port_schedule_eh(ap);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* wait for EH to finish */
+ ata_port_wait_eh(ap);
+ } else {
+ DPRINTK("ata%u: bus probe begin\n", ap->id);
+ rc = ata_bus_probe(ap);
+ DPRINTK("ata%u: bus probe end\n", ap->id);
+
+ if (rc) {
+ /* FIXME: do something useful here?
+ * Current libata behavior will
+ * tear down everything when
+ * the module is removed
+ * or the h/w is unplugged.
+ */
+ }
+ }
}
/* probes are done, now scan each port's disk(s) */
@@ -4668,6 +5463,63 @@ err_free_ret:
}
/**
+ * ata_port_detach - Detach ATA port in prepration of device removal
+ * @ap: ATA port to be detached
+ *
+ * Detach all ATA devices and the associated SCSI devices of @ap;
+ * then, remove the associated SCSI host. @ap is guaranteed to
+ * be quiescent on return from this function.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+void ata_port_detach(struct ata_port *ap)
+{
+ unsigned long flags;
+ int i;
+
+ if (!ap->ops->error_handler)
+ return;
+
+ /* tell EH we're leaving & flush EH */
+ spin_lock_irqsave(ap->lock, flags);
+ ap->flags |= ATA_FLAG_UNLOADING;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_port_wait_eh(ap);
+
+ /* EH is now guaranteed to see UNLOADING, so no new device
+ * will be attached. Disable all existing devices.
+ */
+ spin_lock_irqsave(ap->lock, flags);
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ ata_dev_disable(&ap->device[i]);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* Final freeze & EH. All in-flight commands are aborted. EH
+ * will be skipped and retrials will be terminated with bad
+ * target.
+ */
+ spin_lock_irqsave(ap->lock, flags);
+ ata_port_freeze(ap); /* won't be thawed */
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_port_wait_eh(ap);
+
+ /* Flush hotplug task. The sequence is similar to
+ * ata_port_flush_task().
+ */
+ flush_workqueue(ata_aux_wq);
+ cancel_delayed_work(&ap->hotplug_task);
+ flush_workqueue(ata_aux_wq);
+
+ /* remove the associated SCSI host */
+ scsi_remove_host(ap->host);
+}
+
+/**
* ata_host_set_remove - PCI layer callback for device removal
* @host_set: ATA host set that was removed
*
@@ -4680,18 +5532,15 @@ err_free_ret:
void ata_host_set_remove(struct ata_host_set *host_set)
{
- struct ata_port *ap;
unsigned int i;
- for (i = 0; i < host_set->n_ports; i++) {
- ap = host_set->ports[i];
- scsi_remove_host(ap->host);
- }
+ for (i = 0; i < host_set->n_ports; i++)
+ ata_port_detach(host_set->ports[i]);
free_irq(host_set->irq, host_set);
for (i = 0; i < host_set->n_ports; i++) {
- ap = host_set->ports[i];
+ struct ata_port *ap = host_set->ports[i];
ata_scsi_release(ap->host);
@@ -4729,15 +5578,12 @@ void ata_host_set_remove(struct ata_host_set *host_set)
int ata_scsi_release(struct Scsi_Host *host)
{
- struct ata_port *ap = (struct ata_port *) &host->hostdata[0];
- int i;
+ struct ata_port *ap = ata_shost_to_port(host);
DPRINTK("ENTER\n");
ap->ops->port_disable(ap);
ata_host_remove(ap, 0);
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- kfree(ap->device[i].id);
DPRINTK("EXIT\n");
return 1;
@@ -4797,8 +5643,12 @@ void ata_pci_remove_one (struct pci_dev *pdev)
{
struct device *dev = pci_dev_to_dev(pdev);
struct ata_host_set *host_set = dev_get_drvdata(dev);
+ struct ata_host_set *host_set2 = host_set->next;
ata_host_set_remove(host_set);
+ if (host_set2)
+ ata_host_set_remove(host_set2);
+
pci_release_regions(pdev);
pci_disable_device(pdev);
dev_set_drvdata(dev, NULL);
@@ -4863,6 +5713,12 @@ static int __init ata_init(void)
if (!ata_wq)
return -ENOMEM;
+ ata_aux_wq = create_singlethread_workqueue("ata_aux");
+ if (!ata_aux_wq) {
+ destroy_workqueue(ata_wq);
+ return -ENOMEM;
+ }
+
printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n");
return 0;
}
@@ -4870,6 +5726,7 @@ static int __init ata_init(void)
static void __exit ata_exit(void)
{
destroy_workqueue(ata_wq);
+ destroy_workqueue(ata_aux_wq);
}
module_init(ata_init);
@@ -4896,6 +5753,52 @@ int ata_ratelimit(void)
return rc;
}
+/**
+ * ata_wait_register - wait until register value changes
+ * @reg: IO-mapped register
+ * @mask: Mask to apply to read register value
+ * @val: Wait condition
+ * @interval_msec: polling interval in milliseconds
+ * @timeout_msec: timeout in milliseconds
+ *
+ * Waiting for some bits of register to change is a common
+ * operation for ATA controllers. This function reads 32bit LE
+ * IO-mapped register @reg and tests for the following condition.
+ *
+ * (*@reg & mask) != val
+ *
+ * If the condition is met, it returns; otherwise, the process is
+ * repeated after @interval_msec until timeout.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * The final register value.
+ */
+u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
+ unsigned long interval_msec,
+ unsigned long timeout_msec)
+{
+ unsigned long timeout;
+ u32 tmp;
+
+ tmp = ioread32(reg);
+
+ /* Calculate timeout _after_ the first read to make sure
+ * preceding writes reach the controller before starting to
+ * eat away the timeout.
+ */
+ timeout = jiffies + (timeout_msec * HZ) / 1000;
+
+ while ((tmp & mask) == val && time_before(jiffies, timeout)) {
+ msleep(interval_msec);
+ tmp = ioread32(reg);
+ }
+
+ return tmp;
+}
+
/*
* libata is essentially a library of internal helper functions for
* low-level ATA host controller drivers. As such, the API/ABI is
@@ -4903,15 +5806,20 @@ int ata_ratelimit(void)
* Do not depend on ABI/API stability.
*/
+EXPORT_SYMBOL_GPL(sata_deb_timing_boot);
+EXPORT_SYMBOL_GPL(sata_deb_timing_eh);
+EXPORT_SYMBOL_GPL(sata_deb_timing_before_fsrst);
EXPORT_SYMBOL_GPL(ata_std_bios_param);
EXPORT_SYMBOL_GPL(ata_std_ports);
EXPORT_SYMBOL_GPL(ata_device_add);
+EXPORT_SYMBOL_GPL(ata_port_detach);
EXPORT_SYMBOL_GPL(ata_host_set_remove);
EXPORT_SYMBOL_GPL(ata_sg_init);
EXPORT_SYMBOL_GPL(ata_sg_init_one);
-EXPORT_SYMBOL_GPL(__ata_qc_complete);
+EXPORT_SYMBOL_GPL(ata_hsm_move);
+EXPORT_SYMBOL_GPL(ata_qc_complete);
+EXPORT_SYMBOL_GPL(ata_qc_complete_multiple);
EXPORT_SYMBOL_GPL(ata_qc_issue_prot);
-EXPORT_SYMBOL_GPL(ata_eng_timeout);
EXPORT_SYMBOL_GPL(ata_tf_load);
EXPORT_SYMBOL_GPL(ata_tf_read);
EXPORT_SYMBOL_GPL(ata_noop_dev_select);
@@ -4925,6 +5833,9 @@ EXPORT_SYMBOL_GPL(ata_port_start);
EXPORT_SYMBOL_GPL(ata_port_stop);
EXPORT_SYMBOL_GPL(ata_host_stop);
EXPORT_SYMBOL_GPL(ata_interrupt);
+EXPORT_SYMBOL_GPL(ata_mmio_data_xfer);
+EXPORT_SYMBOL_GPL(ata_pio_data_xfer);
+EXPORT_SYMBOL_GPL(ata_pio_data_xfer_noirq);
EXPORT_SYMBOL_GPL(ata_qc_prep);
EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
EXPORT_SYMBOL_GPL(ata_bmdma_setup);
@@ -4932,33 +5843,46 @@ EXPORT_SYMBOL_GPL(ata_bmdma_start);
EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear);
EXPORT_SYMBOL_GPL(ata_bmdma_status);
EXPORT_SYMBOL_GPL(ata_bmdma_stop);
+EXPORT_SYMBOL_GPL(ata_bmdma_freeze);
+EXPORT_SYMBOL_GPL(ata_bmdma_thaw);
+EXPORT_SYMBOL_GPL(ata_bmdma_drive_eh);
+EXPORT_SYMBOL_GPL(ata_bmdma_error_handler);
+EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd);
EXPORT_SYMBOL_GPL(ata_port_probe);
+EXPORT_SYMBOL_GPL(sata_set_spd);
+EXPORT_SYMBOL_GPL(sata_phy_debounce);
+EXPORT_SYMBOL_GPL(sata_phy_resume);
EXPORT_SYMBOL_GPL(sata_phy_reset);
EXPORT_SYMBOL_GPL(__sata_phy_reset);
EXPORT_SYMBOL_GPL(ata_bus_reset);
-EXPORT_SYMBOL_GPL(ata_std_probeinit);
+EXPORT_SYMBOL_GPL(ata_std_prereset);
EXPORT_SYMBOL_GPL(ata_std_softreset);
EXPORT_SYMBOL_GPL(sata_std_hardreset);
EXPORT_SYMBOL_GPL(ata_std_postreset);
-EXPORT_SYMBOL_GPL(ata_std_probe_reset);
-EXPORT_SYMBOL_GPL(ata_drive_probe_reset);
EXPORT_SYMBOL_GPL(ata_dev_revalidate);
EXPORT_SYMBOL_GPL(ata_dev_classify);
EXPORT_SYMBOL_GPL(ata_dev_pair);
EXPORT_SYMBOL_GPL(ata_port_disable);
EXPORT_SYMBOL_GPL(ata_ratelimit);
+EXPORT_SYMBOL_GPL(ata_wait_register);
EXPORT_SYMBOL_GPL(ata_busy_sleep);
EXPORT_SYMBOL_GPL(ata_port_queue_task);
EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
+EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy);
+EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth);
EXPORT_SYMBOL_GPL(ata_scsi_release);
EXPORT_SYMBOL_GPL(ata_host_intr);
+EXPORT_SYMBOL_GPL(sata_scr_valid);
+EXPORT_SYMBOL_GPL(sata_scr_read);
+EXPORT_SYMBOL_GPL(sata_scr_write);
+EXPORT_SYMBOL_GPL(sata_scr_write_flush);
+EXPORT_SYMBOL_GPL(ata_port_online);
+EXPORT_SYMBOL_GPL(ata_port_offline);
EXPORT_SYMBOL_GPL(ata_id_string);
EXPORT_SYMBOL_GPL(ata_id_c_string);
EXPORT_SYMBOL_GPL(ata_scsi_simulate);
-EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
-EXPORT_SYMBOL_GPL(ata_eh_qc_retry);
EXPORT_SYMBOL_GPL(ata_pio_need_iordy);
EXPORT_SYMBOL_GPL(ata_timing_compute);
@@ -4980,3 +5904,13 @@ EXPORT_SYMBOL_GPL(ata_device_suspend);
EXPORT_SYMBOL_GPL(ata_device_resume);
EXPORT_SYMBOL_GPL(ata_scsi_device_suspend);
EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
+
+EXPORT_SYMBOL_GPL(ata_eng_timeout);
+EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
+EXPORT_SYMBOL_GPL(ata_port_abort);
+EXPORT_SYMBOL_GPL(ata_port_freeze);
+EXPORT_SYMBOL_GPL(ata_eh_freeze_port);
+EXPORT_SYMBOL_GPL(ata_eh_thaw_port);
+EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
+EXPORT_SYMBOL_GPL(ata_eh_qc_retry);
+EXPORT_SYMBOL_GPL(ata_do_eh);
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
new file mode 100644
index 0000000..8233859
--- /dev/null
+++ b/drivers/scsi/libata-eh.c
@@ -0,0 +1,1907 @@
+/*
+ * libata-eh.c - libata error handling
+ *
+ * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Please ALWAYS copy linux-ide@vger.kernel.org
+ * on emails.
+ *
+ * Copyright 2006 Tejun Heo <htejun@gmail.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * Hardware documentation available from http://www.t13.org/ and
+ * http://www.sata-io.org/
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+#include "scsi_transport_api.h"
+
+#include <linux/libata.h>
+
+#include "libata.h"
+
+static void __ata_port_freeze(struct ata_port *ap);
+static void ata_eh_finish(struct ata_port *ap);
+
+static void ata_ering_record(struct ata_ering *ering, int is_io,
+ unsigned int err_mask)
+{
+ struct ata_ering_entry *ent;
+
+ WARN_ON(!err_mask);
+
+ ering->cursor++;
+ ering->cursor %= ATA_ERING_SIZE;
+
+ ent = &ering->ring[ering->cursor];
+ ent->is_io = is_io;
+ ent->err_mask = err_mask;
+ ent->timestamp = get_jiffies_64();
+}
+
+static struct ata_ering_entry * ata_ering_top(struct ata_ering *ering)
+{
+ struct ata_ering_entry *ent = &ering->ring[ering->cursor];
+ if (!ent->err_mask)
+ return NULL;
+ return ent;
+}
+
+static int ata_ering_map(struct ata_ering *ering,
+ int (*map_fn)(struct ata_ering_entry *, void *),
+ void *arg)
+{
+ int idx, rc = 0;
+ struct ata_ering_entry *ent;
+
+ idx = ering->cursor;
+ do {
+ ent = &ering->ring[idx];
+ if (!ent->err_mask)
+ break;
+ rc = map_fn(ent, arg);
+ if (rc)
+ break;
+ idx = (idx - 1 + ATA_ERING_SIZE) % ATA_ERING_SIZE;
+ } while (idx != ering->cursor);
+
+ return rc;
+}
+
+/**
+ * ata_scsi_timed_out - SCSI layer time out callback
+ * @cmd: timed out SCSI command
+ *
+ * Handles SCSI layer timeout. We race with normal completion of
+ * the qc for @cmd. If the qc is already gone, we lose and let
+ * the scsi command finish (EH_HANDLED). Otherwise, the qc has
+ * timed out and EH should be invoked. Prevent ata_qc_complete()
+ * from finishing it by setting EH_SCHEDULED and return
+ * EH_NOT_HANDLED.
+ *
+ * TODO: kill this function once old EH is gone.
+ *
+ * LOCKING:
+ * Called from timer context
+ *
+ * RETURNS:
+ * EH_HANDLED or EH_NOT_HANDLED
+ */
+enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *host = cmd->device->host;
+ struct ata_port *ap = ata_shost_to_port(host);
+ unsigned long flags;
+ struct ata_queued_cmd *qc;
+ enum scsi_eh_timer_return ret;
+
+ DPRINTK("ENTER\n");
+
+ if (ap->ops->error_handler) {
+ ret = EH_NOT_HANDLED;
+ goto out;
+ }
+
+ ret = EH_HANDLED;
+ spin_lock_irqsave(ap->lock, flags);
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc) {
+ WARN_ON(qc->scsicmd != cmd);
+ qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ ret = EH_NOT_HANDLED;
+ }
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ out:
+ DPRINTK("EXIT, ret=%d\n", ret);
+ return ret;
+}
+
+/**
+ * ata_scsi_error - SCSI layer error handler callback
+ * @host: SCSI host on which error occurred
+ *
+ * Handles SCSI-layer-thrown error events.
+ *
+ * LOCKING:
+ * Inherited from SCSI layer (none, can sleep)
+ *
+ * RETURNS:
+ * Zero.
+ */
+void ata_scsi_error(struct Scsi_Host *host)
+{
+ struct ata_port *ap = ata_shost_to_port(host);
+ spinlock_t *ap_lock = ap->lock;
+ int i, repeat_cnt = ATA_EH_MAX_REPEAT;
+ unsigned long flags;
+
+ DPRINTK("ENTER\n");
+
+ /* synchronize with port task */
+ ata_port_flush_task(ap);
+
+ /* synchronize with host_set lock and sort out timeouts */
+
+ /* For new EH, all qcs are finished in one of three ways -
+ * normal completion, error completion, and SCSI timeout.
+ * Both cmpletions can race against SCSI timeout. When normal
+ * completion wins, the qc never reaches EH. When error
+ * completion wins, the qc has ATA_QCFLAG_FAILED set.
+ *
+ * When SCSI timeout wins, things are a bit more complex.
+ * Normal or error completion can occur after the timeout but
+ * before this point. In such cases, both types of
+ * completions are honored. A scmd is determined to have
+ * timed out iff its associated qc is active and not failed.
+ */
+ if (ap->ops->error_handler) {
+ struct scsi_cmnd *scmd, *tmp;
+ int nr_timedout = 0;
+
+ spin_lock_irqsave(ap_lock, flags);
+
+ list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) {
+ struct ata_queued_cmd *qc;
+
+ for (i = 0; i < ATA_MAX_QUEUE; i++) {
+ qc = __ata_qc_from_tag(ap, i);
+ if (qc->flags & ATA_QCFLAG_ACTIVE &&
+ qc->scsicmd == scmd)
+ break;
+ }
+
+ if (i < ATA_MAX_QUEUE) {
+ /* the scmd has an associated qc */
+ if (!(qc->flags & ATA_QCFLAG_FAILED)) {
+ /* which hasn't failed yet, timeout */
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ qc->flags |= ATA_QCFLAG_FAILED;
+ nr_timedout++;
+ }
+ } else {
+ /* Normal completion occurred after
+ * SCSI timeout but before this point.
+ * Successfully complete it.
+ */
+ scmd->retries = scmd->allowed;
+ scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
+ }
+ }
+
+ /* If we have timed out qcs. They belong to EH from
+ * this point but the state of the controller is
+ * unknown. Freeze the port to make sure the IRQ
+ * handler doesn't diddle with those qcs. This must
+ * be done atomically w.r.t. setting QCFLAG_FAILED.
+ */
+ if (nr_timedout)
+ __ata_port_freeze(ap);
+
+ spin_unlock_irqrestore(ap_lock, flags);
+ } else
+ spin_unlock_wait(ap_lock);
+
+ repeat:
+ /* invoke error handler */
+ if (ap->ops->error_handler) {
+ /* fetch & clear EH info */
+ spin_lock_irqsave(ap_lock, flags);
+
+ memset(&ap->eh_context, 0, sizeof(ap->eh_context));
+ ap->eh_context.i = ap->eh_info;
+ memset(&ap->eh_info, 0, sizeof(ap->eh_info));
+
+ ap->flags |= ATA_FLAG_EH_IN_PROGRESS;
+ ap->flags &= ~ATA_FLAG_EH_PENDING;
+
+ spin_unlock_irqrestore(ap_lock, flags);
+
+ /* invoke EH. if unloading, just finish failed qcs */
+ if (!(ap->flags & ATA_FLAG_UNLOADING))
+ ap->ops->error_handler(ap);
+ else
+ ata_eh_finish(ap);
+
+ /* Exception might have happend after ->error_handler
+ * recovered the port but before this point. Repeat
+ * EH in such case.
+ */
+ spin_lock_irqsave(ap_lock, flags);
+
+ if (ap->flags & ATA_FLAG_EH_PENDING) {
+ if (--repeat_cnt) {
+ ata_port_printk(ap, KERN_INFO,
+ "EH pending after completion, "
+ "repeating EH (cnt=%d)\n", repeat_cnt);
+ spin_unlock_irqrestore(ap_lock, flags);
+ goto repeat;
+ }
+ ata_port_printk(ap, KERN_ERR, "EH pending after %d "
+ "tries, giving up\n", ATA_EH_MAX_REPEAT);
+ }
+
+ /* this run is complete, make sure EH info is clear */
+ memset(&ap->eh_info, 0, sizeof(ap->eh_info));
+
+ /* Clear host_eh_scheduled while holding ap_lock such
+ * that if exception occurs after this point but
+ * before EH completion, SCSI midlayer will
+ * re-initiate EH.
+ */
+ host->host_eh_scheduled = 0;
+
+ spin_unlock_irqrestore(ap_lock, flags);
+ } else {
+ WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
+ ap->ops->eng_timeout(ap);
+ }
+
+ /* finish or retry handled scmd's and clean up */
+ WARN_ON(host->host_failed || !list_empty(&host->eh_cmd_q));
+
+ scsi_eh_flush_done_q(&ap->eh_done_q);
+
+ /* clean up */
+ spin_lock_irqsave(ap_lock, flags);
+
+ if (ap->flags & ATA_FLAG_LOADING) {
+ ap->flags &= ~ATA_FLAG_LOADING;
+ } else {
+ if (ap->flags & ATA_FLAG_SCSI_HOTPLUG)
+ queue_work(ata_aux_wq, &ap->hotplug_task);
+ if (ap->flags & ATA_FLAG_RECOVERED)
+ ata_port_printk(ap, KERN_INFO, "EH complete\n");
+ }
+
+ ap->flags &= ~(ATA_FLAG_SCSI_HOTPLUG | ATA_FLAG_RECOVERED);
+
+ /* tell wait_eh that we're done */
+ ap->flags &= ~ATA_FLAG_EH_IN_PROGRESS;
+ wake_up_all(&ap->eh_wait_q);
+
+ spin_unlock_irqrestore(ap_lock, flags);
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * ata_port_wait_eh - Wait for the currently pending EH to complete
+ * @ap: Port to wait EH for
+ *
+ * Wait until the currently pending EH is complete.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+void ata_port_wait_eh(struct ata_port *ap)
+{
+ unsigned long flags;
+ DEFINE_WAIT(wait);
+
+ retry:
+ spin_lock_irqsave(ap->lock, flags);
+
+ while (ap->flags & (ATA_FLAG_EH_PENDING | ATA_FLAG_EH_IN_PROGRESS)) {
+ prepare_to_wait(&ap->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE);
+ spin_unlock_irqrestore(ap->lock, flags);
+ schedule();
+ spin_lock_irqsave(ap->lock, flags);
+ }
+ finish_wait(&ap->eh_wait_q, &wait);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* make sure SCSI EH is complete */
+ if (scsi_host_in_recovery(ap->host)) {
+ msleep(10);
+ goto retry;
+ }
+}
+
+/**
+ * ata_qc_timeout - Handle timeout of queued command
+ * @qc: Command that timed out
+ *
+ * Some part of the kernel (currently, only the SCSI layer)
+ * has noticed that the active command on port @ap has not
+ * completed after a specified length of time. Handle this
+ * condition by disabling DMA (if necessary) and completing
+ * transactions, with error if necessary.
+ *
+ * This also handles the case of the "lost interrupt", where
+ * for some reason (possibly hardware bug, possibly driver bug)
+ * an interrupt was not delivered to the driver, even though the
+ * transaction completed successfully.
+ *
+ * TODO: kill this function once old EH is gone.
+ *
+ * LOCKING:
+ * Inherited from SCSI layer (none, can sleep)
+ */
+static void ata_qc_timeout(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ u8 host_stat = 0, drv_stat;
+ unsigned long flags;
+
+ DPRINTK("ENTER\n");
+
+ ap->hsm_task_state = HSM_ST_IDLE;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ switch (qc->tf.protocol) {
+
+ case ATA_PROT_DMA:
+ case ATA_PROT_ATAPI_DMA:
+ host_stat = ap->ops->bmdma_status(ap);
+
+ /* before we do anything else, clear DMA-Start bit */
+ ap->ops->bmdma_stop(qc);
+
+ /* fall through */
+
+ default:
+ ata_altstatus(ap);
+ drv_stat = ata_chk_status(ap);
+
+ /* ack bmdma irq events */
+ ap->ops->irq_clear(ap);
+
+ ata_dev_printk(qc->dev, KERN_ERR, "command 0x%x timeout, "
+ "stat 0x%x host_stat 0x%x\n",
+ qc->tf.command, drv_stat, host_stat);
+
+ /* complete taskfile transaction */
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ break;
+ }
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_eh_qc_complete(qc);
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * ata_eng_timeout - Handle timeout of queued command
+ * @ap: Port on which timed-out command is active
+ *
+ * Some part of the kernel (currently, only the SCSI layer)
+ * has noticed that the active command on port @ap has not
+ * completed after a specified length of time. Handle this
+ * condition by disabling DMA (if necessary) and completing
+ * transactions, with error if necessary.
+ *
+ * This also handles the case of the "lost interrupt", where
+ * for some reason (possibly hardware bug, possibly driver bug)
+ * an interrupt was not delivered to the driver, even though the
+ * transaction completed successfully.
+ *
+ * TODO: kill this function once old EH is gone.
+ *
+ * LOCKING:
+ * Inherited from SCSI layer (none, can sleep)
+ */
+void ata_eng_timeout(struct ata_port *ap)
+{
+ DPRINTK("ENTER\n");
+
+ ata_qc_timeout(ata_qc_from_tag(ap, ap->active_tag));
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * ata_qc_schedule_eh - schedule qc for error handling
+ * @qc: command to schedule error handling for
+ *
+ * Schedule error handling for @qc. EH will kick in as soon as
+ * other commands are drained.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host_set lock)
+ */
+void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ WARN_ON(!ap->ops->error_handler);
+
+ qc->flags |= ATA_QCFLAG_FAILED;
+ qc->ap->flags |= ATA_FLAG_EH_PENDING;
+
+ /* The following will fail if timeout has already expired.
+ * ata_scsi_error() takes care of such scmds on EH entry.
+ * Note that ATA_QCFLAG_FAILED is unconditionally set after
+ * this function completes.
+ */
+ scsi_req_abort_cmd(qc->scsicmd);
+}
+
+/**
+ * ata_port_schedule_eh - schedule error handling without a qc
+ * @ap: ATA port to schedule EH for
+ *
+ * Schedule error handling for @ap. EH will kick in as soon as
+ * all commands are drained.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host_set lock)
+ */
+void ata_port_schedule_eh(struct ata_port *ap)
+{
+ WARN_ON(!ap->ops->error_handler);
+
+ ap->flags |= ATA_FLAG_EH_PENDING;
+ scsi_schedule_eh(ap->host);
+
+ DPRINTK("port EH scheduled\n");
+}
+
+/**
+ * ata_port_abort - abort all qc's on the port
+ * @ap: ATA port to abort qc's for
+ *
+ * Abort all active qc's of @ap and schedule EH.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host_set lock)
+ *
+ * RETURNS:
+ * Number of aborted qc's.
+ */
+int ata_port_abort(struct ata_port *ap)
+{
+ int tag, nr_aborted = 0;
+
+ WARN_ON(!ap->ops->error_handler);
+
+ for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
+
+ if (qc) {
+ qc->flags |= ATA_QCFLAG_FAILED;
+ ata_qc_complete(qc);
+ nr_aborted++;
+ }
+ }
+
+ if (!nr_aborted)
+ ata_port_schedule_eh(ap);
+
+ return nr_aborted;
+}
+
+/**
+ * __ata_port_freeze - freeze port
+ * @ap: ATA port to freeze
+ *
+ * This function is called when HSM violation or some other
+ * condition disrupts normal operation of the port. Frozen port
+ * is not allowed to perform any operation until the port is
+ * thawed, which usually follows a successful reset.
+ *
+ * ap->ops->freeze() callback can be used for freezing the port
+ * hardware-wise (e.g. mask interrupt and stop DMA engine). If a
+ * port cannot be frozen hardware-wise, the interrupt handler
+ * must ack and clear interrupts unconditionally while the port
+ * is frozen.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host_set lock)
+ */
+static void __ata_port_freeze(struct ata_port *ap)
+{
+ WARN_ON(!ap->ops->error_handler);
+
+ if (ap->ops->freeze)
+ ap->ops->freeze(ap);
+
+ ap->flags |= ATA_FLAG_FROZEN;
+
+ DPRINTK("ata%u port frozen\n", ap->id);
+}
+
+/**
+ * ata_port_freeze - abort & freeze port
+ * @ap: ATA port to freeze
+ *
+ * Abort and freeze @ap.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host_set lock)
+ *
+ * RETURNS:
+ * Number of aborted commands.
+ */
+int ata_port_freeze(struct ata_port *ap)
+{
+ int nr_aborted;
+
+ WARN_ON(!ap->ops->error_handler);
+
+ nr_aborted = ata_port_abort(ap);
+ __ata_port_freeze(ap);
+
+ return nr_aborted;
+}
+
+/**
+ * ata_eh_freeze_port - EH helper to freeze port
+ * @ap: ATA port to freeze
+ *
+ * Freeze @ap.
+ *
+ * LOCKING:
+ * None.
+ */
+void ata_eh_freeze_port(struct ata_port *ap)
+{
+ unsigned long flags;
+
+ if (!ap->ops->error_handler)
+ return;
+
+ spin_lock_irqsave(ap->lock, flags);
+ __ata_port_freeze(ap);
+ spin_unlock_irqrestore(ap->lock, flags);
+}
+
+/**
+ * ata_port_thaw_port - EH helper to thaw port
+ * @ap: ATA port to thaw
+ *
+ * Thaw frozen port @ap.
+ *
+ * LOCKING:
+ * None.
+ */
+void ata_eh_thaw_port(struct ata_port *ap)
+{
+ unsigned long flags;
+
+ if (!ap->ops->error_handler)
+ return;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ ap->flags &= ~ATA_FLAG_FROZEN;
+
+ if (ap->ops->thaw)
+ ap->ops->thaw(ap);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ DPRINTK("ata%u port thawed\n", ap->id);
+}
+
+static void ata_eh_scsidone(struct scsi_cmnd *scmd)
+{
+ /* nada */
+}
+
+static void __ata_eh_qc_complete(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct scsi_cmnd *scmd = qc->scsicmd;
+ unsigned long flags;
+
+ spin_lock_irqsave(ap->lock, flags);
+ qc->scsidone = ata_eh_scsidone;
+ __ata_qc_complete(qc);
+ WARN_ON(ata_tag_valid(qc->tag));
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
+}
+
+/**
+ * ata_eh_qc_complete - Complete an active ATA command from EH
+ * @qc: Command to complete
+ *
+ * Indicate to the mid and upper layers that an ATA command has
+ * completed. To be used from EH.
+ */
+void ata_eh_qc_complete(struct ata_queued_cmd *qc)
+{
+ struct scsi_cmnd *scmd = qc->scsicmd;
+ scmd->retries = scmd->allowed;
+ __ata_eh_qc_complete(qc);
+}
+
+/**
+ * ata_eh_qc_retry - Tell midlayer to retry an ATA command after EH
+ * @qc: Command to retry
+ *
+ * Indicate to the mid and upper layers that an ATA command
+ * should be retried. To be used from EH.
+ *
+ * SCSI midlayer limits the number of retries to scmd->allowed.
+ * scmd->retries is decremented for commands which get retried
+ * due to unrelated failures (qc->err_mask is zero).
+ */
+void ata_eh_qc_retry(struct ata_queued_cmd *qc)
+{
+ struct scsi_cmnd *scmd = qc->scsicmd;
+ if (!qc->err_mask && scmd->retries)
+ scmd->retries--;
+ __ata_eh_qc_complete(qc);
+}
+
+/**
+ * ata_eh_detach_dev - detach ATA device
+ * @dev: ATA device to detach
+ *
+ * Detach @dev.
+ *
+ * LOCKING:
+ * None.
+ */
+static void ata_eh_detach_dev(struct ata_device *dev)
+{
+ struct ata_port *ap = dev->ap;
+ unsigned long flags;
+
+ ata_dev_disable(dev);
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ dev->flags &= ~ATA_DFLAG_DETACH;
+
+ if (ata_scsi_offline_dev(dev)) {
+ dev->flags |= ATA_DFLAG_DETACHED;
+ ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
+ }
+
+ spin_unlock_irqrestore(ap->lock, flags);
+}
+
+static void ata_eh_clear_action(struct ata_device *dev,
+ struct ata_eh_info *ehi, unsigned int action)
+{
+ int i;
+
+ if (!dev) {
+ ehi->action &= ~action;
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ ehi->dev_action[i] &= ~action;
+ } else {
+ /* doesn't make sense for port-wide EH actions */
+ WARN_ON(!(action & ATA_EH_PERDEV_MASK));
+
+ /* break ehi->action into ehi->dev_action */
+ if (ehi->action & action) {
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ ehi->dev_action[i] |= ehi->action & action;
+ ehi->action &= ~action;
+ }
+
+ /* turn off the specified per-dev action */
+ ehi->dev_action[dev->devno] &= ~action;
+ }
+}
+
+/**
+ * ata_eh_about_to_do - about to perform eh_action
+ * @ap: target ATA port
+ * @dev: target ATA dev for per-dev action (can be NULL)
+ * @action: action about to be performed
+ *
+ * Called just before performing EH actions to clear related bits
+ * in @ap->eh_info such that eh actions are not unnecessarily
+ * repeated.
+ *
+ * LOCKING:
+ * None.
+ */
+static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
+ unsigned int action)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(ap->lock, flags);
+ ata_eh_clear_action(dev, &ap->eh_info, action);
+ ap->flags |= ATA_FLAG_RECOVERED;
+ spin_unlock_irqrestore(ap->lock, flags);
+}
+
+/**
+ * ata_eh_done - EH action complete
+ * @ap: target ATA port
+ * @dev: target ATA dev for per-dev action (can be NULL)
+ * @action: action just completed
+ *
+ * Called right after performing EH actions to clear related bits
+ * in @ap->eh_context.
+ *
+ * LOCKING:
+ * None.
+ */
+static void ata_eh_done(struct ata_port *ap, struct ata_device *dev,
+ unsigned int action)
+{
+ ata_eh_clear_action(dev, &ap->eh_context.i, action);
+}
+
+/**
+ * ata_err_string - convert err_mask to descriptive string
+ * @err_mask: error mask to convert to string
+ *
+ * Convert @err_mask to descriptive string. Errors are
+ * prioritized according to severity and only the most severe
+ * error is reported.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * Descriptive string for @err_mask
+ */
+static const char * ata_err_string(unsigned int err_mask)
+{
+ if (err_mask & AC_ERR_HOST_BUS)
+ return "host bus error";
+ if (err_mask & AC_ERR_ATA_BUS)
+ return "ATA bus error";
+ if (err_mask & AC_ERR_TIMEOUT)
+ return "timeout";
+ if (err_mask & AC_ERR_HSM)
+ return "HSM violation";
+ if (err_mask & AC_ERR_SYSTEM)
+ return "internal error";
+ if (err_mask & AC_ERR_MEDIA)
+ return "media error";
+ if (err_mask & AC_ERR_INVALID)
+ return "invalid argument";
+ if (err_mask & AC_ERR_DEV)
+ return "device error";
+ return "unknown error";
+}
+
+/**
+ * ata_read_log_page - read a specific log page
+ * @dev: target device
+ * @page: page to read
+ * @buf: buffer to store read page
+ * @sectors: number of sectors to read
+ *
+ * Read log page using READ_LOG_EXT command.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, AC_ERR_* mask otherwise.
+ */
+static unsigned int ata_read_log_page(struct ata_device *dev,
+ u8 page, void *buf, unsigned int sectors)
+{
+ struct ata_taskfile tf;
+ unsigned int err_mask;
+
+ DPRINTK("read log page - page %d\n", page);
+
+ ata_tf_init(dev, &tf);
+ tf.command = ATA_CMD_READ_LOG_EXT;
+ tf.lbal = page;
+ tf.nsect = sectors;
+ tf.hob_nsect = sectors >> 8;
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_LBA48 | ATA_TFLAG_DEVICE;
+ tf.protocol = ATA_PROT_PIO;
+
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
+ buf, sectors * ATA_SECT_SIZE);
+
+ DPRINTK("EXIT, err_mask=%x\n", err_mask);
+ return err_mask;
+}
+
+/**
+ * ata_eh_read_log_10h - Read log page 10h for NCQ error details
+ * @dev: Device to read log page 10h from
+ * @tag: Resulting tag of the failed command
+ * @tf: Resulting taskfile registers of the failed command
+ *
+ * Read log page 10h to obtain NCQ error details and clear error
+ * condition.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+static int ata_eh_read_log_10h(struct ata_device *dev,
+ int *tag, struct ata_taskfile *tf)
+{
+ u8 *buf = dev->ap->sector_buf;
+ unsigned int err_mask;
+ u8 csum;
+ int i;
+
+ err_mask = ata_read_log_page(dev, ATA_LOG_SATA_NCQ, buf, 1);
+ if (err_mask)
+ return -EIO;
+
+ csum = 0;
+ for (i = 0; i < ATA_SECT_SIZE; i++)
+ csum += buf[i];
+ if (csum)
+ ata_dev_printk(dev, KERN_WARNING,
+ "invalid checksum 0x%x on log page 10h\n", csum);
+
+ if (buf[0] & 0x80)
+ return -ENOENT;
+
+ *tag = buf[0] & 0x1f;
+
+ tf->command = buf[2];
+ tf->feature = buf[3];
+ tf->lbal = buf[4];
+ tf->lbam = buf[5];
+ tf->lbah = buf[6];
+ tf->device = buf[7];
+ tf->hob_lbal = buf[8];
+ tf->hob_lbam = buf[9];
+ tf->hob_lbah = buf[10];
+ tf->nsect = buf[12];
+ tf->hob_nsect = buf[13];
+
+ return 0;
+}
+
+/**
+ * atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
+ * @dev: device to perform REQUEST_SENSE to
+ * @sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long)
+ *
+ * Perform ATAPI REQUEST_SENSE after the device reported CHECK
+ * SENSE. This function is EH helper.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, AC_ERR_* mask on failure
+ */
+static unsigned int atapi_eh_request_sense(struct ata_device *dev,
+ unsigned char *sense_buf)
+{
+ struct ata_port *ap = dev->ap;
+ struct ata_taskfile tf;
+ u8 cdb[ATAPI_CDB_LEN];
+
+ DPRINTK("ATAPI request sense\n");
+
+ ata_tf_init(dev, &tf);
+
+ /* FIXME: is this needed? */
+ memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE);
+
+ /* XXX: why tf_read here? */
+ ap->ops->tf_read(ap, &tf);
+
+ /* fill these in, for the case where they are -not- overwritten */
+ sense_buf[0] = 0x70;
+ sense_buf[2] = tf.feature >> 4;
+
+ memset(cdb, 0, ATAPI_CDB_LEN);
+ cdb[0] = REQUEST_SENSE;
+ cdb[4] = SCSI_SENSE_BUFFERSIZE;
+
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.command = ATA_CMD_PACKET;
+
+ /* is it pointless to prefer PIO for "safety reasons"? */
+ if (ap->flags & ATA_FLAG_PIO_DMA) {
+ tf.protocol = ATA_PROT_ATAPI_DMA;
+ tf.feature |= ATAPI_PKT_DMA;
+ } else {
+ tf.protocol = ATA_PROT_ATAPI;
+ tf.lbam = (8 * 1024) & 0xff;
+ tf.lbah = (8 * 1024) >> 8;
+ }
+
+ return ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE,
+ sense_buf, SCSI_SENSE_BUFFERSIZE);
+}
+
+/**
+ * ata_eh_analyze_serror - analyze SError for a failed port
+ * @ap: ATA port to analyze SError for
+ *
+ * Analyze SError if available and further determine cause of
+ * failure.
+ *
+ * LOCKING:
+ * None.
+ */
+static void ata_eh_analyze_serror(struct ata_port *ap)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ u32 serror = ehc->i.serror;
+ unsigned int err_mask = 0, action = 0;
+
+ if (serror & SERR_PERSISTENT) {
+ err_mask |= AC_ERR_ATA_BUS;
+ action |= ATA_EH_HARDRESET;
+ }
+ if (serror &
+ (SERR_DATA_RECOVERED | SERR_COMM_RECOVERED | SERR_DATA)) {
+ err_mask |= AC_ERR_ATA_BUS;
+ action |= ATA_EH_SOFTRESET;
+ }
+ if (serror & SERR_PROTOCOL) {
+ err_mask |= AC_ERR_HSM;
+ action |= ATA_EH_SOFTRESET;
+ }
+ if (serror & SERR_INTERNAL) {
+ err_mask |= AC_ERR_SYSTEM;
+ action |= ATA_EH_SOFTRESET;
+ }
+ if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG))
+ ata_ehi_hotplugged(&ehc->i);
+
+ ehc->i.err_mask |= err_mask;
+ ehc->i.action |= action;
+}
+
+/**
+ * ata_eh_analyze_ncq_error - analyze NCQ error
+ * @ap: ATA port to analyze NCQ error for
+ *
+ * Read log page 10h, determine the offending qc and acquire
+ * error status TF. For NCQ device errors, all LLDDs have to do
+ * is setting AC_ERR_DEV in ehi->err_mask. This function takes
+ * care of the rest.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_eh_analyze_ncq_error(struct ata_port *ap)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_device *dev = ap->device;
+ struct ata_queued_cmd *qc;
+ struct ata_taskfile tf;
+ int tag, rc;
+
+ /* if frozen, we can't do much */
+ if (ap->flags & ATA_FLAG_FROZEN)
+ return;
+
+ /* is it NCQ device error? */
+ if (!ap->sactive || !(ehc->i.err_mask & AC_ERR_DEV))
+ return;
+
+ /* has LLDD analyzed already? */
+ for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+ qc = __ata_qc_from_tag(ap, tag);
+
+ if (!(qc->flags & ATA_QCFLAG_FAILED))
+ continue;
+
+ if (qc->err_mask)
+ return;
+ }
+
+ /* okay, this error is ours */
+ rc = ata_eh_read_log_10h(dev, &tag, &tf);
+ if (rc) {
+ ata_port_printk(ap, KERN_ERR, "failed to read log page 10h "
+ "(errno=%d)\n", rc);
+ return;
+ }
+
+ if (!(ap->sactive & (1 << tag))) {
+ ata_port_printk(ap, KERN_ERR, "log page 10h reported "
+ "inactive tag %d\n", tag);
+ return;
+ }
+
+ /* we've got the perpetrator, condemn it */
+ qc = __ata_qc_from_tag(ap, tag);
+ memcpy(&qc->result_tf, &tf, sizeof(tf));
+ qc->err_mask |= AC_ERR_DEV;
+ ehc->i.err_mask &= ~AC_ERR_DEV;
+}
+
+/**
+ * ata_eh_analyze_tf - analyze taskfile of a failed qc
+ * @qc: qc to analyze
+ * @tf: Taskfile registers to analyze
+ *
+ * Analyze taskfile of @qc and further determine cause of
+ * failure. This function also requests ATAPI sense data if
+ * avaliable.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * Determined recovery action
+ */
+static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
+ const struct ata_taskfile *tf)
+{
+ unsigned int tmp, action = 0;
+ u8 stat = tf->command, err = tf->feature;
+
+ if ((stat & (ATA_BUSY | ATA_DRQ | ATA_DRDY)) != ATA_DRDY) {
+ qc->err_mask |= AC_ERR_HSM;
+ return ATA_EH_SOFTRESET;
+ }
+
+ if (!(qc->err_mask & AC_ERR_DEV))
+ return 0;
+
+ switch (qc->dev->class) {
+ case ATA_DEV_ATA:
+ if (err & ATA_ICRC)
+ qc->err_mask |= AC_ERR_ATA_BUS;
+ if (err & ATA_UNC)
+ qc->err_mask |= AC_ERR_MEDIA;
+ if (err & ATA_IDNF)
+ qc->err_mask |= AC_ERR_INVALID;
+ break;
+
+ case ATA_DEV_ATAPI:
+ tmp = atapi_eh_request_sense(qc->dev,
+ qc->scsicmd->sense_buffer);
+ if (!tmp) {
+ /* ATA_QCFLAG_SENSE_VALID is used to tell
+ * atapi_qc_complete() that sense data is
+ * already valid.
+ *
+ * TODO: interpret sense data and set
+ * appropriate err_mask.
+ */
+ qc->flags |= ATA_QCFLAG_SENSE_VALID;
+ } else
+ qc->err_mask |= tmp;
+ }
+
+ if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS))
+ action |= ATA_EH_SOFTRESET;
+
+ return action;
+}
+
+static int ata_eh_categorize_ering_entry(struct ata_ering_entry *ent)
+{
+ if (ent->err_mask & (AC_ERR_ATA_BUS | AC_ERR_TIMEOUT))
+ return 1;
+
+ if (ent->is_io) {
+ if (ent->err_mask & AC_ERR_HSM)
+ return 1;
+ if ((ent->err_mask &
+ (AC_ERR_DEV|AC_ERR_MEDIA|AC_ERR_INVALID)) == AC_ERR_DEV)
+ return 2;
+ }
+
+ return 0;
+}
+
+struct speed_down_needed_arg {
+ u64 since;
+ int nr_errors[3];
+};
+
+static int speed_down_needed_cb(struct ata_ering_entry *ent, void *void_arg)
+{
+ struct speed_down_needed_arg *arg = void_arg;
+
+ if (ent->timestamp < arg->since)
+ return -1;
+
+ arg->nr_errors[ata_eh_categorize_ering_entry(ent)]++;
+ return 0;
+}
+
+/**
+ * ata_eh_speed_down_needed - Determine wheter speed down is necessary
+ * @dev: Device of interest
+ *
+ * This function examines error ring of @dev and determines
+ * whether speed down is necessary. Speed down is necessary if
+ * there have been more than 3 of Cat-1 errors or 10 of Cat-2
+ * errors during last 15 minutes.
+ *
+ * Cat-1 errors are ATA_BUS, TIMEOUT for any command and HSM
+ * violation for known supported commands.
+ *
+ * Cat-2 errors are unclassified DEV error for known supported
+ * command.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ *
+ * RETURNS:
+ * 1 if speed down is necessary, 0 otherwise
+ */
+static int ata_eh_speed_down_needed(struct ata_device *dev)
+{
+ const u64 interval = 15LLU * 60 * HZ;
+ static const int err_limits[3] = { -1, 3, 10 };
+ struct speed_down_needed_arg arg;
+ struct ata_ering_entry *ent;
+ int err_cat;
+ u64 j64;
+
+ ent = ata_ering_top(&dev->ering);
+ if (!ent)
+ return 0;
+
+ err_cat = ata_eh_categorize_ering_entry(ent);
+ if (err_cat == 0)
+ return 0;
+
+ memset(&arg, 0, sizeof(arg));
+
+ j64 = get_jiffies_64();
+ if (j64 >= interval)
+ arg.since = j64 - interval;
+ else
+ arg.since = 0;
+
+ ata_ering_map(&dev->ering, speed_down_needed_cb, &arg);
+
+ return arg.nr_errors[err_cat] > err_limits[err_cat];
+}
+
+/**
+ * ata_eh_speed_down - record error and speed down if necessary
+ * @dev: Failed device
+ * @is_io: Did the device fail during normal IO?
+ * @err_mask: err_mask of the error
+ *
+ * Record error and examine error history to determine whether
+ * adjusting transmission speed is necessary. It also sets
+ * transmission limits appropriately if such adjustment is
+ * necessary.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise
+ */
+static int ata_eh_speed_down(struct ata_device *dev, int is_io,
+ unsigned int err_mask)
+{
+ if (!err_mask)
+ return 0;
+
+ /* record error and determine whether speed down is necessary */
+ ata_ering_record(&dev->ering, is_io, err_mask);
+
+ if (!ata_eh_speed_down_needed(dev))
+ return 0;
+
+ /* speed down SATA link speed if possible */
+ if (sata_down_spd_limit(dev->ap) == 0)
+ return ATA_EH_HARDRESET;
+
+ /* lower transfer mode */
+ if (ata_down_xfermask_limit(dev, 0) == 0)
+ return ATA_EH_SOFTRESET;
+
+ ata_dev_printk(dev, KERN_ERR,
+ "speed down requested but no transfer mode left\n");
+ return 0;
+}
+
+/**
+ * ata_eh_autopsy - analyze error and determine recovery action
+ * @ap: ATA port to perform autopsy on
+ *
+ * Analyze why @ap failed and determine which recovery action is
+ * needed. This function also sets more detailed AC_ERR_* values
+ * and fills sense data for ATAPI CHECK SENSE.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_eh_autopsy(struct ata_port *ap)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ unsigned int action = ehc->i.action;
+ struct ata_device *failed_dev = NULL;
+ unsigned int all_err_mask = 0;
+ int tag, is_io = 0;
+ u32 serror;
+ int rc;
+
+ DPRINTK("ENTER\n");
+
+ /* obtain and analyze SError */
+ rc = sata_scr_read(ap, SCR_ERROR, &serror);
+ if (rc == 0) {
+ ehc->i.serror |= serror;
+ ata_eh_analyze_serror(ap);
+ } else if (rc != -EOPNOTSUPP)
+ action |= ATA_EH_HARDRESET;
+
+ /* analyze NCQ failure */
+ ata_eh_analyze_ncq_error(ap);
+
+ /* any real error trumps AC_ERR_OTHER */
+ if (ehc->i.err_mask & ~AC_ERR_OTHER)
+ ehc->i.err_mask &= ~AC_ERR_OTHER;
+
+ all_err_mask |= ehc->i.err_mask;
+
+ for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+ struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
+
+ if (!(qc->flags & ATA_QCFLAG_FAILED))
+ continue;
+
+ /* inherit upper level err_mask */
+ qc->err_mask |= ehc->i.err_mask;
+
+ /* analyze TF */
+ action |= ata_eh_analyze_tf(qc, &qc->result_tf);
+
+ /* DEV errors are probably spurious in case of ATA_BUS error */
+ if (qc->err_mask & AC_ERR_ATA_BUS)
+ qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_MEDIA |
+ AC_ERR_INVALID);
+
+ /* any real error trumps unknown error */
+ if (qc->err_mask & ~AC_ERR_OTHER)
+ qc->err_mask &= ~AC_ERR_OTHER;
+
+ /* SENSE_VALID trumps dev/unknown error and revalidation */
+ if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
+ qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER);
+ action &= ~ATA_EH_REVALIDATE;
+ }
+
+ /* accumulate error info */
+ failed_dev = qc->dev;
+ all_err_mask |= qc->err_mask;
+ if (qc->flags & ATA_QCFLAG_IO)
+ is_io = 1;
+ }
+
+ /* enforce default EH actions */
+ if (ap->flags & ATA_FLAG_FROZEN ||
+ all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT))
+ action |= ATA_EH_SOFTRESET;
+ else if (all_err_mask)
+ action |= ATA_EH_REVALIDATE;
+
+ /* if we have offending qcs and the associated failed device */
+ if (failed_dev) {
+ /* speed down */
+ action |= ata_eh_speed_down(failed_dev, is_io, all_err_mask);
+
+ /* perform per-dev EH action only on the offending device */
+ ehc->i.dev_action[failed_dev->devno] |=
+ action & ATA_EH_PERDEV_MASK;
+ action &= ~ATA_EH_PERDEV_MASK;
+ }
+
+ /* record autopsy result */
+ ehc->i.dev = failed_dev;
+ ehc->i.action = action;
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * ata_eh_report - report error handling to user
+ * @ap: ATA port EH is going on
+ *
+ * Report EH to user.
+ *
+ * LOCKING:
+ * None.
+ */
+static void ata_eh_report(struct ata_port *ap)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ const char *frozen, *desc;
+ int tag, nr_failed = 0;
+
+ desc = NULL;
+ if (ehc->i.desc[0] != '\0')
+ desc = ehc->i.desc;
+
+ for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+ struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
+
+ if (!(qc->flags & ATA_QCFLAG_FAILED))
+ continue;
+ if (qc->flags & ATA_QCFLAG_SENSE_VALID && !qc->err_mask)
+ continue;
+
+ nr_failed++;
+ }
+
+ if (!nr_failed && !ehc->i.err_mask)
+ return;
+
+ frozen = "";
+ if (ap->flags & ATA_FLAG_FROZEN)
+ frozen = " frozen";
+
+ if (ehc->i.dev) {
+ ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x "
+ "SAct 0x%x SErr 0x%x action 0x%x%s\n",
+ ehc->i.err_mask, ap->sactive, ehc->i.serror,
+ ehc->i.action, frozen);
+ if (desc)
+ ata_dev_printk(ehc->i.dev, KERN_ERR, "(%s)\n", desc);
+ } else {
+ ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x "
+ "SAct 0x%x SErr 0x%x action 0x%x%s\n",
+ ehc->i.err_mask, ap->sactive, ehc->i.serror,
+ ehc->i.action, frozen);
+ if (desc)
+ ata_port_printk(ap, KERN_ERR, "(%s)\n", desc);
+ }
+
+ for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+ struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
+
+ if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask)
+ continue;
+
+ ata_dev_printk(qc->dev, KERN_ERR, "tag %d cmd 0x%x "
+ "Emask 0x%x stat 0x%x err 0x%x (%s)\n",
+ qc->tag, qc->tf.command, qc->err_mask,
+ qc->result_tf.command, qc->result_tf.feature,
+ ata_err_string(qc->err_mask));
+ }
+}
+
+static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
+ unsigned int *classes)
+{
+ int i, rc;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ classes[i] = ATA_DEV_UNKNOWN;
+
+ rc = reset(ap, classes);
+ if (rc)
+ return rc;
+
+ /* If any class isn't ATA_DEV_UNKNOWN, consider classification
+ * is complete and convert all ATA_DEV_UNKNOWN to
+ * ATA_DEV_NONE.
+ */
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ if (classes[i] != ATA_DEV_UNKNOWN)
+ break;
+
+ if (i < ATA_MAX_DEVICES)
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ if (classes[i] == ATA_DEV_UNKNOWN)
+ classes[i] = ATA_DEV_NONE;
+
+ return 0;
+}
+
+static int ata_eh_followup_srst_needed(int rc, int classify,
+ const unsigned int *classes)
+{
+ if (rc == -EAGAIN)
+ return 1;
+ if (rc != 0)
+ return 0;
+ if (classify && classes[0] == ATA_DEV_UNKNOWN)
+ return 1;
+ return 0;
+}
+
+static int ata_eh_reset(struct ata_port *ap, int classify,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ unsigned int *classes = ehc->classes;
+ int tries = ATA_EH_RESET_TRIES;
+ int verbose = !(ap->flags & ATA_FLAG_LOADING);
+ unsigned int action;
+ ata_reset_fn_t reset;
+ int i, did_followup_srst, rc;
+
+ /* Determine which reset to use and record in ehc->i.action.
+ * prereset() may examine and modify it.
+ */
+ action = ehc->i.action;
+ ehc->i.action &= ~ATA_EH_RESET_MASK;
+ if (softreset && (!hardreset || (!sata_set_spd_needed(ap) &&
+ !(action & ATA_EH_HARDRESET))))
+ ehc->i.action |= ATA_EH_SOFTRESET;
+ else
+ ehc->i.action |= ATA_EH_HARDRESET;
+
+ if (prereset) {
+ rc = prereset(ap);
+ if (rc) {
+ ata_port_printk(ap, KERN_ERR,
+ "prereset failed (errno=%d)\n", rc);
+ return rc;
+ }
+ }
+
+ /* prereset() might have modified ehc->i.action */
+ if (ehc->i.action & ATA_EH_HARDRESET)
+ reset = hardreset;
+ else if (ehc->i.action & ATA_EH_SOFTRESET)
+ reset = softreset;
+ else {
+ /* prereset told us not to reset, bang classes and return */
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ classes[i] = ATA_DEV_NONE;
+ return 0;
+ }
+
+ /* did prereset() screw up? if so, fix up to avoid oopsing */
+ if (!reset) {
+ ata_port_printk(ap, KERN_ERR, "BUG: prereset() requested "
+ "invalid reset type\n");
+ if (softreset)
+ reset = softreset;
+ else
+ reset = hardreset;
+ }
+
+ retry:
+ /* shut up during boot probing */
+ if (verbose)
+ ata_port_printk(ap, KERN_INFO, "%s resetting port\n",
+ reset == softreset ? "soft" : "hard");
+
+ /* reset */
+ ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
+ ehc->i.flags |= ATA_EHI_DID_RESET;
+
+ rc = ata_do_reset(ap, reset, classes);
+
+ did_followup_srst = 0;
+ if (reset == hardreset &&
+ ata_eh_followup_srst_needed(rc, classify, classes)) {
+ /* okay, let's do follow-up softreset */
+ did_followup_srst = 1;
+ reset = softreset;
+
+ if (!reset) {
+ ata_port_printk(ap, KERN_ERR,
+ "follow-up softreset required "
+ "but no softreset avaliable\n");
+ return -EINVAL;
+ }
+
+ ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
+ rc = ata_do_reset(ap, reset, classes);
+
+ if (rc == 0 && classify &&
+ classes[0] == ATA_DEV_UNKNOWN) {
+ ata_port_printk(ap, KERN_ERR,
+ "classification failed\n");
+ return -EINVAL;
+ }
+ }
+
+ if (rc && --tries) {
+ const char *type;
+
+ if (reset == softreset) {
+ if (did_followup_srst)
+ type = "follow-up soft";
+ else
+ type = "soft";
+ } else
+ type = "hard";
+
+ ata_port_printk(ap, KERN_WARNING,
+ "%sreset failed, retrying in 5 secs\n", type);
+ ssleep(5);
+
+ if (reset == hardreset)
+ sata_down_spd_limit(ap);
+ if (hardreset)
+ reset = hardreset;
+ goto retry;
+ }
+
+ if (rc == 0) {
+ /* After the reset, the device state is PIO 0 and the
+ * controller state is undefined. Record the mode.
+ */
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ ap->device[i].pio_mode = XFER_PIO_0;
+
+ if (postreset)
+ postreset(ap, classes);
+
+ /* reset successful, schedule revalidation */
+ ata_eh_done(ap, NULL, ATA_EH_RESET_MASK);
+ ehc->i.action |= ATA_EH_REVALIDATE;
+ }
+
+ return rc;
+}
+
+static int ata_eh_revalidate_and_attach(struct ata_port *ap,
+ struct ata_device **r_failed_dev)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_device *dev;
+ unsigned long flags;
+ int i, rc = 0;
+
+ DPRINTK("ENTER\n");
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ unsigned int action;
+
+ dev = &ap->device[i];
+ action = ehc->i.action | ehc->i.dev_action[dev->devno];
+
+ if (action & ATA_EH_REVALIDATE && ata_dev_enabled(dev)) {
+ if (ata_port_offline(ap)) {
+ rc = -EIO;
+ break;
+ }
+
+ ata_eh_about_to_do(ap, dev, ATA_EH_REVALIDATE);
+ rc = ata_dev_revalidate(dev,
+ ehc->i.flags & ATA_EHI_DID_RESET);
+ if (rc)
+ break;
+
+ ata_eh_done(ap, dev, ATA_EH_REVALIDATE);
+
+ /* schedule the scsi_rescan_device() here */
+ queue_work(ata_aux_wq, &(ap->scsi_rescan_task));
+ } else if (dev->class == ATA_DEV_UNKNOWN &&
+ ehc->tries[dev->devno] &&
+ ata_class_enabled(ehc->classes[dev->devno])) {
+ dev->class = ehc->classes[dev->devno];
+
+ rc = ata_dev_read_id(dev, &dev->class, 1, dev->id);
+ if (rc == 0)
+ rc = ata_dev_configure(dev, 1);
+
+ if (rc) {
+ dev->class = ATA_DEV_UNKNOWN;
+ break;
+ }
+
+ spin_lock_irqsave(ap->lock, flags);
+ ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
+ spin_unlock_irqrestore(ap->lock, flags);
+ }
+ }
+
+ if (rc)
+ *r_failed_dev = dev;
+
+ DPRINTK("EXIT\n");
+ return rc;
+}
+
+static int ata_port_nr_enabled(struct ata_port *ap)
+{
+ int i, cnt = 0;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ if (ata_dev_enabled(&ap->device[i]))
+ cnt++;
+ return cnt;
+}
+
+static int ata_port_nr_vacant(struct ata_port *ap)
+{
+ int i, cnt = 0;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ if (ap->device[i].class == ATA_DEV_UNKNOWN)
+ cnt++;
+ return cnt;
+}
+
+static int ata_eh_skip_recovery(struct ata_port *ap)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ int i;
+
+ if (ap->flags & ATA_FLAG_FROZEN || ata_port_nr_enabled(ap))
+ return 0;
+
+ /* skip if class codes for all vacant slots are ATA_DEV_NONE */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+
+ if (dev->class == ATA_DEV_UNKNOWN &&
+ ehc->classes[dev->devno] != ATA_DEV_NONE)
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * ata_eh_recover - recover host port after error
+ * @ap: host port to recover
+ * @prereset: prereset method (can be NULL)
+ * @softreset: softreset method (can be NULL)
+ * @hardreset: hardreset method (can be NULL)
+ * @postreset: postreset method (can be NULL)
+ *
+ * This is the alpha and omega, eum and yang, heart and soul of
+ * libata exception handling. On entry, actions required to
+ * recover the port and hotplug requests are recorded in
+ * eh_context. This function executes all the operations with
+ * appropriate retrials and fallbacks to resurrect failed
+ * devices, detach goners and greet newcomers.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
+ ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+ ata_postreset_fn_t postreset)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_device *dev;
+ int down_xfermask, i, rc;
+
+ DPRINTK("ENTER\n");
+
+ /* prep for recovery */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ dev = &ap->device[i];
+
+ ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
+
+ /* process hotplug request */
+ if (dev->flags & ATA_DFLAG_DETACH)
+ ata_eh_detach_dev(dev);
+
+ if (!ata_dev_enabled(dev) &&
+ ((ehc->i.probe_mask & (1 << dev->devno)) &&
+ !(ehc->did_probe_mask & (1 << dev->devno)))) {
+ ata_eh_detach_dev(dev);
+ ata_dev_init(dev);
+ ehc->did_probe_mask |= (1 << dev->devno);
+ ehc->i.action |= ATA_EH_SOFTRESET;
+ }
+ }
+
+ retry:
+ down_xfermask = 0;
+ rc = 0;
+
+ /* if UNLOADING, finish immediately */
+ if (ap->flags & ATA_FLAG_UNLOADING)
+ goto out;
+
+ /* skip EH if possible. */
+ if (ata_eh_skip_recovery(ap))
+ ehc->i.action = 0;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ ehc->classes[i] = ATA_DEV_UNKNOWN;
+
+ /* reset */
+ if (ehc->i.action & ATA_EH_RESET_MASK) {
+ ata_eh_freeze_port(ap);
+
+ rc = ata_eh_reset(ap, ata_port_nr_vacant(ap), prereset,
+ softreset, hardreset, postreset);
+ if (rc) {
+ ata_port_printk(ap, KERN_ERR,
+ "reset failed, giving up\n");
+ goto out;
+ }
+
+ ata_eh_thaw_port(ap);
+ }
+
+ /* revalidate existing devices and attach new ones */
+ rc = ata_eh_revalidate_and_attach(ap, &dev);
+ if (rc)
+ goto dev_fail;
+
+ /* configure transfer mode if the port has been reset */
+ if (ehc->i.flags & ATA_EHI_DID_RESET) {
+ rc = ata_set_mode(ap, &dev);
+ if (rc) {
+ down_xfermask = 1;
+ goto dev_fail;
+ }
+ }
+
+ goto out;
+
+ dev_fail:
+ switch (rc) {
+ case -ENODEV:
+ /* device missing, schedule probing */
+ ehc->i.probe_mask |= (1 << dev->devno);
+ case -EINVAL:
+ ehc->tries[dev->devno] = 0;
+ break;
+ case -EIO:
+ sata_down_spd_limit(ap);
+ default:
+ ehc->tries[dev->devno]--;
+ if (down_xfermask &&
+ ata_down_xfermask_limit(dev, ehc->tries[dev->devno] == 1))
+ ehc->tries[dev->devno] = 0;
+ }
+
+ if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) {
+ /* disable device if it has used up all its chances */
+ ata_dev_disable(dev);
+
+ /* detach if offline */
+ if (ata_port_offline(ap))
+ ata_eh_detach_dev(dev);
+
+ /* probe if requested */
+ if ((ehc->i.probe_mask & (1 << dev->devno)) &&
+ !(ehc->did_probe_mask & (1 << dev->devno))) {
+ ata_eh_detach_dev(dev);
+ ata_dev_init(dev);
+
+ ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
+ ehc->did_probe_mask |= (1 << dev->devno);
+ ehc->i.action |= ATA_EH_SOFTRESET;
+ }
+ } else {
+ /* soft didn't work? be haaaaard */
+ if (ehc->i.flags & ATA_EHI_DID_RESET)
+ ehc->i.action |= ATA_EH_HARDRESET;
+ else
+ ehc->i.action |= ATA_EH_SOFTRESET;
+ }
+
+ if (ata_port_nr_enabled(ap)) {
+ ata_port_printk(ap, KERN_WARNING, "failed to recover some "
+ "devices, retrying in 5 secs\n");
+ ssleep(5);
+ } else {
+ /* no device left, repeat fast */
+ msleep(500);
+ }
+
+ goto retry;
+
+ out:
+ if (rc) {
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ ata_dev_disable(&ap->device[i]);
+ }
+
+ DPRINTK("EXIT, rc=%d\n", rc);
+ return rc;
+}
+
+/**
+ * ata_eh_finish - finish up EH
+ * @ap: host port to finish EH for
+ *
+ * Recovery is complete. Clean up EH states and retry or finish
+ * failed qcs.
+ *
+ * LOCKING:
+ * None.
+ */
+static void ata_eh_finish(struct ata_port *ap)
+{
+ int tag;
+
+ /* retry or finish qcs */
+ for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+ struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
+
+ if (!(qc->flags & ATA_QCFLAG_FAILED))
+ continue;
+
+ if (qc->err_mask) {
+ /* FIXME: Once EH migration is complete,
+ * generate sense data in this function,
+ * considering both err_mask and tf.
+ */
+ if (qc->err_mask & AC_ERR_INVALID)
+ ata_eh_qc_complete(qc);
+ else
+ ata_eh_qc_retry(qc);
+ } else {
+ if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
+ ata_eh_qc_complete(qc);
+ } else {
+ /* feed zero TF to sense generation */
+ memset(&qc->result_tf, 0, sizeof(qc->result_tf));
+ ata_eh_qc_retry(qc);
+ }
+ }
+ }
+}
+
+/**
+ * ata_do_eh - do standard error handling
+ * @ap: host port to handle error for
+ * @prereset: prereset method (can be NULL)
+ * @softreset: softreset method (can be NULL)
+ * @hardreset: hardreset method (can be NULL)
+ * @postreset: postreset method (can be NULL)
+ *
+ * Perform standard error handling sequence.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
+ ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+ ata_postreset_fn_t postreset)
+{
+ if (!(ap->flags & ATA_FLAG_LOADING)) {
+ ata_eh_autopsy(ap);
+ ata_eh_report(ap);
+ }
+
+ ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
+ ata_eh_finish(ap);
+}
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index f1e129b..93d18a7 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -41,6 +41,7 @@
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_device.h>
+#include <scsi/scsi_tcq.h>
#include <scsi/scsi_transport.h>
#include <linux/libata.h>
#include <linux/hdreg.h>
@@ -51,10 +52,14 @@
#define SECTOR_SIZE 512
typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, const u8 *scsicmd);
-static struct ata_device *
-ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev);
-static void ata_scsi_error(struct Scsi_Host *host);
-enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
+
+static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
+ const struct scsi_device *scsidev);
+static struct ata_device * ata_scsi_find_dev(struct ata_port *ap,
+ const struct scsi_device *scsidev);
+static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
+ unsigned int id, unsigned int lun);
+
#define RW_RECOVERY_MPAGE 0x1
#define RW_RECOVERY_MPAGE_LEN 12
@@ -102,6 +107,7 @@ static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = {
struct scsi_transport_template ata_scsi_transport_template = {
.eh_strategy_handler = ata_scsi_error,
.eh_timed_out = ata_scsi_timed_out,
+ .user_scan = ata_scsi_user_scan,
};
@@ -304,7 +310,6 @@ int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
/**
* ata_scsi_qc_new - acquire new ata_queued_cmd reference
- * @ap: ATA port to which the new command is attached
* @dev: ATA device to which the new command is attached
* @cmd: SCSI command that originated this ATA command
* @done: SCSI command completion function
@@ -323,14 +328,13 @@ int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
* RETURNS:
* Command allocated, or %NULL if none available.
*/
-struct ata_queued_cmd *ata_scsi_qc_new(struct ata_port *ap,
- struct ata_device *dev,
+struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
struct ata_queued_cmd *qc;
- qc = ata_qc_new_init(ap, dev);
+ qc = ata_qc_new_init(dev);
if (qc) {
qc->scsicmd = cmd;
qc->scsidone = done;
@@ -397,18 +401,18 @@ void ata_dump_status(unsigned id, struct ata_taskfile *tf)
int ata_scsi_device_resume(struct scsi_device *sdev)
{
- struct ata_port *ap = (struct ata_port *) &sdev->host->hostdata[0];
- struct ata_device *dev = &ap->device[sdev->id];
+ struct ata_port *ap = ata_shost_to_port(sdev->host);
+ struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
- return ata_device_resume(ap, dev);
+ return ata_device_resume(dev);
}
int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
{
- struct ata_port *ap = (struct ata_port *) &sdev->host->hostdata[0];
- struct ata_device *dev = &ap->device[sdev->id];
+ struct ata_port *ap = ata_shost_to_port(sdev->host);
+ struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
- return ata_device_suspend(ap, dev, state);
+ return ata_device_suspend(dev, state);
}
/**
@@ -419,6 +423,7 @@ int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
* @sk: the sense key we'll fill out
* @asc: the additional sense code we'll fill out
* @ascq: the additional sense code qualifier we'll fill out
+ * @verbose: be verbose
*
* Converts an ATA error into a SCSI error. Fill out pointers to
* SK, ASC, and ASCQ bytes for later use in fixed or descriptor
@@ -428,7 +433,7 @@ int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
* spin_lock_irqsave(host_set lock)
*/
void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc,
- u8 *ascq)
+ u8 *ascq, int verbose)
{
int i;
@@ -493,8 +498,9 @@ void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc,
}
}
/* No immediate match */
- printk(KERN_WARNING "ata%u: no sense translation for "
- "error 0x%02x\n", id, drv_err);
+ if (verbose)
+ printk(KERN_WARNING "ata%u: no sense translation for "
+ "error 0x%02x\n", id, drv_err);
}
/* Fall back to interpreting status bits */
@@ -507,8 +513,9 @@ void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc,
}
}
/* No error? Undecoded? */
- printk(KERN_WARNING "ata%u: no sense translation for status: 0x%02x\n",
- id, drv_stat);
+ if (verbose)
+ printk(KERN_WARNING "ata%u: no sense translation for "
+ "status: 0x%02x\n", id, drv_stat);
/* We need a sensible error return here, which is tricky, and one
that won't cause people to do things like return a disk wrongly */
@@ -517,9 +524,10 @@ void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc,
*ascq = 0x00;
translate_done:
- printk(KERN_ERR "ata%u: translated ATA stat/err 0x%02x/%02x to "
- "SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n", id, drv_stat, drv_err,
- *sk, *asc, *ascq);
+ if (verbose)
+ printk(KERN_ERR "ata%u: translated ATA stat/err 0x%02x/%02x "
+ "to SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n",
+ id, drv_stat, drv_err, *sk, *asc, *ascq);
return;
}
@@ -539,27 +547,23 @@ void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc,
void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc)
{
struct scsi_cmnd *cmd = qc->scsicmd;
- struct ata_taskfile *tf = &qc->tf;
+ struct ata_taskfile *tf = &qc->result_tf;
unsigned char *sb = cmd->sense_buffer;
unsigned char *desc = sb + 8;
+ int verbose = qc->ap->ops->error_handler == NULL;
memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
/*
- * Read the controller registers.
- */
- WARN_ON(qc->ap->ops->tf_read == NULL);
- qc->ap->ops->tf_read(qc->ap, tf);
-
- /*
* Use ata_to_sense_error() to map status register bits
* onto sense key, asc & ascq.
*/
- if (tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
+ if (qc->err_mask ||
+ tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
ata_to_sense_error(qc->ap->id, tf->command, tf->feature,
- &sb[1], &sb[2], &sb[3]);
+ &sb[1], &sb[2], &sb[3], verbose);
sb[1] &= 0x0f;
}
@@ -615,26 +619,22 @@ void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc)
void ata_gen_fixed_sense(struct ata_queued_cmd *qc)
{
struct scsi_cmnd *cmd = qc->scsicmd;
- struct ata_taskfile *tf = &qc->tf;
+ struct ata_taskfile *tf = &qc->result_tf;
unsigned char *sb = cmd->sense_buffer;
+ int verbose = qc->ap->ops->error_handler == NULL;
memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
/*
- * Read the controller registers.
- */
- WARN_ON(qc->ap->ops->tf_read == NULL);
- qc->ap->ops->tf_read(qc->ap, tf);
-
- /*
* Use ata_to_sense_error() to map status register bits
* onto sense key, asc & ascq.
*/
- if (tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
+ if (qc->err_mask ||
+ tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
ata_to_sense_error(qc->ap->id, tf->command, tf->feature,
- &sb[2], &sb[12], &sb[13]);
+ &sb[2], &sb[12], &sb[13], verbose);
sb[2] &= 0x0f;
}
@@ -677,7 +677,7 @@ static void ata_scsi_dev_config(struct scsi_device *sdev,
*/
max_sectors = ATA_MAX_SECTORS;
if (dev->flags & ATA_DFLAG_LBA48)
- max_sectors = 2048;
+ max_sectors = ATA_MAX_SECTORS_LBA48;
if (dev->max_sectors)
max_sectors = dev->max_sectors;
@@ -692,6 +692,14 @@ static void ata_scsi_dev_config(struct scsi_device *sdev,
request_queue_t *q = sdev->request_queue;
blk_queue_max_hw_segments(q, q->max_hw_segments - 1);
}
+
+ if (dev->flags & ATA_DFLAG_NCQ) {
+ int depth;
+
+ depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id));
+ depth = min(ATA_MAX_QUEUE - 1, depth);
+ scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
+ }
}
/**
@@ -708,152 +716,88 @@ static void ata_scsi_dev_config(struct scsi_device *sdev,
int ata_scsi_slave_config(struct scsi_device *sdev)
{
+ struct ata_port *ap = ata_shost_to_port(sdev->host);
+ struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
+
ata_scsi_sdev_config(sdev);
blk_queue_max_phys_segments(sdev->request_queue, LIBATA_MAX_PRD);
- if (sdev->id < ATA_MAX_DEVICES) {
- struct ata_port *ap;
- struct ata_device *dev;
-
- ap = (struct ata_port *) &sdev->host->hostdata[0];
- dev = &ap->device[sdev->id];
-
+ if (dev)
ata_scsi_dev_config(sdev, dev);
- }
return 0; /* scsi layer doesn't check return value, sigh */
}
/**
- * ata_scsi_timed_out - SCSI layer time out callback
- * @cmd: timed out SCSI command
+ * ata_scsi_slave_destroy - SCSI device is about to be destroyed
+ * @sdev: SCSI device to be destroyed
*
- * Handles SCSI layer timeout. We race with normal completion of
- * the qc for @cmd. If the qc is already gone, we lose and let
- * the scsi command finish (EH_HANDLED). Otherwise, the qc has
- * timed out and EH should be invoked. Prevent ata_qc_complete()
- * from finishing it by setting EH_SCHEDULED and return
- * EH_NOT_HANDLED.
+ * @sdev is about to be destroyed for hot/warm unplugging. If
+ * this unplugging was initiated by libata as indicated by NULL
+ * dev->sdev, this function doesn't have to do anything.
+ * Otherwise, SCSI layer initiated warm-unplug is in progress.
+ * Clear dev->sdev, schedule the device for ATA detach and invoke
+ * EH.
*
* LOCKING:
- * Called from timer context
- *
- * RETURNS:
- * EH_HANDLED or EH_NOT_HANDLED
+ * Defined by SCSI layer. We don't really care.
*/
-enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
+void ata_scsi_slave_destroy(struct scsi_device *sdev)
{
- struct Scsi_Host *host = cmd->device->host;
- struct ata_port *ap = (struct ata_port *) &host->hostdata[0];
+ struct ata_port *ap = ata_shost_to_port(sdev->host);
unsigned long flags;
- struct ata_queued_cmd *qc;
- enum scsi_eh_timer_return ret = EH_HANDLED;
+ struct ata_device *dev;
- DPRINTK("ENTER\n");
+ if (!ap->ops->error_handler)
+ return;
- spin_lock_irqsave(&ap->host_set->lock, flags);
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc) {
- WARN_ON(qc->scsicmd != cmd);
- qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
- qc->err_mask |= AC_ERR_TIMEOUT;
- ret = EH_NOT_HANDLED;
+ spin_lock_irqsave(ap->lock, flags);
+ dev = __ata_scsi_find_dev(ap, sdev);
+ if (dev && dev->sdev) {
+ /* SCSI device already in CANCEL state, no need to offline it */
+ dev->sdev = NULL;
+ dev->flags |= ATA_DFLAG_DETACH;
+ ata_port_schedule_eh(ap);
}
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
-
- DPRINTK("EXIT, ret=%d\n", ret);
- return ret;
+ spin_unlock_irqrestore(ap->lock, flags);
}
/**
- * ata_scsi_error - SCSI layer error handler callback
- * @host: SCSI host on which error occurred
+ * ata_scsi_change_queue_depth - SCSI callback for queue depth config
+ * @sdev: SCSI device to configure queue depth for
+ * @queue_depth: new queue depth
*
- * Handles SCSI-layer-thrown error events.
+ * This is libata standard hostt->change_queue_depth callback.
+ * SCSI will call into this callback when user tries to set queue
+ * depth via sysfs.
*
* LOCKING:
- * Inherited from SCSI layer (none, can sleep)
+ * SCSI layer (we don't care)
+ *
+ * RETURNS:
+ * Newly configured queue depth.
*/
-
-static void ata_scsi_error(struct Scsi_Host *host)
+int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
{
- struct ata_port *ap;
- unsigned long flags;
-
- DPRINTK("ENTER\n");
-
- ap = (struct ata_port *) &host->hostdata[0];
-
- spin_lock_irqsave(&ap->host_set->lock, flags);
- WARN_ON(ap->flags & ATA_FLAG_IN_EH);
- ap->flags |= ATA_FLAG_IN_EH;
- WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
-
- ata_port_flush_task(ap);
-
- ap->ops->eng_timeout(ap);
-
- WARN_ON(host->host_failed || !list_empty(&host->eh_cmd_q));
-
- scsi_eh_flush_done_q(&ap->eh_done_q);
-
- spin_lock_irqsave(&ap->host_set->lock, flags);
- ap->flags &= ~ATA_FLAG_IN_EH;
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
-
- DPRINTK("EXIT\n");
-}
-
-static void ata_eh_scsidone(struct scsi_cmnd *scmd)
-{
- /* nada */
-}
-
-static void __ata_eh_qc_complete(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct scsi_cmnd *scmd = qc->scsicmd;
- unsigned long flags;
+ struct ata_port *ap = ata_shost_to_port(sdev->host);
+ struct ata_device *dev;
+ int max_depth;
- spin_lock_irqsave(&ap->host_set->lock, flags);
- qc->scsidone = ata_eh_scsidone;
- __ata_qc_complete(qc);
- WARN_ON(ata_tag_valid(qc->tag));
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ if (queue_depth < 1)
+ return sdev->queue_depth;
- scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
-}
+ dev = ata_scsi_find_dev(ap, sdev);
+ if (!dev || !ata_dev_enabled(dev))
+ return sdev->queue_depth;
-/**
- * ata_eh_qc_complete - Complete an active ATA command from EH
- * @qc: Command to complete
- *
- * Indicate to the mid and upper layers that an ATA command has
- * completed. To be used from EH.
- */
-void ata_eh_qc_complete(struct ata_queued_cmd *qc)
-{
- struct scsi_cmnd *scmd = qc->scsicmd;
- scmd->retries = scmd->allowed;
- __ata_eh_qc_complete(qc);
-}
+ max_depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id));
+ max_depth = min(ATA_MAX_QUEUE - 1, max_depth);
+ if (queue_depth > max_depth)
+ queue_depth = max_depth;
-/**
- * ata_eh_qc_retry - Tell midlayer to retry an ATA command after EH
- * @qc: Command to retry
- *
- * Indicate to the mid and upper layers that an ATA command
- * should be retried. To be used from EH.
- *
- * SCSI midlayer limits the number of retries to scmd->allowed.
- * This function might need to adjust scmd->retries for commands
- * which get retried due to unrelated NCQ failures.
- */
-void ata_eh_qc_retry(struct ata_queued_cmd *qc)
-{
- __ata_eh_qc_complete(qc);
+ scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth);
+ return queue_depth;
}
/**
@@ -891,7 +835,7 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc,
tf->nsect = 1; /* 1 sector, lba=0 */
if (qc->dev->flags & ATA_DFLAG_LBA) {
- qc->tf.flags |= ATA_TFLAG_LBA;
+ tf->flags |= ATA_TFLAG_LBA;
tf->lbah = 0x0;
tf->lbam = 0x0;
@@ -1195,6 +1139,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
u64 block;
u32 n_block;
+ qc->flags |= ATA_QCFLAG_IO;
tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 ||
@@ -1241,7 +1186,36 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
*/
goto nothing_to_do;
- if (dev->flags & ATA_DFLAG_LBA) {
+ if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) {
+ /* yay, NCQ */
+ if (!lba_48_ok(block, n_block))
+ goto out_of_range;
+
+ tf->protocol = ATA_PROT_NCQ;
+ tf->flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
+
+ if (tf->flags & ATA_TFLAG_WRITE)
+ tf->command = ATA_CMD_FPDMA_WRITE;
+ else
+ tf->command = ATA_CMD_FPDMA_READ;
+
+ qc->nsect = n_block;
+
+ tf->nsect = qc->tag << 3;
+ tf->hob_feature = (n_block >> 8) & 0xff;
+ tf->feature = n_block & 0xff;
+
+ tf->hob_lbah = (block >> 40) & 0xff;
+ tf->hob_lbam = (block >> 32) & 0xff;
+ tf->hob_lbal = (block >> 24) & 0xff;
+ tf->lbah = (block >> 16) & 0xff;
+ tf->lbam = (block >> 8) & 0xff;
+ tf->lbal = block & 0xff;
+
+ tf->device = 1 << 6;
+ if (tf->flags & ATA_TFLAG_FUA)
+ tf->device |= 1 << 7;
+ } else if (dev->flags & ATA_DFLAG_LBA) {
tf->flags |= ATA_TFLAG_LBA;
if (lba_28_ok(block, n_block)) {
@@ -1332,6 +1306,17 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
u8 *cdb = cmd->cmnd;
int need_sense = (qc->err_mask != 0);
+ /* We snoop the SET_FEATURES - Write Cache ON/OFF command, and
+ * schedule EH_REVALIDATE operation to update the IDENTIFY DEVICE
+ * cache
+ */
+ if (!need_sense && (qc->tf.command == ATA_CMD_SET_FEATURES) &&
+ ((qc->tf.feature == SETFEATURES_WC_ON) ||
+ (qc->tf.feature == SETFEATURES_WC_OFF))) {
+ qc->ap->eh_info.action |= ATA_EH_REVALIDATE;
+ ata_port_schedule_eh(qc->ap);
+ }
+
/* For ATA pass thru (SAT) commands, generate a sense block if
* user mandated it or if there's an error. Note that if we
* generate because the user forced us to, a check condition
@@ -1356,10 +1341,8 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
}
}
- if (need_sense) {
- /* The ata_gen_..._sense routines fill in tf */
- ata_dump_status(qc->ap->id, &qc->tf);
- }
+ if (need_sense && !qc->ap->ops->error_handler)
+ ata_dump_status(qc->ap->id, &qc->result_tf);
qc->scsidone(cmd);
@@ -1367,8 +1350,40 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
}
/**
+ * ata_scmd_need_defer - Check whether we need to defer scmd
+ * @dev: ATA device to which the command is addressed
+ * @is_io: Is the command IO (and thus possibly NCQ)?
+ *
+ * NCQ and non-NCQ commands cannot run together. As upper layer
+ * only knows the queue depth, we are responsible for maintaining
+ * exclusion. This function checks whether a new command can be
+ * issued to @dev.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host_set lock)
+ *
+ * RETURNS:
+ * 1 if deferring is needed, 0 otherwise.
+ */
+static int ata_scmd_need_defer(struct ata_device *dev, int is_io)
+{
+ struct ata_port *ap = dev->ap;
+
+ if (!(dev->flags & ATA_DFLAG_NCQ))
+ return 0;
+
+ if (is_io) {
+ if (!ata_tag_valid(ap->active_tag))
+ return 0;
+ } else {
+ if (!ata_tag_valid(ap->active_tag) && !ap->sactive)
+ return 0;
+ }
+ return 1;
+}
+
+/**
* ata_scsi_translate - Translate then issue SCSI command to ATA device
- * @ap: ATA port to which the command is addressed
* @dev: ATA device to which the command is addressed
* @cmd: SCSI command to execute
* @done: SCSI command completion function
@@ -1389,19 +1404,25 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
*
* LOCKING:
* spin_lock_irqsave(host_set lock)
+ *
+ * RETURNS:
+ * 0 on success, SCSI_ML_QUEUE_DEVICE_BUSY if the command
+ * needs to be deferred.
*/
-
-static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev,
- struct scsi_cmnd *cmd,
+static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *),
ata_xlat_func_t xlat_func)
{
struct ata_queued_cmd *qc;
u8 *scsicmd = cmd->cmnd;
+ int is_io = xlat_func == ata_scsi_rw_xlat;
VPRINTK("ENTER\n");
- qc = ata_scsi_qc_new(ap, dev, cmd, done);
+ if (unlikely(ata_scmd_need_defer(dev, is_io)))
+ goto defer;
+
+ qc = ata_scsi_qc_new(dev, cmd, done);
if (!qc)
goto err_mem;
@@ -1409,8 +1430,8 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev,
if (cmd->sc_data_direction == DMA_FROM_DEVICE ||
cmd->sc_data_direction == DMA_TO_DEVICE) {
if (unlikely(cmd->request_bufflen < 1)) {
- printk(KERN_WARNING "ata%u(%u): WARNING: zero len r/w req\n",
- ap->id, dev->devno);
+ ata_dev_printk(dev, KERN_WARNING,
+ "WARNING: zero len r/w req\n");
goto err_did;
}
@@ -1432,13 +1453,13 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev,
ata_qc_issue(qc);
VPRINTK("EXIT\n");
- return;
+ return 0;
early_finish:
ata_qc_free(qc);
done(cmd);
DPRINTK("EXIT - early finish (good or error)\n");
- return;
+ return 0;
err_did:
ata_qc_free(qc);
@@ -1446,7 +1467,11 @@ err_mem:
cmd->result = (DID_ERROR << 16);
done(cmd);
DPRINTK("EXIT - internal\n");
- return;
+ return 0;
+
+defer:
+ DPRINTK("EXIT - defer\n");
+ return SCSI_MLQUEUE_DEVICE_BUSY;
}
/**
@@ -1944,7 +1969,7 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
return 0;
dpofua = 0;
- if (ata_dev_supports_fua(args->id) && dev->flags & ATA_DFLAG_LBA48 &&
+ if (ata_dev_supports_fua(args->id) && (dev->flags & ATA_DFLAG_LBA48) &&
(!(dev->flags & ATA_DFLAG_PIO) || dev->multi_count))
dpofua = 1 << 4;
@@ -2137,13 +2162,14 @@ void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8
static void atapi_sense_complete(struct ata_queued_cmd *qc)
{
- if (qc->err_mask && ((qc->err_mask & AC_ERR_DEV) == 0))
+ if (qc->err_mask && ((qc->err_mask & AC_ERR_DEV) == 0)) {
/* FIXME: not quite right; we don't want the
* translation of taskfile registers into
* a sense descriptors, since that's only
* correct for ATA, not ATAPI
*/
ata_gen_ata_desc_sense(qc);
+ }
qc->scsidone(qc->scsicmd);
ata_qc_free(qc);
@@ -2207,21 +2233,38 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
VPRINTK("ENTER, err_mask 0x%X\n", err_mask);
+ /* handle completion from new EH */
+ if (unlikely(qc->ap->ops->error_handler &&
+ (err_mask || qc->flags & ATA_QCFLAG_SENSE_VALID))) {
+
+ if (!(qc->flags & ATA_QCFLAG_SENSE_VALID)) {
+ /* FIXME: not quite right; we don't want the
+ * translation of taskfile registers into a
+ * sense descriptors, since that's only
+ * correct for ATA, not ATAPI
+ */
+ ata_gen_ata_desc_sense(qc);
+ }
+
+ qc->scsicmd->result = SAM_STAT_CHECK_CONDITION;
+ qc->scsidone(cmd);
+ ata_qc_free(qc);
+ return;
+ }
+
+ /* successful completion or old EH failure path */
if (unlikely(err_mask & AC_ERR_DEV)) {
cmd->result = SAM_STAT_CHECK_CONDITION;
atapi_request_sense(qc);
return;
- }
-
- else if (unlikely(err_mask))
+ } else if (unlikely(err_mask)) {
/* FIXME: not quite right; we don't want the
* translation of taskfile registers into
* a sense descriptors, since that's only
* correct for ATA, not ATAPI
*/
ata_gen_ata_desc_sense(qc);
-
- else {
+ } else {
u8 *scsicmd = cmd->cmnd;
if ((scsicmd[0] == INQUIRY) && ((scsicmd[1] & 0x03) == 0)) {
@@ -2303,11 +2346,9 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
qc->tf.protocol = ATA_PROT_ATAPI_DMA;
qc->tf.feature |= ATAPI_PKT_DMA;
-#ifdef ATAPI_ENABLE_DMADIR
- /* some SATA bridges need us to indicate data xfer direction */
- if (cmd->sc_data_direction != DMA_TO_DEVICE)
+ if (atapi_dmadir && (cmd->sc_data_direction != DMA_TO_DEVICE))
+ /* some SATA bridges need us to indicate data xfer direction */
qc->tf.feature |= ATAPI_DMADIR;
-#endif
}
qc->nbytes = cmd->request_bufflen;
@@ -2315,6 +2356,53 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
return 0;
}
+static struct ata_device * ata_find_dev(struct ata_port *ap, int id)
+{
+ if (likely(id < ATA_MAX_DEVICES))
+ return &ap->device[id];
+ return NULL;
+}
+
+static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
+ const struct scsi_device *scsidev)
+{
+ /* skip commands not addressed to targets we simulate */
+ if (unlikely(scsidev->channel || scsidev->lun))
+ return NULL;
+
+ return ata_find_dev(ap, scsidev->id);
+}
+
+/**
+ * ata_scsi_dev_enabled - determine if device is enabled
+ * @dev: ATA device
+ *
+ * Determine if commands should be sent to the specified device.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host_set lock)
+ *
+ * RETURNS:
+ * 0 if commands are not allowed / 1 if commands are allowed
+ */
+
+static int ata_scsi_dev_enabled(struct ata_device *dev)
+{
+ if (unlikely(!ata_dev_enabled(dev)))
+ return 0;
+
+ if (!atapi_enabled || (dev->ap->flags & ATA_FLAG_NO_ATAPI)) {
+ if (unlikely(dev->class == ATA_DEV_ATAPI)) {
+ ata_dev_printk(dev, KERN_WARNING,
+ "WARNING: ATAPI is %s, device ignored.\n",
+ atapi_enabled ? "not supported with this driver" : "disabled");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
/**
* ata_scsi_find_dev - lookup ata_device from scsi_cmnd
* @ap: ATA port to which the device is attached
@@ -2331,33 +2419,14 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
* RETURNS:
* Associated ATA device, or %NULL if not found.
*/
-
static struct ata_device *
ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev)
{
- struct ata_device *dev;
+ struct ata_device *dev = __ata_scsi_find_dev(ap, scsidev);
- /* skip commands not addressed to targets we simulate */
- if (likely(scsidev->id < ATA_MAX_DEVICES))
- dev = &ap->device[scsidev->id];
- else
+ if (unlikely(!dev || !ata_scsi_dev_enabled(dev)))
return NULL;
- if (unlikely((scsidev->channel != 0) ||
- (scsidev->lun != 0)))
- return NULL;
-
- if (unlikely(!ata_dev_present(dev)))
- return NULL;
-
- if (!atapi_enabled || (ap->flags & ATA_FLAG_NO_ATAPI)) {
- if (unlikely(dev->class == ATA_DEV_ATAPI)) {
- printk(KERN_WARNING "ata%u(%u): WARNING: ATAPI is %s, device ignored.\n",
- ap->id, dev->devno, atapi_enabled ? "not supported with this driver" : "disabled");
- return NULL;
- }
- }
-
return dev;
}
@@ -2414,10 +2483,15 @@ ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd)
{
struct ata_taskfile *tf = &(qc->tf);
struct scsi_cmnd *cmd = qc->scsicmd;
+ struct ata_device *dev = qc->dev;
if ((tf->protocol = ata_scsi_map_proto(scsicmd[1])) == ATA_PROT_UNKNOWN)
goto invalid_fld;
+ /* We may not issue DMA commands if no DMA mode is set */
+ if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0)
+ goto invalid_fld;
+
if (scsicmd[1] & 0xe0)
/* PIO multi not supported yet */
goto invalid_fld;
@@ -2502,6 +2576,9 @@ ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd)
*/
qc->nsect = cmd->request_bufflen / ATA_SECT_SIZE;
+ /* request result TF */
+ qc->flags |= ATA_QCFLAG_RESULT_TF;
+
return 0;
invalid_fld:
@@ -2578,19 +2655,24 @@ static inline void ata_scsi_dump_cdb(struct ata_port *ap,
#endif
}
-static inline void __ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
- struct ata_port *ap, struct ata_device *dev)
+static inline int __ata_scsi_queuecmd(struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *),
+ struct ata_device *dev)
{
+ int rc = 0;
+
if (dev->class == ATA_DEV_ATA) {
ata_xlat_func_t xlat_func = ata_get_xlat_func(dev,
cmd->cmnd[0]);
if (xlat_func)
- ata_scsi_translate(ap, dev, cmd, done, xlat_func);
+ rc = ata_scsi_translate(dev, cmd, done, xlat_func);
else
- ata_scsi_simulate(ap, dev, cmd, done);
+ ata_scsi_simulate(dev, cmd, done);
} else
- ata_scsi_translate(ap, dev, cmd, done, atapi_xlat);
+ rc = ata_scsi_translate(dev, cmd, done, atapi_xlat);
+
+ return rc;
}
/**
@@ -2609,39 +2691,39 @@ static inline void __ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struc
* Releases scsi-layer-held lock, and obtains host_set lock.
*
* RETURNS:
- * Zero.
+ * Return value from __ata_scsi_queuecmd() if @cmd can be queued,
+ * 0 otherwise.
*/
-
int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct ata_port *ap;
struct ata_device *dev;
struct scsi_device *scsidev = cmd->device;
struct Scsi_Host *shost = scsidev->host;
+ int rc = 0;
- ap = (struct ata_port *) &shost->hostdata[0];
+ ap = ata_shost_to_port(shost);
spin_unlock(shost->host_lock);
- spin_lock(&ap->host_set->lock);
+ spin_lock(ap->lock);
ata_scsi_dump_cdb(ap, cmd);
dev = ata_scsi_find_dev(ap, scsidev);
if (likely(dev))
- __ata_scsi_queuecmd(cmd, done, ap, dev);
+ rc = __ata_scsi_queuecmd(cmd, done, dev);
else {
cmd->result = (DID_BAD_TARGET << 16);
done(cmd);
}
- spin_unlock(&ap->host_set->lock);
+ spin_unlock(ap->lock);
spin_lock(shost->host_lock);
- return 0;
+ return rc;
}
/**
* ata_scsi_simulate - simulate SCSI command on ATA device
- * @ap: port the device is connected to
* @dev: the target device
* @cmd: SCSI command being sent to device.
* @done: SCSI command completion function.
@@ -2653,14 +2735,12 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
* spin_lock_irqsave(host_set lock)
*/
-void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev,
- struct scsi_cmnd *cmd,
+void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
struct ata_scsi_args args;
const u8 *scsicmd = cmd->cmnd;
- args.ap = ap;
args.dev = dev;
args.id = dev->id;
args.cmd = cmd;
@@ -2732,17 +2812,241 @@ void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev,
void ata_scsi_scan_host(struct ata_port *ap)
{
- struct ata_device *dev;
unsigned int i;
- if (ap->flags & ATA_FLAG_PORT_DISABLED)
+ if (ap->flags & ATA_FLAG_DISABLED)
return;
for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
+ struct ata_device *dev = &ap->device[i];
+ struct scsi_device *sdev;
- if (ata_dev_present(dev))
- scsi_scan_target(&ap->host->shost_gendev, 0, i, 0, 0);
+ if (!ata_dev_enabled(dev) || dev->sdev)
+ continue;
+
+ sdev = __scsi_add_device(ap->host, 0, i, 0, NULL);
+ if (!IS_ERR(sdev)) {
+ dev->sdev = sdev;
+ scsi_device_put(sdev);
+ }
+ }
+}
+
+/**
+ * ata_scsi_offline_dev - offline attached SCSI device
+ * @dev: ATA device to offline attached SCSI device for
+ *
+ * This function is called from ata_eh_hotplug() and responsible
+ * for taking the SCSI device attached to @dev offline. This
+ * function is called with host_set lock which protects dev->sdev
+ * against clearing.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host_set lock)
+ *
+ * RETURNS:
+ * 1 if attached SCSI device exists, 0 otherwise.
+ */
+int ata_scsi_offline_dev(struct ata_device *dev)
+{
+ if (dev->sdev) {
+ scsi_device_set_state(dev->sdev, SDEV_OFFLINE);
+ return 1;
}
+ return 0;
}
+/**
+ * ata_scsi_remove_dev - remove attached SCSI device
+ * @dev: ATA device to remove attached SCSI device for
+ *
+ * This function is called from ata_eh_scsi_hotplug() and
+ * responsible for removing the SCSI device attached to @dev.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_scsi_remove_dev(struct ata_device *dev)
+{
+ struct ata_port *ap = dev->ap;
+ struct scsi_device *sdev;
+ unsigned long flags;
+
+ /* Alas, we need to grab scan_mutex to ensure SCSI device
+ * state doesn't change underneath us and thus
+ * scsi_device_get() always succeeds. The mutex locking can
+ * be removed if there is __scsi_device_get() interface which
+ * increments reference counts regardless of device state.
+ */
+ mutex_lock(&ap->host->scan_mutex);
+ spin_lock_irqsave(ap->lock, flags);
+
+ /* clearing dev->sdev is protected by host_set lock */
+ sdev = dev->sdev;
+ dev->sdev = NULL;
+
+ if (sdev) {
+ /* If user initiated unplug races with us, sdev can go
+ * away underneath us after the host_set lock and
+ * scan_mutex are released. Hold onto it.
+ */
+ if (scsi_device_get(sdev) == 0) {
+ /* The following ensures the attached sdev is
+ * offline on return from ata_scsi_offline_dev()
+ * regardless it wins or loses the race
+ * against this function.
+ */
+ scsi_device_set_state(sdev, SDEV_OFFLINE);
+ } else {
+ WARN_ON(1);
+ sdev = NULL;
+ }
+ }
+
+ spin_unlock_irqrestore(ap->lock, flags);
+ mutex_unlock(&ap->host->scan_mutex);
+
+ if (sdev) {
+ ata_dev_printk(dev, KERN_INFO, "detaching (SCSI %s)\n",
+ sdev->sdev_gendev.bus_id);
+
+ scsi_remove_device(sdev);
+ scsi_device_put(sdev);
+ }
+}
+
+/**
+ * ata_scsi_hotplug - SCSI part of hotplug
+ * @data: Pointer to ATA port to perform SCSI hotplug on
+ *
+ * Perform SCSI part of hotplug. It's executed from a separate
+ * workqueue after EH completes. This is necessary because SCSI
+ * hot plugging requires working EH and hot unplugging is
+ * synchronized with hot plugging with a mutex.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+void ata_scsi_hotplug(void *data)
+{
+ struct ata_port *ap = data;
+ int i;
+
+ if (ap->flags & ATA_FLAG_UNLOADING) {
+ DPRINTK("ENTER/EXIT - unloading\n");
+ return;
+ }
+
+ DPRINTK("ENTER\n");
+
+ /* unplug detached devices */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+ unsigned long flags;
+
+ if (!(dev->flags & ATA_DFLAG_DETACHED))
+ continue;
+
+ spin_lock_irqsave(ap->lock, flags);
+ dev->flags &= ~ATA_DFLAG_DETACHED;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_scsi_remove_dev(dev);
+ }
+
+ /* scan for new ones */
+ ata_scsi_scan_host(ap);
+
+ /* If we scanned while EH was in progress, scan would have
+ * failed silently. Requeue if there are enabled but
+ * unattached devices.
+ */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+ if (ata_dev_enabled(dev) && !dev->sdev) {
+ queue_delayed_work(ata_aux_wq, &ap->hotplug_task, HZ);
+ break;
+ }
+ }
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * ata_scsi_user_scan - indication for user-initiated bus scan
+ * @shost: SCSI host to scan
+ * @channel: Channel to scan
+ * @id: ID to scan
+ * @lun: LUN to scan
+ *
+ * This function is called when user explicitly requests bus
+ * scan. Set probe pending flag and invoke EH.
+ *
+ * LOCKING:
+ * SCSI layer (we don't care)
+ *
+ * RETURNS:
+ * Zero.
+ */
+static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
+ unsigned int id, unsigned int lun)
+{
+ struct ata_port *ap = ata_shost_to_port(shost);
+ unsigned long flags;
+ int rc = 0;
+
+ if (!ap->ops->error_handler)
+ return -EOPNOTSUPP;
+
+ if ((channel != SCAN_WILD_CARD && channel != 0) ||
+ (lun != SCAN_WILD_CARD && lun != 0))
+ return -EINVAL;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ if (id == SCAN_WILD_CARD) {
+ ap->eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
+ ap->eh_info.action |= ATA_EH_SOFTRESET;
+ } else {
+ struct ata_device *dev = ata_find_dev(ap, id);
+
+ if (dev) {
+ ap->eh_info.probe_mask |= 1 << dev->devno;
+ ap->eh_info.action |= ATA_EH_SOFTRESET;
+ } else
+ rc = -EINVAL;
+ }
+
+ if (rc == 0)
+ ata_port_schedule_eh(ap);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ return rc;
+}
+
+/**
+ * ata_scsi_dev_rescan - initiate scsi_rescan_device()
+ * @data: Pointer to ATA port to perform scsi_rescan_device()
+ *
+ * After ATA pass thru (SAT) commands are executed successfully,
+ * libata need to propagate the changes to SCSI layer. This
+ * function must be executed from ata_aux_wq such that sdev
+ * attach/detach don't race with rescan.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+void ata_scsi_dev_rescan(void *data)
+{
+ struct ata_port *ap = data;
+ struct ata_device *dev;
+ unsigned int i;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ dev = &ap->device[i];
+
+ if (ata_dev_enabled(dev) && dev->sdev)
+ scsi_rescan_device(&(dev->sdev->sdev_gendev));
+ }
+}
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index bac8cba..bdd4888 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -29,10 +29,9 @@
#define __LIBATA_H__
#define DRV_NAME "libata"
-#define DRV_VERSION "1.20" /* must be exactly four chars */
+#define DRV_VERSION "1.30" /* must be exactly four chars */
struct ata_scsi_args {
- struct ata_port *ap;
struct ata_device *dev;
u16 *id;
struct scsi_cmnd *cmd;
@@ -40,18 +39,32 @@ struct ata_scsi_args {
};
/* libata-core.c */
+extern struct workqueue_struct *ata_aux_wq;
extern int atapi_enabled;
+extern int atapi_dmadir;
extern int libata_fua;
-extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
- struct ata_device *dev);
+extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev);
extern int ata_rwcmd_protocol(struct ata_queued_cmd *qc);
+extern void ata_dev_disable(struct ata_device *dev);
extern void ata_port_flush_task(struct ata_port *ap);
+extern unsigned ata_exec_internal(struct ata_device *dev,
+ struct ata_taskfile *tf, const u8 *cdb,
+ int dma_dir, void *buf, unsigned int buflen);
+extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
+ int post_reset, u16 *id);
+extern int ata_dev_configure(struct ata_device *dev, int print_info);
+extern int sata_down_spd_limit(struct ata_port *ap);
+extern int sata_set_spd_needed(struct ata_port *ap);
+extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0);
+extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev);
extern void ata_qc_free(struct ata_queued_cmd *qc);
extern void ata_qc_issue(struct ata_queued_cmd *qc);
+extern void __ata_qc_complete(struct ata_queued_cmd *qc);
extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
extern void ata_dev_select(struct ata_port *ap, unsigned int device,
unsigned int wait, unsigned int can_sleep);
extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
+extern void ata_dev_init(struct ata_device *dev);
extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
@@ -60,6 +73,8 @@ extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
extern struct scsi_transport_template ata_scsi_transport_template;
extern void ata_scsi_scan_host(struct ata_port *ap);
+extern int ata_scsi_offline_dev(struct ata_device *dev);
+extern void ata_scsi_hotplug(void *data);
extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
unsigned int buflen);
@@ -88,5 +103,13 @@ extern void ata_scsi_set_sense(struct scsi_cmnd *cmd,
extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
unsigned int (*actor) (struct ata_scsi_args *args,
u8 *rbuf, unsigned int buflen));
+extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
+extern void ata_scsi_dev_rescan(void *data);
+
+/* libata-eh.c */
+extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
+extern void ata_scsi_error(struct Scsi_Host *host);
+extern void ata_port_wait_eh(struct ata_port *ap);
+extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
#endif /* __LIBATA_H__ */
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
index e31fadd6..118206d 100644
--- a/drivers/scsi/mac_esp.c
+++ b/drivers/scsi/mac_esp.c
@@ -43,9 +43,6 @@
/* #define DEBUG_MAC_ESP */
-#define mac_turnon_irq(x) mac_enable_irq(x)
-#define mac_turnoff_irq(x) mac_disable_irq(x)
-
extern void esp_handle(struct NCR_ESP *esp);
extern void mac_esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
@@ -639,13 +636,13 @@ static void dma_init_write(struct NCR_ESP * esp, char * vaddress, int length)
static void dma_ints_off(struct NCR_ESP * esp)
{
- mac_turnoff_irq(esp->irq);
+ disable_irq(esp->irq);
}
static void dma_ints_on(struct NCR_ESP * esp)
{
- mac_turnon_irq(esp->irq);
+ enable_irq(esp->irq);
}
/*
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index 777f9bc..a942a21 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -65,9 +65,6 @@
#define RESET_BOOT
#define DRIVER_SETUP
-#define ENABLE_IRQ() mac_enable_irq( IRQ_MAC_SCSI );
-#define DISABLE_IRQ() mac_disable_irq( IRQ_MAC_SCSI );
-
extern void via_scsi_clear(void);
#ifdef RESET_BOOT
@@ -351,7 +348,7 @@ static void mac_scsi_reset_boot(struct Scsi_Host *instance)
printk(KERN_INFO "Macintosh SCSI: resetting the SCSI bus..." );
/* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
- mac_disable_irq(IRQ_MAC_SCSI);
+ disable_irq(IRQ_MAC_SCSI);
/* get in phase */
NCR5380_write( TARGET_COMMAND_REG,
@@ -369,7 +366,7 @@ static void mac_scsi_reset_boot(struct Scsi_Host *instance)
barrier();
/* switch on SCSI IRQ again */
- mac_enable_irq(IRQ_MAC_SCSI);
+ enable_irq(IRQ_MAC_SCSI);
printk(KERN_INFO " done\n" );
}
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index c33857e..5d2cefb 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -1828,7 +1828,7 @@ mega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len)
scb->dma_type = MEGA_SGLIST;
- if( sgcnt > adapter->sglen ) BUG();
+ BUG_ON(sgcnt > adapter->sglen);
*len = 0;
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index bec1424..b7caf60 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -714,7 +714,7 @@ megaraid_io_detach(adapter_t *adapter)
* . Allocate memory required for all the commands
* . Use internal library of FW routines, build up complete soft state
*/
-static int __init
+static int __devinit
megaraid_init_mbox(adapter_t *adapter)
{
struct pci_dev *pdev;
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index ce0ba3a..4a2fed3 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -4724,7 +4724,7 @@ err_out:
/* Flush the tape buffer before close */
-static int os_scsi_tape_flush(struct file * filp)
+static int os_scsi_tape_flush(struct file * filp, fl_owner_t id)
{
int result = 0, result2;
struct osst_tape * STp = filp->private_data;
diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c
index 5cda16c..7ebe8e0 100644
--- a/drivers/scsi/pdc_adma.c
+++ b/drivers/scsi/pdc_adma.c
@@ -46,7 +46,7 @@
#include <linux/libata.h>
#define DRV_NAME "pdc_adma"
-#define DRV_VERSION "0.03"
+#define DRV_VERSION "0.04"
/* macro to calculate base address for ATA regs */
#define ADMA_ATA_REGS(base,port_no) ((base) + ((port_no) * 0x40))
@@ -152,6 +152,7 @@ static struct scsi_host_template adma_ata_sht = {
.proc_name = DRV_NAME,
.dma_boundary = ADMA_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
};
@@ -167,6 +168,7 @@ static const struct ata_port_operations adma_ata_ops = {
.qc_prep = adma_qc_prep,
.qc_issue = adma_qc_issue,
.eng_timeout = adma_eng_timeout,
+ .data_xfer = ata_mmio_data_xfer,
.irq_handler = adma_intr,
.irq_clear = adma_irq_clear,
.port_start = adma_port_start,
@@ -455,13 +457,13 @@ static inline unsigned int adma_intr_pkt(struct ata_host_set *host_set)
continue;
handled = 1;
adma_enter_reg_mode(ap);
- if (ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))
+ if (ap->flags & ATA_FLAG_DISABLED)
continue;
pp = ap->private_data;
if (!pp || pp->state != adma_state_pkt)
continue;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
if ((status & (aPERR | aPSD | aUIRQ)))
qc->err_mask |= AC_ERR_OTHER;
else if (pp->pkt[0] != cDONE)
@@ -480,13 +482,13 @@ static inline unsigned int adma_intr_mmio(struct ata_host_set *host_set)
for (port_no = 0; port_no < host_set->n_ports; ++port_no) {
struct ata_port *ap;
ap = host_set->ports[port_no];
- if (ap && (!(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR)))) {
+ if (ap && (!(ap->flags & ATA_FLAG_DISABLED))) {
struct ata_queued_cmd *qc;
struct adma_port_priv *pp = ap->private_data;
if (!pp || pp->state != adma_state_mmio)
continue;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
/* check main status, clearing INTRQ */
u8 status = ata_check_status(ap);
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 77bb235..680f606 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -397,30 +397,6 @@
#include "ql1280_fw.h"
#include "ql1040_fw.h"
-
-/*
- * Missing PCI ID's
- */
-#ifndef PCI_DEVICE_ID_QLOGIC_ISP1080
-#define PCI_DEVICE_ID_QLOGIC_ISP1080 0x1080
-#endif
-#ifndef PCI_DEVICE_ID_QLOGIC_ISP1240
-#define PCI_DEVICE_ID_QLOGIC_ISP1240 0x1240
-#endif
-#ifndef PCI_DEVICE_ID_QLOGIC_ISP1280
-#define PCI_DEVICE_ID_QLOGIC_ISP1280 0x1280
-#endif
-#ifndef PCI_DEVICE_ID_QLOGIC_ISP10160
-#define PCI_DEVICE_ID_QLOGIC_ISP10160 0x1016
-#endif
-#ifndef PCI_DEVICE_ID_QLOGIC_ISP12160
-#define PCI_DEVICE_ID_QLOGIC_ISP12160 0x1216
-#endif
-
-#ifndef PCI_VENDOR_ID_AMI
-#define PCI_VENDOR_ID_AMI 0x101e
-#endif
-
#ifndef BITS_PER_LONG
#error "BITS_PER_LONG not defined!"
#endif
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 2203103..329ead2 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -1,6 +1,6 @@
/* qlogicpti.c: Performance Technologies QlogicISP sbus card driver.
*
- * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
+ * Copyright (C) 1996, 2006 David S. Miller (davem@davemloft.net)
*
* A lot of this driver was directly stolen from Erik H. Moe's PCI
* Qlogic ISP driver. Mucho kudos to him for this code.
@@ -46,8 +46,6 @@
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_host.h>
-
-
#define MAX_TARGETS 16
#define MAX_LUNS 8 /* 32 for 1.31 F/W */
@@ -57,7 +55,6 @@
static struct qlogicpti *qptichain = NULL;
static DEFINE_SPINLOCK(qptichain_lock);
-static int qptis_running = 0;
#define PACKB(a, b) (((a)<<4)|(b))
@@ -815,173 +812,6 @@ static int __init qpti_map_queues(struct qlogicpti *qpti)
return 0;
}
-/* Detect all PTI Qlogic ISP's in the machine. */
-static int __init qlogicpti_detect(struct scsi_host_template *tpnt)
-{
- struct qlogicpti *qpti;
- struct Scsi_Host *qpti_host;
- struct sbus_bus *sbus;
- struct sbus_dev *sdev;
- int nqptis = 0, nqptis_in_use = 0;
-
- tpnt->proc_name = "qlogicpti";
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- /* Is this a red snapper? */
- if (strcmp(sdev->prom_name, "ptisp") &&
- strcmp(sdev->prom_name, "PTI,ptisp") &&
- strcmp(sdev->prom_name, "QLGC,isp") &&
- strcmp(sdev->prom_name, "SUNW,isp"))
- continue;
-
- /* Sometimes Antares cards come up not completely
- * setup, and we get a report of a zero IRQ.
- * Skip over them in such cases so we survive.
- */
- if (sdev->irqs[0] == 0) {
- printk("qpti%d: Adapter reports no interrupt, "
- "skipping over this card.", nqptis);
- continue;
- }
-
- /* Yep, register and allocate software state. */
- qpti_host = scsi_register(tpnt, sizeof(struct qlogicpti));
- if (!qpti_host) {
- printk("QPTI: Cannot register PTI Qlogic ISP SCSI host");
- continue;
- }
- qpti = (struct qlogicpti *) qpti_host->hostdata;
-
- /* We are wide capable, 16 targets. */
- qpti_host->max_id = MAX_TARGETS;
-
- /* Setup back pointers and misc. state. */
- qpti->qhost = qpti_host;
- qpti->sdev = sdev;
- qpti->qpti_id = nqptis++;
- qpti->prom_node = sdev->prom_node;
- prom_getstring(qpti->prom_node, "name",
- qpti->prom_name,
- sizeof(qpti->prom_name));
-
- /* This is not correct, actually. There's a switch
- * on the PTI cards that put them into "emulation"
- * mode- i.e., report themselves as QLGC,isp
- * instead of PTI,ptisp. The only real substantive
- * difference between non-pti and pti cards is
- * the tmon register. Which is possibly even
- * there for Qlogic cards, but non-functional.
- */
- qpti->is_pti = (strcmp (qpti->prom_name, "QLGC,isp") != 0);
-
- qpti_chain_add(qpti);
- if (qpti_map_regs(qpti) < 0)
- goto fail_unlink;
-
- if (qpti_register_irq(qpti) < 0)
- goto fail_unmap_regs;
-
- qpti_get_scsi_id(qpti);
- qpti_get_bursts(qpti);
- qpti_get_clock(qpti);
-
- /* Clear out scsi_cmnd array. */
- memset(qpti->cmd_slots, 0, sizeof(qpti->cmd_slots));
-
- if (qpti_map_queues(qpti) < 0)
- goto fail_free_irq;
-
- /* Load the firmware. */
- if (qlogicpti_load_firmware(qpti))
- goto fail_unmap_queues;
- if (qpti->is_pti) {
- /* Check the PTI status reg. */
- if (qlogicpti_verify_tmon(qpti))
- goto fail_unmap_queues;
- }
-
- /* Reset the ISP and init res/req queues. */
- if (qlogicpti_reset_hardware(qpti_host))
- goto fail_unmap_queues;
-
- printk("(Firmware v%d.%d.%d)", qpti->fware_majrev,
- qpti->fware_minrev, qpti->fware_micrev);
- {
- char buffer[60];
-
- prom_getstring (qpti->prom_node,
- "isp-fcode", buffer, 60);
- if (buffer[0])
- printk("(Firmware %s)", buffer);
- if (prom_getbool(qpti->prom_node, "differential"))
- qpti->differential = 1;
- }
-
- printk (" [%s Wide, using %s interface]\n",
- (qpti->ultra ? "Ultra" : "Fast"),
- (qpti->differential ? "differential" : "single ended"));
-
- nqptis_in_use++;
- continue;
-
- fail_unmap_queues:
-#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
- sbus_free_consistent(qpti->sdev,
- QSIZE(RES_QUEUE_LEN),
- qpti->res_cpu, qpti->res_dvma);
- sbus_free_consistent(qpti->sdev,
- QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
- qpti->req_cpu, qpti->req_dvma);
-#undef QSIZE
- fail_free_irq:
- free_irq(qpti->irq, qpti);
-
- fail_unmap_regs:
- sbus_iounmap(qpti->qregs,
- qpti->sdev->reg_addrs[0].reg_size);
- if (qpti->is_pti)
- sbus_iounmap(qpti->sreg, sizeof(unsigned char));
- fail_unlink:
- qpti_chain_del(qpti);
- scsi_unregister(qpti->qhost);
- }
- }
- if (nqptis)
- printk("QPTI: Total of %d PTI Qlogic/ISP hosts found, %d actually in use.\n",
- nqptis, nqptis_in_use);
- qptis_running = nqptis_in_use;
- return nqptis;
-}
-
-static int qlogicpti_release(struct Scsi_Host *host)
-{
- struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
-
- /* Remove visibility from IRQ handlers. */
- qpti_chain_del(qpti);
-
- /* Shut up the card. */
- sbus_writew(0, qpti->qregs + SBUS_CTRL);
-
- /* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */
- free_irq(qpti->irq, qpti);
-
-#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
- sbus_free_consistent(qpti->sdev,
- QSIZE(RES_QUEUE_LEN),
- qpti->res_cpu, qpti->res_dvma);
- sbus_free_consistent(qpti->sdev,
- QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
- qpti->req_cpu, qpti->req_dvma);
-#undef QSIZE
-
- sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size);
- if (qpti->is_pti)
- sbus_iounmap(qpti->sreg, sizeof(unsigned char));
-
- return 0;
-}
-
const char *qlogicpti_info(struct Scsi_Host *host)
{
static char buf[80];
@@ -1551,9 +1381,9 @@ static int qlogicpti_reset(struct scsi_cmnd *Cmnd)
return return_status;
}
-static struct scsi_host_template driver_template = {
- .detect = qlogicpti_detect,
- .release = qlogicpti_release,
+static struct scsi_host_template qpti_template = {
+ .module = THIS_MODULE,
+ .name = "qlogicpti",
.info = qlogicpti_info,
.queuecommand = qlogicpti_queuecommand_slow,
.eh_abort_handler = qlogicpti_abort,
@@ -1565,8 +1395,189 @@ static struct scsi_host_template driver_template = {
.use_clustering = ENABLE_CLUSTERING,
};
+static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+{
+ static int nqptis;
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+ struct device_node *dp = dev->node;
+ struct scsi_host_template *tpnt = match->data;
+ struct Scsi_Host *host;
+ struct qlogicpti *qpti;
+ char *fcode;
+
+ /* Sometimes Antares cards come up not completely
+ * setup, and we get a report of a zero IRQ.
+ */
+ if (sdev->irqs[0] == 0)
+ return -ENODEV;
+
+ host = scsi_host_alloc(tpnt, sizeof(struct qlogicpti));
+ if (!host)
+ return -ENOMEM;
+
+ qpti = (struct qlogicpti *) host->hostdata;
+
+ host->max_id = MAX_TARGETS;
+ qpti->qhost = host;
+ qpti->sdev = sdev;
+ qpti->qpti_id = nqptis;
+ qpti->prom_node = sdev->prom_node;
+ strcpy(qpti->prom_name, sdev->ofdev.node->name);
+ qpti->is_pti = strcmp(qpti->prom_name, "QLGC,isp");
+
+ if (qpti_map_regs(qpti) < 0)
+ goto fail_unlink;
+
+ if (qpti_register_irq(qpti) < 0)
+ goto fail_unmap_regs;
+
+ qpti_get_scsi_id(qpti);
+ qpti_get_bursts(qpti);
+ qpti_get_clock(qpti);
+
+ /* Clear out scsi_cmnd array. */
+ memset(qpti->cmd_slots, 0, sizeof(qpti->cmd_slots));
+
+ if (qpti_map_queues(qpti) < 0)
+ goto fail_free_irq;
+
+ /* Load the firmware. */
+ if (qlogicpti_load_firmware(qpti))
+ goto fail_unmap_queues;
+ if (qpti->is_pti) {
+ /* Check the PTI status reg. */
+ if (qlogicpti_verify_tmon(qpti))
+ goto fail_unmap_queues;
+ }
+
+ /* Reset the ISP and init res/req queues. */
+ if (qlogicpti_reset_hardware(host))
+ goto fail_unmap_queues;
+
+ if (scsi_add_host(host, &dev->dev))
+ goto fail_unmap_queues;
+
+ printk("(Firmware v%d.%d.%d)", qpti->fware_majrev,
+ qpti->fware_minrev, qpti->fware_micrev);
+
+ fcode = of_get_property(dp, "isp-fcode", NULL);
+ if (fcode && fcode[0])
+ printk("(Firmware %s)", fcode);
+ if (of_find_property(dp, "differential", NULL) != NULL)
+ qpti->differential = 1;
+
+ printk (" [%s Wide, using %s interface]\n",
+ (qpti->ultra ? "Ultra" : "Fast"),
+ (qpti->differential ? "differential" : "single ended"));
+
+ dev_set_drvdata(&sdev->ofdev.dev, qpti);
+
+ qpti_chain_add(qpti);
+
+ scsi_scan_host(host);
+ nqptis++;
+
+ return 0;
+
+fail_unmap_queues:
+#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
+ sbus_free_consistent(qpti->sdev,
+ QSIZE(RES_QUEUE_LEN),
+ qpti->res_cpu, qpti->res_dvma);
+ sbus_free_consistent(qpti->sdev,
+ QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+ qpti->req_cpu, qpti->req_dvma);
+#undef QSIZE
+
+fail_unmap_regs:
+ sbus_iounmap(qpti->qregs,
+ qpti->sdev->reg_addrs[0].reg_size);
+ if (qpti->is_pti)
+ sbus_iounmap(qpti->sreg, sizeof(unsigned char));
+
+fail_free_irq:
+ free_irq(qpti->irq, qpti);
+
+fail_unlink:
+ scsi_host_put(host);
+
+ return -ENODEV;
+}
+
+static int __devexit qpti_sbus_remove(struct of_device *dev)
+{
+ struct qlogicpti *qpti = dev_get_drvdata(&dev->dev);
+
+ qpti_chain_del(qpti);
+
+ scsi_remove_host(qpti->qhost);
+
+ /* Shut up the card. */
+ sbus_writew(0, qpti->qregs + SBUS_CTRL);
+
+ /* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */
+ free_irq(qpti->irq, qpti);
+
+#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
+ sbus_free_consistent(qpti->sdev,
+ QSIZE(RES_QUEUE_LEN),
+ qpti->res_cpu, qpti->res_dvma);
+ sbus_free_consistent(qpti->sdev,
+ QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+ qpti->req_cpu, qpti->req_dvma);
+#undef QSIZE
+
+ sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size);
+ if (qpti->is_pti)
+ sbus_iounmap(qpti->sreg, sizeof(unsigned char));
+
+ scsi_host_put(qpti->qhost);
+
+ return 0;
+}
+
+static struct of_device_id qpti_match[] = {
+ {
+ .name = "ptisp",
+ .data = &qpti_template,
+ },
+ {
+ .name = "PTI,ptisp",
+ .data = &qpti_template,
+ },
+ {
+ .name = "QLGC,isp",
+ .data = &qpti_template,
+ },
+ {
+ .name = "SUNW,isp",
+ .data = &qpti_template,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, qpti_match);
+
+static struct of_platform_driver qpti_sbus_driver = {
+ .name = "qpti",
+ .match_table = qpti_match,
+ .probe = qpti_sbus_probe,
+ .remove = __devexit_p(qpti_sbus_remove),
+};
-#include "scsi_module.c"
+static int __init qpti_init(void)
+{
+ return of_register_driver(&qpti_sbus_driver, &sbus_bus_type);
+}
+
+static void __exit qpti_exit(void)
+{
+ of_unregister_driver(&qpti_sbus_driver);
+}
+MODULE_DESCRIPTION("QlogicISP SBUS driver");
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
MODULE_LICENSE("GPL");
+MODULE_VERSION("2.0");
+module_init(qpti_init);
+module_exit(qpti_exit);
diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c
index f16f92a..4a71578 100644
--- a/drivers/scsi/sata_mv.c
+++ b/drivers/scsi/sata_mv.c
@@ -93,7 +93,7 @@ enum {
MV_FLAG_IRQ_COALESCE = (1 << 29), /* IRQ coalescing capability */
MV_COMMON_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
- ATA_FLAG_NO_ATAPI),
+ ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING),
MV_6XXX_FLAGS = MV_FLAG_IRQ_COALESCE,
CRQB_FLAG_READ = (1 << 0),
@@ -272,33 +272,33 @@ enum chip_type {
/* Command ReQuest Block: 32B */
struct mv_crqb {
- u32 sg_addr;
- u32 sg_addr_hi;
- u16 ctrl_flags;
- u16 ata_cmd[11];
+ __le32 sg_addr;
+ __le32 sg_addr_hi;
+ __le16 ctrl_flags;
+ __le16 ata_cmd[11];
};
struct mv_crqb_iie {
- u32 addr;
- u32 addr_hi;
- u32 flags;
- u32 len;
- u32 ata_cmd[4];
+ __le32 addr;
+ __le32 addr_hi;
+ __le32 flags;
+ __le32 len;
+ __le32 ata_cmd[4];
};
/* Command ResPonse Block: 8B */
struct mv_crpb {
- u16 id;
- u16 flags;
- u32 tmstmp;
+ __le16 id;
+ __le16 flags;
+ __le32 tmstmp;
};
/* EDMA Physical Region Descriptor (ePRD); A.K.A. SG */
struct mv_sg {
- u32 addr;
- u32 flags_size;
- u32 addr_hi;
- u32 reserved;
+ __le32 addr;
+ __le32 flags_size;
+ __le32 addr_hi;
+ __le32 reserved;
};
struct mv_port_priv {
@@ -390,6 +390,7 @@ static struct scsi_host_template mv_sht = {
.proc_name = DRV_NAME,
.dma_boundary = MV_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
};
@@ -406,6 +407,7 @@ static const struct ata_port_operations mv5_ops = {
.qc_prep = mv_qc_prep,
.qc_issue = mv_qc_issue,
+ .data_xfer = ata_mmio_data_xfer,
.eng_timeout = mv_eng_timeout,
@@ -433,6 +435,7 @@ static const struct ata_port_operations mv6_ops = {
.qc_prep = mv_qc_prep,
.qc_issue = mv_qc_issue,
+ .data_xfer = ata_mmio_data_xfer,
.eng_timeout = mv_eng_timeout,
@@ -683,7 +686,7 @@ static void mv_stop_dma(struct ata_port *ap)
}
if (EDMA_EN & reg) {
- printk(KERN_ERR "ata%u: Unable to stop eDMA\n", ap->id);
+ ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n");
/* FIXME: Consider doing a reset here to recover */
}
}
@@ -1028,7 +1031,7 @@ static inline unsigned mv_inc_q_index(unsigned index)
return (index + 1) & MV_MAX_Q_DEPTH_MASK;
}
-static inline void mv_crqb_pack_cmd(u16 *cmdw, u8 data, u8 addr, unsigned last)
+static inline void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
{
u16 tmp = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS |
(last ? CRQB_CMD_LAST : 0);
@@ -1051,7 +1054,7 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct mv_port_priv *pp = ap->private_data;
- u16 *cw;
+ __le16 *cw;
struct ata_taskfile *tf;
u16 flags = 0;
unsigned in_index;
@@ -1307,8 +1310,8 @@ static void mv_err_intr(struct ata_port *ap, int reset_allowed)
edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
if (EDMA_ERR_SERR & edma_err_cause) {
- serr = scr_read(ap, SCR_ERROR);
- scr_write_flush(ap, SCR_ERROR, serr);
+ sata_scr_read(ap, SCR_ERROR, &serr);
+ sata_scr_write_flush(ap, SCR_ERROR, serr);
}
if (EDMA_ERR_SELF_DIS & edma_err_cause) {
struct mv_port_priv *pp = ap->private_data;
@@ -1377,7 +1380,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
/* Note that DEV_IRQ might happen spuriously during EDMA,
* and should be ignored in such cases.
* The cause of this is still under investigation.
- */
+ */
if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
/* EDMA: check for response queue interrupt */
if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause) {
@@ -1398,7 +1401,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
}
}
- if (ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))
+ if (ap && (ap->flags & ATA_FLAG_DISABLED))
continue;
err_mask = ac_err_mask(ata_status);
@@ -1419,7 +1422,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
VPRINTK("port %u IRQ found for qc, "
"ata_status 0x%x\n", port,ata_status);
/* mark qc status appropriately */
- if (!(qc->tf.ctl & ATA_NIEN)) {
+ if (!(qc->tf.flags & ATA_TFLAG_POLLING)) {
qc->err_mask |= err_mask;
ata_qc_complete(qc);
}
@@ -1949,15 +1952,16 @@ static void __mv_phy_reset(struct ata_port *ap, int can_sleep)
/* Issue COMRESET via SControl */
comreset_retry:
- scr_write_flush(ap, SCR_CONTROL, 0x301);
+ sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
__msleep(1, can_sleep);
- scr_write_flush(ap, SCR_CONTROL, 0x300);
+ sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
__msleep(20, can_sleep);
timeout = jiffies + msecs_to_jiffies(200);
do {
- sstatus = scr_read(ap, SCR_STATUS) & 0x3;
+ sata_scr_read(ap, SCR_STATUS, &sstatus);
+ sstatus &= 0x3;
if ((sstatus == 3) || (sstatus == 0))
break;
@@ -1974,11 +1978,12 @@ comreset_retry:
"SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
- if (sata_dev_present(ap)) {
+ if (ata_port_online(ap)) {
ata_port_probe(ap);
} else {
- printk(KERN_INFO "ata%u: no device found (phy stat %08x)\n",
- ap->id, scr_read(ap, SCR_STATUS));
+ sata_scr_read(ap, SCR_STATUS, &sstatus);
+ ata_port_printk(ap, KERN_INFO,
+ "no device found (phy stat %08x)\n", sstatus);
ata_port_disable(ap);
return;
}
@@ -2005,7 +2010,7 @@ comreset_retry:
tf.nsect = readb((void __iomem *) ap->ioaddr.nsect_addr);
dev->class = ata_dev_classify(&tf);
- if (!ata_dev_present(dev)) {
+ if (!ata_dev_enabled(dev)) {
VPRINTK("Port disabled post-sig: No device present.\n");
ata_port_disable(ap);
}
@@ -2037,7 +2042,7 @@ static void mv_eng_timeout(struct ata_port *ap)
struct ata_queued_cmd *qc;
unsigned long flags;
- printk(KERN_ERR "ata%u: Entering mv_eng_timeout\n",ap->id);
+ ata_port_printk(ap, KERN_ERR, "Entering mv_eng_timeout\n");
DPRINTK("All regs @ start of eng_timeout\n");
mv_dump_all_regs(ap->host_set->mmio_base, ap->port_no,
to_pci_dev(ap->host_set->dev));
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
index 9f55308..d18e7e0 100644
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/scsi/sata_nv.c
@@ -44,7 +44,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_nv"
-#define DRV_VERSION "0.8"
+#define DRV_VERSION "0.9"
enum {
NV_PORTS = 2,
@@ -54,40 +54,25 @@ enum {
NV_PORT0_SCR_REG_OFFSET = 0x00,
NV_PORT1_SCR_REG_OFFSET = 0x40,
+ /* INT_STATUS/ENABLE */
NV_INT_STATUS = 0x10,
- NV_INT_STATUS_CK804 = 0x440,
- NV_INT_STATUS_PDEV_INT = 0x01,
- NV_INT_STATUS_PDEV_PM = 0x02,
- NV_INT_STATUS_PDEV_ADDED = 0x04,
- NV_INT_STATUS_PDEV_REMOVED = 0x08,
- NV_INT_STATUS_SDEV_INT = 0x10,
- NV_INT_STATUS_SDEV_PM = 0x20,
- NV_INT_STATUS_SDEV_ADDED = 0x40,
- NV_INT_STATUS_SDEV_REMOVED = 0x80,
- NV_INT_STATUS_PDEV_HOTPLUG = (NV_INT_STATUS_PDEV_ADDED |
- NV_INT_STATUS_PDEV_REMOVED),
- NV_INT_STATUS_SDEV_HOTPLUG = (NV_INT_STATUS_SDEV_ADDED |
- NV_INT_STATUS_SDEV_REMOVED),
- NV_INT_STATUS_HOTPLUG = (NV_INT_STATUS_PDEV_HOTPLUG |
- NV_INT_STATUS_SDEV_HOTPLUG),
-
NV_INT_ENABLE = 0x11,
+ NV_INT_STATUS_CK804 = 0x440,
NV_INT_ENABLE_CK804 = 0x441,
- NV_INT_ENABLE_PDEV_MASK = 0x01,
- NV_INT_ENABLE_PDEV_PM = 0x02,
- NV_INT_ENABLE_PDEV_ADDED = 0x04,
- NV_INT_ENABLE_PDEV_REMOVED = 0x08,
- NV_INT_ENABLE_SDEV_MASK = 0x10,
- NV_INT_ENABLE_SDEV_PM = 0x20,
- NV_INT_ENABLE_SDEV_ADDED = 0x40,
- NV_INT_ENABLE_SDEV_REMOVED = 0x80,
- NV_INT_ENABLE_PDEV_HOTPLUG = (NV_INT_ENABLE_PDEV_ADDED |
- NV_INT_ENABLE_PDEV_REMOVED),
- NV_INT_ENABLE_SDEV_HOTPLUG = (NV_INT_ENABLE_SDEV_ADDED |
- NV_INT_ENABLE_SDEV_REMOVED),
- NV_INT_ENABLE_HOTPLUG = (NV_INT_ENABLE_PDEV_HOTPLUG |
- NV_INT_ENABLE_SDEV_HOTPLUG),
+ /* INT_STATUS/ENABLE bits */
+ NV_INT_DEV = 0x01,
+ NV_INT_PM = 0x02,
+ NV_INT_ADDED = 0x04,
+ NV_INT_REMOVED = 0x08,
+
+ NV_INT_PORT_SHIFT = 4, /* each port occupies 4 bits */
+
+ NV_INT_ALL = 0x0f,
+ NV_INT_MASK = NV_INT_DEV |
+ NV_INT_ADDED | NV_INT_REMOVED,
+
+ /* INT_CONFIG */
NV_INT_CONFIG = 0x12,
NV_INT_CONFIG_METHD = 0x01, // 0 = INT, 1 = SMI
@@ -97,23 +82,27 @@ enum {
};
static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static irqreturn_t nv_interrupt (int irq, void *dev_instance,
- struct pt_regs *regs);
+static void nv_ck804_host_stop(struct ata_host_set *host_set);
+static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance,
+ struct pt_regs *regs);
+static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance,
+ struct pt_regs *regs);
+static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance,
+ struct pt_regs *regs);
static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
-static void nv_host_stop (struct ata_host_set *host_set);
-static void nv_enable_hotplug(struct ata_probe_ent *probe_ent);
-static void nv_disable_hotplug(struct ata_host_set *host_set);
-static int nv_check_hotplug(struct ata_host_set *host_set);
-static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent);
-static void nv_disable_hotplug_ck804(struct ata_host_set *host_set);
-static int nv_check_hotplug_ck804(struct ata_host_set *host_set);
+
+static void nv_nf2_freeze(struct ata_port *ap);
+static void nv_nf2_thaw(struct ata_port *ap);
+static void nv_ck804_freeze(struct ata_port *ap);
+static void nv_ck804_thaw(struct ata_port *ap);
+static void nv_error_handler(struct ata_port *ap);
enum nv_host_type
{
GENERIC,
NFORCE2,
- NFORCE3,
+ NFORCE3 = NFORCE2, /* NF2 == NF3 as far as sata_nv is concerned */
CK804
};
@@ -140,6 +129,16 @@ static const struct pci_device_id nv_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, 0x045c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, 0x045d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, 0x045e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, 0x045f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
{ PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC },
@@ -149,46 +148,6 @@ static const struct pci_device_id nv_pci_tbl[] = {
{ 0, } /* terminate list */
};
-struct nv_host_desc
-{
- enum nv_host_type host_type;
- void (*enable_hotplug)(struct ata_probe_ent *probe_ent);
- void (*disable_hotplug)(struct ata_host_set *host_set);
- int (*check_hotplug)(struct ata_host_set *host_set);
-
-};
-static struct nv_host_desc nv_device_tbl[] = {
- {
- .host_type = GENERIC,
- .enable_hotplug = NULL,
- .disable_hotplug= NULL,
- .check_hotplug = NULL,
- },
- {
- .host_type = NFORCE2,
- .enable_hotplug = nv_enable_hotplug,
- .disable_hotplug= nv_disable_hotplug,
- .check_hotplug = nv_check_hotplug,
- },
- {
- .host_type = NFORCE3,
- .enable_hotplug = nv_enable_hotplug,
- .disable_hotplug= nv_disable_hotplug,
- .check_hotplug = nv_check_hotplug,
- },
- { .host_type = CK804,
- .enable_hotplug = nv_enable_hotplug_ck804,
- .disable_hotplug= nv_disable_hotplug_ck804,
- .check_hotplug = nv_check_hotplug_ck804,
- },
-};
-
-struct nv_host
-{
- struct nv_host_desc *host_desc;
- unsigned long host_flags;
-};
-
static struct pci_driver nv_pci_driver = {
.name = DRV_NAME,
.id_table = nv_pci_tbl,
@@ -210,51 +169,119 @@ static struct scsi_host_template nv_sht = {
.proc_name = DRV_NAME,
.dma_boundary = ATA_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
};
-static const struct ata_port_operations nv_ops = {
+static const struct ata_port_operations nv_generic_ops = {
.port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.exec_command = ata_exec_command,
.check_status = ata_check_status,
.dev_select = ata_std_dev_select,
- .phy_reset = sata_phy_reset,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
- .irq_handler = nv_interrupt,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = nv_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .data_xfer = ata_pio_data_xfer,
+ .irq_handler = nv_generic_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = ata_port_start,
.port_stop = ata_port_stop,
- .host_stop = nv_host_stop,
+ .host_stop = ata_pci_host_stop,
};
-/* FIXME: The hardware provides the necessary SATA PHY controls
- * to support ATA_FLAG_SATA_RESET. However, it is currently
- * necessary to disable that flag, to solve misdetection problems.
- * See http://bugme.osdl.org/show_bug.cgi?id=3352 for more info.
- *
- * This problem really needs to be investigated further. But in the
- * meantime, we avoid ATA_FLAG_SATA_RESET to get people working.
- */
-static struct ata_port_info nv_port_info = {
- .sht = &nv_sht,
- .host_flags = ATA_FLAG_SATA |
- /* ATA_FLAG_SATA_RESET | */
- ATA_FLAG_SRST |
- ATA_FLAG_NO_LEGACY,
- .pio_mask = NV_PIO_MASK,
- .mwdma_mask = NV_MWDMA_MASK,
- .udma_mask = NV_UDMA_MASK,
- .port_ops = &nv_ops,
+static const struct ata_port_operations nv_nf2_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .exec_command = ata_exec_command,
+ .check_status = ata_check_status,
+ .dev_select = ata_std_dev_select,
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .freeze = nv_nf2_freeze,
+ .thaw = nv_nf2_thaw,
+ .error_handler = nv_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .data_xfer = ata_pio_data_xfer,
+ .irq_handler = nv_nf2_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .scr_read = nv_scr_read,
+ .scr_write = nv_scr_write,
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_pci_host_stop,
+};
+
+static const struct ata_port_operations nv_ck804_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .exec_command = ata_exec_command,
+ .check_status = ata_check_status,
+ .dev_select = ata_std_dev_select,
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .freeze = nv_ck804_freeze,
+ .thaw = nv_ck804_thaw,
+ .error_handler = nv_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .data_xfer = ata_pio_data_xfer,
+ .irq_handler = nv_ck804_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .scr_read = nv_scr_read,
+ .scr_write = nv_scr_write,
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = nv_ck804_host_stop,
+};
+
+static struct ata_port_info nv_port_info[] = {
+ /* generic */
+ {
+ .sht = &nv_sht,
+ .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .pio_mask = NV_PIO_MASK,
+ .mwdma_mask = NV_MWDMA_MASK,
+ .udma_mask = NV_UDMA_MASK,
+ .port_ops = &nv_generic_ops,
+ },
+ /* nforce2/3 */
+ {
+ .sht = &nv_sht,
+ .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .pio_mask = NV_PIO_MASK,
+ .mwdma_mask = NV_MWDMA_MASK,
+ .udma_mask = NV_UDMA_MASK,
+ .port_ops = &nv_nf2_ops,
+ },
+ /* ck804 */
+ {
+ .sht = &nv_sht,
+ .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .pio_mask = NV_PIO_MASK,
+ .mwdma_mask = NV_MWDMA_MASK,
+ .udma_mask = NV_UDMA_MASK,
+ .port_ops = &nv_ck804_ops,
+ },
};
MODULE_AUTHOR("NVIDIA");
@@ -263,11 +290,10 @@ MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-static irqreturn_t nv_interrupt (int irq, void *dev_instance,
- struct pt_regs *regs)
+static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance,
+ struct pt_regs *regs)
{
struct ata_host_set *host_set = dev_instance;
- struct nv_host *host = host_set->private_data;
unsigned int i;
unsigned int handled = 0;
unsigned long flags;
@@ -279,11 +305,11 @@ static irqreturn_t nv_interrupt (int irq, void *dev_instance,
ap = host_set->ports[i];
if (ap &&
- !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
+ !(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN)))
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled += ata_host_intr(ap, qc);
else
// No request pending? Clear interrupt status
@@ -293,14 +319,88 @@ static irqreturn_t nv_interrupt (int irq, void *dev_instance,
}
- if (host->host_desc->check_hotplug)
- handled += host->host_desc->check_hotplug(host_set);
-
spin_unlock_irqrestore(&host_set->lock, flags);
return IRQ_RETVAL(handled);
}
+static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
+{
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+ int handled;
+
+ /* freeze if hotplugged */
+ if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) {
+ ata_port_freeze(ap);
+ return 1;
+ }
+
+ /* bail out if not our interrupt */
+ if (!(irq_stat & NV_INT_DEV))
+ return 0;
+
+ /* DEV interrupt w/ no active qc? */
+ if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
+ ata_check_status(ap);
+ return 1;
+ }
+
+ /* handle interrupt */
+ handled = ata_host_intr(ap, qc);
+ if (unlikely(!handled)) {
+ /* spurious, clear it */
+ ata_check_status(ap);
+ }
+
+ return 1;
+}
+
+static irqreturn_t nv_do_interrupt(struct ata_host_set *host_set, u8 irq_stat)
+{
+ int i, handled = 0;
+
+ for (i = 0; i < host_set->n_ports; i++) {
+ struct ata_port *ap = host_set->ports[i];
+
+ if (ap && !(ap->flags & ATA_FLAG_DISABLED))
+ handled += nv_host_intr(ap, irq_stat);
+
+ irq_stat >>= NV_INT_PORT_SHIFT;
+ }
+
+ return IRQ_RETVAL(handled);
+}
+
+static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance,
+ struct pt_regs *regs)
+{
+ struct ata_host_set *host_set = dev_instance;
+ u8 irq_stat;
+ irqreturn_t ret;
+
+ spin_lock(&host_set->lock);
+ irq_stat = inb(host_set->ports[0]->ioaddr.scr_addr + NV_INT_STATUS);
+ ret = nv_do_interrupt(host_set, irq_stat);
+ spin_unlock(&host_set->lock);
+
+ return ret;
+}
+
+static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance,
+ struct pt_regs *regs)
+{
+ struct ata_host_set *host_set = dev_instance;
+ u8 irq_stat;
+ irqreturn_t ret;
+
+ spin_lock(&host_set->lock);
+ irq_stat = readb(host_set->mmio_base + NV_INT_STATUS_CK804);
+ ret = nv_do_interrupt(host_set, irq_stat);
+ spin_unlock(&host_set->lock);
+
+ return ret;
+}
+
static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
if (sc_reg > SCR_CONTROL)
@@ -317,23 +417,74 @@ static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
iowrite32(val, (void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));
}
-static void nv_host_stop (struct ata_host_set *host_set)
+static void nv_nf2_freeze(struct ata_port *ap)
{
- struct nv_host *host = host_set->private_data;
+ unsigned long scr_addr = ap->host_set->ports[0]->ioaddr.scr_addr;
+ int shift = ap->port_no * NV_INT_PORT_SHIFT;
+ u8 mask;
- // Disable hotplug event interrupts.
- if (host->host_desc->disable_hotplug)
- host->host_desc->disable_hotplug(host_set);
+ mask = inb(scr_addr + NV_INT_ENABLE);
+ mask &= ~(NV_INT_ALL << shift);
+ outb(mask, scr_addr + NV_INT_ENABLE);
+}
- kfree(host);
+static void nv_nf2_thaw(struct ata_port *ap)
+{
+ unsigned long scr_addr = ap->host_set->ports[0]->ioaddr.scr_addr;
+ int shift = ap->port_no * NV_INT_PORT_SHIFT;
+ u8 mask;
- ata_pci_host_stop(host_set);
+ outb(NV_INT_ALL << shift, scr_addr + NV_INT_STATUS);
+
+ mask = inb(scr_addr + NV_INT_ENABLE);
+ mask |= (NV_INT_MASK << shift);
+ outb(mask, scr_addr + NV_INT_ENABLE);
+}
+
+static void nv_ck804_freeze(struct ata_port *ap)
+{
+ void __iomem *mmio_base = ap->host_set->mmio_base;
+ int shift = ap->port_no * NV_INT_PORT_SHIFT;
+ u8 mask;
+
+ mask = readb(mmio_base + NV_INT_ENABLE_CK804);
+ mask &= ~(NV_INT_ALL << shift);
+ writeb(mask, mmio_base + NV_INT_ENABLE_CK804);
+}
+
+static void nv_ck804_thaw(struct ata_port *ap)
+{
+ void __iomem *mmio_base = ap->host_set->mmio_base;
+ int shift = ap->port_no * NV_INT_PORT_SHIFT;
+ u8 mask;
+
+ writeb(NV_INT_ALL << shift, mmio_base + NV_INT_STATUS_CK804);
+
+ mask = readb(mmio_base + NV_INT_ENABLE_CK804);
+ mask |= (NV_INT_MASK << shift);
+ writeb(mask, mmio_base + NV_INT_ENABLE_CK804);
+}
+
+static int nv_hardreset(struct ata_port *ap, unsigned int *class)
+{
+ unsigned int dummy;
+
+ /* SATA hardreset fails to retrieve proper device signature on
+ * some controllers. Don't classify on hardreset. For more
+ * info, see http://bugme.osdl.org/show_bug.cgi?id=3352
+ */
+ return sata_std_hardreset(ap, &dummy);
+}
+
+static void nv_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset,
+ nv_hardreset, ata_std_postreset);
}
static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version = 0;
- struct nv_host *host;
struct ata_port_info *ppi;
struct ata_probe_ent *probe_ent;
int pci_dev_busy = 0;
@@ -370,24 +521,15 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
rc = -ENOMEM;
- ppi = &nv_port_info;
+ ppi = &nv_port_info[ent->driver_data];
probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
if (!probe_ent)
goto err_out_regions;
- host = kmalloc(sizeof(struct nv_host), GFP_KERNEL);
- if (!host)
- goto err_out_free_ent;
-
- memset(host, 0, sizeof(struct nv_host));
- host->host_desc = &nv_device_tbl[ent->driver_data];
-
- probe_ent->private_data = host;
-
probe_ent->mmio_base = pci_iomap(pdev, 5, 0);
if (!probe_ent->mmio_base) {
rc = -EIO;
- goto err_out_free_host;
+ goto err_out_free_ent;
}
base = (unsigned long)probe_ent->mmio_base;
@@ -395,24 +537,27 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET;
probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET;
+ /* enable SATA space for CK804 */
+ if (ent->driver_data == CK804) {
+ u8 regval;
+
+ pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, &regval);
+ regval |= NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
+ pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
+ }
+
pci_set_master(pdev);
rc = ata_device_add(probe_ent);
if (rc != NV_PORTS)
goto err_out_iounmap;
- // Enable hotplug event interrupts.
- if (host->host_desc->enable_hotplug)
- host->host_desc->enable_hotplug(probe_ent);
-
kfree(probe_ent);
return 0;
err_out_iounmap:
pci_iounmap(pdev, probe_ent->mmio_base);
-err_out_free_host:
- kfree(host);
err_out_free_ent:
kfree(probe_ent);
err_out_regions:
@@ -424,127 +569,17 @@ err_out:
return rc;
}
-static void nv_enable_hotplug(struct ata_probe_ent *probe_ent)
-{
- u8 intr_mask;
-
- outb(NV_INT_STATUS_HOTPLUG,
- probe_ent->port[0].scr_addr + NV_INT_STATUS);
-
- intr_mask = inb(probe_ent->port[0].scr_addr + NV_INT_ENABLE);
- intr_mask |= NV_INT_ENABLE_HOTPLUG;
-
- outb(intr_mask, probe_ent->port[0].scr_addr + NV_INT_ENABLE);
-}
-
-static void nv_disable_hotplug(struct ata_host_set *host_set)
-{
- u8 intr_mask;
-
- intr_mask = inb(host_set->ports[0]->ioaddr.scr_addr + NV_INT_ENABLE);
-
- intr_mask &= ~(NV_INT_ENABLE_HOTPLUG);
-
- outb(intr_mask, host_set->ports[0]->ioaddr.scr_addr + NV_INT_ENABLE);
-}
-
-static int nv_check_hotplug(struct ata_host_set *host_set)
-{
- u8 intr_status;
-
- intr_status = inb(host_set->ports[0]->ioaddr.scr_addr + NV_INT_STATUS);
-
- // Clear interrupt status.
- outb(0xff, host_set->ports[0]->ioaddr.scr_addr + NV_INT_STATUS);
-
- if (intr_status & NV_INT_STATUS_HOTPLUG) {
- if (intr_status & NV_INT_STATUS_PDEV_ADDED)
- printk(KERN_WARNING "nv_sata: "
- "Primary device added\n");
-
- if (intr_status & NV_INT_STATUS_PDEV_REMOVED)
- printk(KERN_WARNING "nv_sata: "
- "Primary device removed\n");
-
- if (intr_status & NV_INT_STATUS_SDEV_ADDED)
- printk(KERN_WARNING "nv_sata: "
- "Secondary device added\n");
-
- if (intr_status & NV_INT_STATUS_SDEV_REMOVED)
- printk(KERN_WARNING "nv_sata: "
- "Secondary device removed\n");
-
- return 1;
- }
-
- return 0;
-}
-
-static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent)
-{
- struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
- u8 intr_mask;
- u8 regval;
-
- pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, &regval);
- regval |= NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
- pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
-
- writeb(NV_INT_STATUS_HOTPLUG, probe_ent->mmio_base + NV_INT_STATUS_CK804);
-
- intr_mask = readb(probe_ent->mmio_base + NV_INT_ENABLE_CK804);
- intr_mask |= NV_INT_ENABLE_HOTPLUG;
-
- writeb(intr_mask, probe_ent->mmio_base + NV_INT_ENABLE_CK804);
-}
-
-static void nv_disable_hotplug_ck804(struct ata_host_set *host_set)
+static void nv_ck804_host_stop(struct ata_host_set *host_set)
{
struct pci_dev *pdev = to_pci_dev(host_set->dev);
- u8 intr_mask;
u8 regval;
- intr_mask = readb(host_set->mmio_base + NV_INT_ENABLE_CK804);
-
- intr_mask &= ~(NV_INT_ENABLE_HOTPLUG);
-
- writeb(intr_mask, host_set->mmio_base + NV_INT_ENABLE_CK804);
-
+ /* disable SATA space for CK804 */
pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, &regval);
regval &= ~NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
-}
-
-static int nv_check_hotplug_ck804(struct ata_host_set *host_set)
-{
- u8 intr_status;
- intr_status = readb(host_set->mmio_base + NV_INT_STATUS_CK804);
-
- // Clear interrupt status.
- writeb(0xff, host_set->mmio_base + NV_INT_STATUS_CK804);
-
- if (intr_status & NV_INT_STATUS_HOTPLUG) {
- if (intr_status & NV_INT_STATUS_PDEV_ADDED)
- printk(KERN_WARNING "nv_sata: "
- "Primary device added\n");
-
- if (intr_status & NV_INT_STATUS_PDEV_REMOVED)
- printk(KERN_WARNING "nv_sata: "
- "Primary device removed\n");
-
- if (intr_status & NV_INT_STATUS_SDEV_ADDED)
- printk(KERN_WARNING "nv_sata: "
- "Secondary device added\n");
-
- if (intr_status & NV_INT_STATUS_SDEV_REMOVED)
- printk(KERN_WARNING "nv_sata: "
- "Secondary device removed\n");
-
- return 1;
- }
-
- return 0;
+ ata_pci_host_stop(host_set);
}
static int __init nv_init(void)
diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
index 7eb67a6..b2b6ed5 100644
--- a/drivers/scsi/sata_promise.c
+++ b/drivers/scsi/sata_promise.c
@@ -76,7 +76,8 @@ enum {
PDC_RESET = (1 << 11), /* HDMA reset */
PDC_COMMON_FLAGS = ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST |
- ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI,
+ ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
+ ATA_FLAG_PIO_POLLING,
};
@@ -120,6 +121,7 @@ static struct scsi_host_template pdc_ata_sht = {
.proc_name = DRV_NAME,
.dma_boundary = ATA_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
};
@@ -136,6 +138,7 @@ static const struct ata_port_operations pdc_sata_ops = {
.qc_prep = pdc_qc_prep,
.qc_issue = pdc_qc_issue_prot,
.eng_timeout = pdc_eng_timeout,
+ .data_xfer = ata_mmio_data_xfer,
.irq_handler = pdc_interrupt,
.irq_clear = pdc_irq_clear,
@@ -158,6 +161,7 @@ static const struct ata_port_operations pdc_pata_ops = {
.qc_prep = pdc_qc_prep,
.qc_issue = pdc_qc_issue_prot,
+ .data_xfer = ata_mmio_data_xfer,
.eng_timeout = pdc_eng_timeout,
.irq_handler = pdc_interrupt,
.irq_clear = pdc_irq_clear,
@@ -363,12 +367,23 @@ static void pdc_sata_phy_reset(struct ata_port *ap)
sata_phy_reset(ap);
}
-static void pdc_pata_phy_reset(struct ata_port *ap)
+static void pdc_pata_cbl_detect(struct ata_port *ap)
{
- /* FIXME: add cable detect. Don't assume 40-pin cable */
- ap->cbl = ATA_CBL_PATA40;
- ap->udma_mask &= ATA_UDMA_MASK_40C;
+ u8 tmp;
+ void __iomem *mmio = (void *) ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03;
+
+ tmp = readb(mmio);
+
+ if (tmp & 0x01) {
+ ap->cbl = ATA_CBL_PATA40;
+ ap->udma_mask &= ATA_UDMA_MASK_40C;
+ } else
+ ap->cbl = ATA_CBL_PATA80;
+}
+static void pdc_pata_phy_reset(struct ata_port *ap)
+{
+ pdc_pata_cbl_detect(ap);
pdc_reset_port(ap);
ata_port_probe(ap);
ata_bus_reset(ap);
@@ -435,7 +450,7 @@ static void pdc_eng_timeout(struct ata_port *ap)
switch (qc->tf.protocol) {
case ATA_PROT_DMA:
case ATA_PROT_NODATA:
- printk(KERN_ERR "ata%u: command timeout\n", ap->id);
+ ata_port_printk(ap, KERN_ERR, "command timeout\n");
drv_stat = ata_wait_idle(ap);
qc->err_mask |= __ac_err_mask(drv_stat);
break;
@@ -443,8 +458,9 @@ static void pdc_eng_timeout(struct ata_port *ap)
default:
drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
- printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n",
- ap->id, qc->tf.command, drv_stat);
+ ata_port_printk(ap, KERN_ERR,
+ "unknown timeout, cmd 0x%x stat 0x%x\n",
+ qc->tf.command, drv_stat);
qc->err_mask |= ac_err_mask(drv_stat);
break;
@@ -533,11 +549,11 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *r
ap = host_set->ports[i];
tmp = mask & (1 << (i + 1));
if (tmp && ap &&
- !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
+ !(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN)))
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled += pdc_host_intr(ap, qc);
}
}
@@ -676,10 +692,6 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- /*
- * If this driver happens to only be useful on Apple's K2, then
- * we should check that here as it has a normal Serverworks ID
- */
rc = pci_enable_device(pdev);
if (rc)
return rc;
diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c
index 886f344..98ddc25 100644
--- a/drivers/scsi/sata_qstor.c
+++ b/drivers/scsi/sata_qstor.c
@@ -41,7 +41,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_qstor"
-#define DRV_VERSION "0.05"
+#define DRV_VERSION "0.06"
enum {
QS_PORTS = 4,
@@ -142,6 +142,7 @@ static struct scsi_host_template qs_ata_sht = {
.proc_name = DRV_NAME,
.dma_boundary = QS_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
};
@@ -156,6 +157,7 @@ static const struct ata_port_operations qs_ata_ops = {
.phy_reset = qs_phy_reset,
.qc_prep = qs_qc_prep,
.qc_issue = qs_qc_issue,
+ .data_xfer = ata_mmio_data_xfer,
.eng_timeout = qs_eng_timeout,
.irq_handler = qs_intr,
.irq_clear = qs_irq_clear,
@@ -175,7 +177,7 @@ static const struct ata_port_info qs_port_info[] = {
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_SATA_RESET |
//FIXME ATA_FLAG_SRST |
- ATA_FLAG_MMIO,
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING,
.pio_mask = 0x10, /* pio4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &qs_ata_ops,
@@ -394,14 +396,13 @@ static inline unsigned int qs_intr_pkt(struct ata_host_set *host_set)
DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n",
sff1, sff0, port_no, sHST, sDST);
handled = 1;
- if (ap && !(ap->flags &
- (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) {
+ if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
struct qs_port_priv *pp = ap->private_data;
if (!pp || pp->state != qs_state_pkt)
continue;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
switch (sHST) {
case 0: /* successful CPB */
case 3: /* device error */
@@ -428,13 +429,13 @@ static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set)
struct ata_port *ap;
ap = host_set->ports[port_no];
if (ap &&
- !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
+ !(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
struct qs_port_priv *pp = ap->private_data;
if (!pp || pp->state != qs_state_mmio)
continue;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
/* check main status, clearing INTRQ */
u8 status = ata_check_status(ap);
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index 1066272..bc9f918 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -46,7 +46,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_sil"
-#define DRV_VERSION "0.9"
+#define DRV_VERSION "1.0"
enum {
/*
@@ -54,8 +54,9 @@ enum {
*/
SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29),
SIL_FLAG_MOD15WRITE = (1 << 30),
+
SIL_DFL_HOST_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO,
+ ATA_FLAG_MMIO | ATA_FLAG_HRST_TO_RESUME,
/*
* Controller IDs
@@ -84,6 +85,20 @@ enum {
/* BMDMA/BMDMA2 */
SIL_INTR_STEERING = (1 << 1),
+ SIL_DMA_ENABLE = (1 << 0), /* DMA run switch */
+ SIL_DMA_RDWR = (1 << 3), /* DMA Rd-Wr */
+ SIL_DMA_SATA_IRQ = (1 << 4), /* OR of all SATA IRQs */
+ SIL_DMA_ACTIVE = (1 << 16), /* DMA running */
+ SIL_DMA_ERROR = (1 << 17), /* PCI bus error */
+ SIL_DMA_COMPLETE = (1 << 18), /* cmd complete / IRQ pending */
+ SIL_DMA_N_SATA_IRQ = (1 << 6), /* SATA_IRQ for the next channel */
+ SIL_DMA_N_ACTIVE = (1 << 24), /* ACTIVE for the next channel */
+ SIL_DMA_N_ERROR = (1 << 25), /* ERROR for the next channel */
+ SIL_DMA_N_COMPLETE = (1 << 26), /* COMPLETE for the next channel */
+
+ /* SIEN */
+ SIL_SIEN_N = (1 << 16), /* triggered by SError.N */
+
/*
* Others
*/
@@ -96,6 +111,10 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static void sil_post_set_mode (struct ata_port *ap);
+static irqreturn_t sil_interrupt(int irq, void *dev_instance,
+ struct pt_regs *regs);
+static void sil_freeze(struct ata_port *ap);
+static void sil_thaw(struct ata_port *ap);
static const struct pci_device_id sil_pci_tbl[] = {
@@ -155,6 +174,7 @@ static struct scsi_host_template sil_sht = {
.proc_name = DRV_NAME,
.dma_boundary = ATA_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
};
@@ -166,7 +186,6 @@ static const struct ata_port_operations sil_ops = {
.check_status = ata_check_status,
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
- .probe_reset = ata_std_probe_reset,
.post_set_mode = sil_post_set_mode,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -174,8 +193,12 @@ static const struct ata_port_operations sil_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
- .irq_handler = ata_interrupt,
+ .data_xfer = ata_mmio_data_xfer,
+ .freeze = sil_freeze,
+ .thaw = sil_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .irq_handler = sil_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.scr_read = sil_scr_read,
.scr_write = sil_scr_write,
@@ -220,6 +243,7 @@ static const struct {
unsigned long tf; /* ATA taskfile register block */
unsigned long ctl; /* ATA control/altstatus register block */
unsigned long bmdma; /* DMA register block */
+ unsigned long bmdma2; /* DMA register block #2 */
unsigned long fifo_cfg; /* FIFO Valid Byte Count and Control */
unsigned long scr; /* SATA control register block */
unsigned long sien; /* SATA Interrupt Enable register */
@@ -227,10 +251,10 @@ static const struct {
unsigned long sfis_cfg; /* SATA FIS reception config register */
} sil_port[] = {
/* port 0 ... */
- { 0x80, 0x8A, 0x00, 0x40, 0x100, 0x148, 0xb4, 0x14c },
- { 0xC0, 0xCA, 0x08, 0x44, 0x180, 0x1c8, 0xf4, 0x1cc },
- { 0x280, 0x28A, 0x200, 0x240, 0x300, 0x348, 0x2b4, 0x34c },
- { 0x2C0, 0x2CA, 0x208, 0x244, 0x380, 0x3c8, 0x2f4, 0x3cc },
+ { 0x80, 0x8A, 0x00, 0x10, 0x40, 0x100, 0x148, 0xb4, 0x14c },
+ { 0xC0, 0xCA, 0x08, 0x18, 0x44, 0x180, 0x1c8, 0xf4, 0x1cc },
+ { 0x280, 0x28A, 0x200, 0x210, 0x240, 0x300, 0x348, 0x2b4, 0x34c },
+ { 0x2C0, 0x2CA, 0x208, 0x218, 0x244, 0x380, 0x3c8, 0x2f4, 0x3cc },
/* ... port 3 */
};
@@ -263,7 +287,7 @@ static void sil_post_set_mode (struct ata_port *ap)
for (i = 0; i < 2; i++) {
dev = &ap->device[i];
- if (!ata_dev_present(dev))
+ if (!ata_dev_enabled(dev))
dev_mode[i] = 0; /* PIO0/1/2 */
else if (dev->flags & ATA_DFLAG_PIO)
dev_mode[i] = 1; /* PIO3/4 */
@@ -314,6 +338,151 @@ static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
writel(val, mmio);
}
+static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
+{
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+ u8 status;
+
+ if (unlikely(bmdma2 & SIL_DMA_SATA_IRQ)) {
+ u32 serror;
+
+ /* SIEN doesn't mask SATA IRQs on some 3112s. Those
+ * controllers continue to assert IRQ as long as
+ * SError bits are pending. Clear SError immediately.
+ */
+ serror = sil_scr_read(ap, SCR_ERROR);
+ sil_scr_write(ap, SCR_ERROR, serror);
+
+ /* Trigger hotplug and accumulate SError only if the
+ * port isn't already frozen. Otherwise, PHY events
+ * during hardreset makes controllers with broken SIEN
+ * repeat probing needlessly.
+ */
+ if (!(ap->flags & ATA_FLAG_FROZEN)) {
+ ata_ehi_hotplugged(&ap->eh_info);
+ ap->eh_info.serror |= serror;
+ }
+
+ goto freeze;
+ }
+
+ if (unlikely(!qc || qc->tf.ctl & ATA_NIEN))
+ goto freeze;
+
+ /* Check whether we are expecting interrupt in this state */
+ switch (ap->hsm_task_state) {
+ case HSM_ST_FIRST:
+ /* Some pre-ATAPI-4 devices assert INTRQ
+ * at this state when ready to receive CDB.
+ */
+
+ /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
+ * The flag was turned on only for atapi devices.
+ * No need to check is_atapi_taskfile(&qc->tf) again.
+ */
+ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+ goto err_hsm;
+ break;
+ case HSM_ST_LAST:
+ if (qc->tf.protocol == ATA_PROT_DMA ||
+ qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
+ /* clear DMA-Start bit */
+ ap->ops->bmdma_stop(qc);
+
+ if (bmdma2 & SIL_DMA_ERROR) {
+ qc->err_mask |= AC_ERR_HOST_BUS;
+ ap->hsm_task_state = HSM_ST_ERR;
+ }
+ }
+ break;
+ case HSM_ST:
+ break;
+ default:
+ goto err_hsm;
+ }
+
+ /* check main status, clearing INTRQ */
+ status = ata_chk_status(ap);
+ if (unlikely(status & ATA_BUSY))
+ goto err_hsm;
+
+ /* ack bmdma irq events */
+ ata_bmdma_irq_clear(ap);
+
+ /* kick HSM in the ass */
+ ata_hsm_move(ap, qc, status, 0);
+
+ return;
+
+ err_hsm:
+ qc->err_mask |= AC_ERR_HSM;
+ freeze:
+ ata_port_freeze(ap);
+}
+
+static irqreturn_t sil_interrupt(int irq, void *dev_instance,
+ struct pt_regs *regs)
+{
+ struct ata_host_set *host_set = dev_instance;
+ void __iomem *mmio_base = host_set->mmio_base;
+ int handled = 0;
+ int i;
+
+ spin_lock(&host_set->lock);
+
+ for (i = 0; i < host_set->n_ports; i++) {
+ struct ata_port *ap = host_set->ports[i];
+ u32 bmdma2 = readl(mmio_base + sil_port[ap->port_no].bmdma2);
+
+ if (unlikely(!ap || ap->flags & ATA_FLAG_DISABLED))
+ continue;
+
+ if (bmdma2 == 0xffffffff ||
+ !(bmdma2 & (SIL_DMA_COMPLETE | SIL_DMA_SATA_IRQ)))
+ continue;
+
+ sil_host_intr(ap, bmdma2);
+ handled = 1;
+ }
+
+ spin_unlock(&host_set->lock);
+
+ return IRQ_RETVAL(handled);
+}
+
+static void sil_freeze(struct ata_port *ap)
+{
+ void __iomem *mmio_base = ap->host_set->mmio_base;
+ u32 tmp;
+
+ /* global IRQ mask doesn't block SATA IRQ, turn off explicitly */
+ writel(0, mmio_base + sil_port[ap->port_no].sien);
+
+ /* plug IRQ */
+ tmp = readl(mmio_base + SIL_SYSCFG);
+ tmp |= SIL_MASK_IDE0_INT << ap->port_no;
+ writel(tmp, mmio_base + SIL_SYSCFG);
+ readl(mmio_base + SIL_SYSCFG); /* flush */
+}
+
+static void sil_thaw(struct ata_port *ap)
+{
+ void __iomem *mmio_base = ap->host_set->mmio_base;
+ u32 tmp;
+
+ /* clear IRQ */
+ ata_chk_status(ap);
+ ata_bmdma_irq_clear(ap);
+
+ /* turn on SATA IRQ */
+ writel(SIL_SIEN_N, mmio_base + sil_port[ap->port_no].sien);
+
+ /* turn on IRQ */
+ tmp = readl(mmio_base + SIL_SYSCFG);
+ tmp &= ~(SIL_MASK_IDE0_INT << ap->port_no);
+ writel(tmp, mmio_base + SIL_SYSCFG);
+}
+
/**
* sil_dev_config - Apply device/host-specific errata fixups
* @ap: Port containing device to be examined
@@ -360,16 +529,16 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
if (slow_down ||
((ap->flags & SIL_FLAG_MOD15WRITE) &&
(quirks & SIL_QUIRK_MOD15WRITE))) {
- printk(KERN_INFO "ata%u(%u): applying Seagate errata fix (mod15write workaround)\n",
- ap->id, dev->devno);
+ ata_dev_printk(dev, KERN_INFO, "applying Seagate errata fix "
+ "(mod15write workaround)\n");
dev->max_sectors = 15;
return;
}
/* limit to udma5 */
if (quirks & SIL_QUIRK_UDMA5MAX) {
- printk(KERN_INFO "ata%u(%u): applying Maxtor errata fix %s\n",
- ap->id, dev->devno, model_num);
+ ata_dev_printk(dev, KERN_INFO,
+ "applying Maxtor errata fix %s\n", model_num);
dev->udma_mask &= ATA_UDMA5;
return;
}
@@ -384,16 +553,12 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
int rc;
unsigned int i;
int pci_dev_busy = 0;
- u32 tmp, irq_mask;
+ u32 tmp;
u8 cls;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- /*
- * If this driver happens to only be useful on Apple's K2, then
- * we should check that here as it has a normal Serverworks ID
- */
rc = pci_enable_device(pdev);
if (rc)
return rc;
@@ -478,31 +643,13 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
}
if (ent->driver_data == sil_3114) {
- irq_mask = SIL_MASK_4PORT;
-
/* flip the magic "make 4 ports work" bit */
tmp = readl(mmio_base + sil_port[2].bmdma);
if ((tmp & SIL_INTR_STEERING) == 0)
writel(tmp | SIL_INTR_STEERING,
mmio_base + sil_port[2].bmdma);
-
- } else {
- irq_mask = SIL_MASK_2PORT;
- }
-
- /* make sure IDE0/1/2/3 interrupts are not masked */
- tmp = readl(mmio_base + SIL_SYSCFG);
- if (tmp & irq_mask) {
- tmp &= ~irq_mask;
- writel(tmp, mmio_base + SIL_SYSCFG);
- readl(mmio_base + SIL_SYSCFG); /* flush */
}
- /* mask all SATA phy-related interrupts */
- /* TODO: unmask bit 6 (SError N bit) for hotplug */
- for (i = 0; i < probe_ent->n_ports; i++)
- writel(0, mmio_base + sil_port[i].sien);
-
pci_set_master(pdev);
/* FIXME: check ata_device_add return value */
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index cb9082f..c8b477c 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -31,15 +31,15 @@
#include <asm/io.h>
#define DRV_NAME "sata_sil24"
-#define DRV_VERSION "0.23"
+#define DRV_VERSION "0.24"
/*
* Port request block (PRB) 32 bytes
*/
struct sil24_prb {
- u16 ctrl;
- u16 prot;
- u32 rx_cnt;
+ __le16 ctrl;
+ __le16 prot;
+ __le32 rx_cnt;
u8 fis[6 * 4];
};
@@ -47,17 +47,17 @@ struct sil24_prb {
* Scatter gather entry (SGE) 16 bytes
*/
struct sil24_sge {
- u64 addr;
- u32 cnt;
- u32 flags;
+ __le64 addr;
+ __le32 cnt;
+ __le32 flags;
};
/*
* Port multiplier
*/
struct sil24_port_multiplier {
- u32 diag;
- u32 sactive;
+ __le32 diag;
+ __le32 sactive;
};
enum {
@@ -86,12 +86,21 @@ enum {
/* HOST_SLOT_STAT bits */
HOST_SSTAT_ATTN = (1 << 31),
+ /* HOST_CTRL bits */
+ HOST_CTRL_M66EN = (1 << 16), /* M66EN PCI bus signal */
+ HOST_CTRL_TRDY = (1 << 17), /* latched PCI TRDY */
+ HOST_CTRL_STOP = (1 << 18), /* latched PCI STOP */
+ HOST_CTRL_DEVSEL = (1 << 19), /* latched PCI DEVSEL */
+ HOST_CTRL_REQ64 = (1 << 20), /* latched PCI REQ64 */
+
/*
* Port registers
* (8192 bytes @ +0x0000, +0x2000, +0x4000 and +0x6000 @ BAR2)
*/
PORT_REGS_SIZE = 0x2000,
- PORT_PRB = 0x0000, /* (32 bytes PRB + 16 bytes SGEs * 6) * 31 (3968 bytes) */
+
+ PORT_LRAM = 0x0000, /* 31 LRAM slots and PM regs */
+ PORT_LRAM_SLOT_SZ = 0x0080, /* 32 bytes PRB + 2 SGE, ACT... */
PORT_PM = 0x0f80, /* 8 bytes PM * 16 (128 bytes) */
/* 32 bit regs */
@@ -142,8 +151,16 @@ enum {
PORT_IRQ_PWR_CHG = (1 << 3), /* power management change */
PORT_IRQ_PHYRDY_CHG = (1 << 4), /* PHY ready change */
PORT_IRQ_COMWAKE = (1 << 5), /* COMWAKE received */
- PORT_IRQ_UNK_FIS = (1 << 6), /* Unknown FIS received */
- PORT_IRQ_SDB_FIS = (1 << 11), /* SDB FIS received */
+ PORT_IRQ_UNK_FIS = (1 << 6), /* unknown FIS received */
+ PORT_IRQ_DEV_XCHG = (1 << 7), /* device exchanged */
+ PORT_IRQ_8B10B = (1 << 8), /* 8b/10b decode error threshold */
+ PORT_IRQ_CRC = (1 << 9), /* CRC error threshold */
+ PORT_IRQ_HANDSHAKE = (1 << 10), /* handshake error threshold */
+ PORT_IRQ_SDB_NOTIFY = (1 << 11), /* SDB notify received */
+
+ DEF_PORT_IRQ = PORT_IRQ_COMPLETE | PORT_IRQ_ERROR |
+ PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG |
+ PORT_IRQ_UNK_FIS,
/* bits[27:16] are unmasked (raw) */
PORT_IRQ_RAW_SHIFT = 16,
@@ -174,7 +191,7 @@ enum {
PORT_CERR_CMD_PCIPERR = 27, /* ctrl[15:13] 110 - PCI parity err while fetching PRB */
PORT_CERR_XFR_UNDEF = 32, /* PSD ecode 00 - undefined */
PORT_CERR_XFR_TGTABRT = 33, /* PSD ecode 01 - target abort */
- PORT_CERR_XFR_MSGABRT = 34, /* PSD ecode 10 - master abort */
+ PORT_CERR_XFR_MSTABRT = 34, /* PSD ecode 10 - master abort */
PORT_CERR_XFR_PCIPERR = 35, /* PSD ecode 11 - PCI prity err during transfer */
PORT_CERR_SENDSERVICE = 36, /* FIS received while sending service */
@@ -202,11 +219,19 @@ enum {
SGE_DRD = (1 << 29), /* discard data read (/dev/null)
data address ignored */
+ SIL24_MAX_CMDS = 31,
+
/* board id */
BID_SIL3124 = 0,
BID_SIL3132 = 1,
BID_SIL3131 = 2,
+ /* host flags */
+ SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+ ATA_FLAG_NCQ | ATA_FLAG_SKIP_D2H_BSY,
+ SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */
+
IRQ_STAT_4PORTS = 0xf,
};
@@ -226,6 +251,58 @@ union sil24_cmd_block {
struct sil24_atapi_block atapi;
};
+static struct sil24_cerr_info {
+ unsigned int err_mask, action;
+ const char *desc;
+} sil24_cerr_db[] = {
+ [0] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
+ "device error" },
+ [PORT_CERR_DEV] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
+ "device error via D2H FIS" },
+ [PORT_CERR_SDB] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
+ "device error via SDB FIS" },
+ [PORT_CERR_DATA] = { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET,
+ "error in data FIS" },
+ [PORT_CERR_SEND] = { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET,
+ "failed to transmit command FIS" },
+ [PORT_CERR_INCONSISTENT] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
+ "protocol mismatch" },
+ [PORT_CERR_DIRECTION] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
+ "data directon mismatch" },
+ [PORT_CERR_UNDERRUN] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
+ "ran out of SGEs while writing" },
+ [PORT_CERR_OVERRUN] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
+ "ran out of SGEs while reading" },
+ [PORT_CERR_PKT_PROT] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
+ "invalid data directon for ATAPI CDB" },
+ [PORT_CERR_SGT_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_SOFTRESET,
+ "SGT no on qword boundary" },
+ [PORT_CERR_SGT_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+ "PCI target abort while fetching SGT" },
+ [PORT_CERR_SGT_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+ "PCI master abort while fetching SGT" },
+ [PORT_CERR_SGT_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+ "PCI parity error while fetching SGT" },
+ [PORT_CERR_CMD_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_SOFTRESET,
+ "PRB not on qword boundary" },
+ [PORT_CERR_CMD_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+ "PCI target abort while fetching PRB" },
+ [PORT_CERR_CMD_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+ "PCI master abort while fetching PRB" },
+ [PORT_CERR_CMD_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+ "PCI parity error while fetching PRB" },
+ [PORT_CERR_XFR_UNDEF] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+ "undefined error while transferring data" },
+ [PORT_CERR_XFR_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+ "PCI target abort while transferring data" },
+ [PORT_CERR_XFR_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+ "PCI master abort while transferring data" },
+ [PORT_CERR_XFR_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+ "PCI parity error while transferring data" },
+ [PORT_CERR_SENDSERVICE] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
+ "FIS received while sending service FIS" },
+};
+
/*
* ap->private_data
*
@@ -249,12 +326,14 @@ static u8 sil24_check_status(struct ata_port *ap);
static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
-static int sil24_probe_reset(struct ata_port *ap, unsigned int *classes);
static void sil24_qc_prep(struct ata_queued_cmd *qc);
static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
static void sil24_irq_clear(struct ata_port *ap);
-static void sil24_eng_timeout(struct ata_port *ap);
static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static void sil24_freeze(struct ata_port *ap);
+static void sil24_thaw(struct ata_port *ap);
+static void sil24_error_handler(struct ata_port *ap);
+static void sil24_post_internal_cmd(struct ata_queued_cmd *qc);
static int sil24_port_start(struct ata_port *ap);
static void sil24_port_stop(struct ata_port *ap);
static void sil24_host_stop(struct ata_host_set *host_set);
@@ -281,7 +360,8 @@ static struct scsi_host_template sil24_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .can_queue = ATA_DEF_QUEUE,
+ .change_queue_depth = ata_scsi_change_queue_depth,
+ .can_queue = SIL24_MAX_CMDS,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
@@ -290,6 +370,7 @@ static struct scsi_host_template sil24_sht = {
.proc_name = DRV_NAME,
.dma_boundary = ATA_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
};
@@ -304,19 +385,20 @@ static const struct ata_port_operations sil24_ops = {
.tf_read = sil24_tf_read,
- .probe_reset = sil24_probe_reset,
-
.qc_prep = sil24_qc_prep,
.qc_issue = sil24_qc_issue,
- .eng_timeout = sil24_eng_timeout,
-
.irq_handler = sil24_interrupt,
.irq_clear = sil24_irq_clear,
.scr_read = sil24_scr_read,
.scr_write = sil24_scr_write,
+ .freeze = sil24_freeze,
+ .thaw = sil24_thaw,
+ .error_handler = sil24_error_handler,
+ .post_internal_cmd = sil24_post_internal_cmd,
+
.port_start = sil24_port_start,
.port_stop = sil24_port_stop,
.host_stop = sil24_host_stop,
@@ -333,9 +415,8 @@ static struct ata_port_info sil24_port_info[] = {
/* sil_3124 */
{
.sht = &sil24_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- SIL24_NPORTS2FLAG(4),
+ .host_flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) |
+ SIL24_FLAG_PCIX_IRQ_WOC,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x3f, /* udma0-5 */
@@ -344,9 +425,7 @@ static struct ata_port_info sil24_port_info[] = {
/* sil_3132 */
{
.sht = &sil24_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- SIL24_NPORTS2FLAG(2),
+ .host_flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2),
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x3f, /* udma0-5 */
@@ -355,9 +434,7 @@ static struct ata_port_info sil24_port_info[] = {
/* sil_3131/sil_3531 */
{
.sht = &sil24_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- SIL24_NPORTS2FLAG(1),
+ .host_flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1),
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x3f, /* udma0-5 */
@@ -365,6 +442,13 @@ static struct ata_port_info sil24_port_info[] = {
},
};
+static int sil24_tag(int tag)
+{
+ if (unlikely(ata_tag_internal(tag)))
+ return 0;
+ return tag;
+}
+
static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev)
{
void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
@@ -426,56 +510,65 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
*tf = pp->tf;
}
-static int sil24_softreset(struct ata_port *ap, int verbose,
- unsigned int *class)
+static int sil24_init_port(struct ata_port *ap)
+{
+ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ u32 tmp;
+
+ writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
+ ata_wait_register(port + PORT_CTRL_STAT,
+ PORT_CS_INIT, PORT_CS_INIT, 10, 100);
+ tmp = ata_wait_register(port + PORT_CTRL_STAT,
+ PORT_CS_RDY, 0, 10, 100);
+
+ if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY)
+ return -EIO;
+ return 0;
+}
+
+static int sil24_softreset(struct ata_port *ap, unsigned int *class)
{
void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
struct sil24_port_priv *pp = ap->private_data;
struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
dma_addr_t paddr = pp->cmd_block_dma;
- unsigned long timeout = jiffies + ATA_TMOUT_BOOT * HZ;
- u32 irq_enable, irq_stat;
+ u32 mask, irq_stat;
+ const char *reason;
DPRINTK("ENTER\n");
- if (!sata_dev_present(ap)) {
+ if (ata_port_offline(ap)) {
DPRINTK("PHY reports no device\n");
*class = ATA_DEV_NONE;
goto out;
}
- /* temporarily turn off IRQs during SRST */
- irq_enable = readl(port + PORT_IRQ_ENABLE_SET);
- writel(irq_enable, port + PORT_IRQ_ENABLE_CLR);
-
- /*
- * XXX: Not sure whether the following sleep is needed or not.
- * The original driver had it. So....
- */
- msleep(10);
+ /* put the port into known state */
+ if (sil24_init_port(ap)) {
+ reason ="port not ready";
+ goto err;
+ }
+ /* do SRST */
prb->ctrl = cpu_to_le16(PRB_CTRL_SRST);
prb->fis[1] = 0; /* no PM yet */
writel((u32)paddr, port + PORT_CMD_ACTIVATE);
+ writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
- do {
- irq_stat = readl(port + PORT_IRQ_STAT);
- writel(irq_stat, port + PORT_IRQ_STAT); /* clear irq */
-
- irq_stat >>= PORT_IRQ_RAW_SHIFT;
- if (irq_stat & (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR))
- break;
+ mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
+ irq_stat = ata_wait_register(port + PORT_IRQ_STAT, mask, 0x0,
+ 100, ATA_TMOUT_BOOT / HZ * 1000);
- msleep(100);
- } while (time_before(jiffies, timeout));
-
- /* restore IRQs */
- writel(irq_enable, port + PORT_IRQ_ENABLE_SET);
+ writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */
+ irq_stat >>= PORT_IRQ_RAW_SHIFT;
if (!(irq_stat & PORT_IRQ_COMPLETE)) {
- DPRINTK("EXIT, srst failed\n");
- return -EIO;
+ if (irq_stat & PORT_IRQ_ERROR)
+ reason = "SRST command error";
+ else
+ reason = "timeout";
+ goto err;
}
sil24_update_tf(ap);
@@ -487,22 +580,57 @@ static int sil24_softreset(struct ata_port *ap, int verbose,
out:
DPRINTK("EXIT, class=%u\n", *class);
return 0;
+
+ err:
+ ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
+ return -EIO;
}
-static int sil24_hardreset(struct ata_port *ap, int verbose,
- unsigned int *class)
+static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
{
- unsigned int dummy_class;
+ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ const char *reason;
+ int tout_msec, rc;
+ u32 tmp;
- /* sil24 doesn't report device signature after hard reset */
- return sata_std_hardreset(ap, verbose, &dummy_class);
-}
+ /* sil24 does the right thing(tm) without any protection */
+ sata_set_spd(ap);
-static int sil24_probe_reset(struct ata_port *ap, unsigned int *classes)
-{
- return ata_drive_probe_reset(ap, ata_std_probeinit,
- sil24_softreset, sil24_hardreset,
- ata_std_postreset, classes);
+ tout_msec = 100;
+ if (ata_port_online(ap))
+ tout_msec = 5000;
+
+ writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
+ tmp = ata_wait_register(port + PORT_CTRL_STAT,
+ PORT_CS_DEV_RST, PORT_CS_DEV_RST, 10, tout_msec);
+
+ /* SStatus oscillates between zero and valid status after
+ * DEV_RST, debounce it.
+ */
+ rc = sata_phy_debounce(ap, sata_deb_timing_before_fsrst);
+ if (rc) {
+ reason = "PHY debouncing failed";
+ goto err;
+ }
+
+ if (tmp & PORT_CS_DEV_RST) {
+ if (ata_port_offline(ap))
+ return 0;
+ reason = "link not ready";
+ goto err;
+ }
+
+ /* Sil24 doesn't store signature FIS after hardreset, so we
+ * can't wait for BSY to clear. Some devices take a long time
+ * to get ready and those devices will choke if we don't wait
+ * for BSY clearance here. Tell libata to perform follow-up
+ * softreset.
+ */
+ return -EAGAIN;
+
+ err:
+ ata_port_printk(ap, KERN_ERR, "hardreset failed (%s)\n", reason);
+ return -EIO;
}
static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
@@ -528,17 +656,20 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct sil24_port_priv *pp = ap->private_data;
- union sil24_cmd_block *cb = pp->cmd_block + qc->tag;
+ union sil24_cmd_block *cb;
struct sil24_prb *prb;
struct sil24_sge *sge;
+ u16 ctrl = 0;
+
+ cb = &pp->cmd_block[sil24_tag(qc->tag)];
switch (qc->tf.protocol) {
case ATA_PROT_PIO:
case ATA_PROT_DMA:
+ case ATA_PROT_NCQ:
case ATA_PROT_NODATA:
prb = &cb->ata.prb;
sge = cb->ata.sge;
- prb->ctrl = 0;
break;
case ATA_PROT_ATAPI:
@@ -551,12 +682,10 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
if (qc->tf.protocol != ATA_PROT_ATAPI_NODATA) {
if (qc->tf.flags & ATA_TFLAG_WRITE)
- prb->ctrl = cpu_to_le16(PRB_CTRL_PACKET_WRITE);
+ ctrl = PRB_CTRL_PACKET_WRITE;
else
- prb->ctrl = cpu_to_le16(PRB_CTRL_PACKET_READ);
- } else
- prb->ctrl = 0;
-
+ ctrl = PRB_CTRL_PACKET_READ;
+ }
break;
default:
@@ -565,6 +694,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
BUG();
}
+ prb->ctrl = cpu_to_le16(ctrl);
ata_tf_to_fis(&qc->tf, prb->fis, 0);
if (qc->flags & ATA_QCFLAG_DMAMAP)
@@ -574,11 +704,18 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
struct sil24_port_priv *pp = ap->private_data;
- dma_addr_t paddr = pp->cmd_block_dma + qc->tag * sizeof(*pp->cmd_block);
+ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ unsigned int tag = sil24_tag(qc->tag);
+ dma_addr_t paddr;
+ void __iomem *activate;
+
+ paddr = pp->cmd_block_dma + tag * sizeof(*pp->cmd_block);
+ activate = port + PORT_CMD_ACTIVATE + tag * 8;
+
+ writel((u32)paddr, activate);
+ writel((u64)paddr >> 32, activate + 4);
- writel((u32)paddr, port + PORT_CMD_ACTIVATE);
return 0;
}
@@ -587,162 +724,139 @@ static void sil24_irq_clear(struct ata_port *ap)
/* unused */
}
-static int __sil24_restart_controller(void __iomem *port)
+static void sil24_freeze(struct ata_port *ap)
{
- u32 tmp;
- int cnt;
-
- writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
-
- /* Max ~10ms */
- for (cnt = 0; cnt < 10000; cnt++) {
- tmp = readl(port + PORT_CTRL_STAT);
- if (tmp & PORT_CS_RDY)
- return 0;
- udelay(1);
- }
+ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
- return -1;
+ /* Port-wide IRQ mask in HOST_CTRL doesn't really work, clear
+ * PORT_IRQ_ENABLE instead.
+ */
+ writel(0xffff, port + PORT_IRQ_ENABLE_CLR);
}
-static void sil24_restart_controller(struct ata_port *ap)
+static void sil24_thaw(struct ata_port *ap)
{
- if (__sil24_restart_controller((void __iomem *)ap->ioaddr.cmd_addr))
- printk(KERN_ERR DRV_NAME
- " ata%u: failed to restart controller\n", ap->id);
+ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ u32 tmp;
+
+ /* clear IRQ */
+ tmp = readl(port + PORT_IRQ_STAT);
+ writel(tmp, port + PORT_IRQ_STAT);
+
+ /* turn IRQ back on */
+ writel(DEF_PORT_IRQ, port + PORT_IRQ_ENABLE_SET);
}
-static int __sil24_reset_controller(void __iomem *port)
+static void sil24_error_intr(struct ata_port *ap)
{
- int cnt;
- u32 tmp;
+ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ struct ata_eh_info *ehi = &ap->eh_info;
+ int freeze = 0;
+ u32 irq_stat;
- /* Reset controller state. Is this correct? */
- writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
- readl(port + PORT_CTRL_STAT); /* sync */
+ /* on error, we need to clear IRQ explicitly */
+ irq_stat = readl(port + PORT_IRQ_STAT);
+ writel(irq_stat, port + PORT_IRQ_STAT);
- /* Max ~100ms */
- for (cnt = 0; cnt < 1000; cnt++) {
- udelay(100);
- tmp = readl(port + PORT_CTRL_STAT);
- if (!(tmp & PORT_CS_DEV_RST))
- break;
- }
+ /* first, analyze and record host port events */
+ ata_ehi_clear_desc(ehi);
- if (tmp & PORT_CS_DEV_RST)
- return -1;
+ ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
- if (tmp & PORT_CS_RDY)
- return 0;
+ if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
+ ata_ehi_hotplugged(ehi);
+ ata_ehi_push_desc(ehi, ", %s",
+ irq_stat & PORT_IRQ_PHYRDY_CHG ?
+ "PHY RDY changed" : "device exchanged");
+ freeze = 1;
+ }
- return __sil24_restart_controller(port);
-}
+ if (irq_stat & PORT_IRQ_UNK_FIS) {
+ ehi->err_mask |= AC_ERR_HSM;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(ehi , ", unknown FIS");
+ freeze = 1;
+ }
-static void sil24_reset_controller(struct ata_port *ap)
-{
- printk(KERN_NOTICE DRV_NAME
- " ata%u: resetting controller...\n", ap->id);
- if (__sil24_reset_controller((void __iomem *)ap->ioaddr.cmd_addr))
- printk(KERN_ERR DRV_NAME
- " ata%u: failed to reset controller\n", ap->id);
-}
+ /* deal with command error */
+ if (irq_stat & PORT_IRQ_ERROR) {
+ struct sil24_cerr_info *ci = NULL;
+ unsigned int err_mask = 0, action = 0;
+ struct ata_queued_cmd *qc;
+ u32 cerr;
+
+ /* analyze CMD_ERR */
+ cerr = readl(port + PORT_CMD_ERR);
+ if (cerr < ARRAY_SIZE(sil24_cerr_db))
+ ci = &sil24_cerr_db[cerr];
+
+ if (ci && ci->desc) {
+ err_mask |= ci->err_mask;
+ action |= ci->action;
+ ata_ehi_push_desc(ehi, ", %s", ci->desc);
+ } else {
+ err_mask |= AC_ERR_OTHER;
+ action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(ehi, ", unknown command error %d",
+ cerr);
+ }
-static void sil24_eng_timeout(struct ata_port *ap)
-{
- struct ata_queued_cmd *qc;
+ /* record error info */
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc) {
+ sil24_update_tf(ap);
+ qc->err_mask |= err_mask;
+ } else
+ ehi->err_mask |= err_mask;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ ehi->action |= action;
+ }
- printk(KERN_ERR "ata%u: command timeout\n", ap->id);
- qc->err_mask |= AC_ERR_TIMEOUT;
- ata_eh_qc_complete(qc);
+ /* freeze or abort */
+ if (freeze)
+ ata_port_freeze(ap);
+ else
+ ata_port_abort(ap);
+}
- sil24_reset_controller(ap);
+static void sil24_finish_qc(struct ata_queued_cmd *qc)
+{
+ if (qc->flags & ATA_QCFLAG_RESULT_TF)
+ sil24_update_tf(qc->ap);
}
-static void sil24_error_intr(struct ata_port *ap, u32 slot_stat)
+static inline void sil24_host_intr(struct ata_port *ap)
{
- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
- struct sil24_port_priv *pp = ap->private_data;
void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
- u32 irq_stat, cmd_err, sstatus, serror;
- unsigned int err_mask;
+ u32 slot_stat, qc_active;
+ int rc;
- irq_stat = readl(port + PORT_IRQ_STAT);
- writel(irq_stat, port + PORT_IRQ_STAT); /* clear irq */
+ slot_stat = readl(port + PORT_SLOT_STAT);
- if (!(irq_stat & PORT_IRQ_ERROR)) {
- /* ignore non-completion, non-error irqs for now */
- printk(KERN_WARNING DRV_NAME
- "ata%u: non-error exception irq (irq_stat %x)\n",
- ap->id, irq_stat);
+ if (unlikely(slot_stat & HOST_SSTAT_ATTN)) {
+ sil24_error_intr(ap);
return;
}
- cmd_err = readl(port + PORT_CMD_ERR);
- sstatus = readl(port + PORT_SSTATUS);
- serror = readl(port + PORT_SERROR);
- if (serror)
- writel(serror, port + PORT_SERROR);
+ if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC)
+ writel(PORT_IRQ_COMPLETE, port + PORT_IRQ_STAT);
- /*
- * Don't log ATAPI device errors. They're supposed to happen
- * and any serious errors will be logged using sense data by
- * the SCSI layer.
- */
- if (ap->device[0].class != ATA_DEV_ATAPI || cmd_err > PORT_CERR_SDB)
- printk("ata%u: error interrupt on port%d\n"
- " stat=0x%x irq=0x%x cmd_err=%d sstatus=0x%x serror=0x%x\n",
- ap->id, ap->port_no, slot_stat, irq_stat, cmd_err, sstatus, serror);
-
- if (cmd_err == PORT_CERR_DEV || cmd_err == PORT_CERR_SDB) {
- /*
- * Device is reporting error, tf registers are valid.
- */
- sil24_update_tf(ap);
- err_mask = ac_err_mask(pp->tf.command);
- sil24_restart_controller(ap);
- } else {
- /*
- * Other errors. libata currently doesn't have any
- * mechanism to report these errors. Just turn on
- * ATA_ERR.
- */
- err_mask = AC_ERR_OTHER;
- sil24_reset_controller(ap);
+ qc_active = slot_stat & ~HOST_SSTAT_ATTN;
+ rc = ata_qc_complete_multiple(ap, qc_active, sil24_finish_qc);
+ if (rc > 0)
+ return;
+ if (rc < 0) {
+ struct ata_eh_info *ehi = &ap->eh_info;
+ ehi->err_mask |= AC_ERR_HSM;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ata_port_freeze(ap);
+ return;
}
- if (qc) {
- qc->err_mask |= err_mask;
- ata_qc_complete(qc);
- }
-}
-
-static inline void sil24_host_intr(struct ata_port *ap)
-{
- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
- u32 slot_stat;
-
- slot_stat = readl(port + PORT_SLOT_STAT);
- if (!(slot_stat & HOST_SSTAT_ATTN)) {
- struct sil24_port_priv *pp = ap->private_data;
- /*
- * !HOST_SSAT_ATTN guarantees successful completion,
- * so reading back tf registers is unnecessary for
- * most commands. TODO: read tf registers for
- * commands which require these values on successful
- * completion (EXECUTE DEVICE DIAGNOSTIC, CHECK POWER,
- * DEVICE RESET and READ PORT MULTIPLIER (any more?).
- */
- sil24_update_tf(ap);
-
- if (qc) {
- qc->err_mask |= ac_err_mask(pp->tf.command);
- ata_qc_complete(qc);
- }
- } else
- sil24_error_intr(ap, slot_stat);
+ if (ata_ratelimit())
+ ata_port_printk(ap, KERN_INFO, "spurious interrupt "
+ "(slot_stat 0x%x active_tag %d sactive 0x%x)\n",
+ slot_stat, ap->active_tag, ap->sactive);
}
static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
@@ -769,7 +883,7 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *
for (i = 0; i < host_set->n_ports; i++)
if (status & (1 << i)) {
struct ata_port *ap = host_set->ports[i];
- if (ap && !(ap->flags & ATA_FLAG_PORT_DISABLED)) {
+ if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
sil24_host_intr(host_set->ports[i]);
handled++;
} else
@@ -782,9 +896,35 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *
return IRQ_RETVAL(handled);
}
+static void sil24_error_handler(struct ata_port *ap)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+
+ if (sil24_init_port(ap)) {
+ ata_eh_freeze_port(ap);
+ ehc->i.action |= ATA_EH_HARDRESET;
+ }
+
+ /* perform recovery */
+ ata_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset,
+ ata_std_postreset);
+}
+
+static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ if (qc->flags & ATA_QCFLAG_FAILED)
+ qc->err_mask |= AC_ERR_OTHER;
+
+ /* make DMA engine forget about the failed command */
+ if (qc->err_mask)
+ sil24_init_port(ap);
+}
+
static inline void sil24_cblk_free(struct sil24_port_priv *pp, struct device *dev)
{
- const size_t cb_size = sizeof(*pp->cmd_block);
+ const size_t cb_size = sizeof(*pp->cmd_block) * SIL24_MAX_CMDS;
dma_free_coherent(dev, cb_size, pp->cmd_block, pp->cmd_block_dma);
}
@@ -794,7 +934,7 @@ static int sil24_port_start(struct ata_port *ap)
struct device *dev = ap->host_set->dev;
struct sil24_port_priv *pp;
union sil24_cmd_block *cb;
- size_t cb_size = sizeof(*cb);
+ size_t cb_size = sizeof(*cb) * SIL24_MAX_CMDS;
dma_addr_t cb_dma;
int rc = -ENOMEM;
@@ -858,6 +998,7 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
void __iomem *host_base = NULL;
void __iomem *port_base = NULL;
int i, rc;
+ u32 tmp;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -910,37 +1051,53 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/*
* Configure the device
*/
- /*
- * FIXME: This device is certainly 64-bit capable. We just
- * don't know how to use it. After fixing 32bit activation in
- * this function, enable 64bit masks here.
- */
- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit DMA enable failed\n");
- goto out_free;
- }
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit consistent DMA enable failed\n");
- goto out_free;
+ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ if (rc) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "64-bit DMA enable failed\n");
+ goto out_free;
+ }
+ }
+ } else {
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit DMA enable failed\n");
+ goto out_free;
+ }
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit consistent DMA enable failed\n");
+ goto out_free;
+ }
}
/* GPIO off */
writel(0, host_base + HOST_FLASH_CMD);
- /* Mask interrupts during initialization */
+ /* Apply workaround for completion IRQ loss on PCI-X errata */
+ if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC) {
+ tmp = readl(host_base + HOST_CTRL);
+ if (tmp & (HOST_CTRL_TRDY | HOST_CTRL_STOP | HOST_CTRL_DEVSEL))
+ dev_printk(KERN_INFO, &pdev->dev,
+ "Applying completion IRQ loss on PCI-X "
+ "errata fix\n");
+ else
+ probe_ent->host_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;
+ }
+
+ /* clear global reset & mask interrupts during initialization */
writel(0, host_base + HOST_CTRL);
for (i = 0; i < probe_ent->n_ports; i++) {
void __iomem *port = port_base + i * PORT_REGS_SIZE;
unsigned long portu = (unsigned long)port;
- u32 tmp;
- int cnt;
- probe_ent->port[i].cmd_addr = portu + PORT_PRB;
+ probe_ent->port[i].cmd_addr = portu;
probe_ent->port[i].scr_addr = portu + PORT_SCONTROL;
ata_std_ports(&probe_ent->port[i]);
@@ -952,18 +1109,20 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tmp = readl(port + PORT_CTRL_STAT);
if (tmp & PORT_CS_PORT_RST) {
writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
- readl(port + PORT_CTRL_STAT); /* sync */
- for (cnt = 0; cnt < 10; cnt++) {
- msleep(10);
- tmp = readl(port + PORT_CTRL_STAT);
- if (!(tmp & PORT_CS_PORT_RST))
- break;
- }
+ tmp = ata_wait_register(port + PORT_CTRL_STAT,
+ PORT_CS_PORT_RST,
+ PORT_CS_PORT_RST, 10, 100);
if (tmp & PORT_CS_PORT_RST)
dev_printk(KERN_ERR, &pdev->dev,
"failed to clear port RST\n");
}
+ /* Configure IRQ WoC */
+ if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
+ writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
+ else
+ writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
+
/* Zero error counters. */
writel(0x8000, port + PORT_DECODE_ERR_THRESH);
writel(0x8000, port + PORT_CRC_ERR_THRESH);
@@ -972,26 +1131,11 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
writel(0x0000, port + PORT_CRC_ERR_CNT);
writel(0x0000, port + PORT_HSHK_ERR_CNT);
- /* FIXME: 32bit activation? */
- writel(0, port + PORT_ACTIVATE_UPPER_ADDR);
- writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_STAT);
-
- /* Configure interrupts */
- writel(0xffff, port + PORT_IRQ_ENABLE_CLR);
- writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR | PORT_IRQ_SDB_FIS,
- port + PORT_IRQ_ENABLE_SET);
-
- /* Clear interrupts */
- writel(0x0fff0fff, port + PORT_IRQ_STAT);
- writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
+ /* Always use 64bit activation */
+ writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
/* Clear port multiplier enable and resume bits */
writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
-
- /* Reset itself */
- if (__sil24_reset_controller(port))
- dev_printk(KERN_ERR, &pdev->dev,
- "failed to reset controller\n");
}
/* Turn on interrupts */
diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c
index 728530d..809d337 100644
--- a/drivers/scsi/sata_sis.c
+++ b/drivers/scsi/sata_sis.c
@@ -43,7 +43,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_sis"
-#define DRV_VERSION "0.5"
+#define DRV_VERSION "0.6"
enum {
sis_180 = 0,
@@ -96,6 +96,7 @@ static struct scsi_host_template sis_sht = {
.proc_name = DRV_NAME,
.dma_boundary = ATA_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
};
@@ -106,14 +107,17 @@ static const struct ata_port_operations sis_ops = {
.check_status = ata_check_status,
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
- .phy_reset = sata_phy_reset,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+ .data_xfer = ata_pio_data_xfer,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.scr_read = sis_scr_read,
@@ -125,8 +129,7 @@ static const struct ata_port_operations sis_ops = {
static struct ata_port_info sis_port_info = {
.sht = &sis_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
- ATA_FLAG_NO_LEGACY,
+ .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
.pio_mask = 0x1f,
.mwdma_mask = 0x7,
.udma_mask = 0x7f,
diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c
index 53b0d5c..c94b870 100644
--- a/drivers/scsi/sata_svw.c
+++ b/drivers/scsi/sata_svw.c
@@ -54,7 +54,7 @@
#endif /* CONFIG_PPC_OF */
#define DRV_NAME "sata_svw"
-#define DRV_VERSION "1.07"
+#define DRV_VERSION "1.8"
enum {
/* Taskfile registers offsets */
@@ -257,7 +257,7 @@ static int k2_sata_proc_info(struct Scsi_Host *shost, char *page, char **start,
int len, index;
/* Find the ata_port */
- ap = (struct ata_port *) &shost->hostdata[0];
+ ap = ata_shost_to_port(shost);
if (ap == NULL)
return 0;
@@ -299,6 +299,7 @@ static struct scsi_host_template k2_sata_sht = {
.proc_name = DRV_NAME,
.dma_boundary = ATA_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
#ifdef CONFIG_PPC_OF
.proc_info = k2_sata_proc_info,
#endif
@@ -313,14 +314,17 @@ static const struct ata_port_operations k2_sata_ops = {
.check_status = k2_stat_check_status,
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
- .phy_reset = sata_phy_reset,
.bmdma_setup = k2_bmdma_setup_mmio,
.bmdma_start = k2_bmdma_start_mmio,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+ .data_xfer = ata_mmio_data_xfer,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.scr_read = k2_sata_scr_read,
@@ -420,8 +424,8 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
writel(0x0, mmio_base + K2_SATA_SIM_OFFSET);
probe_ent->sht = &k2_sata_sht;
- probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
- ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO;
+ probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO;
probe_ent->port_ops = &k2_sata_ops;
probe_ent->n_ports = 4;
probe_ent->irq = pdev->irq;
diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c
index 4139ad4..7f86441 100644
--- a/drivers/scsi/sata_sx4.c
+++ b/drivers/scsi/sata_sx4.c
@@ -46,7 +46,7 @@
#include "sata_promise.h"
#define DRV_NAME "sata_sx4"
-#define DRV_VERSION "0.8"
+#define DRV_VERSION "0.9"
enum {
@@ -191,6 +191,7 @@ static struct scsi_host_template pdc_sata_sht = {
.proc_name = DRV_NAME,
.dma_boundary = ATA_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
};
@@ -204,6 +205,7 @@ static const struct ata_port_operations pdc_20621_ops = {
.phy_reset = pdc_20621_phy_reset,
.qc_prep = pdc20621_qc_prep,
.qc_issue = pdc20621_qc_issue_prot,
+ .data_xfer = ata_mmio_data_xfer,
.eng_timeout = pdc_eng_timeout,
.irq_handler = pdc20621_interrupt,
.irq_clear = pdc20621_irq_clear,
@@ -218,7 +220,7 @@ static const struct ata_port_info pdc_port_info[] = {
.sht = &pdc_sata_sht,
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_SRST | ATA_FLAG_MMIO |
- ATA_FLAG_NO_ATAPI,
+ ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
@@ -833,11 +835,11 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_re
tmp = mask & (1 << i);
VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp);
if (tmp && ap &&
- !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
+ !(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN)))
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled += pdc20621_host_intr(ap, qc, (i > 4),
mmio_base);
}
@@ -868,15 +870,16 @@ static void pdc_eng_timeout(struct ata_port *ap)
switch (qc->tf.protocol) {
case ATA_PROT_DMA:
case ATA_PROT_NODATA:
- printk(KERN_ERR "ata%u: command timeout\n", ap->id);
+ ata_port_printk(ap, KERN_ERR, "command timeout\n");
qc->err_mask |= __ac_err_mask(ata_wait_idle(ap));
break;
default:
drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
- printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n",
- ap->id, qc->tf.command, drv_stat);
+ ata_port_printk(ap, KERN_ERR,
+ "unknown timeout, cmd 0x%x stat 0x%x\n",
+ qc->tf.command, drv_stat);
qc->err_mask |= ac_err_mask(drv_stat);
break;
@@ -1375,10 +1378,6 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- /*
- * If this driver happens to only be useful on Apple's K2, then
- * we should check that here as it has a normal Serverworks ID
- */
rc = pci_enable_device(pdev);
if (rc)
return rc;
diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c
index 38b52bd..f668c99 100644
--- a/drivers/scsi/sata_uli.c
+++ b/drivers/scsi/sata_uli.c
@@ -37,7 +37,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_uli"
-#define DRV_VERSION "0.5"
+#define DRV_VERSION "0.6"
enum {
uli_5289 = 0,
@@ -90,6 +90,7 @@ static struct scsi_host_template uli_sht = {
.proc_name = DRV_NAME,
.dma_boundary = ATA_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
};
@@ -102,16 +103,18 @@ static const struct ata_port_operations uli_ops = {
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
- .phy_reset = sata_phy_reset,
-
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
- .eng_timeout = ata_eng_timeout,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
@@ -126,8 +129,7 @@ static const struct ata_port_operations uli_ops = {
static struct ata_port_info uli_port_info = {
.sht = &uli_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
- ATA_FLAG_NO_LEGACY,
+ .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &uli_ops,
diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c
index 9e7ae4e..322890b 100644
--- a/drivers/scsi/sata_via.c
+++ b/drivers/scsi/sata_via.c
@@ -47,7 +47,7 @@
#include <asm/io.h>
#define DRV_NAME "sata_via"
-#define DRV_VERSION "1.1"
+#define DRV_VERSION "1.2"
enum board_ids_enum {
vt6420,
@@ -103,6 +103,7 @@ static struct scsi_host_template svia_sht = {
.proc_name = DRV_NAME,
.dma_boundary = ATA_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
};
@@ -115,8 +116,6 @@ static const struct ata_port_operations svia_sata_ops = {
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
- .phy_reset = sata_phy_reset,
-
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
@@ -124,8 +123,12 @@ static const struct ata_port_operations svia_sata_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
- .eng_timeout = ata_eng_timeout,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
@@ -140,7 +143,7 @@ static const struct ata_port_operations svia_sata_ops = {
static struct ata_port_info svia_port_info = {
.sht = &svia_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | ATA_FLAG_NO_LEGACY,
+ .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
.pio_mask = 0x1f,
.mwdma_mask = 0x07,
.udma_mask = 0x7f,
@@ -235,8 +238,7 @@ static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev)
INIT_LIST_HEAD(&probe_ent->node);
probe_ent->sht = &svia_sht;
- probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
- ATA_FLAG_NO_LEGACY;
+ probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY;
probe_ent->port_ops = &svia_sata_ops;
probe_ent->n_ports = N_PORTS;
probe_ent->irq = pdev->irq;
diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c
index 8a29ce3..6d0c4f1 100644
--- a/drivers/scsi/sata_vsc.c
+++ b/drivers/scsi/sata_vsc.c
@@ -221,14 +221,21 @@ static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance,
ap = host_set->ports[i];
- if (ap && !(ap->flags &
- (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) {
+ if (is_vsc_sata_int_err(i, int_status)) {
+ u32 err_status;
+ printk(KERN_DEBUG "%s: ignoring interrupt(s)\n", __FUNCTION__);
+ err_status = ap ? vsc_sata_scr_read(ap, SCR_ERROR) : 0;
+ vsc_sata_scr_write(ap, SCR_ERROR, err_status);
+ handled++;
+ }
+
+ if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled += ata_host_intr(ap, qc);
- } else if (is_vsc_sata_int_err(i, int_status)) {
+ else if (is_vsc_sata_int_err(i, int_status)) {
/*
* On some chips (i.e. Intel 31244), an error
* interrupt will sneak in at initialization
@@ -272,6 +279,7 @@ static struct scsi_host_template vsc_sata_sht = {
.proc_name = DRV_NAME,
.dma_boundary = ATA_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
};
@@ -283,14 +291,17 @@ static const struct ata_port_operations vsc_sata_ops = {
.exec_command = ata_exec_command,
.check_status = ata_check_status,
.dev_select = ata_std_dev_select,
- .phy_reset = sata_phy_reset,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+ .data_xfer = ata_pio_data_xfer,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = vsc_sata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.scr_read = vsc_sata_scr_read,
@@ -385,7 +396,7 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
probe_ent->sht = &vsc_sata_sht;
probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_SATA_RESET;
+ ATA_FLAG_MMIO;
probe_ent->port_ops = &vsc_sata_ops;
probe_ent->n_ports = 4;
probe_ent->irq = pdev->irq;
@@ -433,13 +444,14 @@ err_out:
/*
- * 0x1725/0x7174 is the Vitesse VSC-7174
- * 0x8086/0x3200 is the Intel 31244, which is supposed to be identical
- * compatibility is untested as of yet
+ * Intel 31244 is supposed to be identical.
+ * Compatibility is untested as of yet.
*/
static const struct pci_device_id vsc_sata_pci_tbl[] = {
- { 0x1725, 0x7174, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
- { 0x8086, 0x3200, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
+ { PCI_VENDOR_ID_VITESSE, PCI_DEVICE_ID_VITESSE_VSC7174,
+ PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GD31244,
+ PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
{ }
};
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 3e90ba7..2ab7df0 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -579,6 +579,24 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
static DEFINE_PER_CPU(struct list_head, scsi_done_q);
/**
+ * scsi_req_abort_cmd -- Request command recovery for the specified command
+ * cmd: pointer to the SCSI command of interest
+ *
+ * This function requests that SCSI Core start recovery for the
+ * command by deleting the timer and adding the command to the eh
+ * queue. It can be called by either LLDDs or SCSI Core. LLDDs who
+ * implement their own error recovery MAY ignore the timeout event if
+ * they generated scsi_req_abort_cmd.
+ */
+void scsi_req_abort_cmd(struct scsi_cmnd *cmd)
+{
+ if (!scsi_delete_timer(cmd))
+ return;
+ scsi_times_out(cmd);
+}
+EXPORT_SYMBOL(scsi_req_abort_cmd);
+
+/**
* scsi_done - Enqueue the finished SCSI command into the done queue.
* @cmd: The SCSI Command for which a low-level device driver (LLDD) gives
* ownership back to SCSI Core -- i.e. the LLDD has finished with it.
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 1c7d993..6a7a60f 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -58,6 +58,28 @@ void scsi_eh_wakeup(struct Scsi_Host *shost)
}
/**
+ * scsi_schedule_eh - schedule EH for SCSI host
+ * @shost: SCSI host to invoke error handling on.
+ *
+ * Schedule SCSI EH without scmd.
+ **/
+void scsi_schedule_eh(struct Scsi_Host *shost)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(shost->host_lock, flags);
+
+ if (scsi_host_set_state(shost, SHOST_RECOVERY) == 0 ||
+ scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY) == 0) {
+ shost->host_eh_scheduled++;
+ scsi_eh_wakeup(shost);
+ }
+
+ spin_unlock_irqrestore(shost->host_lock, flags);
+}
+EXPORT_SYMBOL_GPL(scsi_schedule_eh);
+
+/**
* scsi_eh_scmd_add - add scsi cmd to error handling.
* @scmd: scmd to run eh on.
* @eh_flag: optional SCSI_EH flag.
@@ -1515,7 +1537,7 @@ int scsi_error_handler(void *data)
*/
set_current_state(TASK_INTERRUPTIBLE);
while (!kthread_should_stop()) {
- if (shost->host_failed == 0 ||
+ if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) ||
shost->host_failed != shost->host_busy) {
SCSI_LOG_ERROR_RECOVERY(1,
printk("Error handler scsi_eh_%d sleeping\n",
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 3302d80..3d04a9f 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -500,7 +500,7 @@ void scsi_device_unbusy(struct scsi_device *sdev)
spin_lock_irqsave(shost->host_lock, flags);
shost->host_busy--;
if (unlikely(scsi_host_in_recovery(shost) &&
- shost->host_failed))
+ (shost->host_failed || shost->host_eh_scheduled)))
scsi_eh_wakeup(shost);
spin_unlock(shost->host_lock);
spin_lock(sdev->request_queue->queue_lock);
diff --git a/drivers/scsi/scsi_transport_api.h b/drivers/scsi/scsi_transport_api.h
new file mode 100644
index 0000000..934f0e6
--- /dev/null
+++ b/drivers/scsi/scsi_transport_api.h
@@ -0,0 +1,6 @@
+#ifndef _SCSI_TRANSPORT_API_H
+#define _SCSI_TRANSPORT_API_H
+
+void scsi_schedule_eh(struct Scsi_Host *shost);
+
+#endif /* _SCSI_TRANSPORT_API_H */
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index ad87d73..1272dd2 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -1193,7 +1193,7 @@ static int st_open(struct inode *inode, struct file *filp)
/* Flush the tape buffer before close */
-static int st_flush(struct file *filp)
+static int st_flush(struct file *filp, fl_owner_t id)
{
int result = 0, result2;
unsigned char cmd[MAX_COMMAND_SIZE];
diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c
index cc990be..2e2c1eb 100644
--- a/drivers/scsi/sun3x_esp.c
+++ b/drivers/scsi/sun3x_esp.c
@@ -332,11 +332,11 @@ static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp)
struct scatterlist *sg = sp->SCp.buffer;
while (sz >= 0) {
- sg[sz].dvma_address = dvma_map((unsigned long)page_address(sg[sz].page) +
+ sg[sz].dma_address = dvma_map((unsigned long)page_address(sg[sz].page) +
sg[sz].offset, sg[sz].length);
sz--;
}
- sp->SCp.ptr=(char *)((unsigned long)sp->SCp.buffer->dvma_address);
+ sp->SCp.ptr=(char *)((unsigned long)sp->SCp.buffer->dma_address);
}
static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp)
@@ -350,14 +350,14 @@ static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp)
struct scatterlist *sg = (struct scatterlist *)sp->buffer;
while(sz >= 0) {
- dvma_unmap((char *)sg[sz].dvma_address);
+ dvma_unmap((char *)sg[sz].dma_address);
sz--;
}
}
static void dma_advance_sg (Scsi_Cmnd *sp)
{
- sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address);
+ sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dma_address);
}
static int sun3x_esp_release(struct Scsi_Host *instance)
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index 9341703..27307fe 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -939,6 +939,7 @@ wd33c93_intr(struct Scsi_Host *instance)
DB(DB_INTR, printk("%02x", cmd->SCp.Status))
if (hostdata->level2 >= L2_BASIC) {
sr = read_wd33c93(regs, WD_SCSI_STATUS); /* clear interrupt */
+ udelay(7);
hostdata->state = S_RUNNING_LEVEL2;
write_wd33c93(regs, WD_COMMAND_PHASE, 0x50);
write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);
@@ -955,6 +956,7 @@ wd33c93_intr(struct Scsi_Host *instance)
msg = read_1_byte(regs);
sr = read_wd33c93(regs, WD_SCSI_STATUS); /* clear interrupt */
+ udelay(7);
hostdata->incoming_msg[hostdata->incoming_ptr] = msg;
if (hostdata->incoming_msg[0] == EXTENDED_MESSAGE)
@@ -1358,6 +1360,7 @@ wd33c93_intr(struct Scsi_Host *instance)
} else {
/* Verify this is a change to MSG_IN and read the message */
sr = read_wd33c93(regs, WD_SCSI_STATUS);
+ udelay(7);
if (sr == (CSR_ABORT | PHS_MESS_IN) ||
sr == (CSR_UNEXP | PHS_MESS_IN) ||
sr == (CSR_SRV_REQ | PHS_MESS_IN)) {
@@ -1374,6 +1377,7 @@ wd33c93_intr(struct Scsi_Host *instance)
asr);
}
sr = read_wd33c93(regs, WD_SCSI_STATUS);
+ udelay(7);
if (sr != CSR_MSGIN)
printk
("wd33c93: Not paused with ACK on RESEL (%02x)\n",
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index e55f0ee..574955b 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -1391,7 +1391,7 @@ static int wd7000_proc_info(struct Scsi_Host *host, char *buffer, char **start,
*
*/
-static int wd7000_detect(struct scsi_host_template *tpnt)
+static __init int wd7000_detect(struct scsi_host_template *tpnt)
{
short present = 0, biosaddr_ptr, sig_ptr, i, pass;
short biosptr[NUM_CONFIGS];
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 5ea778f..5b48ac2 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -354,21 +354,24 @@ config SERIAL_CLPS711X_CONSOLE
kernel at boot time.)
config SERIAL_S3C2410
- tristate "Samsung S3C2410 Serial port support"
+ tristate "Samsung S3C2410/S3C2440/S3C2442/S3C2412 Serial port support"
depends on ARM && ARCH_S3C2410
select SERIAL_CORE
help
- Support for the on-chip UARTs on the Samsung S3C2410X CPU,
+ Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
providing /dev/ttySAC0, 1 and 2 (note, some machines may not
provide all of these ports, depending on how the serial port
pins are configured.
+ Currently this driver supports the UARTS on the S3C2410, S3C2440,
+ S3C2442, S3C2412 and S3C2413 CPUs.
+
config SERIAL_S3C2410_CONSOLE
bool "Support for console on S3C2410 serial port"
depends on SERIAL_S3C2410=y
select SERIAL_CORE_CONSOLE
help
- Allow selection of the S3C2410 on-board serial ports for use as
+ Allow selection of the S3C24XX on-board serial ports for use as
an virtual console.
Even if you say Y here, the currently visible virtual console
@@ -937,4 +940,23 @@ config SERIAL_SGI_IOC3
If you have an SGI Altix with an IOC3 serial card,
say Y or M. Otherwise, say N.
+config SERIAL_NETX
+ bool "NetX serial port support"
+ depends on ARM && ARCH_NETX
+ select SERIAL_CORE
+ help
+ If you have a machine based on a Hilscher NetX SoC you
+ can enable its onboard serial port by enabling this option.
+
+ To compile this driver as a module, choose M here: the
+ module will be called netx-serial.
+
+config SERIAL_NETX_CONSOLE
+ bool "Console on NetX serial port"
+ depends on SERIAL_NETX
+ select SERIAL_CORE_CONSOLE
+ help
+ If you have enabled the serial port on the Motorola IMX
+ CPU you can make it the console by answering Y to this option.
+
endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 0a71bf6..927faee 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -55,3 +55,4 @@ obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
obj-$(CONFIG_SERIAL_AT91) += at91_serial.o
+obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c
index 1631414..e920d19 100644
--- a/drivers/serial/amba-pl010.c
+++ b/drivers/serial/amba-pl010.c
@@ -52,7 +52,7 @@
#include <asm/io.h>
-#define UART_NR 2
+#define UART_NR 8
#define SERIAL_AMBA_MAJOR 204
#define SERIAL_AMBA_MINOR 16
diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c
index c620209..717e47b 100644
--- a/drivers/serial/ioc4_serial.c
+++ b/drivers/serial/ioc4_serial.c
@@ -2646,7 +2646,10 @@ static int ioc4_serial_remove_one(struct ioc4_driver_data *idd)
struct ioc4_port *port;
struct ioc4_soft *soft;
+ /* If serial driver did not attach, don't try to detach */
control = idd->idd_serial_data;
+ if (!control)
+ return 0;
for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) {
for (port_type = UART_PORT_MIN;
@@ -2778,6 +2781,12 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, idd->idd_pdev,
idd->idd_pci_id));
+ /* PCI-RT does not bring out serial connections.
+ * Do not attach to this particular IOC4.
+ */
+ if (idd->idd_variant == IOC4_VARIANT_PCI_RT)
+ return 0;
+
/* request serial registers */
tmp_addr1 = idd->idd_bar0 + IOC4_SERIAL_OFFSET;
diff --git a/drivers/serial/netx-serial.c b/drivers/serial/netx-serial.c
new file mode 100644
index 0000000..c1adc9e
--- /dev/null
+++ b/drivers/serial/netx-serial.c
@@ -0,0 +1,749 @@
+/*
+ * drivers/serial/netx-serial.c
+ *
+ * Copyright (c) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/config.h>
+
+#if defined(CONFIG_SERIAL_NETX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/arch/netx-regs.h>
+
+/* We've been assigned a range on the "Low-density serial ports" major */
+#define SERIAL_NX_MAJOR 204
+#define MINOR_START 170
+
+#ifdef CONFIG_SERIAL_NETX_CONSOLE
+
+enum uart_regs {
+ UART_DR = 0x00,
+ UART_SR = 0x04,
+ UART_LINE_CR = 0x08,
+ UART_BAUDDIV_MSB = 0x0c,
+ UART_BAUDDIV_LSB = 0x10,
+ UART_CR = 0x14,
+ UART_FR = 0x18,
+ UART_IIR = 0x1c,
+ UART_ILPR = 0x20,
+ UART_RTS_CR = 0x24,
+ UART_RTS_LEAD = 0x28,
+ UART_RTS_TRAIL = 0x2c,
+ UART_DRV_ENABLE = 0x30,
+ UART_BRM_CR = 0x34,
+ UART_RXFIFO_IRQLEVEL = 0x38,
+ UART_TXFIFO_IRQLEVEL = 0x3c,
+};
+
+#define SR_FE (1<<0)
+#define SR_PE (1<<1)
+#define SR_BE (1<<2)
+#define SR_OE (1<<3)
+
+#define LINE_CR_BRK (1<<0)
+#define LINE_CR_PEN (1<<1)
+#define LINE_CR_EPS (1<<2)
+#define LINE_CR_STP2 (1<<3)
+#define LINE_CR_FEN (1<<4)
+#define LINE_CR_5BIT (0<<5)
+#define LINE_CR_6BIT (1<<5)
+#define LINE_CR_7BIT (2<<5)
+#define LINE_CR_8BIT (3<<5)
+#define LINE_CR_BITS_MASK (3<<5)
+
+#define CR_UART_EN (1<<0)
+#define CR_SIREN (1<<1)
+#define CR_SIRLP (1<<2)
+#define CR_MSIE (1<<3)
+#define CR_RIE (1<<4)
+#define CR_TIE (1<<5)
+#define CR_RTIE (1<<6)
+#define CR_LBE (1<<7)
+
+#define FR_CTS (1<<0)
+#define FR_DSR (1<<1)
+#define FR_DCD (1<<2)
+#define FR_BUSY (1<<3)
+#define FR_RXFE (1<<4)
+#define FR_TXFF (1<<5)
+#define FR_RXFF (1<<6)
+#define FR_TXFE (1<<7)
+
+#define IIR_MIS (1<<0)
+#define IIR_RIS (1<<1)
+#define IIR_TIS (1<<2)
+#define IIR_RTIS (1<<3)
+#define IIR_MASK 0xf
+
+#define RTS_CR_AUTO (1<<0)
+#define RTS_CR_RTS (1<<1)
+#define RTS_CR_COUNT (1<<2)
+#define RTS_CR_MOD2 (1<<3)
+#define RTS_CR_RTS_POL (1<<4)
+#define RTS_CR_CTS_CTR (1<<5)
+#define RTS_CR_CTS_POL (1<<6)
+#define RTS_CR_STICK (1<<7)
+
+#define UART_PORT_SIZE 0x40
+#define DRIVER_NAME "netx-uart"
+
+struct netx_port {
+ struct uart_port port;
+};
+
+static void netx_stop_tx(struct uart_port *port)
+{
+ unsigned int val;
+ val = readl(port->membase + UART_CR);
+ writel(val & ~CR_TIE, port->membase + UART_CR);
+}
+
+static void netx_stop_rx(struct uart_port *port)
+{
+ unsigned int val;
+ val = readl(port->membase + UART_CR);
+ writel(val & ~CR_RIE, port->membase + UART_CR);
+}
+
+static void netx_enable_ms(struct uart_port *port)
+{
+ unsigned int val;
+ val = readl(port->membase + UART_CR);
+ writel(val | CR_MSIE, port->membase + UART_CR);
+}
+
+static inline void netx_transmit_buffer(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->info->xmit;
+
+ if (port->x_char) {
+ writel(port->x_char, port->membase + UART_DR);
+ port->icount.tx++;
+ port->x_char = 0;
+ return;
+ }
+
+ if (uart_tx_stopped(port) || uart_circ_empty(xmit)) {
+ netx_stop_tx(port);
+ return;
+ }
+
+ do {
+ /* send xmit->buf[xmit->tail]
+ * out the port here */
+ writel(xmit->buf[xmit->tail], port->membase + UART_DR);
+ xmit->tail = (xmit->tail + 1) &
+ (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ if (uart_circ_empty(xmit))
+ break;
+ } while (!(readl(port->membase + UART_FR) & FR_TXFF));
+
+ if (uart_circ_empty(xmit))
+ netx_stop_tx(port);
+}
+
+static void netx_start_tx(struct uart_port *port)
+{
+ writel(
+ readl(port->membase + UART_CR) | CR_TIE, port->membase + UART_CR);
+
+ if (!(readl(port->membase + UART_FR) & FR_TXFF))
+ netx_transmit_buffer(port);
+}
+
+static unsigned int netx_tx_empty(struct uart_port *port)
+{
+ return readl(port->membase + UART_FR) & FR_BUSY ? 0 : TIOCSER_TEMT;
+}
+
+static void netx_txint(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->info->xmit;
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ netx_stop_tx(port);
+ return;
+ }
+
+ netx_transmit_buffer(port);
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+}
+
+static void netx_rxint(struct uart_port *port, struct pt_regs *regs)
+{
+ unsigned char rx, flg, status;
+ struct tty_struct *tty = port->info->tty;
+
+ while (!(readl(port->membase + UART_FR) & FR_RXFE)) {
+ rx = readl(port->membase + UART_DR);
+ flg = TTY_NORMAL;
+ port->icount.rx++;
+ status = readl(port->membase + UART_SR);
+ if (status & SR_BE) {
+ writel(0, port->membase + UART_SR);
+ if (uart_handle_break(port))
+ continue;
+ }
+
+ if (unlikely(status & (SR_FE | SR_PE | SR_OE))) {
+
+ if (status & SR_PE)
+ port->icount.parity++;
+ else if (status & SR_FE)
+ port->icount.frame++;
+ if (status & SR_OE)
+ port->icount.overrun++;
+
+ status &= port->read_status_mask;
+
+ if (status & SR_BE)
+ flg = TTY_BREAK;
+ else if (status & SR_PE)
+ flg = TTY_PARITY;
+ else if (status & SR_FE)
+ flg = TTY_FRAME;
+ }
+
+ if (uart_handle_sysrq_char(port, rx, regs))
+ continue;
+
+ uart_insert_char(port, status, SR_OE, rx, flg);
+ }
+
+ tty_flip_buffer_push(tty);
+ return;
+}
+
+static irqreturn_t netx_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct uart_port *port = (struct uart_port *)dev_id;
+ unsigned long flags;
+ unsigned char status;
+
+ spin_lock_irqsave(&port->lock,flags);
+
+ status = readl(port->membase + UART_IIR) & IIR_MASK;
+ while (status) {
+ if (status & IIR_RIS)
+ netx_rxint(port, regs);
+ if (status & IIR_TIS)
+ netx_txint(port);
+ if (status & IIR_MIS) {
+ if (readl(port->membase + UART_FR) & FR_CTS)
+ uart_handle_cts_change(port, 1);
+ else
+ uart_handle_cts_change(port, 0);
+ }
+ writel(0, port->membase + UART_IIR);
+ status = readl(port->membase + UART_IIR) & IIR_MASK;
+ }
+
+ spin_unlock_irqrestore(&port->lock,flags);
+ return IRQ_HANDLED;
+}
+
+static unsigned int netx_get_mctrl(struct uart_port *port)
+{
+ unsigned int ret = TIOCM_DSR | TIOCM_CAR;
+
+ if (readl(port->membase + UART_FR) & FR_CTS)
+ ret |= TIOCM_CTS;
+
+ return ret;
+}
+
+static void netx_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ unsigned int val;
+
+ if (mctrl & TIOCM_RTS) {
+ val = readl(port->membase + UART_RTS_CR);
+ writel(val | RTS_CR_RTS, port->membase + UART_RTS_CR);
+ }
+}
+
+static void netx_break_ctl(struct uart_port *port, int break_state)
+{
+ unsigned int line_cr;
+ spin_lock_irq(&port->lock);
+
+ line_cr = readl(port->membase + UART_LINE_CR);
+ if (break_state != 0)
+ line_cr |= LINE_CR_BRK;
+ else
+ line_cr &= ~LINE_CR_BRK;
+ writel(line_cr, port->membase + UART_LINE_CR);
+
+ spin_unlock_irq(&port->lock);
+}
+
+static int netx_startup(struct uart_port *port)
+{
+ int ret;
+
+ ret = request_irq(port->irq, netx_int, 0,
+ DRIVER_NAME, port);
+ if (ret) {
+ dev_err(port->dev, "unable to grab irq%d\n",port->irq);
+ goto exit;
+ }
+
+ writel(readl(port->membase + UART_LINE_CR) | LINE_CR_FEN,
+ port->membase + UART_LINE_CR);
+
+ writel(CR_MSIE | CR_RIE | CR_TIE | CR_RTIE | CR_UART_EN,
+ port->membase + UART_CR);
+
+exit:
+ return ret;
+}
+
+static void netx_shutdown(struct uart_port *port)
+{
+ writel(0, port->membase + UART_CR) ;
+
+ free_irq(port->irq, port);
+}
+
+static void
+netx_set_termios(struct uart_port *port, struct termios *termios,
+ struct termios *old)
+{
+ unsigned int baud, quot;
+ unsigned char old_cr;
+ unsigned char line_cr = LINE_CR_FEN;
+ unsigned char rts_cr = 0;
+
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ line_cr |= LINE_CR_5BIT;
+ break;
+ case CS6:
+ line_cr |= LINE_CR_6BIT;
+ break;
+ case CS7:
+ line_cr |= LINE_CR_7BIT;
+ break;
+ case CS8:
+ line_cr |= LINE_CR_8BIT;
+ break;
+ }
+
+ if (termios->c_cflag & CSTOPB)
+ line_cr |= LINE_CR_STP2;
+
+ if (termios->c_cflag & PARENB) {
+ line_cr |= LINE_CR_PEN;
+ if (!(termios->c_cflag & PARODD))
+ line_cr |= LINE_CR_EPS;
+ }
+
+ if (termios->c_cflag & CRTSCTS)
+ rts_cr = RTS_CR_AUTO | RTS_CR_CTS_CTR | RTS_CR_RTS_POL;
+
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+ quot = baud * 4096;
+ quot /= 1000;
+ quot *= 256;
+ quot /= 100000;
+
+ spin_lock_irq(&port->lock);
+
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ old_cr = readl(port->membase + UART_CR);
+
+ /* disable interrupts */
+ writel(old_cr & ~(CR_MSIE | CR_RIE | CR_TIE | CR_RTIE),
+ port->membase + UART_CR);
+
+ /* drain transmitter */
+ while (readl(port->membase + UART_FR) & FR_BUSY);
+
+ /* disable UART */
+ writel(old_cr & ~CR_UART_EN, port->membase + UART_CR);
+
+ /* modem status interrupts */
+ old_cr &= ~CR_MSIE;
+ if (UART_ENABLE_MS(port, termios->c_cflag))
+ old_cr |= CR_MSIE;
+
+ writel((quot>>8) & 0xff, port->membase + UART_BAUDDIV_MSB);
+ writel(quot & 0xff, port->membase + UART_BAUDDIV_LSB);
+ writel(line_cr, port->membase + UART_LINE_CR);
+
+ writel(rts_cr, port->membase + UART_RTS_CR);
+
+ /*
+ * Characters to ignore
+ */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= SR_PE;
+ if (termios->c_iflag & IGNBRK) {
+ port->ignore_status_mask |= SR_BE;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= SR_PE;
+ }
+
+ port->read_status_mask = 0;
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= SR_BE;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= SR_PE | SR_FE;
+
+ writel(old_cr, port->membase + UART_CR);
+
+ spin_unlock_irq(&port->lock);
+}
+
+static const char *netx_type(struct uart_port *port)
+{
+ return port->type == PORT_NETX ? "NETX" : NULL;
+}
+
+static void netx_release_port(struct uart_port *port)
+{
+ release_mem_region(port->mapbase, UART_PORT_SIZE);
+}
+
+static int netx_request_port(struct uart_port *port)
+{
+ return request_mem_region(port->mapbase, UART_PORT_SIZE,
+ DRIVER_NAME) != NULL ? 0 : -EBUSY;
+}
+
+static void netx_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE && netx_request_port(port) == 0)
+ port->type = PORT_NETX;
+}
+
+static int
+netx_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ int ret = 0;
+
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_NETX)
+ ret = -EINVAL;
+
+ return ret;
+}
+
+static struct uart_ops netx_pops = {
+ .tx_empty = netx_tx_empty,
+ .set_mctrl = netx_set_mctrl,
+ .get_mctrl = netx_get_mctrl,
+ .stop_tx = netx_stop_tx,
+ .start_tx = netx_start_tx,
+ .stop_rx = netx_stop_rx,
+ .enable_ms = netx_enable_ms,
+ .break_ctl = netx_break_ctl,
+ .startup = netx_startup,
+ .shutdown = netx_shutdown,
+ .set_termios = netx_set_termios,
+ .type = netx_type,
+ .release_port = netx_release_port,
+ .request_port = netx_request_port,
+ .config_port = netx_config_port,
+ .verify_port = netx_verify_port,
+};
+
+static struct netx_port netx_ports[] = {
+ {
+ .port = {
+ .type = PORT_NETX,
+ .iotype = UPIO_MEM,
+ .membase = (char __iomem *)io_p2v(NETX_PA_UART0),
+ .mapbase = NETX_PA_UART0,
+ .irq = NETX_IRQ_UART0,
+ .uartclk = 100000000,
+ .fifosize = 16,
+ .flags = UPF_BOOT_AUTOCONF,
+ .ops = &netx_pops,
+ .line = 0,
+ },
+ }, {
+ .port = {
+ .type = PORT_NETX,
+ .iotype = UPIO_MEM,
+ .membase = (char __iomem *)io_p2v(NETX_PA_UART1),
+ .mapbase = NETX_PA_UART1,
+ .irq = NETX_IRQ_UART1,
+ .uartclk = 100000000,
+ .fifosize = 16,
+ .flags = UPF_BOOT_AUTOCONF,
+ .ops = &netx_pops,
+ .line = 1,
+ },
+ }, {
+ .port = {
+ .type = PORT_NETX,
+ .iotype = UPIO_MEM,
+ .membase = (char __iomem *)io_p2v(NETX_PA_UART2),
+ .mapbase = NETX_PA_UART2,
+ .irq = NETX_IRQ_UART2,
+ .uartclk = 100000000,
+ .fifosize = 16,
+ .flags = UPF_BOOT_AUTOCONF,
+ .ops = &netx_pops,
+ .line = 2,
+ },
+ }
+};
+
+static void netx_console_putchar(struct uart_port *port, int ch)
+{
+ while (readl(port->membase + UART_FR) & FR_BUSY);
+ writel(ch, port->membase + UART_DR);
+}
+
+static void
+netx_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct uart_port *port = &netx_ports[co->index].port;
+ unsigned char cr_save;
+
+ cr_save = readl(port->membase + UART_CR);
+ writel(cr_save | CR_UART_EN, port->membase + UART_CR);
+
+ uart_console_write(port, s, count, netx_console_putchar);
+
+ while (readl(port->membase + UART_FR) & FR_BUSY);
+ writel(cr_save, port->membase + UART_CR);
+}
+
+static void __init
+netx_console_get_options(struct uart_port *port, int *baud,
+ int *parity, int *bits, int *flow)
+{
+ unsigned char line_cr;
+
+ *baud = (readl(port->membase + UART_BAUDDIV_MSB) << 8) |
+ readl(port->membase + UART_BAUDDIV_LSB);
+ *baud *= 1000;
+ *baud /= 4096;
+ *baud *= 1000;
+ *baud /= 256;
+ *baud *= 100;
+
+ line_cr = readl(port->membase + UART_LINE_CR);
+ *parity = 'n';
+ if (line_cr & LINE_CR_PEN) {
+ if (line_cr & LINE_CR_EPS)
+ *parity = 'e';
+ else
+ *parity = 'o';
+ }
+
+ switch (line_cr & LINE_CR_BITS_MASK) {
+ case LINE_CR_8BIT:
+ *bits = 8;
+ break;
+ case LINE_CR_7BIT:
+ *bits = 7;
+ break;
+ case LINE_CR_6BIT:
+ *bits = 6;
+ break;
+ case LINE_CR_5BIT:
+ *bits = 5;
+ break;
+ }
+
+ if (readl(port->membase + UART_RTS_CR) & RTS_CR_AUTO)
+ *flow = 'r';
+}
+
+static int __init
+netx_console_setup(struct console *co, char *options)
+{
+ struct netx_port *sport;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ /*
+ * Check whether an invalid uart number has been specified, and
+ * if so, search for the first available port that does have
+ * console support.
+ */
+ if (co->index == -1 || co->index >= ARRAY_SIZE(netx_ports))
+ co->index = 0;
+ sport = &netx_ports[co->index];
+
+ if (options) {
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ } else {
+ /* if the UART is enabled, assume it has been correctly setup
+ * by the bootloader and get the options
+ */
+ if (readl(sport->port.membase + UART_CR) & CR_UART_EN) {
+ netx_console_get_options(&sport->port, &baud,
+ &parity, &bits, &flow);
+ }
+
+ }
+
+ return uart_set_options(&sport->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver netx_reg;
+static struct console netx_console = {
+ .name = "ttyNX",
+ .write = netx_console_write,
+ .device = uart_console_device,
+ .setup = netx_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &netx_reg,
+};
+
+static int __init netx_console_init(void)
+{
+ register_console(&netx_console);
+ return 0;
+}
+console_initcall(netx_console_init);
+
+#define NETX_CONSOLE &netx_console
+#else
+#define NETX_CONSOLE NULL
+#endif
+
+static struct uart_driver netx_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = DRIVER_NAME,
+ .dev_name = "ttyNX",
+ .major = SERIAL_NX_MAJOR,
+ .minor = MINOR_START,
+ .nr = ARRAY_SIZE(netx_ports),
+ .cons = NETX_CONSOLE,
+};
+
+static int serial_netx_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct netx_port *sport = platform_get_drvdata(pdev);
+
+ if (sport)
+ uart_suspend_port(&netx_reg, &sport->port);
+
+ return 0;
+}
+
+static int serial_netx_resume(struct platform_device *pdev)
+{
+ struct netx_port *sport = platform_get_drvdata(pdev);
+
+ if (sport)
+ uart_resume_port(&netx_reg, &sport->port);
+
+ return 0;
+}
+
+static int serial_netx_probe(struct platform_device *pdev)
+{
+ struct uart_port *port = &netx_ports[pdev->id].port;
+
+ dev_info(&pdev->dev, "initialising\n");
+
+ port->dev = &pdev->dev;
+
+ writel(1, port->membase + UART_RXFIFO_IRQLEVEL);
+ uart_add_one_port(&netx_reg, &netx_ports[pdev->id].port);
+ platform_set_drvdata(pdev, &netx_ports[pdev->id]);
+
+ return 0;
+}
+
+static int serial_netx_remove(struct platform_device *pdev)
+{
+ struct netx_port *sport = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ if (sport)
+ uart_remove_one_port(&netx_reg, &sport->port);
+
+ return 0;
+}
+
+static struct platform_driver serial_netx_driver = {
+ .probe = serial_netx_probe,
+ .remove = serial_netx_remove,
+
+ .suspend = serial_netx_suspend,
+ .resume = serial_netx_resume,
+
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+static int __init netx_serial_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO "Serial: NetX driver\n");
+
+ ret = uart_register_driver(&netx_reg);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&serial_netx_driver);
+ if (ret != 0)
+ uart_unregister_driver(&netx_reg);
+
+ return 0;
+}
+
+static void __exit netx_serial_exit(void)
+{
+ platform_driver_unregister(&serial_netx_driver);
+ uart_unregister_driver(&netx_reg);
+}
+
+module_init(netx_serial_init);
+module_exit(netx_serial_exit);
+
+MODULE_AUTHOR("Sascha Hauer");
+MODULE_DESCRIPTION("NetX serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c
index 77d4568..ae36495 100644
--- a/drivers/serial/pxa.c
+++ b/drivers/serial/pxa.c
@@ -269,7 +269,6 @@ static unsigned int serial_pxa_get_mctrl(struct uart_port *port)
unsigned char status;
unsigned int ret;
-return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
status = serial_in(up, UART_MSR);
ret = 0;
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index 53c2465..837b6da 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -872,6 +872,8 @@ static const char *s3c24xx_serial_type(struct uart_port *port)
return "S3C2410";
case PORT_S3C2440:
return "S3C2440";
+ case PORT_S3C2412:
+ return "S3C2412";
default:
return NULL;
}
@@ -1528,6 +1530,141 @@ static inline void s3c2440_serial_exit(void)
#define s3c2440_uart_inf_at NULL
#endif /* CONFIG_CPU_S3C2440 */
+#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
+
+static int s3c2412_serial_setsource(struct uart_port *port,
+ struct s3c24xx_uart_clksrc *clk)
+{
+ unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+ ucon &= ~S3C2412_UCON_CLKMASK;
+
+ if (strcmp(clk->name, "uclk") == 0)
+ ucon |= S3C2440_UCON_UCLK;
+ else if (strcmp(clk->name, "pclk") == 0)
+ ucon |= S3C2440_UCON_PCLK;
+ else if (strcmp(clk->name, "usysclk") == 0)
+ ucon |= S3C2412_UCON_USYSCLK;
+ else {
+ printk(KERN_ERR "unknown clock source %s\n", clk->name);
+ return -EINVAL;
+ }
+
+ wr_regl(port, S3C2410_UCON, ucon);
+ return 0;
+}
+
+
+static int s3c2412_serial_getsource(struct uart_port *port,
+ struct s3c24xx_uart_clksrc *clk)
+{
+ unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+ switch (ucon & S3C2412_UCON_CLKMASK) {
+ case S3C2412_UCON_UCLK:
+ clk->divisor = 1;
+ clk->name = "uclk";
+ break;
+
+ case S3C2412_UCON_PCLK:
+ case S3C2412_UCON_PCLK2:
+ clk->divisor = 1;
+ clk->name = "pclk";
+ break;
+
+ case S3C2412_UCON_USYSCLK:
+ clk->divisor = 1;
+ clk->name = "usysclk";
+ break;
+ }
+
+ return 0;
+}
+
+static int s3c2412_serial_resetport(struct uart_port *port,
+ struct s3c2410_uartcfg *cfg)
+{
+ unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+ dbg("%s: port=%p (%08lx), cfg=%p\n",
+ __FUNCTION__, port, port->mapbase, cfg);
+
+ /* ensure we don't change the clock settings... */
+
+ ucon &= S3C2412_UCON_CLKMASK;
+
+ wr_regl(port, S3C2410_UCON, ucon | cfg->ucon);
+ wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+ /* reset both fifos */
+
+ wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+ wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+ return 0;
+}
+
+static struct s3c24xx_uart_info s3c2412_uart_inf = {
+ .name = "Samsung S3C2412 UART",
+ .type = PORT_S3C2412,
+ .fifosize = 64,
+ .rx_fifomask = S3C2440_UFSTAT_RXMASK,
+ .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT,
+ .rx_fifofull = S3C2440_UFSTAT_RXFULL,
+ .tx_fifofull = S3C2440_UFSTAT_TXFULL,
+ .tx_fifomask = S3C2440_UFSTAT_TXMASK,
+ .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT,
+ .get_clksrc = s3c2412_serial_getsource,
+ .set_clksrc = s3c2412_serial_setsource,
+ .reset_port = s3c2412_serial_resetport,
+};
+
+/* device management */
+
+static int s3c2412_serial_probe(struct platform_device *dev)
+{
+ dbg("s3c2440_serial_probe: dev=%p\n", dev);
+ return s3c24xx_serial_probe(dev, &s3c2440_uart_inf);
+}
+
+static struct platform_driver s3c2412_serial_drv = {
+ .probe = s3c2412_serial_probe,
+ .remove = s3c24xx_serial_remove,
+ .suspend = s3c24xx_serial_suspend,
+ .resume = s3c24xx_serial_resume,
+ .driver = {
+ .name = "s3c2412-uart",
+ .owner = THIS_MODULE,
+ },
+};
+
+
+static inline int s3c2412_serial_init(void)
+{
+ return s3c24xx_serial_init(&s3c2412_serial_drv, &s3c2412_uart_inf);
+}
+
+static inline void s3c2412_serial_exit(void)
+{
+ platform_driver_unregister(&s3c2412_serial_drv);
+}
+
+#define s3c2412_uart_inf_at &s3c2412_uart_inf
+#else
+
+static inline int s3c2412_serial_init(void)
+{
+ return 0;
+}
+
+static inline void s3c2412_serial_exit(void)
+{
+}
+
+#define s3c2412_uart_inf_at NULL
+#endif /* CONFIG_CPU_S3C2440 */
+
+
/* module initialisation code */
static int __init s3c24xx_serial_modinit(void)
@@ -1542,6 +1679,7 @@ static int __init s3c24xx_serial_modinit(void)
s3c2400_serial_init();
s3c2410_serial_init();
+ s3c2412_serial_init();
s3c2440_serial_init();
return 0;
@@ -1551,6 +1689,7 @@ static void __exit s3c24xx_serial_modexit(void)
{
s3c2400_serial_exit();
s3c2410_serial_exit();
+ s3c2412_serial_exit();
s3c2440_serial_exit();
uart_unregister_driver(&s3c24xx_uart_drv);
@@ -1773,6 +1912,8 @@ static int s3c24xx_serial_initconsole(void)
info = s3c2410_uart_inf_at;
} else if (strcmp(dev->name, "s3c2440-uart") == 0) {
info = s3c2440_uart_inf_at;
+ } else if (strcmp(dev->name, "s3c2412-uart") == 0) {
+ info = s3c2412_uart_inf_at;
} else {
printk(KERN_ERR "s3c24xx: no driver for %s\n", dev->name);
return 0;
@@ -1796,4 +1937,4 @@ console_initcall(s3c24xx_serial_initconsole);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_DESCRIPTION("Samsung S3C2410/S3C2440 Serial port driver");
+MODULE_DESCRIPTION("Samsung S3C2410/S3C2440/S3C2412 Serial port driver");
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index f137804..ba22e25 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -427,31 +427,32 @@ static int __init hv_console_compatible(char *buf, int len)
static unsigned int __init get_interrupt(void)
{
- const char *cons_str = "console";
- const char *compat_str = "compatible";
- int node = prom_getchild(sun4v_vdev_root);
- char buf[64];
- int err, len;
-
- node = prom_searchsiblings(node, cons_str);
- if (!node)
- return 0;
+ struct device_node *dev_node;
- len = prom_getproplen(node, compat_str);
- if (len == 0 || len == -1)
- return 0;
+ dev_node = sun4v_vdev_root->child;
+ while (dev_node != NULL) {
+ struct property *prop;
- err = prom_getproperty(node, compat_str, buf, 64);
- if (err == -1)
- return 0;
+ if (strcmp(dev_node->name, "console"))
+ goto next_sibling;
+
+ prop = of_find_property(dev_node, "compatible", NULL);
+ if (!prop)
+ goto next_sibling;
- if (!hv_console_compatible(buf, len))
+ if (hv_console_compatible(prop->value, prop->length))
+ break;
+
+ next_sibling:
+ dev_node = dev_node->sibling;
+ }
+ if (!dev_node)
return 0;
/* Ok, the this is the OBP node for the sun4v hypervisor
* console device. Decode the interrupt.
*/
- return sun4v_vdev_device_interrupt(node);
+ return sun4v_vdev_device_interrupt(dev_node);
}
static int __init sunhv_init(void)
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index bfbe9dc..e4c0fd2 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -984,19 +984,19 @@ static void __init for_each_sab_edev(void (*callback)(struct linux_ebus_device *
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "se")) {
+ if (!strcmp(edev->prom_node->name, "se")) {
callback(edev, arg);
continue;
- } else if (!strcmp(edev->prom_name, "serial")) {
- char compat[32];
+ } else if (!strcmp(edev->prom_node->name, "serial")) {
+ char *compat;
int clen;
/* On RIO this can be an SE, check it. We could
* just check ebus->is_rio, but this is more portable.
*/
- clen = prom_getproperty(edev->prom_node, "compatible",
- compat, sizeof(compat));
- if (clen > 0) {
+ compat = of_get_property(edev->prom_node,
+ "compatible", &clen);
+ if (compat && clen > 0) {
if (strncmp(compat, "sab82532", 8) == 0) {
callback(edev, arg);
continue;
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 4cdb610..0268b30 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1053,7 +1053,7 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
*/
for_each_ebus(ebus) {
for_each_ebusdev(dev, ebus) {
- if (dev->prom_node == up->port_node) {
+ if (dev->prom_node->node == up->port_node) {
/*
* The EBus is broken on sparc; it delivers
* virtual addresses in resources. Oh well...
@@ -1073,7 +1073,7 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
#ifdef CONFIG_SPARC64
for_each_isa(isa_br) {
for_each_isadev(isa_dev, isa_br) {
- if (isa_dev->prom_node == up->port_node) {
+ if (isa_dev->prom_node->node == up->port_node) {
/* Same on sparc64. Cool architecure... */
up->port.membase = (char *) isa_dev->resource.start;
up->port.mapbase = isa_dev->resource.start;
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index 5b65697..76c9bac 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -1106,7 +1106,7 @@ static struct zilog_layout __iomem * __init get_zs_sun4u(int chip, int zsnode)
+ FHC_UREGS_ICLR;
imap = central_bus->child->fhc_regs.uregs
+ FHC_UREGS_IMAP;
- zilog_irq = build_irq(12, 0, iclr, imap);
+ zilog_irq = build_irq(0, iclr, imap);
} else {
err = prom_getproperty(zsnode, "interrupts",
(char *) &sun4u_ino,
diff --git a/drivers/sn/ioc4.c b/drivers/sn/ioc4.c
index cdeff90..8256a97 100644
--- a/drivers/sn/ioc4.c
+++ b/drivers/sn/ioc4.c
@@ -160,9 +160,6 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd)
writel(0, &idd->idd_misc_regs->int_out.raw);
mmiowb();
- printk(KERN_INFO
- "%s: Calibrating PCI bus speed "
- "for pci_dev %s ... ", __FUNCTION__, pci_name(idd->idd_pdev));
/* Set up square wave */
int_out.raw = 0;
int_out.fields.count = IOC4_CALIBRATE_COUNT;
@@ -206,11 +203,16 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd)
/* Bounds check the result. */
if (period > IOC4_CALIBRATE_LOW_LIMIT ||
period < IOC4_CALIBRATE_HIGH_LIMIT) {
- printk("failed. Assuming PCI clock ticks are %d ns.\n",
+ printk(KERN_INFO
+ "IOC4 %s: Clock calibration failed. Assuming"
+ "PCI clock is %d ns.\n",
+ pci_name(idd->idd_pdev),
IOC4_CALIBRATE_DEFAULT / IOC4_EXTINT_COUNT_DIVISOR);
period = IOC4_CALIBRATE_DEFAULT;
} else {
- printk("succeeded. PCI clock ticks are %ld ns.\n",
+ printk(KERN_DEBUG
+ "IOC4 %s: PCI clock is %ld ns.\n",
+ pci_name(idd->idd_pdev),
period / IOC4_EXTINT_COUNT_DIVISOR);
}
@@ -222,6 +224,51 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd)
idd->count_period = period;
}
+/* There are three variants of IOC4 cards: IO9, IO10, and PCI-RT.
+ * Each brings out different combinations of IOC4 signals, thus.
+ * the IOC4 subdrivers need to know to which we're attached.
+ *
+ * We look for the presence of a SCSI (IO9) or SATA (IO10) controller
+ * on the same PCI bus at slot number 3 to differentiate IO9 from IO10.
+ * If neither is present, it's a PCI-RT.
+ */
+static unsigned int
+ioc4_variant(struct ioc4_driver_data *idd)
+{
+ struct pci_dev *pdev = NULL;
+ int found = 0;
+
+ /* IO9: Look for a QLogic ISP 12160 at the same bus and slot 3. */
+ do {
+ pdev = pci_get_device(PCI_VENDOR_ID_QLOGIC,
+ PCI_DEVICE_ID_QLOGIC_ISP12160, pdev);
+ if (pdev &&
+ idd->idd_pdev->bus->number == pdev->bus->number &&
+ 3 == PCI_SLOT(pdev->devfn))
+ found = 1;
+ pci_dev_put(pdev);
+ } while (pdev && !found);
+ if (NULL != pdev)
+ return IOC4_VARIANT_IO9;
+
+ /* IO10: Look for a Vitesse VSC 7174 at the same bus and slot 3. */
+ pdev = NULL;
+ do {
+ pdev = pci_get_device(PCI_VENDOR_ID_VITESSE,
+ PCI_DEVICE_ID_VITESSE_VSC7174, pdev);
+ if (pdev &&
+ idd->idd_pdev->bus->number == pdev->bus->number &&
+ 3 == PCI_SLOT(pdev->devfn))
+ found = 1;
+ pci_dev_put(pdev);
+ } while (pdev && !found);
+ if (NULL != pdev)
+ return IOC4_VARIANT_IO10;
+
+ /* PCI-RT: No SCSI/SATA controller will be present */
+ return IOC4_VARIANT_PCI_RT;
+}
+
/* Adds a new instance of an IOC4 card */
static int
ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
@@ -286,6 +333,13 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
/* Failsafe portion of per-IOC4 initialization */
+ /* Detect card variant */
+ idd->idd_variant = ioc4_variant(idd);
+ printk(KERN_INFO "IOC4 %s: %s card detected.\n", pci_name(pdev),
+ idd->idd_variant == IOC4_VARIANT_IO9 ? "IO9" :
+ idd->idd_variant == IOC4_VARIANT_PCI_RT ? "PCI-RT" :
+ idd->idd_variant == IOC4_VARIANT_IO10 ? "IO10" : "unknown");
+
/* Initialize IOC4 */
pci_read_config_dword(idd->idd_pdev, PCI_COMMAND, &pcmd);
pci_write_config_dword(idd->idd_pdev, PCI_COMMAND,
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 3f8e062..bcbeaf7 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -1078,9 +1078,7 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
if (copy_from_user(&uurb, arg, sizeof(uurb)))
return -EFAULT;
- return proc_do_submiturb(ps, &uurb,
- (struct usbdevfs_iso_packet_desc __user *)uurb.iso_frame_desc,
- arg);
+ return proc_do_submiturb(ps, &uurb, (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), arg);
}
static int proc_unlinkurb(struct dev_state *ps, void __user *arg)
@@ -1205,9 +1203,7 @@ static int proc_submiturb_compat(struct dev_state *ps, void __user *arg)
if (get_urb32(&uurb,(struct usbdevfs_urb32 *)arg))
return -EFAULT;
- return proc_do_submiturb(ps, &uurb,
- (struct usbdevfs_iso_packet_desc __user *)uurb.iso_frame_desc,
- arg);
+ return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, arg);
}
static int processcompl_compat(struct async *as, void __user * __user *arg)
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 3cf945c..bfc9b28 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -543,10 +543,10 @@ static void fs_remove_file (struct dentry *dentry)
/* --------------------------------------------------------------------- */
-static struct super_block *usb_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int usb_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, usbfs_fill_super);
+ return get_sb_single(fs_type, flags, data, usbfs_fill_super, mnt);
}
static struct file_system_type usb_fs_type = {
@@ -569,7 +569,7 @@ static int create_special_files (void)
ignore_mount = 1;
/* create the devices special file */
- retval = simple_pin_fs("usbfs", &usbfs_mount, &usbfs_mount_count);
+ retval = simple_pin_fs(&usb_fs_type, &usbfs_mount, &usbfs_mount_count);
if (retval) {
err ("Unable to get usbfs mount");
goto exit;
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 5153107..fb488c8 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -991,6 +991,8 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
static int verify_suspended(struct device *dev, void *unused)
{
+ if (dev->driver == NULL)
+ return 0;
return (dev->power.power_state.event == PM_EVENT_ON) ? -EBUSY : 0;
}
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 6f88747..a43dc90 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -1906,7 +1906,6 @@ static int fsync_sub(struct lun *curlun)
inode = filp->f_dentry->d_inode;
mutex_lock(&inode->i_mutex);
- current->flags |= PF_SYNCWRITE;
rc = filemap_fdatawrite(inode->i_mapping);
err = filp->f_op->fsync(filp, filp->f_dentry, 1);
if (!rc)
@@ -1914,7 +1913,6 @@ static int fsync_sub(struct lun *curlun)
err = filemap_fdatawait(inode->i_mapping);
if (!rc)
rc = err;
- current->flags &= ~PF_SYNCWRITE;
mutex_unlock(&inode->i_mutex);
VLDBG(curlun, "fdatasync -> %d\n", rc);
return rc;
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index aef0722..3bdc5e3 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -2070,11 +2070,11 @@ enomem0:
}
/* "mount -t gadgetfs path /dev/gadget" ends up here */
-static struct super_block *
+static int
gadgetfs_get_sb (struct file_system_type *t, int flags,
- const char *path, void *opts)
+ const char *path, void *opts, struct vfsmount *mnt)
{
- return get_sb_single (t, flags, opts, gadgetfs_fill_super);
+ return get_sb_single (t, flags, opts, gadgetfs_fill_super, mnt);
}
static void
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index c060eb9..b93d71d 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -70,7 +70,6 @@ config USB_EHCI_TT_NEWSCHED
config USB_ISP116X_HCD
tristate "ISP116X HCD support"
depends on USB
- default N
---help---
The ISP1160 and ISP1161 chips are USB host controllers. Enable this
option if your board has this chip. If unsure, say N.
@@ -145,7 +144,6 @@ config USB_UHCI_HCD
config USB_SL811_HCD
tristate "SL811HS HCD support"
depends on USB
- default N
help
The SL811HS is a single-port USB controller that supports either
host side or peripheral side roles. Enable this option if your
@@ -158,7 +156,6 @@ config USB_SL811_HCD
config USB_SL811_CS
tristate "CF/PCMCIA support for SL811HS HCD"
depends on USB_SL811_HCD && PCMCIA
- default N
help
Wraps a PCMCIA driver around the SL811HS HCD, supporting the RATOC
REX-CFU1U CF card (often used with PDAs). If unsure, say N.
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 5a2840a..168ede7 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -86,6 +86,11 @@ config FB_FIRMWARE_EDID
combination with certain motherboards and monitors are known to
suffer from this problem.
+config FB_BACKLIGHT
+ bool
+ depends on FB
+ default n
+
config FB_MODE_HELPERS
bool "Enable Video Mode Handling Helpers"
depends on FB
@@ -717,6 +722,16 @@ config FB_NVIDIA_I2C
independently validate video mode parameters, you should say Y
here.
+config FB_NVIDIA_BACKLIGHT
+ bool "Support for backlight control"
+ depends on FB_NVIDIA && PPC_PMAC
+ select FB_BACKLIGHT
+ select BACKLIGHT_LCD_SUPPORT
+ select BACKLIGHT_CLASS_DEVICE
+ default y
+ help
+ Say Y here if you want to control the backlight of your display.
+
config FB_RIVA
tristate "nVidia Riva support"
depends on FB && PCI
@@ -755,6 +770,16 @@ config FB_RIVA_DEBUG
of debugging informations to provide to the maintainer when
something goes wrong.
+config FB_RIVA_BACKLIGHT
+ bool "Support for backlight control"
+ depends on FB_RIVA && PPC_PMAC
+ select FB_BACKLIGHT
+ select BACKLIGHT_LCD_SUPPORT
+ select BACKLIGHT_CLASS_DEVICE
+ default y
+ help
+ Say Y here if you want to control the backlight of your display.
+
config FB_I810
tristate "Intel 810/815 support (EXPERIMENTAL)"
depends on FB && EXPERIMENTAL && PCI && X86_32
@@ -993,6 +1018,7 @@ config FB_RADEON
There is a product page at
http://apps.ati.com/ATIcompare/
+
config FB_RADEON_I2C
bool "DDC/I2C for ATI Radeon support"
depends on FB_RADEON
@@ -1000,6 +1026,16 @@ config FB_RADEON_I2C
help
Say Y here if you want DDC/I2C support for your Radeon board.
+config FB_RADEON_BACKLIGHT
+ bool "Support for backlight control"
+ depends on FB_RADEON && PPC_PMAC
+ select FB_BACKLIGHT
+ select BACKLIGHT_LCD_SUPPORT
+ select BACKLIGHT_CLASS_DEVICE
+ default y
+ help
+ Say Y here if you want to control the backlight of your display.
+
config FB_RADEON_DEBUG
bool "Lots of debug output from Radeon driver"
depends on FB_RADEON
@@ -1024,6 +1060,16 @@ config FB_ATY128
To compile this driver as a module, choose M here: the
module will be called aty128fb.
+config FB_ATY128_BACKLIGHT
+ bool "Support for backlight control"
+ depends on FB_ATY128 && PPC_PMAC
+ select FB_BACKLIGHT
+ select BACKLIGHT_LCD_SUPPORT
+ select BACKLIGHT_CLASS_DEVICE
+ default y
+ help
+ Say Y here if you want to control the backlight of your display.
+
config FB_ATY
tristate "ATI Mach64 display support" if PCI || ATARI
depends on FB && !SPARC32
@@ -1066,6 +1112,16 @@ config FB_ATY_GX
is at
<http://support.ati.com/products/pc/mach64/graphics_xpression.html>.
+config FB_ATY_BACKLIGHT
+ bool "Support for backlight control"
+ depends on FB_ATY && PPC_PMAC
+ select FB_BACKLIGHT
+ select BACKLIGHT_LCD_SUPPORT
+ select BACKLIGHT_CLASS_DEVICE
+ default y
+ help
+ Say Y here if you want to control the backlight of your display.
+
config FB_S3TRIO
bool "S3 Trio display support"
depends on (FB = y) && PPC && BROKEN
diff --git a/drivers/video/aty/Makefile b/drivers/video/aty/Makefile
index 1852139..a6cc0e9 100644
--- a/drivers/video/aty/Makefile
+++ b/drivers/video/aty/Makefile
@@ -10,5 +10,6 @@ atyfb-objs := $(atyfb-y)
radeonfb-y := radeon_base.o radeon_pm.o radeon_monitor.o radeon_accel.o
radeonfb-$(CONFIG_FB_RADEON_I2C) += radeon_i2c.o
+radeonfb-$(CONFIG_FB_RADEON_BACKLIGHT) += radeon_backlight.o
radeonfb-objs := $(radeonfb-y)
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index f7bbff4..db878fd 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -64,6 +64,7 @@
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/console.h>
+#include <linux/backlight.h>
#include <asm/io.h>
#ifdef CONFIG_PPC_PMAC
@@ -480,16 +481,6 @@ static struct fb_ops aty128fb_ops = {
.fb_imageblit = cfb_imageblit,
};
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int aty128_set_backlight_enable(int on, int level, void* data);
-static int aty128_set_backlight_level(int level, void* data);
-
-static struct backlight_controller aty128_backlight_controller = {
- aty128_set_backlight_enable,
- aty128_set_backlight_level
-};
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
/*
* Functions to read from/write to the mmio registers
* - endian conversions may possibly be avoided by
@@ -1258,19 +1249,35 @@ static void aty128_set_crt_enable(struct aty128fb_par *par, int on)
static void aty128_set_lcd_enable(struct aty128fb_par *par, int on)
{
u32 reg;
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+#endif
if (on) {
reg = aty_ld_le32(LVDS_GEN_CNTL);
reg |= LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION;
reg &= ~LVDS_DISPLAY_DIS;
aty_st_le32(LVDS_GEN_CNTL, reg);
-#ifdef CONFIG_PMAC_BACKLIGHT
- aty128_set_backlight_enable(get_backlight_enable(),
- get_backlight_level(), par);
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+ mutex_lock(&info->bl_mutex);
+ if (info->bl_dev) {
+ down(&info->bl_dev->sem);
+ info->bl_dev->props->update_status(info->bl_dev);
+ up(&info->bl_dev->sem);
+ }
+ mutex_unlock(&info->bl_mutex);
#endif
} else {
-#ifdef CONFIG_PMAC_BACKLIGHT
- aty128_set_backlight_enable(0, 0, par);
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+ mutex_lock(&info->bl_mutex);
+ if (info->bl_dev) {
+ down(&info->bl_dev->sem);
+ info->bl_dev->props->brightness = 0;
+ info->bl_dev->props->power = FB_BLANK_POWERDOWN;
+ info->bl_dev->props->update_status(info->bl_dev);
+ up(&info->bl_dev->sem);
+ }
+ mutex_unlock(&info->bl_mutex);
#endif
reg = aty_ld_le32(LVDS_GEN_CNTL);
reg |= LVDS_DISPLAY_DIS;
@@ -1691,6 +1698,184 @@ static int __init aty128fb_setup(char *options)
}
#endif /* MODULE */
+/* Backlight */
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+#define MAX_LEVEL 0xFF
+
+static struct backlight_properties aty128_bl_data;
+
+static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
+ int level)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ int atylevel;
+
+ /* Get and convert the value */
+ mutex_lock(&info->bl_mutex);
+ atylevel = MAX_LEVEL -
+ (info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL);
+ mutex_unlock(&info->bl_mutex);
+
+ if (atylevel < 0)
+ atylevel = 0;
+ else if (atylevel > MAX_LEVEL)
+ atylevel = MAX_LEVEL;
+
+ return atylevel;
+}
+
+/* We turn off the LCD completely instead of just dimming the backlight.
+ * This provides greater power saving and the display is useless without
+ * backlight anyway
+ */
+#define BACKLIGHT_LVDS_OFF
+/* That one prevents proper CRT output with LCD off */
+#undef BACKLIGHT_DAC_OFF
+
+static int aty128_bl_update_status(struct backlight_device *bd)
+{
+ struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
+ unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
+ int level;
+
+ if (bd->props->power != FB_BLANK_UNBLANK ||
+ bd->props->fb_blank != FB_BLANK_UNBLANK ||
+ !par->lcd_on)
+ level = 0;
+ else
+ level = bd->props->brightness;
+
+ reg |= LVDS_BL_MOD_EN | LVDS_BLON;
+ if (level > 0) {
+ reg |= LVDS_DIGION;
+ if (!(reg & LVDS_ON)) {
+ reg &= ~LVDS_BLON;
+ aty_st_le32(LVDS_GEN_CNTL, reg);
+ aty_ld_le32(LVDS_GEN_CNTL);
+ mdelay(10);
+ reg |= LVDS_BLON;
+ aty_st_le32(LVDS_GEN_CNTL, reg);
+ }
+ reg &= ~LVDS_BL_MOD_LEVEL_MASK;
+ reg |= (aty128_bl_get_level_brightness(par, level) << LVDS_BL_MOD_LEVEL_SHIFT);
+#ifdef BACKLIGHT_LVDS_OFF
+ reg |= LVDS_ON | LVDS_EN;
+ reg &= ~LVDS_DISPLAY_DIS;
+#endif
+ aty_st_le32(LVDS_GEN_CNTL, reg);
+#ifdef BACKLIGHT_DAC_OFF
+ aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN));
+#endif
+ } else {
+ reg &= ~LVDS_BL_MOD_LEVEL_MASK;
+ reg |= (aty128_bl_get_level_brightness(par, 0) << LVDS_BL_MOD_LEVEL_SHIFT);
+#ifdef BACKLIGHT_LVDS_OFF
+ reg |= LVDS_DISPLAY_DIS;
+ aty_st_le32(LVDS_GEN_CNTL, reg);
+ aty_ld_le32(LVDS_GEN_CNTL);
+ udelay(10);
+ reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION);
+#endif
+ aty_st_le32(LVDS_GEN_CNTL, reg);
+#ifdef BACKLIGHT_DAC_OFF
+ aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN);
+#endif
+ }
+
+ return 0;
+}
+
+static int aty128_bl_get_brightness(struct backlight_device *bd)
+{
+ return bd->props->brightness;
+}
+
+static struct backlight_properties aty128_bl_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = aty128_bl_get_brightness,
+ .update_status = aty128_bl_update_status,
+ .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
+};
+
+static void aty128_bl_init(struct aty128fb_par *par)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ struct backlight_device *bd;
+ char name[12];
+
+ /* Could be extended to Rage128Pro LVDS output too */
+ if (par->chip_gen != rage_M3)
+ return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (!pmac_has_backlight_type("ati"))
+ return;
+#endif
+
+ snprintf(name, sizeof(name), "aty128bl%d", info->node);
+
+ bd = backlight_device_register(name, par, &aty128_bl_data);
+ if (IS_ERR(bd)) {
+ info->bl_dev = NULL;
+ printk("aty128: Backlight registration failed\n");
+ goto error;
+ }
+
+ mutex_lock(&info->bl_mutex);
+ info->bl_dev = bd;
+ fb_bl_default_curve(info, 0,
+ 63 * FB_BACKLIGHT_MAX / MAX_LEVEL,
+ 219 * FB_BACKLIGHT_MAX / MAX_LEVEL);
+ mutex_unlock(&info->bl_mutex);
+
+ up(&bd->sem);
+ bd->props->brightness = aty128_bl_data.max_brightness;
+ bd->props->power = FB_BLANK_UNBLANK;
+ bd->props->update_status(bd);
+ down(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+ if (!pmac_backlight)
+ pmac_backlight = bd;
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+ printk("aty128: Backlight initialized (%s)\n", name);
+
+ return;
+
+error:
+ return;
+}
+
+static void aty128_bl_exit(struct aty128fb_par *par)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+#endif
+
+ mutex_lock(&info->bl_mutex);
+ if (info->bl_dev) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (pmac_backlight == info->bl_dev)
+ pmac_backlight = NULL;
+#endif
+
+ backlight_device_unregister(info->bl_dev);
+ info->bl_dev = NULL;
+
+ printk("aty128: Backlight unloaded\n");
+ }
+ mutex_unlock(&info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
+#endif /* CONFIG_FB_ATY128_BACKLIGHT */
/*
* Initialisation
@@ -1835,17 +2020,15 @@ static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *
if (register_framebuffer(info) < 0)
return 0;
-#ifdef CONFIG_PMAC_BACKLIGHT
- /* Could be extended to Rage128Pro LVDS output too */
- if (par->chip_gen == rage_M3)
- register_backlight_controller(&aty128_backlight_controller, par, "ati");
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);
par->pdev = pdev;
par->asleep = 0;
par->lock_blank = 0;
-
+
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+ aty128_bl_init(par);
+#endif
+
printk(KERN_INFO "fb%d: %s frame buffer device on %s\n",
info->node, info->fix.id, video_card);
@@ -1981,6 +2164,10 @@ static void __devexit aty128_remove(struct pci_dev *pdev)
par = info->par;
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+ aty128_bl_exit(par);
+#endif
+
unregister_framebuffer(info);
#ifdef CONFIG_MTRR
if (par->mtrr.vram_valid)
@@ -2011,10 +2198,14 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
if (par->lock_blank || par->asleep)
return 0;
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (machine_is(powermac) && blank)
- set_backlight_enable(0);
-#endif /* CONFIG_PMAC_BACKLIGHT */
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+ if (machine_is(powermac) && blank) {
+ down(&fb->bl_dev->sem);
+ fb->bl_dev->props->power = FB_BLANK_POWERDOWN;
+ fb->bl_dev->props->update_status(fb->bl_dev);
+ up(&fb->bl_dev->sem);
+ }
+#endif
if (blank & FB_BLANK_VSYNC_SUSPEND)
state |= 2;
@@ -2029,10 +2220,14 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
aty128_set_crt_enable(par, par->crt_on && !blank);
aty128_set_lcd_enable(par, par->lcd_on && !blank);
}
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (machine_is(powermac) && !blank)
- set_backlight_enable(1);
-#endif /* CONFIG_PMAC_BACKLIGHT */
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+ if (machine_is(powermac) && !blank) {
+ down(&fb->bl_dev->sem);
+ fb->bl_dev->props->power = FB_BLANK_UNBLANK;
+ fb->bl_dev->props->update_status(fb->bl_dev);
+ up(&fb->bl_dev->sem);
+ }
+#endif
return 0;
}
@@ -2138,73 +2333,6 @@ static int aty128fb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
return -EINVAL;
}
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int backlight_conv[] = {
- 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
- 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
-};
-
-/* We turn off the LCD completely instead of just dimming the backlight.
- * This provides greater power saving and the display is useless without
- * backlight anyway
- */
-#define BACKLIGHT_LVDS_OFF
-/* That one prevents proper CRT output with LCD off */
-#undef BACKLIGHT_DAC_OFF
-
-static int aty128_set_backlight_enable(int on, int level, void *data)
-{
- struct aty128fb_par *par = data;
- unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
-
- if (!par->lcd_on)
- on = 0;
- reg |= LVDS_BL_MOD_EN | LVDS_BLON;
- if (on && level > BACKLIGHT_OFF) {
- reg |= LVDS_DIGION;
- if (!(reg & LVDS_ON)) {
- reg &= ~LVDS_BLON;
- aty_st_le32(LVDS_GEN_CNTL, reg);
- (void)aty_ld_le32(LVDS_GEN_CNTL);
- mdelay(10);
- reg |= LVDS_BLON;
- aty_st_le32(LVDS_GEN_CNTL, reg);
- }
- reg &= ~LVDS_BL_MOD_LEVEL_MASK;
- reg |= (backlight_conv[level] << LVDS_BL_MOD_LEVEL_SHIFT);
-#ifdef BACKLIGHT_LVDS_OFF
- reg |= LVDS_ON | LVDS_EN;
- reg &= ~LVDS_DISPLAY_DIS;
-#endif
- aty_st_le32(LVDS_GEN_CNTL, reg);
-#ifdef BACKLIGHT_DAC_OFF
- aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN));
-#endif
- } else {
- reg &= ~LVDS_BL_MOD_LEVEL_MASK;
- reg |= (backlight_conv[0] << LVDS_BL_MOD_LEVEL_SHIFT);
-#ifdef BACKLIGHT_LVDS_OFF
- reg |= LVDS_DISPLAY_DIS;
- aty_st_le32(LVDS_GEN_CNTL, reg);
- (void)aty_ld_le32(LVDS_GEN_CNTL);
- udelay(10);
- reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION);
-#endif
- aty_st_le32(LVDS_GEN_CNTL, reg);
-#ifdef BACKLIGHT_DAC_OFF
- aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN);
-#endif
- }
-
- return 0;
-}
-
-static int aty128_set_backlight_level(int level, void* data)
-{
- return aty128_set_backlight_enable(1, level, data);
-}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
#if 0
/*
* Accelerated functions
diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h
index e9b7a64..43d2cb5 100644
--- a/drivers/video/aty/atyfb.h
+++ b/drivers/video/aty/atyfb.h
@@ -151,6 +151,7 @@ struct atyfb_par {
int lock_blank;
unsigned long res_start;
unsigned long res_size;
+ struct pci_dev *pdev;
#ifdef __sparc__
struct pci_mmap_map *mmap_map;
u8 mmaped;
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index d9d7d3c..c5185f7 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -66,6 +66,7 @@
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
+#include <linux/backlight.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -2115,45 +2116,142 @@ static int atyfb_pci_resume(struct pci_dev *pdev)
#endif /* defined(CONFIG_PM) && defined(CONFIG_PCI) */
-#ifdef CONFIG_PMAC_BACKLIGHT
+/* Backlight */
+#ifdef CONFIG_FB_ATY_BACKLIGHT
+#define MAX_LEVEL 0xFF
- /*
- * LCD backlight control
- */
+static struct backlight_properties aty_bl_data;
-static int backlight_conv[] = {
- 0x00, 0x3f, 0x4c, 0x59, 0x66, 0x73, 0x80, 0x8d,
- 0x9a, 0xa7, 0xb4, 0xc1, 0xcf, 0xdc, 0xe9, 0xff
-};
+static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ int atylevel;
+
+ /* Get and convert the value */
+ mutex_lock(&info->bl_mutex);
+ atylevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
+ mutex_unlock(&info->bl_mutex);
-static int aty_set_backlight_enable(int on, int level, void *data)
+ if (atylevel < 0)
+ atylevel = 0;
+ else if (atylevel > MAX_LEVEL)
+ atylevel = MAX_LEVEL;
+
+ return atylevel;
+}
+
+static int aty_bl_update_status(struct backlight_device *bd)
{
- struct fb_info *info = (struct fb_info *) data;
- struct atyfb_par *par = (struct atyfb_par *) info->par;
+ struct atyfb_par *par = class_get_devdata(&bd->class_dev);
unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
+ int level;
+
+ if (bd->props->power != FB_BLANK_UNBLANK ||
+ bd->props->fb_blank != FB_BLANK_UNBLANK)
+ level = 0;
+ else
+ level = bd->props->brightness;
reg |= (BLMOD_EN | BIASMOD_EN);
- if (on && level > BACKLIGHT_OFF) {
+ if (level > 0) {
reg &= ~BIAS_MOD_LEVEL_MASK;
- reg |= (backlight_conv[level] << BIAS_MOD_LEVEL_SHIFT);
+ reg |= (aty_bl_get_level_brightness(par, level) << BIAS_MOD_LEVEL_SHIFT);
} else {
reg &= ~BIAS_MOD_LEVEL_MASK;
- reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT);
+ reg |= (aty_bl_get_level_brightness(par, 0) << BIAS_MOD_LEVEL_SHIFT);
}
aty_st_lcd(LCD_MISC_CNTL, reg, par);
+
return 0;
}
-static int aty_set_backlight_level(int level, void *data)
+static int aty_bl_get_brightness(struct backlight_device *bd)
{
- return aty_set_backlight_enable(1, level, data);
+ return bd->props->brightness;
}
-static struct backlight_controller aty_backlight_controller = {
- aty_set_backlight_enable,
- aty_set_backlight_level
+static struct backlight_properties aty_bl_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = aty_bl_get_brightness,
+ .update_status = aty_bl_update_status,
+ .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};
-#endif /* CONFIG_PMAC_BACKLIGHT */
+
+static void aty_bl_init(struct atyfb_par *par)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ struct backlight_device *bd;
+ char name[12];
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (!pmac_has_backlight_type("ati"))
+ return;
+#endif
+
+ snprintf(name, sizeof(name), "atybl%d", info->node);
+
+ bd = backlight_device_register(name, par, &aty_bl_data);
+ if (IS_ERR(bd)) {
+ info->bl_dev = NULL;
+ printk("aty: Backlight registration failed\n");
+ goto error;
+ }
+
+ mutex_lock(&info->bl_mutex);
+ info->bl_dev = bd;
+ fb_bl_default_curve(info, 0,
+ 0x3F * FB_BACKLIGHT_MAX / MAX_LEVEL,
+ 0xFF * FB_BACKLIGHT_MAX / MAX_LEVEL);
+ mutex_unlock(&info->bl_mutex);
+
+ up(&bd->sem);
+ bd->props->brightness = aty_bl_data.max_brightness;
+ bd->props->power = FB_BLANK_UNBLANK;
+ bd->props->update_status(bd);
+ down(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+ if (!pmac_backlight)
+ pmac_backlight = bd;
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+ printk("aty: Backlight initialized (%s)\n", name);
+
+ return;
+
+error:
+ return;
+}
+
+static void aty_bl_exit(struct atyfb_par *par)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+#endif
+
+ mutex_lock(&info->bl_mutex);
+ if (info->bl_dev) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (pmac_backlight == info->bl_dev)
+ pmac_backlight = NULL;
+#endif
+
+ backlight_device_unregister(info->bl_dev);
+
+ printk("aty: Backlight unloaded\n");
+ }
+ mutex_unlock(&info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
+
+#endif /* CONFIG_FB_ATY_BACKLIGHT */
static void __init aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
{
@@ -2513,9 +2611,13 @@ static int __init aty_init(struct fb_info *info, const char *name)
/* these bits let the 101 powerbook wake up from sleep -- paulus */
aty_st_lcd(POWER_MANAGEMENT, aty_ld_lcd(POWER_MANAGEMENT, par)
| (USE_F32KHZ | TRISTATE_MEM_EN), par);
- } else if (M64_HAS(MOBIL_BUS))
- register_backlight_controller(&aty_backlight_controller, info, "ati");
-#endif /* CONFIG_PMAC_BACKLIGHT */
+ } else
+#endif
+ if (M64_HAS(MOBIL_BUS)) {
+#ifdef CONFIG_FB_ATY_BACKLIGHT
+ aty_bl_init (par);
+#endif
+ }
memset(&var, 0, sizeof(var));
#ifdef CONFIG_PPC
@@ -2674,8 +2776,16 @@ static int atyfb_blank(int blank, struct fb_info *info)
return 0;
#ifdef CONFIG_PMAC_BACKLIGHT
- if (machine_is(powermac) && blank > FB_BLANK_NORMAL)
- set_backlight_enable(0);
+ if (machine_is(powermac) && blank > FB_BLANK_NORMAL) {
+ mutex_lock(&info->bl_mutex);
+ if (info->bl_dev) {
+ down(&info->bl_dev->sem);
+ info->bl_dev->props->power = FB_BLANK_POWERDOWN;
+ info->bl_dev->props->update_status(info->bl_dev);
+ up(&info->bl_dev->sem);
+ }
+ mutex_unlock(&info->bl_mutex);
+ }
#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
if (par->lcd_table && blank > FB_BLANK_NORMAL &&
(aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
@@ -2706,8 +2816,16 @@ static int atyfb_blank(int blank, struct fb_info *info)
aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par);
#ifdef CONFIG_PMAC_BACKLIGHT
- if (machine_is(powermac) && blank <= FB_BLANK_NORMAL)
- set_backlight_enable(1);
+ if (machine_is(powermac) && blank <= FB_BLANK_NORMAL) {
+ mutex_lock(&info->bl_mutex);
+ if (info->bl_dev) {
+ down(&info->bl_dev->sem);
+ info->bl_dev->props->power = FB_BLANK_UNBLANK;
+ info->bl_dev->props->update_status(info->bl_dev);
+ up(&info->bl_dev->sem);
+ }
+ mutex_unlock(&info->bl_mutex);
+ }
#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
if (par->lcd_table && blank <= FB_BLANK_NORMAL &&
(aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
@@ -2966,7 +3084,7 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
}
pcp = pdev->sysdata;
- if (node == pcp->prom_node) {
+ if (node == pcp->prom_node->node) {
struct fb_var_screeninfo *var = &default_var;
unsigned int N, P, Q, M, T, R;
u32 v_total, h_total;
@@ -3440,6 +3558,7 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi
par->res_start = res_start;
par->res_size = res_size;
par->irq = pdev->irq;
+ par->pdev = pdev;
/* Setup "info" structure */
#ifdef __sparc__
@@ -3571,6 +3690,11 @@ static void __devexit atyfb_remove(struct fb_info *info)
aty_set_crtc(par, &saved_crtc);
par->pll_ops->set_pll(info, &saved_pll);
+#ifdef CONFIG_FB_ATY_BACKLIGHT
+ if (M64_HAS(MOBIL_BUS))
+ aty_bl_exit(par);
+#endif
+
unregister_framebuffer(info);
#ifdef CONFIG_MTRR
@@ -3722,7 +3846,9 @@ static int __init atyfb_init(void)
atyfb_setup(option);
#endif
+#ifdef CONFIG_PCI
pci_register_driver(&atyfb_driver);
+#endif
#ifdef CONFIG_ATARI
atyfb_atari_probe();
#endif
@@ -3731,7 +3857,9 @@ static int __init atyfb_init(void)
static void __exit atyfb_exit(void)
{
+#ifdef CONFIG_PCI
pci_unregister_driver(&atyfb_driver);
+#endif
}
module_init(atyfb_init);
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
new file mode 100644
index 0000000..7de66b8
--- /dev/null
+++ b/drivers/video/aty/radeon_backlight.c
@@ -0,0 +1,247 @@
+/*
+ * Backlight code for ATI Radeon based graphic cards
+ *
+ * Copyright (c) 2000 Ani Joshi <ajoshi@kernel.crashing.org>
+ * Copyright (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "radeonfb.h"
+#include <linux/backlight.h>
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
+#define MAX_RADEON_LEVEL 0xFF
+
+static struct backlight_properties radeon_bl_data;
+
+struct radeon_bl_privdata {
+ struct radeonfb_info *rinfo;
+ uint8_t negative;
+};
+
+static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata,
+ int level)
+{
+ struct fb_info *info = pdata->rinfo->info;
+ int rlevel;
+
+ mutex_lock(&info->bl_mutex);
+
+ /* Get and convert the value */
+ rlevel = pdata->rinfo->info->bl_curve[level] *
+ FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL;
+
+ mutex_unlock(&info->bl_mutex);
+
+ if (pdata->negative)
+ rlevel = MAX_RADEON_LEVEL - rlevel;
+
+ if (rlevel < 0)
+ rlevel = 0;
+ else if (rlevel > MAX_RADEON_LEVEL)
+ rlevel = MAX_RADEON_LEVEL;
+
+ return rlevel;
+}
+
+static int radeon_bl_update_status(struct backlight_device *bd)
+{
+ struct radeon_bl_privdata *pdata = class_get_devdata(&bd->class_dev);
+ struct radeonfb_info *rinfo = pdata->rinfo;
+ u32 lvds_gen_cntl, tmpPixclksCntl;
+ int level;
+
+ if (rinfo->mon1_type != MT_LCD)
+ return 0;
+
+ /* We turn off the LCD completely instead of just dimming the
+ * backlight. This provides some greater power saving and the display
+ * is useless without backlight anyway.
+ */
+ if (bd->props->power != FB_BLANK_UNBLANK ||
+ bd->props->fb_blank != FB_BLANK_UNBLANK)
+ level = 0;
+ else
+ level = bd->props->brightness;
+
+ del_timer_sync(&rinfo->lvds_timer);
+ radeon_engine_idle();
+
+ lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
+ if (level > 0) {
+ lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
+ if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) {
+ lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
+ lvds_gen_cntl |= LVDS_BLON | LVDS_EN;
+ OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+ lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
+ lvds_gen_cntl |=
+ (radeon_bl_get_level_brightness(pdata, level) <<
+ LVDS_BL_MOD_LEVEL_SHIFT);
+ lvds_gen_cntl |= LVDS_ON;
+ lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN);
+ rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
+ mod_timer(&rinfo->lvds_timer,
+ jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
+ } else {
+ lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
+ lvds_gen_cntl |=
+ (radeon_bl_get_level_brightness(pdata, level) <<
+ LVDS_BL_MOD_LEVEL_SHIFT);
+ OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+ }
+ rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
+ rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl
+ & LVDS_STATE_MASK;
+ } else {
+ /* Asic bug, when turning off LVDS_ON, we have to make sure
+ RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
+ */
+ tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
+ if (rinfo->is_mobility || rinfo->is_IGP)
+ OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
+ lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN);
+ lvds_gen_cntl |= (radeon_bl_get_level_brightness(pdata, 0) <<
+ LVDS_BL_MOD_LEVEL_SHIFT);
+ lvds_gen_cntl |= LVDS_DISPLAY_DIS;
+ OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+ udelay(100);
+ lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN);
+ OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+ lvds_gen_cntl &= ~(LVDS_DIGON);
+ rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
+ mod_timer(&rinfo->lvds_timer,
+ jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
+ if (rinfo->is_mobility || rinfo->is_IGP)
+ OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl);
+ }
+ rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
+ rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
+
+ return 0;
+}
+
+static int radeon_bl_get_brightness(struct backlight_device *bd)
+{
+ return bd->props->brightness;
+}
+
+static struct backlight_properties radeon_bl_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = radeon_bl_get_brightness,
+ .update_status = radeon_bl_update_status,
+ .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
+};
+
+void radeonfb_bl_init(struct radeonfb_info *rinfo)
+{
+ struct backlight_device *bd;
+ struct radeon_bl_privdata *pdata;
+ char name[12];
+
+ if (rinfo->mon1_type != MT_LCD)
+ return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (!pmac_has_backlight_type("ati") &&
+ !pmac_has_backlight_type("mnca"))
+ return;
+#endif
+
+ pdata = kmalloc(sizeof(struct radeon_bl_privdata), GFP_KERNEL);
+ if (!pdata) {
+ printk("radeonfb: Memory allocation failed\n");
+ goto error;
+ }
+
+ snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node);
+
+ bd = backlight_device_register(name, pdata, &radeon_bl_data);
+ if (IS_ERR(bd)) {
+ rinfo->info->bl_dev = NULL;
+ printk("radeonfb: Backlight registration failed\n");
+ goto error;
+ }
+
+ pdata->rinfo = rinfo;
+
+ /* Pardon me for that hack... maybe some day we can figure out in what
+ * direction backlight should work on a given panel?
+ */
+ pdata->negative =
+ (rinfo->family != CHIP_FAMILY_RV200 &&
+ rinfo->family != CHIP_FAMILY_RV250 &&
+ rinfo->family != CHIP_FAMILY_RV280 &&
+ rinfo->family != CHIP_FAMILY_RV350);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ pdata->negative = pdata->negative ||
+ machine_is_compatible("PowerBook4,3") ||
+ machine_is_compatible("PowerBook6,3") ||
+ machine_is_compatible("PowerBook6,5");
+#endif
+
+ mutex_lock(&rinfo->info->bl_mutex);
+ rinfo->info->bl_dev = bd;
+ fb_bl_default_curve(rinfo->info, 0,
+ 63 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL,
+ 217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL);
+ mutex_unlock(&rinfo->info->bl_mutex);
+
+ up(&bd->sem);
+ bd->props->brightness = radeon_bl_data.max_brightness;
+ bd->props->power = FB_BLANK_UNBLANK;
+ bd->props->update_status(bd);
+ down(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+ if (!pmac_backlight)
+ pmac_backlight = bd;
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+ printk("radeonfb: Backlight initialized (%s)\n", name);
+
+ return;
+
+error:
+ kfree(pdata);
+ return;
+}
+
+void radeonfb_bl_exit(struct radeonfb_info *rinfo)
+{
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+#endif
+
+ mutex_lock(&rinfo->info->bl_mutex);
+ if (rinfo->info->bl_dev) {
+ struct radeon_bl_privdata *pdata;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (pmac_backlight == rinfo->info->bl_dev)
+ pmac_backlight = NULL;
+#endif
+
+ pdata = class_get_devdata(&rinfo->info->bl_dev->class_dev);
+ backlight_device_unregister(rinfo->info->bl_dev);
+ kfree(pdata);
+ rinfo->info->bl_dev = NULL;
+
+ printk("radeonfb: Backlight unloaded\n");
+ }
+ mutex_unlock(&rinfo->info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 387a18a..c5ecbb0 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -78,10 +78,6 @@
#include <asm/pci-bridge.h>
#include "../macmodes.h"
-#ifdef CONFIG_PMAC_BACKLIGHT
-#include <asm/backlight.h>
-#endif
-
#ifdef CONFIG_BOOTX_TEXT
#include <asm/btext.h>
#endif
@@ -277,20 +273,6 @@ static int nomtrr = 0;
* prototypes
*/
-
-#ifdef CONFIG_PPC_OF
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int radeon_set_backlight_enable(int on, int level, void *data);
-static int radeon_set_backlight_level(int level, void *data);
-static struct backlight_controller radeon_backlight_controller = {
- radeon_set_backlight_enable,
- radeon_set_backlight_level
-};
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
-#endif /* CONFIG_PPC_OF */
-
static void radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev)
{
if (!rinfo->bios_seg)
@@ -1913,116 +1895,6 @@ static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo)
return 0;
}
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-
-/* TODO: Dbl check these tables, we don't go up to full ON backlight
- * in these, possibly because we noticed MacOS doesn't, but I'd prefer
- * having some more official numbers from ATI
- */
-static int backlight_conv_m6[] = {
- 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
- 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
-};
-static int backlight_conv_m7[] = {
- 0x00, 0x3f, 0x4a, 0x55, 0x60, 0x6b, 0x76, 0x81,
- 0x8c, 0x97, 0xa2, 0xad, 0xb8, 0xc3, 0xce, 0xd9
-};
-
-#define BACKLIGHT_LVDS_OFF
-#undef BACKLIGHT_DAC_OFF
-
-/* We turn off the LCD completely instead of just dimming the backlight.
- * This provides some greater power saving and the display is useless
- * without backlight anyway.
- */
-static int radeon_set_backlight_enable(int on, int level, void *data)
-{
- struct radeonfb_info *rinfo = (struct radeonfb_info *)data;
- u32 lvds_gen_cntl, tmpPixclksCntl;
- int* conv_table;
-
- if (rinfo->mon1_type != MT_LCD)
- return 0;
-
- /* Pardon me for that hack... maybe some day we can figure
- * out in what direction backlight should work on a given
- * panel ?
- */
- if ((rinfo->family == CHIP_FAMILY_RV200 ||
- rinfo->family == CHIP_FAMILY_RV250 ||
- rinfo->family == CHIP_FAMILY_RV280 ||
- rinfo->family == CHIP_FAMILY_RV350) &&
- !machine_is_compatible("PowerBook4,3") &&
- !machine_is_compatible("PowerBook6,3") &&
- !machine_is_compatible("PowerBook6,5"))
- conv_table = backlight_conv_m7;
- else
- conv_table = backlight_conv_m6;
-
- del_timer_sync(&rinfo->lvds_timer);
- radeon_engine_idle();
-
- lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
- if (on && (level > BACKLIGHT_OFF)) {
- lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
- if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) {
- lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
- lvds_gen_cntl |= LVDS_BLON | LVDS_EN;
- OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
- lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
- lvds_gen_cntl |= (conv_table[level] <<
- LVDS_BL_MOD_LEVEL_SHIFT);
- lvds_gen_cntl |= LVDS_ON;
- lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN);
- rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
- mod_timer(&rinfo->lvds_timer,
- jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
- } else {
- lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
- lvds_gen_cntl |= (conv_table[level] <<
- LVDS_BL_MOD_LEVEL_SHIFT);
- OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
- }
- rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
- rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl
- & LVDS_STATE_MASK;
- } else {
- /* Asic bug, when turning off LVDS_ON, we have to make sure
- RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
- */
- tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
- if (rinfo->is_mobility || rinfo->is_IGP)
- OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
- lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN);
- lvds_gen_cntl |= (conv_table[0] <<
- LVDS_BL_MOD_LEVEL_SHIFT);
- lvds_gen_cntl |= LVDS_DISPLAY_DIS;
- OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
- udelay(100);
- lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN);
- OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
- lvds_gen_cntl &= ~(LVDS_DIGON);
- rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
- mod_timer(&rinfo->lvds_timer,
- jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
- if (rinfo->is_mobility || rinfo->is_IGP)
- OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl);
- }
- rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
- rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
-
- return 0;
-}
-
-
-static int radeon_set_backlight_level(int level, void *data)
-{
- return radeon_set_backlight_enable(1, level, data);
-}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
-
/*
* This reconfigure the card's internal memory map. In theory, we'd like
* to setup the card's memory at the same address as it's PCI bus address,
@@ -2477,14 +2349,7 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
MTRR_TYPE_WRCOMB, 1);
#endif
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (rinfo->mon1_type == MT_LCD) {
- register_backlight_controller(&radeon_backlight_controller,
- rinfo, "ati");
- register_backlight_controller(&radeon_backlight_controller,
- rinfo, "mnca");
- }
-#endif
+ radeonfb_bl_init(rinfo);
printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name);
@@ -2528,7 +2393,8 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev)
if (!rinfo)
return;
-
+
+ radeonfb_bl_exit(rinfo);
radeonfb_pm_exit(rinfo);
if (rinfo->mon1_EDID)
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h
index 217e00a..1645943 100644
--- a/drivers/video/aty/radeonfb.h
+++ b/drivers/video/aty/radeonfb.h
@@ -625,4 +625,13 @@ extern int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_
extern void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
int reg_only);
+/* Backlight functions */
+#ifdef CONFIG_FB_RADEON_BACKLIGHT
+extern void radeonfb_bl_init(struct radeonfb_info *rinfo);
+extern void radeonfb_bl_exit(struct radeonfb_info *rinfo);
+#else
+static inline void radeonfb_bl_init(struct radeonfb_info *rinfo) {}
+static inline void radeonfb_bl_exit(struct radeonfb_info *rinfo) {}
+#endif
+
#endif /* __RADEONFB_H__ */
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c
index 72ff6bf..d76bbfac 100644
--- a/drivers/video/chipsfb.c
+++ b/drivers/video/chipsfb.c
@@ -148,9 +148,24 @@ static int chipsfb_set_par(struct fb_info *info)
static int chipsfb_blank(int blank, struct fb_info *info)
{
#ifdef CONFIG_PMAC_BACKLIGHT
- // used to disable backlight only for blank > 1, but it seems
- // useful at blank = 1 too (saves battery, extends backlight life)
- set_backlight_enable(!blank);
+ mutex_lock(&pmac_backlight_mutex);
+
+ if (pmac_backlight) {
+ down(&pmac_backlight->sem);
+
+ /* used to disable backlight only for blank > 1, but it seems
+ * useful at blank = 1 too (saves battery, extends backlight
+ * life)
+ */
+ if (blank)
+ pmac_backlight->props->power = FB_BLANK_POWERDOWN;
+ else
+ pmac_backlight->props->power = FB_BLANK_UNBLANK;
+ pmac_backlight->props->update_status(pmac_backlight);
+ up(&pmac_backlight->sem);
+ }
+
+ mutex_unlock(&pmac_backlight_mutex);
#endif /* CONFIG_PMAC_BACKLIGHT */
return 1; /* get fb_blank to set the colormap to all black */
@@ -401,7 +416,14 @@ chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
#ifdef CONFIG_PMAC_BACKLIGHT
/* turn on the backlight */
- set_backlight_enable(1);
+ mutex_lock(&pmac_backlight_mutex);
+ if (pmac_backlight) {
+ down(&pmac_backlight->sem);
+ pmac_backlight->props->power = FB_BLANK_UNBLANK;
+ pmac_backlight->props->update_status(pmac_backlight);
+ up(&pmac_backlight->sem);
+ }
+ mutex_unlock(&pmac_backlight_mutex);
#endif /* CONFIG_PMAC_BACKLIGHT */
#ifdef CONFIG_PPC
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c
index 989e4d4..7f939d0 100644
--- a/drivers/video/console/mdacon.c
+++ b/drivers/video/console/mdacon.c
@@ -313,8 +313,8 @@ static const char __init *mdacon_startup(void)
mda_num_columns = 80;
mda_num_lines = 25;
- mda_vram_base = VGA_MAP_MEM(0xb0000);
mda_vram_len = 0x01000;
+ mda_vram_base = VGA_MAP_MEM(0xb0000, mda_vram_len);
mda_index_port = 0x3b4;
mda_value_port = 0x3b5;
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index d5a04b6..e64d42e 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -391,7 +391,7 @@ static const char __init *vgacon_startup(void)
static struct resource ega_console_resource =
{ "ega", 0x3B0, 0x3BF };
vga_video_type = VIDEO_TYPE_EGAM;
- vga_vram_end = 0xb8000;
+ vga_vram_size = 0x8000;
display_desc = "EGA+";
request_resource(&ioport_resource,
&ega_console_resource);
@@ -401,7 +401,7 @@ static const char __init *vgacon_startup(void)
static struct resource mda2_console_resource =
{ "mda", 0x3BF, 0x3BF };
vga_video_type = VIDEO_TYPE_MDA;
- vga_vram_end = 0xb2000;
+ vga_vram_size = 0x2000;
display_desc = "*MDA";
request_resource(&ioport_resource,
&mda1_console_resource);
@@ -418,7 +418,7 @@ static const char __init *vgacon_startup(void)
if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {
int i;
- vga_vram_end = 0xc0000;
+ vga_vram_size = 0x8000;
if (!ORIG_VIDEO_ISVGA) {
static struct resource ega_console_resource
@@ -443,7 +443,7 @@ static const char __init *vgacon_startup(void)
* and COE=1 isn't necessarily a good idea)
*/
vga_vram_base = 0xa0000;
- vga_vram_end = 0xb0000;
+ vga_vram_size = 0x10000;
outb_p(6, VGA_GFX_I);
outb_p(6, VGA_GFX_D);
#endif
@@ -475,7 +475,7 @@ static const char __init *vgacon_startup(void)
static struct resource cga_console_resource =
{ "cga", 0x3D4, 0x3D5 };
vga_video_type = VIDEO_TYPE_CGA;
- vga_vram_end = 0xba000;
+ vga_vram_size = 0x2000;
display_desc = "*CGA";
request_resource(&ioport_resource,
&cga_console_resource);
@@ -483,9 +483,8 @@ static const char __init *vgacon_startup(void)
}
}
- vga_vram_base = VGA_MAP_MEM(vga_vram_base);
- vga_vram_end = VGA_MAP_MEM(vga_vram_end);
- vga_vram_size = vga_vram_end - vga_vram_base;
+ vga_vram_base = VGA_MAP_MEM(vga_vram_base, vga_vram_size);
+ vga_vram_end = vga_vram_base + vga_vram_size;
/*
* Find out if there is a graphics card present.
@@ -1020,14 +1019,14 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
char *charmap;
if (vga_video_type != VIDEO_TYPE_EGAM) {
- charmap = (char *) VGA_MAP_MEM(colourmap);
+ charmap = (char *) VGA_MAP_MEM(colourmap, 0);
beg = 0x0e;
#ifdef VGA_CAN_DO_64KB
if (vga_video_type == VIDEO_TYPE_VGAC)
beg = 0x06;
#endif
} else {
- charmap = (char *) VGA_MAP_MEM(blackwmap);
+ charmap = (char *) VGA_MAP_MEM(blackwmap, 0);
beg = 0x0a;
}
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index 34e0739..3ceb8c1 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -18,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/fb.h>
#include <linux/console.h>
+#include <linux/module.h>
/**
* framebuffer_alloc - creates a new frame buffer info structure
@@ -55,6 +56,10 @@ struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
info->device = dev;
+#ifdef CONFIG_FB_BACKLIGHT
+ mutex_init(&info->bl_mutex);
+#endif
+
return info;
#undef PADDING
#undef BYTES_PER_LONG
@@ -414,6 +419,65 @@ static ssize_t show_fbstate(struct class_device *class_device, char *buf)
return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->state);
}
+#ifdef CONFIG_FB_BACKLIGHT
+static ssize_t store_bl_curve(struct class_device *class_device,
+ const char *buf, size_t count)
+{
+ struct fb_info *fb_info = class_get_devdata(class_device);
+ u8 tmp_curve[FB_BACKLIGHT_LEVELS];
+ unsigned int i;
+
+ if (count != (FB_BACKLIGHT_LEVELS / 8 * 24))
+ return -EINVAL;
+
+ for (i = 0; i < (FB_BACKLIGHT_LEVELS / 8); ++i)
+ if (sscanf(&buf[i * 24],
+ "%2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx\n",
+ &tmp_curve[i * 8 + 0],
+ &tmp_curve[i * 8 + 1],
+ &tmp_curve[i * 8 + 2],
+ &tmp_curve[i * 8 + 3],
+ &tmp_curve[i * 8 + 4],
+ &tmp_curve[i * 8 + 5],
+ &tmp_curve[i * 8 + 6],
+ &tmp_curve[i * 8 + 7]) != 8)
+ return -EINVAL;
+
+ /* If there has been an error in the input data, we won't
+ * reach this loop.
+ */
+ mutex_lock(&fb_info->bl_mutex);
+ for (i = 0; i < FB_BACKLIGHT_LEVELS; ++i)
+ fb_info->bl_curve[i] = tmp_curve[i];
+ mutex_unlock(&fb_info->bl_mutex);
+
+ return count;
+}
+
+static ssize_t show_bl_curve(struct class_device *class_device, char *buf)
+{
+ struct fb_info *fb_info = class_get_devdata(class_device);
+ ssize_t len = 0;
+ unsigned int i;
+
+ mutex_lock(&fb_info->bl_mutex);
+ for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8)
+ len += snprintf(&buf[len], PAGE_SIZE,
+ "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ fb_info->bl_curve[i + 0],
+ fb_info->bl_curve[i + 1],
+ fb_info->bl_curve[i + 2],
+ fb_info->bl_curve[i + 3],
+ fb_info->bl_curve[i + 4],
+ fb_info->bl_curve[i + 5],
+ fb_info->bl_curve[i + 6],
+ fb_info->bl_curve[i + 7]);
+ mutex_unlock(&fb_info->bl_mutex);
+
+ return len;
+}
+#endif
+
/* When cmap is added back in it should be a binary attribute
* not a text one. Consideration should also be given to converting
* fbdev to use configfs instead of sysfs */
@@ -432,6 +496,9 @@ static struct class_device_attribute class_device_attrs[] = {
__ATTR(con_rotate, S_IRUGO|S_IWUSR, show_con_rotate, store_con_rotate),
__ATTR(con_rotate_all, S_IWUSR, NULL, store_con_rotate_all),
__ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate),
+#ifdef CONFIG_FB_BACKLIGHT
+ __ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve),
+#endif
};
int fb_init_class_device(struct fb_info *fb_info)
@@ -454,4 +521,25 @@ void fb_cleanup_class_device(struct fb_info *fb_info)
&class_device_attrs[i]);
}
+#ifdef CONFIG_FB_BACKLIGHT
+/* This function generates a linear backlight curve
+ *
+ * 0: off
+ * 1-7: min
+ * 8-127: linear from min to max
+ */
+void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max)
+{
+ unsigned int i, flat, count, range = (max - min);
+
+ fb_info->bl_curve[0] = off;
+ for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat)
+ fb_info->bl_curve[flat] = min;
+
+ count = FB_BACKLIGHT_LEVELS * 15 / 16;
+ for (i = 0; i < count; ++i)
+ fb_info->bl_curve[flat + i] = min + (range * (i + 1) / count);
+}
+EXPORT_SYMBOL_GPL(fb_bl_default_curve);
+#endif
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index 6b88050..8a0c2d3 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -232,9 +232,6 @@ static int igafb_mmap(struct fb_info *info,
size = vma->vm_end - vma->vm_start;
- /* To stop the swapper from even considering these pages. */
- vma->vm_flags |= (VM_SHM | VM_LOCKED);
-
/* Each page, see which map applies */
for (page = 0; page < size; ) {
map_size = 0;
diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
index 469b06c..e290d74 100644
--- a/drivers/video/intelfb/intelfb.h
+++ b/drivers/video/intelfb/intelfb.h
@@ -237,7 +237,7 @@ struct intelfb_info {
u32 fb_start;
/* ring buffer */
- u8 __iomem *ring_head;
+ u32 ring_head;
u32 ring_tail;
u32 ring_tail_mask;
u32 ring_space;
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index 076fa56..0a0a8b1 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -707,7 +707,7 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
+ (dinfo->ring.offset << 12);
dinfo->ring.virtual = dinfo->aperture.virtual
+ (dinfo->ring.offset << 12);
- dinfo->ring_head = dinfo->ring.virtual;
+ dinfo->ring_head = 0;
}
if (dinfo->hwcursor) {
agp_memtype = dinfo->mobile ? AGP_PHYSICAL_MEMORY
@@ -766,18 +766,18 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
if (mtrr)
set_mtrr(dinfo);
- DBG_MSG("fb: 0x%x(+ 0x%x)/0x%x (0x%x)\n",
+ DBG_MSG("fb: 0x%x(+ 0x%x)/0x%x (0x%p)\n",
dinfo->fb.physical, dinfo->fb.offset, dinfo->fb.size,
- (u32 __iomem ) dinfo->fb.virtual);
- DBG_MSG("MMIO: 0x%x/0x%x (0x%x)\n",
+ dinfo->fb.virtual);
+ DBG_MSG("MMIO: 0x%x/0x%x (0x%p)\n",
dinfo->mmio_base_phys, INTEL_REG_SIZE,
- (u32 __iomem) dinfo->mmio_base);
- DBG_MSG("ring buffer: 0x%x/0x%x (0x%x)\n",
+ dinfo->mmio_base);
+ DBG_MSG("ring buffer: 0x%x/0x%x (0x%p)\n",
dinfo->ring.physical, dinfo->ring.size,
- (u32 __iomem ) dinfo->ring.virtual);
- DBG_MSG("HW cursor: 0x%x/0x%x (0x%x) (offset 0x%x) (phys 0x%x)\n",
+ dinfo->ring.virtual);
+ DBG_MSG("HW cursor: 0x%x/0x%x (0x%p) (offset 0x%x) (phys 0x%x)\n",
dinfo->cursor.physical, dinfo->cursor.size,
- (u32 __iomem ) dinfo->cursor.virtual, dinfo->cursor.offset,
+ dinfo->cursor.virtual, dinfo->cursor.offset,
dinfo->cursor.physical);
DBG_MSG("options: vram = %d, accel = %d, hwcursor = %d, fixed = %d, "
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 426b7430..7533b3d 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -1423,19 +1423,17 @@ wait_ring(struct intelfb_info *dinfo, int n)
end = jiffies + (HZ * 3);
while (dinfo->ring_space < n) {
- dinfo->ring_head = (u8 __iomem *)(INREG(PRI_RING_HEAD) &
- RING_HEAD_MASK);
- if (dinfo->ring_tail + RING_MIN_FREE <
- (u32 __iomem) dinfo->ring_head)
- dinfo->ring_space = (u32 __iomem) dinfo->ring_head
+ dinfo->ring_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;
+ if (dinfo->ring_tail + RING_MIN_FREE < dinfo->ring_head)
+ dinfo->ring_space = dinfo->ring_head
- (dinfo->ring_tail + RING_MIN_FREE);
else
dinfo->ring_space = (dinfo->ring.size +
- (u32 __iomem) dinfo->ring_head)
+ dinfo->ring_head)
- (dinfo->ring_tail + RING_MIN_FREE);
- if ((u32 __iomem) dinfo->ring_head != last_head) {
+ if (dinfo->ring_head != last_head) {
end = jiffies + (HZ * 3);
- last_head = (u32 __iomem) dinfo->ring_head;
+ last_head = dinfo->ring_head;
}
i++;
if (time_before(end, jiffies)) {
@@ -1495,15 +1493,13 @@ refresh_ring(struct intelfb_info *dinfo)
DBG_MSG("refresh_ring\n");
#endif
- dinfo->ring_head = (u8 __iomem *) (INREG(PRI_RING_HEAD) &
- RING_HEAD_MASK);
+ dinfo->ring_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;
dinfo->ring_tail = INREG(PRI_RING_TAIL) & RING_TAIL_MASK;
- if (dinfo->ring_tail + RING_MIN_FREE < (u32 __iomem)dinfo->ring_head)
- dinfo->ring_space = (u32 __iomem) dinfo->ring_head
+ if (dinfo->ring_tail + RING_MIN_FREE < dinfo->ring_head)
+ dinfo->ring_space = dinfo->ring_head
- (dinfo->ring_tail + RING_MIN_FREE);
else
- dinfo->ring_space = (dinfo->ring.size +
- (u32 __iomem) dinfo->ring_head)
+ dinfo->ring_space = (dinfo->ring.size + dinfo->ring_head)
- (dinfo->ring_tail + RING_MIN_FREE);
}
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index 23c1827..f4ddd34 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -102,6 +102,8 @@
#include <linux/config.h>
#include <linux/version.h>
+#define __OLD_VIDIOC_
+
#include "matroxfb_base.h"
#include "matroxfb_misc.h"
#include "matroxfb_accel.h"
@@ -158,9 +160,9 @@ static void update_crtc2(WPMINFO unsigned int pos) {
/* Make sure that displays are compatible */
if (info && (info->fbcon.var.bits_per_pixel == ACCESS_FBINFO(fbcon).var.bits_per_pixel)
- && (info->fbcon.var.xres_virtual == ACCESS_FBINFO(fbcon).var.xres_virtual)
- && (info->fbcon.var.green.length == ACCESS_FBINFO(fbcon).var.green.length)
- ) {
+ && (info->fbcon.var.xres_virtual == ACCESS_FBINFO(fbcon).var.xres_virtual)
+ && (info->fbcon.var.green.length == ACCESS_FBINFO(fbcon).var.green.length)
+ ) {
switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
case 16:
case 32:
@@ -224,7 +226,7 @@ static irqreturn_t matrox_irq(int irq, void *dev_id, struct pt_regs *fp)
int matroxfb_enable_irq(WPMINFO int reenable) {
u_int32_t bm;
-
+
if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400)
bm = 0x220;
else
@@ -241,7 +243,7 @@ int matroxfb_enable_irq(WPMINFO int reenable) {
mga_outl(M_IEN, mga_inl(M_IEN) | bm);
} else if (reenable) {
u_int32_t ien;
-
+
ien = mga_inl(M_IEN);
if ((ien & bm) != bm) {
printk(KERN_DEBUG "matroxfb: someone disabled IRQ [%08X]\n", ien);
@@ -347,7 +349,7 @@ static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
mga_setr(M_EXTVGA_INDEX, 0x00, p2);
}
matroxfb_DAC_unlock_irqrestore(flags);
-
+
update_crtc2(PMINFO pos);
CRITEND
@@ -390,7 +392,7 @@ static void matroxfb_remove(WPMINFO int dummy) {
static int matroxfb_open(struct fb_info *info, int user)
{
MINFO_FROM_INFO(info);
-
+
DBG_LOOP(__FUNCTION__)
if (ACCESS_FBINFO(dead)) {
@@ -406,7 +408,7 @@ static int matroxfb_open(struct fb_info *info, int user)
static int matroxfb_release(struct fb_info *info, int user)
{
MINFO_FROM_INFO(info);
-
+
DBG_LOOP(__FUNCTION__)
if (user) {
@@ -854,7 +856,7 @@ static int matroxfb_get_vblank(WPMINFO struct fb_vblank *vblank)
vblank->flags |= FB_VBLANK_VBLANKING;
if (test_bit(0, &ACCESS_FBINFO(irq_flags))) {
vblank->flags |= FB_VBLANK_HAVE_COUNT;
- /* Only one writer, aligned int value...
+ /* Only one writer, aligned int value...
it should work without lock and without atomic_t */
vblank->count = ACCESS_FBINFO(crtc1).vsync.cnt;
}
@@ -870,7 +872,7 @@ static int matroxfb_ioctl(struct fb_info *info,
{
void __user *argp = (void __user *)arg;
MINFO_FROM_INFO(info);
-
+
DBG(__FUNCTION__)
if (ACCESS_FBINFO(dead)) {
@@ -1081,7 +1083,7 @@ static int matroxfb_ioctl(struct fb_info *info,
case VIDIOC_QUERYCAP:
{
struct v4l2_capability r;
-
+
memset(&r, 0, sizeof(r));
strcpy(r.driver, "matroxfb");
strcpy(r.card, "Matrox");
@@ -1091,7 +1093,7 @@ static int matroxfb_ioctl(struct fb_info *info,
if (copy_to_user(argp, &r, sizeof(r)))
return -EFAULT;
return 0;
-
+
}
case VIDIOC_QUERYCTRL:
{
@@ -1690,8 +1692,8 @@ static int initMatrox2(WPMINFO struct board* b){
pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, &cmd);
mga_option &= 0x7FFFFFFF; /* clear BIG_ENDIAN */
mga_option |= MX_OPTION_BSWAP;
- /* disable palette snooping */
- cmd &= ~PCI_COMMAND_VGA_PALETTE;
+ /* disable palette snooping */
+ cmd &= ~PCI_COMMAND_VGA_PALETTE;
if (pci_dev_present(intel_82437)) {
if (!(mga_option & 0x20000000) && !ACCESS_FBINFO(devflags.nopciretry)) {
printk(KERN_WARNING "matroxfb: Disabling PCI retries due to i82437 present\n");
@@ -1809,12 +1811,12 @@ static int initMatrox2(WPMINFO struct board* b){
if (fv) {
tmp = fv * (vesafb_defined.upper_margin + vesafb_defined.yres
- + vesafb_defined.lower_margin + vesafb_defined.vsync_len);
+ + vesafb_defined.lower_margin + vesafb_defined.vsync_len);
if ((tmp < fh) || (fh == 0)) fh = tmp;
}
if (fh) {
tmp = fh * (vesafb_defined.left_margin + vesafb_defined.xres
- + vesafb_defined.right_margin + vesafb_defined.hsync_len);
+ + vesafb_defined.right_margin + vesafb_defined.hsync_len);
if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
}
tmp = (maxclk + 499) / 500;
@@ -1890,14 +1892,14 @@ static int initMatrox2(WPMINFO struct board* b){
/* there is no console on this fb... but we have to initialize hardware
* until someone tells me what is proper thing to do */
- if (!ACCESS_FBINFO(initialized)) {
- printk(KERN_INFO "fb%d: initializing hardware\n",
- ACCESS_FBINFO(fbcon.node));
- /* We have to use FB_ACTIVATE_FORCE, as we had to put vesafb_defined to the fbcon.var
- * already before, so register_framebuffer works correctly. */
- vesafb_defined.activate |= FB_ACTIVATE_FORCE;
- fb_set_var(&ACCESS_FBINFO(fbcon), &vesafb_defined);
- }
+ if (!ACCESS_FBINFO(initialized)) {
+ printk(KERN_INFO "fb%d: initializing hardware\n",
+ ACCESS_FBINFO(fbcon.node));
+ /* We have to use FB_ACTIVATE_FORCE, as we had to put vesafb_defined to the fbcon.var
+ * already before, so register_framebuffer works correctly. */
+ vesafb_defined.activate |= FB_ACTIVATE_FORCE;
+ fb_set_var(&ACCESS_FBINFO(fbcon), &vesafb_defined);
+ }
return 0;
failVideoIO:;
@@ -2356,7 +2358,7 @@ static int __init matroxfb_setup(char *options) {
else if (!strncmp(this_opt, "dfp:", 4)) {
dfp_type = simple_strtoul(this_opt+4, NULL, 0);
dfp = 1;
- }
+ }
#ifdef CONFIG_PPC_PMAC
else if (!strncmp(this_opt, "vmode:", 6)) {
unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
diff --git a/drivers/video/nvidia/Makefile b/drivers/video/nvidia/Makefile
index 690d37e..ca47432 100644
--- a/drivers/video/nvidia/Makefile
+++ b/drivers/video/nvidia/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_FB_NVIDIA) += nvidiafb.o
nvidiafb-y := nvidia.o nv_hw.o nv_setup.o \
nv_accel.o
nvidiafb-$(CONFIG_FB_NVIDIA_I2C) += nv_i2c.o
+nvidiafb-$(CONFIG_FB_NVIDIA_BACKLIGHT) += nv_backlight.o
nvidiafb-$(CONFIG_PPC_OF) += nv_of.o
-nvidiafb-objs := $(nvidiafb-y) \ No newline at end of file
+nvidiafb-objs := $(nvidiafb-y)
diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c
new file mode 100644
index 0000000..1c1c10c
--- /dev/null
+++ b/drivers/video/nvidia/nv_backlight.c
@@ -0,0 +1,175 @@
+/*
+ * Backlight code for nVidia based graphic cards
+ *
+ * Copyright 2004 Antonino Daplas <adaplas@pol.net>
+ * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include "nv_local.h"
+#include "nv_type.h"
+#include "nv_proto.h"
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#include <asm/machdep.h>
+#endif
+
+/* We do not have any information about which values are allowed, thus
+ * we used safe values.
+ */
+#define MIN_LEVEL 0x158
+#define MAX_LEVEL 0x534
+
+static struct backlight_properties nvidia_bl_data;
+
+static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
+ int level)
+{
+ struct fb_info *info = pci_get_drvdata(par->pci_dev);
+ int nlevel;
+
+ /* Get and convert the value */
+ mutex_lock(&info->bl_mutex);
+ nlevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
+ mutex_unlock(&info->bl_mutex);
+
+ if (nlevel < 0)
+ nlevel = 0;
+ else if (nlevel < MIN_LEVEL)
+ nlevel = MIN_LEVEL;
+ else if (nlevel > MAX_LEVEL)
+ nlevel = MAX_LEVEL;
+
+ return nlevel;
+}
+
+static int nvidia_bl_update_status(struct backlight_device *bd)
+{
+ struct nvidia_par *par = class_get_devdata(&bd->class_dev);
+ u32 tmp_pcrt, tmp_pmc, fpcontrol;
+ int level;
+
+ if (!par->FlatPanel)
+ return 0;
+
+ if (bd->props->power != FB_BLANK_UNBLANK ||
+ bd->props->fb_blank != FB_BLANK_UNBLANK)
+ level = 0;
+ else
+ level = bd->props->brightness;
+
+ tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF;
+ tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC;
+ fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC;
+
+ if (level > 0) {
+ tmp_pcrt |= 0x1;
+ tmp_pmc |= (1 << 31); /* backlight bit */
+ tmp_pmc |= nvidia_bl_get_level_brightness(par, level) << 16;
+ fpcontrol |= par->fpSyncs;
+ } else
+ fpcontrol |= 0x20000022;
+
+ NV_WR32(par->PCRTC0, 0x081C, tmp_pcrt);
+ NV_WR32(par->PMC, 0x10F0, tmp_pmc);
+ NV_WR32(par->PRAMDAC, 0x848, fpcontrol);
+
+ return 0;
+}
+
+static int nvidia_bl_get_brightness(struct backlight_device *bd)
+{
+ return bd->props->brightness;
+}
+
+static struct backlight_properties nvidia_bl_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = nvidia_bl_get_brightness,
+ .update_status = nvidia_bl_update_status,
+ .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
+};
+
+void nvidia_bl_init(struct nvidia_par *par)
+{
+ struct fb_info *info = pci_get_drvdata(par->pci_dev);
+ struct backlight_device *bd;
+ char name[12];
+
+ if (!par->FlatPanel)
+ return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (!machine_is(powermac) ||
+ !pmac_has_backlight_type("mnca"))
+ return;
+#endif
+
+ snprintf(name, sizeof(name), "nvidiabl%d", info->node);
+
+ bd = backlight_device_register(name, par, &nvidia_bl_data);
+ if (IS_ERR(bd)) {
+ info->bl_dev = NULL;
+ printk("nvidia: Backlight registration failed\n");
+ goto error;
+ }
+
+ mutex_lock(&info->bl_mutex);
+ info->bl_dev = bd;
+ fb_bl_default_curve(info, 0,
+ 0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL,
+ 0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL);
+ mutex_unlock(&info->bl_mutex);
+
+ up(&bd->sem);
+ bd->props->brightness = nvidia_bl_data.max_brightness;
+ bd->props->power = FB_BLANK_UNBLANK;
+ bd->props->update_status(bd);
+ down(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+ if (!pmac_backlight)
+ pmac_backlight = bd;
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+ printk("nvidia: Backlight initialized (%s)\n", name);
+
+ return;
+
+error:
+ return;
+}
+
+void nvidia_bl_exit(struct nvidia_par *par)
+{
+ struct fb_info *info = pci_get_drvdata(par->pci_dev);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+#endif
+
+ mutex_lock(&info->bl_mutex);
+ if (info->bl_dev) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (pmac_backlight == info->bl_dev)
+ pmac_backlight = NULL;
+#endif
+
+ backlight_device_unregister(info->bl_dev);
+
+ printk("nvidia: Backlight unloaded\n");
+ }
+ mutex_unlock(&info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
diff --git a/drivers/video/nvidia/nv_proto.h b/drivers/video/nvidia/nv_proto.h
index b149a69..6fba656 100644
--- a/drivers/video/nvidia/nv_proto.h
+++ b/drivers/video/nvidia/nv_proto.h
@@ -63,4 +63,14 @@ extern void nvidiafb_imageblit(struct fb_info *info,
const struct fb_image *image);
extern int nvidiafb_sync(struct fb_info *info);
extern u8 byte_rev[256];
+
+/* in nv_backlight.h */
+#ifdef CONFIG_FB_NVIDIA_BACKLIGHT
+extern void nvidia_bl_init(struct nvidia_par *par);
+extern void nvidia_bl_exit(struct nvidia_par *par);
+#else
+static inline void nvidia_bl_init(struct nvidia_par *par) {}
+static inline void nvidia_bl_exit(struct nvidia_par *par) {}
+#endif
+
#endif /* __NV_PROTO_H__ */
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index 093ab99..03a7c1e 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -22,6 +22,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/console.h>
+#include <linux/backlight.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif
@@ -29,10 +30,6 @@
#include <asm/prom.h>
#include <asm/pci-bridge.h>
#endif
-#ifdef CONFIG_PMAC_BACKLIGHT
-#include <asm/machdep.h>
-#include <asm/backlight.h>
-#endif
#include "nv_local.h"
#include "nv_type.h"
@@ -470,75 +467,6 @@ static struct fb_var_screeninfo __devinitdata nvidiafb_default_var = {
.vmode = FB_VMODE_NONINTERLACED
};
-/*
- * Backlight control
- */
-#ifdef CONFIG_PMAC_BACKLIGHT
-
-static int nvidia_backlight_levels[] = {
- 0x158,
- 0x192,
- 0x1c6,
- 0x200,
- 0x234,
- 0x268,
- 0x2a2,
- 0x2d6,
- 0x310,
- 0x344,
- 0x378,
- 0x3b2,
- 0x3e6,
- 0x41a,
- 0x454,
- 0x534,
-};
-
-/* ------------------------------------------------------------------------- *
- *
- * Backlight operations
- *
- * ------------------------------------------------------------------------- */
-
-static int nvidia_set_backlight_enable(int on, int level, void *data)
-{
- struct nvidia_par *par = data;
- u32 tmp_pcrt, tmp_pmc, fpcontrol;
-
- tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF;
- tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC;
- fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC;
-
- if (on && (level > BACKLIGHT_OFF)) {
- tmp_pcrt |= 0x1;
- tmp_pmc |= (1 << 31); // backlight bit
- tmp_pmc |= nvidia_backlight_levels[level - 1] << 16;
- }
-
- if (on)
- fpcontrol |= par->fpSyncs;
- else
- fpcontrol |= 0x20000022;
-
- NV_WR32(par->PCRTC0, 0x081C, tmp_pcrt);
- NV_WR32(par->PMC, 0x10F0, tmp_pmc);
- NV_WR32(par->PRAMDAC, 0x848, fpcontrol);
-
- return 0;
-}
-
-static int nvidia_set_backlight_level(int level, void *data)
-{
- return nvidia_set_backlight_enable(1, level, data);
-}
-
-static struct backlight_controller nvidia_backlight_controller = {
- nvidia_set_backlight_enable,
- nvidia_set_backlight_level
-};
-
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
static void nvidiafb_load_cursor_image(struct nvidia_par *par, u8 * data8,
u16 bg, u16 fg, u32 w, u32 h)
{
@@ -1355,10 +1283,15 @@ static int nvidiafb_blank(int blank, struct fb_info *info)
NVWriteSeq(par, 0x01, tmp);
NVWriteCrtc(par, 0x1a, vesa);
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (par->FlatPanel && machine_is(powermac)) {
- set_backlight_enable(!blank);
+#ifdef CONFIG_FB_NVIDIA_BACKLIGHT
+ mutex_lock(&info->bl_mutex);
+ if (info->bl_dev) {
+ down(&info->bl_dev->sem);
+ info->bl_dev->props->power = blank;
+ info->bl_dev->props->update_status(info->bl_dev);
+ up(&info->bl_dev->sem);
}
+ mutex_unlock(&info->bl_mutex);
#endif
NVTRACE_LEAVE();
@@ -1741,11 +1674,9 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
"PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n",
info->fix.id,
par->FbMapSize / (1024 * 1024), info->fix.smem_start);
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (par->FlatPanel && machine_is(powermac))
- register_backlight_controller(&nvidia_backlight_controller,
- par, "mnca");
-#endif
+
+ nvidia_bl_init(par);
+
NVTRACE_LEAVE();
return 0;
@@ -1775,6 +1706,8 @@ static void __exit nvidiafb_remove(struct pci_dev *pd)
NVTRACE_ENTER();
+ nvidia_bl_exit(par);
+
unregister_framebuffer(info);
#ifdef CONFIG_MTRR
if (par->mtrr.vram_valid)
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 3e9308f..d4384ab 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -41,6 +41,7 @@
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/backlight.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif
@@ -272,34 +273,154 @@ static const struct riva_regs reg_template = {
/*
* Backlight control
*/
-#ifdef CONFIG_PMAC_BACKLIGHT
+#ifdef CONFIG_FB_RIVA_BACKLIGHT
+/* We do not have any information about which values are allowed, thus
+ * we used safe values.
+ */
+#define MIN_LEVEL 0x158
+#define MAX_LEVEL 0x534
-static int riva_backlight_levels[] = {
- 0x158,
- 0x192,
- 0x1c6,
- 0x200,
- 0x234,
- 0x268,
- 0x2a2,
- 0x2d6,
- 0x310,
- 0x344,
- 0x378,
- 0x3b2,
- 0x3e6,
- 0x41a,
- 0x454,
- 0x534,
-};
+static struct backlight_properties riva_bl_data;
+
+static int riva_bl_get_level_brightness(struct riva_par *par,
+ int level)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ int nlevel;
+
+ /* Get and convert the value */
+ mutex_lock(&info->bl_mutex);
+ nlevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
+ mutex_unlock(&info->bl_mutex);
+
+ if (nlevel < 0)
+ nlevel = 0;
+ else if (nlevel < MIN_LEVEL)
+ nlevel = MIN_LEVEL;
+ else if (nlevel > MAX_LEVEL)
+ nlevel = MAX_LEVEL;
+
+ return nlevel;
+}
+
+static int riva_bl_update_status(struct backlight_device *bd)
+{
+ struct riva_par *par = class_get_devdata(&bd->class_dev);
+ U032 tmp_pcrt, tmp_pmc;
+ int level;
+
+ if (bd->props->power != FB_BLANK_UNBLANK ||
+ bd->props->fb_blank != FB_BLANK_UNBLANK)
+ level = 0;
+ else
+ level = bd->props->brightness;
+
+ tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF;
+ tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC;
+ if(level > 0) {
+ tmp_pcrt |= 0x1;
+ tmp_pmc |= (1 << 31); /* backlight bit */
+ tmp_pmc |= riva_bl_get_level_brightness(par, level) << 16; /* level */
+ }
+ par->riva.PCRTC0[0x081C/4] = tmp_pcrt;
+ par->riva.PMC[0x10F0/4] = tmp_pmc;
+
+ return 0;
+}
+
+static int riva_bl_get_brightness(struct backlight_device *bd)
+{
+ return bd->props->brightness;
+}
-static int riva_set_backlight_enable(int on, int level, void *data);
-static int riva_set_backlight_level(int level, void *data);
-static struct backlight_controller riva_backlight_controller = {
- riva_set_backlight_enable,
- riva_set_backlight_level
+static struct backlight_properties riva_bl_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = riva_bl_get_brightness,
+ .update_status = riva_bl_update_status,
+ .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};
-#endif /* CONFIG_PMAC_BACKLIGHT */
+
+static void riva_bl_init(struct riva_par *par)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ struct backlight_device *bd;
+ char name[12];
+
+ if (!par->FlatPanel)
+ return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (!machine_is(powermac) ||
+ !pmac_has_backlight_type("mnca"))
+ return;
+#endif
+
+ snprintf(name, sizeof(name), "rivabl%d", info->node);
+
+ bd = backlight_device_register(name, par, &riva_bl_data);
+ if (IS_ERR(bd)) {
+ info->bl_dev = NULL;
+ printk("riva: Backlight registration failed\n");
+ goto error;
+ }
+
+ mutex_lock(&info->bl_mutex);
+ info->bl_dev = bd;
+ fb_bl_default_curve(info, 0,
+ 0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL,
+ 0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL);
+ mutex_unlock(&info->bl_mutex);
+
+ up(&bd->sem);
+ bd->props->brightness = riva_bl_data.max_brightness;
+ bd->props->power = FB_BLANK_UNBLANK;
+ bd->props->update_status(bd);
+ down(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+ if (!pmac_backlight)
+ pmac_backlight = bd;
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+ printk("riva: Backlight initialized (%s)\n", name);
+
+ return;
+
+error:
+ return;
+}
+
+static void riva_bl_exit(struct riva_par *par)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+#endif
+
+ mutex_lock(&info->bl_mutex);
+ if (info->bl_dev) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (pmac_backlight == info->bl_dev)
+ pmac_backlight = NULL;
+#endif
+
+ backlight_device_unregister(info->bl_dev);
+
+ printk("riva: Backlight unloaded\n");
+ }
+ mutex_unlock(&info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
+#else
+static inline void riva_bl_init(struct riva_par *par) {}
+static inline void riva_bl_exit(struct riva_par *par) {}
+#endif /* CONFIG_FB_RIVA_BACKLIGHT */
/* ------------------------------------------------------------------------- *
*
@@ -973,36 +1094,6 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
/* ------------------------------------------------------------------------- *
*
- * Backlight operations
- *
- * ------------------------------------------------------------------------- */
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int riva_set_backlight_enable(int on, int level, void *data)
-{
- struct riva_par *par = data;
- U032 tmp_pcrt, tmp_pmc;
-
- tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF;
- tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC;
- if(on && (level > BACKLIGHT_OFF)) {
- tmp_pcrt |= 0x1;
- tmp_pmc |= (1 << 31); // backlight bit
- tmp_pmc |= riva_backlight_levels[level-1] << 16; // level
- }
- par->riva.PCRTC0[0x081C/4] = tmp_pcrt;
- par->riva.PMC[0x10F0/4] = tmp_pmc;
- return 0;
-}
-
-static int riva_set_backlight_level(int level, void *data)
-{
- return riva_set_backlight_enable(1, level, data);
-}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
-/* ------------------------------------------------------------------------- *
- *
* framebuffer operations
*
* ------------------------------------------------------------------------- */
@@ -1247,10 +1338,15 @@ static int rivafb_blank(int blank, struct fb_info *info)
SEQout(par, 0x01, tmp);
CRTCout(par, 0x1a, vesa);
-#ifdef CONFIG_PMAC_BACKLIGHT
- if ( par->FlatPanel && machine_is(powermac)) {
- set_backlight_enable(!blank);
+#ifdef CONFIG_FB_RIVA_BACKLIGHT
+ mutex_lock(&info->bl_mutex);
+ if (info->bl_dev) {
+ down(&info->bl_dev->sem);
+ info->bl_dev->props->power = blank;
+ info->bl_dev->props->update_status(info->bl_dev);
+ up(&info->bl_dev->sem);
}
+ mutex_unlock(&info->bl_mutex);
#endif
NVTRACE_LEAVE();
@@ -2037,11 +2133,9 @@ static int __devinit rivafb_probe(struct pci_dev *pd,
RIVAFB_VERSION,
info->fix.smem_len / (1024 * 1024),
info->fix.smem_start);
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (default_par->FlatPanel && machine_is(powermac))
- register_backlight_controller(&riva_backlight_controller,
- default_par, "mnca");
-#endif
+
+ riva_bl_init(info->par);
+
NVTRACE_LEAVE();
return 0;
@@ -2074,6 +2168,8 @@ static void __exit rivafb_remove(struct pci_dev *pd)
NVTRACE_ENTER();
+ riva_bl_exit(par);
+
#ifdef CONFIG_FB_RIVA_I2C
riva_delete_i2c_busses(par);
kfree(par->EDID);
diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c
index 9ac2d31..41f8c2d 100644
--- a/drivers/video/tridentfb.c
+++ b/drivers/video/tridentfb.c
@@ -551,7 +551,7 @@ static inline void enable_mmio(void)
#define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F)
/* Return flat panel's maximum x resolution */
-static int __init get_nativex(void)
+static int __devinit get_nativex(void)
{
int x,y,tmp;
@@ -658,7 +658,7 @@ static void set_number_of_lines(int lines)
* If we see that FP is active we assume we have one.
* Otherwise we have a CRT display.User can override.
*/
-static unsigned int __init get_displaytype(void)
+static unsigned int __devinit get_displaytype(void)
{
if (fp)
return DISPLAY_FP;
@@ -668,7 +668,7 @@ static unsigned int __init get_displaytype(void)
}
/* Try detecting the video memory size */
-static unsigned int __init get_memsize(void)
+static unsigned int __devinit get_memsize(void)
{
unsigned char tmp, tmp2;
unsigned int k;
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
index f3f16fd..4fd2a27 100644
--- a/drivers/video/vga16fb.c
+++ b/drivers/video/vga16fb.c
@@ -1351,7 +1351,7 @@ static int __init vga16fb_probe(struct device *device)
}
/* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
- info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS);
+ info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0);
if (!info->screen_base) {
printk(KERN_ERR "vga16fb: unable to map device\n");
diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig
index 5e61ed5..8b3d0f0 100644
--- a/drivers/w1/Kconfig
+++ b/drivers/w1/Kconfig
@@ -2,8 +2,9 @@ menu "Dallas's 1-wire bus"
config W1
tristate "Dallas's 1-wire support"
+ depends on CONNECTOR
---help---
- Dallas's 1-wire bus is useful to connect slow 1-pin devices
+ Dallas' 1-wire bus is useful to connect slow 1-pin devices
such as iButtons and thermal sensors.
If you want W1 support, you should say Y here.
@@ -11,6 +12,18 @@ config W1
This W1 support can also be built as a module. If so, the module
will be called wire.ko.
+config W1_CON
+ depends on CONNECTOR && W1
+ bool "Userspace communication over connector"
+ default y
+ --- help ---
+ This allows to communicate with userspace using connector [Documentation/connector].
+ There are three types of messages between w1 core and userspace:
+ 1. Events. They are generated each time new master or slave device found
+ either due to automatic or requested search.
+ 2. Userspace commands. Includes read/write and search/alarm search comamnds.
+ 3. Replies to userspace commands.
+
source drivers/w1/masters/Kconfig
source drivers/w1/slaves/Kconfig
diff --git a/drivers/w1/Makefile b/drivers/w1/Makefile
index 0c2aa22..93845a2 100644
--- a/drivers/w1/Makefile
+++ b/drivers/w1/Makefile
@@ -2,10 +2,6 @@
# Makefile for the Dallas's 1-wire bus.
#
-ifneq ($(CONFIG_NET), y)
-EXTRA_CFLAGS += -DNETLINK_DISABLED
-endif
-
ifeq ($(CONFIG_W1_DS2433_CRC), y)
EXTRA_CFLAGS += -DCONFIG_W1_F23_CRC
endif
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig
index c6bad4d..2fb4255 100644
--- a/drivers/w1/masters/Kconfig
+++ b/drivers/w1/masters/Kconfig
@@ -15,24 +15,15 @@ config W1_MASTER_MATROX
This support is also available as a module. If so, the module
will be called matrox_w1.ko.
-config W1_MASTER_DS9490
- tristate "DS9490R transport layer driver"
- depends on W1 && USB
- help
- Say Y here if you want to have a driver for DS9490R UWB <-> W1 bridge.
-
- This support is also available as a module. If so, the module
- will be called ds9490r.ko.
-
-config W1_MASTER_DS9490_BRIDGE
- tristate "DS9490R USB <-> W1 transport layer for 1-wire"
- depends on W1_MASTER_DS9490
- help
- Say Y here if you want to communicate with your 1-wire devices
- using DS9490R USB bridge.
-
- This support is also available as a module. If so, the module
- will be called ds_w1_bridge.ko.
+config W1_MASTER_DS2490
+ tristate "DS2490 USB <-> W1 transport layer for 1-wire"
+ depends on W1 && USB
+ help
+ Say Y here if you want to have a driver for DS2490 based USB <-> W1 bridges,
+ for example DS9490*.
+
+ This support is also available as a module. If so, the module
+ will be called ds2490.ko.
config W1_MASTER_DS2482
tristate "Maxim DS2482 I2C to 1-Wire bridge"
diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile
index 1f3c8b9..4cee256 100644
--- a/drivers/w1/masters/Makefile
+++ b/drivers/w1/masters/Makefile
@@ -3,11 +3,6 @@
#
obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o
-
-obj-$(CONFIG_W1_MASTER_DS9490) += ds9490r.o
-ds9490r-objs := dscore.o
-
-obj-$(CONFIG_W1_MASTER_DS9490_BRIDGE) += ds_w1_bridge.o
-
+obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o
obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o
diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c
index d1cacd2..af492cc 100644
--- a/drivers/w1/masters/ds2482.c
+++ b/drivers/w1/masters/ds2482.c
@@ -125,7 +125,7 @@ struct ds2482_w1_chan {
struct ds2482_data {
struct i2c_client client;
- struct semaphore access_lock;
+ struct mutex access_lock;
/* 1-wire interface(s) */
int w1_count; /* 1 or 8 */
@@ -265,7 +265,7 @@ static u8 ds2482_w1_touch_bit(void *data, u8 bit)
struct ds2482_data *pdev = pchan->pdev;
int status = -1;
- down(&pdev->access_lock);
+ mutex_lock(&pdev->access_lock);
/* Select the channel */
ds2482_wait_1wire_idle(pdev);
@@ -277,7 +277,7 @@ static u8 ds2482_w1_touch_bit(void *data, u8 bit)
bit ? 0xFF : 0))
status = ds2482_wait_1wire_idle(pdev);
- up(&pdev->access_lock);
+ mutex_unlock(&pdev->access_lock);
return (status & DS2482_REG_STS_SBR) ? 1 : 0;
}
@@ -297,7 +297,7 @@ static u8 ds2482_w1_triplet(void *data, u8 dbit)
struct ds2482_data *pdev = pchan->pdev;
int status = (3 << 5);
- down(&pdev->access_lock);
+ mutex_lock(&pdev->access_lock);
/* Select the channel */
ds2482_wait_1wire_idle(pdev);
@@ -309,7 +309,7 @@ static u8 ds2482_w1_triplet(void *data, u8 dbit)
dbit ? 0xFF : 0))
status = ds2482_wait_1wire_idle(pdev);
- up(&pdev->access_lock);
+ mutex_unlock(&pdev->access_lock);
/* Decode the status */
return (status >> 5);
@@ -326,7 +326,7 @@ static void ds2482_w1_write_byte(void *data, u8 byte)
struct ds2482_w1_chan *pchan = data;
struct ds2482_data *pdev = pchan->pdev;
- down(&pdev->access_lock);
+ mutex_lock(&pdev->access_lock);
/* Select the channel */
ds2482_wait_1wire_idle(pdev);
@@ -336,7 +336,7 @@ static void ds2482_w1_write_byte(void *data, u8 byte)
/* Send the write byte command */
ds2482_send_cmd_data(pdev, DS2482_CMD_1WIRE_WRITE_BYTE, byte);
- up(&pdev->access_lock);
+ mutex_unlock(&pdev->access_lock);
}
/**
@@ -351,7 +351,7 @@ static u8 ds2482_w1_read_byte(void *data)
struct ds2482_data *pdev = pchan->pdev;
int result;
- down(&pdev->access_lock);
+ mutex_lock(&pdev->access_lock);
/* Select the channel */
ds2482_wait_1wire_idle(pdev);
@@ -370,7 +370,7 @@ static u8 ds2482_w1_read_byte(void *data)
/* Read the data byte */
result = i2c_smbus_read_byte(&pdev->client);
- up(&pdev->access_lock);
+ mutex_unlock(&pdev->access_lock);
return result;
}
@@ -389,7 +389,7 @@ static u8 ds2482_w1_reset_bus(void *data)
int err;
u8 retval = 1;
- down(&pdev->access_lock);
+ mutex_lock(&pdev->access_lock);
/* Select the channel */
ds2482_wait_1wire_idle(pdev);
@@ -409,7 +409,7 @@ static u8 ds2482_w1_reset_bus(void *data)
0xF0);
}
- up(&pdev->access_lock);
+ mutex_unlock(&pdev->access_lock);
return retval;
}
@@ -482,7 +482,7 @@ static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind)
snprintf(new_client->name, sizeof(new_client->name), "ds2482-%d00",
data->w1_count);
- init_MUTEX(&data->access_lock);
+ mutex_init(&data->access_lock);
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
diff --git a/drivers/w1/masters/dscore.c b/drivers/w1/masters/ds2490.c
index 2cf7776..299e274 100644
--- a/drivers/w1/masters/dscore.c
+++ b/drivers/w1/masters/ds2490.c
@@ -24,7 +24,136 @@
#include <linux/mod_devicetable.h>
#include <linux/usb.h>
-#include "dscore.h"
+#include "../w1_int.h"
+#include "../w1.h"
+
+/* COMMAND TYPE CODES */
+#define CONTROL_CMD 0x00
+#define COMM_CMD 0x01
+#define MODE_CMD 0x02
+
+/* CONTROL COMMAND CODES */
+#define CTL_RESET_DEVICE 0x0000
+#define CTL_START_EXE 0x0001
+#define CTL_RESUME_EXE 0x0002
+#define CTL_HALT_EXE_IDLE 0x0003
+#define CTL_HALT_EXE_DONE 0x0004
+#define CTL_FLUSH_COMM_CMDS 0x0007
+#define CTL_FLUSH_RCV_BUFFER 0x0008
+#define CTL_FLUSH_XMT_BUFFER 0x0009
+#define CTL_GET_COMM_CMDS 0x000A
+
+/* MODE COMMAND CODES */
+#define MOD_PULSE_EN 0x0000
+#define MOD_SPEED_CHANGE_EN 0x0001
+#define MOD_1WIRE_SPEED 0x0002
+#define MOD_STRONG_PU_DURATION 0x0003
+#define MOD_PULLDOWN_SLEWRATE 0x0004
+#define MOD_PROG_PULSE_DURATION 0x0005
+#define MOD_WRITE1_LOWTIME 0x0006
+#define MOD_DSOW0_TREC 0x0007
+
+/* COMMUNICATION COMMAND CODES */
+#define COMM_ERROR_ESCAPE 0x0601
+#define COMM_SET_DURATION 0x0012
+#define COMM_BIT_IO 0x0020
+#define COMM_PULSE 0x0030
+#define COMM_1_WIRE_RESET 0x0042
+#define COMM_BYTE_IO 0x0052
+#define COMM_MATCH_ACCESS 0x0064
+#define COMM_BLOCK_IO 0x0074
+#define COMM_READ_STRAIGHT 0x0080
+#define COMM_DO_RELEASE 0x6092
+#define COMM_SET_PATH 0x00A2
+#define COMM_WRITE_SRAM_PAGE 0x00B2
+#define COMM_WRITE_EPROM 0x00C4
+#define COMM_READ_CRC_PROT_PAGE 0x00D4
+#define COMM_READ_REDIRECT_PAGE_CRC 0x21E4
+#define COMM_SEARCH_ACCESS 0x00F4
+
+/* Communication command bits */
+#define COMM_TYPE 0x0008
+#define COMM_SE 0x0008
+#define COMM_D 0x0008
+#define COMM_Z 0x0008
+#define COMM_CH 0x0008
+#define COMM_SM 0x0008
+#define COMM_R 0x0008
+#define COMM_IM 0x0001
+
+#define COMM_PS 0x4000
+#define COMM_PST 0x4000
+#define COMM_CIB 0x4000
+#define COMM_RTS 0x4000
+#define COMM_DT 0x2000
+#define COMM_SPU 0x1000
+#define COMM_F 0x0800
+#define COMM_NTP 0x0400
+#define COMM_ICP 0x0200
+#define COMM_RST 0x0100
+
+#define PULSE_PROG 0x01
+#define PULSE_SPUE 0x02
+
+#define BRANCH_MAIN 0xCC
+#define BRANCH_AUX 0x33
+
+/*
+ * Duration of the strong pull-up pulse in milliseconds.
+ */
+#define PULLUP_PULSE_DURATION 750
+
+/* Status flags */
+#define ST_SPUA 0x01 /* Strong Pull-up is active */
+#define ST_PRGA 0x02 /* 12V programming pulse is being generated */
+#define ST_12VP 0x04 /* external 12V programming voltage is present */
+#define ST_PMOD 0x08 /* DS2490 powered from USB and external sources */
+#define ST_HALT 0x10 /* DS2490 is currently halted */
+#define ST_IDLE 0x20 /* DS2490 is currently idle */
+#define ST_EPOF 0x80
+
+#define SPEED_NORMAL 0x00
+#define SPEED_FLEXIBLE 0x01
+#define SPEED_OVERDRIVE 0x02
+
+#define NUM_EP 4
+#define EP_CONTROL 0
+#define EP_STATUS 1
+#define EP_DATA_OUT 2
+#define EP_DATA_IN 3
+
+struct ds_device
+{
+ struct list_head ds_entry;
+
+ struct usb_device *udev;
+ struct usb_interface *intf;
+
+ int ep[NUM_EP];
+
+ struct w1_bus_master master;
+};
+
+struct ds_status
+{
+ u8 enable;
+ u8 speed;
+ u8 pullup_dur;
+ u8 ppuls_dur;
+ u8 pulldown_slew;
+ u8 write1_time;
+ u8 write0_time;
+ u8 reserved0;
+ u8 status;
+ u8 command0;
+ u8 command1;
+ u8 command_buffer_status;
+ u8 data_out_buffer_status;
+ u8 data_in_buffer_status;
+ u8 reserved1;
+ u8 reserved2;
+
+};
static struct usb_device_id ds_id_table [] = {
{ USB_DEVICE(0x04fa, 0x2490) },
@@ -35,21 +164,12 @@ MODULE_DEVICE_TABLE(usb, ds_id_table);
static int ds_probe(struct usb_interface *, const struct usb_device_id *);
static void ds_disconnect(struct usb_interface *);
-int ds_touch_bit(struct ds_device *, u8, u8 *);
-int ds_read_byte(struct ds_device *, u8 *);
-int ds_read_bit(struct ds_device *, u8 *);
-int ds_write_byte(struct ds_device *, u8);
-int ds_write_bit(struct ds_device *, u8);
-static int ds_start_pulse(struct ds_device *, int);
-int ds_reset(struct ds_device *, struct ds_status *);
-struct ds_device * ds_get_device(void);
-void ds_put_device(struct ds_device *);
-
static inline void ds_dump_status(unsigned char *, unsigned char *, int);
static int ds_send_control(struct ds_device *, u16, u16);
-static int ds_send_control_mode(struct ds_device *, u16, u16);
static int ds_send_control_cmd(struct ds_device *, u16, u16);
+static LIST_HEAD(ds_devices);
+static DEFINE_MUTEX(ds_mutex);
static struct usb_driver ds_driver = {
.name = "DS9490R",
@@ -58,20 +178,6 @@ static struct usb_driver ds_driver = {
.id_table = ds_id_table,
};
-static struct ds_device *ds_dev;
-
-struct ds_device * ds_get_device(void)
-{
- if (ds_dev)
- atomic_inc(&ds_dev->refcnt);
- return ds_dev;
-}
-
-void ds_put_device(struct ds_device *dev)
-{
- atomic_dec(&dev->refcnt);
-}
-
static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index)
{
int err;
@@ -86,7 +192,7 @@ static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index)
return err;
}
-
+#if 0
static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index)
{
int err;
@@ -101,7 +207,7 @@ static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index)
return err;
}
-
+#endif
static int ds_send_control(struct ds_device *dev, u16 value, u16 index)
{
int err;
@@ -324,7 +430,7 @@ static int ds_wait_status(struct ds_device *dev, struct ds_status *st)
return 0;
}
-int ds_reset(struct ds_device *dev, struct ds_status *st)
+static int ds_reset(struct ds_device *dev, struct ds_status *st)
{
int err;
@@ -345,7 +451,7 @@ int ds_reset(struct ds_device *dev, struct ds_status *st)
}
#if 0
-int ds_set_speed(struct ds_device *dev, int speed)
+static int ds_set_speed(struct ds_device *dev, int speed)
{
int err;
@@ -395,7 +501,7 @@ static int ds_start_pulse(struct ds_device *dev, int delay)
return err;
}
-int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit)
+static int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit)
{
int err, count;
struct ds_status st;
@@ -427,7 +533,7 @@ int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit)
return 0;
}
-int ds_write_bit(struct ds_device *dev, u8 bit)
+static int ds_write_bit(struct ds_device *dev, u8 bit)
{
int err;
struct ds_status st;
@@ -441,7 +547,7 @@ int ds_write_bit(struct ds_device *dev, u8 bit)
return 0;
}
-int ds_write_byte(struct ds_device *dev, u8 byte)
+static int ds_write_byte(struct ds_device *dev, u8 byte)
{
int err;
struct ds_status st;
@@ -464,26 +570,7 @@ int ds_write_byte(struct ds_device *dev, u8 byte)
return !(byte == rbyte);
}
-int ds_read_bit(struct ds_device *dev, u8 *bit)
-{
- int err;
-
- err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE);
- if (err)
- return err;
-
- err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | COMM_SPU | COMM_D, 0);
- if (err)
- return err;
-
- err = ds_recv_data(dev, bit, sizeof(*bit));
- if (err < 0)
- return err;
-
- return 0;
-}
-
-int ds_read_byte(struct ds_device *dev, u8 *byte)
+static int ds_read_byte(struct ds_device *dev, u8 *byte)
{
int err;
struct ds_status st;
@@ -501,7 +588,7 @@ int ds_read_byte(struct ds_device *dev, u8 *byte)
return 0;
}
-int ds_read_block(struct ds_device *dev, u8 *buf, int len)
+static int ds_read_block(struct ds_device *dev, u8 *buf, int len)
{
struct ds_status st;
int err;
@@ -527,7 +614,7 @@ int ds_read_block(struct ds_device *dev, u8 *buf, int len)
return err;
}
-int ds_write_block(struct ds_device *dev, u8 *buf, int len)
+static int ds_write_block(struct ds_device *dev, u8 *buf, int len)
{
int err;
struct ds_status st;
@@ -555,7 +642,7 @@ int ds_write_block(struct ds_device *dev, u8 *buf, int len)
#if 0
-int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int conditional_search)
+static int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int conditional_search)
{
int err;
u16 value, index;
@@ -584,7 +671,7 @@ int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int condi
return err/8;
}
-int ds_match_access(struct ds_device *dev, u64 init)
+static int ds_match_access(struct ds_device *dev, u64 init)
{
int err;
struct ds_status st;
@@ -604,7 +691,7 @@ int ds_match_access(struct ds_device *dev, u64 init)
return 0;
}
-int ds_set_path(struct ds_device *dev, u64 init)
+static int ds_set_path(struct ds_device *dev, u64 init)
{
int err;
struct ds_status st;
@@ -630,45 +717,156 @@ int ds_set_path(struct ds_device *dev, u64 init)
#endif /* 0 */
+static u8 ds9490r_touch_bit(void *data, u8 bit)
+{
+ u8 ret;
+ struct ds_device *dev = data;
+
+ if (ds_touch_bit(dev, bit, &ret))
+ return 0;
+
+ return ret;
+}
+
+static void ds9490r_write_bit(void *data, u8 bit)
+{
+ struct ds_device *dev = data;
+
+ ds_write_bit(dev, bit);
+}
+
+static void ds9490r_write_byte(void *data, u8 byte)
+{
+ struct ds_device *dev = data;
+
+ ds_write_byte(dev, byte);
+}
+
+static u8 ds9490r_read_bit(void *data)
+{
+ struct ds_device *dev = data;
+ int err;
+ u8 bit = 0;
+
+ err = ds_touch_bit(dev, 1, &bit);
+ if (err)
+ return 0;
+
+ return bit & 1;
+}
+
+static u8 ds9490r_read_byte(void *data)
+{
+ struct ds_device *dev = data;
+ int err;
+ u8 byte = 0;
+
+ err = ds_read_byte(dev, &byte);
+ if (err)
+ return 0;
+
+ return byte;
+}
+
+static void ds9490r_write_block(void *data, const u8 *buf, int len)
+{
+ struct ds_device *dev = data;
+
+ ds_write_block(dev, (u8 *)buf, len);
+}
+
+static u8 ds9490r_read_block(void *data, u8 *buf, int len)
+{
+ struct ds_device *dev = data;
+ int err;
+
+ err = ds_read_block(dev, buf, len);
+ if (err < 0)
+ return 0;
+
+ return len;
+}
+
+static u8 ds9490r_reset(void *data)
+{
+ struct ds_device *dev = data;
+ struct ds_status st;
+ int err;
+
+ memset(&st, 0, sizeof(st));
+
+ err = ds_reset(dev, &st);
+ if (err)
+ return 1;
+
+ return 0;
+}
+
+static int ds_w1_init(struct ds_device *dev)
+{
+ memset(&dev->master, 0, sizeof(struct w1_bus_master));
+
+ dev->master.data = dev;
+ dev->master.touch_bit = &ds9490r_touch_bit;
+ dev->master.read_bit = &ds9490r_read_bit;
+ dev->master.write_bit = &ds9490r_write_bit;
+ dev->master.read_byte = &ds9490r_read_byte;
+ dev->master.write_byte = &ds9490r_write_byte;
+ dev->master.read_block = &ds9490r_read_block;
+ dev->master.write_block = &ds9490r_write_block;
+ dev->master.reset_bus = &ds9490r_reset;
+
+ return w1_add_master_device(&dev->master);
+}
+
+static void ds_w1_fini(struct ds_device *dev)
+{
+ w1_remove_master_device(&dev->master);
+}
+
static int ds_probe(struct usb_interface *intf,
const struct usb_device_id *udev_id)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct usb_endpoint_descriptor *endpoint;
struct usb_host_interface *iface_desc;
+ struct ds_device *dev;
int i, err;
- ds_dev = kmalloc(sizeof(struct ds_device), GFP_KERNEL);
- if (!ds_dev) {
+ dev = kmalloc(sizeof(struct ds_device), GFP_KERNEL);
+ if (!dev) {
printk(KERN_INFO "Failed to allocate new DS9490R structure.\n");
return -ENOMEM;
}
+ dev->udev = usb_get_dev(udev);
+ if (!dev->udev) {
+ err = -ENOMEM;
+ goto err_out_free;
+ }
+ memset(dev->ep, 0, sizeof(dev->ep));
- ds_dev->udev = usb_get_dev(udev);
- usb_set_intfdata(intf, ds_dev);
+ usb_set_intfdata(intf, dev);
- err = usb_set_interface(ds_dev->udev, intf->altsetting[0].desc.bInterfaceNumber, 3);
+ err = usb_set_interface(dev->udev, intf->altsetting[0].desc.bInterfaceNumber, 3);
if (err) {
printk(KERN_ERR "Failed to set alternative setting 3 for %d interface: err=%d.\n",
intf->altsetting[0].desc.bInterfaceNumber, err);
- return err;
+ goto err_out_clear;
}
- err = usb_reset_configuration(ds_dev->udev);
+ err = usb_reset_configuration(dev->udev);
if (err) {
printk(KERN_ERR "Failed to reset configuration: err=%d.\n", err);
- return err;
+ goto err_out_clear;
}
iface_desc = &intf->altsetting[0];
if (iface_desc->desc.bNumEndpoints != NUM_EP-1) {
printk(KERN_INFO "Num endpoints=%d. It is not DS9490R.\n", iface_desc->desc.bNumEndpoints);
- return -ENODEV;
+ err = -EINVAL;
+ goto err_out_clear;
}
- atomic_set(&ds_dev->refcnt, 0);
- memset(ds_dev->ep, 0, sizeof(ds_dev->ep));
-
/*
* This loop doesn'd show control 0 endpoint,
* so we will fill only 1-3 endpoints entry.
@@ -676,54 +874,31 @@ static int ds_probe(struct usb_interface *intf,
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
- ds_dev->ep[i+1] = endpoint->bEndpointAddress;
-
+ dev->ep[i+1] = endpoint->bEndpointAddress;
+#if 0
printk("%d: addr=%x, size=%d, dir=%s, type=%x\n",
i, endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize),
(endpoint->bEndpointAddress & USB_DIR_IN)?"IN":"OUT",
endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+#endif
}
-#if 0
- {
- int err, i;
- u64 buf[3];
- u64 init=0xb30000002078ee81ull;
- struct ds_status st;
-
- ds_reset(ds_dev, &st);
- err = ds_search(ds_dev, init, buf, 3, 0);
- if (err < 0)
- return err;
- for (i=0; i<err; ++i)
- printk("%d: %llx\n", i, buf[i]);
-
- printk("Resetting...\n");
- ds_reset(ds_dev, &st);
- printk("Setting path for %llx.\n", init);
- err = ds_set_path(ds_dev, init);
- if (err)
- return err;
- printk("Calling MATCH_ACCESS.\n");
- err = ds_match_access(ds_dev, init);
- if (err)
- return err;
-
- printk("Searching the bus...\n");
- err = ds_search(ds_dev, init, buf, 3, 0);
-
- printk("ds_search() returned %d\n", err);
-
- if (err < 0)
- return err;
- for (i=0; i<err; ++i)
- printk("%d: %llx\n", i, buf[i]);
+ err = ds_w1_init(dev);
+ if (err)
+ goto err_out_clear;
- return 0;
- }
-#endif
+ mutex_lock(&ds_mutex);
+ list_add_tail(&dev->ds_entry, &ds_devices);
+ mutex_unlock(&ds_mutex);
return 0;
+
+err_out_clear:
+ usb_set_intfdata(intf, NULL);
+ usb_put_dev(dev->udev);
+err_out_free:
+ kfree(dev);
+ return err;
}
static void ds_disconnect(struct usb_interface *intf)
@@ -731,19 +906,19 @@ static void ds_disconnect(struct usb_interface *intf)
struct ds_device *dev;
dev = usb_get_intfdata(intf);
- usb_set_intfdata(intf, NULL);
+ if (!dev)
+ return;
- while (atomic_read(&dev->refcnt)) {
- printk(KERN_INFO "Waiting for DS to become free: refcnt=%d.\n",
- atomic_read(&dev->refcnt));
+ mutex_lock(&ds_mutex);
+ list_del(&dev->ds_entry);
+ mutex_unlock(&ds_mutex);
- if (msleep_interruptible(1000))
- flush_signals(current);
- }
+ ds_w1_fini(dev);
+
+ usb_set_intfdata(intf, NULL);
usb_put_dev(dev->udev);
kfree(dev);
- ds_dev = NULL;
}
static int ds_init(void)
@@ -769,27 +944,4 @@ module_exit(ds_fini);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
-
-EXPORT_SYMBOL(ds_touch_bit);
-EXPORT_SYMBOL(ds_read_byte);
-EXPORT_SYMBOL(ds_read_bit);
-EXPORT_SYMBOL(ds_read_block);
-EXPORT_SYMBOL(ds_write_byte);
-EXPORT_SYMBOL(ds_write_bit);
-EXPORT_SYMBOL(ds_write_block);
-EXPORT_SYMBOL(ds_reset);
-EXPORT_SYMBOL(ds_get_device);
-EXPORT_SYMBOL(ds_put_device);
-
-/*
- * This functions can be used for EEPROM programming,
- * when driver will be included into mainline this will
- * require uncommenting.
- */
-#if 0
-EXPORT_SYMBOL(ds_start_pulse);
-EXPORT_SYMBOL(ds_set_speed);
-EXPORT_SYMBOL(ds_detect);
-EXPORT_SYMBOL(ds_stop_pulse);
-EXPORT_SYMBOL(ds_search);
-#endif
+MODULE_DESCRIPTION("DS2490 USB <-> W1 bus master driver (DS9490*)");
diff --git a/drivers/w1/masters/ds_w1_bridge.c b/drivers/w1/masters/ds_w1_bridge.c
deleted file mode 100644
index 5d30783..0000000
--- a/drivers/w1/masters/ds_w1_bridge.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * ds_w1_bridge.c
- *
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-
-#include "../w1.h"
-#include "../w1_int.h"
-#include "dscore.h"
-
-static struct ds_device *ds_dev;
-static struct w1_bus_master *ds_bus_master;
-
-static u8 ds9490r_touch_bit(void *data, u8 bit)
-{
- u8 ret;
- struct ds_device *dev = data;
-
- if (ds_touch_bit(dev, bit, &ret))
- return 0;
-
- return ret;
-}
-
-static void ds9490r_write_bit(void *data, u8 bit)
-{
- struct ds_device *dev = data;
-
- ds_write_bit(dev, bit);
-}
-
-static void ds9490r_write_byte(void *data, u8 byte)
-{
- struct ds_device *dev = data;
-
- ds_write_byte(dev, byte);
-}
-
-static u8 ds9490r_read_bit(void *data)
-{
- struct ds_device *dev = data;
- int err;
- u8 bit = 0;
-
- err = ds_touch_bit(dev, 1, &bit);
- if (err)
- return 0;
- //err = ds_read_bit(dev, &bit);
- //if (err)
- // return 0;
-
- return bit & 1;
-}
-
-static u8 ds9490r_read_byte(void *data)
-{
- struct ds_device *dev = data;
- int err;
- u8 byte = 0;
-
- err = ds_read_byte(dev, &byte);
- if (err)
- return 0;
-
- return byte;
-}
-
-static void ds9490r_write_block(void *data, const u8 *buf, int len)
-{
- struct ds_device *dev = data;
-
- ds_write_block(dev, (u8 *)buf, len);
-}
-
-static u8 ds9490r_read_block(void *data, u8 *buf, int len)
-{
- struct ds_device *dev = data;
- int err;
-
- err = ds_read_block(dev, buf, len);
- if (err < 0)
- return 0;
-
- return len;
-}
-
-static u8 ds9490r_reset(void *data)
-{
- struct ds_device *dev = data;
- struct ds_status st;
- int err;
-
- memset(&st, 0, sizeof(st));
-
- err = ds_reset(dev, &st);
- if (err)
- return 1;
-
- return 0;
-}
-
-static int __devinit ds_w1_init(void)
-{
- int err;
-
- ds_bus_master = kmalloc(sizeof(*ds_bus_master), GFP_KERNEL);
- if (!ds_bus_master) {
- printk(KERN_ERR "Failed to allocate DS9490R USB<->W1 bus_master structure.\n");
- return -ENOMEM;
- }
-
- ds_dev = ds_get_device();
- if (!ds_dev) {
- printk(KERN_ERR "DS9490R is not registered.\n");
- err = -ENODEV;
- goto err_out_free_bus_master;
- }
-
- memset(ds_bus_master, 0, sizeof(*ds_bus_master));
-
- ds_bus_master->data = ds_dev;
- ds_bus_master->touch_bit = &ds9490r_touch_bit;
- ds_bus_master->read_bit = &ds9490r_read_bit;
- ds_bus_master->write_bit = &ds9490r_write_bit;
- ds_bus_master->read_byte = &ds9490r_read_byte;
- ds_bus_master->write_byte = &ds9490r_write_byte;
- ds_bus_master->read_block = &ds9490r_read_block;
- ds_bus_master->write_block = &ds9490r_write_block;
- ds_bus_master->reset_bus = &ds9490r_reset;
-
- err = w1_add_master_device(ds_bus_master);
- if (err)
- goto err_out_put_device;
-
- return 0;
-
-err_out_put_device:
- ds_put_device(ds_dev);
-err_out_free_bus_master:
- kfree(ds_bus_master);
-
- return err;
-}
-
-static void __devexit ds_w1_fini(void)
-{
- w1_remove_master_device(ds_bus_master);
- ds_put_device(ds_dev);
- kfree(ds_bus_master);
-}
-
-module_init(ds_w1_init);
-module_exit(ds_w1_fini);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
diff --git a/drivers/w1/masters/dscore.h b/drivers/w1/masters/dscore.h
deleted file mode 100644
index 6cf5671..0000000
--- a/drivers/w1/masters/dscore.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * dscore.h
- *
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
- *
- * 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 __DSCORE_H
-#define __DSCORE_H
-
-#include <linux/usb.h>
-#include <asm/atomic.h>
-
-/* COMMAND TYPE CODES */
-#define CONTROL_CMD 0x00
-#define COMM_CMD 0x01
-#define MODE_CMD 0x02
-
-/* CONTROL COMMAND CODES */
-#define CTL_RESET_DEVICE 0x0000
-#define CTL_START_EXE 0x0001
-#define CTL_RESUME_EXE 0x0002
-#define CTL_HALT_EXE_IDLE 0x0003
-#define CTL_HALT_EXE_DONE 0x0004
-#define CTL_FLUSH_COMM_CMDS 0x0007
-#define CTL_FLUSH_RCV_BUFFER 0x0008
-#define CTL_FLUSH_XMT_BUFFER 0x0009
-#define CTL_GET_COMM_CMDS 0x000A
-
-/* MODE COMMAND CODES */
-#define MOD_PULSE_EN 0x0000
-#define MOD_SPEED_CHANGE_EN 0x0001
-#define MOD_1WIRE_SPEED 0x0002
-#define MOD_STRONG_PU_DURATION 0x0003
-#define MOD_PULLDOWN_SLEWRATE 0x0004
-#define MOD_PROG_PULSE_DURATION 0x0005
-#define MOD_WRITE1_LOWTIME 0x0006
-#define MOD_DSOW0_TREC 0x0007
-
-/* COMMUNICATION COMMAND CODES */
-#define COMM_ERROR_ESCAPE 0x0601
-#define COMM_SET_DURATION 0x0012
-#define COMM_BIT_IO 0x0020
-#define COMM_PULSE 0x0030
-#define COMM_1_WIRE_RESET 0x0042
-#define COMM_BYTE_IO 0x0052
-#define COMM_MATCH_ACCESS 0x0064
-#define COMM_BLOCK_IO 0x0074
-#define COMM_READ_STRAIGHT 0x0080
-#define COMM_DO_RELEASE 0x6092
-#define COMM_SET_PATH 0x00A2
-#define COMM_WRITE_SRAM_PAGE 0x00B2
-#define COMM_WRITE_EPROM 0x00C4
-#define COMM_READ_CRC_PROT_PAGE 0x00D4
-#define COMM_READ_REDIRECT_PAGE_CRC 0x21E4
-#define COMM_SEARCH_ACCESS 0x00F4
-
-/* Communication command bits */
-#define COMM_TYPE 0x0008
-#define COMM_SE 0x0008
-#define COMM_D 0x0008
-#define COMM_Z 0x0008
-#define COMM_CH 0x0008
-#define COMM_SM 0x0008
-#define COMM_R 0x0008
-#define COMM_IM 0x0001
-
-#define COMM_PS 0x4000
-#define COMM_PST 0x4000
-#define COMM_CIB 0x4000
-#define COMM_RTS 0x4000
-#define COMM_DT 0x2000
-#define COMM_SPU 0x1000
-#define COMM_F 0x0800
-#define COMM_NTP 0x0400
-#define COMM_ICP 0x0200
-#define COMM_RST 0x0100
-
-#define PULSE_PROG 0x01
-#define PULSE_SPUE 0x02
-
-#define BRANCH_MAIN 0xCC
-#define BRANCH_AUX 0x33
-
-/*
- * Duration of the strong pull-up pulse in milliseconds.
- */
-#define PULLUP_PULSE_DURATION 750
-
-/* Status flags */
-#define ST_SPUA 0x01 /* Strong Pull-up is active */
-#define ST_PRGA 0x02 /* 12V programming pulse is being generated */
-#define ST_12VP 0x04 /* external 12V programming voltage is present */
-#define ST_PMOD 0x08 /* DS2490 powered from USB and external sources */
-#define ST_HALT 0x10 /* DS2490 is currently halted */
-#define ST_IDLE 0x20 /* DS2490 is currently idle */
-#define ST_EPOF 0x80
-
-#define SPEED_NORMAL 0x00
-#define SPEED_FLEXIBLE 0x01
-#define SPEED_OVERDRIVE 0x02
-
-#define NUM_EP 4
-#define EP_CONTROL 0
-#define EP_STATUS 1
-#define EP_DATA_OUT 2
-#define EP_DATA_IN 3
-
-struct ds_device
-{
- struct usb_device *udev;
- struct usb_interface *intf;
-
- int ep[NUM_EP];
-
- atomic_t refcnt;
-};
-
-struct ds_status
-{
- u8 enable;
- u8 speed;
- u8 pullup_dur;
- u8 ppuls_dur;
- u8 pulldown_slew;
- u8 write1_time;
- u8 write0_time;
- u8 reserved0;
- u8 status;
- u8 command0;
- u8 command1;
- u8 command_buffer_status;
- u8 data_out_buffer_status;
- u8 data_in_buffer_status;
- u8 reserved1;
- u8 reserved2;
-
-};
-
-int ds_touch_bit(struct ds_device *, u8, u8 *);
-int ds_read_byte(struct ds_device *, u8 *);
-int ds_read_bit(struct ds_device *, u8 *);
-int ds_write_byte(struct ds_device *, u8);
-int ds_write_bit(struct ds_device *, u8);
-int ds_reset(struct ds_device *, struct ds_status *);
-struct ds_device * ds_get_device(void);
-void ds_put_device(struct ds_device *);
-int ds_write_block(struct ds_device *, u8 *, int);
-int ds_read_block(struct ds_device *, u8 *, int);
-
-#endif /* __DSCORE_H */
-
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig
index f9d4c91..d18d642 100644
--- a/drivers/w1/slaves/Kconfig
+++ b/drivers/w1/slaves/Kconfig
@@ -28,7 +28,7 @@ config W1_SLAVE_DS2433
config W1_SLAVE_DS2433_CRC
bool "Protect DS2433 data with a CRC16"
- depends on W1_DS2433
+ depends on W1_SLAVE_DS2433
select CRC16
help
Say Y here to protect DS2433 data with a CRC16.
diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c
index fb118be..2ac238f 100644
--- a/drivers/w1/slaves/w1_ds2433.c
+++ b/drivers/w1/slaves/w1_ds2433.c
@@ -22,7 +22,6 @@
#endif
#include "../w1.h"
-#include "../w1_io.h"
#include "../w1_int.h"
#include "../w1_family.h"
@@ -106,11 +105,7 @@ static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off,
if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0)
return 0;
- atomic_inc(&sl->refcnt);
- if (down_interruptible(&sl->master->mutex)) {
- count = 0;
- goto out_dec;
- }
+ mutex_lock(&sl->master->mutex);
#ifdef CONFIG_W1_F23_CRC
@@ -141,9 +136,7 @@ static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off,
#endif /* CONFIG_W1_F23_CRC */
out_up:
- up(&sl->master->mutex);
-out_dec:
- atomic_dec(&sl->refcnt);
+ mutex_unlock(&sl->master->mutex);
return count;
}
@@ -232,11 +225,7 @@ static ssize_t w1_f23_write_bin(struct kobject *kobj, char *buf, loff_t off,
}
#endif /* CONFIG_W1_F23_CRC */
- atomic_inc(&sl->refcnt);
- if (down_interruptible(&sl->master->mutex)) {
- count = 0;
- goto out_dec;
- }
+ mutex_lock(&sl->master->mutex);
/* Can only write data to one page at a time */
idx = 0;
@@ -254,9 +243,7 @@ static ssize_t w1_f23_write_bin(struct kobject *kobj, char *buf, loff_t off,
}
out_up:
- up(&sl->master->mutex);
-out_dec:
- atomic_dec(&sl->refcnt);
+ mutex_unlock(&sl->master->mutex);
return count;
}
diff --git a/drivers/w1/slaves/w1_smem.c b/drivers/w1/slaves/w1_smem.c
index c6d3be5..cc8c02e 100644
--- a/drivers/w1/slaves/w1_smem.c
+++ b/drivers/w1/slaves/w1_smem.c
@@ -28,7 +28,6 @@
#include <linux/types.h>
#include "../w1.h"
-#include "../w1_io.h"
#include "../w1_int.h"
#include "../w1_family.h"
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
index 536d16d..5372cfc 100644
--- a/drivers/w1/slaves/w1_therm.c
+++ b/drivers/w1/slaves/w1_therm.c
@@ -29,7 +29,6 @@
#include <linux/delay.h>
#include "../w1.h"
-#include "../w1_io.h"
#include "../w1_int.h"
#include "../w1_family.h"
@@ -166,12 +165,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si
u8 rom[9], crc, verdict;
int i, max_trying = 10;
- atomic_inc(&sl->refcnt);
- smp_mb__after_atomic_inc();
- if (down_interruptible(&sl->master->mutex)) {
- count = 0;
- goto out_dec;
- }
+ mutex_lock(&sl->master->mutex);
if (off > W1_SLAVE_DATA_SIZE) {
count = 0;
@@ -234,10 +228,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si
count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom, sl->family->fid));
out:
- up(&dev->mutex);
-out_dec:
- smp_mb__before_atomic_inc();
- atomic_dec(&sl->refcnt);
+ mutex_unlock(&dev->mutex);
return count;
}
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index a698b51..de3e979 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -35,7 +35,6 @@
#include <asm/atomic.h>
#include "w1.h"
-#include "w1_io.h"
#include "w1_log.h"
#include "w1_int.h"
#include "w1_family.h"
@@ -55,7 +54,7 @@ module_param_named(control_timeout, w1_control_timeout, int, 0);
module_param_named(max_slave_count, w1_max_slave_count, int, 0);
module_param_named(slave_ttl, w1_max_slave_ttl, int, 0);
-DEFINE_SPINLOCK(w1_mlock);
+DEFINE_MUTEX(w1_mlock);
LIST_HEAD(w1_masters);
static struct task_struct *w1_control_thread;
@@ -75,8 +74,6 @@ static void w1_master_release(struct device *dev)
struct w1_master *md = dev_to_w1_master(dev);
dev_dbg(dev, "%s: Releasing %s.\n", __func__, md->name);
-
- dev_fini_netlink(md);
memset(md, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master));
kfree(md);
}
@@ -85,10 +82,10 @@ static void w1_slave_release(struct device *dev)
{
struct w1_slave *sl = dev_to_w1_slave(dev);
- dev_dbg(dev, "%s: Releasing %s.\n", __func__, sl->name);
+ printk("%s: Releasing %s.\n", __func__, sl->name);
while (atomic_read(&sl->refcnt)) {
- dev_dbg(dev, "Waiting for %s to become free: refcnt=%d.\n",
+ printk("Waiting for %s to become free: refcnt=%d.\n",
sl->name, atomic_read(&sl->refcnt));
if (msleep_interruptible(1000))
flush_signals(current);
@@ -111,7 +108,6 @@ static ssize_t w1_slave_read_id(struct kobject *kobj, char *buf, loff_t off, siz
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
- atomic_inc(&sl->refcnt);
if (off > 8) {
count = 0;
} else {
@@ -120,7 +116,6 @@ static ssize_t w1_slave_read_id(struct kobject *kobj, char *buf, loff_t off, siz
memcpy(buf, (u8 *)&sl->reg_num, count);
}
- atomic_dec(&sl->refcnt);
return count;
}
@@ -139,7 +134,63 @@ static struct bin_attribute w1_slave_attr_bin_id = {
};
/* Default family */
-static struct w1_family w1_default_family;
+
+static ssize_t w1_default_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+ struct w1_slave *sl = kobj_to_w1_slave(kobj);
+
+ mutex_lock(&sl->master->mutex);
+ if (w1_reset_select_slave(sl)) {
+ count = 0;
+ goto out_up;
+ }
+
+ w1_write_block(sl->master, buf, count);
+
+out_up:
+ mutex_unlock(&sl->master->mutex);
+ return count;
+}
+
+static ssize_t w1_default_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+ struct w1_slave *sl = kobj_to_w1_slave(kobj);
+
+ mutex_lock(&sl->master->mutex);
+ w1_read_block(sl->master, buf, count);
+ mutex_unlock(&sl->master->mutex);
+ return count;
+}
+
+static struct bin_attribute w1_default_attr = {
+ .attr = {
+ .name = "rw",
+ .mode = S_IRUGO | S_IWUSR,
+ .owner = THIS_MODULE,
+ },
+ .size = PAGE_SIZE,
+ .read = w1_default_read,
+ .write = w1_default_write,
+};
+
+static int w1_default_add_slave(struct w1_slave *sl)
+{
+ return sysfs_create_bin_file(&sl->dev.kobj, &w1_default_attr);
+}
+
+static void w1_default_remove_slave(struct w1_slave *sl)
+{
+ sysfs_remove_bin_file(&sl->dev.kobj, &w1_default_attr);
+}
+
+static struct w1_family_ops w1_default_fops = {
+ .add_slave = w1_default_add_slave,
+ .remove_slave = w1_default_remove_slave,
+};
+
+static struct w1_family w1_default_family = {
+ .fops = &w1_default_fops,
+};
static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
@@ -183,12 +234,9 @@ static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_a
struct w1_master *md = dev_to_w1_master(dev);
ssize_t count;
- if (down_interruptible (&md->mutex))
- return -EBUSY;
-
+ mutex_lock(&md->mutex);
count = sprintf(buf, "%s\n", md->name);
-
- up(&md->mutex);
+ mutex_unlock(&md->mutex);
return count;
}
@@ -199,12 +247,9 @@ static ssize_t w1_master_attribute_store_search(struct device * dev,
{
struct w1_master *md = dev_to_w1_master(dev);
- if (down_interruptible (&md->mutex))
- return -EBUSY;
-
+ mutex_lock(&md->mutex);
md->search_count = simple_strtol(buf, NULL, 0);
-
- up(&md->mutex);
+ mutex_unlock(&md->mutex);
return count;
}
@@ -216,12 +261,9 @@ static ssize_t w1_master_attribute_show_search(struct device *dev,
struct w1_master *md = dev_to_w1_master(dev);
ssize_t count;
- if (down_interruptible (&md->mutex))
- return -EBUSY;
-
+ mutex_lock(&md->mutex);
count = sprintf(buf, "%d\n", md->search_count);
-
- up(&md->mutex);
+ mutex_unlock(&md->mutex);
return count;
}
@@ -231,12 +273,9 @@ static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct devic
struct w1_master *md = dev_to_w1_master(dev);
ssize_t count;
- if (down_interruptible(&md->mutex))
- return -EBUSY;
-
+ mutex_lock(&md->mutex);
count = sprintf(buf, "0x%p\n", md->bus_master);
-
- up(&md->mutex);
+ mutex_unlock(&md->mutex);
return count;
}
@@ -252,12 +291,9 @@ static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, stru
struct w1_master *md = dev_to_w1_master(dev);
ssize_t count;
- if (down_interruptible(&md->mutex))
- return -EBUSY;
-
+ mutex_lock(&md->mutex);
count = sprintf(buf, "%d\n", md->max_slave_count);
-
- up(&md->mutex);
+ mutex_unlock(&md->mutex);
return count;
}
@@ -266,12 +302,9 @@ static ssize_t w1_master_attribute_show_attempts(struct device *dev, struct devi
struct w1_master *md = dev_to_w1_master(dev);
ssize_t count;
- if (down_interruptible(&md->mutex))
- return -EBUSY;
-
+ mutex_lock(&md->mutex);
count = sprintf(buf, "%lu\n", md->attempts);
-
- up(&md->mutex);
+ mutex_unlock(&md->mutex);
return count;
}
@@ -280,12 +313,9 @@ static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct d
struct w1_master *md = dev_to_w1_master(dev);
ssize_t count;
- if (down_interruptible(&md->mutex))
- return -EBUSY;
-
+ mutex_lock(&md->mutex);
count = sprintf(buf, "%d\n", md->slave_count);
-
- up(&md->mutex);
+ mutex_unlock(&md->mutex);
return count;
}
@@ -294,8 +324,7 @@ static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device
struct w1_master *md = dev_to_w1_master(dev);
int c = PAGE_SIZE;
- if (down_interruptible(&md->mutex))
- return -EBUSY;
+ mutex_lock(&md->mutex);
if (md->slave_count == 0)
c -= snprintf(buf + PAGE_SIZE - c, c, "not found.\n");
@@ -310,7 +339,7 @@ static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device
}
}
- up(&md->mutex);
+ mutex_unlock(&md->mutex);
return PAGE_SIZE - c;
}
@@ -362,7 +391,8 @@ static void w1_destroy_master_attributes(struct w1_master *master)
}
#ifdef CONFIG_HOTPLUG
-static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+static int w1_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
{
struct w1_master *md = NULL;
struct w1_slave *sl = NULL;
@@ -382,7 +412,8 @@ static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer
return -EINVAL;
}
- dev_dbg(dev, "Hotplug event for %s %s, bus_id=%s.\n", event_owner, name, dev->bus_id);
+ dev_dbg(dev, "Hotplug event for %s %s, bus_id=%s.\n",
+ event_owner, name, dev->bus_id);
if (dev->driver != &w1_slave_driver || !sl)
return 0;
@@ -401,7 +432,8 @@ static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer
return 0;
};
#else
-static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+static int w1_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
{
return 0;
}
@@ -425,7 +457,8 @@ static int __w1_attach_slave_device(struct w1_slave *sl)
(unsigned int) sl->reg_num.family,
(unsigned long long) sl->reg_num.id);
- dev_dbg(&sl->dev, "%s: registering %s as %p.\n", __func__, &sl->dev.bus_id[0]);
+ dev_dbg(&sl->dev, "%s: registering %s as %p.\n", __func__,
+ &sl->dev.bus_id[0]);
err = device_register(&sl->dev);
if (err < 0) {
@@ -496,6 +529,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
sl->master = dev;
set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
+ memset(&msg, 0, sizeof(msg));
memcpy(&sl->reg_num, rn, sizeof(sl->reg_num));
atomic_set(&sl->refcnt, 0);
init_completion(&sl->released);
@@ -526,7 +560,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
sl->ttl = dev->slave_ttl;
dev->slave_count++;
- memcpy(&msg.id.id, rn, sizeof(msg.id.id));
+ memcpy(msg.id.id, rn, sizeof(msg.id));
msg.type = W1_SLAVE_ADD;
w1_netlink_send(dev, &msg);
@@ -544,7 +578,8 @@ static void w1_slave_detach(struct w1_slave *sl)
if (sl->family->fops && sl->family->fops->remove_slave)
sl->family->fops->remove_slave(sl);
- memcpy(&msg.id.id, &sl->reg_num, sizeof(msg.id.id));
+ memset(&msg, 0, sizeof(msg));
+ memcpy(msg.id.id, &sl->reg_num, sizeof(msg.id));
msg.type = W1_SLAVE_REMOVE;
w1_netlink_send(sl->master, &msg);
@@ -561,7 +596,7 @@ static struct w1_master *w1_search_master(void *data)
struct w1_master *dev;
int found = 0;
- spin_lock_bh(&w1_mlock);
+ mutex_lock(&w1_mlock);
list_for_each_entry(dev, &w1_masters, w1_master_entry) {
if (dev->bus_master->data == data) {
found = 1;
@@ -569,22 +604,69 @@ static struct w1_master *w1_search_master(void *data)
break;
}
}
- spin_unlock_bh(&w1_mlock);
+ mutex_unlock(&w1_mlock);
+
+ return (found)?dev:NULL;
+}
+
+struct w1_master *w1_search_master_id(u32 id)
+{
+ struct w1_master *dev;
+ int found = 0;
+
+ mutex_lock(&w1_mlock);
+ list_for_each_entry(dev, &w1_masters, w1_master_entry) {
+ if (dev->id == id) {
+ found = 1;
+ atomic_inc(&dev->refcnt);
+ break;
+ }
+ }
+ mutex_unlock(&w1_mlock);
return (found)?dev:NULL;
}
+struct w1_slave *w1_search_slave(struct w1_reg_num *id)
+{
+ struct w1_master *dev;
+ struct w1_slave *sl = NULL;
+ int found = 0;
+
+ mutex_lock(&w1_mlock);
+ list_for_each_entry(dev, &w1_masters, w1_master_entry) {
+ mutex_lock(&dev->mutex);
+ list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
+ if (sl->reg_num.family == id->family &&
+ sl->reg_num.id == id->id &&
+ sl->reg_num.crc == id->crc) {
+ found = 1;
+ atomic_inc(&dev->refcnt);
+ atomic_inc(&sl->refcnt);
+ break;
+ }
+ }
+ mutex_unlock(&dev->mutex);
+
+ if (found)
+ break;
+ }
+ mutex_unlock(&w1_mlock);
+
+ return (found)?sl:NULL;
+}
+
void w1_reconnect_slaves(struct w1_family *f)
{
struct w1_master *dev;
- spin_lock_bh(&w1_mlock);
+ mutex_lock(&w1_mlock);
list_for_each_entry(dev, &w1_masters, w1_master_entry) {
dev_dbg(&dev->dev, "Reconnecting slaves in %s into new family %02x.\n",
dev->name, f->fid);
set_bit(W1_MASTER_NEED_RECONNECT, &dev->flags);
}
- spin_unlock_bh(&w1_mlock);
+ mutex_unlock(&w1_mlock);
}
static void w1_slave_found(void *data, u64 rn)
@@ -646,7 +728,7 @@ static void w1_slave_found(void *data, u64 rn)
* @dev The master device to search
* @cb Function to call when a device is found
*/
-void w1_search(struct w1_master *dev, w1_slave_found_callback cb)
+void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb)
{
u64 last_rn, rn, tmp64;
int i, slave_count = 0;
@@ -677,7 +759,7 @@ void w1_search(struct w1_master *dev, w1_slave_found_callback cb)
}
/* Start the search */
- w1_write_8(dev, W1_SEARCH);
+ w1_write_8(dev, search_type);
for (i = 0; i < 64; ++i) {
/* Determine the direction/search bit */
if (i == desc_bit)
@@ -739,23 +821,23 @@ static int w1_control(void *data)
if (kthread_should_stop() || test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) {
set_bit(W1_MASTER_NEED_EXIT, &dev->flags);
- spin_lock(&w1_mlock);
+ mutex_lock(&w1_mlock);
list_del(&dev->w1_master_entry);
- spin_unlock(&w1_mlock);
+ mutex_unlock(&w1_mlock);
- down(&dev->mutex);
+ mutex_lock(&dev->mutex);
list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
w1_slave_detach(sl);
}
w1_destroy_master_attributes(dev);
- up(&dev->mutex);
+ mutex_unlock(&dev->mutex);
atomic_dec(&dev->refcnt);
continue;
}
if (test_bit(W1_MASTER_NEED_RECONNECT, &dev->flags)) {
dev_dbg(&dev->dev, "Reconnecting slaves in device %s.\n", dev->name);
- down(&dev->mutex);
+ mutex_lock(&dev->mutex);
list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
if (sl->family->fid == W1_FAMILY_DEFAULT) {
struct w1_reg_num rn;
@@ -768,7 +850,7 @@ static int w1_control(void *data)
}
dev_dbg(&dev->dev, "Reconnecting slaves in device %s has been finished.\n", dev->name);
clear_bit(W1_MASTER_NEED_RECONNECT, &dev->flags);
- up(&dev->mutex);
+ mutex_unlock(&dev->mutex);
}
}
}
@@ -776,10 +858,31 @@ static int w1_control(void *data)
return 0;
}
+void w1_search_process(struct w1_master *dev, u8 search_type)
+{
+ struct w1_slave *sl, *sln;
+
+ list_for_each_entry(sl, &dev->slist, w1_slave_entry)
+ clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
+
+ w1_search_devices(dev, search_type, w1_slave_found);
+
+ list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
+ if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) {
+ w1_slave_detach(sl);
+
+ dev->slave_count--;
+ } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags))
+ sl->ttl = dev->slave_ttl;
+ }
+
+ if (dev->search_count > 0)
+ dev->search_count--;
+}
+
int w1_process(void *data)
{
struct w1_master *dev = (struct w1_master *) data;
- struct w1_slave *sl, *sln;
while (!kthread_should_stop() && !test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) {
try_to_freeze();
@@ -794,27 +897,9 @@ int w1_process(void *data)
if (dev->search_count == 0)
continue;
- if (down_interruptible(&dev->mutex))
- continue;
-
- list_for_each_entry(sl, &dev->slist, w1_slave_entry)
- clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
-
- w1_search_devices(dev, w1_slave_found);
-
- list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
- if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) {
- w1_slave_detach(sl);
-
- dev->slave_count--;
- } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags))
- sl->ttl = dev->slave_ttl;
- }
-
- if (dev->search_count > 0)
- dev->search_count--;
-
- up(&dev->mutex);
+ mutex_lock(&dev->mutex);
+ w1_search_process(dev, W1_SEARCH);
+ mutex_unlock(&dev->mutex);
}
atomic_dec(&dev->refcnt);
@@ -828,6 +913,8 @@ static int w1_init(void)
printk(KERN_INFO "Driver for 1-wire Dallas network protocol.\n");
+ w1_init_netlink();
+
retval = bus_register(&w1_bus_type);
if (retval) {
printk(KERN_ERR "Failed to register bus. err=%d.\n", retval);
@@ -880,6 +967,8 @@ static void w1_fini(void)
list_for_each_entry(dev, &w1_masters, w1_master_entry)
__w1_remove_master_device(dev);
+ w1_fini_netlink();
+
kthread_stop(w1_control_thread);
driver_unregister(&w1_slave_driver);
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h
index 5698050..f1df534 100644
--- a/drivers/w1/w1.h
+++ b/drivers/w1/w1.h
@@ -41,10 +41,7 @@ struct w1_reg_num
#include <linux/completion.h>
#include <linux/device.h>
-
-#include <net/sock.h>
-
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#include "w1_family.h"
@@ -52,7 +49,7 @@ struct w1_reg_num
#define W1_SLAVE_DATA_SIZE 128
#define W1_SEARCH 0xF0
-#define W1_CONDITIONAL_SEARCH 0xEC
+#define W1_ALARM_SEARCH 0xEC
#define W1_CONVERT_TEMP 0x44
#define W1_SKIP_ROM 0xCC
#define W1_READ_SCRATCHPAD 0xBE
@@ -60,7 +57,7 @@ struct w1_reg_num
#define W1_READ_PSUPPLY 0xB4
#define W1_MATCH_ROM 0x55
-#define W1_SLAVE_ACTIVE (1<<0)
+#define W1_SLAVE_ACTIVE 0
struct w1_slave
{
@@ -145,8 +142,8 @@ struct w1_bus_master
*/
u8 (*reset_bus)(void *);
- /** Really nice hardware can handles the ROM searches */
- void (*search)(void *, w1_slave_found_callback);
+ /** Really nice hardware can handles the different types of ROM search */
+ void (*search)(void *, u8, w1_slave_found_callback);
};
#define W1_MASTER_NEED_EXIT 0
@@ -173,19 +170,30 @@ struct w1_master
long flags;
struct task_struct *thread;
- struct semaphore mutex;
+ struct mutex mutex;
struct device_driver *driver;
struct device dev;
struct w1_bus_master *bus_master;
- u32 seq, groups;
- struct sock *nls;
+ u32 seq;
};
int w1_create_master_attributes(struct w1_master *);
-void w1_search(struct w1_master *dev, w1_slave_found_callback cb);
+void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb);
+void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb);
+struct w1_slave *w1_search_slave(struct w1_reg_num *id);
+void w1_search_process(struct w1_master *dev, u8 search_type);
+struct w1_master *w1_search_master_id(u32 id);
+
+u8 w1_triplet(struct w1_master *dev, int bdir);
+void w1_write_8(struct w1_master *, u8);
+int w1_reset_bus(struct w1_master *);
+u8 w1_calc_crc8(u8 *, int);
+void w1_write_block(struct w1_master *, const u8 *, int);
+u8 w1_read_block(struct w1_master *, u8 *, int);
+int w1_reset_select_slave(struct w1_slave *sl);
static inline struct w1_slave* dev_to_w1_slave(struct device *dev)
{
@@ -202,15 +210,14 @@ static inline struct w1_master* dev_to_w1_master(struct device *dev)
return container_of(dev, struct w1_master, dev);
}
+extern struct device_driver w1_master_driver;
+extern struct device w1_master_device;
extern int w1_max_slave_count;
extern int w1_max_slave_ttl;
-extern spinlock_t w1_mlock;
extern struct list_head w1_masters;
-extern struct device_driver w1_master_driver;
-extern struct device w1_master_device;
+extern struct mutex w1_mlock;
-int w1_process(void *data);
-void w1_reconnect_slaves(struct w1_family *f);
+extern int w1_process(void *);
#endif /* __KERNEL__ */
diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c
index 0e32c11..a3c95bd 100644
--- a/drivers/w1/w1_family.c
+++ b/drivers/w1/w1_family.c
@@ -107,6 +107,12 @@ struct w1_family * w1_family_registered(u8 fid)
return (ret) ? f : NULL;
}
+static void __w1_family_put(struct w1_family *f)
+{
+ if (atomic_dec_and_test(&f->refcnt))
+ f->need_exit = 1;
+}
+
void w1_family_put(struct w1_family *f)
{
spin_lock(&w1_flock);
@@ -114,19 +120,14 @@ void w1_family_put(struct w1_family *f)
spin_unlock(&w1_flock);
}
-void __w1_family_put(struct w1_family *f)
-{
- if (atomic_dec_and_test(&f->refcnt))
- f->need_exit = 1;
-}
-
+#if 0
void w1_family_get(struct w1_family *f)
{
spin_lock(&w1_flock);
__w1_family_get(f);
spin_unlock(&w1_flock);
-
}
+#endif /* 0 */
void __w1_family_get(struct w1_family *f)
{
@@ -135,8 +136,5 @@ void __w1_family_get(struct w1_family *f)
smp_mb__after_atomic_inc();
}
-EXPORT_SYMBOL(w1_family_get);
-EXPORT_SYMBOL(w1_family_put);
-EXPORT_SYMBOL(w1_family_registered);
EXPORT_SYMBOL(w1_unregister_family);
EXPORT_SYMBOL(w1_register_family);
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index 2ca0489..1e2ac40 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -57,12 +57,11 @@ struct w1_family
extern spinlock_t w1_flock;
-void w1_family_get(struct w1_family *);
void w1_family_put(struct w1_family *);
void __w1_family_get(struct w1_family *);
-void __w1_family_put(struct w1_family *);
struct w1_family * w1_family_registered(u8);
void w1_unregister_family(struct w1_family *);
int w1_register_family(struct w1_family *);
+void w1_reconnect_slaves(struct w1_family *f);
#endif /* __W1_FAMILY_H */
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index 68565aa..357a2e0 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -65,7 +65,7 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
atomic_set(&dev->refcnt, 2);
INIT_LIST_HEAD(&dev->slist);
- init_MUTEX(&dev->mutex);
+ mutex_init(&dev->mutex);
memcpy(&dev->dev, device, sizeof(struct device));
snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id),
@@ -74,16 +74,11 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
dev->driver = driver;
- dev->groups = 1;
dev->seq = 1;
- dev_init_netlink(dev);
err = device_register(&dev->dev);
if (err) {
printk(KERN_ERR "Failed to register master device. err=%d\n", err);
-
- dev_fini_netlink(dev);
-
memset(dev, 0, sizeof(struct w1_master));
kfree(dev);
dev = NULL;
@@ -131,12 +126,12 @@ int w1_add_master_device(struct w1_bus_master *master)
dev->initialized = 1;
- spin_lock(&w1_mlock);
+ mutex_lock(&w1_mlock);
list_add(&dev->w1_master_entry, &w1_masters);
- spin_unlock(&w1_mlock);
+ mutex_unlock(&w1_mlock);
+ memset(&msg, 0, sizeof(msg));
msg.id.mst.id = dev->id;
- msg.id.mst.pid = dev->thread->pid;
msg.type = W1_MASTER_ADD;
w1_netlink_send(dev, &msg);
@@ -153,7 +148,6 @@ err_out_free_dev:
void __w1_remove_master_device(struct w1_master *dev)
{
struct w1_netlink_msg msg;
- pid_t pid = dev->thread->pid;
set_bit(W1_MASTER_NEED_EXIT, &dev->flags);
kthread_stop(dev->thread);
@@ -166,8 +160,8 @@ void __w1_remove_master_device(struct w1_master *dev)
flush_signals(current);
}
+ memset(&msg, 0, sizeof(msg));
msg.id.mst.id = dev->id;
- msg.id.mst.pid = pid;
msg.type = W1_MASTER_REMOVE;
w1_netlink_send(dev, &msg);
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c
index f7f7e8b..30b6fbf 100644
--- a/drivers/w1/w1_io.c
+++ b/drivers/w1/w1_io.c
@@ -23,10 +23,10 @@
#include <linux/delay.h>
#include <linux/moduleparam.h>
+#include <linux/module.h>
#include "w1.h"
#include "w1_log.h"
-#include "w1_io.h"
static int w1_delay_parm = 1;
module_param_named(delay_coef, w1_delay_parm, int, 0);
@@ -50,7 +50,7 @@ static u8 w1_crc8_table[] = {
116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53
};
-void w1_delay(unsigned long tm)
+static void w1_delay(unsigned long tm)
{
udelay(tm * w1_delay_parm);
}
@@ -61,7 +61,7 @@ static u8 w1_read_bit(struct w1_master *dev);
/**
* Generates a write-0 or write-1 cycle and samples the level.
*/
-u8 w1_touch_bit(struct w1_master *dev, int bit)
+static u8 w1_touch_bit(struct w1_master *dev, int bit)
{
if (dev->bus_master->touch_bit)
return dev->bus_master->touch_bit(dev->bus_master->data, bit);
@@ -108,6 +108,7 @@ void w1_write_8(struct w1_master *dev, u8 byte)
for (i = 0; i < 8; ++i)
w1_touch_bit(dev, (byte >> i) & 0x1);
}
+EXPORT_SYMBOL_GPL(w1_write_8);
/**
@@ -176,7 +177,7 @@ u8 w1_triplet(struct w1_master *dev, int bdir)
* @param dev the master device
* @return the byte read
*/
-u8 w1_read_8(struct w1_master * dev)
+static u8 w1_read_8(struct w1_master * dev)
{
int i;
u8 res = 0;
@@ -208,6 +209,7 @@ void w1_write_block(struct w1_master *dev, const u8 *buf, int len)
for (i = 0; i < len; ++i)
w1_write_8(dev, buf[i]);
}
+EXPORT_SYMBOL_GPL(w1_write_block);
/**
* Reads a series of bytes.
@@ -232,6 +234,7 @@ u8 w1_read_block(struct w1_master *dev, u8 *buf, int len)
return ret;
}
+EXPORT_SYMBOL_GPL(w1_read_block);
/**
* Issues a reset bus sequence.
@@ -257,6 +260,7 @@ int w1_reset_bus(struct w1_master *dev)
return result;
}
+EXPORT_SYMBOL_GPL(w1_reset_bus);
u8 w1_calc_crc8(u8 * data, int len)
{
@@ -267,14 +271,15 @@ u8 w1_calc_crc8(u8 * data, int len)
return crc;
}
+EXPORT_SYMBOL_GPL(w1_calc_crc8);
-void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb)
+void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb)
{
dev->attempts++;
if (dev->bus_master->search)
- dev->bus_master->search(dev->bus_master->data, cb);
+ dev->bus_master->search(dev->bus_master->data, search_type, cb);
else
- w1_search(dev, cb);
+ w1_search(dev, search_type, cb);
}
/**
@@ -299,14 +304,4 @@ int w1_reset_select_slave(struct w1_slave *sl)
}
return 0;
}
-
-EXPORT_SYMBOL(w1_touch_bit);
-EXPORT_SYMBOL(w1_write_8);
-EXPORT_SYMBOL(w1_read_8);
-EXPORT_SYMBOL(w1_reset_bus);
-EXPORT_SYMBOL(w1_calc_crc8);
-EXPORT_SYMBOL(w1_delay);
-EXPORT_SYMBOL(w1_read_block);
-EXPORT_SYMBOL(w1_write_block);
-EXPORT_SYMBOL(w1_search_devices);
-EXPORT_SYMBOL(w1_reset_select_slave);
+EXPORT_SYMBOL_GPL(w1_reset_select_slave);
diff --git a/drivers/w1/w1_io.h b/drivers/w1/w1_io.h
index 2328601..9a76d2a 100644
--- a/drivers/w1/w1_io.h
+++ b/drivers/w1/w1_io.h
@@ -24,11 +24,8 @@
#include "w1.h"
-void w1_delay(unsigned long);
-u8 w1_touch_bit(struct w1_master *, int);
u8 w1_triplet(struct w1_master *dev, int bdir);
void w1_write_8(struct w1_master *, u8);
-u8 w1_read_8(struct w1_master *);
int w1_reset_bus(struct w1_master *);
u8 w1_calc_crc8(u8 *, int);
void w1_write_block(struct w1_master *, const u8 *, int);
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c
index 328645d..65c5ebd 100644
--- a/drivers/w1/w1_netlink.c
+++ b/drivers/w1/w1_netlink.c
@@ -21,72 +21,225 @@
#include <linux/skbuff.h>
#include <linux/netlink.h>
+#include <linux/connector.h>
#include "w1.h"
#include "w1_log.h"
#include "w1_netlink.h"
-#ifndef NETLINK_DISABLED
+#if defined(CONFIG_W1_CON) && (defined(CONFIG_CONNECTOR) || (defined(CONFIG_CONNECTOR_MODULE) && defined(CONFIG_W1_MODULE)))
void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
{
- unsigned int size;
- struct sk_buff *skb;
- struct w1_netlink_msg *data;
- struct nlmsghdr *nlh;
+ char buf[sizeof(struct cn_msg) + sizeof(struct w1_netlink_msg)];
+ struct cn_msg *m = (struct cn_msg *)buf;
+ struct w1_netlink_msg *w = (struct w1_netlink_msg *)(m+1);
- if (!dev->nls)
- return;
+ memset(buf, 0, sizeof(buf));
- size = NLMSG_SPACE(sizeof(struct w1_netlink_msg));
+ m->id.idx = CN_W1_IDX;
+ m->id.val = CN_W1_VAL;
- skb = alloc_skb(size, GFP_ATOMIC);
- if (!skb) {
- dev_err(&dev->dev, "skb_alloc() failed.\n");
- return;
- }
+ m->seq = dev->seq++;
+ m->len = sizeof(struct w1_netlink_msg);
+
+ memcpy(w, msg, sizeof(struct w1_netlink_msg));
+
+ cn_netlink_send(m, 0, GFP_KERNEL);
+}
+
+static int w1_process_command_master(struct w1_master *dev, struct cn_msg *msg,
+ struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd)
+{
+ dev_dbg(&dev->dev, "%s: %s: cmd=%02x, len=%u.\n",
+ __func__, dev->name, cmd->cmd, cmd->len);
+
+ if (cmd->cmd != W1_CMD_SEARCH && cmd->cmd != W1_CMD_ALARM_SEARCH)
+ return -EINVAL;
+
+ w1_search_process(dev, (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH);
+ return 0;
+}
+
+static int w1_send_read_reply(struct w1_slave *sl, struct cn_msg *msg,
+ struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd)
+{
+ void *data;
+ struct w1_netlink_msg *h;
+ struct w1_netlink_cmd *c;
+ struct cn_msg *cm;
+ int err;
+
+ data = kzalloc(sizeof(struct cn_msg) +
+ sizeof(struct w1_netlink_msg) +
+ sizeof(struct w1_netlink_cmd) +
+ cmd->len, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ cm = (struct cn_msg *)(data);
+ h = (struct w1_netlink_msg *)(cm + 1);
+ c = (struct w1_netlink_cmd *)(h + 1);
+
+ memcpy(cm, msg, sizeof(struct cn_msg));
+ memcpy(h, hdr, sizeof(struct w1_netlink_msg));
+ memcpy(c, cmd, sizeof(struct w1_netlink_cmd));
- nlh = NLMSG_PUT(skb, 0, dev->seq++, NLMSG_DONE, size - sizeof(*nlh));
+ cm->ack = msg->seq+1;
+ cm->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd) + cmd->len;
- data = (struct w1_netlink_msg *)NLMSG_DATA(nlh);
+ h->len = sizeof(struct w1_netlink_cmd) + cmd->len;
- memcpy(data, msg, sizeof(struct w1_netlink_msg));
+ memcpy(c->data, cmd->data, c->len);
- NETLINK_CB(skb).dst_group = dev->groups;
- netlink_broadcast(dev->nls, skb, 0, dev->groups, GFP_ATOMIC);
+ err = cn_netlink_send(cm, 0, GFP_KERNEL);
-nlmsg_failure:
- return;
+ kfree(data);
+
+ return err;
}
-int dev_init_netlink(struct w1_master *dev)
+static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg,
+ struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd)
{
- dev->nls = netlink_kernel_create(NETLINK_W1, 1, NULL, THIS_MODULE);
- if (!dev->nls) {
- printk(KERN_ERR "Failed to create new netlink socket(%u) for w1 master %s.\n",
- NETLINK_W1, dev->dev.bus_id);
+ int err = 0;
+
+ dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n",
+ __func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id, sl->reg_num.crc,
+ cmd->cmd, cmd->len);
+
+ switch (cmd->cmd) {
+ case W1_CMD_READ:
+ w1_read_block(sl->master, cmd->data, cmd->len);
+ w1_send_read_reply(sl, msg, hdr, cmd);
+ break;
+ case W1_CMD_WRITE:
+ w1_write_block(sl->master, cmd->data, cmd->len);
+ break;
+ case W1_CMD_SEARCH:
+ case W1_CMD_ALARM_SEARCH:
+ w1_search_process(sl->master,
+ (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH);
+ break;
+ default:
+ err = -1;
+ break;
}
- return 0;
+ return err;
}
-void dev_fini_netlink(struct w1_master *dev)
+static void w1_cn_callback(void *data)
{
- if (dev->nls && dev->nls->sk_socket)
- sock_release(dev->nls->sk_socket);
+ struct cn_msg *msg = data;
+ struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1);
+ struct w1_netlink_cmd *cmd;
+ struct w1_slave *sl;
+ struct w1_master *dev;
+ int err = 0;
+
+ while (msg->len && !err) {
+ struct w1_reg_num id;
+ u16 mlen = m->len;
+ u8 *cmd_data = m->data;
+
+ dev = NULL;
+ sl = NULL;
+
+ memcpy(&id, m->id.id, sizeof(id));
+#if 0
+ printk("%s: %02x.%012llx.%02x: type=%02x, len=%u.\n",
+ __func__, id.family, (unsigned long long)id.id, id.crc, m->type, m->len);
+#endif
+ if (m->len + sizeof(struct w1_netlink_msg) > msg->len) {
+ err = -E2BIG;
+ break;
+ }
+
+ if (!mlen)
+ goto out_cont;
+
+ if (m->type == W1_MASTER_CMD) {
+ dev = w1_search_master_id(m->id.mst.id);
+ } else if (m->type == W1_SLAVE_CMD) {
+ sl = w1_search_slave(&id);
+ if (sl)
+ dev = sl->master;
+ }
+
+ if (!dev) {
+ err = -ENODEV;
+ goto out_cont;
+ }
+
+ mutex_lock(&dev->mutex);
+
+ if (sl && w1_reset_select_slave(sl)) {
+ err = -ENODEV;
+ goto out_up;
+ }
+
+ while (mlen) {
+ cmd = (struct w1_netlink_cmd *)cmd_data;
+
+ if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) {
+ err = -E2BIG;
+ break;
+ }
+
+ if (sl)
+ w1_process_command_slave(sl, msg, m, cmd);
+ else
+ w1_process_command_master(dev, msg, m, cmd);
+
+ cmd_data += cmd->len + sizeof(struct w1_netlink_cmd);
+ mlen -= cmd->len + sizeof(struct w1_netlink_cmd);
+ }
+out_up:
+ atomic_dec(&dev->refcnt);
+ if (sl)
+ atomic_dec(&sl->refcnt);
+ mutex_unlock(&dev->mutex);
+out_cont:
+ msg->len -= sizeof(struct w1_netlink_msg) + m->len;
+ m = (struct w1_netlink_msg *)(((u8 *)m) + sizeof(struct w1_netlink_msg) + m->len);
+
+ /*
+ * Let's allow requests for nonexisting devices.
+ */
+ if (err == -ENODEV)
+ err = 0;
+ }
+#if 0
+ if (err) {
+ printk("%s: malformed message. Dropping.\n", __func__);
+ }
+#endif
}
-#else
-#warning Netlink support is disabled. Please compile with NET support enabled.
+int w1_init_netlink(void)
+{
+ struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL};
+
+ return cn_add_callback(&w1_id, "w1", &w1_cn_callback);
+}
+
+void w1_fini_netlink(void)
+{
+ struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL};
+
+ cn_del_callback(&w1_id);
+}
+#else
void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
{
}
-int dev_init_netlink(struct w1_master *dev)
+int w1_init_netlink(void)
{
return 0;
}
-void dev_fini_netlink(struct w1_master *dev)
+void w1_fini_netlink(void)
{
}
#endif
diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h
index eb0c8b3..56122b9 100644
--- a/drivers/w1/w1_netlink.h
+++ b/drivers/w1/w1_netlink.h
@@ -23,6 +23,7 @@
#define __W1_NETLINK_H
#include <asm/types.h>
+#include <linux/connector.h>
#include "w1.h"
@@ -31,29 +32,43 @@ enum w1_netlink_message_types {
W1_SLAVE_REMOVE,
W1_MASTER_ADD,
W1_MASTER_REMOVE,
+ W1_MASTER_CMD,
+ W1_SLAVE_CMD,
};
struct w1_netlink_msg
{
__u8 type;
- __u8 reserved[3];
- union
- {
- struct w1_reg_num id;
- __u64 w1_id;
- struct
- {
+ __u8 reserved;
+ __u16 len;
+ union {
+ __u8 id[8];
+ struct w1_mst {
__u32 id;
- __u32 pid;
+ __u32 res;
} mst;
} id;
+ __u8 data[0];
+};
+
+#define W1_CMD_READ 0x0
+#define W1_CMD_WRITE 0x1
+#define W1_CMD_SEARCH 0x2
+#define W1_CMD_ALARM_SEARCH 0x3
+
+struct w1_netlink_cmd
+{
+ __u8 cmd;
+ __u8 res;
+ __u16 len;
+ __u8 data[0];
};
#ifdef __KERNEL__
void w1_netlink_send(struct w1_master *, struct w1_netlink_msg *);
-int dev_init_netlink(struct w1_master *dev);
-void dev_fini_netlink(struct w1_master *dev);
+int w1_init_netlink(void);
+void w1_fini_netlink(void);
#endif /* __KERNEL__ */
#endif /* __W1_NETLINK_H */
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 2cb87ba..5c6bdf8 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -530,9 +530,6 @@ error:
if (vfid)
v9fs_fid_destroy(vfid);
- if (inode)
- iput(inode);
-
return err;
}
@@ -1054,6 +1051,9 @@ static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer,
int ret;
char *link = __getname();
+ if (unlikely(!link))
+ return -ENOMEM;
+
if (buflen > PATH_MAX)
buflen = PATH_MAX;
@@ -1171,9 +1171,6 @@ error:
if (vfid)
v9fs_fid_destroy(vfid);
- if (inode)
- iput(inode);
-
return err;
}
@@ -1227,6 +1224,9 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
}
name = __getname();
+ if (unlikely(!name))
+ return -ENOMEM;
+
sprintf(name, "%d\n", oldfid->fid);
retval = v9fs_vfs_mkspecial(dir, dentry, V9FS_DMLINK, name);
__putname(name);
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 61c599b..8b15bb2 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -99,12 +99,13 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
* @flags: mount flags
* @dev_name: device name that was mounted
* @data: mount options
+ * @mnt: mountpoint record to be instantiated
*
*/
-static struct super_block *v9fs_get_sb(struct file_system_type
- *fs_type, int flags,
- const char *dev_name, void *data)
+static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data,
+ struct vfsmount *mnt)
{
struct super_block *sb = NULL;
struct v9fs_fcall *fcall = NULL;
@@ -123,17 +124,19 @@ static struct super_block *v9fs_get_sb(struct file_system_type
v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
if (!v9ses)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) {
dprintk(DEBUG_ERROR, "problem initiating session\n");
- sb = ERR_PTR(newfid);
+ retval = newfid;
goto out_free_session;
}
sb = sget(fs_type, NULL, v9fs_set_super, v9ses);
- if (IS_ERR(sb))
+ if (IS_ERR(sb)) {
+ retval = PTR_ERR(sb);
goto out_close_session;
+ }
v9fs_fill_super(sb, v9ses, flags);
inode = v9fs_get_inode(sb, S_IFDIR | mode);
@@ -184,19 +187,19 @@ static struct super_block *v9fs_get_sb(struct file_system_type
goto put_back_sb;
}
- return sb;
+ return simple_set_mnt(mnt, sb);
out_close_session:
v9fs_session_close(v9ses);
out_free_session:
kfree(v9ses);
- return sb;
+ return retval;
put_back_sb:
/* deactivate_super calls v9fs_kill_super which will frees the rest */
up_write(&sb->s_umount);
deactivate_super(sb);
- return ERR_PTR(retval);
+ return retval;
}
/**
@@ -253,11 +256,12 @@ static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt)
}
static void
-v9fs_umount_begin(struct super_block *sb)
+v9fs_umount_begin(struct vfsmount *vfsmnt, int flags)
{
- struct v9fs_session_info *v9ses = sb->s_fs_info;
+ struct v9fs_session_info *v9ses = vfsmnt->mnt_sb->s_fs_info;
- v9fs_session_cancel(v9ses);
+ if (flags & MNT_FORCE)
+ v9fs_session_cancel(v9ses);
}
static struct super_operations v9fs_super_ops = {
diff --git a/fs/Kconfig b/fs/Kconfig
index 20f9b55..1cdc043 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -53,7 +53,7 @@ config EXT2_FS_SECURITY
config EXT2_FS_XIP
bool "Ext2 execute in place support"
- depends on EXT2_FS
+ depends on EXT2_FS && MMU
help
Execute in place can be used on memory-backed block devices. If you
enable this option, you can select to mount block devices which are
@@ -776,7 +776,8 @@ endmenu
menu "Pseudo filesystems"
config PROC_FS
- bool "/proc file system support"
+ bool "/proc file system support" if EMBEDDED
+ default y
help
This is a virtual file system providing information about the status
of the system. "Virtual" means that it doesn't take up any space on
@@ -1370,11 +1371,19 @@ config UFS_FS
config UFS_FS_WRITE
bool "UFS file system write support (DANGEROUS)"
- depends on UFS_FS && EXPERIMENTAL && BROKEN
+ depends on UFS_FS && EXPERIMENTAL
help
Say Y here if you want to try writing to UFS partitions. This is
experimental, so you should back up your UFS partitions beforehand.
+config UFS_DEBUG
+ bool "UFS debugging"
+ depends on UFS_FS
+ help
+ If you are experiencing any problems with the UFS filesystem, say
+ Y here. This will result in _many_ additional debugging messages to be
+ written to the system log.
+
endmenu
menu "Network File Systems"
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 252abda..ba1c88a 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -196,17 +196,17 @@ static int adfs_remount(struct super_block *sb, int *flags, char *data)
return parse_options(sb, data);
}
-static int adfs_statfs(struct super_block *sb, struct kstatfs *buf)
+static int adfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
- struct adfs_sb_info *asb = ADFS_SB(sb);
+ struct adfs_sb_info *asb = ADFS_SB(dentry->d_sb);
buf->f_type = ADFS_SUPER_MAGIC;
buf->f_namelen = asb->s_namelen;
- buf->f_bsize = sb->s_blocksize;
+ buf->f_bsize = dentry->d_sb->s_blocksize;
buf->f_blocks = asb->s_size;
buf->f_files = asb->s_ids_per_zone * asb->s_map_size;
buf->f_bavail =
- buf->f_bfree = adfs_map_free(sb);
+ buf->f_bfree = adfs_map_free(dentry->d_sb);
buf->f_ffree = (long)(buf->f_bfree * buf->f_files) / (long)buf->f_blocks;
return 0;
@@ -470,10 +470,11 @@ error:
return -EINVAL;
}
-static struct super_block *adfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int adfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, adfs_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, adfs_fill_super,
+ mnt);
}
static struct file_system_type adfs_fs_type = {
diff --git a/fs/affs/super.c b/fs/affs/super.c
index 4d7e5b1..5200f49 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -18,7 +18,7 @@
extern struct timezone sys_tz;
-static int affs_statfs(struct super_block *sb, struct kstatfs *buf);
+static int affs_statfs(struct dentry *dentry, struct kstatfs *buf);
static int affs_remount (struct super_block *sb, int *flags, char *data);
static void
@@ -271,6 +271,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
int reserved;
unsigned long mount_flags;
int tmp_flags; /* fix remount prototype... */
+ u8 sig[4];
pr_debug("AFFS: read_super(%s)\n",data ? (const char *)data : "no options");
@@ -370,8 +371,9 @@ got_root:
printk(KERN_ERR "AFFS: Cannot read boot block\n");
goto out_error;
}
- chksum = be32_to_cpu(*(__be32 *)boot_bh->b_data);
+ memcpy(sig, boot_bh->b_data, 4);
brelse(boot_bh);
+ chksum = be32_to_cpu(*(__be32 *)sig);
/* Dircache filesystems are compatible with non-dircache ones
* when reading. As long as they aren't supported, writing is
@@ -420,11 +422,11 @@ got_root:
}
if (mount_flags & SF_VERBOSE) {
- chksum = cpu_to_be32(chksum);
- printk(KERN_NOTICE "AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n",
- AFFS_ROOT_TAIL(sb, root_bh)->disk_name[0],
+ u8 len = AFFS_ROOT_TAIL(sb, root_bh)->disk_name[0];
+ printk(KERN_NOTICE "AFFS: Mounting volume \"%.*s\": Type=%.3s\\%c, Blocksize=%d\n",
+ len > 31 ? 31 : len,
AFFS_ROOT_TAIL(sb, root_bh)->disk_name + 1,
- (char *)&chksum,((char *)&chksum)[3] + '0',blocksize);
+ sig, sig[3] + '0', blocksize);
}
sb->s_flags |= MS_NODEV | MS_NOSUID;
@@ -508,8 +510,9 @@ affs_remount(struct super_block *sb, int *flags, char *data)
}
static int
-affs_statfs(struct super_block *sb, struct kstatfs *buf)
+affs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
+ struct super_block *sb = dentry->d_sb;
int free;
pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n",AFFS_SB(sb)->s_partition_size,
@@ -524,10 +527,11 @@ affs_statfs(struct super_block *sb, struct kstatfs *buf)
return 0;
}
-static struct super_block *affs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int affs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, affs_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, affs_fill_super,
+ mnt);
}
static struct file_system_type affs_fs_type = {
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index a6dff6a..2fc9987 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -185,9 +185,7 @@ static struct page *afs_dir_get_page(struct inode *dir, unsigned long index)
_enter("{%lu},%lu", dir->i_ino, index);
- page = read_cache_page(dir->i_mapping,index,
- (filler_t *) dir->i_mapping->a_ops->readpage,
- NULL);
+ page = read_mapping_page(dir->i_mapping, index, NULL);
if (!IS_ERR(page)) {
wait_on_page_locked(page);
kmap(page);
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index 4e6eeb5..99785a7 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -63,7 +63,6 @@ unsigned long afs_mntpt_expiry_timeout = 20;
int afs_mntpt_check_symlink(struct afs_vnode *vnode)
{
struct page *page;
- filler_t *filler;
size_t size;
char *buf;
int ret;
@@ -71,10 +70,7 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode)
_enter("{%u,%u}", vnode->fid.vnode, vnode->fid.unique);
/* read the contents of the symlink into the pagecache */
- filler = (filler_t *) AFS_VNODE_TO_I(vnode)->i_mapping->a_ops->readpage;
-
- page = read_cache_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0,
- filler, NULL);
+ page = read_mapping_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0, NULL);
if (IS_ERR(page)) {
ret = PTR_ERR(page);
goto out;
@@ -160,7 +156,6 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
struct page *page = NULL;
size_t size;
char *buf, *devname = NULL, *options = NULL;
- filler_t *filler;
int ret;
kenter("{%s}", mntpt->d_name.name);
@@ -182,9 +177,7 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
goto error;
/* read the contents of the AFS special symlink */
- filler = (filler_t *)mntpt->d_inode->i_mapping->a_ops->readpage;
-
- page = read_cache_page(mntpt->d_inode->i_mapping, 0, filler, NULL);
+ page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL);
if (IS_ERR(page)) {
ret = PTR_ERR(page);
goto error;
@@ -210,7 +203,7 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
/* try and do the mount */
kdebug("--- attempting mount %s -o %s ---", devname, options);
- mnt = do_kern_mount("afs", 0, devname, options);
+ mnt = vfs_kern_mount(&afs_fs_type, 0, devname, options);
kdebug("--- mount result %p ---", mnt);
free_page((unsigned long) devname);
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 53c56e7..67d1f5c 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -38,9 +38,9 @@ struct afs_mount_params {
static void afs_i_init_once(void *foo, kmem_cache_t *cachep,
unsigned long flags);
-static struct super_block *afs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data);
+static int afs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data, struct vfsmount *mnt);
static struct inode *afs_alloc_inode(struct super_block *sb);
@@ -48,7 +48,7 @@ static void afs_put_super(struct super_block *sb);
static void afs_destroy_inode(struct inode *inode);
-static struct file_system_type afs_fs_type = {
+struct file_system_type afs_fs_type = {
.owner = THIS_MODULE,
.name = "afs",
.get_sb = afs_get_sb,
@@ -294,10 +294,11 @@ static int afs_fill_super(struct super_block *sb, void *data, int silent)
* get an AFS superblock
* - TODO: don't use get_sb_nodev(), but rather call sget() directly
*/
-static struct super_block *afs_get_sb(struct file_system_type *fs_type,
- int flags,
- const char *dev_name,
- void *options)
+static int afs_get_sb(struct file_system_type *fs_type,
+ int flags,
+ const char *dev_name,
+ void *options,
+ struct vfsmount *mnt)
{
struct afs_mount_params params;
struct super_block *sb;
@@ -311,7 +312,7 @@ static struct super_block *afs_get_sb(struct file_system_type *fs_type,
ret = afscm_start();
if (ret < 0) {
_leave(" = %d", ret);
- return ERR_PTR(ret);
+ return ret;
}
/* parse the options */
@@ -348,18 +349,19 @@ static struct super_block *afs_get_sb(struct file_system_type *fs_type,
goto error;
}
sb->s_flags |= MS_ACTIVE;
+ simple_set_mnt(mnt, sb);
afs_put_volume(params.volume);
afs_put_cell(params.default_cell);
- _leave(" = %p", sb);
- return sb;
+ _leave(" = 0 [%p]", 0, sb);
+ return 0;
error:
afs_put_volume(params.volume);
afs_put_cell(params.default_cell);
afscm_stop();
_leave(" = %d", ret);
- return ERR_PTR(ret);
+ return ret;
} /* end afs_get_sb() */
/*****************************************************************************/
diff --git a/fs/afs/super.h b/fs/afs/super.h
index ac11362..32de8cc 100644
--- a/fs/afs/super.h
+++ b/fs/afs/super.h
@@ -38,6 +38,8 @@ static inline struct afs_super_info *AFS_FS_S(struct super_block *sb)
return sb->s_fs_info;
}
+extern struct file_system_type afs_fs_type;
+
#endif /* __KERNEL__ */
#endif /* _LINUX_AFS_SUPER_H */
diff --git a/fs/aio.c b/fs/aio.c
index e41e932..8c34a62 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -777,11 +777,11 @@ out:
static int __aio_run_iocbs(struct kioctx *ctx)
{
struct kiocb *iocb;
- LIST_HEAD(run_list);
+ struct list_head run_list;
assert_spin_locked(&ctx->ctx_lock);
- list_splice_init(&ctx->run_list, &run_list);
+ list_replace_init(&ctx->run_list, &run_list);
while (!list_empty(&run_list)) {
iocb = list_entry(run_list.next, struct kiocb,
ki_run_list);
diff --git a/fs/autofs/init.c b/fs/autofs/init.c
index b977ece..aca1237 100644
--- a/fs/autofs/init.c
+++ b/fs/autofs/init.c
@@ -14,10 +14,10 @@
#include <linux/init.h>
#include "autofs_i.h"
-static struct super_block *autofs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int autofs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_nodev(fs_type, flags, data, autofs_fill_super);
+ return get_sb_nodev(fs_type, flags, data, autofs_fill_super, mnt);
}
static struct file_system_type autofs_fs_type = {
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index b8ce026..4456d1d 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -174,6 +174,12 @@ static int autofs4_tree_busy(struct vfsmount *mnt,
struct autofs_info *ino = autofs4_dentry_ino(p);
unsigned int ino_count = atomic_read(&ino->count);
+ /*
+ * Clean stale dentries below that have not been
+ * invalidated after a mount fail during lookup
+ */
+ d_invalidate(p);
+
/* allow for dget above and top is already dgot */
if (p == top)
ino_count += 2;
diff --git a/fs/autofs4/init.c b/fs/autofs4/init.c
index acecec8..5d91933 100644
--- a/fs/autofs4/init.c
+++ b/fs/autofs4/init.c
@@ -14,10 +14,10 @@
#include <linux/init.h>
#include "autofs_i.h"
-static struct super_block *autofs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int autofs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_nodev(fs_type, flags, data, autofs4_fill_super);
+ return get_sb_nodev(fs_type, flags, data, autofs4_fill_super, mnt);
}
static struct file_system_type autofs_fs_type = {
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 68ebd10..08201fa 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -49,7 +49,7 @@ static int befs_nls2utf(struct super_block *sb, const char *in, int in_len,
char **out, int *out_len);
static void befs_put_super(struct super_block *);
static int befs_remount(struct super_block *, int *, char *);
-static int befs_statfs(struct super_block *, struct kstatfs *);
+static int befs_statfs(struct dentry *, struct kstatfs *);
static int parse_options(char *, befs_mount_options *);
static const struct super_operations befs_sops = {
@@ -880,8 +880,9 @@ befs_remount(struct super_block *sb, int *flags, char *data)
}
static int
-befs_statfs(struct super_block *sb, struct kstatfs *buf)
+befs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
+ struct super_block *sb = dentry->d_sb;
befs_debug(sb, "---> befs_statfs()");
@@ -899,11 +900,12 @@ befs_statfs(struct super_block *sb, struct kstatfs *buf)
return 0;
}
-static struct super_block *
+static int
befs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name,
- void *data)
+ void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, befs_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, befs_fill_super,
+ mnt);
}
static struct file_system_type befs_fs_type = {
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index 55a7a78..cf74f3d 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -203,8 +203,9 @@ static void bfs_put_super(struct super_block *s)
s->s_fs_info = NULL;
}
-static int bfs_statfs(struct super_block *s, struct kstatfs *buf)
+static int bfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
+ struct super_block *s = dentry->d_sb;
struct bfs_sb_info *info = BFS_SB(s);
u64 id = huge_encode_dev(s->s_bdev->bd_dev);
buf->f_type = BFS_MAGIC;
@@ -410,10 +411,10 @@ out:
return -EINVAL;
}
-static struct super_block *bfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int bfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, bfs_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, bfs_fill_super, mnt);
}
static struct file_system_type bfs_fs_type = {
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 537893a..d043440 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -38,15 +38,13 @@
#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/random.h>
-
+#include <linux/elf.h>
#include <asm/uaccess.h>
#include <asm/param.h>
#include <asm/page.h>
-#include <linux/elf.h>
-
-static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs);
-static int load_elf_library(struct file*);
+static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs);
+static int load_elf_library(struct file *);
static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int);
extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
@@ -59,15 +57,15 @@ extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
* don't even try.
*/
#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE)
-static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file);
+static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file);
#else
#define elf_core_dump NULL
#endif
#if ELF_EXEC_PAGESIZE > PAGE_SIZE
-# define ELF_MIN_ALIGN ELF_EXEC_PAGESIZE
+#define ELF_MIN_ALIGN ELF_EXEC_PAGESIZE
#else
-# define ELF_MIN_ALIGN PAGE_SIZE
+#define ELF_MIN_ALIGN PAGE_SIZE
#endif
#ifndef ELF_CORE_EFLAGS
@@ -86,7 +84,7 @@ static struct linux_binfmt elf_format = {
.min_coredump = ELF_EXEC_PAGESIZE
};
-#define BAD_ADDR(x) ((unsigned long)(x) > TASK_SIZE)
+#define BAD_ADDR(x) ((unsigned long)(x) > TASK_SIZE)
static int set_brk(unsigned long start, unsigned long end)
{
@@ -104,13 +102,11 @@ static int set_brk(unsigned long start, unsigned long end)
return 0;
}
-
/* We need to explicitly zero any fractional pages
after the data section (i.e. bss). This would
contain the junk from the file that should not
- be in memory */
-
-
+ be in memory
+ */
static int padzero(unsigned long elf_bss)
{
unsigned long nbyte;
@@ -129,7 +125,9 @@ static int padzero(unsigned long elf_bss)
#define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) + (items))
#define STACK_ROUND(sp, items) \
((15 + (unsigned long) ((sp) + (items))) &~ 15UL)
-#define STACK_ALLOC(sp, len) ({ elf_addr_t __user *old_sp = (elf_addr_t __user *)sp; sp += len; old_sp; })
+#define STACK_ALLOC(sp, len) ({ \
+ elf_addr_t __user *old_sp = (elf_addr_t __user *)sp; sp += len; \
+ old_sp; })
#else
#define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) - (items))
#define STACK_ROUND(sp, items) \
@@ -138,7 +136,7 @@ static int padzero(unsigned long elf_bss)
#endif
static int
-create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec,
+create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
int interp_aout, unsigned long load_addr,
unsigned long interp_load_addr)
{
@@ -161,7 +159,6 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec,
* for userspace to get any other way, in others (i386) it is
* merely difficult.
*/
-
u_platform = NULL;
if (k_platform) {
size_t len = strlen(k_platform) + 1;
@@ -171,7 +168,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec,
* evictions by the processes running on the same package. One
* thing we can do is to shuffle the initial stack for them.
*/
-
+
p = arch_align_stack(p);
u_platform = (elf_addr_t __user *)STACK_ALLOC(p, len);
@@ -180,9 +177,12 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec,
}
/* Create the ELF interpreter info */
- elf_info = (elf_addr_t *) current->mm->saved_auxv;
+ elf_info = (elf_addr_t *)current->mm->saved_auxv;
#define NEW_AUX_ENT(id, val) \
- do { elf_info[ei_index++] = id; elf_info[ei_index++] = val; } while (0)
+ do { \
+ elf_info[ei_index++] = id; \
+ elf_info[ei_index++] = val; \
+ } while (0)
#ifdef ARCH_DLINFO
/*
@@ -195,21 +195,22 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec,
NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE);
NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC);
NEW_AUX_ENT(AT_PHDR, load_addr + exec->e_phoff);
- NEW_AUX_ENT(AT_PHENT, sizeof (struct elf_phdr));
+ NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr));
NEW_AUX_ENT(AT_PHNUM, exec->e_phnum);
NEW_AUX_ENT(AT_BASE, interp_load_addr);
NEW_AUX_ENT(AT_FLAGS, 0);
NEW_AUX_ENT(AT_ENTRY, exec->e_entry);
- NEW_AUX_ENT(AT_UID, (elf_addr_t) tsk->uid);
- NEW_AUX_ENT(AT_EUID, (elf_addr_t) tsk->euid);
- NEW_AUX_ENT(AT_GID, (elf_addr_t) tsk->gid);
- NEW_AUX_ENT(AT_EGID, (elf_addr_t) tsk->egid);
- NEW_AUX_ENT(AT_SECURE, (elf_addr_t) security_bprm_secureexec(bprm));
+ NEW_AUX_ENT(AT_UID, tsk->uid);
+ NEW_AUX_ENT(AT_EUID, tsk->euid);
+ NEW_AUX_ENT(AT_GID, tsk->gid);
+ NEW_AUX_ENT(AT_EGID, tsk->egid);
+ NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm));
if (k_platform) {
- NEW_AUX_ENT(AT_PLATFORM, (elf_addr_t)(unsigned long)u_platform);
+ NEW_AUX_ENT(AT_PLATFORM,
+ (elf_addr_t)(unsigned long)u_platform);
}
if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) {
- NEW_AUX_ENT(AT_EXECFD, (elf_addr_t) bprm->interp_data);
+ NEW_AUX_ENT(AT_EXECFD, bprm->interp_data);
}
#undef NEW_AUX_ENT
/* AT_NULL is zero; clear the rest too */
@@ -232,7 +233,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec,
/* Point sp at the lowest address on the stack */
#ifdef CONFIG_STACK_GROWSUP
sp = (elf_addr_t __user *)bprm->p - items - ei_index;
- bprm->exec = (unsigned long) sp; /* XXX: PARISC HACK */
+ bprm->exec = (unsigned long)sp; /* XXX: PARISC HACK */
#else
sp = (elf_addr_t __user *)bprm->p;
#endif
@@ -285,7 +286,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec,
#ifndef elf_map
static unsigned long elf_map(struct file *filep, unsigned long addr,
- struct elf_phdr *eppnt, int prot, int type)
+ struct elf_phdr *eppnt, int prot, int type)
{
unsigned long map_addr;
unsigned long pageoffset = ELF_PAGEOFFSET(eppnt->p_vaddr);
@@ -310,9 +311,8 @@ static unsigned long elf_map(struct file *filep, unsigned long addr,
is only provided so that we can read a.out libraries that have
an ELF header */
-static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
- struct file * interpreter,
- unsigned long *interp_load_addr)
+static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
+ struct file *interpreter, unsigned long *interp_load_addr)
{
struct elf_phdr *elf_phdata;
struct elf_phdr *eppnt;
@@ -342,15 +342,15 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
goto out;
/* Now read in all of the header information */
-
size = sizeof(struct elf_phdr) * interp_elf_ex->e_phnum;
if (size > ELF_MIN_ALIGN)
goto out;
- elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL);
+ elf_phdata = kmalloc(size, GFP_KERNEL);
if (!elf_phdata)
goto out;
- retval = kernel_read(interpreter,interp_elf_ex->e_phoff,(char *)elf_phdata,size);
+ retval = kernel_read(interpreter, interp_elf_ex->e_phoff,
+ (char *)elf_phdata,size);
error = -EIO;
if (retval != size) {
if (retval < 0)
@@ -359,58 +359,65 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
}
eppnt = elf_phdata;
- for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
- if (eppnt->p_type == PT_LOAD) {
- int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
- int elf_prot = 0;
- unsigned long vaddr = 0;
- unsigned long k, map_addr;
-
- if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
- if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
- if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
- vaddr = eppnt->p_vaddr;
- if (interp_elf_ex->e_type == ET_EXEC || load_addr_set)
- elf_type |= MAP_FIXED;
-
- map_addr = elf_map(interpreter, load_addr + vaddr, eppnt, elf_prot, elf_type);
- error = map_addr;
- if (BAD_ADDR(map_addr))
- goto out_close;
-
- if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
- load_addr = map_addr - ELF_PAGESTART(vaddr);
- load_addr_set = 1;
- }
-
- /*
- * Check to see if the section's size will overflow the
- * allowed task size. Note that p_filesz must always be
- * <= p_memsize so it is only necessary to check p_memsz.
- */
- k = load_addr + eppnt->p_vaddr;
- if (k > TASK_SIZE || eppnt->p_filesz > eppnt->p_memsz ||
- eppnt->p_memsz > TASK_SIZE || TASK_SIZE - eppnt->p_memsz < k) {
- error = -ENOMEM;
- goto out_close;
- }
-
- /*
- * Find the end of the file mapping for this phdr, and keep
- * track of the largest address we see for this.
- */
- k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
- if (k > elf_bss)
- elf_bss = k;
-
- /*
- * Do the same thing for the memory mapping - between
- * elf_bss and last_bss is the bss section.
- */
- k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
- if (k > last_bss)
- last_bss = k;
- }
+ for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) {
+ if (eppnt->p_type == PT_LOAD) {
+ int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+ int elf_prot = 0;
+ unsigned long vaddr = 0;
+ unsigned long k, map_addr;
+
+ if (eppnt->p_flags & PF_R)
+ elf_prot = PROT_READ;
+ if (eppnt->p_flags & PF_W)
+ elf_prot |= PROT_WRITE;
+ if (eppnt->p_flags & PF_X)
+ elf_prot |= PROT_EXEC;
+ vaddr = eppnt->p_vaddr;
+ if (interp_elf_ex->e_type == ET_EXEC || load_addr_set)
+ elf_type |= MAP_FIXED;
+
+ map_addr = elf_map(interpreter, load_addr + vaddr,
+ eppnt, elf_prot, elf_type);
+ error = map_addr;
+ if (BAD_ADDR(map_addr))
+ goto out_close;
+
+ if (!load_addr_set &&
+ interp_elf_ex->e_type == ET_DYN) {
+ load_addr = map_addr - ELF_PAGESTART(vaddr);
+ load_addr_set = 1;
+ }
+
+ /*
+ * Check to see if the section's size will overflow the
+ * allowed task size. Note that p_filesz must always be
+ * <= p_memsize so it's only necessary to check p_memsz.
+ */
+ k = load_addr + eppnt->p_vaddr;
+ if (k > TASK_SIZE ||
+ eppnt->p_filesz > eppnt->p_memsz ||
+ eppnt->p_memsz > TASK_SIZE ||
+ TASK_SIZE - eppnt->p_memsz < k) {
+ error = -ENOMEM;
+ goto out_close;
+ }
+
+ /*
+ * Find the end of the file mapping for this phdr, and
+ * keep track of the largest address we see for this.
+ */
+ k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
+ if (k > elf_bss)
+ elf_bss = k;
+
+ /*
+ * Do the same thing for the memory mapping - between
+ * elf_bss and last_bss is the bss section.
+ */
+ k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
+ if (k > last_bss)
+ last_bss = k;
+ }
}
/*
@@ -424,7 +431,8 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
goto out_close;
}
- elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); /* What we have mapped so far */
+ /* What we have mapped so far */
+ elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1);
/* Map the last of the bss segment */
if (last_bss > elf_bss) {
@@ -436,7 +444,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
}
*interp_load_addr = load_addr;
- error = ((unsigned long) interp_elf_ex->e_entry) + load_addr;
+ error = ((unsigned long)interp_elf_ex->e_entry) + load_addr;
out_close:
kfree(elf_phdata);
@@ -444,8 +452,8 @@ out:
return error;
}
-static unsigned long load_aout_interp(struct exec * interp_ex,
- struct file * interpreter)
+static unsigned long load_aout_interp(struct exec *interp_ex,
+ struct file *interpreter)
{
unsigned long text_data, elf_entry = ~0UL;
char __user * addr;
@@ -464,7 +472,7 @@ static unsigned long load_aout_interp(struct exec * interp_ex,
case ZMAGIC:
case QMAGIC:
offset = N_TXTOFF(*interp_ex);
- addr = (char __user *) N_TXTADDR(*interp_ex);
+ addr = (char __user *)N_TXTADDR(*interp_ex);
break;
default:
goto out;
@@ -480,7 +488,6 @@ static unsigned long load_aout_interp(struct exec * interp_ex,
flush_icache_range((unsigned long)addr,
(unsigned long)addr + text_data);
-
down_write(&current->mm->mmap_sem);
do_brk(ELF_PAGESTART(text_data + ELF_MIN_ALIGN - 1),
interp_ex->a_bss);
@@ -519,7 +526,7 @@ static unsigned long randomize_stack_top(unsigned long stack_top)
#endif
}
-static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
+static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
{
struct file *interpreter = NULL; /* to shut gcc up */
unsigned long load_addr = 0, load_bias = 0;
@@ -528,7 +535,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
unsigned int interpreter_type = INTERPRETER_NONE;
unsigned char ibcs2_interpreter = 0;
unsigned long error;
- struct elf_phdr * elf_ppnt, *elf_phdata;
+ struct elf_phdr *elf_ppnt, *elf_phdata;
unsigned long elf_bss, elf_brk;
int elf_exec_fileno;
int retval, i;
@@ -553,7 +560,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
}
/* Get the exec-header */
- loc->elf_ex = *((struct elfhdr *) bprm->buf);
+ loc->elf_ex = *((struct elfhdr *)bprm->buf);
retval = -ENOEXEC;
/* First of all, some simple consistency checks */
@@ -568,7 +575,6 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
goto out;
/* Now read in all of the header information */
-
if (loc->elf_ex.e_phentsize != sizeof(struct elf_phdr))
goto out;
if (loc->elf_ex.e_phnum < 1 ||
@@ -576,18 +582,19 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
goto out;
size = loc->elf_ex.e_phnum * sizeof(struct elf_phdr);
retval = -ENOMEM;
- elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL);
+ elf_phdata = kmalloc(size, GFP_KERNEL);
if (!elf_phdata)
goto out;
- retval = kernel_read(bprm->file, loc->elf_ex.e_phoff, (char *) elf_phdata, size);
+ retval = kernel_read(bprm->file, loc->elf_ex.e_phoff,
+ (char *)elf_phdata, size);
if (retval != size) {
if (retval >= 0)
retval = -EIO;
goto out_free_ph;
}
- files = current->files; /* Refcounted so ok */
+ files = current->files; /* Refcounted so ok */
retval = unshare_files();
if (retval < 0)
goto out_free_ph;
@@ -598,7 +605,6 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
/* exec will make our files private anyway, but for the a.out
loader stuff we need to do it earlier */
-
retval = get_unused_fd();
if (retval < 0)
goto out_free_fh;
@@ -620,7 +626,6 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
* shared libraries - for now assume that this
* is an a.out format binary
*/
-
retval = -ENOEXEC;
if (elf_ppnt->p_filesz > PATH_MAX ||
elf_ppnt->p_filesz < 2)
@@ -628,13 +633,13 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
retval = -ENOMEM;
elf_interpreter = kmalloc(elf_ppnt->p_filesz,
- GFP_KERNEL);
+ GFP_KERNEL);
if (!elf_interpreter)
goto out_free_file;
retval = kernel_read(bprm->file, elf_ppnt->p_offset,
- elf_interpreter,
- elf_ppnt->p_filesz);
+ elf_interpreter,
+ elf_ppnt->p_filesz);
if (retval != elf_ppnt->p_filesz) {
if (retval >= 0)
retval = -EIO;
@@ -678,7 +683,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
retval = PTR_ERR(interpreter);
if (IS_ERR(interpreter))
goto out_free_interp;
- retval = kernel_read(interpreter, 0, bprm->buf, BINPRM_BUF_SIZE);
+ retval = kernel_read(interpreter, 0, bprm->buf,
+ BINPRM_BUF_SIZE);
if (retval != BINPRM_BUF_SIZE) {
if (retval >= 0)
retval = -EIO;
@@ -686,8 +692,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
}
/* Get the exec headers */
- loc->interp_ex = *((struct exec *) bprm->buf);
- loc->interp_elf_ex = *((struct elfhdr *) bprm->buf);
+ loc->interp_ex = *((struct exec *)bprm->buf);
+ loc->interp_elf_ex = *((struct elfhdr *)bprm->buf);
break;
}
elf_ppnt++;
@@ -739,7 +745,6 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
/* OK, we are done with that, now set up the arg stuff,
and then start this sucker up */
-
if ((!bprm->sh_bang) && (interpreter_type == INTERPRETER_AOUT)) {
char *passed_p = passed_fileno;
sprintf(passed_fileno, "%d", elf_exec_fileno);
@@ -759,7 +764,6 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
/* Discard our unneeded old files struct */
if (files) {
- steal_locks(files);
put_files_struct(files);
files = NULL;
}
@@ -778,7 +782,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if (elf_read_implies_exec(loc->elf_ex, executable_stack))
current->personality |= READ_IMPLIES_EXEC;
- if ( !(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
+ if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
current->flags |= PF_RANDOMIZE;
arch_pick_mmap_layout(current->mm);
@@ -799,8 +803,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
the correct location in memory. At this point, we assume that
the image should be loaded at fixed address, not at a variable
address. */
-
- for(i = 0, elf_ppnt = elf_phdata; i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
+ for(i = 0, elf_ppnt = elf_phdata;
+ i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
int elf_prot = 0, elf_flags;
unsigned long k, vaddr;
@@ -828,30 +832,35 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
load_bias, nbyte)) {
/*
* This bss-zeroing can fail if the ELF
- * file specifies odd protections. So
+ * file specifies odd protections. So
* we don't check the return value
*/
}
}
}
- if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
- if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
- if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
+ if (elf_ppnt->p_flags & PF_R)
+ elf_prot |= PROT_READ;
+ if (elf_ppnt->p_flags & PF_W)
+ elf_prot |= PROT_WRITE;
+ if (elf_ppnt->p_flags & PF_X)
+ elf_prot |= PROT_EXEC;
- elf_flags = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE;
+ elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE;
vaddr = elf_ppnt->p_vaddr;
if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) {
elf_flags |= MAP_FIXED;
} else if (loc->elf_ex.e_type == ET_DYN) {
- /* Try and get dynamic programs out of the way of the default mmap
- base, as well as whatever program they might try to exec. This
- is because the brk will follow the loader, and is not movable. */
+ /* Try and get dynamic programs out of the way of the
+ * default mmap base, as well as whatever program they
+ * might try to exec. This is because the brk will
+ * follow the loader, and is not movable. */
load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
}
- error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags);
+ error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
+ elf_prot, elf_flags);
if (BAD_ADDR(error)) {
send_sig(SIGKILL, current, 0);
goto out_free_dentry;
@@ -868,8 +877,10 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
}
}
k = elf_ppnt->p_vaddr;
- if (k < start_code) start_code = k;
- if (start_data < k) start_data = k;
+ if (k < start_code)
+ start_code = k;
+ if (start_data < k)
+ start_data = k;
/*
* Check to see if the section's size will overflow the
@@ -879,7 +890,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if (k > TASK_SIZE || elf_ppnt->p_filesz > elf_ppnt->p_memsz ||
elf_ppnt->p_memsz > TASK_SIZE ||
TASK_SIZE - elf_ppnt->p_memsz < k) {
- /* set_brk can never work. Avoid overflows. */
+ /* set_brk can never work. Avoid overflows. */
send_sig(SIGKILL, current, 0);
goto out_free_dentry;
}
@@ -967,8 +978,9 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
compute_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
- create_elf_tables(bprm, &loc->elf_ex, (interpreter_type == INTERPRETER_AOUT),
- load_addr, interp_load_addr);
+ create_elf_tables(bprm, &loc->elf_ex,
+ (interpreter_type == INTERPRETER_AOUT),
+ load_addr, interp_load_addr);
/* N.B. passed_fileno might not be initialized? */
if (interpreter_type == INTERPRETER_AOUT)
current->mm->arg_start += strlen(passed_fileno) + 1;
@@ -982,7 +994,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
/* Why this, you ask??? Well SVr4 maps page 0 as read-only,
and some applications "depend" upon this behavior.
Since we do not have the power to recompile these, we
- emulate the SVr4 behavior. Sigh. */
+ emulate the SVr4 behavior. Sigh. */
down_write(&current->mm->mmap_sem);
error = do_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE, 0);
@@ -1037,7 +1049,6 @@ out_free_ph:
/* This is really simpleminded and specialized - we are loading an
a.out library that is given an ELF header. */
-
static int load_elf_library(struct file *file)
{
struct elf_phdr *elf_phdata;
@@ -1047,7 +1058,7 @@ static int load_elf_library(struct file *file)
struct elfhdr elf_ex;
error = -ENOEXEC;
- retval = kernel_read(file, 0, (char *) &elf_ex, sizeof(elf_ex));
+ retval = kernel_read(file, 0, (char *)&elf_ex, sizeof(elf_ex));
if (retval != sizeof(elf_ex))
goto out;
@@ -1056,7 +1067,7 @@ static int load_elf_library(struct file *file)
/* First of all, some simple consistency checks */
if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
- !elf_check_arch(&elf_ex) || !file->f_op || !file->f_op->mmap)
+ !elf_check_arch(&elf_ex) || !file->f_op || !file->f_op->mmap)
goto out;
/* Now read in all of the header information */
@@ -1104,7 +1115,8 @@ static int load_elf_library(struct file *file)
goto out_free_ph;
}
- len = ELF_PAGESTART(eppnt->p_filesz + eppnt->p_vaddr + ELF_MIN_ALIGN - 1);
+ len = ELF_PAGESTART(eppnt->p_filesz + eppnt->p_vaddr +
+ ELF_MIN_ALIGN - 1);
bss = eppnt->p_memsz + eppnt->p_vaddr;
if (bss > len) {
down_write(&current->mm->mmap_sem);
@@ -1163,7 +1175,7 @@ static int maydump(struct vm_area_struct *vma)
if (vma->vm_flags & (VM_IO | VM_RESERVED))
return 0;
- /* Dump shared memory only if mapped from an anonymous file. */
+ /* Dump shared memory only if mapped from an anonymous file. */
if (vma->vm_flags & VM_SHARED)
return vma->vm_file->f_dentry->d_inode->i_nlink == 0;
@@ -1174,7 +1186,7 @@ static int maydump(struct vm_area_struct *vma)
return 1;
}
-#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
+#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
/* An ELF note in memory */
struct memelfnote
@@ -1277,11 +1289,11 @@ static void fill_note(struct memelfnote *note, const char *name, int type,
}
/*
- * fill up all the fields in prstatus from the given task struct, except registers
- * which need to be filled up separately.
+ * fill up all the fields in prstatus from the given task struct, except
+ * registers which need to be filled up separately.
*/
static void fill_prstatus(struct elf_prstatus *prstatus,
- struct task_struct *p, long signr)
+ struct task_struct *p, long signr)
{
prstatus->pr_info.si_signo = prstatus->pr_cursig = signr;
prstatus->pr_sigpend = p->pending.signal.sig[0];
@@ -1366,8 +1378,8 @@ struct elf_thread_status
/*
* In order to add the specific thread information for the elf file format,
- * we need to keep a linked list of every threads pr_status and then
- * create a single section for them in the final core file.
+ * we need to keep a linked list of every threads pr_status and then create
+ * a single section for them in the final core file.
*/
static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
{
@@ -1378,19 +1390,23 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
fill_prstatus(&t->prstatus, p, signr);
elf_core_copy_task_regs(p, &t->prstatus.pr_reg);
- fill_note(&t->notes[0], "CORE", NT_PRSTATUS, sizeof(t->prstatus), &(t->prstatus));
+ fill_note(&t->notes[0], "CORE", NT_PRSTATUS, sizeof(t->prstatus),
+ &(t->prstatus));
t->num_notes++;
sz += notesize(&t->notes[0]);
- if ((t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, NULL, &t->fpu))) {
- fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(t->fpu), &(t->fpu));
+ if ((t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, NULL,
+ &t->fpu))) {
+ fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(t->fpu),
+ &(t->fpu));
t->num_notes++;
sz += notesize(&t->notes[1]);
}
#ifdef ELF_CORE_COPY_XFPREGS
if (elf_core_copy_task_xfpregs(p, &t->xfpu)) {
- fill_note(&t->notes[2], "LINUX", NT_PRXFPREG, sizeof(t->xfpu), &t->xfpu);
+ fill_note(&t->notes[2], "LINUX", NT_PRXFPREG, sizeof(t->xfpu),
+ &t->xfpu);
t->num_notes++;
sz += notesize(&t->notes[2]);
}
@@ -1405,7 +1421,7 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
* and then they are actually written out. If we run out of core limit
* we just truncate.
*/
-static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
+static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
{
#define NUM_NOTES 6
int has_dumped = 0;
@@ -1434,12 +1450,12 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
/*
* We no longer stop all VM operations.
*
- * This is because those proceses that could possibly change map_count or
- * the mmap / vma pages are now blocked in do_exit on current finishing
- * this core dump.
+ * This is because those proceses that could possibly change map_count
+ * or the mmap / vma pages are now blocked in do_exit on current
+ * finishing this core dump.
*
* Only ptrace can touch these memory addresses, but it doesn't change
- * the map_count or the pages allocated. So no possibility of crashing
+ * the map_count or the pages allocated. So no possibility of crashing
* exists while dumping the mm->vm_next areas to the core file.
*/
@@ -1501,7 +1517,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
#endif
/* Set up header */
- fill_elf_header(elf, segs+1); /* including notes section */
+ fill_elf_header(elf, segs + 1); /* including notes section */
has_dumped = 1;
current->flags |= PF_DUMPCORE;
@@ -1511,24 +1527,24 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
* with info from their /proc.
*/
- fill_note(notes +0, "CORE", NT_PRSTATUS, sizeof(*prstatus), prstatus);
-
+ fill_note(notes + 0, "CORE", NT_PRSTATUS, sizeof(*prstatus), prstatus);
fill_psinfo(psinfo, current->group_leader, current->mm);
- fill_note(notes +1, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo);
+ fill_note(notes + 1, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo);
numnote = 2;
- auxv = (elf_addr_t *) current->mm->saved_auxv;
+ auxv = (elf_addr_t *)current->mm->saved_auxv;
i = 0;
do
i += 2;
while (auxv[i - 2] != AT_NULL);
fill_note(&notes[numnote++], "CORE", NT_AUXV,
- i * sizeof (elf_addr_t), auxv);
+ i * sizeof(elf_addr_t), auxv);
/* Try to dump the FPU. */
- if ((prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs, fpu)))
+ if ((prstatus->pr_fpvalid =
+ elf_core_copy_task_fpregs(current, regs, fpu)))
fill_note(notes + numnote++,
"CORE", NT_PRFPREG, sizeof(*fpu), fpu);
#ifdef ELF_CORE_COPY_XFPREGS
@@ -1577,8 +1593,10 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
phdr.p_memsz = sz;
offset += phdr.p_filesz;
phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
- if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W;
- if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X;
+ if (vma->vm_flags & VM_WRITE)
+ phdr.p_flags |= PF_W;
+ if (vma->vm_flags & VM_EXEC)
+ phdr.p_flags |= PF_X;
phdr.p_align = ELF_EXEC_PAGESIZE;
DUMP_WRITE(&phdr, sizeof(phdr));
@@ -1595,7 +1613,9 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
/* write out the thread status notes section */
list_for_each(t, &thread_list) {
- struct elf_thread_status *tmp = list_entry(t, struct elf_thread_status, list);
+ struct elf_thread_status *tmp =
+ list_entry(t, struct elf_thread_status, list);
+
for (i = 0; i < tmp->num_notes; i++)
if (!writenote(&tmp->notes[i], file))
goto end_coredump;
@@ -1612,18 +1632,19 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
for (addr = vma->vm_start;
addr < vma->vm_end;
addr += PAGE_SIZE) {
- struct page* page;
+ struct page *page;
struct vm_area_struct *vma;
if (get_user_pages(current, current->mm, addr, 1, 0, 1,
&page, &vma) <= 0) {
- DUMP_SEEK (file->f_pos + PAGE_SIZE);
+ DUMP_SEEK(file->f_pos + PAGE_SIZE);
} else {
if (page == ZERO_PAGE(addr)) {
- DUMP_SEEK (file->f_pos + PAGE_SIZE);
+ DUMP_SEEK(file->f_pos + PAGE_SIZE);
} else {
void *kaddr;
- flush_cache_page(vma, addr, page_to_pfn(page));
+ flush_cache_page(vma, addr,
+ page_to_pfn(page));
kaddr = kmap(page);
if ((size += PAGE_SIZE) > limit ||
!dump_write(file, kaddr,
@@ -1645,7 +1666,8 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
if ((off_t)file->f_pos != offset) {
/* Sanity check */
- printk(KERN_WARNING "elf_core_dump: file->f_pos (%ld) != offset (%ld)\n",
+ printk(KERN_WARNING
+ "elf_core_dump: file->f_pos (%ld) != offset (%ld)\n",
(off_t)file->f_pos, offset);
}
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index a2e48c9..eba4e23 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -435,9 +435,10 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
struct elf_fdpic_params *interp_params)
{
unsigned long sp, csp, nitems;
- elf_caddr_t *argv, *envp;
+ elf_caddr_t __user *argv, *envp;
size_t platform_len = 0, len;
- char *k_platform, *u_platform, *p;
+ char *k_platform;
+ char __user *u_platform, *p;
long hwcap;
int loop;
@@ -462,12 +463,11 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
if (k_platform) {
platform_len = strlen(k_platform) + 1;
sp -= platform_len;
+ u_platform = (char __user *) sp;
if (__copy_to_user(u_platform, k_platform, platform_len) != 0)
return -EFAULT;
}
- u_platform = (char *) sp;
-
#if defined(__i386__) && defined(CONFIG_SMP)
/* in some cases (e.g. Hyper-Threading), we want to avoid L1 evictions
* by the processes running on the same package. One thing we can do
@@ -490,7 +490,7 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
sp = (sp - len) & ~7UL;
exec_params->map_addr = sp;
- if (copy_to_user((void *) sp, exec_params->loadmap, len) != 0)
+ if (copy_to_user((void __user *) sp, exec_params->loadmap, len) != 0)
return -EFAULT;
current->mm->context.exec_fdpic_loadmap = (unsigned long) sp;
@@ -501,7 +501,7 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
sp = (sp - len) & ~7UL;
interp_params->map_addr = sp;
- if (copy_to_user((void *) sp, interp_params->loadmap, len) != 0)
+ if (copy_to_user((void __user *) sp, interp_params->loadmap, len) != 0)
return -EFAULT;
current->mm->context.interp_fdpic_loadmap = (unsigned long) sp;
@@ -527,7 +527,7 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
/* put the ELF interpreter info on the stack */
#define NEW_AUX_ENT(nr, id, val) \
do { \
- struct { unsigned long _id, _val; } *ent = (void *) csp; \
+ struct { unsigned long _id, _val; } __user *ent = (void __user *) csp; \
__put_user((id), &ent[nr]._id); \
__put_user((val), &ent[nr]._val); \
} while (0)
@@ -564,13 +564,13 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
/* allocate room for argv[] and envv[] */
csp -= (bprm->envc + 1) * sizeof(elf_caddr_t);
- envp = (elf_caddr_t *) csp;
+ envp = (elf_caddr_t __user *) csp;
csp -= (bprm->argc + 1) * sizeof(elf_caddr_t);
- argv = (elf_caddr_t *) csp;
+ argv = (elf_caddr_t __user *) csp;
/* stack argc */
csp -= sizeof(unsigned long);
- __put_user(bprm->argc, (unsigned long *) csp);
+ __put_user(bprm->argc, (unsigned long __user *) csp);
BUG_ON(csp != sp);
@@ -581,7 +581,7 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
current->mm->arg_start = current->mm->start_stack - (MAX_ARG_PAGES * PAGE_SIZE - bprm->p);
#endif
- p = (char *) current->mm->arg_start;
+ p = (char __user *) current->mm->arg_start;
for (loop = bprm->argc; loop > 0; loop--) {
__put_user((elf_caddr_t) p, argv++);
len = strnlen_user(p, PAGE_SIZE * MAX_ARG_PAGES);
@@ -1025,7 +1025,7 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params,
/* clear the bit between beginning of mapping and beginning of PT_LOAD */
if (prot & PROT_WRITE && disp > 0) {
kdebug("clear[%d] ad=%lx sz=%lx", loop, maddr, disp);
- clear_user((void *) maddr, disp);
+ clear_user((void __user *) maddr, disp);
maddr += disp;
}
@@ -1059,7 +1059,7 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params,
if (prot & PROT_WRITE && excess1 > 0) {
kdebug("clear[%d] ad=%lx sz=%lx",
loop, maddr + phdr->p_filesz, excess1);
- clear_user((void *) maddr + phdr->p_filesz, excess1);
+ clear_user((void __user *) maddr + phdr->p_filesz, excess1);
}
#else
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index d73d755..34ebbc1 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -55,6 +55,7 @@ typedef struct {
} Node;
static DEFINE_RWLOCK(entries_lock);
+static struct file_system_type bm_fs_type;
static struct vfsmount *bm_mnt;
static int entry_count;
@@ -203,7 +204,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
goto _error;
if (files) {
- steal_locks(files);
put_files_struct(files);
files = NULL;
}
@@ -638,7 +638,7 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
if (!inode)
goto out2;
- err = simple_pin_fs("binfmt_misc", &bm_mnt, &entry_count);
+ err = simple_pin_fs(&bm_fs_type, &bm_mnt, &entry_count);
if (err) {
iput(inode);
inode = NULL;
@@ -740,10 +740,10 @@ static int bm_fill_super(struct super_block * sb, void * data, int silent)
return err;
}
-static struct super_block *bm_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int bm_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, bm_fill_super);
+ return get_sb_single(fs_type, flags, data, bm_fill_super, mnt);
}
static struct linux_binfmt misc_format = {
diff --git a/fs/block_dev.c b/fs/block_dev.c
index f5958f4..028d9fb 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -300,10 +300,10 @@ static struct super_operations bdev_sops = {
.clear_inode = bdev_clear_inode,
};
-static struct super_block *bd_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int bd_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_pseudo(fs_type, "bdev:", &bdev_sops, 0x62646576);
+ return get_sb_pseudo(fs_type, "bdev:", &bdev_sops, 0x62646576, mnt);
}
static struct file_system_type bd_type = {
@@ -414,21 +414,31 @@ EXPORT_SYMBOL(bdput);
static struct block_device *bd_acquire(struct inode *inode)
{
struct block_device *bdev;
+
spin_lock(&bdev_lock);
bdev = inode->i_bdev;
- if (bdev && igrab(bdev->bd_inode)) {
+ if (bdev) {
+ atomic_inc(&bdev->bd_inode->i_count);
spin_unlock(&bdev_lock);
return bdev;
}
spin_unlock(&bdev_lock);
+
bdev = bdget(inode->i_rdev);
if (bdev) {
spin_lock(&bdev_lock);
- if (inode->i_bdev)
- __bd_forget(inode);
- inode->i_bdev = bdev;
- inode->i_mapping = bdev->bd_inode->i_mapping;
- list_add(&inode->i_devices, &bdev->bd_inodes);
+ if (!inode->i_bdev) {
+ /*
+ * We take an additional bd_inode->i_count for inode,
+ * and it's released in clear_inode() of inode.
+ * So, we can access it via ->i_mapping always
+ * without igrab().
+ */
+ atomic_inc(&bdev->bd_inode->i_count);
+ inode->i_bdev = bdev;
+ inode->i_mapping = bdev->bd_inode->i_mapping;
+ list_add(&inode->i_devices, &bdev->bd_inodes);
+ }
spin_unlock(&bdev_lock);
}
return bdev;
@@ -438,10 +448,18 @@ static struct block_device *bd_acquire(struct inode *inode)
void bd_forget(struct inode *inode)
{
+ struct block_device *bdev = NULL;
+
spin_lock(&bdev_lock);
- if (inode->i_bdev)
+ if (inode->i_bdev) {
+ if (inode->i_sb != blockdev_superblock)
+ bdev = inode->i_bdev;
__bd_forget(inode);
+ }
spin_unlock(&bdev_lock);
+
+ if (bdev)
+ iput(bdev->bd_inode);
}
int bd_claim(struct block_device *bdev, void *holder)
diff --git a/fs/buffer.c b/fs/buffer.c
index 23f1f3a..373bb62 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -331,7 +331,6 @@ long do_fsync(struct file *file, int datasync)
goto out;
}
- current->flags |= PF_SYNCWRITE;
ret = filemap_fdatawrite(mapping);
/*
@@ -346,7 +345,6 @@ long do_fsync(struct file *file, int datasync)
err = filemap_fdatawait(mapping);
if (!ret)
ret = err;
- current->flags &= ~PF_SYNCWRITE;
out:
return ret;
}
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index c262d88..8b4de6e 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -166,8 +166,9 @@ cifs_put_super(struct super_block *sb)
}
static int
-cifs_statfs(struct super_block *sb, struct kstatfs *buf)
+cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
+ struct super_block *sb = dentry->d_sb;
int xid;
int rc = -EOPNOTSUPP;
struct cifs_sb_info *cifs_sb;
@@ -402,12 +403,14 @@ static struct quotactl_ops cifs_quotactl_ops = {
#endif
#ifdef CONFIG_CIFS_EXPERIMENTAL
-static void cifs_umount_begin(struct super_block * sblock)
+static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
{
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo * tcon;
- cifs_sb = CIFS_SB(sblock);
+ if (!(flags & MNT_FORCE))
+ return;
+ cifs_sb = CIFS_SB(vfsmnt->mnt_sb);
if(cifs_sb == NULL)
return;
@@ -460,9 +463,9 @@ struct super_operations cifs_super_ops = {
.remount_fs = cifs_remount,
};
-static struct super_block *
+static int
cifs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
int rc;
struct super_block *sb = sget(fs_type, NULL, set_anon_super, NULL);
@@ -470,7 +473,7 @@ cifs_get_sb(struct file_system_type *fs_type,
cFYI(1, ("Devname: %s flags: %d ", dev_name, flags));
if (IS_ERR(sb))
- return sb;
+ return PTR_ERR(sb);
sb->s_flags = flags;
@@ -478,10 +481,10 @@ cifs_get_sb(struct file_system_type *fs_type,
if (rc) {
up_write(&sb->s_umount);
deactivate_super(sb);
- return ERR_PTR(rc);
+ return rc;
}
sb->s_flags |= MS_ACTIVE;
- return sb;
+ return simple_set_mnt(mnt, sb);
}
static ssize_t cifs_file_writev(struct file *file, const struct iovec *iov,
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index c98755d..d56c057 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -74,7 +74,7 @@ extern ssize_t cifs_user_write(struct file *file, const char __user *write_data,
size_t write_size, loff_t * poffset);
extern int cifs_lock(struct file *, int, struct file_lock *);
extern int cifs_fsync(struct file *, struct dentry *, int);
-extern int cifs_flush(struct file *);
+extern int cifs_flush(struct file *, fl_owner_t id);
extern int cifs_file_mmap(struct file * , struct vm_area_struct *);
extern const struct file_operations cifs_dir_ops;
extern int cifs_dir_open(struct inode *inode, struct file *file);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index e2b4ce1..b4a18c1 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1079,9 +1079,9 @@ static int cifs_writepages(struct address_space *mapping,
unsigned int bytes_written;
struct cifs_sb_info *cifs_sb;
int done = 0;
- pgoff_t end = -1;
+ pgoff_t end;
pgoff_t index;
- int is_range = 0;
+ int range_whole = 0;
struct kvec iov[32];
int len;
int n_iov = 0;
@@ -1122,16 +1122,14 @@ static int cifs_writepages(struct address_space *mapping,
xid = GetXid();
pagevec_init(&pvec, 0);
- if (wbc->sync_mode == WB_SYNC_NONE)
+ if (wbc->range_cyclic) {
index = mapping->writeback_index; /* Start from prev offset */
- else {
- index = 0;
- scanned = 1;
- }
- if (wbc->start || wbc->end) {
- index = wbc->start >> PAGE_CACHE_SHIFT;
- end = wbc->end >> PAGE_CACHE_SHIFT;
- is_range = 1;
+ end = -1;
+ } else {
+ index = wbc->range_start >> PAGE_CACHE_SHIFT;
+ end = wbc->range_end >> PAGE_CACHE_SHIFT;
+ if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
+ range_whole = 1;
scanned = 1;
}
retry:
@@ -1167,7 +1165,7 @@ retry:
break;
}
- if (unlikely(is_range) && (page->index > end)) {
+ if (!wbc->range_cyclic && page->index > end) {
done = 1;
unlock_page(page);
break;
@@ -1271,7 +1269,7 @@ retry:
index = 0;
goto retry;
}
- if (!is_range)
+ if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
mapping->writeback_index = index;
FreeXid(xid);
@@ -1419,7 +1417,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
* As file closes, flush all cached write data for this inode checking
* for write behind errors.
*/
-int cifs_flush(struct file *file)
+int cifs_flush(struct file *file, fl_owner_t id)
{
struct inode * inode = file->f_dentry->d_inode;
int rc = 0;
diff --git a/fs/coda/file.c b/fs/coda/file.c
index 7c26424..cc66c68 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -164,7 +164,7 @@ int coda_open(struct inode *coda_inode, struct file *coda_file)
return 0;
}
-int coda_flush(struct file *coda_file)
+int coda_flush(struct file *coda_file, fl_owner_t id)
{
unsigned short flags = coda_file->f_flags & ~O_EXCL;
unsigned short coda_flags = coda_flags_to_cflags(flags);
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index ada1a81..87f1dc8 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -36,7 +36,7 @@
/* VFS super_block ops */
static void coda_clear_inode(struct inode *);
static void coda_put_super(struct super_block *);
-static int coda_statfs(struct super_block *sb, struct kstatfs *buf);
+static int coda_statfs(struct dentry *dentry, struct kstatfs *buf);
static kmem_cache_t * coda_inode_cachep;
@@ -278,13 +278,13 @@ struct inode_operations coda_file_inode_operations = {
.setattr = coda_setattr,
};
-static int coda_statfs(struct super_block *sb, struct kstatfs *buf)
+static int coda_statfs(struct dentry *dentry, struct kstatfs *buf)
{
int error;
lock_kernel();
- error = venus_statfs(sb, buf);
+ error = venus_statfs(dentry, buf);
unlock_kernel();
@@ -307,10 +307,10 @@ static int coda_statfs(struct super_block *sb, struct kstatfs *buf)
/* init_coda: used by filesystems.c to register coda */
-static struct super_block *coda_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int coda_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_nodev(fs_type, flags, data, coda_fill_super);
+ return get_sb_nodev(fs_type, flags, data, coda_fill_super, mnt);
}
struct file_system_type coda_fs_type = {
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index 1bae996..b040eba 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -611,7 +611,7 @@ int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
return error;
}
-int venus_statfs(struct super_block *sb, struct kstatfs *sfs)
+int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
{
union inputArgs *inp;
union outputArgs *outp;
@@ -620,7 +620,7 @@ int venus_statfs(struct super_block *sb, struct kstatfs *sfs)
insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
UPARG(CODA_STATFS);
- error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+ error = coda_upcall(coda_sbp(dentry->d_sb), insize, &outsize, inp);
if (!error) {
sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
diff --git a/fs/compat.c b/fs/compat.c
index b1f6478..7e7e5bc 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -197,7 +197,7 @@ asmlinkage long compat_sys_statfs(const char __user *path, struct compat_statfs
error = user_path_walk(path, &nd);
if (!error) {
struct kstatfs tmp;
- error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
+ error = vfs_statfs(nd.dentry, &tmp);
if (!error)
error = put_compat_statfs(buf, &tmp);
path_release(&nd);
@@ -215,7 +215,7 @@ asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
+ error = vfs_statfs(file->f_dentry, &tmp);
if (!error)
error = put_compat_statfs(buf, &tmp);
fput(file);
@@ -265,7 +265,7 @@ asmlinkage long compat_sys_statfs64(const char __user *path, compat_size_t sz, s
error = user_path_walk(path, &nd);
if (!error) {
struct kstatfs tmp;
- error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
+ error = vfs_statfs(nd.dentry, &tmp);
if (!error)
error = put_compat_statfs64(buf, &tmp);
path_release(&nd);
@@ -286,7 +286,7 @@ asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct c
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
+ error = vfs_statfs(file->f_dentry, &tmp);
if (!error)
error = put_compat_statfs64(buf, &tmp);
fput(file);
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index d2c3887..9eb9824 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -205,38 +205,6 @@ static int do_ext3_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
return sys_ioctl(fd, cmd, (unsigned long)compat_ptr(arg));
}
-struct compat_dmx_event {
- dmx_event_t event;
- compat_time_t timeStamp;
- union
- {
- dmx_scrambling_status_t scrambling;
- } u;
-};
-
-static int do_dmx_get_event(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- struct dmx_event kevent;
- mm_segment_t old_fs = get_fs();
- int err;
-
- set_fs(KERNEL_DS);
- err = sys_ioctl(fd, cmd, (unsigned long) &kevent);
- set_fs(old_fs);
-
- if (!err) {
- struct compat_dmx_event __user *up = compat_ptr(arg);
-
- err = put_user(kevent.event, &up->event);
- err |= put_user(kevent.timeStamp, &up->timeStamp);
- err |= put_user(kevent.u.scrambling, &up->u.scrambling);
- if (err)
- err = -EFAULT;
- }
-
- return err;
-}
-
struct compat_video_event {
int32_t type;
compat_time_t timestamp;
@@ -2964,7 +2932,6 @@ HANDLE_IOCTL(NCP_IOC_SETPRIVATEDATA_32, do_ncp_setprivatedata)
#endif
/* dvb */
-HANDLE_IOCTL(DMX_GET_EVENT, do_dmx_get_event)
HANDLE_IOCTL(VIDEO_GET_EVENT, do_video_get_event)
HANDLE_IOCTL(VIDEO_STILLPICTURE, do_video_stillpicture)
HANDLE_IOCTL(VIDEO_SET_SPU_PALETTE, do_video_set_spu_palette)
diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c
index f920d30..3e5fe84 100644
--- a/fs/configfs/mount.c
+++ b/fs/configfs/mount.c
@@ -103,10 +103,10 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent)
return 0;
}
-static struct super_block *configfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int configfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, configfs_fill_super);
+ return get_sb_single(fs_type, flags, data, configfs_fill_super, mnt);
}
static struct file_system_type configfs_fs_type = {
@@ -118,7 +118,7 @@ static struct file_system_type configfs_fs_type = {
int configfs_pin_fs(void)
{
- return simple_pin_fs("configfs", &configfs_mount,
+ return simple_pin_fs(&configfs_fs_type, &configfs_mount,
&configfs_mnt_count);
}
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 9efcc3a..c45d738 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -181,9 +181,7 @@ static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned i
struct page *page = NULL;
if (blocknr + i < devsize) {
- page = read_cache_page(mapping, blocknr + i,
- (filler_t *)mapping->a_ops->readpage,
- NULL);
+ page = read_mapping_page(mapping, blocknr + i, NULL);
/* synchronous error? */
if (IS_ERR(page))
page = NULL;
@@ -322,8 +320,10 @@ out:
return -EINVAL;
}
-static int cramfs_statfs(struct super_block *sb, struct kstatfs *buf)
+static int cramfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
+ struct super_block *sb = dentry->d_sb;
+
buf->f_type = CRAMFS_MAGIC;
buf->f_bsize = PAGE_CACHE_SIZE;
buf->f_blocks = CRAMFS_SB(sb)->blocks;
@@ -528,10 +528,11 @@ static struct super_operations cramfs_ops = {
.statfs = cramfs_statfs,
};
-static struct super_block *cramfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int cramfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, cramfs_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, cramfs_fill_super,
+ mnt);
}
static struct file_system_type cramfs_fs_type = {
diff --git a/fs/dcache.c b/fs/dcache.c
index 940d188..b85fda3 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -359,12 +359,13 @@ restart:
}
/*
- * Throw away a dentry - free the inode, dput the parent.
- * This requires that the LRU list has already been
- * removed.
+ * Throw away a dentry - free the inode, dput the parent. This requires that
+ * the LRU list has already been removed.
+ *
* Called with dcache_lock, drops it and then regains.
+ * Called with dentry->d_lock held, drops it.
*/
-static inline void prune_one_dentry(struct dentry * dentry)
+static void prune_one_dentry(struct dentry * dentry)
{
struct dentry * parent;
@@ -382,6 +383,8 @@ static inline void prune_one_dentry(struct dentry * dentry)
/**
* prune_dcache - shrink the dcache
* @count: number of entries to try and free
+ * @sb: if given, ignore dentries for other superblocks
+ * which are being unmounted.
*
* Shrink the dcache. This is done when we need
* more memory, or simply when we need to unmount
@@ -392,16 +395,29 @@ static inline void prune_one_dentry(struct dentry * dentry)
* all the dentries are in use.
*/
-static void prune_dcache(int count)
+static void prune_dcache(int count, struct super_block *sb)
{
spin_lock(&dcache_lock);
for (; count ; count--) {
struct dentry *dentry;
struct list_head *tmp;
+ struct rw_semaphore *s_umount;
cond_resched_lock(&dcache_lock);
tmp = dentry_unused.prev;
+ if (sb) {
+ /* Try to find a dentry for this sb, but don't try
+ * too hard, if they aren't near the tail they will
+ * be moved down again soon
+ */
+ int skip = count;
+ while (skip && tmp != &dentry_unused &&
+ list_entry(tmp, struct dentry, d_lru)->d_sb != sb) {
+ skip--;
+ tmp = tmp->prev;
+ }
+ }
if (tmp == &dentry_unused)
break;
list_del_init(tmp);
@@ -427,7 +443,45 @@ static void prune_dcache(int count)
spin_unlock(&dentry->d_lock);
continue;
}
- prune_one_dentry(dentry);
+ /*
+ * If the dentry is not DCACHED_REFERENCED, it is time
+ * to remove it from the dcache, provided the super block is
+ * NULL (which means we are trying to reclaim memory)
+ * or this dentry belongs to the same super block that
+ * we want to shrink.
+ */
+ /*
+ * If this dentry is for "my" filesystem, then I can prune it
+ * without taking the s_umount lock (I already hold it).
+ */
+ if (sb && dentry->d_sb == sb) {
+ prune_one_dentry(dentry);
+ continue;
+ }
+ /*
+ * ...otherwise we need to be sure this filesystem isn't being
+ * unmounted, otherwise we could race with
+ * generic_shutdown_super(), and end up holding a reference to
+ * an inode while the filesystem is unmounted.
+ * So we try to get s_umount, and make sure s_root isn't NULL.
+ * (Take a local copy of s_umount to avoid a use-after-free of
+ * `dentry').
+ */
+ s_umount = &dentry->d_sb->s_umount;
+ if (down_read_trylock(s_umount)) {
+ if (dentry->d_sb->s_root != NULL) {
+ prune_one_dentry(dentry);
+ up_read(s_umount);
+ continue;
+ }
+ up_read(s_umount);
+ }
+ spin_unlock(&dentry->d_lock);
+ /* Cannot remove the first dentry, and it isn't appropriate
+ * to move it to the head of the list, so give up, and try
+ * later
+ */
+ break;
}
spin_unlock(&dcache_lock);
}
@@ -630,46 +684,7 @@ void shrink_dcache_parent(struct dentry * parent)
int found;
while ((found = select_parent(parent)) != 0)
- prune_dcache(found);
-}
-
-/**
- * shrink_dcache_anon - further prune the cache
- * @head: head of d_hash list of dentries to prune
- *
- * Prune the dentries that are anonymous
- *
- * parsing d_hash list does not hlist_for_each_entry_rcu() as it
- * done under dcache_lock.
- *
- */
-void shrink_dcache_anon(struct hlist_head *head)
-{
- struct hlist_node *lp;
- int found;
- do {
- found = 0;
- spin_lock(&dcache_lock);
- hlist_for_each(lp, head) {
- struct dentry *this = hlist_entry(lp, struct dentry, d_hash);
- if (!list_empty(&this->d_lru)) {
- dentry_stat.nr_unused--;
- list_del_init(&this->d_lru);
- }
-
- /*
- * move only zero ref count dentries to the end
- * of the unused list for prune_dcache
- */
- if (!atomic_read(&this->d_count)) {
- list_add_tail(&this->d_lru, &dentry_unused);
- dentry_stat.nr_unused++;
- found++;
- }
- }
- spin_unlock(&dcache_lock);
- prune_dcache(found);
- } while(found);
+ prune_dcache(found, parent->d_sb);
}
/*
@@ -689,7 +704,7 @@ static int shrink_dcache_memory(int nr, gfp_t gfp_mask)
if (nr) {
if (!(gfp_mask & __GFP_FS))
return -1;
- prune_dcache(nr);
+ prune_dcache(nr, NULL);
}
return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure;
}
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index b55b4ea..6fa1e04 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -111,11 +111,11 @@ static int debug_fill_super(struct super_block *sb, void *data, int silent)
return simple_fill_super(sb, DEBUGFS_MAGIC, debug_files);
}
-static struct super_block *debug_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data)
+static int debug_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data, struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, debug_fill_super);
+ return get_sb_single(fs_type, flags, data, debug_fill_super, mnt);
}
static struct file_system_type debug_fs_type = {
@@ -199,7 +199,7 @@ struct dentry *debugfs_create_file(const char *name, mode_t mode,
pr_debug("debugfs: creating file '%s'\n",name);
- error = simple_pin_fs("debugfs", &debugfs_mount, &debugfs_mount_count);
+ error = simple_pin_fs(&debug_fs_type, &debugfs_mount, &debugfs_mount_count);
if (error)
goto exit;
diff --git a/fs/devfs/base.c b/fs/devfs/base.c
index 52f5059..51a97f1 100644
--- a/fs/devfs/base.c
+++ b/fs/devfs/base.c
@@ -2549,11 +2549,11 @@ static int devfs_fill_super(struct super_block *sb, void *data, int silent)
return -EINVAL;
} /* End Function devfs_fill_super */
-static struct super_block *devfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data)
+static int devfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data, struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, devfs_fill_super);
+ return get_sb_single(fs_type, flags, data, devfs_fill_super, mnt);
}
static struct file_system_type devfs_fs_type = {
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 14c5620..f7aef5b 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -130,10 +130,10 @@ fail:
return -ENOMEM;
}
-static struct super_block *devpts_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int devpts_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, devpts_fill_super);
+ return get_sb_single(fs_type, flags, data, devpts_fill_super, mnt);
}
static struct file_system_type devpts_fs_type = {
diff --git a/fs/direct-io.c b/fs/direct-io.c
index b05d1b2..538fb04 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -162,7 +162,7 @@ static int dio_refill_pages(struct dio *dio)
NULL); /* vmas */
up_read(&current->mm->mmap_sem);
- if (ret < 0 && dio->blocks_available && (dio->rw == WRITE)) {
+ if (ret < 0 && dio->blocks_available && (dio->rw & WRITE)) {
struct page *page = ZERO_PAGE(dio->curr_user_address);
/*
* A memory fault, but the filesystem has some outstanding
@@ -535,7 +535,7 @@ static int get_more_blocks(struct dio *dio)
map_bh->b_state = 0;
map_bh->b_size = fs_count << dio->inode->i_blkbits;
- create = dio->rw == WRITE;
+ create = dio->rw & WRITE;
if (dio->lock_type == DIO_LOCKING) {
if (dio->block_in_file < (i_size_read(dio->inode) >>
dio->blkbits))
@@ -867,7 +867,7 @@ do_holes:
loff_t i_size_aligned;
/* AKPM: eargh, -ENOTBLK is a hack */
- if (dio->rw == WRITE) {
+ if (dio->rw & WRITE) {
page_cache_release(page);
return -ENOTBLK;
}
@@ -1045,7 +1045,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
}
} /* end iovec loop */
- if (ret == -ENOTBLK && rw == WRITE) {
+ if (ret == -ENOTBLK && (rw & WRITE)) {
/*
* The remaining part of the request will be
* be handled by buffered I/O when we return
@@ -1089,7 +1089,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
if (dio->is_async) {
int should_wait = 0;
- if (dio->result < dio->size && rw == WRITE) {
+ if (dio->result < dio->size && (rw & WRITE)) {
dio->waiter = current;
should_wait = 1;
}
@@ -1142,7 +1142,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
ret = transferred;
/* We could have also come here on an AIO file extend */
- if (!is_sync_kiocb(iocb) && rw == WRITE &&
+ if (!is_sync_kiocb(iocb) && (rw & WRITE) &&
ret >= 0 && dio->result == dio->size)
/*
* For AIO writes where we have completed the
@@ -1194,7 +1194,7 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
int acquire_i_mutex = 0;
if (rw & WRITE)
- current->flags |= PF_SYNCWRITE;
+ rw = WRITE_SYNC;
if (bdev)
bdev_blkbits = blksize_bits(bdev_hardsect_size(bdev));
@@ -1270,7 +1270,7 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
* even for AIO, we need to wait for i/o to complete before
* returning in this case.
*/
- dio->is_async = !is_sync_kiocb(iocb) && !((rw == WRITE) &&
+ dio->is_async = !is_sync_kiocb(iocb) && !((rw & WRITE) &&
(end > i_size_read(inode)));
retval = direct_io_worker(rw, iocb, inode, iov, offset,
@@ -1284,8 +1284,6 @@ out:
mutex_unlock(&inode->i_mutex);
else if (acquire_i_mutex)
mutex_lock(&inode->i_mutex);
- if (rw & WRITE)
- current->flags &= ~PF_SYNCWRITE;
return retval;
}
EXPORT_SYMBOL(__blockdev_direct_IO);
diff --git a/fs/efs/super.c b/fs/efs/super.c
index dff623e..8ac2462 100644
--- a/fs/efs/super.c
+++ b/fs/efs/super.c
@@ -15,13 +15,13 @@
#include <linux/buffer_head.h>
#include <linux/vfs.h>
-static int efs_statfs(struct super_block *s, struct kstatfs *buf);
+static int efs_statfs(struct dentry *dentry, struct kstatfs *buf);
static int efs_fill_super(struct super_block *s, void *d, int silent);
-static struct super_block *efs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int efs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, efs_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, efs_fill_super, mnt);
}
static struct file_system_type efs_fs_type = {
@@ -322,8 +322,8 @@ out_no_fs:
return -EINVAL;
}
-static int efs_statfs(struct super_block *s, struct kstatfs *buf) {
- struct efs_sb_info *sb = SUPER_INFO(s);
+static int efs_statfs(struct dentry *dentry, struct kstatfs *buf) {
+ struct efs_sb_info *sb = SUPER_INFO(dentry->d_sb);
buf->f_type = EFS_SUPER_MAGIC; /* efs magic number */
buf->f_bsize = EFS_BLOCKSIZE; /* blocksize */
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 2695337..9c677bb 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -1,6 +1,6 @@
/*
* fs/eventpoll.c ( Efficent event polling implementation )
- * Copyright (C) 2001,...,2003 Davide Libenzi
+ * Copyright (C) 2001,...,2006 Davide Libenzi
*
* 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
@@ -268,9 +268,9 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
int maxevents, long timeout);
static int eventpollfs_delete_dentry(struct dentry *dentry);
static struct inode *ep_eventpoll_inode(void);
-static struct super_block *eventpollfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data);
+static int eventpollfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data, struct vfsmount *mnt);
/*
* This semaphore is used to serialize ep_free() and eventpoll_release_file().
@@ -1004,7 +1004,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
/* Notify waiting tasks that events are available */
if (waitqueue_active(&ep->wq))
- wake_up(&ep->wq);
+ __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE);
if (waitqueue_active(&ep->poll_wait))
pwake++;
}
@@ -1083,7 +1083,8 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
/* Notify waiting tasks that events are available */
if (waitqueue_active(&ep->wq))
- wake_up(&ep->wq);
+ __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
+ TASK_INTERRUPTIBLE);
if (waitqueue_active(&ep->poll_wait))
pwake++;
}
@@ -1260,7 +1261,8 @@ is_linked:
* wait list.
*/
if (waitqueue_active(&ep->wq))
- wake_up(&ep->wq);
+ __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
+ TASK_INTERRUPTIBLE);
if (waitqueue_active(&ep->poll_wait))
pwake++;
@@ -1444,7 +1446,8 @@ static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist)
* wait list.
*/
if (waitqueue_active(&ep->wq))
- wake_up(&ep->wq);
+ __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
+ TASK_INTERRUPTIBLE);
if (waitqueue_active(&ep->poll_wait))
pwake++;
}
@@ -1516,7 +1519,7 @@ retry:
* ep_poll_callback() when events will become available.
*/
init_waitqueue_entry(&wait, current);
- add_wait_queue(&ep->wq, &wait);
+ __add_wait_queue(&ep->wq, &wait);
for (;;) {
/*
@@ -1536,7 +1539,7 @@ retry:
jtimeout = schedule_timeout(jtimeout);
write_lock_irqsave(&ep->lock, flags);
}
- remove_wait_queue(&ep->wq, &wait);
+ __remove_wait_queue(&ep->wq, &wait);
set_current_state(TASK_RUNNING);
}
@@ -1595,11 +1598,12 @@ eexit_1:
}
-static struct super_block *
+static int
eventpollfs_get_sb(struct file_system_type *fs_type, int flags,
- const char *dev_name, void *data)
+ const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_pseudo(fs_type, "eventpoll:", NULL, EVENTPOLLFS_MAGIC);
+ return get_sb_pseudo(fs_type, "eventpoll:", NULL, EVENTPOLLFS_MAGIC,
+ mnt);
}
diff --git a/fs/exec.c b/fs/exec.c
index d07858c..0b88bf6 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -866,7 +866,6 @@ int flush_old_exec(struct linux_binprm * bprm)
bprm->mm = NULL; /* We're using it now */
/* This is the point of no return */
- steal_locks(files);
put_files_struct(files);
current->sas_ss_sp = current->sas_ss_size = 0;
diff --git a/fs/ext2/Makefile b/fs/ext2/Makefile
index c5d02da..e0b2b43 100644
--- a/fs/ext2/Makefile
+++ b/fs/ext2/Makefile
@@ -4,7 +4,7 @@
obj-$(CONFIG_EXT2_FS) += ext2.o
-ext2-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
+ext2-y := balloc.o dir.o file.o fsync.o ialloc.o inode.o \
ioctl.o namei.o super.o symlink.o
ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 2c00953..433a213 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -521,6 +521,26 @@ io_error:
goto out_release;
}
+#ifdef EXT2FS_DEBUG
+
+static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
+
+unsigned long ext2_count_free (struct buffer_head * map, unsigned int numchars)
+{
+ unsigned int i;
+ unsigned long sum = 0;
+
+ if (!map)
+ return (0);
+ for (i = 0; i < numchars; i++)
+ sum += nibblemap[map->b_data[i] & 0xf] +
+ nibblemap[(map->b_data[i] >> 4) & 0xf];
+ return (sum);
+}
+
+#endif /* EXT2FS_DEBUG */
+
+/* Superblock must be locked */
unsigned long ext2_count_free_blocks (struct super_block * sb)
{
struct ext2_group_desc * desc;
@@ -530,7 +550,6 @@ unsigned long ext2_count_free_blocks (struct super_block * sb)
unsigned long bitmap_count, x;
struct ext2_super_block *es;
- lock_super (sb);
es = EXT2_SB(sb)->s_es;
desc_count = 0;
bitmap_count = 0;
@@ -554,7 +573,6 @@ unsigned long ext2_count_free_blocks (struct super_block * sb)
printk("ext2_count_free_blocks: stored = %lu, computed = %lu, %lu\n",
(long)le32_to_cpu(es->s_free_blocks_count),
desc_count, bitmap_count);
- unlock_super (sb);
return bitmap_count;
#else
for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) {
diff --git a/fs/ext2/bitmap.c b/fs/ext2/bitmap.c
deleted file mode 100644
index e9983a0..0000000
--- a/fs/ext2/bitmap.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * linux/fs/ext2/bitmap.c
- *
- * Copyright (C) 1992, 1993, 1994, 1995
- * Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
- */
-
-#ifdef EXT2FS_DEBUG
-
-#include <linux/buffer_head.h>
-
-#include "ext2.h"
-
-static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
-
-unsigned long ext2_count_free (struct buffer_head * map, unsigned int numchars)
-{
- unsigned int i;
- unsigned long sum = 0;
-
- if (!map)
- return (0);
- for (i = 0; i < numchars; i++)
- sum += nibblemap[map->b_data[i] & 0xf] +
- nibblemap[(map->b_data[i] >> 4) & 0xf];
- return (sum);
-}
-
-#endif /* EXT2FS_DEBUG */
-
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index d672aa9..92ea826 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -159,8 +159,7 @@ fail:
static struct page * ext2_get_page(struct inode *dir, unsigned long n)
{
struct address_space *mapping = dir->i_mapping;
- struct page *page = read_cache_page(mapping, n,
- (filler_t*)mapping->a_ops->readpage, NULL);
+ struct page *page = read_mapping_page(mapping, n, NULL);
if (!IS_ERR(page)) {
wait_on_page_locked(page);
kmap(page);
@@ -400,8 +399,7 @@ ino_t ext2_inode_by_name(struct inode * dir, struct dentry *dentry)
de = ext2_find_entry (dir, dentry, &page);
if (de) {
res = le32_to_cpu(de->inode);
- kunmap(page);
- page_cache_release(page);
+ ext2_put_page(page);
}
return res;
}
diff --git a/fs/ext2/fsync.c b/fs/ext2/fsync.c
index c9c2e5f..7806b9e 100644
--- a/fs/ext2/fsync.c
+++ b/fs/ext2/fsync.c
@@ -24,7 +24,7 @@
#include "ext2.h"
#include <linux/smp_lock.h>
-#include <linux/buffer_head.h> /* for fsync_inode_buffers() */
+#include <linux/buffer_head.h> /* for sync_mapping_buffers() */
/*
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index e527652..308c252 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -638,6 +638,7 @@ fail:
return ERR_PTR(err);
}
+/* Superblock must be locked */
unsigned long ext2_count_free_inodes (struct super_block * sb)
{
struct ext2_group_desc *desc;
@@ -649,7 +650,6 @@ unsigned long ext2_count_free_inodes (struct super_block * sb)
unsigned long bitmap_count = 0;
struct buffer_head *bitmap_bh = NULL;
- lock_super (sb);
es = EXT2_SB(sb)->s_es;
for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) {
unsigned x;
@@ -672,7 +672,6 @@ unsigned long ext2_count_free_inodes (struct super_block * sb)
printk("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n",
percpu_counter_read(&EXT2_SB(sb)->s_freeinodes_counter),
desc_count, bitmap_count);
- unlock_super(sb);
return desc_count;
#else
for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) {
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 7e30bae..d4233b2 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -39,7 +39,7 @@
static void ext2_sync_super(struct super_block *sb,
struct ext2_super_block *es);
static int ext2_remount (struct super_block * sb, int * flags, char * data);
-static int ext2_statfs (struct super_block * sb, struct kstatfs * buf);
+static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf);
void ext2_error (struct super_block * sb, const char * function,
const char * fmt, ...)
@@ -834,9 +834,6 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
printk ("EXT2-fs: not enough memory\n");
goto failed_mount;
}
- percpu_counter_init(&sbi->s_freeblocks_counter);
- percpu_counter_init(&sbi->s_freeinodes_counter);
- percpu_counter_init(&sbi->s_dirs_counter);
bgl_lock_init(&sbi->s_blockgroup_lock);
sbi->s_debts = kmalloc(sbi->s_groups_count * sizeof(*sbi->s_debts),
GFP_KERNEL);
@@ -857,12 +854,18 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
}
if (!ext2_check_descriptors (sb)) {
printk ("EXT2-fs: group descriptors corrupted!\n");
- db_count = i;
goto failed_mount2;
}
sbi->s_gdb_count = db_count;
get_random_bytes(&sbi->s_next_generation, sizeof(u32));
spin_lock_init(&sbi->s_next_gen_lock);
+
+ percpu_counter_init(&sbi->s_freeblocks_counter,
+ ext2_count_free_blocks(sb));
+ percpu_counter_init(&sbi->s_freeinodes_counter,
+ ext2_count_free_inodes(sb));
+ percpu_counter_init(&sbi->s_dirs_counter,
+ ext2_count_dirs(sb));
/*
* set up enough so that it can read an inode
*/
@@ -874,24 +877,18 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
if (!sb->s_root) {
iput(root);
printk(KERN_ERR "EXT2-fs: get root inode failed\n");
- goto failed_mount2;
+ goto failed_mount3;
}
if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
dput(sb->s_root);
sb->s_root = NULL;
printk(KERN_ERR "EXT2-fs: corrupt root inode, run e2fsck\n");
- goto failed_mount2;
+ goto failed_mount3;
}
if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL))
ext2_warning(sb, __FUNCTION__,
"mounting ext3 filesystem as ext2");
ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY);
- percpu_counter_mod(&sbi->s_freeblocks_counter,
- ext2_count_free_blocks(sb));
- percpu_counter_mod(&sbi->s_freeinodes_counter,
- ext2_count_free_inodes(sb));
- percpu_counter_mod(&sbi->s_dirs_counter,
- ext2_count_dirs(sb));
return 0;
cantfind_ext2:
@@ -899,7 +896,10 @@ cantfind_ext2:
printk("VFS: Can't find an ext2 filesystem on dev %s.\n",
sb->s_id);
goto failed_mount;
-
+failed_mount3:
+ percpu_counter_destroy(&sbi->s_freeblocks_counter);
+ percpu_counter_destroy(&sbi->s_freeinodes_counter);
+ percpu_counter_destroy(&sbi->s_dirs_counter);
failed_mount2:
for (i = 0; i < db_count; i++)
brelse(sbi->s_group_desc[i]);
@@ -1038,12 +1038,14 @@ restore_opts:
return err;
}
-static int ext2_statfs (struct super_block * sb, struct kstatfs * buf)
+static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf)
{
+ struct super_block *sb = dentry->d_sb;
struct ext2_sb_info *sbi = EXT2_SB(sb);
unsigned long overhead;
int i;
+ lock_super(sb);
if (test_opt (sb, MINIX_DF))
overhead = 0;
else {
@@ -1084,13 +1086,14 @@ static int ext2_statfs (struct super_block * sb, struct kstatfs * buf)
buf->f_files = le32_to_cpu(sbi->s_es->s_inodes_count);
buf->f_ffree = ext2_count_free_inodes (sb);
buf->f_namelen = EXT2_NAME_LEN;
+ unlock_super(sb);
return 0;
}
-static struct super_block *ext2_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int ext2_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, ext2_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, ext2_fill_super, mnt);
}
#ifdef CONFIG_QUOTA
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index 77927d6..96172e8 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -163,20 +163,19 @@ restart:
#endif
static int
-goal_in_my_reservation(struct ext3_reserve_window *rsv, int goal,
+goal_in_my_reservation(struct ext3_reserve_window *rsv, ext3_grpblk_t grp_goal,
unsigned int group, struct super_block * sb)
{
- unsigned long group_first_block, group_last_block;
+ ext3_fsblk_t group_first_block, group_last_block;
- group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
- group * EXT3_BLOCKS_PER_GROUP(sb);
+ group_first_block = ext3_group_first_block_no(sb, group);
group_last_block = group_first_block + EXT3_BLOCKS_PER_GROUP(sb) - 1;
if ((rsv->_rsv_start > group_last_block) ||
(rsv->_rsv_end < group_first_block))
return 0;
- if ((goal >= 0) && ((goal + group_first_block < rsv->_rsv_start)
- || (goal + group_first_block > rsv->_rsv_end)))
+ if ((grp_goal >= 0) && ((grp_goal + group_first_block < rsv->_rsv_start)
+ || (grp_goal + group_first_block > rsv->_rsv_end)))
return 0;
return 1;
}
@@ -187,7 +186,7 @@ goal_in_my_reservation(struct ext3_reserve_window *rsv, int goal,
* Returns NULL if there are no windows or if all windows start after the goal.
*/
static struct ext3_reserve_window_node *
-search_reserve_window(struct rb_root *root, unsigned long goal)
+search_reserve_window(struct rb_root *root, ext3_fsblk_t goal)
{
struct rb_node *n = root->rb_node;
struct ext3_reserve_window_node *rsv;
@@ -223,7 +222,7 @@ void ext3_rsv_window_add(struct super_block *sb,
{
struct rb_root *root = &EXT3_SB(sb)->s_rsv_window_root;
struct rb_node *node = &rsv->rsv_node;
- unsigned int start = rsv->rsv_start;
+ ext3_fsblk_t start = rsv->rsv_start;
struct rb_node ** p = &root->rb_node;
struct rb_node * parent = NULL;
@@ -310,20 +309,20 @@ void ext3_discard_reservation(struct inode *inode)
/* Free given blocks, update quota and i_blocks field */
void ext3_free_blocks_sb(handle_t *handle, struct super_block *sb,
- unsigned long block, unsigned long count,
- int *pdquot_freed_blocks)
+ ext3_fsblk_t block, unsigned long count,
+ unsigned long *pdquot_freed_blocks)
{
struct buffer_head *bitmap_bh = NULL;
struct buffer_head *gd_bh;
unsigned long block_group;
- unsigned long bit;
+ ext3_grpblk_t bit;
unsigned long i;
unsigned long overflow;
struct ext3_group_desc * desc;
struct ext3_super_block * es;
struct ext3_sb_info *sbi;
int err = 0, ret;
- unsigned group_freed;
+ ext3_grpblk_t group_freed;
*pdquot_freed_blocks = 0;
sbi = EXT3_SB(sb);
@@ -333,7 +332,7 @@ void ext3_free_blocks_sb(handle_t *handle, struct super_block *sb,
block + count > le32_to_cpu(es->s_blocks_count)) {
ext3_error (sb, "ext3_free_blocks",
"Freeing blocks not in datazone - "
- "block = %lu, count = %lu", block, count);
+ "block = "E3FSBLK", count = %lu", block, count);
goto error_return;
}
@@ -369,7 +368,7 @@ do_more:
sbi->s_itb_per_group))
ext3_error (sb, "ext3_free_blocks",
"Freeing blocks in system zones - "
- "Block = %lu, count = %lu",
+ "Block = "E3FSBLK", count = %lu",
block, count);
/*
@@ -453,7 +452,8 @@ do_more:
bit + i, bitmap_bh->b_data)) {
jbd_unlock_bh_state(bitmap_bh);
ext3_error(sb, __FUNCTION__,
- "bit already cleared for block %lu", block + i);
+ "bit already cleared for block "E3FSBLK,
+ block + i);
jbd_lock_bh_state(bitmap_bh);
BUFFER_TRACE(bitmap_bh, "bit already cleared");
} else {
@@ -493,10 +493,10 @@ error_return:
/* Free given blocks, update quota and i_blocks field */
void ext3_free_blocks(handle_t *handle, struct inode *inode,
- unsigned long block, unsigned long count)
+ ext3_fsblk_t block, unsigned long count)
{
struct super_block * sb;
- int dquot_freed_blocks;
+ unsigned long dquot_freed_blocks;
sb = inode->i_sb;
if (!sb) {
@@ -525,7 +525,7 @@ void ext3_free_blocks(handle_t *handle, struct inode *inode,
* data-writes at some point, and disable it for metadata allocations or
* sync-data inodes.
*/
-static int ext3_test_allocatable(int nr, struct buffer_head *bh)
+static int ext3_test_allocatable(ext3_grpblk_t nr, struct buffer_head *bh)
{
int ret;
struct journal_head *jh = bh2jh(bh);
@@ -542,11 +542,11 @@ static int ext3_test_allocatable(int nr, struct buffer_head *bh)
return ret;
}
-static int
-bitmap_search_next_usable_block(int start, struct buffer_head *bh,
- int maxblocks)
+static ext3_grpblk_t
+bitmap_search_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh,
+ ext3_grpblk_t maxblocks)
{
- int next;
+ ext3_grpblk_t next;
struct journal_head *jh = bh2jh(bh);
/*
@@ -576,10 +576,11 @@ bitmap_search_next_usable_block(int start, struct buffer_head *bh,
* the initial goal; then for a free byte somewhere in the bitmap; then
* for any free bit in the bitmap.
*/
-static int
-find_next_usable_block(int start, struct buffer_head *bh, int maxblocks)
+static ext3_grpblk_t
+find_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh,
+ ext3_grpblk_t maxblocks)
{
- int here, next;
+ ext3_grpblk_t here, next;
char *p, *r;
if (start > 0) {
@@ -591,7 +592,7 @@ find_next_usable_block(int start, struct buffer_head *bh, int maxblocks)
* less than EXT3_BLOCKS_PER_GROUP. Aligning up to the
* next 64-bit boundary is simple..
*/
- int end_goal = (start + 63) & ~63;
+ ext3_grpblk_t end_goal = (start + 63) & ~63;
if (end_goal > maxblocks)
end_goal = maxblocks;
here = ext3_find_next_zero_bit(bh->b_data, end_goal, start);
@@ -628,7 +629,7 @@ find_next_usable_block(int start, struct buffer_head *bh, int maxblocks)
* zero (failure).
*/
static inline int
-claim_block(spinlock_t *lock, int block, struct buffer_head *bh)
+claim_block(spinlock_t *lock, ext3_grpblk_t block, struct buffer_head *bh)
{
struct journal_head *jh = bh2jh(bh);
int ret;
@@ -651,19 +652,18 @@ claim_block(spinlock_t *lock, int block, struct buffer_head *bh)
* new bitmap. In that case we must release write access to the old one via
* ext3_journal_release_buffer(), else we'll run out of credits.
*/
-static int
+static ext3_grpblk_t
ext3_try_to_allocate(struct super_block *sb, handle_t *handle, int group,
- struct buffer_head *bitmap_bh, int goal,
+ struct buffer_head *bitmap_bh, ext3_grpblk_t grp_goal,
unsigned long *count, struct ext3_reserve_window *my_rsv)
{
- int group_first_block, start, end;
+ ext3_fsblk_t group_first_block;
+ ext3_grpblk_t start, end;
unsigned long num = 0;
/* we do allocation within the reservation window if we have a window */
if (my_rsv) {
- group_first_block =
- le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
- group * EXT3_BLOCKS_PER_GROUP(sb);
+ group_first_block = ext3_group_first_block_no(sb, group);
if (my_rsv->_rsv_start >= group_first_block)
start = my_rsv->_rsv_start - group_first_block;
else
@@ -673,13 +673,13 @@ ext3_try_to_allocate(struct super_block *sb, handle_t *handle, int group,
if (end > EXT3_BLOCKS_PER_GROUP(sb))
/* reservation window crosses group boundary */
end = EXT3_BLOCKS_PER_GROUP(sb);
- if ((start <= goal) && (goal < end))
- start = goal;
+ if ((start <= grp_goal) && (grp_goal < end))
+ start = grp_goal;
else
- goal = -1;
+ grp_goal = -1;
} else {
- if (goal > 0)
- start = goal;
+ if (grp_goal > 0)
+ start = grp_goal;
else
start = 0;
end = EXT3_BLOCKS_PER_GROUP(sb);
@@ -688,43 +688,43 @@ ext3_try_to_allocate(struct super_block *sb, handle_t *handle, int group,
BUG_ON(start > EXT3_BLOCKS_PER_GROUP(sb));
repeat:
- if (goal < 0 || !ext3_test_allocatable(goal, bitmap_bh)) {
- goal = find_next_usable_block(start, bitmap_bh, end);
- if (goal < 0)
+ if (grp_goal < 0 || !ext3_test_allocatable(grp_goal, bitmap_bh)) {
+ grp_goal = find_next_usable_block(start, bitmap_bh, end);
+ if (grp_goal < 0)
goto fail_access;
if (!my_rsv) {
int i;
- for (i = 0; i < 7 && goal > start &&
- ext3_test_allocatable(goal - 1,
+ for (i = 0; i < 7 && grp_goal > start &&
+ ext3_test_allocatable(grp_goal - 1,
bitmap_bh);
- i++, goal--)
+ i++, grp_goal--)
;
}
}
- start = goal;
+ start = grp_goal;
- if (!claim_block(sb_bgl_lock(EXT3_SB(sb), group), goal, bitmap_bh)) {
+ if (!claim_block(sb_bgl_lock(EXT3_SB(sb), group), grp_goal, bitmap_bh)) {
/*
* The block was allocated by another thread, or it was
* allocated and then freed by another thread
*/
start++;
- goal++;
+ grp_goal++;
if (start >= end)
goto fail_access;
goto repeat;
}
num++;
- goal++;
- while (num < *count && goal < end
- && ext3_test_allocatable(goal, bitmap_bh)
- && claim_block(sb_bgl_lock(EXT3_SB(sb), group), goal, bitmap_bh)) {
+ grp_goal++;
+ while (num < *count && grp_goal < end
+ && ext3_test_allocatable(grp_goal, bitmap_bh)
+ && claim_block(sb_bgl_lock(EXT3_SB(sb), group), grp_goal, bitmap_bh)) {
num++;
- goal++;
+ grp_goal++;
}
*count = num;
- return goal - num;
+ return grp_goal - num;
fail_access:
*count = num;
return -1;
@@ -766,12 +766,13 @@ fail_access:
static int find_next_reservable_window(
struct ext3_reserve_window_node *search_head,
struct ext3_reserve_window_node *my_rsv,
- struct super_block * sb, int start_block,
- int last_block)
+ struct super_block * sb,
+ ext3_fsblk_t start_block,
+ ext3_fsblk_t last_block)
{
struct rb_node *next;
struct ext3_reserve_window_node *rsv, *prev;
- int cur;
+ ext3_fsblk_t cur;
int size = my_rsv->rsv_goal_size;
/* TODO: make the start of the reservation window byte-aligned */
@@ -873,10 +874,10 @@ static int find_next_reservable_window(
*
* @rsv: the reservation
*
- * @goal: The goal (group-relative). It is where the search for a
+ * @grp_goal: The goal (group-relative). It is where the search for a
* free reservable space should start from.
- * if we have a goal(goal >0 ), then start from there,
- * no goal(goal = -1), we start from the first block
+ * if we have a grp_goal(grp_goal >0 ), then start from there,
+ * no grp_goal(grp_goal = -1), we start from the first block
* of the group.
*
* @sb: the super block
@@ -885,25 +886,24 @@ static int find_next_reservable_window(
*
*/
static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv,
- int goal, struct super_block *sb,
+ ext3_grpblk_t grp_goal, struct super_block *sb,
unsigned int group, struct buffer_head *bitmap_bh)
{
struct ext3_reserve_window_node *search_head;
- int group_first_block, group_end_block, start_block;
- int first_free_block;
+ ext3_fsblk_t group_first_block, group_end_block, start_block;
+ ext3_grpblk_t first_free_block;
struct rb_root *fs_rsv_root = &EXT3_SB(sb)->s_rsv_window_root;
unsigned long size;
int ret;
spinlock_t *rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock;
- group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
- group * EXT3_BLOCKS_PER_GROUP(sb);
+ group_first_block = ext3_group_first_block_no(sb, group);
group_end_block = group_first_block + EXT3_BLOCKS_PER_GROUP(sb) - 1;
- if (goal < 0)
+ if (grp_goal < 0)
start_block = group_first_block;
else
- start_block = goal + group_first_block;
+ start_block = grp_goal + group_first_block;
size = my_rsv->rsv_goal_size;
@@ -1057,14 +1057,15 @@ static void try_to_extend_reservation(struct ext3_reserve_window_node *my_rsv,
* sorted double linked list should be fast.
*
*/
-static int
+static ext3_grpblk_t
ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
unsigned int group, struct buffer_head *bitmap_bh,
- int goal, struct ext3_reserve_window_node * my_rsv,
+ ext3_grpblk_t grp_goal,
+ struct ext3_reserve_window_node * my_rsv,
unsigned long *count, int *errp)
{
- unsigned long group_first_block;
- int ret = 0;
+ ext3_fsblk_t group_first_block;
+ ext3_grpblk_t ret = 0;
int fatal;
unsigned long num = *count;
@@ -1090,17 +1091,16 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
*/
if (my_rsv == NULL ) {
ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh,
- goal, count, NULL);
+ grp_goal, count, NULL);
goto out;
}
/*
- * goal is a group relative block number (if there is a goal)
- * 0 < goal < EXT3_BLOCKS_PER_GROUP(sb)
+ * grp_goal is a group relative block number (if there is a goal)
+ * 0 < grp_goal < EXT3_BLOCKS_PER_GROUP(sb)
* first block is a filesystem wide block number
* first block is the block number of the first block in this group
*/
- group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
- group * EXT3_BLOCKS_PER_GROUP(sb);
+ group_first_block = ext3_group_first_block_no(sb, group);
/*
* Basically we will allocate a new block from inode's reservation
@@ -1119,24 +1119,24 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
*/
while (1) {
if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) ||
- !goal_in_my_reservation(&my_rsv->rsv_window, goal, group, sb)) {
+ !goal_in_my_reservation(&my_rsv->rsv_window, grp_goal, group, sb)) {
if (my_rsv->rsv_goal_size < *count)
my_rsv->rsv_goal_size = *count;
- ret = alloc_new_reservation(my_rsv, goal, sb,
+ ret = alloc_new_reservation(my_rsv, grp_goal, sb,
group, bitmap_bh);
if (ret < 0)
break; /* failed */
- if (!goal_in_my_reservation(&my_rsv->rsv_window, goal, group, sb))
- goal = -1;
- } else if (goal > 0 && (my_rsv->rsv_end-goal+1) < *count)
+ if (!goal_in_my_reservation(&my_rsv->rsv_window, grp_goal, group, sb))
+ grp_goal = -1;
+ } else if (grp_goal > 0 && (my_rsv->rsv_end-grp_goal+1) < *count)
try_to_extend_reservation(my_rsv, sb,
- *count-my_rsv->rsv_end + goal - 1);
+ *count-my_rsv->rsv_end + grp_goal - 1);
if ((my_rsv->rsv_start >= group_first_block + EXT3_BLOCKS_PER_GROUP(sb))
|| (my_rsv->rsv_end < group_first_block))
BUG();
- ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal,
+ ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, grp_goal,
&num, &my_rsv->rsv_window);
if (ret >= 0) {
my_rsv->rsv_alloc_hit += num;
@@ -1164,7 +1164,7 @@ out:
static int ext3_has_free_blocks(struct ext3_sb_info *sbi)
{
- int free_blocks, root_blocks;
+ ext3_fsblk_t free_blocks, root_blocks;
free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count);
@@ -1200,19 +1200,20 @@ int ext3_should_retry_alloc(struct super_block *sb, int *retries)
* bitmap, and then for any free bit if that fails.
* This function also updates quota and i_blocks field.
*/
-int ext3_new_blocks(handle_t *handle, struct inode *inode,
- unsigned long goal, unsigned long *count, int *errp)
+ext3_fsblk_t ext3_new_blocks(handle_t *handle, struct inode *inode,
+ ext3_fsblk_t goal, unsigned long *count, int *errp)
{
struct buffer_head *bitmap_bh = NULL;
struct buffer_head *gdp_bh;
int group_no;
int goal_group;
- int ret_block;
+ ext3_grpblk_t grp_target_blk; /* blockgroup relative goal block */
+ ext3_grpblk_t grp_alloc_blk; /* blockgroup-relative allocated block*/
+ ext3_fsblk_t ret_block; /* filesyetem-wide allocated block */
int bgi; /* blockgroup iteration index */
- int target_block;
int fatal = 0, err;
int performed_allocation = 0;
- int free_blocks;
+ ext3_grpblk_t free_blocks; /* number of free blocks in a group */
struct super_block *sb;
struct ext3_group_desc *gdp;
struct ext3_super_block *es;
@@ -1285,16 +1286,17 @@ retry:
my_rsv = NULL;
if (free_blocks > 0) {
- ret_block = ((goal - le32_to_cpu(es->s_first_data_block)) %
+ grp_target_blk = ((goal - le32_to_cpu(es->s_first_data_block)) %
EXT3_BLOCKS_PER_GROUP(sb));
bitmap_bh = read_block_bitmap(sb, group_no);
if (!bitmap_bh)
goto io_error;
- ret_block = ext3_try_to_allocate_with_rsv(sb, handle, group_no,
- bitmap_bh, ret_block, my_rsv, &num, &fatal);
+ grp_alloc_blk = ext3_try_to_allocate_with_rsv(sb, handle,
+ group_no, bitmap_bh, grp_target_blk,
+ my_rsv, &num, &fatal);
if (fatal)
goto out;
- if (ret_block >= 0)
+ if (grp_alloc_blk >= 0)
goto allocated;
}
@@ -1327,11 +1329,15 @@ retry:
bitmap_bh = read_block_bitmap(sb, group_no);
if (!bitmap_bh)
goto io_error;
- ret_block = ext3_try_to_allocate_with_rsv(sb, handle, group_no,
- bitmap_bh, -1, my_rsv, &num, &fatal);
+ /*
+ * try to allocate block(s) from this group, without a goal(-1).
+ */
+ grp_alloc_blk = ext3_try_to_allocate_with_rsv(sb, handle,
+ group_no, bitmap_bh, -1, my_rsv,
+ &num, &fatal);
if (fatal)
goto out;
- if (ret_block >= 0)
+ if (grp_alloc_blk >= 0)
goto allocated;
}
/*
@@ -1360,18 +1366,18 @@ allocated:
if (fatal)
goto out;
- target_block = ret_block + group_no * EXT3_BLOCKS_PER_GROUP(sb)
- + le32_to_cpu(es->s_first_data_block);
+ ret_block = grp_alloc_blk + ext3_group_first_block_no(sb, group_no);
- if (in_range(le32_to_cpu(gdp->bg_block_bitmap), target_block, num) ||
- in_range(le32_to_cpu(gdp->bg_inode_bitmap), target_block, num) ||
- in_range(target_block, le32_to_cpu(gdp->bg_inode_table),
+ if (in_range(le32_to_cpu(gdp->bg_block_bitmap), ret_block, num) ||
+ in_range(le32_to_cpu(gdp->bg_inode_bitmap), ret_block, num) ||
+ in_range(ret_block, le32_to_cpu(gdp->bg_inode_table),
EXT3_SB(sb)->s_itb_per_group) ||
- in_range(target_block + num - 1, le32_to_cpu(gdp->bg_inode_table),
+ in_range(ret_block + num - 1, le32_to_cpu(gdp->bg_inode_table),
EXT3_SB(sb)->s_itb_per_group))
ext3_error(sb, "ext3_new_block",
"Allocating block in system zone - "
- "blocks from %u, length %lu", target_block, num);
+ "blocks from "E3FSBLK", length %lu",
+ ret_block, num);
performed_allocation = 1;
@@ -1380,7 +1386,7 @@ allocated:
struct buffer_head *debug_bh;
/* Record bitmap buffer state in the newly allocated block */
- debug_bh = sb_find_get_block(sb, target_block);
+ debug_bh = sb_find_get_block(sb, ret_block);
if (debug_bh) {
BUFFER_TRACE(debug_bh, "state when allocated");
BUFFER_TRACE2(debug_bh, bitmap_bh, "bitmap state");
@@ -1393,24 +1399,21 @@ allocated:
int i;
for (i = 0; i < num; i++) {
- if (ext3_test_bit(ret_block,
+ if (ext3_test_bit(grp_alloc_blk+i,
bh2jh(bitmap_bh)->b_committed_data)) {
printk("%s: block was unexpectedly set in "
"b_committed_data\n", __FUNCTION__);
}
}
}
- ext3_debug("found bit %d\n", ret_block);
+ ext3_debug("found bit %d\n", grp_alloc_blk);
spin_unlock(sb_bgl_lock(sbi, group_no));
jbd_unlock_bh_state(bitmap_bh);
#endif
- /* ret_block was blockgroup-relative. Now it becomes fs-relative */
- ret_block = target_block;
-
if (ret_block + num - 1 >= le32_to_cpu(es->s_blocks_count)) {
ext3_error(sb, "ext3_new_block",
- "block(%d) >= blocks count(%d) - "
+ "block("E3FSBLK") >= blocks count(%d) - "
"block_group = %d, es == %p ", ret_block,
le32_to_cpu(es->s_blocks_count), group_no, es);
goto out;
@@ -1421,7 +1424,7 @@ allocated:
* list of some description. We don't know in advance whether
* the caller wants to use it as metadata or data.
*/
- ext3_debug("allocating block %d. Goal hits %d of %d.\n",
+ ext3_debug("allocating block %lu. Goal hits %d of %d.\n",
ret_block, goal_hits, goal_attempts);
spin_lock(sb_bgl_lock(sbi, group_no));
@@ -1461,23 +1464,24 @@ out:
return 0;
}
-int ext3_new_block(handle_t *handle, struct inode *inode,
- unsigned long goal, int *errp)
+ext3_fsblk_t ext3_new_block(handle_t *handle, struct inode *inode,
+ ext3_fsblk_t goal, int *errp)
{
unsigned long count = 1;
return ext3_new_blocks(handle, inode, goal, &count, errp);
}
-unsigned long ext3_count_free_blocks(struct super_block *sb)
+ext3_fsblk_t ext3_count_free_blocks(struct super_block *sb)
{
- unsigned long desc_count;
+ ext3_fsblk_t desc_count;
struct ext3_group_desc *gdp;
int i;
unsigned long ngroups = EXT3_SB(sb)->s_groups_count;
#ifdef EXT3FS_DEBUG
struct ext3_super_block *es;
- unsigned long bitmap_count, x;
+ ext3_fsblk_t bitmap_count;
+ unsigned long x;
struct buffer_head *bitmap_bh = NULL;
es = EXT3_SB(sb)->s_es;
@@ -1502,8 +1506,10 @@ unsigned long ext3_count_free_blocks(struct super_block *sb)
bitmap_count += x;
}
brelse(bitmap_bh);
- printk("ext3_count_free_blocks: stored = %u, computed = %lu, %lu\n",
- le32_to_cpu(es->s_free_blocks_count), desc_count, bitmap_count);
+ printk("ext3_count_free_blocks: stored = "E3FSBLK
+ ", computed = "E3FSBLK", "E3FSBLK"\n",
+ le32_to_cpu(es->s_free_blocks_count),
+ desc_count, bitmap_count);
return bitmap_count;
#else
desc_count = 0;
@@ -1520,7 +1526,7 @@ unsigned long ext3_count_free_blocks(struct super_block *sb)
}
static inline int
-block_in_use(unsigned long block, struct super_block *sb, unsigned char *map)
+block_in_use(ext3_fsblk_t block, struct super_block *sb, unsigned char *map)
{
return ext3_test_bit ((block -
le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block)) %
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
index dc82646..36546ed 100644
--- a/fs/ext3/ialloc.c
+++ b/fs/ext3/ialloc.c
@@ -262,9 +262,11 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent)
int ngroups = sbi->s_groups_count;
int inodes_per_group = EXT3_INODES_PER_GROUP(sb);
int freei, avefreei;
- int freeb, avefreeb;
- int blocks_per_dir, ndirs;
- int max_debt, max_dirs, min_blocks, min_inodes;
+ ext3_fsblk_t freeb, avefreeb;
+ ext3_fsblk_t blocks_per_dir;
+ int ndirs;
+ int max_debt, max_dirs, min_inodes;
+ ext3_grpblk_t min_blocks;
int group = -1, i;
struct ext3_group_desc *desc;
struct buffer_head *bh;
@@ -307,7 +309,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent)
min_inodes = avefreei - inodes_per_group / 4;
min_blocks = avefreeb - EXT3_BLOCKS_PER_GROUP(sb) / 4;
- max_debt = EXT3_BLOCKS_PER_GROUP(sb) / max(blocks_per_dir, BLOCK_COST);
+ max_debt = EXT3_BLOCKS_PER_GROUP(sb) / max(blocks_per_dir, (ext3_fsblk_t)BLOCK_COST);
if (max_debt * INODE_COST > inodes_per_group)
max_debt = inodes_per_group / INODE_COST;
if (max_debt > 255)
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 2edd7ee..0321e1b 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -62,7 +62,7 @@ static int ext3_inode_is_fast_symlink(struct inode *inode)
* still needs to be revoked.
*/
int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode,
- struct buffer_head *bh, int blocknr)
+ struct buffer_head *bh, ext3_fsblk_t blocknr)
{
int err;
@@ -407,13 +407,13 @@ no_block:
*
* Caller must make sure that @ind is valid and will stay that way.
*/
-static unsigned long ext3_find_near(struct inode *inode, Indirect *ind)
+static ext3_fsblk_t ext3_find_near(struct inode *inode, Indirect *ind)
{
struct ext3_inode_info *ei = EXT3_I(inode);
__le32 *start = ind->bh ? (__le32*) ind->bh->b_data : ei->i_data;
__le32 *p;
- unsigned long bg_start;
- unsigned long colour;
+ ext3_fsblk_t bg_start;
+ ext3_grpblk_t colour;
/* Try to find previous block */
for (p = ind->p - 1; p >= start; p--) {
@@ -429,8 +429,7 @@ static unsigned long ext3_find_near(struct inode *inode, Indirect *ind)
* It is going to be referred to from the inode itself? OK, just put it
* into the same cylinder group then.
*/
- bg_start = (ei->i_block_group * EXT3_BLOCKS_PER_GROUP(inode->i_sb)) +
- le32_to_cpu(EXT3_SB(inode->i_sb)->s_es->s_first_data_block);
+ bg_start = ext3_group_first_block_no(inode->i_sb, ei->i_block_group);
colour = (current->pid % 16) *
(EXT3_BLOCKS_PER_GROUP(inode->i_sb) / 16);
return bg_start + colour;
@@ -448,7 +447,7 @@ static unsigned long ext3_find_near(struct inode *inode, Indirect *ind)
* stores it in *@goal and returns zero.
*/
-static unsigned long ext3_find_goal(struct inode *inode, long block,
+static ext3_fsblk_t ext3_find_goal(struct inode *inode, long block,
Indirect chain[4], Indirect *partial)
{
struct ext3_block_alloc_info *block_i;
@@ -516,13 +515,13 @@ static int ext3_blks_to_allocate(Indirect *branch, int k, unsigned long blks,
* direct blocks
*/
static int ext3_alloc_blocks(handle_t *handle, struct inode *inode,
- unsigned long goal, int indirect_blks, int blks,
- unsigned long long new_blocks[4], int *err)
+ ext3_fsblk_t goal, int indirect_blks, int blks,
+ ext3_fsblk_t new_blocks[4], int *err)
{
int target, i;
unsigned long count = 0;
int index = 0;
- unsigned long current_block = 0;
+ ext3_fsblk_t current_block = 0;
int ret = 0;
/*
@@ -592,7 +591,7 @@ failed_out:
* as described above and return 0.
*/
static int ext3_alloc_branch(handle_t *handle, struct inode *inode,
- int indirect_blks, int *blks, unsigned long goal,
+ int indirect_blks, int *blks, ext3_fsblk_t goal,
int *offsets, Indirect *branch)
{
int blocksize = inode->i_sb->s_blocksize;
@@ -600,8 +599,8 @@ static int ext3_alloc_branch(handle_t *handle, struct inode *inode,
int err = 0;
struct buffer_head *bh;
int num;
- unsigned long long new_blocks[4];
- unsigned long long current_block;
+ ext3_fsblk_t new_blocks[4];
+ ext3_fsblk_t current_block;
num = ext3_alloc_blocks(handle, inode, goal, indirect_blks,
*blks, new_blocks, &err);
@@ -688,7 +687,7 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode,
int i;
int err = 0;
struct ext3_block_alloc_info *block_i;
- unsigned long current_block;
+ ext3_fsblk_t current_block;
block_i = EXT3_I(inode)->i_block_alloc_info;
/*
@@ -795,13 +794,13 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
int offsets[4];
Indirect chain[4];
Indirect *partial;
- unsigned long goal;
+ ext3_fsblk_t goal;
int indirect_blks;
int blocks_to_boundary = 0;
int depth;
struct ext3_inode_info *ei = EXT3_I(inode);
int count = 0;
- unsigned long first_block = 0;
+ ext3_fsblk_t first_block = 0;
J_ASSERT(handle != NULL || create == 0);
@@ -819,7 +818,7 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
count++;
/*map more blocks*/
while (count < maxblocks && count <= blocks_to_boundary) {
- unsigned long blk;
+ ext3_fsblk_t blk;
if (!verify_chain(chain, partial)) {
/*
@@ -1759,7 +1758,7 @@ void ext3_set_aops(struct inode *inode)
static int ext3_block_truncate_page(handle_t *handle, struct page *page,
struct address_space *mapping, loff_t from)
{
- unsigned long index = from >> PAGE_CACHE_SHIFT;
+ ext3_fsblk_t index = from >> PAGE_CACHE_SHIFT;
unsigned offset = from & (PAGE_CACHE_SIZE-1);
unsigned blocksize, iblock, length, pos;
struct inode *inode = mapping->host;
@@ -1960,7 +1959,7 @@ no_top:
* than `count' because there can be holes in there.
*/
static void ext3_clear_blocks(handle_t *handle, struct inode *inode,
- struct buffer_head *bh, unsigned long block_to_free,
+ struct buffer_head *bh, ext3_fsblk_t block_to_free,
unsigned long count, __le32 *first, __le32 *last)
{
__le32 *p;
@@ -2022,12 +2021,12 @@ static void ext3_free_data(handle_t *handle, struct inode *inode,
struct buffer_head *this_bh,
__le32 *first, __le32 *last)
{
- unsigned long block_to_free = 0; /* Starting block # of a run */
+ ext3_fsblk_t block_to_free = 0; /* Starting block # of a run */
unsigned long count = 0; /* Number of blocks in the run */
__le32 *block_to_free_p = NULL; /* Pointer into inode/ind
corresponding to
block_to_free */
- unsigned long nr; /* Current block # */
+ ext3_fsblk_t nr; /* Current block # */
__le32 *p; /* Pointer into inode/ind
for current block */
int err;
@@ -2089,7 +2088,7 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode,
struct buffer_head *parent_bh,
__le32 *first, __le32 *last, int depth)
{
- unsigned long nr;
+ ext3_fsblk_t nr;
__le32 *p;
if (is_handle_aborted(handle))
@@ -2113,7 +2112,7 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode,
*/
if (!bh) {
ext3_error(inode->i_sb, "ext3_free_branches",
- "Read failure, inode=%ld, block=%ld",
+ "Read failure, inode=%ld, block="E3FSBLK,
inode->i_ino, nr);
continue;
}
@@ -2394,11 +2393,12 @@ out_stop:
ext3_journal_stop(handle);
}
-static unsigned long ext3_get_inode_block(struct super_block *sb,
+static ext3_fsblk_t ext3_get_inode_block(struct super_block *sb,
unsigned long ino, struct ext3_iloc *iloc)
{
unsigned long desc, group_desc, block_group;
- unsigned long offset, block;
+ unsigned long offset;
+ ext3_fsblk_t block;
struct buffer_head *bh;
struct ext3_group_desc * gdp;
@@ -2448,7 +2448,7 @@ static unsigned long ext3_get_inode_block(struct super_block *sb,
static int __ext3_get_inode_loc(struct inode *inode,
struct ext3_iloc *iloc, int in_mem)
{
- unsigned long block;
+ ext3_fsblk_t block;
struct buffer_head *bh;
block = ext3_get_inode_block(inode->i_sb, inode->i_ino, iloc);
@@ -2459,7 +2459,8 @@ static int __ext3_get_inode_loc(struct inode *inode,
if (!bh) {
ext3_error (inode->i_sb, "ext3_get_inode_loc",
"unable to read inode block - "
- "inode=%lu, block=%lu", inode->i_ino, block);
+ "inode=%lu, block="E3FSBLK,
+ inode->i_ino, block);
return -EIO;
}
if (!buffer_uptodate(bh)) {
@@ -2540,7 +2541,7 @@ make_io:
if (!buffer_uptodate(bh)) {
ext3_error(inode->i_sb, "ext3_get_inode_loc",
"unable to read inode block - "
- "inode=%lu, block=%lu",
+ "inode=%lu, block="E3FSBLK,
inode->i_ino, block);
brelse(bh);
return -EIO;
diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c
index 8c22aa9..3a6b012 100644
--- a/fs/ext3/ioctl.c
+++ b/fs/ext3/ioctl.c
@@ -204,7 +204,7 @@ flags_err:
return 0;
}
case EXT3_IOC_GROUP_EXTEND: {
- unsigned long n_blocks_count;
+ ext3_fsblk_t n_blocks_count;
struct super_block *sb = inode->i_sb;
int err;
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index b8f5cd1..d9176db 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -1379,7 +1379,6 @@ static int ext3_add_entry (handle_t *handle, struct dentry *dentry,
int dx_fallback=0;
#endif
unsigned blocksize;
- unsigned nlen, rlen;
u32 block, blocks;
sb = dir->i_sb;
@@ -1417,8 +1416,7 @@ static int ext3_add_entry (handle_t *handle, struct dentry *dentry,
return retval;
de = (struct ext3_dir_entry_2 *) bh->b_data;
de->inode = 0;
- de->rec_len = cpu_to_le16(rlen = blocksize);
- nlen = 0;
+ de->rec_len = cpu_to_le16(blocksize);
return add_dirent_to_buf(handle, dentry, inode, de, bh);
}
diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c
index 34b39e9..dfd8118 100644
--- a/fs/ext3/resize.c
+++ b/fs/ext3/resize.c
@@ -28,16 +28,16 @@ static int verify_group_input(struct super_block *sb,
{
struct ext3_sb_info *sbi = EXT3_SB(sb);
struct ext3_super_block *es = sbi->s_es;
- unsigned start = le32_to_cpu(es->s_blocks_count);
- unsigned end = start + input->blocks_count;
+ ext3_fsblk_t start = le32_to_cpu(es->s_blocks_count);
+ ext3_fsblk_t end = start + input->blocks_count;
unsigned group = input->group;
- unsigned itend = input->inode_table + sbi->s_itb_per_group;
+ ext3_fsblk_t itend = input->inode_table + sbi->s_itb_per_group;
unsigned overhead = ext3_bg_has_super(sb, group) ?
(1 + ext3_bg_num_gdb(sb, group) +
le16_to_cpu(es->s_reserved_gdt_blocks)) : 0;
- unsigned metaend = start + overhead;
+ ext3_fsblk_t metaend = start + overhead;
struct buffer_head *bh = NULL;
- int free_blocks_count;
+ ext3_grpblk_t free_blocks_count;
int err = -EINVAL;
input->free_blocks_count = free_blocks_count =
@@ -64,7 +64,8 @@ static int verify_group_input(struct super_block *sb,
ext3_warning(sb, __FUNCTION__, "Bad blocks count %u",
input->blocks_count);
else if (!(bh = sb_bread(sb, end - 1)))
- ext3_warning(sb, __FUNCTION__, "Cannot read last block (%u)",
+ ext3_warning(sb, __FUNCTION__,
+ "Cannot read last block ("E3FSBLK")",
end - 1);
else if (outside(input->block_bitmap, start, end))
ext3_warning(sb, __FUNCTION__,
@@ -77,7 +78,7 @@ static int verify_group_input(struct super_block *sb,
else if (outside(input->inode_table, start, end) ||
outside(itend - 1, start, end))
ext3_warning(sb, __FUNCTION__,
- "Inode table not in group (blocks %u-%u)",
+ "Inode table not in group (blocks %u-"E3FSBLK")",
input->inode_table, itend - 1);
else if (input->inode_bitmap == input->block_bitmap)
ext3_warning(sb, __FUNCTION__,
@@ -85,24 +86,27 @@ static int verify_group_input(struct super_block *sb,
input->block_bitmap);
else if (inside(input->block_bitmap, input->inode_table, itend))
ext3_warning(sb, __FUNCTION__,
- "Block bitmap (%u) in inode table (%u-%u)",
+ "Block bitmap (%u) in inode table (%u-"E3FSBLK")",
input->block_bitmap, input->inode_table, itend-1);
else if (inside(input->inode_bitmap, input->inode_table, itend))
ext3_warning(sb, __FUNCTION__,
- "Inode bitmap (%u) in inode table (%u-%u)",
+ "Inode bitmap (%u) in inode table (%u-"E3FSBLK")",
input->inode_bitmap, input->inode_table, itend-1);
else if (inside(input->block_bitmap, start, metaend))
ext3_warning(sb, __FUNCTION__,
- "Block bitmap (%u) in GDT table (%u-%u)",
+ "Block bitmap (%u) in GDT table"
+ " ("E3FSBLK"-"E3FSBLK")",
input->block_bitmap, start, metaend - 1);
else if (inside(input->inode_bitmap, start, metaend))
ext3_warning(sb, __FUNCTION__,
- "Inode bitmap (%u) in GDT table (%u-%u)",
+ "Inode bitmap (%u) in GDT table"
+ " ("E3FSBLK"-"E3FSBLK")",
input->inode_bitmap, start, metaend - 1);
else if (inside(input->inode_table, start, metaend) ||
inside(itend - 1, start, metaend))
ext3_warning(sb, __FUNCTION__,
- "Inode table (%u-%u) overlaps GDT table (%u-%u)",
+ "Inode table (%u-"E3FSBLK") overlaps"
+ "GDT table ("E3FSBLK"-"E3FSBLK")",
input->inode_table, itend - 1, start, metaend - 1);
else
err = 0;
@@ -112,7 +116,7 @@ static int verify_group_input(struct super_block *sb,
}
static struct buffer_head *bclean(handle_t *handle, struct super_block *sb,
- unsigned long blk)
+ ext3_fsblk_t blk)
{
struct buffer_head *bh;
int err;
@@ -163,15 +167,14 @@ static int setup_new_group_blocks(struct super_block *sb,
struct ext3_new_group_data *input)
{
struct ext3_sb_info *sbi = EXT3_SB(sb);
- unsigned long start = input->group * sbi->s_blocks_per_group +
- le32_to_cpu(sbi->s_es->s_first_data_block);
+ ext3_fsblk_t start = ext3_group_first_block_no(sb, input->group);
int reserved_gdb = ext3_bg_has_super(sb, input->group) ?
le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) : 0;
unsigned long gdblocks = ext3_bg_num_gdb(sb, input->group);
struct buffer_head *bh;
handle_t *handle;
- unsigned long block;
- int bit;
+ ext3_fsblk_t block;
+ ext3_grpblk_t bit;
int i;
int err = 0, err2;
@@ -328,7 +331,7 @@ static unsigned ext3_list_backups(struct super_block *sb, unsigned *three,
static int verify_reserved_gdb(struct super_block *sb,
struct buffer_head *primary)
{
- const unsigned long blk = primary->b_blocknr;
+ const ext3_fsblk_t blk = primary->b_blocknr;
const unsigned long end = EXT3_SB(sb)->s_groups_count;
unsigned three = 1;
unsigned five = 5;
@@ -340,7 +343,8 @@ static int verify_reserved_gdb(struct super_block *sb,
while ((grp = ext3_list_backups(sb, &three, &five, &seven)) < end) {
if (le32_to_cpu(*p++) != grp * EXT3_BLOCKS_PER_GROUP(sb) + blk){
ext3_warning(sb, __FUNCTION__,
- "reserved GDT %ld missing grp %d (%ld)",
+ "reserved GDT "E3FSBLK
+ " missing grp %d ("E3FSBLK")",
blk, grp,
grp * EXT3_BLOCKS_PER_GROUP(sb) + blk);
return -EINVAL;
@@ -372,7 +376,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
struct super_block *sb = inode->i_sb;
struct ext3_super_block *es = EXT3_SB(sb)->s_es;
unsigned long gdb_num = input->group / EXT3_DESC_PER_BLOCK(sb);
- unsigned long gdblock = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + gdb_num;
+ ext3_fsblk_t gdblock = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + gdb_num;
struct buffer_head **o_group_desc, **n_group_desc;
struct buffer_head *dind;
int gdbackups;
@@ -417,7 +421,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
data = (__u32 *)dind->b_data;
if (le32_to_cpu(data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)]) != gdblock) {
ext3_warning(sb, __FUNCTION__,
- "new group %u GDT block %lu not reserved",
+ "new group %u GDT block "E3FSBLK" not reserved",
input->group, gdblock);
err = -EINVAL;
goto exit_dind;
@@ -515,7 +519,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
struct buffer_head **primary;
struct buffer_head *dind;
struct ext3_iloc iloc;
- unsigned long blk;
+ ext3_fsblk_t blk;
__u32 *data, *end;
int gdbackups = 0;
int res, i;
@@ -540,7 +544,8 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
for (res = 0; res < reserved_gdb; res++, blk++) {
if (le32_to_cpu(*data) != blk) {
ext3_warning(sb, __FUNCTION__,
- "reserved block %lu not at offset %ld",
+ "reserved block "E3FSBLK
+ " not at offset %ld",
blk, (long)(data - (__u32 *)dind->b_data));
err = -EINVAL;
goto exit_bh;
@@ -902,15 +907,16 @@ exit_put:
* GDT blocks are reserved to grow to the desired size.
*/
int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
- unsigned long n_blocks_count)
+ ext3_fsblk_t n_blocks_count)
{
- unsigned long o_blocks_count;
+ ext3_fsblk_t o_blocks_count;
unsigned long o_groups_count;
- unsigned long last;
- int add;
+ ext3_grpblk_t last;
+ ext3_grpblk_t add;
struct buffer_head * bh;
handle_t *handle;
- int err, freed_blocks;
+ int err;
+ unsigned long freed_blocks;
/* We don't need to worry about locking wrt other resizers just
* yet: we're going to revalidate es->s_blocks_count after
@@ -919,12 +925,22 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
o_groups_count = EXT3_SB(sb)->s_groups_count;
if (test_opt(sb, DEBUG))
- printk(KERN_DEBUG "EXT3-fs: extending last group from %lu to %lu blocks\n",
+ printk(KERN_DEBUG "EXT3-fs: extending last group from "E3FSBLK" uto "E3FSBLK" blocks\n",
o_blocks_count, n_blocks_count);
if (n_blocks_count == 0 || n_blocks_count == o_blocks_count)
return 0;
+ if (n_blocks_count > (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) {
+ printk(KERN_ERR "EXT3-fs: filesystem on %s:"
+ " too large to resize to %lu blocks safely\n",
+ sb->s_id, n_blocks_count);
+ if (sizeof(sector_t) < 8)
+ ext3_warning(sb, __FUNCTION__,
+ "CONFIG_LBD not enabled\n");
+ return -EINVAL;
+ }
+
if (n_blocks_count < o_blocks_count) {
ext3_warning(sb, __FUNCTION__,
"can't shrink FS - resize aborted");
@@ -948,7 +964,8 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
if (o_blocks_count + add < n_blocks_count)
ext3_warning(sb, __FUNCTION__,
- "will only finish group (%lu blocks, %u new)",
+ "will only finish group ("E3FSBLK
+ " blocks, %u new)",
o_blocks_count + add, add);
/* See if the device is actually as big as what was requested */
@@ -991,10 +1008,10 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh);
sb->s_dirt = 1;
unlock_super(sb);
- ext3_debug("freeing blocks %ld through %ld\n", o_blocks_count,
+ ext3_debug("freeing blocks %lu through "E3FSBLK"\n", o_blocks_count,
o_blocks_count + add);
ext3_free_blocks_sb(handle, sb, o_blocks_count, add, &freed_blocks);
- ext3_debug("freed blocks %ld through %ld\n", o_blocks_count,
+ ext3_debug("freed blocks "E3FSBLK" through "E3FSBLK"\n", o_blocks_count,
o_blocks_count + add);
if ((err = ext3_journal_stop(handle)))
goto exit_put;
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index f8a5266..b2891cc 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -58,7 +58,7 @@ static int ext3_sync_fs(struct super_block *sb, int wait);
static const char *ext3_decode_error(struct super_block * sb, int errno,
char nbuf[16]);
static int ext3_remount (struct super_block * sb, int * flags, char * data);
-static int ext3_statfs (struct super_block * sb, struct kstatfs * buf);
+static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf);
static void ext3_unlockfs(struct super_block *sb);
static void ext3_write_super (struct super_block * sb);
static void ext3_write_super_lockfs(struct super_block *sb);
@@ -499,20 +499,21 @@ static void ext3_clear_inode(struct inode *inode)
{
struct ext3_block_alloc_info *rsv = EXT3_I(inode)->i_block_alloc_info;
#ifdef CONFIG_EXT3_FS_POSIX_ACL
- if (EXT3_I(inode)->i_acl &&
- EXT3_I(inode)->i_acl != EXT3_ACL_NOT_CACHED) {
- posix_acl_release(EXT3_I(inode)->i_acl);
- EXT3_I(inode)->i_acl = EXT3_ACL_NOT_CACHED;
- }
- if (EXT3_I(inode)->i_default_acl &&
- EXT3_I(inode)->i_default_acl != EXT3_ACL_NOT_CACHED) {
- posix_acl_release(EXT3_I(inode)->i_default_acl);
- EXT3_I(inode)->i_default_acl = EXT3_ACL_NOT_CACHED;
- }
+ if (EXT3_I(inode)->i_acl &&
+ EXT3_I(inode)->i_acl != EXT3_ACL_NOT_CACHED) {
+ posix_acl_release(EXT3_I(inode)->i_acl);
+ EXT3_I(inode)->i_acl = EXT3_ACL_NOT_CACHED;
+ }
+ if (EXT3_I(inode)->i_default_acl &&
+ EXT3_I(inode)->i_default_acl != EXT3_ACL_NOT_CACHED) {
+ posix_acl_release(EXT3_I(inode)->i_default_acl);
+ EXT3_I(inode)->i_default_acl = EXT3_ACL_NOT_CACHED;
+ }
#endif
ext3_discard_reservation(inode);
EXT3_I(inode)->i_block_alloc_info = NULL;
- kfree(rsv);
+ if (unlikely(rsv))
+ kfree(rsv);
}
static inline void ext3_show_quota_options(struct seq_file *seq, struct super_block *sb)
@@ -688,14 +689,15 @@ static match_table_t tokens = {
{Opt_resize, "resize"},
};
-static unsigned long get_sb_block(void **data)
+static ext3_fsblk_t get_sb_block(void **data)
{
- unsigned long sb_block;
+ ext3_fsblk_t sb_block;
char *options = (char *) *data;
if (!options || strncmp(options, "sb=", 3) != 0)
return 1; /* Default location */
options += 3;
+ /*todo: use simple_strtoll with >32bit ext3 */
sb_block = simple_strtoul(options, &options, 0);
if (*options && *options != ',') {
printk("EXT3-fs: Invalid sb specification: %s\n",
@@ -710,7 +712,7 @@ static unsigned long get_sb_block(void **data)
static int parse_options (char *options, struct super_block *sb,
unsigned long *inum, unsigned long *journal_devnum,
- unsigned long *n_blocks_count, int is_remount)
+ ext3_fsblk_t *n_blocks_count, int is_remount)
{
struct ext3_sb_info *sbi = EXT3_SB(sb);
char * p;
@@ -1127,7 +1129,7 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es,
static int ext3_check_descriptors (struct super_block * sb)
{
struct ext3_sb_info *sbi = EXT3_SB(sb);
- unsigned long block = le32_to_cpu(sbi->s_es->s_first_data_block);
+ ext3_fsblk_t block = le32_to_cpu(sbi->s_es->s_first_data_block);
struct ext3_group_desc * gdp = NULL;
int desc_block = 0;
int i;
@@ -1314,15 +1316,14 @@ static loff_t ext3_max_size(int bits)
return res;
}
-static unsigned long descriptor_loc(struct super_block *sb,
- unsigned long logic_sb_block,
+static ext3_fsblk_t descriptor_loc(struct super_block *sb,
+ ext3_fsblk_t logic_sb_block,
int nr)
{
struct ext3_sb_info *sbi = EXT3_SB(sb);
- unsigned long bg, first_data_block, first_meta_bg;
+ unsigned long bg, first_meta_bg;
int has_super = 0;
- first_data_block = le32_to_cpu(sbi->s_es->s_first_data_block);
first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_META_BG) ||
@@ -1331,7 +1332,7 @@ static unsigned long descriptor_loc(struct super_block *sb,
bg = sbi->s_desc_per_block * nr;
if (ext3_bg_has_super(sb, bg))
has_super = 1;
- return (first_data_block + has_super + (bg * sbi->s_blocks_per_group));
+ return (has_super + ext3_group_first_block_no(sb, bg));
}
@@ -1340,9 +1341,9 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
struct buffer_head * bh;
struct ext3_super_block *es = NULL;
struct ext3_sb_info *sbi;
- unsigned long block;
- unsigned long sb_block = get_sb_block(&data);
- unsigned long logic_sb_block;
+ ext3_fsblk_t block;
+ ext3_fsblk_t sb_block = get_sb_block(&data);
+ ext3_fsblk_t logic_sb_block;
unsigned long offset = 0;
unsigned long journal_inum = 0;
unsigned long journal_devnum = 0;
@@ -1564,6 +1565,16 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
goto failed_mount;
}
+ if (le32_to_cpu(es->s_blocks_count) >
+ (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) {
+ printk(KERN_ERR "EXT3-fs: filesystem on %s:"
+ " too large to mount safely\n", sb->s_id);
+ if (sizeof(sector_t) < 8)
+ printk(KERN_WARNING "EXT3-fs: CONFIG_LBD not "
+ "enabled\n");
+ goto failed_mount;
+ }
+
if (EXT3_BLOCKS_PER_GROUP(sb) == 0)
goto cantfind_ext3;
sbi->s_groups_count = (le32_to_cpu(es->s_blocks_count) -
@@ -1579,9 +1590,6 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
goto failed_mount;
}
- percpu_counter_init(&sbi->s_freeblocks_counter);
- percpu_counter_init(&sbi->s_freeinodes_counter);
- percpu_counter_init(&sbi->s_dirs_counter);
bgl_lock_init(&sbi->s_blockgroup_lock);
for (i = 0; i < db_count; i++) {
@@ -1595,12 +1603,20 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
}
}
if (!ext3_check_descriptors (sb)) {
- printk (KERN_ERR "EXT3-fs: group descriptors corrupted !\n");
+ printk(KERN_ERR "EXT3-fs: group descriptors corrupted!\n");
goto failed_mount2;
}
sbi->s_gdb_count = db_count;
get_random_bytes(&sbi->s_next_generation, sizeof(u32));
spin_lock_init(&sbi->s_next_gen_lock);
+
+ percpu_counter_init(&sbi->s_freeblocks_counter,
+ ext3_count_free_blocks(sb));
+ percpu_counter_init(&sbi->s_freeinodes_counter,
+ ext3_count_free_inodes(sb));
+ percpu_counter_init(&sbi->s_dirs_counter,
+ ext3_count_dirs(sb));
+
/* per fileystem reservation list head & lock */
spin_lock_init(&sbi->s_rsv_window_lock);
sbi->s_rsv_window_root = RB_ROOT;
@@ -1639,16 +1655,16 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
if (!test_opt(sb, NOLOAD) &&
EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
if (ext3_load_journal(sb, es, journal_devnum))
- goto failed_mount2;
+ goto failed_mount3;
} else if (journal_inum) {
if (ext3_create_journal(sb, es, journal_inum))
- goto failed_mount2;
+ goto failed_mount3;
} else {
if (!silent)
printk (KERN_ERR
"ext3: No journal on filesystem on %s\n",
sb->s_id);
- goto failed_mount2;
+ goto failed_mount3;
}
/* We have now updated the journal if required, so we can
@@ -1671,7 +1687,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
(sbi->s_journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)) {
printk(KERN_ERR "EXT3-fs: Journal does not support "
"requested data journaling mode\n");
- goto failed_mount3;
+ goto failed_mount4;
}
default:
break;
@@ -1694,13 +1710,13 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
if (!sb->s_root) {
printk(KERN_ERR "EXT3-fs: get root inode failed\n");
iput(root);
- goto failed_mount3;
+ goto failed_mount4;
}
if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
dput(sb->s_root);
sb->s_root = NULL;
printk(KERN_ERR "EXT3-fs: corrupt root inode, run e2fsck\n");
- goto failed_mount3;
+ goto failed_mount4;
}
ext3_setup_super (sb, es, sb->s_flags & MS_RDONLY);
@@ -1723,13 +1739,6 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered":
"writeback");
- percpu_counter_mod(&sbi->s_freeblocks_counter,
- ext3_count_free_blocks(sb));
- percpu_counter_mod(&sbi->s_freeinodes_counter,
- ext3_count_free_inodes(sb));
- percpu_counter_mod(&sbi->s_dirs_counter,
- ext3_count_dirs(sb));
-
lock_kernel();
return 0;
@@ -1739,8 +1748,12 @@ cantfind_ext3:
sb->s_id);
goto failed_mount;
-failed_mount3:
+failed_mount4:
journal_destroy(sbi->s_journal);
+failed_mount3:
+ percpu_counter_destroy(&sbi->s_freeblocks_counter);
+ percpu_counter_destroy(&sbi->s_freeinodes_counter);
+ percpu_counter_destroy(&sbi->s_dirs_counter);
failed_mount2:
for (i = 0; i < db_count; i++)
brelse(sbi->s_group_desc[i]);
@@ -1827,10 +1840,10 @@ static journal_t *ext3_get_dev_journal(struct super_block *sb,
{
struct buffer_head * bh;
journal_t *journal;
- int start;
- int len;
+ ext3_fsblk_t start;
+ ext3_fsblk_t len;
int hblock, blocksize;
- unsigned long sb_block;
+ ext3_fsblk_t sb_block;
unsigned long offset;
struct ext3_super_block * es;
struct block_device *bdev;
@@ -2203,7 +2216,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
{
struct ext3_super_block * es;
struct ext3_sb_info *sbi = EXT3_SB(sb);
- unsigned long n_blocks_count = 0;
+ ext3_fsblk_t n_blocks_count = 0;
unsigned long old_sb_flags;
struct ext3_mount_options old_opts;
int err;
@@ -2318,11 +2331,12 @@ restore_opts:
return err;
}
-static int ext3_statfs (struct super_block * sb, struct kstatfs * buf)
+static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf)
{
+ struct super_block *sb = dentry->d_sb;
struct ext3_sb_info *sbi = EXT3_SB(sb);
struct ext3_super_block *es = sbi->s_es;
- unsigned long overhead;
+ ext3_fsblk_t overhead;
int i;
if (test_opt (sb, MINIX_DF))
@@ -2646,10 +2660,10 @@ out:
#endif
-static struct super_block *ext3_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int ext3_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, ext3_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, ext3_fill_super, mnt);
}
static struct file_system_type ext3_fs_type = {
diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c
index e8d60bf..a44a056 100644
--- a/fs/ext3/xattr.c
+++ b/fs/ext3/xattr.c
@@ -225,7 +225,7 @@ ext3_xattr_block_get(struct inode *inode, int name_index, const char *name,
error = -ENODATA;
if (!EXT3_I(inode)->i_file_acl)
goto cleanup;
- ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl);
+ ea_idebug(inode, "reading block %u", EXT3_I(inode)->i_file_acl);
bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
if (!bh)
goto cleanup;
@@ -233,7 +233,7 @@ ext3_xattr_block_get(struct inode *inode, int name_index, const char *name,
atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
if (ext3_xattr_check_block(bh)) {
bad_block: ext3_error(inode->i_sb, __FUNCTION__,
- "inode %ld: bad block %d", inode->i_ino,
+ "inode %ld: bad block "E3FSBLK, inode->i_ino,
EXT3_I(inode)->i_file_acl);
error = -EIO;
goto cleanup;
@@ -366,7 +366,7 @@ ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
error = 0;
if (!EXT3_I(inode)->i_file_acl)
goto cleanup;
- ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl);
+ ea_idebug(inode, "reading block %u", EXT3_I(inode)->i_file_acl);
bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
error = -EIO;
if (!bh)
@@ -375,7 +375,7 @@ ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
if (ext3_xattr_check_block(bh)) {
ext3_error(inode->i_sb, __FUNCTION__,
- "inode %ld: bad block %d", inode->i_ino,
+ "inode %ld: bad block "E3FSBLK, inode->i_ino,
EXT3_I(inode)->i_file_acl);
error = -EIO;
goto cleanup;
@@ -647,7 +647,7 @@ ext3_xattr_block_find(struct inode *inode, struct ext3_xattr_info *i,
le32_to_cpu(BHDR(bs->bh)->h_refcount));
if (ext3_xattr_check_block(bs->bh)) {
ext3_error(sb, __FUNCTION__,
- "inode %ld: bad block %d", inode->i_ino,
+ "inode %ld: bad block "E3FSBLK, inode->i_ino,
EXT3_I(inode)->i_file_acl);
error = -EIO;
goto cleanup;
@@ -792,11 +792,12 @@ inserted:
get_bh(new_bh);
} else {
/* We need to allocate a new block */
- int goal = le32_to_cpu(
+ ext3_fsblk_t goal = le32_to_cpu(
EXT3_SB(sb)->s_es->s_first_data_block) +
- EXT3_I(inode)->i_block_group *
+ (ext3_fsblk_t)EXT3_I(inode)->i_block_group *
EXT3_BLOCKS_PER_GROUP(sb);
- int block = ext3_new_block(handle, inode, goal, &error);
+ ext3_fsblk_t block = ext3_new_block(handle, inode,
+ goal, &error);
if (error)
goto cleanup;
ea_idebug(inode, "creating block %d", block);
@@ -847,7 +848,7 @@ cleanup_dquot:
bad_block:
ext3_error(inode->i_sb, __FUNCTION__,
- "inode %ld: bad block %d", inode->i_ino,
+ "inode %ld: bad block "E3FSBLK, inode->i_ino,
EXT3_I(inode)->i_file_acl);
goto cleanup;
@@ -1076,14 +1077,14 @@ ext3_xattr_delete_inode(handle_t *handle, struct inode *inode)
bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
if (!bh) {
ext3_error(inode->i_sb, __FUNCTION__,
- "inode %ld: block %d read error", inode->i_ino,
+ "inode %ld: block "E3FSBLK" read error", inode->i_ino,
EXT3_I(inode)->i_file_acl);
goto cleanup;
}
if (BHDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
BHDR(bh)->h_blocks != cpu_to_le32(1)) {
ext3_error(inode->i_sb, __FUNCTION__,
- "inode %ld: bad block %d", inode->i_ino,
+ "inode %ld: bad block "E3FSBLK, inode->i_ino,
EXT3_I(inode)->i_file_acl);
goto cleanup;
}
@@ -1210,11 +1211,11 @@ again:
bh = sb_bread(inode->i_sb, ce->e_block);
if (!bh) {
ext3_error(inode->i_sb, __FUNCTION__,
- "inode %ld: block %ld read error",
+ "inode %ld: block %lu read error",
inode->i_ino, (unsigned long) ce->e_block);
} else if (le32_to_cpu(BHDR(bh)->h_refcount) >=
EXT3_XATTR_REFCOUNT_MAX) {
- ea_idebug(inode, "block %ld refcount %d>=%d",
+ ea_idebug(inode, "block %lu refcount %d>=%d",
(unsigned long) ce->e_block,
le32_to_cpu(BHDR(bh)->h_refcount),
EXT3_XATTR_REFCOUNT_MAX);
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index c1ce284..7c35d58 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -539,18 +539,18 @@ static int fat_remount(struct super_block *sb, int *flags, char *data)
return 0;
}
-static int fat_statfs(struct super_block *sb, struct kstatfs *buf)
+static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
{
- struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
/* If the count of free cluster is still unknown, counts it here. */
if (sbi->free_clusters == -1) {
- int err = fat_count_free_clusters(sb);
+ int err = fat_count_free_clusters(dentry->d_sb);
if (err)
return err;
}
- buf->f_type = sb->s_magic;
+ buf->f_type = dentry->d_sb->s_magic;
buf->f_bsize = sbi->cluster_size;
buf->f_blocks = sbi->max_cluster - FAT_START_ENT;
buf->f_bfree = sbi->free_clusters;
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index 944652e..308f2b6 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -210,4 +210,3 @@ int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs)
return err;
}
-EXPORT_SYMBOL_GPL(fat_sync_bhs);
diff --git a/fs/file_table.c b/fs/file_table.c
index bcea199..506d530 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -300,5 +300,5 @@ void __init files_init(unsigned long mempages)
if (files_stat.max_files < NR_FILE)
files_stat.max_files = NR_FILE;
files_defer_init();
- percpu_counter_init(&nr_files);
+ percpu_counter_init(&nr_files, 0);
}
diff --git a/fs/freevxfs/vxfs.h b/fs/freevxfs/vxfs.h
index 583bd78..d35979a 100644
--- a/fs/freevxfs/vxfs.h
+++ b/fs/freevxfs/vxfs.h
@@ -159,11 +159,11 @@ struct vxfs_sb {
* In core superblock filesystem private data for VxFS.
*/
struct vxfs_sb_info {
- struct vxfs_sb *vsi_raw; /* raw (on disk) supeblock */
+ struct vxfs_sb *vsi_raw; /* raw (on disk) superblock */
struct buffer_head *vsi_bp; /* buffer for raw superblock*/
struct inode *vsi_fship; /* fileset header inode */
struct inode *vsi_ilist; /* inode list inode */
- struct inode *vsi_stilist; /* structual inode list inode */
+ struct inode *vsi_stilist; /* structural inode list inode */
u_long vsi_iext; /* initial inode list */
ino_t vsi_fshino; /* fileset header inode */
daddr_t vsi_oltext; /* OLT extent */
diff --git a/fs/freevxfs/vxfs_fshead.c b/fs/freevxfs/vxfs_fshead.c
index 6dee109..78948b4 100644
--- a/fs/freevxfs/vxfs_fshead.c
+++ b/fs/freevxfs/vxfs_fshead.c
@@ -112,7 +112,7 @@ vxfs_read_fshead(struct super_block *sbp)
vip = vxfs_blkiget(sbp, infp->vsi_iext, infp->vsi_fshino);
if (!vip) {
- printk(KERN_ERR "vxfs: unabled to read fsh inode\n");
+ printk(KERN_ERR "vxfs: unable to read fsh inode\n");
return -EINVAL;
}
if (!VXFS_ISFSH(vip)) {
@@ -129,13 +129,13 @@ vxfs_read_fshead(struct super_block *sbp)
infp->vsi_fship = vxfs_get_fake_inode(sbp, vip);
if (!infp->vsi_fship) {
- printk(KERN_ERR "vxfs: unabled to get fsh inode\n");
+ printk(KERN_ERR "vxfs: unable to get fsh inode\n");
goto out_free_fship;
}
sfp = vxfs_getfsh(infp->vsi_fship, 0);
if (!sfp) {
- printk(KERN_ERR "vxfs: unabled to get structural fsh\n");
+ printk(KERN_ERR "vxfs: unable to get structural fsh\n");
goto out_iput_fship;
}
@@ -145,7 +145,7 @@ vxfs_read_fshead(struct super_block *sbp)
pfp = vxfs_getfsh(infp->vsi_fship, 1);
if (!pfp) {
- printk(KERN_ERR "vxfs: unabled to get primary fsh\n");
+ printk(KERN_ERR "vxfs: unable to get primary fsh\n");
goto out_free_sfp;
}
@@ -159,7 +159,7 @@ vxfs_read_fshead(struct super_block *sbp)
infp->vsi_stilist = vxfs_get_fake_inode(sbp, tip);
if (!infp->vsi_stilist) {
- printk(KERN_ERR "vxfs: unabled to get structual list inode\n");
+ printk(KERN_ERR "vxfs: unable to get structural list inode\n");
kfree(tip);
goto out_free_pfp;
}
@@ -174,7 +174,7 @@ vxfs_read_fshead(struct super_block *sbp)
goto out_iput_stilist;
infp->vsi_ilist = vxfs_get_fake_inode(sbp, tip);
if (!infp->vsi_ilist) {
- printk(KERN_ERR "vxfs: unabled to get inode list inode\n");
+ printk(KERN_ERR "vxfs: unable to get inode list inode\n");
kfree(tip);
goto out_iput_stilist;
}
diff --git a/fs/freevxfs/vxfs_subr.c b/fs/freevxfs/vxfs_subr.c
index 50aae77..c1be118 100644
--- a/fs/freevxfs/vxfs_subr.c
+++ b/fs/freevxfs/vxfs_subr.c
@@ -71,8 +71,7 @@ vxfs_get_page(struct address_space *mapping, u_long n)
{
struct page * pp;
- pp = read_cache_page(mapping, n,
- (filler_t*)mapping->a_ops->readpage, NULL);
+ pp = read_mapping_page(mapping, n, NULL);
if (!IS_ERR(pp)) {
wait_on_page_locked(pp);
diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
index b44c916..b74b791 100644
--- a/fs/freevxfs/vxfs_super.c
+++ b/fs/freevxfs/vxfs_super.c
@@ -40,6 +40,7 @@
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/vfs.h>
+#include <linux/mount.h>
#include "vxfs.h"
#include "vxfs_extern.h"
@@ -55,7 +56,7 @@ MODULE_ALIAS("vxfs"); /* makes mount -t vxfs autoload the module */
static void vxfs_put_super(struct super_block *);
-static int vxfs_statfs(struct super_block *, struct kstatfs *);
+static int vxfs_statfs(struct dentry *, struct kstatfs *);
static int vxfs_remount(struct super_block *, int *, char *);
static struct super_operations vxfs_super_ops = {
@@ -90,12 +91,12 @@ vxfs_put_super(struct super_block *sbp)
/**
* vxfs_statfs - get filesystem information
- * @sbp: VFS superblock
+ * @dentry: VFS dentry to locate superblock
* @bufp: output buffer
*
* Description:
* vxfs_statfs fills the statfs buffer @bufp with information
- * about the filesystem described by @sbp.
+ * about the filesystem described by @dentry.
*
* Returns:
* Zero.
@@ -107,12 +108,12 @@ vxfs_put_super(struct super_block *sbp)
* This is everything but complete...
*/
static int
-vxfs_statfs(struct super_block *sbp, struct kstatfs *bufp)
+vxfs_statfs(struct dentry *dentry, struct kstatfs *bufp)
{
- struct vxfs_sb_info *infp = VXFS_SBI(sbp);
+ struct vxfs_sb_info *infp = VXFS_SBI(dentry->d_sb);
bufp->f_type = VXFS_SUPER_MAGIC;
- bufp->f_bsize = sbp->s_blocksize;
+ bufp->f_bsize = dentry->d_sb->s_blocksize;
bufp->f_blocks = infp->vsi_raw->vs_dsize;
bufp->f_bfree = infp->vsi_raw->vs_free;
bufp->f_bavail = 0;
@@ -241,10 +242,11 @@ out:
/*
* The usual module blurb.
*/
-static struct super_block *vxfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int vxfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, vxfs_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, vxfs_fill_super,
+ mnt);
}
static struct file_system_type vxfs_fs_type = {
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index f3fbe2d..031b27a 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -461,6 +461,8 @@ void sync_inodes_sb(struct super_block *sb, int wait)
{
struct writeback_control wbc = {
.sync_mode = wait ? WB_SYNC_ALL : WB_SYNC_HOLD,
+ .range_start = 0,
+ .range_end = LLONG_MAX,
};
unsigned long nr_dirty = read_page_state(nr_dirty);
unsigned long nr_unstable = read_page_state(nr_unstable);
@@ -559,6 +561,8 @@ int write_inode_now(struct inode *inode, int sync)
struct writeback_control wbc = {
.nr_to_write = LONG_MAX,
.sync_mode = WB_SYNC_ALL,
+ .range_start = 0,
+ .range_end = LLONG_MAX,
};
if (!mapping_cap_writeback_dirty(inode->i_mapping))
@@ -619,7 +623,6 @@ int generic_osync_inode(struct inode *inode, struct address_space *mapping, int
int need_write_inode_now = 0;
int err2;
- current->flags |= PF_SYNCWRITE;
if (what & OSYNC_DATA)
err = filemap_fdatawrite(mapping);
if (what & (OSYNC_METADATA|OSYNC_DATA)) {
@@ -632,7 +635,6 @@ int generic_osync_inode(struct inode *inode, struct address_space *mapping, int
if (!err)
err = err2;
}
- current->flags &= ~PF_SYNCWRITE;
spin_lock(&inode_lock);
if ((inode->i_state & I_DIRTY) &&
diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile
index c3e1f76..7243706 100644
--- a/fs/fuse/Makefile
+++ b/fs/fuse/Makefile
@@ -4,4 +4,4 @@
obj-$(CONFIG_FUSE_FS) += fuse.o
-fuse-objs := dev.o dir.o file.o inode.o
+fuse-objs := dev.o dir.o file.o inode.o control.o
diff --git a/fs/fuse/control.c b/fs/fuse/control.c
new file mode 100644
index 0000000..a3bce3a
--- /dev/null
+++ b/fs/fuse/control.c
@@ -0,0 +1,218 @@
+/*
+ FUSE: Filesystem in Userspace
+ Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
+
+ This program can be distributed under the terms of the GNU GPL.
+ See the file COPYING.
+*/
+
+#include "fuse_i.h"
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+#define FUSE_CTL_SUPER_MAGIC 0x65735543
+
+/*
+ * This is non-NULL when the single instance of the control filesystem
+ * exists. Protected by fuse_mutex
+ */
+static struct super_block *fuse_control_sb;
+
+static struct fuse_conn *fuse_ctl_file_conn_get(struct file *file)
+{
+ struct fuse_conn *fc;
+ mutex_lock(&fuse_mutex);
+ fc = file->f_dentry->d_inode->u.generic_ip;
+ if (fc)
+ fc = fuse_conn_get(fc);
+ mutex_unlock(&fuse_mutex);
+ return fc;
+}
+
+static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
+ if (fc) {
+ fuse_abort_conn(fc);
+ fuse_conn_put(fc);
+ }
+ return count;
+}
+
+static ssize_t fuse_conn_waiting_read(struct file *file, char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ char tmp[32];
+ size_t size;
+
+ if (!*ppos) {
+ struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
+ if (!fc)
+ return 0;
+
+ file->private_data=(void *)(long)atomic_read(&fc->num_waiting);
+ fuse_conn_put(fc);
+ }
+ size = sprintf(tmp, "%ld\n", (long)file->private_data);
+ return simple_read_from_buffer(buf, len, ppos, tmp, size);
+}
+
+static const struct file_operations fuse_ctl_abort_ops = {
+ .open = nonseekable_open,
+ .write = fuse_conn_abort_write,
+};
+
+static const struct file_operations fuse_ctl_waiting_ops = {
+ .open = nonseekable_open,
+ .read = fuse_conn_waiting_read,
+};
+
+static struct dentry *fuse_ctl_add_dentry(struct dentry *parent,
+ struct fuse_conn *fc,
+ const char *name,
+ int mode, int nlink,
+ struct inode_operations *iop,
+ const struct file_operations *fop)
+{
+ struct dentry *dentry;
+ struct inode *inode;
+
+ BUG_ON(fc->ctl_ndents >= FUSE_CTL_NUM_DENTRIES);
+ dentry = d_alloc_name(parent, name);
+ if (!dentry)
+ return NULL;
+
+ fc->ctl_dentry[fc->ctl_ndents++] = dentry;
+ inode = new_inode(fuse_control_sb);
+ if (!inode)
+ return NULL;
+
+ inode->i_mode = mode;
+ inode->i_uid = fc->user_id;
+ inode->i_gid = fc->group_id;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ /* setting ->i_op to NULL is not allowed */
+ if (iop)
+ inode->i_op = iop;
+ inode->i_fop = fop;
+ inode->i_nlink = nlink;
+ inode->u.generic_ip = fc;
+ d_add(dentry, inode);
+ return dentry;
+}
+
+/*
+ * Add a connection to the control filesystem (if it exists). Caller
+ * must host fuse_mutex
+ */
+int fuse_ctl_add_conn(struct fuse_conn *fc)
+{
+ struct dentry *parent;
+ char name[32];
+
+ if (!fuse_control_sb)
+ return 0;
+
+ parent = fuse_control_sb->s_root;
+ parent->d_inode->i_nlink++;
+ sprintf(name, "%llu", (unsigned long long) fc->id);
+ parent = fuse_ctl_add_dentry(parent, fc, name, S_IFDIR | 0500, 2,
+ &simple_dir_inode_operations,
+ &simple_dir_operations);
+ if (!parent)
+ goto err;
+
+ if (!fuse_ctl_add_dentry(parent, fc, "waiting", S_IFREG | 0400, 1,
+ NULL, &fuse_ctl_waiting_ops) ||
+ !fuse_ctl_add_dentry(parent, fc, "abort", S_IFREG | 0200, 1,
+ NULL, &fuse_ctl_abort_ops))
+ goto err;
+
+ return 0;
+
+ err:
+ fuse_ctl_remove_conn(fc);
+ return -ENOMEM;
+}
+
+/*
+ * Remove a connection from the control filesystem (if it exists).
+ * Caller must host fuse_mutex
+ */
+void fuse_ctl_remove_conn(struct fuse_conn *fc)
+{
+ int i;
+
+ if (!fuse_control_sb)
+ return;
+
+ for (i = fc->ctl_ndents - 1; i >= 0; i--) {
+ struct dentry *dentry = fc->ctl_dentry[i];
+ dentry->d_inode->u.generic_ip = NULL;
+ d_drop(dentry);
+ dput(dentry);
+ }
+ fuse_control_sb->s_root->d_inode->i_nlink--;
+}
+
+static int fuse_ctl_fill_super(struct super_block *sb, void *data, int silent)
+{
+ struct tree_descr empty_descr = {""};
+ struct fuse_conn *fc;
+ int err;
+
+ err = simple_fill_super(sb, FUSE_CTL_SUPER_MAGIC, &empty_descr);
+ if (err)
+ return err;
+
+ mutex_lock(&fuse_mutex);
+ BUG_ON(fuse_control_sb);
+ fuse_control_sb = sb;
+ list_for_each_entry(fc, &fuse_conn_list, entry) {
+ err = fuse_ctl_add_conn(fc);
+ if (err) {
+ fuse_control_sb = NULL;
+ mutex_unlock(&fuse_mutex);
+ return err;
+ }
+ }
+ mutex_unlock(&fuse_mutex);
+
+ return 0;
+}
+
+static int fuse_ctl_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *raw_data,
+ struct vfsmount *mnt)
+{
+ return get_sb_single(fs_type, flags, raw_data,
+ fuse_ctl_fill_super, mnt);
+}
+
+static void fuse_ctl_kill_sb(struct super_block *sb)
+{
+ mutex_lock(&fuse_mutex);
+ fuse_control_sb = NULL;
+ mutex_unlock(&fuse_mutex);
+
+ kill_litter_super(sb);
+}
+
+static struct file_system_type fuse_ctl_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "fusectl",
+ .get_sb = fuse_ctl_get_sb,
+ .kill_sb = fuse_ctl_kill_sb,
+};
+
+int __init fuse_ctl_init(void)
+{
+ return register_filesystem(&fuse_ctl_fs_type);
+}
+
+void fuse_ctl_cleanup(void)
+{
+ unregister_filesystem(&fuse_ctl_fs_type);
+}
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 104a62d..1e2006c 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -34,6 +34,7 @@ static void fuse_request_init(struct fuse_req *req)
{
memset(req, 0, sizeof(*req));
INIT_LIST_HEAD(&req->list);
+ INIT_LIST_HEAD(&req->intr_entry);
init_waitqueue_head(&req->waitq);
atomic_set(&req->count, 1);
}
@@ -64,18 +65,6 @@ static void restore_sigs(sigset_t *oldset)
sigprocmask(SIG_SETMASK, oldset, NULL);
}
-/*
- * Reset request, so that it can be reused
- *
- * The caller must be _very_ careful to make sure, that it is holding
- * the only reference to req
- */
-void fuse_reset_request(struct fuse_req *req)
-{
- BUG_ON(atomic_read(&req->count) != 1);
- fuse_request_init(req);
-}
-
static void __fuse_get_request(struct fuse_req *req)
{
atomic_inc(&req->count);
@@ -88,6 +77,13 @@ static void __fuse_put_request(struct fuse_req *req)
atomic_dec(&req->count);
}
+static void fuse_req_init_context(struct fuse_req *req)
+{
+ req->in.h.uid = current->fsuid;
+ req->in.h.gid = current->fsgid;
+ req->in.h.pid = current->pid;
+}
+
struct fuse_req *fuse_get_req(struct fuse_conn *fc)
{
struct fuse_req *req;
@@ -103,14 +99,16 @@ struct fuse_req *fuse_get_req(struct fuse_conn *fc)
if (intr)
goto out;
+ err = -ENOTCONN;
+ if (!fc->connected)
+ goto out;
+
req = fuse_request_alloc();
err = -ENOMEM;
if (!req)
goto out;
- req->in.h.uid = current->fsuid;
- req->in.h.gid = current->fsgid;
- req->in.h.pid = current->pid;
+ fuse_req_init_context(req);
req->waiting = 1;
return req;
@@ -119,142 +117,183 @@ struct fuse_req *fuse_get_req(struct fuse_conn *fc)
return ERR_PTR(err);
}
-void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
+/*
+ * Return request in fuse_file->reserved_req. However that may
+ * currently be in use. If that is the case, wait for it to become
+ * available.
+ */
+static struct fuse_req *get_reserved_req(struct fuse_conn *fc,
+ struct file *file)
{
- if (atomic_dec_and_test(&req->count)) {
- if (req->waiting)
- atomic_dec(&fc->num_waiting);
- fuse_request_free(req);
- }
+ struct fuse_req *req = NULL;
+ struct fuse_file *ff = file->private_data;
+
+ do {
+ wait_event(fc->blocked_waitq, ff->reserved_req);
+ spin_lock(&fc->lock);
+ if (ff->reserved_req) {
+ req = ff->reserved_req;
+ ff->reserved_req = NULL;
+ get_file(file);
+ req->stolen_file = file;
+ }
+ spin_unlock(&fc->lock);
+ } while (!req);
+
+ return req;
}
/*
- * Called with sbput_sem held for read (request_end) or write
- * (fuse_put_super). By the time fuse_put_super() is finished, all
- * inodes belonging to background requests must be released, so the
- * iputs have to be done within the locked region.
+ * Put stolen request back into fuse_file->reserved_req
*/
-void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req)
+static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req)
{
- iput(req->inode);
- iput(req->inode2);
+ struct file *file = req->stolen_file;
+ struct fuse_file *ff = file->private_data;
+
spin_lock(&fc->lock);
- list_del(&req->bg_entry);
- if (fc->num_background == FUSE_MAX_BACKGROUND) {
- fc->blocked = 0;
- wake_up_all(&fc->blocked_waitq);
- }
- fc->num_background--;
+ fuse_request_init(req);
+ BUG_ON(ff->reserved_req);
+ ff->reserved_req = req;
+ wake_up(&fc->blocked_waitq);
spin_unlock(&fc->lock);
+ fput(file);
}
/*
- * This function is called when a request is finished. Either a reply
- * has arrived or it was interrupted (and not yet sent) or some error
- * occurred during communication with userspace, or the device file
- * was closed. In case of a background request the reference to the
- * stored objects are released. The requester thread is woken up (if
- * still waiting), the 'end' callback is called if given, else the
- * reference to the request is released
+ * Gets a requests for a file operation, always succeeds
*
- * Releasing extra reference for foreground requests must be done
- * within the same locked region as setting state to finished. This
- * is because fuse_reset_request() may be called after request is
- * finished and it must be the sole possessor. If request is
- * interrupted and put in the background, it will return with an error
- * and hence never be reset and reused.
+ * This is used for sending the FLUSH request, which must get to
+ * userspace, due to POSIX locks which may need to be unlocked.
*
- * Called with fc->lock, unlocks it
+ * If allocation fails due to OOM, use the reserved request in
+ * fuse_file.
+ *
+ * This is very unlikely to deadlock accidentally, since the
+ * filesystem should not have it's own file open. If deadlock is
+ * intentional, it can still be broken by "aborting" the filesystem.
*/
-static void request_end(struct fuse_conn *fc, struct fuse_req *req)
+struct fuse_req *fuse_get_req_nofail(struct fuse_conn *fc, struct file *file)
{
- list_del(&req->list);
- req->state = FUSE_REQ_FINISHED;
- if (!req->background) {
- spin_unlock(&fc->lock);
- wake_up(&req->waitq);
- fuse_put_request(fc, req);
- } else {
- void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
- req->end = NULL;
- spin_unlock(&fc->lock);
- down_read(&fc->sbput_sem);
- if (fc->mounted)
- fuse_release_background(fc, req);
- up_read(&fc->sbput_sem);
+ struct fuse_req *req;
- /* fput must go outside sbput_sem, otherwise it can deadlock */
- if (req->file)
- fput(req->file);
+ atomic_inc(&fc->num_waiting);
+ wait_event(fc->blocked_waitq, !fc->blocked);
+ req = fuse_request_alloc();
+ if (!req)
+ req = get_reserved_req(fc, file);
- if (end)
- end(fc, req);
+ fuse_req_init_context(req);
+ req->waiting = 1;
+ return req;
+}
+
+void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
+{
+ if (atomic_dec_and_test(&req->count)) {
+ if (req->waiting)
+ atomic_dec(&fc->num_waiting);
+
+ if (req->stolen_file)
+ put_reserved_req(fc, req);
else
- fuse_put_request(fc, req);
+ fuse_request_free(req);
}
}
/*
- * Unfortunately request interruption not just solves the deadlock
- * problem, it causes problems too. These stem from the fact, that an
- * interrupted request is continued to be processed in userspace,
- * while all the locks and object references (inode and file) held
- * during the operation are released.
- *
- * To release the locks is exactly why there's a need to interrupt the
- * request, so there's not a lot that can be done about this, except
- * introduce additional locking in userspace.
- *
- * More important is to keep inode and file references until userspace
- * has replied, otherwise FORGET and RELEASE could be sent while the
- * inode/file is still used by the filesystem.
- *
- * For this reason the concept of "background" request is introduced.
- * An interrupted request is backgrounded if it has been already sent
- * to userspace. Backgrounding involves getting an extra reference to
- * inode(s) or file used in the request, and adding the request to
- * fc->background list. When a reply is received for a background
- * request, the object references are released, and the request is
- * removed from the list. If the filesystem is unmounted while there
- * are still background requests, the list is walked and references
- * are released as if a reply was received.
+ * This function is called when a request is finished. Either a reply
+ * has arrived or it was aborted (and not yet sent) or some error
+ * occurred during communication with userspace, or the device file
+ * was closed. The requester thread is woken up (if still waiting),
+ * the 'end' callback is called if given, else the reference to the
+ * request is released
*
- * There's one more use for a background request. The RELEASE message is
- * always sent as background, since it doesn't return an error or
- * data.
+ * Called with fc->lock, unlocks it
*/
-static void background_request(struct fuse_conn *fc, struct fuse_req *req)
-{
- req->background = 1;
- list_add(&req->bg_entry, &fc->background);
- fc->num_background++;
- if (fc->num_background == FUSE_MAX_BACKGROUND)
- fc->blocked = 1;
- if (req->inode)
- req->inode = igrab(req->inode);
- if (req->inode2)
- req->inode2 = igrab(req->inode2);
+static void request_end(struct fuse_conn *fc, struct fuse_req *req)
+{
+ void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
+ req->end = NULL;
+ list_del(&req->list);
+ list_del(&req->intr_entry);
+ req->state = FUSE_REQ_FINISHED;
+ if (req->background) {
+ if (fc->num_background == FUSE_MAX_BACKGROUND) {
+ fc->blocked = 0;
+ wake_up_all(&fc->blocked_waitq);
+ }
+ fc->num_background--;
+ }
+ spin_unlock(&fc->lock);
+ dput(req->dentry);
+ mntput(req->vfsmount);
if (req->file)
- get_file(req->file);
+ fput(req->file);
+ wake_up(&req->waitq);
+ if (end)
+ end(fc, req);
+ else
+ fuse_put_request(fc, req);
}
-/* Called with fc->lock held. Releases, and then reacquires it. */
-static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
+static void wait_answer_interruptible(struct fuse_conn *fc,
+ struct fuse_req *req)
{
- sigset_t oldset;
+ if (signal_pending(current))
+ return;
spin_unlock(&fc->lock);
- block_sigs(&oldset);
wait_event_interruptible(req->waitq, req->state == FUSE_REQ_FINISHED);
- restore_sigs(&oldset);
spin_lock(&fc->lock);
- if (req->state == FUSE_REQ_FINISHED && !req->interrupted)
- return;
+}
+
+static void queue_interrupt(struct fuse_conn *fc, struct fuse_req *req)
+{
+ list_add_tail(&req->intr_entry, &fc->interrupts);
+ wake_up(&fc->waitq);
+ kill_fasync(&fc->fasync, SIGIO, POLL_IN);
+}
+
+/* Called with fc->lock held. Releases, and then reacquires it. */
+static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
+{
+ if (!fc->no_interrupt) {
+ /* Any signal may interrupt this */
+ wait_answer_interruptible(fc, req);
+
+ if (req->aborted)
+ goto aborted;
+ if (req->state == FUSE_REQ_FINISHED)
+ return;
- if (!req->interrupted) {
- req->out.h.error = -EINTR;
req->interrupted = 1;
+ if (req->state == FUSE_REQ_SENT)
+ queue_interrupt(fc, req);
+ }
+
+ if (req->force) {
+ spin_unlock(&fc->lock);
+ wait_event(req->waitq, req->state == FUSE_REQ_FINISHED);
+ spin_lock(&fc->lock);
+ } else {
+ sigset_t oldset;
+
+ /* Only fatal signals may interrupt this */
+ block_sigs(&oldset);
+ wait_answer_interruptible(fc, req);
+ restore_sigs(&oldset);
}
+
+ if (req->aborted)
+ goto aborted;
+ if (req->state == FUSE_REQ_FINISHED)
+ return;
+
+ req->out.h.error = -EINTR;
+ req->aborted = 1;
+
+ aborted:
if (req->locked) {
/* This is uninterruptible sleep, because data is
being copied to/from the buffers of req. During
@@ -268,8 +307,11 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
if (req->state == FUSE_REQ_PENDING) {
list_del(&req->list);
__fuse_put_request(req);
- } else if (req->state == FUSE_REQ_SENT)
- background_request(fc, req);
+ } else if (req->state == FUSE_REQ_SENT) {
+ spin_unlock(&fc->lock);
+ wait_event(req->waitq, req->state == FUSE_REQ_FINISHED);
+ spin_lock(&fc->lock);
+ }
}
static unsigned len_args(unsigned numargs, struct fuse_arg *args)
@@ -283,13 +325,19 @@ static unsigned len_args(unsigned numargs, struct fuse_arg *args)
return nbytes;
}
+static u64 fuse_get_unique(struct fuse_conn *fc)
+ {
+ fc->reqctr++;
+ /* zero is special */
+ if (fc->reqctr == 0)
+ fc->reqctr = 1;
+
+ return fc->reqctr;
+}
+
static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
{
- fc->reqctr++;
- /* zero is special */
- if (fc->reqctr == 0)
- fc->reqctr = 1;
- req->in.h.unique = fc->reqctr;
+ req->in.h.unique = fuse_get_unique(fc);
req->in.h.len = sizeof(struct fuse_in_header) +
len_args(req->in.numargs, (struct fuse_arg *) req->in.args);
list_add_tail(&req->list, &fc->pending);
@@ -302,9 +350,6 @@ static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
kill_fasync(&fc->fasync, SIGIO, POLL_IN);
}
-/*
- * This can only be interrupted by a SIGKILL
- */
void request_send(struct fuse_conn *fc, struct fuse_req *req)
{
req->isreply = 1;
@@ -327,8 +372,12 @@ void request_send(struct fuse_conn *fc, struct fuse_req *req)
static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
{
spin_lock(&fc->lock);
- background_request(fc, req);
if (fc->connected) {
+ req->background = 1;
+ fc->num_background++;
+ if (fc->num_background == FUSE_MAX_BACKGROUND)
+ fc->blocked = 1;
+
queue_request(fc, req);
spin_unlock(&fc->lock);
} else {
@@ -352,14 +401,14 @@ void request_send_background(struct fuse_conn *fc, struct fuse_req *req)
/*
* Lock the request. Up to the next unlock_request() there mustn't be
* anything that could cause a page-fault. If the request was already
- * interrupted bail out.
+ * aborted bail out.
*/
static int lock_request(struct fuse_conn *fc, struct fuse_req *req)
{
int err = 0;
if (req) {
spin_lock(&fc->lock);
- if (req->interrupted)
+ if (req->aborted)
err = -ENOENT;
else
req->locked = 1;
@@ -369,7 +418,7 @@ static int lock_request(struct fuse_conn *fc, struct fuse_req *req)
}
/*
- * Unlock request. If it was interrupted during being locked, the
+ * Unlock request. If it was aborted during being locked, the
* requester thread is currently waiting for it to be unlocked, so
* wake it up.
*/
@@ -378,7 +427,7 @@ static void unlock_request(struct fuse_conn *fc, struct fuse_req *req)
if (req) {
spin_lock(&fc->lock);
req->locked = 0;
- if (req->interrupted)
+ if (req->aborted)
wake_up(&req->waitq);
spin_unlock(&fc->lock);
}
@@ -557,13 +606,18 @@ static int fuse_copy_args(struct fuse_copy_state *cs, unsigned numargs,
return err;
}
+static int request_pending(struct fuse_conn *fc)
+{
+ return !list_empty(&fc->pending) || !list_empty(&fc->interrupts);
+}
+
/* Wait until a request is available on the pending list */
static void request_wait(struct fuse_conn *fc)
{
DECLARE_WAITQUEUE(wait, current);
add_wait_queue_exclusive(&fc->waitq, &wait);
- while (fc->connected && list_empty(&fc->pending)) {
+ while (fc->connected && !request_pending(fc)) {
set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current))
break;
@@ -577,11 +631,50 @@ static void request_wait(struct fuse_conn *fc)
}
/*
+ * Transfer an interrupt request to userspace
+ *
+ * Unlike other requests this is assembled on demand, without a need
+ * to allocate a separate fuse_req structure.
+ *
+ * Called with fc->lock held, releases it
+ */
+static int fuse_read_interrupt(struct fuse_conn *fc, struct fuse_req *req,
+ const struct iovec *iov, unsigned long nr_segs)
+{
+ struct fuse_copy_state cs;
+ struct fuse_in_header ih;
+ struct fuse_interrupt_in arg;
+ unsigned reqsize = sizeof(ih) + sizeof(arg);
+ int err;
+
+ list_del_init(&req->intr_entry);
+ req->intr_unique = fuse_get_unique(fc);
+ memset(&ih, 0, sizeof(ih));
+ memset(&arg, 0, sizeof(arg));
+ ih.len = reqsize;
+ ih.opcode = FUSE_INTERRUPT;
+ ih.unique = req->intr_unique;
+ arg.unique = req->in.h.unique;
+
+ spin_unlock(&fc->lock);
+ if (iov_length(iov, nr_segs) < reqsize)
+ return -EINVAL;
+
+ fuse_copy_init(&cs, fc, 1, NULL, iov, nr_segs);
+ err = fuse_copy_one(&cs, &ih, sizeof(ih));
+ if (!err)
+ err = fuse_copy_one(&cs, &arg, sizeof(arg));
+ fuse_copy_finish(&cs);
+
+ return err ? err : reqsize;
+}
+
+/*
* Read a single request into the userspace filesystem's buffer. This
* function waits until a request is available, then removes it from
* the pending list and copies request data to userspace buffer. If
- * no reply is needed (FORGET) or request has been interrupted or
- * there was an error during the copying then it's finished by calling
+ * no reply is needed (FORGET) or request has been aborted or there
+ * was an error during the copying then it's finished by calling
* request_end(). Otherwise add it to the processing list, and set
* the 'sent' flag.
*/
@@ -601,7 +694,7 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
spin_lock(&fc->lock);
err = -EAGAIN;
if ((file->f_flags & O_NONBLOCK) && fc->connected &&
- list_empty(&fc->pending))
+ !request_pending(fc))
goto err_unlock;
request_wait(fc);
@@ -609,9 +702,15 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
if (!fc->connected)
goto err_unlock;
err = -ERESTARTSYS;
- if (list_empty(&fc->pending))
+ if (!request_pending(fc))
goto err_unlock;
+ if (!list_empty(&fc->interrupts)) {
+ req = list_entry(fc->interrupts.next, struct fuse_req,
+ intr_entry);
+ return fuse_read_interrupt(fc, req, iov, nr_segs);
+ }
+
req = list_entry(fc->pending.next, struct fuse_req, list);
req->state = FUSE_REQ_READING;
list_move(&req->list, &fc->io);
@@ -636,10 +735,10 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
fuse_copy_finish(&cs);
spin_lock(&fc->lock);
req->locked = 0;
- if (!err && req->interrupted)
+ if (!err && req->aborted)
err = -ENOENT;
if (err) {
- if (!req->interrupted)
+ if (!req->aborted)
req->out.h.error = -EIO;
request_end(fc, req);
return err;
@@ -649,6 +748,8 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
else {
req->state = FUSE_REQ_SENT;
list_move_tail(&req->list, &fc->processing);
+ if (req->interrupted)
+ queue_interrupt(fc, req);
spin_unlock(&fc->lock);
}
return reqsize;
@@ -675,7 +776,7 @@ static struct fuse_req *request_find(struct fuse_conn *fc, u64 unique)
list_for_each(entry, &fc->processing) {
struct fuse_req *req;
req = list_entry(entry, struct fuse_req, list);
- if (req->in.h.unique == unique)
+ if (req->in.h.unique == unique || req->intr_unique == unique)
return req;
}
return NULL;
@@ -741,17 +842,33 @@ static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov,
goto err_unlock;
req = request_find(fc, oh.unique);
- err = -EINVAL;
if (!req)
goto err_unlock;
- if (req->interrupted) {
+ if (req->aborted) {
spin_unlock(&fc->lock);
fuse_copy_finish(&cs);
spin_lock(&fc->lock);
request_end(fc, req);
return -ENOENT;
}
+ /* Is it an interrupt reply? */
+ if (req->intr_unique == oh.unique) {
+ err = -EINVAL;
+ if (nbytes != sizeof(struct fuse_out_header))
+ goto err_unlock;
+
+ if (oh.error == -ENOSYS)
+ fc->no_interrupt = 1;
+ else if (oh.error == -EAGAIN)
+ queue_interrupt(fc, req);
+
+ spin_unlock(&fc->lock);
+ fuse_copy_finish(&cs);
+ return nbytes;
+ }
+
+ req->state = FUSE_REQ_WRITING;
list_move(&req->list, &fc->io);
req->out.h = oh;
req->locked = 1;
@@ -764,9 +881,9 @@ static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov,
spin_lock(&fc->lock);
req->locked = 0;
if (!err) {
- if (req->interrupted)
+ if (req->aborted)
err = -ENOENT;
- } else if (!req->interrupted)
+ } else if (!req->aborted)
req->out.h.error = -EIO;
request_end(fc, req);
@@ -800,7 +917,7 @@ static unsigned fuse_dev_poll(struct file *file, poll_table *wait)
spin_lock(&fc->lock);
if (!fc->connected)
mask = POLLERR;
- else if (!list_empty(&fc->pending))
+ else if (request_pending(fc))
mask |= POLLIN | POLLRDNORM;
spin_unlock(&fc->lock);
@@ -826,7 +943,7 @@ static void end_requests(struct fuse_conn *fc, struct list_head *head)
/*
* Abort requests under I/O
*
- * The requests are set to interrupted and finished, and the request
+ * The requests are set to aborted and finished, and the request
* waiter is woken up. This will make request_wait_answer() wait
* until the request is unlocked and then return.
*
@@ -841,7 +958,7 @@ static void end_io_requests(struct fuse_conn *fc)
list_entry(fc->io.next, struct fuse_req, list);
void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
- req->interrupted = 1;
+ req->aborted = 1;
req->out.h.error = -ECONNABORTED;
req->state = FUSE_REQ_FINISHED;
list_del_init(&req->list);
@@ -874,19 +991,20 @@ static void end_io_requests(struct fuse_conn *fc)
* onto the pending list is prevented by req->connected being false.
*
* Progression of requests under I/O to the processing list is
- * prevented by the req->interrupted flag being true for these
- * requests. For this reason requests on the io list must be aborted
- * first.
+ * prevented by the req->aborted flag being true for these requests.
+ * For this reason requests on the io list must be aborted first.
*/
void fuse_abort_conn(struct fuse_conn *fc)
{
spin_lock(&fc->lock);
if (fc->connected) {
fc->connected = 0;
+ fc->blocked = 0;
end_io_requests(fc);
end_requests(fc, &fc->pending);
end_requests(fc, &fc->processing);
wake_up_all(&fc->waitq);
+ wake_up_all(&fc->blocked_waitq);
kill_fasync(&fc->fasync, SIGIO, POLL_IN);
}
spin_unlock(&fc->lock);
@@ -902,7 +1020,7 @@ static int fuse_dev_release(struct inode *inode, struct file *file)
end_requests(fc, &fc->processing);
spin_unlock(&fc->lock);
fasync_helper(-1, file, 0, &fc->fasync);
- kobject_put(&fc->kobj);
+ fuse_conn_put(fc);
}
return 0;
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 8d7546e..72a74cd 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1,6 +1,6 @@
/*
FUSE: Filesystem in Userspace
- Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
+ Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
@@ -79,7 +79,6 @@ static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
{
req->in.h.opcode = FUSE_LOOKUP;
req->in.h.nodeid = get_node_id(dir);
- req->inode = dir;
req->in.numargs = 1;
req->in.args[0].size = entry->d_name.len + 1;
req->in.args[0].value = entry->d_name.name;
@@ -225,6 +224,20 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
}
/*
+ * Synchronous release for the case when something goes wrong in CREATE_OPEN
+ */
+static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff,
+ u64 nodeid, int flags)
+{
+ struct fuse_req *req;
+
+ req = fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE);
+ req->force = 1;
+ request_send(fc, req);
+ fuse_put_request(fc, req);
+}
+
+/*
* Atomic create+open operation
*
* If the filesystem doesn't support this, then fall back to separate
@@ -237,6 +250,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
struct inode *inode;
struct fuse_conn *fc = get_fuse_conn(dir);
struct fuse_req *req;
+ struct fuse_req *forget_req;
struct fuse_open_in inarg;
struct fuse_open_out outopen;
struct fuse_entry_out outentry;
@@ -247,9 +261,14 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
if (fc->no_create)
return -ENOSYS;
+ forget_req = fuse_get_req(fc);
+ if (IS_ERR(forget_req))
+ return PTR_ERR(forget_req);
+
req = fuse_get_req(fc);
+ err = PTR_ERR(req);
if (IS_ERR(req))
- return PTR_ERR(req);
+ goto out_put_forget_req;
err = -ENOMEM;
ff = fuse_file_alloc();
@@ -262,7 +281,6 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
inarg.mode = mode;
req->in.h.opcode = FUSE_CREATE;
req->in.h.nodeid = get_node_id(dir);
- req->inode = dir;
req->in.numargs = 2;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
@@ -285,25 +303,23 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
goto out_free_ff;
+ fuse_put_request(fc, req);
inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
&outentry.attr);
- err = -ENOMEM;
if (!inode) {
flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
ff->fh = outopen.fh;
- /* Special release, with inode = NULL, this will
- trigger a 'forget' request when the release is
- complete */
- fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0);
- goto out_put_request;
+ fuse_sync_release(fc, ff, outentry.nodeid, flags);
+ fuse_send_forget(fc, forget_req, outentry.nodeid, 1);
+ return -ENOMEM;
}
- fuse_put_request(fc, req);
+ fuse_put_request(fc, forget_req);
d_instantiate(entry, inode);
fuse_change_timeout(entry, &outentry);
file = lookup_instantiate_filp(nd, entry, generic_file_open);
if (IS_ERR(file)) {
ff->fh = outopen.fh;
- fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0);
+ fuse_sync_release(fc, ff, outentry.nodeid, flags);
return PTR_ERR(file);
}
fuse_finish_open(inode, file, ff, &outopen);
@@ -313,6 +329,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
fuse_file_free(ff);
out_put_request:
fuse_put_request(fc, req);
+ out_put_forget_req:
+ fuse_put_request(fc, forget_req);
return err;
}
@@ -328,7 +346,6 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
int err;
req->in.h.nodeid = get_node_id(dir);
- req->inode = dir;
req->out.numargs = 1;
req->out.args[0].size = sizeof(outarg);
req->out.args[0].value = &outarg;
@@ -448,7 +465,6 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)
req->in.h.opcode = FUSE_UNLINK;
req->in.h.nodeid = get_node_id(dir);
- req->inode = dir;
req->in.numargs = 1;
req->in.args[0].size = entry->d_name.len + 1;
req->in.args[0].value = entry->d_name.name;
@@ -480,7 +496,6 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
req->in.h.opcode = FUSE_RMDIR;
req->in.h.nodeid = get_node_id(dir);
- req->inode = dir;
req->in.numargs = 1;
req->in.args[0].size = entry->d_name.len + 1;
req->in.args[0].value = entry->d_name.name;
@@ -510,8 +525,6 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
inarg.newdir = get_node_id(newdir);
req->in.h.opcode = FUSE_RENAME;
req->in.h.nodeid = get_node_id(olddir);
- req->inode = olddir;
- req->inode2 = newdir;
req->in.numargs = 3;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
@@ -558,7 +571,6 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
memset(&inarg, 0, sizeof(inarg));
inarg.oldnodeid = get_node_id(inode);
req->in.h.opcode = FUSE_LINK;
- req->inode2 = inode;
req->in.numargs = 2;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
@@ -587,7 +599,6 @@ int fuse_do_getattr(struct inode *inode)
req->in.h.opcode = FUSE_GETATTR;
req->in.h.nodeid = get_node_id(inode);
- req->inode = inode;
req->out.numargs = 1;
req->out.args[0].size = sizeof(arg);
req->out.args[0].value = &arg;
@@ -679,7 +690,6 @@ static int fuse_access(struct inode *inode, int mask)
inarg.mask = mask;
req->in.h.opcode = FUSE_ACCESS;
req->in.h.nodeid = get_node_id(inode);
- req->inode = inode;
req->in.numargs = 1;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
@@ -820,7 +830,6 @@ static char *read_link(struct dentry *dentry)
}
req->in.h.opcode = FUSE_READLINK;
req->in.h.nodeid = get_node_id(inode);
- req->inode = inode;
req->out.argvar = 1;
req->out.numargs = 1;
req->out.args[0].size = PAGE_SIZE - 1;
@@ -939,7 +948,6 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
iattr_to_fattr(attr, &inarg);
req->in.h.opcode = FUSE_SETATTR;
req->in.h.nodeid = get_node_id(inode);
- req->inode = inode;
req->in.numargs = 1;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
@@ -1002,7 +1010,6 @@ static int fuse_setxattr(struct dentry *entry, const char *name,
inarg.flags = flags;
req->in.h.opcode = FUSE_SETXATTR;
req->in.h.nodeid = get_node_id(inode);
- req->inode = inode;
req->in.numargs = 3;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
@@ -1041,7 +1048,6 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
inarg.size = size;
req->in.h.opcode = FUSE_GETXATTR;
req->in.h.nodeid = get_node_id(inode);
- req->inode = inode;
req->in.numargs = 2;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
@@ -1091,7 +1097,6 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
inarg.size = size;
req->in.h.opcode = FUSE_LISTXATTR;
req->in.h.nodeid = get_node_id(inode);
- req->inode = inode;
req->in.numargs = 1;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
@@ -1135,7 +1140,6 @@ static int fuse_removexattr(struct dentry *entry, const char *name)
req->in.h.opcode = FUSE_REMOVEXATTR;
req->in.h.nodeid = get_node_id(inode);
- req->inode = inode;
req->in.numargs = 1;
req->in.args[0].size = strlen(name) + 1;
req->in.args[0].value = name;
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index fc342cf..28aa81e 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -30,7 +30,6 @@ static int fuse_send_open(struct inode *inode, struct file *file, int isdir,
inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
req->in.h.opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN;
req->in.h.nodeid = get_node_id(inode);
- req->inode = inode;
req->in.numargs = 1;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
@@ -49,8 +48,8 @@ struct fuse_file *fuse_file_alloc(void)
struct fuse_file *ff;
ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL);
if (ff) {
- ff->release_req = fuse_request_alloc();
- if (!ff->release_req) {
+ ff->reserved_req = fuse_request_alloc();
+ if (!ff->reserved_req) {
kfree(ff);
ff = NULL;
}
@@ -60,7 +59,7 @@ struct fuse_file *fuse_file_alloc(void)
void fuse_file_free(struct fuse_file *ff)
{
- fuse_request_free(ff->release_req);
+ fuse_request_free(ff->reserved_req);
kfree(ff);
}
@@ -113,37 +112,22 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir)
return err;
}
-/* Special case for failed iget in CREATE */
-static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req)
+struct fuse_req *fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags,
+ int opcode)
{
- /* If called from end_io_requests(), req has more than one
- reference and fuse_reset_request() cannot work */
- if (fc->connected) {
- u64 nodeid = req->in.h.nodeid;
- fuse_reset_request(req);
- fuse_send_forget(fc, req, nodeid, 1);
- } else
- fuse_put_request(fc, req);
-}
-
-void fuse_send_release(struct fuse_conn *fc, struct fuse_file *ff,
- u64 nodeid, struct inode *inode, int flags, int isdir)
-{
- struct fuse_req * req = ff->release_req;
+ struct fuse_req *req = ff->reserved_req;
struct fuse_release_in *inarg = &req->misc.release_in;
inarg->fh = ff->fh;
inarg->flags = flags;
- req->in.h.opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE;
+ req->in.h.opcode = opcode;
req->in.h.nodeid = nodeid;
- req->inode = inode;
req->in.numargs = 1;
req->in.args[0].size = sizeof(struct fuse_release_in);
req->in.args[0].value = inarg;
- request_send_background(fc, req);
- if (!inode)
- req->end = fuse_release_end;
kfree(ff);
+
+ return req;
}
int fuse_release_common(struct inode *inode, struct file *file, int isdir)
@@ -151,8 +135,15 @@ int fuse_release_common(struct inode *inode, struct file *file, int isdir)
struct fuse_file *ff = file->private_data;
if (ff) {
struct fuse_conn *fc = get_fuse_conn(inode);
- u64 nodeid = get_node_id(inode);
- fuse_send_release(fc, ff, nodeid, inode, file->f_flags, isdir);
+ struct fuse_req *req;
+
+ req = fuse_release_fill(ff, get_node_id(inode), file->f_flags,
+ isdir ? FUSE_RELEASEDIR : FUSE_RELEASE);
+
+ /* Hold vfsmount and dentry until release is finished */
+ req->vfsmount = mntget(file->f_vfsmnt);
+ req->dentry = dget(file->f_dentry);
+ request_send_background(fc, req);
}
/* Return value is ignored by VFS */
@@ -169,7 +160,29 @@ static int fuse_release(struct inode *inode, struct file *file)
return fuse_release_common(inode, file, 0);
}
-static int fuse_flush(struct file *file)
+/*
+ * Scramble the ID space with XTEA, so that the value of the files_struct
+ * pointer is not exposed to userspace.
+ */
+static u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id)
+{
+ u32 *k = fc->scramble_key;
+ u64 v = (unsigned long) id;
+ u32 v0 = v;
+ u32 v1 = v >> 32;
+ u32 sum = 0;
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ v0 += ((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + k[sum & 3]);
+ sum += 0x9E3779B9;
+ v1 += ((v0 << 4 ^ v0 >> 5) + v0) ^ (sum + k[sum>>11 & 3]);
+ }
+
+ return (u64) v0 + ((u64) v1 << 32);
+}
+
+static int fuse_flush(struct file *file, fl_owner_t id)
{
struct inode *inode = file->f_dentry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
@@ -184,19 +197,16 @@ static int fuse_flush(struct file *file)
if (fc->no_flush)
return 0;
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
+ req = fuse_get_req_nofail(fc, file);
memset(&inarg, 0, sizeof(inarg));
inarg.fh = ff->fh;
+ inarg.lock_owner = fuse_lock_owner_id(fc, id);
req->in.h.opcode = FUSE_FLUSH;
req->in.h.nodeid = get_node_id(inode);
- req->inode = inode;
- req->file = file;
req->in.numargs = 1;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
+ req->force = 1;
request_send(fc, req);
err = req->out.h.error;
fuse_put_request(fc, req);
@@ -232,8 +242,6 @@ int fuse_fsync_common(struct file *file, struct dentry *de, int datasync,
inarg.fsync_flags = datasync ? 1 : 0;
req->in.h.opcode = isdir ? FUSE_FSYNCDIR : FUSE_FSYNC;
req->in.h.nodeid = get_node_id(inode);
- req->inode = inode;
- req->file = file;
req->in.numargs = 1;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
@@ -266,8 +274,6 @@ void fuse_read_fill(struct fuse_req *req, struct file *file,
inarg->size = count;
req->in.h.opcode = opcode;
req->in.h.nodeid = get_node_id(inode);
- req->inode = inode;
- req->file = file;
req->in.numargs = 1;
req->in.args[0].size = sizeof(struct fuse_read_in);
req->in.args[0].value = inarg;
@@ -342,6 +348,8 @@ static void fuse_send_readpages(struct fuse_req *req, struct file *file,
req->out.page_zeroing = 1;
fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
if (fc->async_read) {
+ get_file(file);
+ req->file = file;
req->end = fuse_readpages_end;
request_send_background(fc, req);
} else {
@@ -420,8 +428,6 @@ static size_t fuse_send_write(struct fuse_req *req, struct file *file,
inarg.size = count;
req->in.h.opcode = FUSE_WRITE;
req->in.h.nodeid = get_node_id(inode);
- req->inode = inode;
- req->file = file;
req->in.argpages = 1;
req->in.numargs = 2;
req->in.args[0].size = sizeof(struct fuse_write_in);
@@ -619,6 +625,126 @@ static int fuse_set_page_dirty(struct page *page)
return 0;
}
+static int convert_fuse_file_lock(const struct fuse_file_lock *ffl,
+ struct file_lock *fl)
+{
+ switch (ffl->type) {
+ case F_UNLCK:
+ break;
+
+ case F_RDLCK:
+ case F_WRLCK:
+ if (ffl->start > OFFSET_MAX || ffl->end > OFFSET_MAX ||
+ ffl->end < ffl->start)
+ return -EIO;
+
+ fl->fl_start = ffl->start;
+ fl->fl_end = ffl->end;
+ fl->fl_pid = ffl->pid;
+ break;
+
+ default:
+ return -EIO;
+ }
+ fl->fl_type = ffl->type;
+ return 0;
+}
+
+static void fuse_lk_fill(struct fuse_req *req, struct file *file,
+ const struct file_lock *fl, int opcode, pid_t pid)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_file *ff = file->private_data;
+ struct fuse_lk_in *arg = &req->misc.lk_in;
+
+ arg->fh = ff->fh;
+ arg->owner = fuse_lock_owner_id(fc, fl->fl_owner);
+ arg->lk.start = fl->fl_start;
+ arg->lk.end = fl->fl_end;
+ arg->lk.type = fl->fl_type;
+ arg->lk.pid = pid;
+ req->in.h.opcode = opcode;
+ req->in.h.nodeid = get_node_id(inode);
+ req->in.numargs = 1;
+ req->in.args[0].size = sizeof(*arg);
+ req->in.args[0].value = arg;
+}
+
+static int fuse_getlk(struct file *file, struct file_lock *fl)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_req *req;
+ struct fuse_lk_out outarg;
+ int err;
+
+ req = fuse_get_req(fc);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ fuse_lk_fill(req, file, fl, FUSE_GETLK, 0);
+ req->out.numargs = 1;
+ req->out.args[0].size = sizeof(outarg);
+ req->out.args[0].value = &outarg;
+ request_send(fc, req);
+ err = req->out.h.error;
+ fuse_put_request(fc, req);
+ if (!err)
+ err = convert_fuse_file_lock(&outarg.lk, fl);
+
+ return err;
+}
+
+static int fuse_setlk(struct file *file, struct file_lock *fl)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_req *req;
+ int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK;
+ pid_t pid = fl->fl_type != F_UNLCK ? current->tgid : 0;
+ int err;
+
+ /* Unlock on close is handled by the flush method */
+ if (fl->fl_flags & FL_CLOSE)
+ return 0;
+
+ req = fuse_get_req(fc);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ fuse_lk_fill(req, file, fl, opcode, pid);
+ request_send(fc, req);
+ err = req->out.h.error;
+ /* locking is restartable */
+ if (err == -EINTR)
+ err = -ERESTARTSYS;
+ fuse_put_request(fc, req);
+ return err;
+}
+
+static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ int err;
+
+ if (cmd == F_GETLK) {
+ if (fc->no_lock) {
+ if (!posix_test_lock(file, fl, fl))
+ fl->fl_type = F_UNLCK;
+ err = 0;
+ } else
+ err = fuse_getlk(file, fl);
+ } else {
+ if (fc->no_lock)
+ err = posix_lock_file_wait(file, fl);
+ else
+ err = fuse_setlk(file, fl);
+ }
+ return err;
+}
+
static const struct file_operations fuse_file_operations = {
.llseek = generic_file_llseek,
.read = generic_file_read,
@@ -628,6 +754,7 @@ static const struct file_operations fuse_file_operations = {
.flush = fuse_flush,
.release = fuse_release,
.fsync = fuse_fsync,
+ .lock = fuse_file_lock,
.sendfile = generic_file_sendfile,
};
@@ -639,6 +766,7 @@ static const struct file_operations fuse_direct_io_file_operations = {
.flush = fuse_flush,
.release = fuse_release,
.fsync = fuse_fsync,
+ .lock = fuse_file_lock,
/* no mmap and sendfile */
};
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 0474202..0dbf966 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -8,12 +8,13 @@
#include <linux/fuse.h>
#include <linux/fs.h>
+#include <linux/mount.h>
#include <linux/wait.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/backing-dev.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
/** Max number of pages that can be used in a single read request */
#define FUSE_MAX_PAGES_PER_REQ 32
@@ -24,6 +25,9 @@
/** It could be as large as PATH_MAX, but would that have any uses? */
#define FUSE_NAME_MAX 1024
+/** Number of dentries for each connection in the control filesystem */
+#define FUSE_CTL_NUM_DENTRIES 3
+
/** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem
module will check permissions based on the file mode. Otherwise no
permission checking is done in the kernel */
@@ -33,6 +37,11 @@
doing the mount will be allowed to access the filesystem */
#define FUSE_ALLOW_OTHER (1 << 1)
+/** List of active connections */
+extern struct list_head fuse_conn_list;
+
+/** Global mutex protecting fuse_conn_list and the control filesystem */
+extern struct mutex fuse_mutex;
/** FUSE inode */
struct fuse_inode {
@@ -56,7 +65,7 @@ struct fuse_inode {
/** FUSE specific file data */
struct fuse_file {
/** Request reserved for flush and release */
- struct fuse_req *release_req;
+ struct fuse_req *reserved_req;
/** File handle used by userspace */
u64 fh;
@@ -122,6 +131,7 @@ enum fuse_req_state {
FUSE_REQ_PENDING,
FUSE_REQ_READING,
FUSE_REQ_SENT,
+ FUSE_REQ_WRITING,
FUSE_REQ_FINISHED
};
@@ -135,12 +145,15 @@ struct fuse_req {
fuse_conn */
struct list_head list;
- /** Entry on the background list */
- struct list_head bg_entry;
+ /** Entry on the interrupts list */
+ struct list_head intr_entry;
/** refcount */
atomic_t count;
+ /** Unique ID for the interrupt request */
+ u64 intr_unique;
+
/*
* The following bitfields are either set once before the
* request is queued or setting/clearing them is protected by
@@ -150,12 +163,18 @@ struct fuse_req {
/** True if the request has reply */
unsigned isreply:1;
- /** The request was interrupted */
- unsigned interrupted:1;
+ /** Force sending of the request even if interrupted */
+ unsigned force:1;
+
+ /** The request was aborted */
+ unsigned aborted:1;
/** Request is sent in the background */
unsigned background:1;
+ /** The request has been interrupted */
+ unsigned interrupted:1;
+
/** Data is being copied to/from the request */
unsigned locked:1;
@@ -181,6 +200,7 @@ struct fuse_req {
struct fuse_init_in init_in;
struct fuse_init_out init_out;
struct fuse_read_in read_in;
+ struct fuse_lk_in lk_in;
} misc;
/** page vector */
@@ -192,17 +212,20 @@ struct fuse_req {
/** offset of data on first page */
unsigned page_offset;
- /** Inode used in the request */
- struct inode *inode;
-
- /** Second inode used in the request (or NULL) */
- struct inode *inode2;
-
/** File used in the request (or NULL) */
struct file *file;
+ /** vfsmount used in release */
+ struct vfsmount *vfsmount;
+
+ /** dentry used in release */
+ struct dentry *dentry;
+
/** Request completion callback */
void (*end)(struct fuse_conn *, struct fuse_req *);
+
+ /** Request is stolen from fuse_file->reserved_req */
+ struct file *stolen_file;
};
/**
@@ -216,6 +239,9 @@ struct fuse_conn {
/** Lock protecting accessess to members of this structure */
spinlock_t lock;
+ /** Refcount */
+ atomic_t count;
+
/** The user id for this mount */
uid_t user_id;
@@ -243,13 +269,12 @@ struct fuse_conn {
/** The list of requests under I/O */
struct list_head io;
- /** Requests put in the background (RELEASE or any other
- interrupted request) */
- struct list_head background;
-
/** Number of requests currently in the background */
unsigned num_background;
+ /** Pending interrupts */
+ struct list_head interrupts;
+
/** Flag indicating if connection is blocked. This will be
the case before the INIT reply is received, and if there
are too many outstading backgrounds requests */
@@ -258,15 +283,9 @@ struct fuse_conn {
/** waitq for blocked connection */
wait_queue_head_t blocked_waitq;
- /** RW semaphore for exclusion with fuse_put_super() */
- struct rw_semaphore sbput_sem;
-
/** The next unique request id */
u64 reqctr;
- /** Mount is active */
- unsigned mounted;
-
/** Connection established, cleared on umount, connection
abort and device release */
unsigned connected;
@@ -305,12 +324,18 @@ struct fuse_conn {
/** Is removexattr not implemented by fs? */
unsigned no_removexattr : 1;
+ /** Are file locking primitives not implemented by fs? */
+ unsigned no_lock : 1;
+
/** Is access not implemented by fs? */
unsigned no_access : 1;
/** Is create not implemented by fs? */
unsigned no_create : 1;
+ /** Is interrupt not implemented by fs? */
+ unsigned no_interrupt : 1;
+
/** The number of requests waiting for completion */
atomic_t num_waiting;
@@ -320,11 +345,23 @@ struct fuse_conn {
/** Backing dev info */
struct backing_dev_info bdi;
- /** kobject */
- struct kobject kobj;
+ /** Entry on the fuse_conn_list */
+ struct list_head entry;
+
+ /** Unique ID */
+ u64 id;
+
+ /** Dentries in the control filesystem */
+ struct dentry *ctl_dentry[FUSE_CTL_NUM_DENTRIES];
+
+ /** number of dentries used in the above array */
+ int ctl_ndents;
/** O_ASYNC requests */
struct fasync_struct *fasync;
+
+ /** Key for lock owner ID scrambling */
+ u32 scramble_key[4];
};
static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
@@ -337,11 +374,6 @@ static inline struct fuse_conn *get_fuse_conn(struct inode *inode)
return get_fuse_conn_super(inode->i_sb);
}
-static inline struct fuse_conn *get_fuse_conn_kobj(struct kobject *obj)
-{
- return container_of(obj, struct fuse_conn, kobj);
-}
-
static inline struct fuse_inode *get_fuse_inode(struct inode *inode)
{
return container_of(inode, struct fuse_inode, inode);
@@ -383,12 +415,9 @@ void fuse_file_free(struct fuse_file *ff);
void fuse_finish_open(struct inode *inode, struct file *file,
struct fuse_file *ff, struct fuse_open_out *outarg);
-/**
- * Send a RELEASE request
- */
-void fuse_send_release(struct fuse_conn *fc, struct fuse_file *ff,
- u64 nodeid, struct inode *inode, int flags, int isdir);
-
+/** */
+struct fuse_req *fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags,
+ int opcode);
/**
* Send RELEASE or RELEASEDIR request
*/
@@ -435,6 +464,9 @@ int fuse_dev_init(void);
*/
void fuse_dev_cleanup(void);
+int fuse_ctl_init(void);
+void fuse_ctl_cleanup(void);
+
/**
* Allocate a request
*/
@@ -446,14 +478,14 @@ struct fuse_req *fuse_request_alloc(void);
void fuse_request_free(struct fuse_req *req);
/**
- * Reinitialize a request, the preallocated flag is left unmodified
+ * Get a request, may fail with -ENOMEM
*/
-void fuse_reset_request(struct fuse_req *req);
+struct fuse_req *fuse_get_req(struct fuse_conn *fc);
/**
- * Reserve a preallocated request
+ * Gets a requests for a file operation, always succeeds
*/
-struct fuse_req *fuse_get_req(struct fuse_conn *fc);
+struct fuse_req *fuse_get_req_nofail(struct fuse_conn *fc, struct file *file);
/**
* Decrement reference count of a request. If count goes to zero free
@@ -476,11 +508,6 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req);
*/
void request_send_background(struct fuse_conn *fc, struct fuse_req *req);
-/**
- * Release inodes and file associated with background request
- */
-void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req);
-
/* Abort all requests */
void fuse_abort_conn(struct fuse_conn *fc);
@@ -493,3 +520,23 @@ int fuse_do_getattr(struct inode *inode);
* Invalidate inode attributes
*/
void fuse_invalidate_attr(struct inode *inode);
+
+/**
+ * Acquire reference to fuse_conn
+ */
+struct fuse_conn *fuse_conn_get(struct fuse_conn *fc);
+
+/**
+ * Release reference to fuse_conn
+ */
+void fuse_conn_put(struct fuse_conn *fc);
+
+/**
+ * Add connection to control filesystem
+ */
+int fuse_ctl_add_conn(struct fuse_conn *fc);
+
+/**
+ * Remove connection from control filesystem
+ */
+void fuse_ctl_remove_conn(struct fuse_conn *fc);
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 7627022..dcaaabd 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -11,25 +11,20 @@
#include <linux/pagemap.h>
#include <linux/slab.h>
#include <linux/file.h>
-#include <linux/mount.h>
#include <linux/seq_file.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/parser.h>
#include <linux/statfs.h>
+#include <linux/random.h>
MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
MODULE_DESCRIPTION("Filesystem in Userspace");
MODULE_LICENSE("GPL");
static kmem_cache_t *fuse_inode_cachep;
-static struct subsystem connections_subsys;
-
-struct fuse_conn_attr {
- struct attribute attr;
- ssize_t (*show)(struct fuse_conn *, char *);
- ssize_t (*store)(struct fuse_conn *, const char *, size_t);
-};
+struct list_head fuse_conn_list;
+DEFINE_MUTEX(fuse_mutex);
#define FUSE_SUPER_MAGIC 0x65735546
@@ -104,6 +99,14 @@ static void fuse_clear_inode(struct inode *inode)
}
}
+static int fuse_remount_fs(struct super_block *sb, int *flags, char *data)
+{
+ if (*flags & MS_MANDLOCK)
+ return -EINVAL;
+
+ return 0;
+}
+
void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
{
if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size)
@@ -195,31 +198,29 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
return inode;
}
-static void fuse_umount_begin(struct super_block *sb)
+static void fuse_umount_begin(struct vfsmount *vfsmnt, int flags)
{
- fuse_abort_conn(get_fuse_conn_super(sb));
+ if (flags & MNT_FORCE)
+ fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb));
}
static void fuse_put_super(struct super_block *sb)
{
struct fuse_conn *fc = get_fuse_conn_super(sb);
- down_write(&fc->sbput_sem);
- while (!list_empty(&fc->background))
- fuse_release_background(fc,
- list_entry(fc->background.next,
- struct fuse_req, bg_entry));
-
spin_lock(&fc->lock);
- fc->mounted = 0;
fc->connected = 0;
+ fc->blocked = 0;
spin_unlock(&fc->lock);
- up_write(&fc->sbput_sem);
/* Flush all readers on this fs */
kill_fasync(&fc->fasync, SIGIO, POLL_IN);
wake_up_all(&fc->waitq);
- kobject_del(&fc->kobj);
- kobject_put(&fc->kobj);
+ wake_up_all(&fc->blocked_waitq);
+ mutex_lock(&fuse_mutex);
+ list_del(&fc->entry);
+ fuse_ctl_remove_conn(fc);
+ mutex_unlock(&fuse_mutex);
+ fuse_conn_put(fc);
}
static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
@@ -236,8 +237,9 @@ static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr
/* fsid is left zero */
}
-static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
+static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf)
{
+ struct super_block *sb = dentry->d_sb;
struct fuse_conn *fc = get_fuse_conn_super(sb);
struct fuse_req *req;
struct fuse_statfs_out outarg;
@@ -368,11 +370,6 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
return 0;
}
-static void fuse_conn_release(struct kobject *kobj)
-{
- kfree(get_fuse_conn_kobj(kobj));
-}
-
static struct fuse_conn *new_conn(void)
{
struct fuse_conn *fc;
@@ -380,24 +377,35 @@ static struct fuse_conn *new_conn(void)
fc = kzalloc(sizeof(*fc), GFP_KERNEL);
if (fc) {
spin_lock_init(&fc->lock);
+ atomic_set(&fc->count, 1);
init_waitqueue_head(&fc->waitq);
init_waitqueue_head(&fc->blocked_waitq);
INIT_LIST_HEAD(&fc->pending);
INIT_LIST_HEAD(&fc->processing);
INIT_LIST_HEAD(&fc->io);
- INIT_LIST_HEAD(&fc->background);
- init_rwsem(&fc->sbput_sem);
- kobj_set_kset_s(fc, connections_subsys);
- kobject_init(&fc->kobj);
+ INIT_LIST_HEAD(&fc->interrupts);
atomic_set(&fc->num_waiting, 0);
fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
fc->bdi.unplug_io_fn = default_unplug_io_fn;
fc->reqctr = 0;
fc->blocked = 1;
+ get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
}
return fc;
}
+void fuse_conn_put(struct fuse_conn *fc)
+{
+ if (atomic_dec_and_test(&fc->count))
+ kfree(fc);
+}
+
+struct fuse_conn *fuse_conn_get(struct fuse_conn *fc)
+{
+ atomic_inc(&fc->count);
+ return fc;
+}
+
static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
{
struct fuse_attr attr;
@@ -413,6 +421,7 @@ static struct super_operations fuse_super_operations = {
.destroy_inode = fuse_destroy_inode,
.read_inode = fuse_read_inode,
.clear_inode = fuse_clear_inode,
+ .remount_fs = fuse_remount_fs,
.put_super = fuse_put_super,
.umount_begin = fuse_umount_begin,
.statfs = fuse_statfs,
@@ -432,8 +441,12 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
ra_pages = arg->max_readahead / PAGE_CACHE_SIZE;
if (arg->flags & FUSE_ASYNC_READ)
fc->async_read = 1;
- } else
+ if (!(arg->flags & FUSE_POSIX_LOCKS))
+ fc->no_lock = 1;
+ } else {
ra_pages = fc->max_read / PAGE_CACHE_SIZE;
+ fc->no_lock = 1;
+ }
fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages);
fc->minor = arg->minor;
@@ -451,7 +464,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
arg->major = FUSE_KERNEL_VERSION;
arg->minor = FUSE_KERNEL_MINOR_VERSION;
arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
- arg->flags |= FUSE_ASYNC_READ;
+ arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS;
req->in.h.opcode = FUSE_INIT;
req->in.numargs = 1;
req->in.args[0].size = sizeof(*arg);
@@ -467,10 +480,9 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
request_send_background(fc, req);
}
-static unsigned long long conn_id(void)
+static u64 conn_id(void)
{
- /* BKL is held for ->get_sb() */
- static unsigned long long ctr = 1;
+ static u64 ctr = 1;
return ctr++;
}
@@ -484,6 +496,9 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
struct fuse_req *init_req;
int err;
+ if (sb->s_flags & MS_MANDLOCK)
+ return -EINVAL;
+
if (!parse_fuse_opt((char *) data, &d))
return -EINVAL;
@@ -527,25 +542,21 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
if (!init_req)
goto err_put_root;
- err = kobject_set_name(&fc->kobj, "%llu", conn_id());
- if (err)
- goto err_free_req;
-
- err = kobject_add(&fc->kobj);
- if (err)
- goto err_free_req;
-
- /* Setting file->private_data can't race with other mount()
- instances, since BKL is held for ->get_sb() */
+ mutex_lock(&fuse_mutex);
err = -EINVAL;
if (file->private_data)
- goto err_kobject_del;
+ goto err_unlock;
+ fc->id = conn_id();
+ err = fuse_ctl_add_conn(fc);
+ if (err)
+ goto err_unlock;
+
+ list_add_tail(&fc->entry, &fuse_conn_list);
sb->s_root = root_dentry;
- fc->mounted = 1;
fc->connected = 1;
- kobject_get(&fc->kobj);
- file->private_data = fc;
+ file->private_data = fuse_conn_get(fc);
+ mutex_unlock(&fuse_mutex);
/*
* atomic_dec_and_test() in fput() provides the necessary
* memory barrier for file->private_data to be visible on all
@@ -557,23 +568,22 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
return 0;
- err_kobject_del:
- kobject_del(&fc->kobj);
- err_free_req:
+ err_unlock:
+ mutex_unlock(&fuse_mutex);
fuse_request_free(init_req);
err_put_root:
dput(root_dentry);
err:
fput(file);
- kobject_put(&fc->kobj);
+ fuse_conn_put(fc);
return err;
}
-static struct super_block *fuse_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *raw_data)
+static int fuse_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *raw_data, struct vfsmount *mnt)
{
- return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super);
+ return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt);
}
static struct file_system_type fuse_fs_type = {
@@ -583,68 +593,8 @@ static struct file_system_type fuse_fs_type = {
.kill_sb = kill_anon_super,
};
-static ssize_t fuse_conn_waiting_show(struct fuse_conn *fc, char *page)
-{
- return sprintf(page, "%i\n", atomic_read(&fc->num_waiting));
-}
-
-static ssize_t fuse_conn_abort_store(struct fuse_conn *fc, const char *page,
- size_t count)
-{
- fuse_abort_conn(fc);
- return count;
-}
-
-static struct fuse_conn_attr fuse_conn_waiting =
- __ATTR(waiting, 0400, fuse_conn_waiting_show, NULL);
-static struct fuse_conn_attr fuse_conn_abort =
- __ATTR(abort, 0600, NULL, fuse_conn_abort_store);
-
-static struct attribute *fuse_conn_attrs[] = {
- &fuse_conn_waiting.attr,
- &fuse_conn_abort.attr,
- NULL,
-};
-
-static ssize_t fuse_conn_attr_show(struct kobject *kobj,
- struct attribute *attr,
- char *page)
-{
- struct fuse_conn_attr *fca =
- container_of(attr, struct fuse_conn_attr, attr);
-
- if (fca->show)
- return fca->show(get_fuse_conn_kobj(kobj), page);
- else
- return -EACCES;
-}
-
-static ssize_t fuse_conn_attr_store(struct kobject *kobj,
- struct attribute *attr,
- const char *page, size_t count)
-{
- struct fuse_conn_attr *fca =
- container_of(attr, struct fuse_conn_attr, attr);
-
- if (fca->store)
- return fca->store(get_fuse_conn_kobj(kobj), page, count);
- else
- return -EACCES;
-}
-
-static struct sysfs_ops fuse_conn_sysfs_ops = {
- .show = &fuse_conn_attr_show,
- .store = &fuse_conn_attr_store,
-};
-
-static struct kobj_type ktype_fuse_conn = {
- .release = fuse_conn_release,
- .sysfs_ops = &fuse_conn_sysfs_ops,
- .default_attrs = fuse_conn_attrs,
-};
-
static decl_subsys(fuse, NULL, NULL);
-static decl_subsys(connections, &ktype_fuse_conn, NULL);
+static decl_subsys(connections, NULL, NULL);
static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep,
unsigned long flags)
@@ -718,6 +668,7 @@ static int __init fuse_init(void)
printk("fuse init (API version %i.%i)\n",
FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
+ INIT_LIST_HEAD(&fuse_conn_list);
res = fuse_fs_init();
if (res)
goto err;
@@ -730,8 +681,14 @@ static int __init fuse_init(void)
if (res)
goto err_dev_cleanup;
+ res = fuse_ctl_init();
+ if (res)
+ goto err_sysfs_cleanup;
+
return 0;
+ err_sysfs_cleanup:
+ fuse_sysfs_cleanup();
err_dev_cleanup:
fuse_dev_cleanup();
err_fs_cleanup:
@@ -744,6 +701,7 @@ static void __exit fuse_exit(void)
{
printk(KERN_DEBUG "fuse exit\n");
+ fuse_ctl_cleanup();
fuse_sysfs_cleanup();
fuse_fs_cleanup();
fuse_dev_cleanup();
diff --git a/fs/hfs/bnode.c b/fs/hfs/bnode.c
index 1e44dcf..13231dd 100644
--- a/fs/hfs/bnode.c
+++ b/fs/hfs/bnode.c
@@ -280,7 +280,7 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
block = off >> PAGE_CACHE_SHIFT;
node->page_offset = off & ~PAGE_CACHE_MASK;
for (i = 0; i < tree->pages_per_bnode; i++) {
- page = read_cache_page(mapping, block++, (filler_t *)mapping->a_ops->readpage, NULL);
+ page = read_mapping_page(mapping, block++, NULL);
if (IS_ERR(page))
goto fail;
if (PageError(page)) {
diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c
index d20131c..4003579 100644
--- a/fs/hfs/btree.c
+++ b/fs/hfs/btree.c
@@ -59,7 +59,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke
unlock_new_inode(tree->inode);
mapping = tree->inode->i_mapping;
- page = read_cache_page(mapping, 0, (filler_t *)mapping->a_ops->readpage, NULL);
+ page = read_mapping_page(mapping, 0, NULL);
if (IS_ERR(page))
goto free_tree;
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 1181d11..d9227bf 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -80,8 +80,10 @@ static void hfs_put_super(struct super_block *sb)
*
* changed f_files/f_ffree to reflect the fs_ablock/free_ablocks.
*/
-static int hfs_statfs(struct super_block *sb, struct kstatfs *buf)
+static int hfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
+ struct super_block *sb = dentry->d_sb;
+
buf->f_type = HFS_SUPER_MAGIC;
buf->f_bsize = sb->s_blocksize;
buf->f_blocks = (u32)HFS_SB(sb)->fs_ablocks * HFS_SB(sb)->fs_div;
@@ -413,10 +415,11 @@ bail:
return res;
}
-static struct super_block *hfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int hfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data,
+ struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, hfs_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, hfs_fill_super, mnt);
}
static struct file_system_type hfs_fs_type = {
diff --git a/fs/hfsplus/bitmap.c b/fs/hfsplus/bitmap.c
index 9fb5163..d128a25b 100644
--- a/fs/hfsplus/bitmap.c
+++ b/fs/hfsplus/bitmap.c
@@ -31,8 +31,7 @@ int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *ma
dprint(DBG_BITMAP, "block_allocate: %u,%u,%u\n", size, offset, len);
mutex_lock(&HFSPLUS_SB(sb).alloc_file->i_mutex);
mapping = HFSPLUS_SB(sb).alloc_file->i_mapping;
- page = read_cache_page(mapping, offset / PAGE_CACHE_BITS,
- (filler_t *)mapping->a_ops->readpage, NULL);
+ page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS, NULL);
pptr = kmap(page);
curr = pptr + (offset & (PAGE_CACHE_BITS - 1)) / 32;
i = offset % 32;
@@ -72,8 +71,8 @@ int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *ma
offset += PAGE_CACHE_BITS;
if (offset >= size)
break;
- page = read_cache_page(mapping, offset / PAGE_CACHE_BITS,
- (filler_t *)mapping->a_ops->readpage, NULL);
+ page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS,
+ NULL);
curr = pptr = kmap(page);
if ((size ^ offset) / PAGE_CACHE_BITS)
end = pptr + PAGE_CACHE_BITS / 32;
@@ -119,8 +118,8 @@ found:
set_page_dirty(page);
kunmap(page);
offset += PAGE_CACHE_BITS;
- page = read_cache_page(mapping, offset / PAGE_CACHE_BITS,
- (filler_t *)mapping->a_ops->readpage, NULL);
+ page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS,
+ NULL);
pptr = kmap(page);
curr = pptr;
end = pptr + PAGE_CACHE_BITS / 32;
@@ -167,7 +166,7 @@ int hfsplus_block_free(struct super_block *sb, u32 offset, u32 count)
mutex_lock(&HFSPLUS_SB(sb).alloc_file->i_mutex);
mapping = HFSPLUS_SB(sb).alloc_file->i_mapping;
pnr = offset / PAGE_CACHE_BITS;
- page = read_cache_page(mapping, pnr, (filler_t *)mapping->a_ops->readpage, NULL);
+ page = read_mapping_page(mapping, pnr, NULL);
pptr = kmap(page);
curr = pptr + (offset & (PAGE_CACHE_BITS - 1)) / 32;
end = pptr + PAGE_CACHE_BITS / 32;
@@ -199,7 +198,7 @@ int hfsplus_block_free(struct super_block *sb, u32 offset, u32 count)
break;
set_page_dirty(page);
kunmap(page);
- page = read_cache_page(mapping, ++pnr, (filler_t *)mapping->a_ops->readpage, NULL);
+ page = read_mapping_page(mapping, ++pnr, NULL);
pptr = kmap(page);
curr = pptr;
end = pptr + PAGE_CACHE_BITS / 32;
diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c
index 746abc9..77bf434 100644
--- a/fs/hfsplus/bnode.c
+++ b/fs/hfsplus/bnode.c
@@ -440,7 +440,7 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
block = off >> PAGE_CACHE_SHIFT;
node->page_offset = off & ~PAGE_CACHE_MASK;
for (i = 0; i < tree->pages_per_bnode; block++, i++) {
- page = read_cache_page(mapping, block, (filler_t *)mapping->a_ops->readpage, NULL);
+ page = read_mapping_page(mapping, block, NULL);
if (IS_ERR(page))
goto fail;
if (PageError(page)) {
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c
index effa899..cfc852f 100644
--- a/fs/hfsplus/btree.c
+++ b/fs/hfsplus/btree.c
@@ -38,7 +38,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
goto free_tree;
mapping = tree->inode->i_mapping;
- page = read_cache_page(mapping, 0, (filler_t *)mapping->a_ops->readpage, NULL);
+ page = read_mapping_page(mapping, 0, NULL);
if (IS_ERR(page))
goto free_tree;
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index 7843f79..0a92fa2 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -212,8 +212,10 @@ static void hfsplus_put_super(struct super_block *sb)
sb->s_fs_info = NULL;
}
-static int hfsplus_statfs(struct super_block *sb, struct kstatfs *buf)
+static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf)
{
+ struct super_block *sb = dentry->d_sb;
+
buf->f_type = HFSPLUS_SUPER_MAGIC;
buf->f_bsize = sb->s_blocksize;
buf->f_blocks = HFSPLUS_SB(sb).total_blocks << HFSPLUS_SB(sb).fs_shift;
@@ -450,10 +452,12 @@ static void hfsplus_destroy_inode(struct inode *inode)
#define HFSPLUS_INODE_SIZE sizeof(struct hfsplus_inode_info)
-static struct super_block *hfsplus_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int hfsplus_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data,
+ struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, hfsplus_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, hfsplus_fill_super,
+ mnt);
}
static struct file_system_type hfsplus_fs_type = {
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index bf0f8e1..8e0d377 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -239,7 +239,7 @@ static int read_inode(struct inode *ino)
return(err);
}
-int hostfs_statfs(struct super_block *sb, struct kstatfs *sf)
+int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
{
/* do_statfs uses struct statfs64 internally, but the linux kernel
* struct statfs still has 32-bit versions for most of these fields,
@@ -252,7 +252,7 @@ int hostfs_statfs(struct super_block *sb, struct kstatfs *sf)
long long f_files;
long long f_ffree;
- err = do_statfs(HOSTFS_I(sb->s_root->d_inode)->host_filename,
+ err = do_statfs(HOSTFS_I(dentry->d_sb->s_root->d_inode)->host_filename,
&sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
&f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
&sf->f_namelen, sf->f_spare);
@@ -993,11 +993,11 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
return(err);
}
-static struct super_block *hostfs_read_sb(struct file_system_type *type,
- int flags, const char *dev_name,
- void *data)
+static int hostfs_read_sb(struct file_system_type *type,
+ int flags, const char *dev_name,
+ void *data, struct vfsmount *mnt)
{
- return(get_sb_nodev(type, flags, data, hostfs_fill_sb_common));
+ return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
}
static struct file_system_type hostfs_type = {
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index d72d8c8..f798480 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -135,8 +135,9 @@ static unsigned count_bitmaps(struct super_block *s)
return count;
}
-static int hpfs_statfs(struct super_block *s, struct kstatfs *buf)
+static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
+ struct super_block *s = dentry->d_sb;
struct hpfs_sb_info *sbi = hpfs_sb(s);
lock_kernel();
@@ -662,10 +663,11 @@ bail0:
return -EINVAL;
}
-static struct super_block *hpfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int hpfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, hpfs_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, hpfs_fill_super,
+ mnt);
}
static struct file_system_type hpfs_fs_type = {
diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c
index 5e6363b..3a9bdf58 100644
--- a/fs/hppfs/hppfs_kern.c
+++ b/fs/hppfs/hppfs_kern.c
@@ -616,7 +616,7 @@ static const struct file_operations hppfs_dir_fops = {
.fsync = hppfs_fsync,
};
-static int hppfs_statfs(struct super_block *sb, struct kstatfs *sf)
+static int hppfs_statfs(struct dentry *dentry, struct kstatfs *sf)
{
sf->f_blocks = 0;
sf->f_bfree = 0;
@@ -769,11 +769,11 @@ static int hppfs_fill_super(struct super_block *sb, void *d, int silent)
return(err);
}
-static struct super_block *hppfs_read_super(struct file_system_type *type,
- int flags, const char *dev_name,
- void *data)
+static int hppfs_read_super(struct file_system_type *type,
+ int flags, const char *dev_name,
+ void *data, struct vfsmount *mnt)
{
- return(get_sb_nodev(type, flags, data, hppfs_fill_super));
+ return get_sb_nodev(type, flags, data, hppfs_fill_super, mnt);
}
static struct file_system_type hppfs_type = {
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 3a5b4e9..e6410d8 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -59,7 +59,6 @@ static void huge_pagevec_release(struct pagevec *pvec)
static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
{
struct inode *inode = file->f_dentry->d_inode;
- struct hugetlbfs_inode_info *info = HUGETLBFS_I(inode);
loff_t len, vma_len;
int ret;
@@ -87,9 +86,10 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
if (!(vma->vm_flags & VM_WRITE) && len > inode->i_size)
goto out;
- if (vma->vm_flags & VM_MAYSHARE)
- if (hugetlb_extend_reservation(info, len >> HPAGE_SHIFT) != 0)
- goto out;
+ if (vma->vm_flags & VM_MAYSHARE &&
+ hugetlb_reserve_pages(inode, vma->vm_pgoff >> (HPAGE_SHIFT-PAGE_SHIFT),
+ len >> HPAGE_SHIFT))
+ goto out;
ret = 0;
hugetlb_prefault_arch_hook(vma->vm_mm);
@@ -195,12 +195,8 @@ static void truncate_hugepages(struct inode *inode, loff_t lstart)
const pgoff_t start = lstart >> HPAGE_SHIFT;
struct pagevec pvec;
pgoff_t next;
- int i;
+ int i, freed = 0;
- hugetlb_truncate_reservation(HUGETLBFS_I(inode),
- lstart >> HPAGE_SHIFT);
- if (!mapping->nrpages)
- return;
pagevec_init(&pvec, 0);
next = start;
while (1) {
@@ -221,10 +217,12 @@ static void truncate_hugepages(struct inode *inode, loff_t lstart)
truncate_huge_page(page);
unlock_page(page);
hugetlb_put_quota(mapping);
+ freed++;
}
huge_pagevec_release(&pvec);
}
BUG_ON(!lstart && mapping->nrpages);
+ hugetlb_unreserve_pages(inode, start, freed);
}
static void hugetlbfs_delete_inode(struct inode *inode)
@@ -366,6 +364,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid,
inode->i_mapping->a_ops = &hugetlbfs_aops;
inode->i_mapping->backing_dev_info =&hugetlbfs_backing_dev_info;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ INIT_LIST_HEAD(&inode->i_mapping->private_list);
info = HUGETLBFS_I(inode);
mpol_shared_policy_init(&info->policy, MPOL_DEFAULT, NULL);
switch (mode & S_IFMT) {
@@ -467,9 +466,9 @@ static int hugetlbfs_set_page_dirty(struct page *page)
return 0;
}
-static int hugetlbfs_statfs(struct super_block *sb, struct kstatfs *buf)
+static int hugetlbfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
- struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(sb);
+ struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(dentry->d_sb);
buf->f_type = HUGETLBFS_MAGIC;
buf->f_bsize = HPAGE_SIZE;
@@ -538,7 +537,6 @@ static struct inode *hugetlbfs_alloc_inode(struct super_block *sb)
hugetlbfs_inc_free_inodes(sbinfo);
return NULL;
}
- p->prereserved_hpages = 0;
return &p->vfs_inode;
}
@@ -723,10 +721,10 @@ void hugetlb_put_quota(struct address_space *mapping)
}
}
-static struct super_block *hugetlbfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int hugetlbfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_nodev(fs_type, flags, data, hugetlbfs_fill_super);
+ return get_sb_nodev(fs_type, flags, data, hugetlbfs_fill_super, mnt);
}
static struct file_system_type hugetlbfs_fs_type = {
@@ -781,8 +779,7 @@ struct file *hugetlb_zero_setup(size_t size)
goto out_file;
error = -ENOMEM;
- if (hugetlb_extend_reservation(HUGETLBFS_I(inode),
- size >> HPAGE_SHIFT) != 0)
+ if (hugetlb_reserve_pages(inode, 0, size >> HPAGE_SHIFT))
goto out_inode;
d_instantiate(dentry, inode);
diff --git a/fs/inotify_user.c b/fs/inotify_user.c
index 9e9931e..f238644 100644
--- a/fs/inotify_user.c
+++ b/fs/inotify_user.c
@@ -672,11 +672,11 @@ out:
return ret;
}
-static struct super_block *
+static int
inotify_get_sb(struct file_system_type *fs_type, int flags,
- const char *dev_name, void *data)
+ const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_pseudo(fs_type, "inotify", NULL, 0xBAD1DEA);
+ return get_sb_pseudo(fs_type, "inotify", NULL, 0xBAD1DEA, mnt);
}
static struct file_system_type inotify_fs_type = {
diff --git a/fs/ioprio.c b/fs/ioprio.c
index ca77008..7fa76ed 100644
--- a/fs/ioprio.c
+++ b/fs/ioprio.c
@@ -24,15 +24,21 @@
#include <linux/blkdev.h>
#include <linux/capability.h>
#include <linux/syscalls.h>
+#include <linux/security.h>
static int set_task_ioprio(struct task_struct *task, int ioprio)
{
+ int err;
struct io_context *ioc;
if (task->uid != current->euid &&
task->uid != current->uid && !capable(CAP_SYS_NICE))
return -EPERM;
+ err = security_task_setioprio(task, ioprio);
+ if (err)
+ return err;
+
task_lock(task);
task->ioprio = ioprio;
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 70adbb9..3f9c8ba 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -56,7 +56,7 @@ static void isofs_put_super(struct super_block *sb)
}
static void isofs_read_inode(struct inode *);
-static int isofs_statfs (struct super_block *, struct kstatfs *);
+static int isofs_statfs (struct dentry *, struct kstatfs *);
static kmem_cache_t *isofs_inode_cachep;
@@ -901,8 +901,10 @@ out_freesbi:
return -EINVAL;
}
-static int isofs_statfs (struct super_block *sb, struct kstatfs *buf)
+static int isofs_statfs (struct dentry *dentry, struct kstatfs *buf)
{
+ struct super_block *sb = dentry->d_sb;
+
buf->f_type = ISOFS_SUPER_MAGIC;
buf->f_bsize = sb->s_blocksize;
buf->f_blocks = (ISOFS_SB(sb)->s_nzones
@@ -1399,10 +1401,11 @@ struct inode *isofs_iget(struct super_block *sb,
return inode;
}
-static struct super_block *isofs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int isofs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, isofs_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, isofs_fill_super,
+ mnt);
}
static struct file_system_type iso9660_fs_type = {
diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c
index 3f5102b..47678a2 100644
--- a/fs/jbd/checkpoint.c
+++ b/fs/jbd/checkpoint.c
@@ -24,29 +24,67 @@
#include <linux/slab.h>
/*
- * Unlink a buffer from a transaction.
+ * Unlink a buffer from a transaction checkpoint list.
*
* Called with j_list_lock held.
*/
-
-static inline void __buffer_unlink(struct journal_head *jh)
+static inline void __buffer_unlink_first(struct journal_head *jh)
{
- transaction_t *transaction;
-
- transaction = jh->b_cp_transaction;
- jh->b_cp_transaction = NULL;
+ transaction_t *transaction = jh->b_cp_transaction;
jh->b_cpnext->b_cpprev = jh->b_cpprev;
jh->b_cpprev->b_cpnext = jh->b_cpnext;
- if (transaction->t_checkpoint_list == jh)
+ if (transaction->t_checkpoint_list == jh) {
transaction->t_checkpoint_list = jh->b_cpnext;
- if (transaction->t_checkpoint_list == jh)
- transaction->t_checkpoint_list = NULL;
+ if (transaction->t_checkpoint_list == jh)
+ transaction->t_checkpoint_list = NULL;
+ }
+}
+
+/*
+ * Unlink a buffer from a transaction checkpoint(io) list.
+ *
+ * Called with j_list_lock held.
+ */
+static inline void __buffer_unlink(struct journal_head *jh)
+{
+ transaction_t *transaction = jh->b_cp_transaction;
+
+ __buffer_unlink_first(jh);
+ if (transaction->t_checkpoint_io_list == jh) {
+ transaction->t_checkpoint_io_list = jh->b_cpnext;
+ if (transaction->t_checkpoint_io_list == jh)
+ transaction->t_checkpoint_io_list = NULL;
+ }
+}
+
+/*
+ * Move a buffer from the checkpoint list to the checkpoint io list
+ *
+ * Called with j_list_lock held
+ */
+static inline void __buffer_relink_io(struct journal_head *jh)
+{
+ transaction_t *transaction = jh->b_cp_transaction;
+
+ __buffer_unlink_first(jh);
+
+ if (!transaction->t_checkpoint_io_list) {
+ jh->b_cpnext = jh->b_cpprev = jh;
+ } else {
+ jh->b_cpnext = transaction->t_checkpoint_io_list;
+ jh->b_cpprev = transaction->t_checkpoint_io_list->b_cpprev;
+ jh->b_cpprev->b_cpnext = jh;
+ jh->b_cpnext->b_cpprev = jh;
+ }
+ transaction->t_checkpoint_io_list = jh;
}
/*
* Try to release a checkpointed buffer from its transaction.
- * Returns 1 if we released it.
+ * Returns 1 if we released it and 2 if we also released the
+ * whole transaction.
+ *
* Requires j_list_lock
* Called under jbd_lock_bh_state(jh2bh(jh)), and drops it
*/
@@ -57,12 +95,11 @@ static int __try_to_free_cp_buf(struct journal_head *jh)
if (jh->b_jlist == BJ_None && !buffer_locked(bh) && !buffer_dirty(bh)) {
JBUFFER_TRACE(jh, "remove from checkpoint list");
- __journal_remove_checkpoint(jh);
+ ret = __journal_remove_checkpoint(jh) + 1;
jbd_unlock_bh_state(bh);
journal_remove_journal_head(bh);
BUFFER_TRACE(bh, "release");
__brelse(bh);
- ret = 1;
} else {
jbd_unlock_bh_state(bh);
}
@@ -117,83 +154,54 @@ static void jbd_sync_bh(journal_t *journal, struct buffer_head *bh)
}
/*
- * Clean up a transaction's checkpoint list.
- *
- * We wait for any pending IO to complete and make sure any clean
- * buffers are removed from the transaction.
- *
- * Return 1 if we performed any actions which might have destroyed the
- * checkpoint. (journal_remove_checkpoint() deletes the transaction when
- * the last checkpoint buffer is cleansed)
+ * Clean up transaction's list of buffers submitted for io.
+ * We wait for any pending IO to complete and remove any clean
+ * buffers. Note that we take the buffers in the opposite ordering
+ * from the one in which they were submitted for IO.
*
* Called with j_list_lock held.
*/
-static int __cleanup_transaction(journal_t *journal, transaction_t *transaction)
+static void __wait_cp_io(journal_t *journal, transaction_t *transaction)
{
- struct journal_head *jh, *next_jh, *last_jh;
+ struct journal_head *jh;
struct buffer_head *bh;
- int ret = 0;
-
- assert_spin_locked(&journal->j_list_lock);
- jh = transaction->t_checkpoint_list;
- if (!jh)
- return 0;
-
- last_jh = jh->b_cpprev;
- next_jh = jh;
- do {
- jh = next_jh;
+ tid_t this_tid;
+ int released = 0;
+
+ this_tid = transaction->t_tid;
+restart:
+ /* Did somebody clean up the transaction in the meanwhile? */
+ if (journal->j_checkpoint_transactions != transaction ||
+ transaction->t_tid != this_tid)
+ return;
+ while (!released && transaction->t_checkpoint_io_list) {
+ jh = transaction->t_checkpoint_io_list;
bh = jh2bh(jh);
+ if (!jbd_trylock_bh_state(bh)) {
+ jbd_sync_bh(journal, bh);
+ spin_lock(&journal->j_list_lock);
+ goto restart;
+ }
if (buffer_locked(bh)) {
atomic_inc(&bh->b_count);
spin_unlock(&journal->j_list_lock);
+ jbd_unlock_bh_state(bh);
wait_on_buffer(bh);
/* the journal_head may have gone by now */
BUFFER_TRACE(bh, "brelse");
__brelse(bh);
- goto out_return_1;
+ spin_lock(&journal->j_list_lock);
+ goto restart;
}
-
/*
- * This is foul
+ * Now in whatever state the buffer currently is, we know that
+ * it has been written out and so we can drop it from the list
*/
- if (!jbd_trylock_bh_state(bh)) {
- jbd_sync_bh(journal, bh);
- goto out_return_1;
- }
-
- if (jh->b_transaction != NULL) {
- transaction_t *t = jh->b_transaction;
- tid_t tid = t->t_tid;
-
- spin_unlock(&journal->j_list_lock);
- jbd_unlock_bh_state(bh);
- log_start_commit(journal, tid);
- log_wait_commit(journal, tid);
- goto out_return_1;
- }
-
- /*
- * AKPM: I think the buffer_jbddirty test is redundant - it
- * shouldn't have NULL b_transaction?
- */
- next_jh = jh->b_cpnext;
- if (!buffer_dirty(bh) && !buffer_jbddirty(bh)) {
- BUFFER_TRACE(bh, "remove from checkpoint");
- __journal_remove_checkpoint(jh);
- jbd_unlock_bh_state(bh);
- journal_remove_journal_head(bh);
- __brelse(bh);
- ret = 1;
- } else {
- jbd_unlock_bh_state(bh);
- }
- } while (jh != last_jh);
-
- return ret;
-out_return_1:
- spin_lock(&journal->j_list_lock);
- return 1;
+ released = __journal_remove_checkpoint(jh);
+ jbd_unlock_bh_state(bh);
+ journal_remove_journal_head(bh);
+ __brelse(bh);
+ }
}
#define NR_BATCH 64
@@ -203,9 +211,7 @@ __flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count)
{
int i;
- spin_unlock(&journal->j_list_lock);
ll_rw_block(SWRITE, *batch_count, bhs);
- spin_lock(&journal->j_list_lock);
for (i = 0; i < *batch_count; i++) {
struct buffer_head *bh = bhs[i];
clear_buffer_jwrite(bh);
@@ -221,19 +227,43 @@ __flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count)
* Return 1 if something happened which requires us to abort the current
* scan of the checkpoint list.
*
- * Called with j_list_lock held.
+ * Called with j_list_lock held and drops it if 1 is returned
* Called under jbd_lock_bh_state(jh2bh(jh)), and drops it
*/
-static int __flush_buffer(journal_t *journal, struct journal_head *jh,
- struct buffer_head **bhs, int *batch_count,
- int *drop_count)
+static int __process_buffer(journal_t *journal, struct journal_head *jh,
+ struct buffer_head **bhs, int *batch_count)
{
struct buffer_head *bh = jh2bh(jh);
int ret = 0;
- if (buffer_dirty(bh) && !buffer_locked(bh) && jh->b_jlist == BJ_None) {
- J_ASSERT_JH(jh, jh->b_transaction == NULL);
+ if (buffer_locked(bh)) {
+ atomic_inc(&bh->b_count);
+ spin_unlock(&journal->j_list_lock);
+ jbd_unlock_bh_state(bh);
+ wait_on_buffer(bh);
+ /* the journal_head may have gone by now */
+ BUFFER_TRACE(bh, "brelse");
+ __brelse(bh);
+ ret = 1;
+ } else if (jh->b_transaction != NULL) {
+ transaction_t *t = jh->b_transaction;
+ tid_t tid = t->t_tid;
+ spin_unlock(&journal->j_list_lock);
+ jbd_unlock_bh_state(bh);
+ log_start_commit(journal, tid);
+ log_wait_commit(journal, tid);
+ ret = 1;
+ } else if (!buffer_dirty(bh)) {
+ J_ASSERT_JH(jh, !buffer_jbddirty(bh));
+ BUFFER_TRACE(bh, "remove from checkpoint");
+ __journal_remove_checkpoint(jh);
+ spin_unlock(&journal->j_list_lock);
+ jbd_unlock_bh_state(bh);
+ journal_remove_journal_head(bh);
+ __brelse(bh);
+ ret = 1;
+ } else {
/*
* Important: we are about to write the buffer, and
* possibly block, while still holding the journal lock.
@@ -246,45 +276,30 @@ static int __flush_buffer(journal_t *journal, struct journal_head *jh,
J_ASSERT_BH(bh, !buffer_jwrite(bh));
set_buffer_jwrite(bh);
bhs[*batch_count] = bh;
+ __buffer_relink_io(jh);
jbd_unlock_bh_state(bh);
(*batch_count)++;
if (*batch_count == NR_BATCH) {
+ spin_unlock(&journal->j_list_lock);
__flush_batch(journal, bhs, batch_count);
ret = 1;
}
- } else {
- int last_buffer = 0;
- if (jh->b_cpnext == jh) {
- /* We may be about to drop the transaction. Tell the
- * caller that the lists have changed.
- */
- last_buffer = 1;
- }
- if (__try_to_free_cp_buf(jh)) {
- (*drop_count)++;
- ret = last_buffer;
- }
}
return ret;
}
/*
- * Perform an actual checkpoint. We don't write out only enough to
- * satisfy the current blocked requests: rather we submit a reasonably
- * sized chunk of the outstanding data to disk at once for
- * efficiency. __log_wait_for_space() will retry if we didn't free enough.
+ * Perform an actual checkpoint. We take the first transaction on the
+ * list of transactions to be checkpointed and send all its buffers
+ * to disk. We submit larger chunks of data at once.
*
- * However, we _do_ take into account the amount requested so that once
- * the IO has been queued, we can return as soon as enough of it has
- * completed to disk.
- *
* The journal should be locked before calling this function.
*/
int log_do_checkpoint(journal_t *journal)
{
+ transaction_t *transaction;
+ tid_t this_tid;
int result;
- int batch_count = 0;
- struct buffer_head *bhs[NR_BATCH];
jbd_debug(1, "Start checkpoint\n");
@@ -299,79 +314,68 @@ int log_do_checkpoint(journal_t *journal)
return result;
/*
- * OK, we need to start writing disk blocks. Try to free up a
- * quarter of the log in a single checkpoint if we can.
+ * OK, we need to start writing disk blocks. Take one transaction
+ * and write it.
*/
+ spin_lock(&journal->j_list_lock);
+ if (!journal->j_checkpoint_transactions)
+ goto out;
+ transaction = journal->j_checkpoint_transactions;
+ this_tid = transaction->t_tid;
+restart:
/*
- * AKPM: check this code. I had a feeling a while back that it
- * degenerates into a busy loop at unmount time.
+ * If someone cleaned up this transaction while we slept, we're
+ * done (maybe it's a new transaction, but it fell at the same
+ * address).
*/
- spin_lock(&journal->j_list_lock);
- while (journal->j_checkpoint_transactions) {
- transaction_t *transaction;
- struct journal_head *jh, *last_jh, *next_jh;
- int drop_count = 0;
- int cleanup_ret, retry = 0;
- tid_t this_tid;
-
- transaction = journal->j_checkpoint_transactions;
- this_tid = transaction->t_tid;
- jh = transaction->t_checkpoint_list;
- last_jh = jh->b_cpprev;
- next_jh = jh;
- do {
+ if (journal->j_checkpoint_transactions == transaction &&
+ transaction->t_tid == this_tid) {
+ int batch_count = 0;
+ struct buffer_head *bhs[NR_BATCH];
+ struct journal_head *jh;
+ int retry = 0;
+
+ while (!retry && transaction->t_checkpoint_list) {
struct buffer_head *bh;
- jh = next_jh;
- next_jh = jh->b_cpnext;
+ jh = transaction->t_checkpoint_list;
bh = jh2bh(jh);
if (!jbd_trylock_bh_state(bh)) {
jbd_sync_bh(journal, bh);
- spin_lock(&journal->j_list_lock);
retry = 1;
break;
}
- retry = __flush_buffer(journal, jh, bhs, &batch_count, &drop_count);
- if (cond_resched_lock(&journal->j_list_lock)) {
+ retry = __process_buffer(journal, jh, bhs,&batch_count);
+ if (!retry && lock_need_resched(&journal->j_list_lock)){
+ spin_unlock(&journal->j_list_lock);
retry = 1;
break;
}
- } while (jh != last_jh && !retry);
+ }
if (batch_count) {
+ if (!retry) {
+ spin_unlock(&journal->j_list_lock);
+ retry = 1;
+ }
__flush_batch(journal, bhs, &batch_count);
- retry = 1;
}
+ if (retry) {
+ spin_lock(&journal->j_list_lock);
+ goto restart;
+ }
/*
- * If someone cleaned up this transaction while we slept, we're
- * done
- */
- if (journal->j_checkpoint_transactions != transaction)
- break;
- if (retry)
- continue;
- /*
- * Maybe it's a new transaction, but it fell at the same
- * address
- */
- if (transaction->t_tid != this_tid)
- continue;
- /*
- * We have walked the whole transaction list without
- * finding anything to write to disk. We had better be
- * able to make some progress or we are in trouble.
+ * Now we have cleaned up the first transaction's checkpoint
+ * list. Let's clean up the second one
*/
- cleanup_ret = __cleanup_transaction(journal, transaction);
- J_ASSERT(drop_count != 0 || cleanup_ret != 0);
- if (journal->j_checkpoint_transactions != transaction)
- break;
+ __wait_cp_io(journal, transaction);
}
+out:
spin_unlock(&journal->j_list_lock);
result = cleanup_journal_tail(journal);
if (result < 0)
return result;
-
return 0;
}
@@ -456,52 +460,98 @@ int cleanup_journal_tail(journal_t *journal)
/* Checkpoint list management */
/*
+ * journal_clean_one_cp_list
+ *
+ * Find all the written-back checkpoint buffers in the given list and release them.
+ *
+ * Called with the journal locked.
+ * Called with j_list_lock held.
+ * Returns number of bufers reaped (for debug)
+ */
+
+static int journal_clean_one_cp_list(struct journal_head *jh, int *released)
+{
+ struct journal_head *last_jh;
+ struct journal_head *next_jh = jh;
+ int ret, freed = 0;
+
+ *released = 0;
+ if (!jh)
+ return 0;
+
+ last_jh = jh->b_cpprev;
+ do {
+ jh = next_jh;
+ next_jh = jh->b_cpnext;
+ /* Use trylock because of the ranking */
+ if (jbd_trylock_bh_state(jh2bh(jh))) {
+ ret = __try_to_free_cp_buf(jh);
+ if (ret) {
+ freed++;
+ if (ret == 2) {
+ *released = 1;
+ return freed;
+ }
+ }
+ }
+ /*
+ * This function only frees up some memory
+ * if possible so we dont have an obligation
+ * to finish processing. Bail out if preemption
+ * requested:
+ */
+ if (need_resched())
+ return freed;
+ } while (jh != last_jh);
+
+ return freed;
+}
+
+/*
* journal_clean_checkpoint_list
*
* Find all the written-back checkpoint buffers in the journal and release them.
*
* Called with the journal locked.
* Called with j_list_lock held.
- * Returns number of bufers reaped (for debug)
+ * Returns number of buffers reaped (for debug)
*/
int __journal_clean_checkpoint_list(journal_t *journal)
{
transaction_t *transaction, *last_transaction, *next_transaction;
int ret = 0;
+ int released;
transaction = journal->j_checkpoint_transactions;
- if (transaction == 0)
+ if (!transaction)
goto out;
last_transaction = transaction->t_cpprev;
next_transaction = transaction;
do {
- struct journal_head *jh;
-
transaction = next_transaction;
next_transaction = transaction->t_cpnext;
- jh = transaction->t_checkpoint_list;
- if (jh) {
- struct journal_head *last_jh = jh->b_cpprev;
- struct journal_head *next_jh = jh;
-
- do {
- jh = next_jh;
- next_jh = jh->b_cpnext;
- /* Use trylock because of the ranknig */
- if (jbd_trylock_bh_state(jh2bh(jh)))
- ret += __try_to_free_cp_buf(jh);
- /*
- * This function only frees up some memory
- * if possible so we dont have an obligation
- * to finish processing. Bail out if preemption
- * requested:
- */
- if (need_resched())
- goto out;
- } while (jh != last_jh);
- }
+ ret += journal_clean_one_cp_list(transaction->
+ t_checkpoint_list, &released);
+ /*
+ * This function only frees up some memory if possible so we
+ * dont have an obligation to finish processing. Bail out if
+ * preemption requested:
+ */
+ if (need_resched())
+ goto out;
+ if (released)
+ continue;
+ /*
+ * It is essential that we are as careful as in the case of
+ * t_checkpoint_list with removing the buffer from the list as
+ * we can possibly see not yet submitted buffers on io_list
+ */
+ ret += journal_clean_one_cp_list(transaction->
+ t_checkpoint_io_list, &released);
+ if (need_resched())
+ goto out;
} while (transaction != last_transaction);
out:
return ret;
@@ -516,18 +566,22 @@ out:
* buffer updates committed in that transaction have safely been stored
* elsewhere on disk. To achieve this, all of the buffers in a
* transaction need to be maintained on the transaction's checkpoint
- * list until they have been rewritten, at which point this function is
+ * lists until they have been rewritten, at which point this function is
* called to remove the buffer from the existing transaction's
- * checkpoint list.
+ * checkpoint lists.
+ *
+ * The function returns 1 if it frees the transaction, 0 otherwise.
*
* This function is called with the journal locked.
* This function is called with j_list_lock held.
+ * This function is called with jbd_lock_bh_state(jh2bh(jh))
*/
-void __journal_remove_checkpoint(struct journal_head *jh)
+int __journal_remove_checkpoint(struct journal_head *jh)
{
transaction_t *transaction;
journal_t *journal;
+ int ret = 0;
JBUFFER_TRACE(jh, "entry");
@@ -538,8 +592,10 @@ void __journal_remove_checkpoint(struct journal_head *jh)
journal = transaction->t_journal;
__buffer_unlink(jh);
+ jh->b_cp_transaction = NULL;
- if (transaction->t_checkpoint_list != NULL)
+ if (transaction->t_checkpoint_list != NULL ||
+ transaction->t_checkpoint_io_list != NULL)
goto out;
JBUFFER_TRACE(jh, "transaction has no more buffers");
@@ -565,8 +621,10 @@ void __journal_remove_checkpoint(struct journal_head *jh)
/* Just in case anybody was waiting for more transactions to be
checkpointed... */
wake_up(&journal->j_wait_logspace);
+ ret = 1;
out:
JBUFFER_TRACE(jh, "exit");
+ return ret;
}
/*
@@ -628,6 +686,7 @@ void __journal_drop_transaction(journal_t *journal, transaction_t *transaction)
J_ASSERT(transaction->t_shadow_list == NULL);
J_ASSERT(transaction->t_log_list == NULL);
J_ASSERT(transaction->t_checkpoint_list == NULL);
+ J_ASSERT(transaction->t_checkpoint_io_list == NULL);
J_ASSERT(transaction->t_updates == 0);
J_ASSERT(journal->j_committing_transaction != transaction);
J_ASSERT(journal->j_running_transaction != transaction);
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c
index 002ad2b..0971814 100644
--- a/fs/jbd/commit.c
+++ b/fs/jbd/commit.c
@@ -790,11 +790,22 @@ restart_loop:
jbd_unlock_bh_state(bh);
} else {
J_ASSERT_BH(bh, !buffer_dirty(bh));
- J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
- __journal_unfile_buffer(jh);
- jbd_unlock_bh_state(bh);
- journal_remove_journal_head(bh); /* needs a brelse */
- release_buffer_page(bh);
+ /* The buffer on BJ_Forget list and not jbddirty means
+ * it has been freed by this transaction and hence it
+ * could not have been reallocated until this
+ * transaction has committed. *BUT* it could be
+ * reallocated once we have written all the data to
+ * disk and before we process the buffer on BJ_Forget
+ * list. */
+ JBUFFER_TRACE(jh, "refile or unfile freed buffer");
+ __journal_refile_buffer(jh);
+ if (!jh->b_transaction) {
+ jbd_unlock_bh_state(bh);
+ /* needs a brelse */
+ journal_remove_journal_head(bh);
+ release_buffer_page(bh);
+ } else
+ jbd_unlock_bh_state(bh);
}
cond_resched_lock(&journal->j_list_lock);
}
diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c
index 80d7f53..de5bafb4e 100644
--- a/fs/jbd/recovery.c
+++ b/fs/jbd/recovery.c
@@ -531,6 +531,7 @@ static int do_one_pass(journal_t *journal,
default:
jbd_debug(3, "Unrecognised magic %d, end of scan.\n",
blocktype);
+ brelse(bh);
goto done;
}
}
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
index c609f50..508b2ea 100644
--- a/fs/jbd/transaction.c
+++ b/fs/jbd/transaction.c
@@ -227,7 +227,8 @@ repeat_locked:
spin_unlock(&transaction->t_handle_lock);
spin_unlock(&journal->j_state_lock);
out:
- kfree(new_transaction);
+ if (unlikely(new_transaction)) /* It's usually NULL */
+ kfree(new_transaction);
return ret;
}
@@ -724,7 +725,8 @@ done:
journal_cancel_revoke(handle, jh);
out:
- kfree(frozen_buffer);
+ if (unlikely(frozen_buffer)) /* It's usually NULL */
+ kfree(frozen_buffer);
JBUFFER_TRACE(jh, "exit");
return error;
@@ -903,7 +905,8 @@ repeat:
jbd_unlock_bh_state(bh);
out:
journal_put_journal_head(jh);
- kfree(committed_data);
+ if (unlikely(committed_data))
+ kfree(committed_data);
return err;
}
@@ -2038,7 +2041,8 @@ void __journal_refile_buffer(struct journal_head *jh)
__journal_temp_unlink_buffer(jh);
jh->b_transaction = jh->b_next_transaction;
jh->b_next_transaction = NULL;
- __journal_file_buffer(jh, jh->b_transaction, BJ_Metadata);
+ __journal_file_buffer(jh, jh->b_transaction,
+ was_dirty ? BJ_Metadata : BJ_Reserved);
J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING);
if (was_dirty)
diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c
index 020cc09..9e46ea6 100644
--- a/fs/jffs/inode-v23.c
+++ b/fs/jffs/inode-v23.c
@@ -377,9 +377,9 @@ jffs_new_inode(const struct inode * dir, struct jffs_raw_inode *raw_inode,
/* Get statistics of the file system. */
static int
-jffs_statfs(struct super_block *sb, struct kstatfs *buf)
+jffs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
- struct jffs_control *c = (struct jffs_control *) sb->s_fs_info;
+ struct jffs_control *c = (struct jffs_control *) dentry->d_sb->s_fs_info;
struct jffs_fmcontrol *fmc;
lock_kernel();
@@ -1785,10 +1785,11 @@ static struct super_operations jffs_ops =
.remount_fs = jffs_remount,
};
-static struct super_block *jffs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int jffs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, jffs_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, jffs_fill_super,
+ mnt);
}
static struct file_system_type jffs_fs_type = {
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index 7b6c24b..2900ec3 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -192,9 +192,9 @@ int jffs2_setattr(struct dentry *dentry, struct iattr *iattr)
return rc;
}
-int jffs2_statfs(struct super_block *sb, struct kstatfs *buf)
+int jffs2_statfs(struct dentry *dentry, struct kstatfs *buf)
{
- struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(dentry->d_sb);
unsigned long avail;
buf->f_type = JFFS2_SUPER_MAGIC;
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index cd4021b..6b52235 100644
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -175,7 +175,7 @@ void jffs2_clear_inode (struct inode *);
void jffs2_dirty_inode(struct inode *inode);
struct inode *jffs2_new_inode (struct inode *dir_i, int mode,
struct jffs2_raw_inode *ri);
-int jffs2_statfs (struct super_block *, struct kstatfs *);
+int jffs2_statfs (struct dentry *, struct kstatfs *);
void jffs2_write_super (struct super_block *);
int jffs2_remount_fs (struct super_block *, int *, char *);
int jffs2_do_fill_super(struct super_block *sb, void *data, int silent);
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index 9d05214..2378a66 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -111,9 +111,10 @@ static int jffs2_sb_set(struct super_block *sb, void *data)
return 0;
}
-static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data, struct mtd_info *mtd)
+static int jffs2_get_sb_mtd(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data, struct mtd_info *mtd,
+ struct vfsmount *mnt)
{
struct super_block *sb;
struct jffs2_sb_info *c;
@@ -121,19 +122,20 @@ static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type,
c = kmalloc(sizeof(*c), GFP_KERNEL);
if (!c)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
memset(c, 0, sizeof(*c));
c->mtd = mtd;
sb = sget(fs_type, jffs2_sb_compare, jffs2_sb_set, c);
if (IS_ERR(sb))
- goto out_put;
+ goto out_error;
if (sb->s_root) {
/* New mountpoint for JFFS2 which is already mounted */
D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): Device %d (\"%s\") is already mounted\n",
mtd->index, mtd->name));
+ ret = simple_set_mnt(mnt, sb);
goto out_put;
}
@@ -161,44 +163,47 @@ static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type,
/* Failure case... */
up_write(&sb->s_umount);
deactivate_super(sb);
- return ERR_PTR(ret);
+ return ret;
}
sb->s_flags |= MS_ACTIVE;
- return sb;
+ return simple_set_mnt(mnt, sb);
+out_error:
+ ret = PTR_ERR(sb);
out_put:
kfree(c);
put_mtd_device(mtd);
- return sb;
+ return ret;
}
-static struct super_block *jffs2_get_sb_mtdnr(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data, int mtdnr)
+static int jffs2_get_sb_mtdnr(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data, int mtdnr,
+ struct vfsmount *mnt)
{
struct mtd_info *mtd;
mtd = get_mtd_device(NULL, mtdnr);
if (!mtd) {
D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", mtdnr));
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
- return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd);
+ return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd, mnt);
}
-static struct super_block *jffs2_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data)
+static int jffs2_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data, struct vfsmount *mnt)
{
int err;
struct nameidata nd;
int mtdnr;
if (!dev_name)
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
D1(printk(KERN_DEBUG "jffs2_get_sb(): dev_name \"%s\"\n", dev_name));
@@ -220,7 +225,7 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type,
mtd = get_mtd_device(NULL, mtdnr);
if (mtd) {
if (!strcmp(mtd->name, dev_name+4))
- return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd);
+ return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd, mnt);
put_mtd_device(mtd);
}
}
@@ -233,7 +238,7 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type,
if (!*endptr) {
/* It was a valid number */
D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd%%d, mtdnr %d\n", mtdnr));
- return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr);
+ return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr, mnt);
}
}
}
@@ -247,7 +252,7 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type,
err, nd.dentry->d_inode));
if (err)
- return ERR_PTR(err);
+ return err;
err = -EINVAL;
@@ -269,11 +274,11 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type,
mtdnr = iminor(nd.dentry->d_inode);
path_release(&nd);
- return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr);
+ return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr, mnt);
out:
path_release(&nd);
- return ERR_PTR(err);
+ return err;
}
static void jffs2_put_super (struct super_block *sb)
diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
index 2b220dd..7f6e880 100644
--- a/fs/jfs/jfs_metapage.c
+++ b/fs/jfs/jfs_metapage.c
@@ -632,10 +632,9 @@ struct metapage *__get_metapage(struct inode *inode, unsigned long lblock,
}
SetPageUptodate(page);
} else {
- page = read_cache_page(mapping, page_index,
- (filler_t *)mapping->a_ops->readpage, NULL);
+ page = read_mapping_page(mapping, page_index, NULL);
if (IS_ERR(page) || !PageUptodate(page)) {
- jfs_err("read_cache_page failed!");
+ jfs_err("read_mapping_page failed!");
return NULL;
}
lock_page(page);
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index db6f41d..73d2aba 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -139,9 +139,9 @@ static void jfs_destroy_inode(struct inode *inode)
kmem_cache_free(jfs_inode_cachep, ji);
}
-static int jfs_statfs(struct super_block *sb, struct kstatfs *buf)
+static int jfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
- struct jfs_sb_info *sbi = JFS_SBI(sb);
+ struct jfs_sb_info *sbi = JFS_SBI(dentry->d_sb);
s64 maxinodes;
struct inomap *imap = JFS_IP(sbi->ipimap)->i_imap;
@@ -565,10 +565,11 @@ static void jfs_unlockfs(struct super_block *sb)
}
}
-static struct super_block *jfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int jfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, jfs_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, jfs_fill_super,
+ mnt);
}
static int jfs_sync_fs(struct super_block *sb, int wait)
diff --git a/fs/libfs.c b/fs/libfs.c
index 7145ba7..fc785d8 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -20,9 +20,9 @@ int simple_getattr(struct vfsmount *mnt, struct dentry *dentry,
return 0;
}
-int simple_statfs(struct super_block *sb, struct kstatfs *buf)
+int simple_statfs(struct dentry *dentry, struct kstatfs *buf)
{
- buf->f_type = sb->s_magic;
+ buf->f_type = dentry->d_sb->s_magic;
buf->f_bsize = PAGE_CACHE_SIZE;
buf->f_namelen = NAME_MAX;
return 0;
@@ -196,9 +196,9 @@ struct inode_operations simple_dir_inode_operations = {
* Common helper for pseudo-filesystems (sockfs, pipefs, bdev - stuff that
* will never be mountable)
*/
-struct super_block *
-get_sb_pseudo(struct file_system_type *fs_type, char *name,
- struct super_operations *ops, unsigned long magic)
+int get_sb_pseudo(struct file_system_type *fs_type, char *name,
+ struct super_operations *ops, unsigned long magic,
+ struct vfsmount *mnt)
{
struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
static struct super_operations default_ops = {.statfs = simple_statfs};
@@ -207,7 +207,7 @@ get_sb_pseudo(struct file_system_type *fs_type, char *name,
struct qstr d_name = {.name = name, .len = strlen(name)};
if (IS_ERR(s))
- return s;
+ return PTR_ERR(s);
s->s_flags = MS_NOUSER;
s->s_maxbytes = ~0ULL;
@@ -232,12 +232,12 @@ get_sb_pseudo(struct file_system_type *fs_type, char *name,
d_instantiate(dentry, root);
s->s_root = dentry;
s->s_flags |= MS_ACTIVE;
- return s;
+ return simple_set_mnt(mnt, s);
Enomem:
up_write(&s->s_umount);
deactivate_super(s);
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
}
int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
@@ -424,13 +424,13 @@ out:
static DEFINE_SPINLOCK(pin_fs_lock);
-int simple_pin_fs(char *name, struct vfsmount **mount, int *count)
+int simple_pin_fs(struct file_system_type *type, struct vfsmount **mount, int *count)
{
struct vfsmount *mnt = NULL;
spin_lock(&pin_fs_lock);
if (unlikely(!*mount)) {
spin_unlock(&pin_fs_lock);
- mnt = do_kern_mount(name, 0, name, NULL);
+ mnt = vfs_kern_mount(type, 0, type->name, NULL);
if (IS_ERR(mnt))
return PTR_ERR(mnt);
spin_lock(&pin_fs_lock);
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index bce7444..52774fe 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -147,11 +147,10 @@ u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock)
* Someone has sent us an SM_NOTIFY. Ensure we bind to the new port number,
* that we mark locks for reclaiming, and that we bump the pseudo NSM state.
*/
-static inline
-void nlmclnt_prepare_reclaim(struct nlm_host *host, u32 newstate)
+static void nlmclnt_prepare_reclaim(struct nlm_host *host)
{
+ down_write(&host->h_rwsem);
host->h_monitored = 0;
- host->h_nsmstate = newstate;
host->h_state++;
host->h_nextrebind = 0;
nlm_rebind_host(host);
@@ -164,6 +163,13 @@ void nlmclnt_prepare_reclaim(struct nlm_host *host, u32 newstate)
dprintk("NLM: reclaiming locks for host %s", host->h_name);
}
+static void nlmclnt_finish_reclaim(struct nlm_host *host)
+{
+ host->h_reclaiming = 0;
+ up_write(&host->h_rwsem);
+ dprintk("NLM: done reclaiming locks for host %s", host->h_name);
+}
+
/*
* Reclaim all locks on server host. We do this by spawning a separate
* reclaimer thread.
@@ -171,12 +177,10 @@ void nlmclnt_prepare_reclaim(struct nlm_host *host, u32 newstate)
void
nlmclnt_recovery(struct nlm_host *host, u32 newstate)
{
- if (host->h_reclaiming++) {
- if (host->h_nsmstate == newstate)
- return;
- nlmclnt_prepare_reclaim(host, newstate);
- } else {
- nlmclnt_prepare_reclaim(host, newstate);
+ if (host->h_nsmstate == newstate)
+ return;
+ host->h_nsmstate = newstate;
+ if (!host->h_reclaiming++) {
nlm_get_host(host);
__module_get(THIS_MODULE);
if (kernel_thread(reclaimer, host, CLONE_KERNEL) < 0)
@@ -190,6 +194,7 @@ reclaimer(void *ptr)
struct nlm_host *host = (struct nlm_host *) ptr;
struct nlm_wait *block;
struct file_lock *fl, *next;
+ u32 nsmstate;
daemonize("%s-reclaim", host->h_name);
allow_signal(SIGKILL);
@@ -199,19 +204,25 @@ reclaimer(void *ptr)
lock_kernel();
lockd_up();
+ nlmclnt_prepare_reclaim(host);
/* First, reclaim all locks that have been marked. */
restart:
+ nsmstate = host->h_nsmstate;
list_for_each_entry_safe(fl, next, &host->h_reclaim, fl_u.nfs_fl.list) {
list_del_init(&fl->fl_u.nfs_fl.list);
if (signalled())
continue;
- if (nlmclnt_reclaim(host, fl) == 0)
- list_add_tail(&fl->fl_u.nfs_fl.list, &host->h_granted);
- goto restart;
+ if (nlmclnt_reclaim(host, fl) != 0)
+ continue;
+ list_add_tail(&fl->fl_u.nfs_fl.list, &host->h_granted);
+ if (host->h_nsmstate != nsmstate) {
+ /* Argh! The server rebooted again! */
+ list_splice_init(&host->h_granted, &host->h_reclaim);
+ goto restart;
+ }
}
-
- host->h_reclaiming = 0;
+ nlmclnt_finish_reclaim(host);
/* Now, wake up all processes that sleep on a blocked lock */
list_for_each_entry(block, &nlm_blocked, b_list) {
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index f96e381..4db6209 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -508,7 +508,10 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
}
block = nlmclnt_prepare_block(host, fl);
+again:
for(;;) {
+ /* Reboot protection */
+ fl->fl_u.nfs_fl.state = host->h_state;
status = nlmclnt_call(req, NLMPROC_LOCK);
if (status < 0)
goto out_unblock;
@@ -531,10 +534,16 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
}
if (resp->status == NLM_LCK_GRANTED) {
- fl->fl_u.nfs_fl.state = host->h_state;
+ down_read(&host->h_rwsem);
+ /* Check whether or not the server has rebooted */
+ if (fl->fl_u.nfs_fl.state != host->h_state) {
+ up_read(&host->h_rwsem);
+ goto again;
+ }
fl->fl_flags |= FL_SLEEP;
/* Ensure the resulting lock will get added to granted list */
do_vfs_lock(fl);
+ up_read(&host->h_rwsem);
}
status = nlm_stat_to_errno(resp->status);
out_unblock:
@@ -596,6 +605,7 @@ nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl)
static int
nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
{
+ struct nlm_host *host = req->a_host;
struct nlm_res *resp = &req->a_res;
int status;
@@ -604,7 +614,9 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
* request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either
* case, we want to unlock.
*/
+ down_read(&host->h_rwsem);
do_vfs_lock(fl);
+ up_read(&host->h_rwsem);
if (req->a_flags & RPC_TASK_ASYNC)
return nlm_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index 729ac42..38b0e8a 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -112,11 +112,12 @@ nlm_lookup_host(int server, struct sockaddr_in *sin,
host->h_version = version;
host->h_proto = proto;
host->h_rpcclnt = NULL;
- init_MUTEX(&host->h_sema);
+ mutex_init(&host->h_mutex);
host->h_nextrebind = jiffies + NLM_HOST_REBIND;
host->h_expires = jiffies + NLM_HOST_EXPIRE;
atomic_set(&host->h_count, 1);
init_waitqueue_head(&host->h_gracewait);
+ init_rwsem(&host->h_rwsem);
host->h_state = 0; /* pseudo NSM state */
host->h_nsmstate = 0; /* real NSM state */
host->h_server = server;
@@ -172,7 +173,7 @@ nlm_bind_host(struct nlm_host *host)
(unsigned)ntohl(host->h_addr.sin_addr.s_addr));
/* Lock host handle */
- down(&host->h_sema);
+ mutex_lock(&host->h_mutex);
/* If we've already created an RPC client, check whether
* RPC rebind is required
@@ -204,12 +205,12 @@ nlm_bind_host(struct nlm_host *host)
host->h_rpcclnt = clnt;
}
- up(&host->h_sema);
+ mutex_unlock(&host->h_mutex);
return clnt;
forgetit:
printk("lockd: couldn't create RPC handle for %s\n", host->h_name);
- up(&host->h_sema);
+ mutex_unlock(&host->h_mutex);
return NULL;
}
diff --git a/fs/locks.c b/fs/locks.c
index ab61a8b..1ad29c9 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -703,7 +703,7 @@ EXPORT_SYMBOL(posix_test_lock);
* from a broken NFS client. But broken NFS clients have a lot more to
* worry about than proper deadlock detection anyway... --okir
*/
-int posix_locks_deadlock(struct file_lock *caller_fl,
+static int posix_locks_deadlock(struct file_lock *caller_fl,
struct file_lock *block_fl)
{
struct list_head *tmp;
@@ -722,8 +722,6 @@ next_task:
return 0;
}
-EXPORT_SYMBOL(posix_locks_deadlock);
-
/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks
* at the head of the list, but that's secret knowledge known only to
* flock_lock_file and posix_lock_file.
@@ -794,7 +792,8 @@ out:
static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request, struct file_lock *conflock)
{
struct file_lock *fl;
- struct file_lock *new_fl, *new_fl2;
+ struct file_lock *new_fl = NULL;
+ struct file_lock *new_fl2 = NULL;
struct file_lock *left = NULL;
struct file_lock *right = NULL;
struct file_lock **before;
@@ -803,9 +802,15 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
/*
* We may need two file_lock structures for this operation,
* so we get them in advance to avoid races.
+ *
+ * In some cases we can be sure, that no new locks will be needed
*/
- new_fl = locks_alloc_lock();
- new_fl2 = locks_alloc_lock();
+ if (!(request->fl_flags & FL_ACCESS) &&
+ (request->fl_type != F_UNLCK ||
+ request->fl_start != 0 || request->fl_end != OFFSET_MAX)) {
+ new_fl = locks_alloc_lock();
+ new_fl2 = locks_alloc_lock();
+ }
lock_kernel();
if (request->fl_type != F_UNLCK) {
@@ -834,14 +839,7 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
if (request->fl_flags & FL_ACCESS)
goto out;
- error = -ENOLCK; /* "no luck" */
- if (!(new_fl && new_fl2))
- goto out;
-
/*
- * We've allocated the new locks in advance, so there are no
- * errors possible (and no blocking operations) from here on.
- *
* Find the first old lock with the same owner as the new lock.
*/
@@ -938,10 +936,25 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
before = &fl->fl_next;
}
+ /*
+ * The above code only modifies existing locks in case of
+ * merging or replacing. If new lock(s) need to be inserted
+ * all modifications are done bellow this, so it's safe yet to
+ * bail out.
+ */
+ error = -ENOLCK; /* "no luck" */
+ if (right && left == right && !new_fl2)
+ goto out;
+
error = 0;
if (!added) {
if (request->fl_type == F_UNLCK)
goto out;
+
+ if (!new_fl) {
+ error = -ENOLCK;
+ goto out;
+ }
locks_copy_lock(new_fl, request);
locks_insert_lock(before, new_fl);
new_fl = NULL;
@@ -1881,19 +1894,18 @@ out:
*/
void locks_remove_posix(struct file *filp, fl_owner_t owner)
{
- struct file_lock lock, **before;
+ struct file_lock lock;
/*
* If there are no locks held on this file, we don't need to call
* posix_lock_file(). Another process could be setting a lock on this
* file at the same time, but we wouldn't remove that lock anyway.
*/
- before = &filp->f_dentry->d_inode->i_flock;
- if (*before == NULL)
+ if (!filp->f_dentry->d_inode->i_flock)
return;
lock.fl_type = F_UNLCK;
- lock.fl_flags = FL_POSIX;
+ lock.fl_flags = FL_POSIX | FL_CLOSE;
lock.fl_start = 0;
lock.fl_end = OFFSET_MAX;
lock.fl_owner = owner;
@@ -1902,25 +1914,11 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
lock.fl_ops = NULL;
lock.fl_lmops = NULL;
- if (filp->f_op && filp->f_op->lock != NULL) {
+ if (filp->f_op && filp->f_op->lock != NULL)
filp->f_op->lock(filp, F_SETLK, &lock);
- goto out;
- }
+ else
+ posix_lock_file(filp, &lock);
- /* Can't use posix_lock_file here; we need to remove it no matter
- * which pid we have.
- */
- lock_kernel();
- while (*before != NULL) {
- struct file_lock *fl = *before;
- if (IS_POSIX(fl) && posix_same_owner(fl, &lock)) {
- locks_delete_lock(before);
- continue;
- }
- before = &fl->fl_next;
- }
- unlock_kernel();
-out:
if (lock.fl_ops && lock.fl_ops->fl_release_private)
lock.fl_ops->fl_release_private(&lock);
}
@@ -2206,63 +2204,6 @@ int lock_may_write(struct inode *inode, loff_t start, unsigned long len)
EXPORT_SYMBOL(lock_may_write);
-static inline void __steal_locks(struct file *file, fl_owner_t from)
-{
- struct inode *inode = file->f_dentry->d_inode;
- struct file_lock *fl = inode->i_flock;
-
- while (fl) {
- if (fl->fl_file == file && fl->fl_owner == from)
- fl->fl_owner = current->files;
- fl = fl->fl_next;
- }
-}
-
-/* When getting ready for executing a binary, we make sure that current
- * has a files_struct on its own. Before dropping the old files_struct,
- * we take over ownership of all locks for all file descriptors we own.
- * Note that we may accidentally steal a lock for a file that a sibling
- * has created since the unshare_files() call.
- */
-void steal_locks(fl_owner_t from)
-{
- struct files_struct *files = current->files;
- int i, j;
- struct fdtable *fdt;
-
- if (from == files)
- return;
-
- lock_kernel();
- j = 0;
-
- /*
- * We are not taking a ref to the file structures, so
- * we need to acquire ->file_lock.
- */
- spin_lock(&files->file_lock);
- fdt = files_fdtable(files);
- for (;;) {
- unsigned long set;
- i = j * __NFDBITS;
- if (i >= fdt->max_fdset || i >= fdt->max_fds)
- break;
- set = fdt->open_fds->fds_bits[j++];
- while (set) {
- if (set & 1) {
- struct file *file = fdt->fd[i];
- if (file)
- __steal_locks(file, from);
- }
- i++;
- set >>= 1;
- }
- }
- spin_unlock(&files->file_lock);
- unlock_kernel();
-}
-EXPORT_SYMBOL(steal_locks);
-
static int __init filelock_init(void)
{
filelock_cache = kmem_cache_create("file_lock_cache",
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
index 69224d1..2b0a389 100644
--- a/fs/minix/dir.c
+++ b/fs/minix/dir.c
@@ -60,8 +60,7 @@ static int dir_commit_chunk(struct page *page, unsigned from, unsigned to)
static struct page * dir_get_page(struct inode *dir, unsigned long n)
{
struct address_space *mapping = dir->i_mapping;
- struct page *page = read_cache_page(mapping, n,
- (filler_t*)mapping->a_ops->readpage, NULL);
+ struct page *page = read_mapping_page(mapping, n, NULL);
if (!IS_ERR(page)) {
wait_on_page_locked(page);
kmap(page);
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 2dcccf1..a6fb509 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -19,7 +19,7 @@
static void minix_read_inode(struct inode * inode);
static int minix_write_inode(struct inode * inode, int wait);
-static int minix_statfs(struct super_block *sb, struct kstatfs *buf);
+static int minix_statfs(struct dentry *dentry, struct kstatfs *buf);
static int minix_remount (struct super_block * sb, int * flags, char * data);
static void minix_delete_inode(struct inode *inode)
@@ -296,11 +296,11 @@ out_bad_sb:
return -EINVAL;
}
-static int minix_statfs(struct super_block *sb, struct kstatfs *buf)
+static int minix_statfs(struct dentry *dentry, struct kstatfs *buf)
{
- struct minix_sb_info *sbi = minix_sb(sb);
- buf->f_type = sb->s_magic;
- buf->f_bsize = sb->s_blocksize;
+ struct minix_sb_info *sbi = minix_sb(dentry->d_sb);
+ buf->f_type = dentry->d_sb->s_magic;
+ buf->f_bsize = dentry->d_sb->s_blocksize;
buf->f_blocks = (sbi->s_nzones - sbi->s_firstdatazone) << sbi->s_log_zone_size;
buf->f_bfree = minix_count_free_blocks(sbi);
buf->f_bavail = buf->f_bfree;
@@ -559,10 +559,11 @@ void minix_truncate(struct inode * inode)
V2_minix_truncate(inode);
}
-static struct super_block *minix_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int minix_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, minix_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, minix_fill_super,
+ mnt);
}
static struct file_system_type minix_fs_type = {
diff --git a/fs/mpage.c b/fs/mpage.c
index 9bf2eb3..1e45982 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -707,9 +707,9 @@ mpage_writepages(struct address_space *mapping,
struct pagevec pvec;
int nr_pages;
pgoff_t index;
- pgoff_t end = -1; /* Inclusive */
+ pgoff_t end; /* Inclusive */
int scanned = 0;
- int is_range = 0;
+ int range_whole = 0;
if (wbc->nonblocking && bdi_write_congested(bdi)) {
wbc->encountered_congestion = 1;
@@ -721,16 +721,14 @@ mpage_writepages(struct address_space *mapping,
writepage = mapping->a_ops->writepage;
pagevec_init(&pvec, 0);
- if (wbc->sync_mode == WB_SYNC_NONE) {
+ if (wbc->range_cyclic) {
index = mapping->writeback_index; /* Start from prev offset */
+ end = -1;
} else {
- index = 0; /* whole-file sweep */
- scanned = 1;
- }
- if (wbc->start || wbc->end) {
- index = wbc->start >> PAGE_CACHE_SHIFT;
- end = wbc->end >> PAGE_CACHE_SHIFT;
- is_range = 1;
+ index = wbc->range_start >> PAGE_CACHE_SHIFT;
+ end = wbc->range_end >> PAGE_CACHE_SHIFT;
+ if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
+ range_whole = 1;
scanned = 1;
}
retry:
@@ -759,7 +757,7 @@ retry:
continue;
}
- if (unlikely(is_range) && page->index > end) {
+ if (!wbc->range_cyclic && page->index > end) {
done = 1;
unlock_page(page);
continue;
@@ -810,7 +808,7 @@ retry:
index = 0;
goto retry;
}
- if (!is_range)
+ if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
mapping->writeback_index = index;
if (bio)
mpage_bio_submit(WRITE, bio);
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index 5b76ccd..9e44158 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -661,11 +661,12 @@ static int msdos_fill_super(struct super_block *sb, void *data, int silent)
return 0;
}
-static struct super_block *msdos_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data)
+static int msdos_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, msdos_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, msdos_fill_super,
+ mnt);
}
static struct file_system_type msdos_fs_type = {
diff --git a/fs/namei.c b/fs/namei.c
index 184fe4ac..c784e8b 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2243,14 +2243,16 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname,
int error;
char * to;
- if (flags != 0)
+ if ((flags & ~AT_SYMLINK_FOLLOW) != 0)
return -EINVAL;
to = getname(newname);
if (IS_ERR(to))
return PTR_ERR(to);
- error = __user_walk_fd(olddfd, oldname, 0, &old_nd);
+ error = __user_walk_fd(olddfd, oldname,
+ flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0,
+ &old_nd);
if (error)
goto exit;
error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
@@ -2577,8 +2579,7 @@ static char *page_getlink(struct dentry * dentry, struct page **ppage)
{
struct page * page;
struct address_space *mapping = dentry->d_inode->i_mapping;
- page = read_cache_page(mapping, 0, (filler_t *)mapping->a_ops->readpage,
- NULL);
+ page = read_mapping_page(mapping, 0, NULL);
if (IS_ERR(page))
goto sync_fail;
wait_on_page_locked(page);
diff --git a/fs/namespace.c b/fs/namespace.c
index bf478ad..866430b 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -86,6 +86,15 @@ struct vfsmount *alloc_vfsmnt(const char *name)
return mnt;
}
+int simple_set_mnt(struct vfsmount *mnt, struct super_block *sb)
+{
+ mnt->mnt_sb = sb;
+ mnt->mnt_root = dget(sb->s_root);
+ return 0;
+}
+
+EXPORT_SYMBOL(simple_set_mnt);
+
void free_vfsmnt(struct vfsmount *mnt)
{
kfree(mnt->mnt_devname);
@@ -576,8 +585,8 @@ static int do_umount(struct vfsmount *mnt, int flags)
*/
lock_kernel();
- if ((flags & MNT_FORCE) && sb->s_op->umount_begin)
- sb->s_op->umount_begin(sb);
+ if (sb->s_op->umount_begin)
+ sb->s_op->umount_begin(mnt, flags);
unlock_kernel();
/*
@@ -1163,13 +1172,46 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts,
}
/*
+ * go through the vfsmounts we've just consigned to the graveyard to
+ * - check that they're still dead
+ * - delete the vfsmount from the appropriate namespace under lock
+ * - dispose of the corpse
+ */
+static void expire_mount_list(struct list_head *graveyard, struct list_head *mounts)
+{
+ struct namespace *namespace;
+ struct vfsmount *mnt;
+
+ while (!list_empty(graveyard)) {
+ LIST_HEAD(umounts);
+ mnt = list_entry(graveyard->next, struct vfsmount, mnt_expire);
+ list_del_init(&mnt->mnt_expire);
+
+ /* don't do anything if the namespace is dead - all the
+ * vfsmounts from it are going away anyway */
+ namespace = mnt->mnt_namespace;
+ if (!namespace || !namespace->root)
+ continue;
+ get_namespace(namespace);
+
+ spin_unlock(&vfsmount_lock);
+ down_write(&namespace_sem);
+ expire_mount(mnt, mounts, &umounts);
+ up_write(&namespace_sem);
+ release_mounts(&umounts);
+ mntput(mnt);
+ put_namespace(namespace);
+ spin_lock(&vfsmount_lock);
+ }
+}
+
+/*
* process a list of expirable mountpoints with the intent of discarding any
* mountpoints that aren't in use and haven't been touched since last we came
* here
*/
void mark_mounts_for_expiry(struct list_head *mounts)
{
- struct namespace *namespace;
struct vfsmount *mnt, *next;
LIST_HEAD(graveyard);
@@ -1193,38 +1235,79 @@ void mark_mounts_for_expiry(struct list_head *mounts)
list_move(&mnt->mnt_expire, &graveyard);
}
- /*
- * go through the vfsmounts we've just consigned to the graveyard to
- * - check that they're still dead
- * - delete the vfsmount from the appropriate namespace under lock
- * - dispose of the corpse
- */
- while (!list_empty(&graveyard)) {
- LIST_HEAD(umounts);
- mnt = list_entry(graveyard.next, struct vfsmount, mnt_expire);
- list_del_init(&mnt->mnt_expire);
+ expire_mount_list(&graveyard, mounts);
- /* don't do anything if the namespace is dead - all the
- * vfsmounts from it are going away anyway */
- namespace = mnt->mnt_namespace;
- if (!namespace || !namespace->root)
+ spin_unlock(&vfsmount_lock);
+}
+
+EXPORT_SYMBOL_GPL(mark_mounts_for_expiry);
+
+/*
+ * Ripoff of 'select_parent()'
+ *
+ * search the list of submounts for a given mountpoint, and move any
+ * shrinkable submounts to the 'graveyard' list.
+ */
+static int select_submounts(struct vfsmount *parent, struct list_head *graveyard)
+{
+ struct vfsmount *this_parent = parent;
+ struct list_head *next;
+ int found = 0;
+
+repeat:
+ next = this_parent->mnt_mounts.next;
+resume:
+ while (next != &this_parent->mnt_mounts) {
+ struct list_head *tmp = next;
+ struct vfsmount *mnt = list_entry(tmp, struct vfsmount, mnt_child);
+
+ next = tmp->next;
+ if (!(mnt->mnt_flags & MNT_SHRINKABLE))
continue;
- get_namespace(namespace);
+ /*
+ * Descend a level if the d_mounts list is non-empty.
+ */
+ if (!list_empty(&mnt->mnt_mounts)) {
+ this_parent = mnt;
+ goto repeat;
+ }
- spin_unlock(&vfsmount_lock);
- down_write(&namespace_sem);
- expire_mount(mnt, mounts, &umounts);
- up_write(&namespace_sem);
- release_mounts(&umounts);
- mntput(mnt);
- put_namespace(namespace);
- spin_lock(&vfsmount_lock);
+ if (!propagate_mount_busy(mnt, 1)) {
+ mntget(mnt);
+ list_move_tail(&mnt->mnt_expire, graveyard);
+ found++;
+ }
}
+ /*
+ * All done at this level ... ascend and resume the search
+ */
+ if (this_parent != parent) {
+ next = this_parent->mnt_child.next;
+ this_parent = this_parent->mnt_parent;
+ goto resume;
+ }
+ return found;
+}
+
+/*
+ * process a list of expirable mountpoints with the intent of discarding any
+ * submounts of a specific parent mountpoint
+ */
+void shrink_submounts(struct vfsmount *mountpoint, struct list_head *mounts)
+{
+ LIST_HEAD(graveyard);
+ int found;
+
+ spin_lock(&vfsmount_lock);
+
+ /* extract submounts of 'mountpoint' from the expiration list */
+ while ((found = select_submounts(mountpoint, &graveyard)) != 0)
+ expire_mount_list(&graveyard, mounts);
spin_unlock(&vfsmount_lock);
}
-EXPORT_SYMBOL_GPL(mark_mounts_for_expiry);
+EXPORT_SYMBOL_GPL(shrink_submounts);
/*
* Some copy_from_user() implementations do not return the exact number of
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index a1f3e97..90d2ea2 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -39,7 +39,7 @@
static void ncp_delete_inode(struct inode *);
static void ncp_put_super(struct super_block *);
-static int ncp_statfs(struct super_block *, struct kstatfs *);
+static int ncp_statfs(struct dentry *, struct kstatfs *);
static kmem_cache_t * ncp_inode_cachep;
@@ -724,13 +724,14 @@ static void ncp_put_super(struct super_block *sb)
kfree(server);
}
-static int ncp_statfs(struct super_block *sb, struct kstatfs *buf)
+static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct dentry* d;
struct inode* i;
struct ncp_inode_info* ni;
struct ncp_server* s;
struct ncp_volume_info vi;
+ struct super_block *sb = dentry->d_sb;
int err;
__u8 dh;
@@ -957,10 +958,10 @@ out:
return result;
}
-static struct super_block *ncp_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int ncp_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_nodev(fs_type, flags, data, ncp_fill_super);
+ return get_sb_nodev(fs_type, flags, data, ncp_fill_super, mnt);
}
static struct file_system_type ncp_fs_type = {
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index ec61fd5..0b572a0 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -4,14 +4,16 @@
obj-$(CONFIG_NFS_FS) += nfs.o
-nfs-y := dir.o file.o inode.o nfs2xdr.o pagelist.o \
- proc.o read.o symlink.o unlink.o write.o
+nfs-y := dir.o file.o inode.o super.o nfs2xdr.o pagelist.o \
+ proc.o read.o symlink.o unlink.o write.o \
+ namespace.o
nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o
nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o
nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
delegation.o idmap.o \
- callback.o callback_xdr.o callback_proc.o
+ callback.o callback_xdr.o callback_proc.o \
+ nfs4namespace.o
nfs-$(CONFIG_NFS_DIRECTIO) += direct.o
nfs-$(CONFIG_SYSCTL) += sysctl.o
nfs-objs := $(nfs-y)
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index 90c95ad..d53f8c6 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -182,8 +182,6 @@ static int nfs_callback_authenticate(struct svc_rqst *rqstp)
/*
* Define NFS4 callback program
*/
-extern struct svc_version nfs4_callback_version1;
-
static struct svc_version *nfs4_callback_version[] = {
[1] = &nfs4_callback_version1,
};
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index 05c38cf..c929913 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -202,7 +202,7 @@ static unsigned decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xd
status = decode_fh(xdr, &args->fh);
out:
dprintk("%s: exit with status = %d\n", __FUNCTION__, status);
- return 0;
+ return status;
}
static unsigned encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index cae74dd..3ddda6f 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -528,7 +528,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
lock_kernel();
- res = nfs_revalidate_inode(NFS_SERVER(inode), inode);
+ res = nfs_revalidate_mapping(inode, filp->f_mapping);
if (res < 0) {
unlock_kernel();
return res;
@@ -868,6 +868,17 @@ int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
return (nd->intent.open.flags & O_EXCL) != 0;
}
+static inline int nfs_reval_fsid(struct inode *dir,
+ struct nfs_fh *fh, struct nfs_fattr *fattr)
+{
+ struct nfs_server *server = NFS_SERVER(dir);
+
+ if (!nfs_fsid_equal(&server->fsid, &fattr->fsid))
+ /* Revalidate fsid on root dir */
+ return __nfs_revalidate_inode(server, dir->i_sb->s_root->d_inode);
+ return 0;
+}
+
static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
{
struct dentry *res;
@@ -900,6 +911,11 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
res = ERR_PTR(error);
goto out_unlock;
}
+ error = nfs_reval_fsid(dir, &fhandle, &fattr);
+ if (error < 0) {
+ res = ERR_PTR(error);
+ goto out_unlock;
+ }
inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr);
res = (struct dentry *)inode;
if (IS_ERR(res))
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 3c72b0c..402005c 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -892,7 +892,7 @@ out:
* nfs_init_directcache - create a slab cache for nfs_direct_req structures
*
*/
-int nfs_init_directcache(void)
+int __init nfs_init_directcache(void)
{
nfs_direct_cachep = kmem_cache_create("nfs_direct_cache",
sizeof(struct nfs_direct_req),
@@ -906,10 +906,10 @@ int nfs_init_directcache(void)
}
/**
- * nfs_init_directcache - destroy the slab cache for nfs_direct_req structures
+ * nfs_destroy_directcache - destroy the slab cache for nfs_direct_req structures
*
*/
-void nfs_destroy_directcache(void)
+void __exit nfs_destroy_directcache(void)
{
if (kmem_cache_destroy(nfs_direct_cachep))
printk(KERN_INFO "nfs_direct_cache: not all structures were freed\n");
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index fade02c..add2891 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -43,7 +43,7 @@ static int nfs_file_mmap(struct file *, struct vm_area_struct *);
static ssize_t nfs_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *);
static ssize_t nfs_file_read(struct kiocb *, char __user *, size_t, loff_t);
static ssize_t nfs_file_write(struct kiocb *, const char __user *, size_t, loff_t);
-static int nfs_file_flush(struct file *);
+static int nfs_file_flush(struct file *, fl_owner_t id);
static int nfs_fsync(struct file *, struct dentry *dentry, int datasync);
static int nfs_check_flags(int flags);
static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl);
@@ -127,23 +127,6 @@ nfs_file_release(struct inode *inode, struct file *filp)
}
/**
- * nfs_revalidate_file - Revalidate the page cache & related metadata
- * @inode - pointer to inode struct
- * @file - pointer to file
- */
-static int nfs_revalidate_file(struct inode *inode, struct file *filp)
-{
- struct nfs_inode *nfsi = NFS_I(inode);
- int retval = 0;
-
- if ((nfsi->cache_validity & (NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_ATTR))
- || nfs_attribute_timeout(inode))
- retval = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
- nfs_revalidate_mapping(inode, filp->f_mapping);
- return 0;
-}
-
-/**
* nfs_revalidate_size - Revalidate the file size
* @inode - pointer to inode struct
* @file - pointer to struct file
@@ -188,7 +171,7 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
*
*/
static int
-nfs_file_flush(struct file *file)
+nfs_file_flush(struct file *file, fl_owner_t id)
{
struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
struct inode *inode = file->f_dentry->d_inode;
@@ -228,7 +211,7 @@ nfs_file_read(struct kiocb *iocb, char __user * buf, size_t count, loff_t pos)
dentry->d_parent->d_name.name, dentry->d_name.name,
(unsigned long) count, (unsigned long) pos);
- result = nfs_revalidate_file(inode, iocb->ki_filp);
+ result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, count);
if (!result)
result = generic_file_aio_read(iocb, buf, count, pos);
@@ -247,7 +230,7 @@ nfs_file_sendfile(struct file *filp, loff_t *ppos, size_t count,
dentry->d_parent->d_name.name, dentry->d_name.name,
(unsigned long) count, (unsigned long long) *ppos);
- res = nfs_revalidate_file(inode, filp);
+ res = nfs_revalidate_mapping(inode, filp->f_mapping);
if (!res)
res = generic_file_sendfile(filp, ppos, count, actor, target);
return res;
@@ -263,7 +246,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
dfprintk(VFS, "nfs: mmap(%s/%s)\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
- status = nfs_revalidate_file(inode, file);
+ status = nfs_revalidate_mapping(inode, file->f_mapping);
if (!status)
status = generic_file_mmap(file, vma);
return status;
@@ -320,7 +303,11 @@ static int nfs_commit_write(struct file *file, struct page *page, unsigned offse
static void nfs_invalidate_page(struct page *page, unsigned long offset)
{
- /* FIXME: we really should cancel any unstarted writes on this page */
+ struct inode *inode = page->mapping->host;
+
+ /* Cancel any unstarted writes on this page */
+ if (offset == 0)
+ nfs_sync_inode_wait(inode, page->index, 1, FLUSH_INVALIDATE);
}
static int nfs_release_page(struct page *page, gfp_t gfp)
@@ -373,7 +360,6 @@ nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t
if (result)
goto out;
}
- nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
result = count;
if (!count)
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
index 3fab5b0..b81e7ed 100644
--- a/fs/nfs/idmap.c
+++ b/fs/nfs/idmap.c
@@ -47,7 +47,6 @@
#include <linux/workqueue.h>
#include <linux/sunrpc/rpc_pipe_fs.h>
-#include <linux/nfs_fs_sb.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_idmap.h>
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index d0b991a..51bc88b 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -36,6 +36,8 @@
#include <linux/mount.h>
#include <linux/nfs_idmap.h>
#include <linux/vfs.h>
+#include <linux/inet.h>
+#include <linux/nfs_xdr.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -44,89 +46,17 @@
#include "callback.h"
#include "delegation.h"
#include "iostat.h"
+#include "internal.h"
#define NFSDBG_FACILITY NFSDBG_VFS
#define NFS_PARANOIA 1
-/* Maximum number of readahead requests
- * FIXME: this should really be a sysctl so that users may tune it to suit
- * their needs. People that do NFS over a slow network, might for
- * instance want to reduce it to something closer to 1 for improved
- * interactive response.
- */
-#define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1)
-
static void nfs_invalidate_inode(struct inode *);
static int nfs_update_inode(struct inode *, struct nfs_fattr *);
-static struct inode *nfs_alloc_inode(struct super_block *sb);
-static void nfs_destroy_inode(struct inode *);
-static int nfs_write_inode(struct inode *,int);
-static void nfs_delete_inode(struct inode *);
-static void nfs_clear_inode(struct inode *);
-static void nfs_umount_begin(struct super_block *);
-static int nfs_statfs(struct super_block *, struct kstatfs *);
-static int nfs_show_options(struct seq_file *, struct vfsmount *);
-static int nfs_show_stats(struct seq_file *, struct vfsmount *);
static void nfs_zap_acl_cache(struct inode *);
-static struct rpc_program nfs_program;
-
-static struct super_operations nfs_sops = {
- .alloc_inode = nfs_alloc_inode,
- .destroy_inode = nfs_destroy_inode,
- .write_inode = nfs_write_inode,
- .delete_inode = nfs_delete_inode,
- .statfs = nfs_statfs,
- .clear_inode = nfs_clear_inode,
- .umount_begin = nfs_umount_begin,
- .show_options = nfs_show_options,
- .show_stats = nfs_show_stats,
-};
-
-/*
- * RPC cruft for NFS
- */
-static struct rpc_stat nfs_rpcstat = {
- .program = &nfs_program
-};
-static struct rpc_version * nfs_version[] = {
- NULL,
- NULL,
- &nfs_version2,
-#if defined(CONFIG_NFS_V3)
- &nfs_version3,
-#elif defined(CONFIG_NFS_V4)
- NULL,
-#endif
-#if defined(CONFIG_NFS_V4)
- &nfs_version4,
-#endif
-};
-
-static struct rpc_program nfs_program = {
- .name = "nfs",
- .number = NFS_PROGRAM,
- .nrvers = ARRAY_SIZE(nfs_version),
- .version = nfs_version,
- .stats = &nfs_rpcstat,
- .pipe_dir_name = "/nfs",
-};
-
-#ifdef CONFIG_NFS_V3_ACL
-static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program };
-static struct rpc_version * nfsacl_version[] = {
- [3] = &nfsacl_version3,
-};
-
-struct rpc_program nfsacl_program = {
- .name = "nfsacl",
- .number = NFS_ACL_PROGRAM,
- .nrvers = ARRAY_SIZE(nfsacl_version),
- .version = nfsacl_version,
- .stats = &nfsacl_rpcstat,
-};
-#endif /* CONFIG_NFS_V3_ACL */
+static kmem_cache_t * nfs_inode_cachep;
static inline unsigned long
nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
@@ -134,8 +64,7 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
return nfs_fileid_to_ino_t(fattr->fileid);
}
-static int
-nfs_write_inode(struct inode *inode, int sync)
+int nfs_write_inode(struct inode *inode, int sync)
{
int flags = sync ? FLUSH_SYNC : 0;
int ret;
@@ -146,31 +75,15 @@ nfs_write_inode(struct inode *inode, int sync)
return 0;
}
-static void
-nfs_delete_inode(struct inode * inode)
+void nfs_clear_inode(struct inode *inode)
{
- dprintk("NFS: delete_inode(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
-
- truncate_inode_pages(&inode->i_data, 0);
+ struct nfs_inode *nfsi = NFS_I(inode);
+ struct rpc_cred *cred;
- nfs_wb_all(inode);
/*
* The following should never happen...
*/
- if (nfs_have_writebacks(inode)) {
- printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
- }
-
- clear_inode(inode);
-}
-
-static void
-nfs_clear_inode(struct inode *inode)
-{
- struct nfs_inode *nfsi = NFS_I(inode);
- struct rpc_cred *cred;
-
- nfs_wb_all(inode);
+ BUG_ON(nfs_have_writebacks(inode));
BUG_ON (!list_empty(&nfsi->open_files));
nfs_zap_acl_cache(inode);
cred = nfsi->cache_access.cred;
@@ -179,554 +92,6 @@ nfs_clear_inode(struct inode *inode)
BUG_ON(atomic_read(&nfsi->data_updates) != 0);
}
-void
-nfs_umount_begin(struct super_block *sb)
-{
- struct rpc_clnt *rpc = NFS_SB(sb)->client;
-
- /* -EIO all pending I/O */
- if (!IS_ERR(rpc))
- rpc_killall_tasks(rpc);
- rpc = NFS_SB(sb)->client_acl;
- if (!IS_ERR(rpc))
- rpc_killall_tasks(rpc);
-}
-
-
-static inline unsigned long
-nfs_block_bits(unsigned long bsize, unsigned char *nrbitsp)
-{
- /* make sure blocksize is a power of two */
- if ((bsize & (bsize - 1)) || nrbitsp) {
- unsigned char nrbits;
-
- for (nrbits = 31; nrbits && !(bsize & (1 << nrbits)); nrbits--)
- ;
- bsize = 1 << nrbits;
- if (nrbitsp)
- *nrbitsp = nrbits;
- }
-
- return bsize;
-}
-
-/*
- * Calculate the number of 512byte blocks used.
- */
-static inline unsigned long
-nfs_calc_block_size(u64 tsize)
-{
- loff_t used = (tsize + 511) >> 9;
- return (used > ULONG_MAX) ? ULONG_MAX : used;
-}
-
-/*
- * Compute and set NFS server blocksize
- */
-static inline unsigned long
-nfs_block_size(unsigned long bsize, unsigned char *nrbitsp)
-{
- if (bsize < NFS_MIN_FILE_IO_SIZE)
- bsize = NFS_DEF_FILE_IO_SIZE;
- else if (bsize >= NFS_MAX_FILE_IO_SIZE)
- bsize = NFS_MAX_FILE_IO_SIZE;
-
- return nfs_block_bits(bsize, nrbitsp);
-}
-
-/*
- * Obtain the root inode of the file system.
- */
-static struct inode *
-nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo)
-{
- struct nfs_server *server = NFS_SB(sb);
- int error;
-
- error = server->rpc_ops->getroot(server, rootfh, fsinfo);
- if (error < 0) {
- dprintk("nfs_get_root: getattr error = %d\n", -error);
- return ERR_PTR(error);
- }
-
- return nfs_fhget(sb, rootfh, fsinfo->fattr);
-}
-
-/*
- * Do NFS version-independent mount processing, and sanity checking
- */
-static int
-nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
-{
- struct nfs_server *server;
- struct inode *root_inode;
- struct nfs_fattr fattr;
- struct nfs_fsinfo fsinfo = {
- .fattr = &fattr,
- };
- struct nfs_pathconf pathinfo = {
- .fattr = &fattr,
- };
- int no_root_error = 0;
- unsigned long max_rpc_payload;
-
- /* We probably want something more informative here */
- snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
-
- server = NFS_SB(sb);
-
- sb->s_magic = NFS_SUPER_MAGIC;
-
- server->io_stats = nfs_alloc_iostats();
- if (server->io_stats == NULL)
- return -ENOMEM;
-
- root_inode = nfs_get_root(sb, &server->fh, &fsinfo);
- /* Did getting the root inode fail? */
- if (IS_ERR(root_inode)) {
- no_root_error = PTR_ERR(root_inode);
- goto out_no_root;
- }
- sb->s_root = d_alloc_root(root_inode);
- if (!sb->s_root) {
- no_root_error = -ENOMEM;
- goto out_no_root;
- }
- sb->s_root->d_op = server->rpc_ops->dentry_ops;
-
- /* mount time stamp, in seconds */
- server->mount_time = jiffies;
-
- /* Get some general file system info */
- if (server->namelen == 0 &&
- server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0)
- server->namelen = pathinfo.max_namelen;
- /* Work out a lot of parameters */
- if (server->rsize == 0)
- server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
- if (server->wsize == 0)
- server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
-
- if (fsinfo.rtmax >= 512 && server->rsize > fsinfo.rtmax)
- server->rsize = nfs_block_size(fsinfo.rtmax, NULL);
- if (fsinfo.wtmax >= 512 && server->wsize > fsinfo.wtmax)
- server->wsize = nfs_block_size(fsinfo.wtmax, NULL);
-
- max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL);
- if (server->rsize > max_rpc_payload)
- server->rsize = max_rpc_payload;
- if (server->rsize > NFS_MAX_FILE_IO_SIZE)
- server->rsize = NFS_MAX_FILE_IO_SIZE;
- server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-
- if (server->wsize > max_rpc_payload)
- server->wsize = max_rpc_payload;
- if (server->wsize > NFS_MAX_FILE_IO_SIZE)
- server->wsize = NFS_MAX_FILE_IO_SIZE;
- server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-
- if (sb->s_blocksize == 0)
- sb->s_blocksize = nfs_block_bits(server->wsize,
- &sb->s_blocksize_bits);
- server->wtmult = nfs_block_bits(fsinfo.wtmult, NULL);
-
- server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
- if (server->dtsize > PAGE_CACHE_SIZE)
- server->dtsize = PAGE_CACHE_SIZE;
- if (server->dtsize > server->rsize)
- server->dtsize = server->rsize;
-
- if (server->flags & NFS_MOUNT_NOAC) {
- server->acregmin = server->acregmax = 0;
- server->acdirmin = server->acdirmax = 0;
- sb->s_flags |= MS_SYNCHRONOUS;
- }
- server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD;
-
- sb->s_maxbytes = fsinfo.maxfilesize;
- if (sb->s_maxbytes > MAX_LFS_FILESIZE)
- sb->s_maxbytes = MAX_LFS_FILESIZE;
-
- server->client->cl_intr = (server->flags & NFS_MOUNT_INTR) ? 1 : 0;
- server->client->cl_softrtry = (server->flags & NFS_MOUNT_SOFT) ? 1 : 0;
-
- /* We're airborne Set socket buffersize */
- rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
- return 0;
- /* Yargs. It didn't work out. */
-out_no_root:
- dprintk("nfs_sb_init: get root inode failed: errno %d\n", -no_root_error);
- if (!IS_ERR(root_inode))
- iput(root_inode);
- return no_root_error;
-}
-
-static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, unsigned int timeo, unsigned int retrans)
-{
- to->to_initval = timeo * HZ / 10;
- to->to_retries = retrans;
- if (!to->to_retries)
- to->to_retries = 2;
-
- switch (proto) {
- case IPPROTO_TCP:
- if (!to->to_initval)
- to->to_initval = 60 * HZ;
- if (to->to_initval > NFS_MAX_TCP_TIMEOUT)
- to->to_initval = NFS_MAX_TCP_TIMEOUT;
- to->to_increment = to->to_initval;
- to->to_maxval = to->to_initval + (to->to_increment * to->to_retries);
- to->to_exponential = 0;
- break;
- case IPPROTO_UDP:
- default:
- if (!to->to_initval)
- to->to_initval = 11 * HZ / 10;
- if (to->to_initval > NFS_MAX_UDP_TIMEOUT)
- to->to_initval = NFS_MAX_UDP_TIMEOUT;
- to->to_maxval = NFS_MAX_UDP_TIMEOUT;
- to->to_exponential = 1;
- break;
- }
-}
-
-/*
- * Create an RPC client handle.
- */
-static struct rpc_clnt *
-nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data)
-{
- struct rpc_timeout timeparms;
- struct rpc_xprt *xprt = NULL;
- struct rpc_clnt *clnt = NULL;
- int proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
-
- nfs_init_timeout_values(&timeparms, proto, data->timeo, data->retrans);
-
- server->retrans_timeo = timeparms.to_initval;
- server->retrans_count = timeparms.to_retries;
-
- /* create transport and client */
- xprt = xprt_create_proto(proto, &server->addr, &timeparms);
- if (IS_ERR(xprt)) {
- dprintk("%s: cannot create RPC transport. Error = %ld\n",
- __FUNCTION__, PTR_ERR(xprt));
- return (struct rpc_clnt *)xprt;
- }
- clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
- server->rpc_ops->version, data->pseudoflavor);
- if (IS_ERR(clnt)) {
- dprintk("%s: cannot create RPC client. Error = %ld\n",
- __FUNCTION__, PTR_ERR(xprt));
- goto out_fail;
- }
-
- clnt->cl_intr = 1;
- clnt->cl_softrtry = 1;
-
- return clnt;
-
-out_fail:
- return clnt;
-}
-
-/*
- * The way this works is that the mount process passes a structure
- * in the data argument which contains the server's IP address
- * and the root file handle obtained from the server's mount
- * daemon. We stash these away in the private superblock fields.
- */
-static int
-nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent)
-{
- struct nfs_server *server;
- rpc_authflavor_t authflavor;
-
- server = NFS_SB(sb);
- sb->s_blocksize_bits = 0;
- sb->s_blocksize = 0;
- if (data->bsize)
- sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
- if (data->rsize)
- server->rsize = nfs_block_size(data->rsize, NULL);
- if (data->wsize)
- server->wsize = nfs_block_size(data->wsize, NULL);
- server->flags = data->flags & NFS_MOUNT_FLAGMASK;
-
- server->acregmin = data->acregmin*HZ;
- server->acregmax = data->acregmax*HZ;
- server->acdirmin = data->acdirmin*HZ;
- server->acdirmax = data->acdirmax*HZ;
-
- /* Start lockd here, before we might error out */
- if (!(server->flags & NFS_MOUNT_NONLM))
- lockd_up();
-
- server->namelen = data->namlen;
- server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL);
- if (!server->hostname)
- return -ENOMEM;
- strcpy(server->hostname, data->hostname);
-
- /* Check NFS protocol revision and initialize RPC op vector
- * and file handle pool. */
-#ifdef CONFIG_NFS_V3
- if (server->flags & NFS_MOUNT_VER3) {
- server->rpc_ops = &nfs_v3_clientops;
- server->caps |= NFS_CAP_READDIRPLUS;
- } else {
- server->rpc_ops = &nfs_v2_clientops;
- }
-#else
- server->rpc_ops = &nfs_v2_clientops;
-#endif
-
- /* Fill in pseudoflavor for mount version < 5 */
- if (!(data->flags & NFS_MOUNT_SECFLAVOUR))
- data->pseudoflavor = RPC_AUTH_UNIX;
- authflavor = data->pseudoflavor; /* save for sb_init() */
- /* XXX maybe we want to add a server->pseudoflavor field */
-
- /* Create RPC client handles */
- server->client = nfs_create_client(server, data);
- if (IS_ERR(server->client))
- return PTR_ERR(server->client);
- /* RFC 2623, sec 2.3.2 */
- if (authflavor != RPC_AUTH_UNIX) {
- struct rpc_auth *auth;
-
- server->client_sys = rpc_clone_client(server->client);
- if (IS_ERR(server->client_sys))
- return PTR_ERR(server->client_sys);
- auth = rpcauth_create(RPC_AUTH_UNIX, server->client_sys);
- if (IS_ERR(auth))
- return PTR_ERR(auth);
- } else {
- atomic_inc(&server->client->cl_count);
- server->client_sys = server->client;
- }
- if (server->flags & NFS_MOUNT_VER3) {
-#ifdef CONFIG_NFS_V3_ACL
- if (!(server->flags & NFS_MOUNT_NOACL)) {
- server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3);
- /* No errors! Assume that Sun nfsacls are supported */
- if (!IS_ERR(server->client_acl))
- server->caps |= NFS_CAP_ACLS;
- }
-#else
- server->flags &= ~NFS_MOUNT_NOACL;
-#endif /* CONFIG_NFS_V3_ACL */
- /*
- * The VFS shouldn't apply the umask to mode bits. We will
- * do so ourselves when necessary.
- */
- sb->s_flags |= MS_POSIXACL;
- if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
- server->namelen = NFS3_MAXNAMLEN;
- sb->s_time_gran = 1;
- } else {
- if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
- server->namelen = NFS2_MAXNAMLEN;
- }
-
- sb->s_op = &nfs_sops;
- return nfs_sb_init(sb, authflavor);
-}
-
-static int
-nfs_statfs(struct super_block *sb, struct kstatfs *buf)
-{
- struct nfs_server *server = NFS_SB(sb);
- unsigned char blockbits;
- unsigned long blockres;
- struct nfs_fh *rootfh = NFS_FH(sb->s_root->d_inode);
- struct nfs_fattr fattr;
- struct nfs_fsstat res = {
- .fattr = &fattr,
- };
- int error;
-
- lock_kernel();
-
- error = server->rpc_ops->statfs(server, rootfh, &res);
- buf->f_type = NFS_SUPER_MAGIC;
- if (error < 0)
- goto out_err;
-
- /*
- * Current versions of glibc do not correctly handle the
- * case where f_frsize != f_bsize. Eventually we want to
- * report the value of wtmult in this field.
- */
- buf->f_frsize = sb->s_blocksize;
-
- /*
- * On most *nix systems, f_blocks, f_bfree, and f_bavail
- * are reported in units of f_frsize. Linux hasn't had
- * an f_frsize field in its statfs struct until recently,
- * thus historically Linux's sys_statfs reports these
- * fields in units of f_bsize.
- */
- buf->f_bsize = sb->s_blocksize;
- blockbits = sb->s_blocksize_bits;
- blockres = (1 << blockbits) - 1;
- buf->f_blocks = (res.tbytes + blockres) >> blockbits;
- buf->f_bfree = (res.fbytes + blockres) >> blockbits;
- buf->f_bavail = (res.abytes + blockres) >> blockbits;
-
- buf->f_files = res.tfiles;
- buf->f_ffree = res.afiles;
-
- buf->f_namelen = server->namelen;
- out:
- unlock_kernel();
- return 0;
-
- out_err:
- dprintk("%s: statfs error = %d\n", __FUNCTION__, -error);
- buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1;
- goto out;
-
-}
-
-static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, int showdefaults)
-{
- static struct proc_nfs_info {
- int flag;
- char *str;
- char *nostr;
- } nfs_info[] = {
- { NFS_MOUNT_SOFT, ",soft", ",hard" },
- { NFS_MOUNT_INTR, ",intr", "" },
- { NFS_MOUNT_NOCTO, ",nocto", "" },
- { NFS_MOUNT_NOAC, ",noac", "" },
- { NFS_MOUNT_NONLM, ",nolock", "" },
- { NFS_MOUNT_NOACL, ",noacl", "" },
- { 0, NULL, NULL }
- };
- struct proc_nfs_info *nfs_infop;
- char buf[12];
- char *proto;
-
- seq_printf(m, ",vers=%d", nfss->rpc_ops->version);
- seq_printf(m, ",rsize=%d", nfss->rsize);
- seq_printf(m, ",wsize=%d", nfss->wsize);
- if (nfss->acregmin != 3*HZ || showdefaults)
- seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ);
- if (nfss->acregmax != 60*HZ || showdefaults)
- seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ);
- if (nfss->acdirmin != 30*HZ || showdefaults)
- seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ);
- if (nfss->acdirmax != 60*HZ || showdefaults)
- seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ);
- for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
- if (nfss->flags & nfs_infop->flag)
- seq_puts(m, nfs_infop->str);
- else
- seq_puts(m, nfs_infop->nostr);
- }
- switch (nfss->client->cl_xprt->prot) {
- case IPPROTO_TCP:
- proto = "tcp";
- break;
- case IPPROTO_UDP:
- proto = "udp";
- break;
- default:
- snprintf(buf, sizeof(buf), "%u", nfss->client->cl_xprt->prot);
- proto = buf;
- }
- seq_printf(m, ",proto=%s", proto);
- seq_printf(m, ",timeo=%lu", 10U * nfss->retrans_timeo / HZ);
- seq_printf(m, ",retrans=%u", nfss->retrans_count);
-}
-
-static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
-{
- struct nfs_server *nfss = NFS_SB(mnt->mnt_sb);
-
- nfs_show_mount_options(m, nfss, 0);
-
- seq_puts(m, ",addr=");
- seq_escape(m, nfss->hostname, " \t\n\\");
-
- return 0;
-}
-
-static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
-{
- int i, cpu;
- struct nfs_server *nfss = NFS_SB(mnt->mnt_sb);
- struct rpc_auth *auth = nfss->client->cl_auth;
- struct nfs_iostats totals = { };
-
- seq_printf(m, "statvers=%s", NFS_IOSTAT_VERS);
-
- /*
- * Display all mount option settings
- */
- seq_printf(m, "\n\topts:\t");
- seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? "ro" : "rw");
- seq_puts(m, mnt->mnt_sb->s_flags & MS_SYNCHRONOUS ? ",sync" : "");
- seq_puts(m, mnt->mnt_sb->s_flags & MS_NOATIME ? ",noatime" : "");
- seq_puts(m, mnt->mnt_sb->s_flags & MS_NODIRATIME ? ",nodiratime" : "");
- nfs_show_mount_options(m, nfss, 1);
-
- seq_printf(m, "\n\tage:\t%lu", (jiffies - nfss->mount_time) / HZ);
-
- seq_printf(m, "\n\tcaps:\t");
- seq_printf(m, "caps=0x%x", nfss->caps);
- seq_printf(m, ",wtmult=%d", nfss->wtmult);
- seq_printf(m, ",dtsize=%d", nfss->dtsize);
- seq_printf(m, ",bsize=%d", nfss->bsize);
- seq_printf(m, ",namelen=%d", nfss->namelen);
-
-#ifdef CONFIG_NFS_V4
- if (nfss->rpc_ops->version == 4) {
- seq_printf(m, "\n\tnfsv4:\t");
- seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]);
- seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]);
- seq_printf(m, ",acl=0x%x", nfss->acl_bitmask);
- }
-#endif
-
- /*
- * Display security flavor in effect for this mount
- */
- seq_printf(m, "\n\tsec:\tflavor=%d", auth->au_ops->au_flavor);
- if (auth->au_flavor)
- seq_printf(m, ",pseudoflavor=%d", auth->au_flavor);
-
- /*
- * Display superblock I/O counters
- */
- for_each_possible_cpu(cpu) {
- struct nfs_iostats *stats;
-
- preempt_disable();
- stats = per_cpu_ptr(nfss->io_stats, cpu);
-
- for (i = 0; i < __NFSIOS_COUNTSMAX; i++)
- totals.events[i] += stats->events[i];
- for (i = 0; i < __NFSIOS_BYTESMAX; i++)
- totals.bytes[i] += stats->bytes[i];
-
- preempt_enable();
- }
-
- seq_printf(m, "\n\tevents:\t");
- for (i = 0; i < __NFSIOS_COUNTSMAX; i++)
- seq_printf(m, "%lu ", totals.events[i]);
- seq_printf(m, "\n\tbytes:\t");
- for (i = 0; i < __NFSIOS_BYTESMAX; i++)
- seq_printf(m, "%Lu ", totals.bytes[i]);
- seq_printf(m, "\n");
-
- rpc_print_iostats(m, nfss->client);
-
- return 0;
-}
-
/**
* nfs_sync_mapping - helper to flush all mmapped dirty data to disk
*/
@@ -889,6 +254,14 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)
&& fattr->size <= NFS_LIMIT_READDIRPLUS)
set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode));
+ /* Deal with crossing mountpoints */
+ if (!nfs_fsid_equal(&NFS_SB(sb)->fsid, &fattr->fsid)) {
+ if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
+ inode->i_op = &nfs_referral_inode_operations;
+ else
+ inode->i_op = &nfs_mountpoint_inode_operations;
+ inode->i_fop = NULL;
+ }
} else if (S_ISLNK(inode->i_mode))
inode->i_op = &nfs_symlink_inode_operations;
else
@@ -1207,6 +580,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n",
inode->i_sb->s_id, (long long)NFS_FILEID(inode));
+ nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
lock_kernel();
if (!inode || is_bad_inode(inode))
goto out_nowait;
@@ -1220,7 +594,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
status = -ESTALE;
/* Do we trust the cached ESTALE? */
if (NFS_ATTRTIMEO(inode) != 0) {
- if (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ATIME)) {
+ if (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME)) {
/* no */
} else
goto out;
@@ -1251,8 +625,6 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
}
spin_unlock(&inode->i_lock);
- nfs_revalidate_mapping(inode, inode->i_mapping);
-
if (nfsi->cache_validity & NFS_INO_INVALID_ACL)
nfs_zap_acl_cache(inode);
@@ -1286,8 +658,7 @@ int nfs_attribute_timeout(struct inode *inode)
*/
int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
{
- nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
- if (!(NFS_I(inode)->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))
+ if (!(NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATTR)
&& !nfs_attribute_timeout(inode))
return NFS_STALE(inode) ? -ESTALE : 0;
return __nfs_revalidate_inode(server, inode);
@@ -1298,9 +669,16 @@ int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
* @inode - pointer to host inode
* @mapping - pointer to mapping
*/
-void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
+int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
{
struct nfs_inode *nfsi = NFS_I(inode);
+ int ret = 0;
+
+ if (NFS_STALE(inode))
+ ret = -ESTALE;
+ if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE)
+ || nfs_attribute_timeout(inode))
+ ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
if (nfsi->cache_validity & NFS_INO_INVALID_DATA) {
nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
@@ -1321,6 +699,7 @@ void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
inode->i_sb->s_id,
(long long)NFS_FILEID(inode));
}
+ return ret;
}
/**
@@ -1360,12 +739,6 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
{
struct nfs_inode *nfsi = NFS_I(inode);
- if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0
- && nfsi->change_attr == fattr->pre_change_attr) {
- nfsi->change_attr = fattr->change_attr;
- nfsi->cache_change_attribute = jiffies;
- }
-
/* If we have atomic WCC data, we may update some attributes */
if ((fattr->valid & NFS_ATTR_WCC) != 0) {
if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) {
@@ -1399,9 +772,6 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
int data_unstable;
- if ((fattr->valid & NFS_ATTR_FATTR) == 0)
- return 0;
-
/* Has the inode gone and changed behind our back? */
if (nfsi->fileid != fattr->fileid
|| (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) {
@@ -1414,20 +784,13 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
/* Do atomic weak cache consistency updates */
nfs_wcc_update_inode(inode, fattr);
- if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0) {
- if (nfsi->change_attr == fattr->change_attr)
- goto out;
- nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
- if (!data_unstable)
- nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE;
- }
+ if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
+ nfsi->change_attr != fattr->change_attr)
+ nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
/* Verify a few of the more important attributes */
- if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
- nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
- if (!data_unstable)
- nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE;
- }
+ if (!timespec_equal(&inode->i_mtime, &fattr->mtime))
+ nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
cur_size = i_size_read(inode);
new_isize = nfs_size_to_loff_t(fattr->size);
@@ -1444,7 +807,6 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
if (inode->i_nlink != fattr->nlink)
nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
-out:
if (!timespec_equal(&inode->i_atime, &fattr->atime))
nfsi->cache_validity |= NFS_INO_INVALID_ATIME;
@@ -1470,7 +832,6 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
if ((fattr->valid & NFS_ATTR_FATTR) == 0)
return 0;
spin_lock(&inode->i_lock);
- nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE;
if (time_after(fattr->time_start, nfsi->last_updated))
status = nfs_update_inode(inode, fattr);
else
@@ -1495,7 +856,7 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
spin_lock(&inode->i_lock);
if (unlikely((fattr->valid & NFS_ATTR_FATTR) == 0)) {
- nfsi->cache_validity |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS;
+ nfsi->cache_validity |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
goto out;
}
status = nfs_update_inode(inode, fattr);
@@ -1518,6 +879,7 @@ out:
*/
static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
{
+ struct nfs_server *server;
struct nfs_inode *nfsi = NFS_I(inode);
loff_t cur_isize, new_isize;
unsigned int invalid = 0;
@@ -1527,9 +889,6 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
__FUNCTION__, inode->i_sb->s_id, inode->i_ino,
atomic_read(&inode->i_count), fattr->valid);
- if ((fattr->valid & NFS_ATTR_FATTR) == 0)
- return 0;
-
if (nfsi->fileid != fattr->fileid)
goto out_fileid;
@@ -1539,6 +898,12 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
goto out_changed;
+ server = NFS_SERVER(inode);
+ /* Update the fsid if and only if this is the root directory */
+ if (inode == inode->i_sb->s_root->d_inode
+ && !nfs_fsid_equal(&server->fsid, &fattr->fsid))
+ server->fsid = fattr->fsid;
+
/*
* Update the read time so we don't revalidate too often.
*/
@@ -1548,7 +913,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
/* Are we racing with known updates of the metadata on the server? */
data_stable = nfs_verify_change_attribute(inode, fattr->time_start);
if (data_stable)
- nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME);
+ nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_ATIME);
/* Do atomic weak cache consistency updates */
nfs_wcc_update_inode(inode, fattr);
@@ -1612,15 +977,13 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
inode->i_blksize = fattr->du.nfs2.blocksize;
}
- if ((fattr->valid & NFS_ATTR_FATTR_V4)) {
- if (nfsi->change_attr != fattr->change_attr) {
- dprintk("NFS: change_attr change on server for file %s/%ld\n",
- inode->i_sb->s_id, inode->i_ino);
- nfsi->change_attr = fattr->change_attr;
- invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
- nfsi->cache_change_attribute = jiffies;
- } else
- invalid &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA);
+ if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
+ nfsi->change_attr != fattr->change_attr) {
+ dprintk("NFS: change_attr change on server for file %s/%ld\n",
+ inode->i_sb->s_id, inode->i_ino);
+ nfsi->change_attr = fattr->change_attr;
+ invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+ nfsi->cache_change_attribute = jiffies;
}
/* Update attrtimeo value if we're out of the unstable period */
@@ -1668,190 +1031,15 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
goto out_err;
}
-/*
- * File system information
- */
-
-static int nfs_set_super(struct super_block *s, void *data)
-{
- s->s_fs_info = data;
- return set_anon_super(s, data);
-}
-
-static int nfs_compare_super(struct super_block *sb, void *data)
-{
- struct nfs_server *server = data;
- struct nfs_server *old = NFS_SB(sb);
-
- if (old->addr.sin_addr.s_addr != server->addr.sin_addr.s_addr)
- return 0;
- if (old->addr.sin_port != server->addr.sin_port)
- return 0;
- return !nfs_compare_fh(&old->fh, &server->fh);
-}
-
-static struct super_block *nfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *raw_data)
-{
- int error;
- struct nfs_server *server = NULL;
- struct super_block *s;
- struct nfs_fh *root;
- struct nfs_mount_data *data = raw_data;
-
- s = ERR_PTR(-EINVAL);
- if (data == NULL) {
- dprintk("%s: missing data argument\n", __FUNCTION__);
- goto out_err;
- }
- if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) {
- dprintk("%s: bad mount version\n", __FUNCTION__);
- goto out_err;
- }
- switch (data->version) {
- case 1:
- data->namlen = 0;
- case 2:
- data->bsize = 0;
- case 3:
- if (data->flags & NFS_MOUNT_VER3) {
- dprintk("%s: mount structure version %d does not support NFSv3\n",
- __FUNCTION__,
- data->version);
- goto out_err;
- }
- data->root.size = NFS2_FHSIZE;
- memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
- case 4:
- if (data->flags & NFS_MOUNT_SECFLAVOUR) {
- dprintk("%s: mount structure version %d does not support strong security\n",
- __FUNCTION__,
- data->version);
- goto out_err;
- }
- case 5:
- memset(data->context, 0, sizeof(data->context));
- }
-#ifndef CONFIG_NFS_V3
- /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */
- s = ERR_PTR(-EPROTONOSUPPORT);
- if (data->flags & NFS_MOUNT_VER3) {
- dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__);
- goto out_err;
- }
-#endif /* CONFIG_NFS_V3 */
-
- s = ERR_PTR(-ENOMEM);
- server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
- if (!server)
- goto out_err;
- /* Zero out the NFS state stuff */
- init_nfsv4_state(server);
- server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
-
- root = &server->fh;
- if (data->flags & NFS_MOUNT_VER3)
- root->size = data->root.size;
- else
- root->size = NFS2_FHSIZE;
- s = ERR_PTR(-EINVAL);
- if (root->size > sizeof(root->data)) {
- dprintk("%s: invalid root filehandle\n", __FUNCTION__);
- goto out_err;
- }
- memcpy(root->data, data->root.data, root->size);
-
- /* We now require that the mount process passes the remote address */
- memcpy(&server->addr, &data->addr, sizeof(server->addr));
- if (server->addr.sin_addr.s_addr == INADDR_ANY) {
- dprintk("%s: mount program didn't pass remote address!\n",
- __FUNCTION__);
- goto out_err;
- }
-
- /* Fire up rpciod if not yet running */
- s = ERR_PTR(rpciod_up());
- if (IS_ERR(s)) {
- dprintk("%s: couldn't start rpciod! Error = %ld\n",
- __FUNCTION__, PTR_ERR(s));
- goto out_err;
- }
-
- s = sget(fs_type, nfs_compare_super, nfs_set_super, server);
- if (IS_ERR(s) || s->s_root)
- goto out_rpciod_down;
-
- s->s_flags = flags;
-
- error = nfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
- if (error) {
- up_write(&s->s_umount);
- deactivate_super(s);
- return ERR_PTR(error);
- }
- s->s_flags |= MS_ACTIVE;
- return s;
-out_rpciod_down:
- rpciod_down();
-out_err:
- kfree(server);
- return s;
-}
-
-static void nfs_kill_super(struct super_block *s)
-{
- struct nfs_server *server = NFS_SB(s);
-
- kill_anon_super(s);
-
- if (!IS_ERR(server->client))
- rpc_shutdown_client(server->client);
- if (!IS_ERR(server->client_sys))
- rpc_shutdown_client(server->client_sys);
- if (!IS_ERR(server->client_acl))
- rpc_shutdown_client(server->client_acl);
-
- if (!(server->flags & NFS_MOUNT_NONLM))
- lockd_down(); /* release rpc.lockd */
-
- rpciod_down(); /* release rpciod */
-
- nfs_free_iostats(server->io_stats);
- kfree(server->hostname);
- kfree(server);
-}
-
-static struct file_system_type nfs_fs_type = {
- .owner = THIS_MODULE,
- .name = "nfs",
- .get_sb = nfs_get_sb,
- .kill_sb = nfs_kill_super,
- .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
-};
#ifdef CONFIG_NFS_V4
-static void nfs4_clear_inode(struct inode *);
-
-
-static struct super_operations nfs4_sops = {
- .alloc_inode = nfs_alloc_inode,
- .destroy_inode = nfs_destroy_inode,
- .write_inode = nfs_write_inode,
- .delete_inode = nfs_delete_inode,
- .statfs = nfs_statfs,
- .clear_inode = nfs4_clear_inode,
- .umount_begin = nfs_umount_begin,
- .show_options = nfs_show_options,
- .show_stats = nfs_show_stats,
-};
-
/*
* Clean out any remaining NFSv4 state that might be left over due
* to open() calls that passed nfs_atomic_lookup, but failed to call
* nfs_open().
*/
-static void nfs4_clear_inode(struct inode *inode)
+void nfs4_clear_inode(struct inode *inode)
{
struct nfs_inode *nfsi = NFS_I(inode);
@@ -1875,357 +1063,9 @@ static void nfs4_clear_inode(struct inode *inode)
nfs4_close_state(state, state->state);
}
}
-
-
-static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, int silent)
-{
- struct nfs_server *server;
- struct nfs4_client *clp = NULL;
- struct rpc_xprt *xprt = NULL;
- struct rpc_clnt *clnt = NULL;
- struct rpc_timeout timeparms;
- rpc_authflavor_t authflavour;
- int err = -EIO;
-
- sb->s_blocksize_bits = 0;
- sb->s_blocksize = 0;
- server = NFS_SB(sb);
- if (data->rsize != 0)
- server->rsize = nfs_block_size(data->rsize, NULL);
- if (data->wsize != 0)
- server->wsize = nfs_block_size(data->wsize, NULL);
- server->flags = data->flags & NFS_MOUNT_FLAGMASK;
- server->caps = NFS_CAP_ATOMIC_OPEN;
-
- server->acregmin = data->acregmin*HZ;
- server->acregmax = data->acregmax*HZ;
- server->acdirmin = data->acdirmin*HZ;
- server->acdirmax = data->acdirmax*HZ;
-
- server->rpc_ops = &nfs_v4_clientops;
-
- nfs_init_timeout_values(&timeparms, data->proto, data->timeo, data->retrans);
-
- server->retrans_timeo = timeparms.to_initval;
- server->retrans_count = timeparms.to_retries;
-
- clp = nfs4_get_client(&server->addr.sin_addr);
- if (!clp) {
- dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__);
- return -EIO;
- }
-
- /* Now create transport and client */
- authflavour = RPC_AUTH_UNIX;
- if (data->auth_flavourlen != 0) {
- if (data->auth_flavourlen != 1) {
- dprintk("%s: Invalid number of RPC auth flavours %d.\n",
- __FUNCTION__, data->auth_flavourlen);
- err = -EINVAL;
- goto out_fail;
- }
- if (copy_from_user(&authflavour, data->auth_flavours, sizeof(authflavour))) {
- err = -EFAULT;
- goto out_fail;
- }
- }
-
- down_write(&clp->cl_sem);
- if (IS_ERR(clp->cl_rpcclient)) {
- xprt = xprt_create_proto(data->proto, &server->addr, &timeparms);
- if (IS_ERR(xprt)) {
- up_write(&clp->cl_sem);
- err = PTR_ERR(xprt);
- dprintk("%s: cannot create RPC transport. Error = %d\n",
- __FUNCTION__, err);
- goto out_fail;
- }
- clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
- server->rpc_ops->version, authflavour);
- if (IS_ERR(clnt)) {
- up_write(&clp->cl_sem);
- err = PTR_ERR(clnt);
- dprintk("%s: cannot create RPC client. Error = %d\n",
- __FUNCTION__, err);
- goto out_fail;
- }
- clnt->cl_intr = 1;
- clnt->cl_softrtry = 1;
- clp->cl_rpcclient = clnt;
- memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr));
- nfs_idmap_new(clp);
- }
- list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
- clnt = rpc_clone_client(clp->cl_rpcclient);
- if (!IS_ERR(clnt))
- server->nfs4_state = clp;
- up_write(&clp->cl_sem);
- clp = NULL;
-
- if (IS_ERR(clnt)) {
- err = PTR_ERR(clnt);
- dprintk("%s: cannot create RPC client. Error = %d\n",
- __FUNCTION__, err);
- return err;
- }
-
- server->client = clnt;
-
- if (server->nfs4_state->cl_idmap == NULL) {
- dprintk("%s: failed to create idmapper.\n", __FUNCTION__);
- return -ENOMEM;
- }
-
- if (clnt->cl_auth->au_flavor != authflavour) {
- struct rpc_auth *auth;
-
- auth = rpcauth_create(authflavour, clnt);
- if (IS_ERR(auth)) {
- dprintk("%s: couldn't create credcache!\n", __FUNCTION__);
- return PTR_ERR(auth);
- }
- }
-
- sb->s_time_gran = 1;
-
- sb->s_op = &nfs4_sops;
- err = nfs_sb_init(sb, authflavour);
- if (err == 0)
- return 0;
-out_fail:
- if (clp)
- nfs4_put_client(clp);
- return err;
-}
-
-static int nfs4_compare_super(struct super_block *sb, void *data)
-{
- struct nfs_server *server = data;
- struct nfs_server *old = NFS_SB(sb);
-
- if (strcmp(server->hostname, old->hostname) != 0)
- return 0;
- if (strcmp(server->mnt_path, old->mnt_path) != 0)
- return 0;
- return 1;
-}
-
-static void *
-nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen)
-{
- void *p = NULL;
-
- if (!src->len)
- return ERR_PTR(-EINVAL);
- if (src->len < maxlen)
- maxlen = src->len;
- if (dst == NULL) {
- p = dst = kmalloc(maxlen + 1, GFP_KERNEL);
- if (p == NULL)
- return ERR_PTR(-ENOMEM);
- }
- if (copy_from_user(dst, src->data, maxlen)) {
- kfree(p);
- return ERR_PTR(-EFAULT);
- }
- dst[maxlen] = '\0';
- return dst;
-}
-
-static struct super_block *nfs4_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *raw_data)
-{
- int error;
- struct nfs_server *server;
- struct super_block *s;
- struct nfs4_mount_data *data = raw_data;
- void *p;
-
- if (data == NULL) {
- dprintk("%s: missing data argument\n", __FUNCTION__);
- return ERR_PTR(-EINVAL);
- }
- if (data->version <= 0 || data->version > NFS4_MOUNT_VERSION) {
- dprintk("%s: bad mount version\n", __FUNCTION__);
- return ERR_PTR(-EINVAL);
- }
-
- server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
- if (!server)
- return ERR_PTR(-ENOMEM);
- /* Zero out the NFS state stuff */
- init_nfsv4_state(server);
- server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
-
- p = nfs_copy_user_string(NULL, &data->hostname, 256);
- if (IS_ERR(p))
- goto out_err;
- server->hostname = p;
-
- p = nfs_copy_user_string(NULL, &data->mnt_path, 1024);
- if (IS_ERR(p))
- goto out_err;
- server->mnt_path = p;
-
- p = nfs_copy_user_string(server->ip_addr, &data->client_addr,
- sizeof(server->ip_addr) - 1);
- if (IS_ERR(p))
- goto out_err;
-
- /* We now require that the mount process passes the remote address */
- if (data->host_addrlen != sizeof(server->addr)) {
- s = ERR_PTR(-EINVAL);
- goto out_free;
- }
- if (copy_from_user(&server->addr, data->host_addr, sizeof(server->addr))) {
- s = ERR_PTR(-EFAULT);
- goto out_free;
- }
- if (server->addr.sin_family != AF_INET ||
- server->addr.sin_addr.s_addr == INADDR_ANY) {
- dprintk("%s: mount program didn't pass remote IP address!\n",
- __FUNCTION__);
- s = ERR_PTR(-EINVAL);
- goto out_free;
- }
-
- /* Fire up rpciod if not yet running */
- s = ERR_PTR(rpciod_up());
- if (IS_ERR(s)) {
- dprintk("%s: couldn't start rpciod! Error = %ld\n",
- __FUNCTION__, PTR_ERR(s));
- goto out_free;
- }
-
- s = sget(fs_type, nfs4_compare_super, nfs_set_super, server);
-
- if (IS_ERR(s) || s->s_root)
- goto out_free;
-
- s->s_flags = flags;
-
- error = nfs4_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
- if (error) {
- up_write(&s->s_umount);
- deactivate_super(s);
- return ERR_PTR(error);
- }
- s->s_flags |= MS_ACTIVE;
- return s;
-out_err:
- s = (struct super_block *)p;
-out_free:
- kfree(server->mnt_path);
- kfree(server->hostname);
- kfree(server);
- return s;
-}
-
-static void nfs4_kill_super(struct super_block *sb)
-{
- struct nfs_server *server = NFS_SB(sb);
-
- nfs_return_all_delegations(sb);
- kill_anon_super(sb);
-
- nfs4_renewd_prepare_shutdown(server);
-
- if (server->client != NULL && !IS_ERR(server->client))
- rpc_shutdown_client(server->client);
-
- destroy_nfsv4_state(server);
-
- rpciod_down();
-
- nfs_free_iostats(server->io_stats);
- kfree(server->hostname);
- kfree(server);
-}
-
-static struct file_system_type nfs4_fs_type = {
- .owner = THIS_MODULE,
- .name = "nfs4",
- .get_sb = nfs4_get_sb,
- .kill_sb = nfs4_kill_super,
- .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
-};
-
-static const int nfs_set_port_min = 0;
-static const int nfs_set_port_max = 65535;
-static int param_set_port(const char *val, struct kernel_param *kp)
-{
- char *endp;
- int num = simple_strtol(val, &endp, 0);
- if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max)
- return -EINVAL;
- *((int *)kp->arg) = num;
- return 0;
-}
-
-module_param_call(callback_tcpport, param_set_port, param_get_int,
- &nfs_callback_set_tcpport, 0644);
-
-static int param_set_idmap_timeout(const char *val, struct kernel_param *kp)
-{
- char *endp;
- int num = simple_strtol(val, &endp, 0);
- int jif = num * HZ;
- if (endp == val || *endp || num < 0 || jif < num)
- return -EINVAL;
- *((int *)kp->arg) = jif;
- return 0;
-}
-
-module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int,
- &nfs_idmap_cache_timeout, 0644);
-
-#define nfs4_init_once(nfsi) \
- do { \
- INIT_LIST_HEAD(&(nfsi)->open_states); \
- nfsi->delegation = NULL; \
- nfsi->delegation_state = 0; \
- init_rwsem(&nfsi->rwsem); \
- } while(0)
-
-static inline int register_nfs4fs(void)
-{
- int ret;
-
- ret = nfs_register_sysctl();
- if (ret != 0)
- return ret;
- ret = register_filesystem(&nfs4_fs_type);
- if (ret != 0)
- nfs_unregister_sysctl();
- return ret;
-}
-
-static inline void unregister_nfs4fs(void)
-{
- unregister_filesystem(&nfs4_fs_type);
- nfs_unregister_sysctl();
-}
-#else
-#define nfs4_init_once(nfsi) \
- do { } while (0)
-#define register_nfs4fs() (0)
-#define unregister_nfs4fs()
#endif
-extern int nfs_init_nfspagecache(void);
-extern void nfs_destroy_nfspagecache(void);
-extern int nfs_init_readpagecache(void);
-extern void nfs_destroy_readpagecache(void);
-extern int nfs_init_writepagecache(void);
-extern void nfs_destroy_writepagecache(void);
-#ifdef CONFIG_NFS_DIRECTIO
-extern int nfs_init_directcache(void);
-extern void nfs_destroy_directcache(void);
-#endif
-
-static kmem_cache_t * nfs_inode_cachep;
-
-static struct inode *nfs_alloc_inode(struct super_block *sb)
+struct inode *nfs_alloc_inode(struct super_block *sb)
{
struct nfs_inode *nfsi;
nfsi = (struct nfs_inode *)kmem_cache_alloc(nfs_inode_cachep, SLAB_KERNEL);
@@ -2244,11 +1084,21 @@ static struct inode *nfs_alloc_inode(struct super_block *sb)
return &nfsi->vfs_inode;
}
-static void nfs_destroy_inode(struct inode *inode)
+void nfs_destroy_inode(struct inode *inode)
{
kmem_cache_free(nfs_inode_cachep, NFS_I(inode));
}
+static inline void nfs4_init_once(struct nfs_inode *nfsi)
+{
+#ifdef CONFIG_NFS_V4
+ INIT_LIST_HEAD(&nfsi->open_states);
+ nfsi->delegation = NULL;
+ nfsi->delegation_state = 0;
+ init_rwsem(&nfsi->rwsem);
+#endif
+}
+
static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
{
struct nfs_inode *nfsi = (struct nfs_inode *) foo;
@@ -2269,7 +1119,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
}
}
-static int nfs_init_inodecache(void)
+static int __init nfs_init_inodecache(void)
{
nfs_inode_cachep = kmem_cache_create("nfs_inode_cache",
sizeof(struct nfs_inode),
@@ -2282,7 +1132,7 @@ static int nfs_init_inodecache(void)
return 0;
}
-static void nfs_destroy_inodecache(void)
+static void __exit nfs_destroy_inodecache(void)
{
if (kmem_cache_destroy(nfs_inode_cachep))
printk(KERN_INFO "nfs_inode_cache: not all structures were freed\n");
@@ -2311,29 +1161,22 @@ static int __init init_nfs_fs(void)
if (err)
goto out1;
-#ifdef CONFIG_NFS_DIRECTIO
err = nfs_init_directcache();
if (err)
goto out0;
-#endif
#ifdef CONFIG_PROC_FS
rpc_proc_register(&nfs_rpcstat);
#endif
- err = register_filesystem(&nfs_fs_type);
- if (err)
- goto out;
- if ((err = register_nfs4fs()) != 0)
+ if ((err = register_nfs_fs()) != 0)
goto out;
return 0;
out:
#ifdef CONFIG_PROC_FS
rpc_proc_unregister("nfs");
#endif
-#ifdef CONFIG_NFS_DIRECTIO
nfs_destroy_directcache();
out0:
-#endif
nfs_destroy_writepagecache();
out1:
nfs_destroy_readpagecache();
@@ -2347,9 +1190,7 @@ out4:
static void __exit exit_nfs_fs(void)
{
-#ifdef CONFIG_NFS_DIRECTIO
nfs_destroy_directcache();
-#endif
nfs_destroy_writepagecache();
nfs_destroy_readpagecache();
nfs_destroy_inodecache();
@@ -2357,8 +1198,7 @@ static void __exit exit_nfs_fs(void)
#ifdef CONFIG_PROC_FS
rpc_proc_unregister("nfs");
#endif
- unregister_filesystem(&nfs_fs_type);
- unregister_nfs4fs();
+ unregister_nfs_fs();
}
/* Not quite true; I just maintain it */
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
new file mode 100644
index 0000000..bd2815e
--- /dev/null
+++ b/fs/nfs/internal.h
@@ -0,0 +1,186 @@
+/*
+ * NFS internal definitions
+ */
+
+#include <linux/mount.h>
+
+struct nfs_clone_mount {
+ const struct super_block *sb;
+ const struct dentry *dentry;
+ struct nfs_fh *fh;
+ struct nfs_fattr *fattr;
+ char *hostname;
+ char *mnt_path;
+ struct sockaddr_in *addr;
+ rpc_authflavor_t authflavor;
+};
+
+/* namespace-nfs4.c */
+#ifdef CONFIG_NFS_V4
+extern struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry);
+#else
+static inline
+struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry)
+{
+ return ERR_PTR(-ENOENT);
+}
+#endif
+
+/* callback_xdr.c */
+extern struct svc_version nfs4_callback_version1;
+
+/* pagelist.c */
+extern int __init nfs_init_nfspagecache(void);
+extern void __exit nfs_destroy_nfspagecache(void);
+extern int __init nfs_init_readpagecache(void);
+extern void __exit nfs_destroy_readpagecache(void);
+extern int __init nfs_init_writepagecache(void);
+extern void __exit nfs_destroy_writepagecache(void);
+
+#ifdef CONFIG_NFS_DIRECTIO
+extern int __init nfs_init_directcache(void);
+extern void __exit nfs_destroy_directcache(void);
+#else
+#define nfs_init_directcache() (0)
+#define nfs_destroy_directcache() do {} while(0)
+#endif
+
+/* nfs2xdr.c */
+extern struct rpc_procinfo nfs_procedures[];
+extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
+
+/* nfs3xdr.c */
+extern struct rpc_procinfo nfs3_procedures[];
+extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
+
+/* nfs4xdr.c */
+extern int nfs_stat_to_errno(int);
+extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
+
+/* nfs4proc.c */
+#ifdef CONFIG_NFS_V4
+extern struct rpc_procinfo nfs4_procedures[];
+
+extern int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry,
+ struct nfs4_fs_locations *fs_locations,
+ struct page *page);
+#endif
+
+/* inode.c */
+extern struct inode *nfs_alloc_inode(struct super_block *sb);
+extern void nfs_destroy_inode(struct inode *);
+extern int nfs_write_inode(struct inode *,int);
+extern void nfs_clear_inode(struct inode *);
+#ifdef CONFIG_NFS_V4
+extern void nfs4_clear_inode(struct inode *);
+#endif
+
+/* super.c */
+extern struct file_system_type nfs_referral_nfs4_fs_type;
+extern struct file_system_type clone_nfs_fs_type;
+#ifdef CONFIG_NFS_V4
+extern struct file_system_type clone_nfs4_fs_type;
+#endif
+#ifdef CONFIG_PROC_FS
+extern struct rpc_stat nfs_rpcstat;
+#endif
+extern int __init register_nfs_fs(void);
+extern void __exit unregister_nfs_fs(void);
+
+/* namespace.c */
+extern char *nfs_path(const char *base, const struct dentry *dentry,
+ char *buffer, ssize_t buflen);
+
+/*
+ * Determine the mount path as a string
+ */
+static inline char *
+nfs4_path(const struct dentry *dentry, char *buffer, ssize_t buflen)
+{
+#ifdef CONFIG_NFS_V4
+ return nfs_path(NFS_SB(dentry->d_sb)->mnt_path, dentry, buffer, buflen);
+#else
+ return NULL;
+#endif
+}
+
+/*
+ * Determine the device name as a string
+ */
+static inline char *nfs_devname(const struct vfsmount *mnt_parent,
+ const struct dentry *dentry,
+ char *buffer, ssize_t buflen)
+{
+ return nfs_path(mnt_parent->mnt_devname, dentry, buffer, buflen);
+}
+
+/*
+ * Determine the actual block size (and log2 thereof)
+ */
+static inline
+unsigned long nfs_block_bits(unsigned long bsize, unsigned char *nrbitsp)
+{
+ /* make sure blocksize is a power of two */
+ if ((bsize & (bsize - 1)) || nrbitsp) {
+ unsigned char nrbits;
+
+ for (nrbits = 31; nrbits && !(bsize & (1 << nrbits)); nrbits--)
+ ;
+ bsize = 1 << nrbits;
+ if (nrbitsp)
+ *nrbitsp = nrbits;
+ }
+
+ return bsize;
+}
+
+/*
+ * Calculate the number of 512byte blocks used.
+ */
+static inline unsigned long nfs_calc_block_size(u64 tsize)
+{
+ loff_t used = (tsize + 511) >> 9;
+ return (used > ULONG_MAX) ? ULONG_MAX : used;
+}
+
+/*
+ * Compute and set NFS server blocksize
+ */
+static inline
+unsigned long nfs_block_size(unsigned long bsize, unsigned char *nrbitsp)
+{
+ if (bsize < NFS_MIN_FILE_IO_SIZE)
+ bsize = NFS_DEF_FILE_IO_SIZE;
+ else if (bsize >= NFS_MAX_FILE_IO_SIZE)
+ bsize = NFS_MAX_FILE_IO_SIZE;
+
+ return nfs_block_bits(bsize, nrbitsp);
+}
+
+/*
+ * Determine the maximum file size for a superblock
+ */
+static inline
+void nfs_super_set_maxbytes(struct super_block *sb, __u64 maxfilesize)
+{
+ sb->s_maxbytes = (loff_t)maxfilesize;
+ if (sb->s_maxbytes > MAX_LFS_FILESIZE || sb->s_maxbytes <= 0)
+ sb->s_maxbytes = MAX_LFS_FILESIZE;
+}
+
+/*
+ * Check if the string represents a "valid" IPv4 address
+ */
+static inline int valid_ipaddr4(const char *buf)
+{
+ int rc, count, in[4];
+
+ rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]);
+ if (rc != 4)
+ return -EINVAL;
+ for (count = 0; count < 4; count++) {
+ if (in[count] > 255)
+ return -EINVAL;
+ }
+ return 0;
+}
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
new file mode 100644
index 0000000..19b98ca
--- /dev/null
+++ b/fs/nfs/namespace.c
@@ -0,0 +1,229 @@
+/*
+ * linux/fs/nfs/namespace.c
+ *
+ * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com>
+ *
+ * NFS namespace
+ */
+
+#include <linux/config.h>
+
+#include <linux/dcache.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/nfs_fs.h>
+#include <linux/string.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/vfs.h>
+#include "internal.h"
+
+#define NFSDBG_FACILITY NFSDBG_VFS
+
+static void nfs_expire_automounts(void *list);
+
+LIST_HEAD(nfs_automount_list);
+static DECLARE_WORK(nfs_automount_task, nfs_expire_automounts, &nfs_automount_list);
+int nfs_mountpoint_expiry_timeout = 500 * HZ;
+
+/*
+ * nfs_path - reconstruct the path given an arbitrary dentry
+ * @base - arbitrary string to prepend to the path
+ * @dentry - pointer to dentry
+ * @buffer - result buffer
+ * @buflen - length of buffer
+ *
+ * Helper function for constructing the path from the
+ * root dentry to an arbitrary hashed dentry.
+ *
+ * This is mainly for use in figuring out the path on the
+ * server side when automounting on top of an existing partition.
+ */
+char *nfs_path(const char *base, const struct dentry *dentry,
+ char *buffer, ssize_t buflen)
+{
+ char *end = buffer+buflen;
+ int namelen;
+
+ *--end = '\0';
+ buflen--;
+ spin_lock(&dcache_lock);
+ while (!IS_ROOT(dentry)) {
+ namelen = dentry->d_name.len;
+ buflen -= namelen + 1;
+ if (buflen < 0)
+ goto Elong;
+ end -= namelen;
+ memcpy(end, dentry->d_name.name, namelen);
+ *--end = '/';
+ dentry = dentry->d_parent;
+ }
+ spin_unlock(&dcache_lock);
+ namelen = strlen(base);
+ /* Strip off excess slashes in base string */
+ while (namelen > 0 && base[namelen - 1] == '/')
+ namelen--;
+ buflen -= namelen;
+ if (buflen < 0)
+ goto Elong;
+ end -= namelen;
+ memcpy(end, base, namelen);
+ return end;
+Elong:
+ return ERR_PTR(-ENAMETOOLONG);
+}
+
+/*
+ * nfs_follow_mountpoint - handle crossing a mountpoint on the server
+ * @dentry - dentry of mountpoint
+ * @nd - nameidata info
+ *
+ * When we encounter a mountpoint on the server, we want to set up
+ * a mountpoint on the client too, to prevent inode numbers from
+ * colliding, and to allow "df" to work properly.
+ * On NFSv4, we also want to allow for the fact that different
+ * filesystems may be migrated to different servers in a failover
+ * situation, and that different filesystems may want to use
+ * different security flavours.
+ */
+static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
+{
+ struct vfsmount *mnt;
+ struct nfs_server *server = NFS_SERVER(dentry->d_inode);
+ struct dentry *parent;
+ struct nfs_fh fh;
+ struct nfs_fattr fattr;
+ int err;
+
+ BUG_ON(IS_ROOT(dentry));
+ dprintk("%s: enter\n", __FUNCTION__);
+ dput(nd->dentry);
+ nd->dentry = dget(dentry);
+ if (d_mountpoint(nd->dentry))
+ goto out_follow;
+ /* Look it up again */
+ parent = dget_parent(nd->dentry);
+ err = server->rpc_ops->lookup(parent->d_inode, &nd->dentry->d_name, &fh, &fattr);
+ dput(parent);
+ if (err != 0)
+ goto out_err;
+
+ if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL)
+ mnt = nfs_do_refmount(nd->mnt, nd->dentry);
+ else
+ mnt = nfs_do_submount(nd->mnt, nd->dentry, &fh, &fattr);
+ err = PTR_ERR(mnt);
+ if (IS_ERR(mnt))
+ goto out_err;
+
+ mntget(mnt);
+ err = do_add_mount(mnt, nd, nd->mnt->mnt_flags|MNT_SHRINKABLE, &nfs_automount_list);
+ if (err < 0) {
+ mntput(mnt);
+ if (err == -EBUSY)
+ goto out_follow;
+ goto out_err;
+ }
+ mntput(nd->mnt);
+ dput(nd->dentry);
+ nd->mnt = mnt;
+ nd->dentry = dget(mnt->mnt_root);
+ schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
+out:
+ dprintk("%s: done, returned %d\n", __FUNCTION__, err);
+ return ERR_PTR(err);
+out_err:
+ path_release(nd);
+ goto out;
+out_follow:
+ while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))
+ ;
+ err = 0;
+ goto out;
+}
+
+struct inode_operations nfs_mountpoint_inode_operations = {
+ .follow_link = nfs_follow_mountpoint,
+ .getattr = nfs_getattr,
+};
+
+struct inode_operations nfs_referral_inode_operations = {
+ .follow_link = nfs_follow_mountpoint,
+};
+
+static void nfs_expire_automounts(void *data)
+{
+ struct list_head *list = (struct list_head *)data;
+
+ mark_mounts_for_expiry(list);
+ if (!list_empty(list))
+ schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
+}
+
+void nfs_release_automount_timer(void)
+{
+ if (list_empty(&nfs_automount_list)) {
+ cancel_delayed_work(&nfs_automount_task);
+ flush_scheduled_work();
+ }
+}
+
+/*
+ * Clone a mountpoint of the appropriate type
+ */
+static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, char *devname,
+ struct nfs_clone_mount *mountdata)
+{
+#ifdef CONFIG_NFS_V4
+ struct vfsmount *mnt = NULL;
+ switch (server->rpc_ops->version) {
+ case 2:
+ case 3:
+ mnt = vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata);
+ break;
+ case 4:
+ mnt = vfs_kern_mount(&clone_nfs4_fs_type, 0, devname, mountdata);
+ }
+ return mnt;
+#else
+ return vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata);
+#endif
+}
+
+/**
+ * nfs_do_submount - set up mountpoint when crossing a filesystem boundary
+ * @mnt_parent - mountpoint of parent directory
+ * @dentry - parent directory
+ * @fh - filehandle for new root dentry
+ * @fattr - attributes for new root inode
+ *
+ */
+struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
+ const struct dentry *dentry, struct nfs_fh *fh,
+ struct nfs_fattr *fattr)
+{
+ struct nfs_clone_mount mountdata = {
+ .sb = mnt_parent->mnt_sb,
+ .dentry = dentry,
+ .fh = fh,
+ .fattr = fattr,
+ };
+ struct vfsmount *mnt = ERR_PTR(-ENOMEM);
+ char *page = (char *) __get_free_page(GFP_USER);
+ char *devname;
+
+ dprintk("%s: submounting on %s/%s\n", __FUNCTION__,
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name);
+ if (page == NULL)
+ goto out;
+ devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE);
+ mnt = (struct vfsmount *)devname;
+ if (IS_ERR(devname))
+ goto free_page;
+ mnt = nfs_do_clone_mount(NFS_SB(mnt_parent->mnt_sb), devname, &mountdata);
+free_page:
+ free_page((unsigned long)page);
+out:
+ dprintk("%s: done\n", __FUNCTION__);
+ return mnt;
+}
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index f0015fa..67391ee 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -23,12 +23,11 @@
#include <linux/nfs.h>
#include <linux/nfs2.h>
#include <linux/nfs_fs.h>
+#include "internal.h"
#define NFSDBG_FACILITY NFSDBG_XDR
/* #define NFS_PARANOIA 1 */
-extern int nfs_stat_to_errno(int stat);
-
/* Mapping from NFS error code to "errno" error code. */
#define errno_NFSERR_IO EIO
@@ -131,7 +130,8 @@ xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
fattr->du.nfs2.blocksize = ntohl(*p++);
rdev = ntohl(*p++);
fattr->du.nfs2.blocks = ntohl(*p++);
- fattr->fsid_u.nfs3 = ntohl(*p++);
+ fattr->fsid.major = ntohl(*p++);
+ fattr->fsid.minor = 0;
fattr->fileid = ntohl(*p++);
p = xdr_decode_time(p, &fattr->atime);
p = xdr_decode_time(p, &fattr->mtime);
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index 3328787..7322da4 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -172,8 +172,10 @@ static void nfs3_cache_acls(struct inode *inode, struct posix_acl *acl,
inode->i_ino, acl, dfacl);
spin_lock(&inode->i_lock);
__nfs3_forget_cached_acls(NFS_I(inode));
- nfsi->acl_access = posix_acl_dup(acl);
- nfsi->acl_default = posix_acl_dup(dfacl);
+ if (!IS_ERR(acl))
+ nfsi->acl_access = posix_acl_dup(acl);
+ if (!IS_ERR(dfacl))
+ nfsi->acl_default = posix_acl_dup(dfacl);
spin_unlock(&inode->i_lock);
}
@@ -254,7 +256,9 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
res.acl_access = NULL;
}
}
- nfs3_cache_acls(inode, res.acl_access, res.acl_default);
+ nfs3_cache_acls(inode,
+ (res.mask & NFS_ACL) ? res.acl_access : ERR_PTR(-EINVAL),
+ (res.mask & NFS_DFACL) ? res.acl_default : ERR_PTR(-EINVAL));
switch(type) {
case ACL_TYPE_ACCESS:
@@ -329,6 +333,7 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
switch (status) {
case 0:
status = nfs_refresh_inode(inode, &fattr);
+ nfs3_cache_acls(inode, acl, dfacl);
break;
case -EPFNOSUPPORT:
case -EPROTONOSUPPORT:
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index cf186f0..7143b1f 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -20,11 +20,10 @@
#include <linux/nfs_mount.h>
#include "iostat.h"
+#include "internal.h"
#define NFSDBG_FACILITY NFSDBG_PROC
-extern struct rpc_procinfo nfs3_procedures[];
-
/* A wrapper to handle the EJUKEBOX error message */
static int
nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
@@ -809,8 +808,6 @@ nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
return status;
}
-extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
-
static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data)
{
if (nfs3_async_handle_jukebox(task, data->inode))
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index ec23361..0250269 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -22,14 +22,13 @@
#include <linux/nfs3.h>
#include <linux/nfs_fs.h>
#include <linux/nfsacl.h>
+#include "internal.h"
#define NFSDBG_FACILITY NFSDBG_XDR
/* Mapping from NFS error code to "errno" error code. */
#define errno_NFSERR_IO EIO
-extern int nfs_stat_to_errno(int);
-
/*
* Declare the space requirements for NFS arguments and replies as
* number of 32bit-words
@@ -166,7 +165,8 @@ xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
fattr->rdev = 0;
- p = xdr_decode_hyper(p, &fattr->fsid_u.nfs3);
+ p = xdr_decode_hyper(p, &fattr->fsid.major);
+ fattr->fsid.minor = 0;
p = xdr_decode_hyper(p, &fattr->fileid);
p = xdr_decode_time3(p, &fattr->atime);
p = xdr_decode_time3(p, &fattr->mtime);
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 0f5e4e7..9a10286 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -217,6 +217,9 @@ extern int nfs4_proc_renew(struct nfs4_client *, struct rpc_cred *);
extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state);
extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
+extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
+extern int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry,
+ struct nfs4_fs_locations *fs_locations, struct page *page);
extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops;
extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops;
@@ -225,6 +228,7 @@ extern const u32 nfs4_fattr_bitmap[2];
extern const u32 nfs4_statfs_bitmap[2];
extern const u32 nfs4_pathconf_bitmap[2];
extern const u32 nfs4_fsinfo_bitmap[2];
+extern const u32 nfs4_fs_locations_bitmap[2];
/* nfs4renewd.c */
extern void nfs4_schedule_state_renewal(struct nfs4_client *);
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
new file mode 100644
index 0000000..ea38d27
--- /dev/null
+++ b/fs/nfs/nfs4namespace.c
@@ -0,0 +1,201 @@
+/*
+ * linux/fs/nfs/nfs4namespace.c
+ *
+ * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com>
+ *
+ * NFSv4 namespace
+ */
+
+#include <linux/config.h>
+
+#include <linux/dcache.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/nfs_fs.h>
+#include <linux/string.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/vfs.h>
+#include <linux/inet.h>
+#include "internal.h"
+
+#define NFSDBG_FACILITY NFSDBG_VFS
+
+/*
+ * Check if fs_root is valid
+ */
+static inline char *nfs4_pathname_string(struct nfs4_pathname *pathname,
+ char *buffer, ssize_t buflen)
+{
+ char *end = buffer + buflen;
+ int n;
+
+ *--end = '\0';
+ buflen--;
+
+ n = pathname->ncomponents;
+ while (--n >= 0) {
+ struct nfs4_string *component = &pathname->components[n];
+ buflen -= component->len + 1;
+ if (buflen < 0)
+ goto Elong;
+ end -= component->len;
+ memcpy(end, component->data, component->len);
+ *--end = '/';
+ }
+ return end;
+Elong:
+ return ERR_PTR(-ENAMETOOLONG);
+}
+
+
+/**
+ * nfs_follow_referral - set up mountpoint when hitting a referral on moved error
+ * @mnt_parent - mountpoint of parent directory
+ * @dentry - parent directory
+ * @fspath - fs path returned in fs_locations
+ * @mntpath - mount path to new server
+ * @hostname - hostname of new server
+ * @addr - host addr of new server
+ *
+ */
+static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
+ const struct dentry *dentry,
+ struct nfs4_fs_locations *locations)
+{
+ struct vfsmount *mnt = ERR_PTR(-ENOENT);
+ struct nfs_clone_mount mountdata = {
+ .sb = mnt_parent->mnt_sb,
+ .dentry = dentry,
+ .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor,
+ };
+ char *page, *page2;
+ char *path, *fs_path;
+ char *devname;
+ int loc, s;
+
+ if (locations == NULL || locations->nlocations <= 0)
+ goto out;
+
+ dprintk("%s: referral at %s/%s\n", __FUNCTION__,
+ dentry->d_parent->d_name.name, dentry->d_name.name);
+
+ /* Ensure fs path is a prefix of current dentry path */
+ page = (char *) __get_free_page(GFP_USER);
+ if (page == NULL)
+ goto out;
+ page2 = (char *) __get_free_page(GFP_USER);
+ if (page2 == NULL)
+ goto out;
+
+ path = nfs4_path(dentry, page, PAGE_SIZE);
+ if (IS_ERR(path))
+ goto out_free;
+
+ fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE);
+ if (IS_ERR(fs_path))
+ goto out_free;
+
+ if (strncmp(path, fs_path, strlen(fs_path)) != 0) {
+ dprintk("%s: path %s does not begin with fsroot %s\n", __FUNCTION__, path, fs_path);
+ goto out_free;
+ }
+
+ devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE);
+ if (IS_ERR(devname)) {
+ mnt = (struct vfsmount *)devname;
+ goto out_free;
+ }
+
+ loc = 0;
+ while (loc < locations->nlocations && IS_ERR(mnt)) {
+ struct nfs4_fs_location *location = &locations->locations[loc];
+ char *mnt_path;
+
+ if (location == NULL || location->nservers <= 0 ||
+ location->rootpath.ncomponents == 0) {
+ loc++;
+ continue;
+ }
+
+ mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE);
+ if (IS_ERR(mnt_path)) {
+ loc++;
+ continue;
+ }
+ mountdata.mnt_path = mnt_path;
+
+ s = 0;
+ while (s < location->nservers) {
+ struct sockaddr_in addr = {};
+
+ if (location->servers[s].len <= 0 ||
+ valid_ipaddr4(location->servers[s].data) < 0) {
+ s++;
+ continue;
+ }
+
+ mountdata.hostname = location->servers[s].data;
+ addr.sin_addr.s_addr = in_aton(mountdata.hostname);
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(NFS_PORT);
+ mountdata.addr = &addr;
+
+ mnt = vfs_kern_mount(&nfs_referral_nfs4_fs_type, 0, devname, &mountdata);
+ if (!IS_ERR(mnt)) {
+ break;
+ }
+ s++;
+ }
+ loc++;
+ }
+
+out_free:
+ free_page((unsigned long)page);
+ free_page((unsigned long)page2);
+out:
+ dprintk("%s: done\n", __FUNCTION__);
+ return mnt;
+}
+
+/*
+ * nfs_do_refmount - handle crossing a referral on server
+ * @dentry - dentry of referral
+ * @nd - nameidata info
+ *
+ */
+struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry)
+{
+ struct vfsmount *mnt = ERR_PTR(-ENOENT);
+ struct dentry *parent;
+ struct nfs4_fs_locations *fs_locations = NULL;
+ struct page *page;
+ int err;
+
+ /* BUG_ON(IS_ROOT(dentry)); */
+ dprintk("%s: enter\n", __FUNCTION__);
+
+ page = alloc_page(GFP_KERNEL);
+ if (page == NULL)
+ goto out;
+
+ fs_locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
+ if (fs_locations == NULL)
+ goto out_free;
+
+ /* Get locations */
+ parent = dget_parent(dentry);
+ dprintk("%s: getting locations for %s/%s\n", __FUNCTION__, parent->d_name.name, dentry->d_name.name);
+ err = nfs4_proc_fs_locations(parent->d_inode, dentry, fs_locations, page);
+ dput(parent);
+ if (err != 0 || fs_locations->nlocations <= 0 ||
+ fs_locations->fs_path.ncomponents <= 0)
+ goto out_free;
+
+ mnt = nfs_follow_referral(mnt_parent, dentry, fs_locations);
+out_free:
+ __free_page(page);
+ kfree(fs_locations);
+out:
+ dprintk("%s: done\n", __FUNCTION__);
+ return mnt;
+}
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index d86c0db..b4916b0 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -65,8 +65,6 @@ static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *)
static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry);
static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception);
static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp);
-extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
-extern struct rpc_procinfo nfs4_procedures[];
/* Prevent leaks of NFSv4 errors into userland */
int nfs4_map_errors(int err)
@@ -121,6 +119,25 @@ const u32 nfs4_fsinfo_bitmap[2] = { FATTR4_WORD0_MAXFILESIZE
0
};
+const u32 nfs4_fs_locations_bitmap[2] = {
+ FATTR4_WORD0_TYPE
+ | FATTR4_WORD0_CHANGE
+ | FATTR4_WORD0_SIZE
+ | FATTR4_WORD0_FSID
+ | FATTR4_WORD0_FILEID
+ | FATTR4_WORD0_FS_LOCATIONS,
+ FATTR4_WORD1_MODE
+ | FATTR4_WORD1_NUMLINKS
+ | FATTR4_WORD1_OWNER
+ | FATTR4_WORD1_OWNER_GROUP
+ | FATTR4_WORD1_RAWDEV
+ | FATTR4_WORD1_SPACE_USED
+ | FATTR4_WORD1_TIME_ACCESS
+ | FATTR4_WORD1_TIME_METADATA
+ | FATTR4_WORD1_TIME_MODIFY
+ | FATTR4_WORD1_MOUNTED_ON_FILEID
+};
+
static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry,
struct nfs4_readdir_arg *readdir)
{
@@ -185,15 +202,15 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp
spin_unlock(&clp->cl_lock);
}
-static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinfo)
+static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
{
- struct nfs_inode *nfsi = NFS_I(inode);
+ struct nfs_inode *nfsi = NFS_I(dir);
- spin_lock(&inode->i_lock);
- nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
+ spin_lock(&dir->i_lock);
+ nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA;
if (cinfo->before == nfsi->change_attr && cinfo->atomic)
nfsi->change_attr = cinfo->after;
- spin_unlock(&inode->i_lock);
+ spin_unlock(&dir->i_lock);
}
struct nfs4_opendata {
@@ -1331,7 +1348,7 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
return status;
}
-static int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
+int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
{
struct nfs4_exception exception = { };
int err;
@@ -1443,6 +1460,50 @@ out:
return nfs4_map_errors(status);
}
+/*
+ * Get locations and (maybe) other attributes of a referral.
+ * Note that we'll actually follow the referral later when
+ * we detect fsid mismatch in inode revalidation
+ */
+static int nfs4_get_referral(struct inode *dir, struct qstr *name, struct nfs_fattr *fattr, struct nfs_fh *fhandle)
+{
+ int status = -ENOMEM;
+ struct page *page = NULL;
+ struct nfs4_fs_locations *locations = NULL;
+ struct dentry dentry = {};
+
+ page = alloc_page(GFP_KERNEL);
+ if (page == NULL)
+ goto out;
+ locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
+ if (locations == NULL)
+ goto out;
+
+ dentry.d_name.name = name->name;
+ dentry.d_name.len = name->len;
+ status = nfs4_proc_fs_locations(dir, &dentry, locations, page);
+ if (status != 0)
+ goto out;
+ /* Make sure server returned a different fsid for the referral */
+ if (nfs_fsid_equal(&NFS_SERVER(dir)->fsid, &locations->fattr.fsid)) {
+ dprintk("%s: server did not return a different fsid for a referral at %s\n", __FUNCTION__, name->name);
+ status = -EIO;
+ goto out;
+ }
+
+ memcpy(fattr, &locations->fattr, sizeof(struct nfs_fattr));
+ fattr->valid |= NFS_ATTR_FATTR_V4_REFERRAL;
+ if (!fattr->mode)
+ fattr->mode = S_IFDIR;
+ memset(fhandle, 0, sizeof(struct nfs_fh));
+out:
+ if (page)
+ __free_page(page);
+ if (locations)
+ kfree(locations);
+ return status;
+}
+
static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
struct nfs4_getattr_arg args = {
@@ -1547,6 +1608,8 @@ static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name,
dprintk("NFS call lookup %s\n", name->name);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+ if (status == -NFS4ERR_MOVED)
+ status = nfs4_get_referral(dir, name, fattr, fhandle);
dprintk("NFS reply lookup: %d\n", status);
return status;
}
@@ -2008,7 +2071,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
if (!status) {
update_changeattr(dir, &res.cinfo);
nfs_post_op_update_inode(dir, res.dir_attr);
- nfs_refresh_inode(inode, res.fattr);
+ nfs_post_op_update_inode(inode, res.fattr);
}
return status;
@@ -3570,6 +3633,36 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen)
return len;
}
+int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry,
+ struct nfs4_fs_locations *fs_locations, struct page *page)
+{
+ struct nfs_server *server = NFS_SERVER(dir);
+ u32 bitmask[2] = {
+ [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
+ [1] = FATTR4_WORD1_MOUNTED_ON_FILEID,
+ };
+ struct nfs4_fs_locations_arg args = {
+ .dir_fh = NFS_FH(dir),
+ .name = &dentry->d_name,
+ .page = page,
+ .bitmask = bitmask,
+ };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS],
+ .rpc_argp = &args,
+ .rpc_resp = fs_locations,
+ };
+ int status;
+
+ dprintk("%s: start\n", __FUNCTION__);
+ fs_locations->fattr.valid = 0;
+ fs_locations->server = server;
+ fs_locations->nlocations = 0;
+ status = rpc_call_sync(server->client, &msg, 0);
+ dprintk("%s: returned status = %d\n", __FUNCTION__, status);
+ return status;
+}
+
struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = {
.recover_open = nfs4_open_reclaim,
.recover_lock = nfs4_lock_reclaim,
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 7c5d70e..1750d99 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -411,6 +411,15 @@ static int nfs_stat_to_errno(int);
#define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
+#define NFS4_enc_fs_locations_sz \
+ (compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ encode_getattr_maxsz)
+#define NFS4_dec_fs_locations_sz \
+ (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ op_decode_hdr_maxsz + \
+ nfs4_fattr_bitmap_maxsz)
static struct {
unsigned int mode;
@@ -722,6 +731,13 @@ static int encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask)
bitmask[1] & nfs4_fsinfo_bitmap[1]);
}
+static int encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask)
+{
+ return encode_getattr_two(xdr,
+ bitmask[0] & nfs4_fs_locations_bitmap[0],
+ bitmask[1] & nfs4_fs_locations_bitmap[1]);
+}
+
static int encode_getfh(struct xdr_stream *xdr)
{
uint32_t *p;
@@ -2003,6 +2019,38 @@ out:
}
/*
+ * Encode FS_LOCATIONS request
+ */
+static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs_locations_arg *args)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+ .nops = 3,
+ };
+ struct rpc_auth *auth = req->rq_task->tk_auth;
+ int replen;
+ int status;
+
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+ encode_compound_hdr(&xdr, &hdr);
+ if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
+ goto out;
+ if ((status = encode_lookup(&xdr, args->name)) != 0)
+ goto out;
+ if ((status = encode_fs_locations(&xdr, args->bitmask)) != 0)
+ goto out;
+ /* set up reply
+ * toplevel_status + OP_PUTFH + status
+ * + OP_LOOKUP + status + OP_GETATTR + status = 7
+ */
+ replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2;
+ xdr_inline_pages(&req->rq_rcv_buf, replen, &args->page,
+ 0, PAGE_SIZE);
+out:
+ return status;
+}
+
+/*
* START OF "GENERIC" DECODE ROUTINES.
* These may look a little ugly since they are imported from a "generic"
* set of XDR encode/decode routines which are intended to be shared by
@@ -2036,7 +2084,7 @@ out:
} \
} while (0)
-static int decode_opaque_inline(struct xdr_stream *xdr, uint32_t *len, char **string)
+static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string)
{
uint32_t *p;
@@ -2087,7 +2135,7 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs4_client *clp)
{
uint32_t *p;
- uint32_t strlen;
+ unsigned int strlen;
char *str;
READ_BUF(12);
@@ -2217,7 +2265,7 @@ static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap,
return 0;
}
-static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fsid *fsid)
+static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid)
{
uint32_t *p;
@@ -2285,6 +2333,22 @@ static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t
return 0;
}
+static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
+{
+ uint32_t *p;
+
+ *fileid = 0;
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_MOUNTED_ON_FILEID - 1U)))
+ return -EIO;
+ if (likely(bitmap[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) {
+ READ_BUF(8);
+ READ64(*fileid);
+ bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
+ }
+ dprintk("%s: fileid=%Lu\n", __FUNCTION__, (unsigned long long)*fileid);
+ return 0;
+}
+
static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
uint32_t *p;
@@ -2336,6 +2400,116 @@ static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uin
return status;
}
+static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
+{
+ int n;
+ uint32_t *p;
+ int status = 0;
+
+ READ_BUF(4);
+ READ32(n);
+ if (n < 0)
+ goto out_eio;
+ if (n == 0)
+ goto root_path;
+ dprintk("path ");
+ path->ncomponents = 0;
+ while (path->ncomponents < n) {
+ struct nfs4_string *component = &path->components[path->ncomponents];
+ status = decode_opaque_inline(xdr, &component->len, &component->data);
+ if (unlikely(status != 0))
+ goto out_eio;
+ if (path->ncomponents != n)
+ dprintk("/");
+ dprintk("%s", component->data);
+ if (path->ncomponents < NFS4_PATHNAME_MAXCOMPONENTS)
+ path->ncomponents++;
+ else {
+ dprintk("cannot parse %d components in path\n", n);
+ goto out_eio;
+ }
+ }
+out:
+ dprintk("\n");
+ return status;
+root_path:
+/* a root pathname is sent as a zero component4 */
+ path->ncomponents = 1;
+ path->components[0].len=0;
+ path->components[0].data=NULL;
+ dprintk("path /\n");
+ goto out;
+out_eio:
+ dprintk(" status %d", status);
+ status = -EIO;
+ goto out;
+}
+
+static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fs_locations *res)
+{
+ int n;
+ uint32_t *p;
+ int status = -EIO;
+
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_FS_LOCATIONS -1U)))
+ goto out;
+ status = 0;
+ if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS)))
+ goto out;
+ dprintk("%s: fsroot ", __FUNCTION__);
+ status = decode_pathname(xdr, &res->fs_path);
+ if (unlikely(status != 0))
+ goto out;
+ READ_BUF(4);
+ READ32(n);
+ if (n <= 0)
+ goto out_eio;
+ res->nlocations = 0;
+ while (res->nlocations < n) {
+ int m;
+ struct nfs4_fs_location *loc = &res->locations[res->nlocations];
+
+ READ_BUF(4);
+ READ32(m);
+ if (m <= 0)
+ goto out_eio;
+
+ loc->nservers = 0;
+ dprintk("%s: servers ", __FUNCTION__);
+ while (loc->nservers < m) {
+ struct nfs4_string *server = &loc->servers[loc->nservers];
+ status = decode_opaque_inline(xdr, &server->len, &server->data);
+ if (unlikely(status != 0))
+ goto out_eio;
+ dprintk("%s ", server->data);
+ if (loc->nservers < NFS4_FS_LOCATION_MAXSERVERS)
+ loc->nservers++;
+ else {
+ int i;
+ dprintk("%s: using first %d of %d servers returned for location %d\n", __FUNCTION__, NFS4_FS_LOCATION_MAXSERVERS, m, res->nlocations);
+ for (i = loc->nservers; i < m; i++) {
+ int len;
+ char *data;
+ status = decode_opaque_inline(xdr, &len, &data);
+ if (unlikely(status != 0))
+ goto out_eio;
+ }
+ }
+ }
+ status = decode_pathname(xdr, &loc->rootpath);
+ if (unlikely(status != 0))
+ goto out_eio;
+ if (res->nlocations < NFS4_FS_LOCATIONS_MAXENTRIES)
+ res->nlocations++;
+ }
+out:
+ dprintk("%s: fs_locations done, error = %d\n", __FUNCTION__, status);
+ return status;
+out_eio:
+ status = -EIO;
+ goto out;
+}
+
static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
uint32_t *p;
@@ -2841,6 +3015,7 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
bitmap[2] = {0},
type;
int status, fmode = 0;
+ uint64_t fileid;
if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
goto xdr_error;
@@ -2863,10 +3038,14 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
goto xdr_error;
if ((status = decode_attr_size(xdr, bitmap, &fattr->size)) != 0)
goto xdr_error;
- if ((status = decode_attr_fsid(xdr, bitmap, &fattr->fsid_u.nfs4)) != 0)
+ if ((status = decode_attr_fsid(xdr, bitmap, &fattr->fsid)) != 0)
goto xdr_error;
if ((status = decode_attr_fileid(xdr, bitmap, &fattr->fileid)) != 0)
goto xdr_error;
+ if ((status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
+ struct nfs4_fs_locations,
+ fattr))) != 0)
+ goto xdr_error;
if ((status = decode_attr_mode(xdr, bitmap, &fattr->mode)) != 0)
goto xdr_error;
fattr->mode |= fmode;
@@ -2886,6 +3065,10 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
goto xdr_error;
if ((status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime)) != 0)
goto xdr_error;
+ if ((status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid)) != 0)
+ goto xdr_error;
+ if (fattr->fileid == 0 && fileid != 0)
+ fattr->fileid = fileid;
if ((status = verify_attr_len(xdr, savep, attrlen)) == 0)
fattr->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
xdr_error:
@@ -3350,8 +3533,7 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
attrlen, recvd);
return -EINVAL;
}
- if (attrlen <= *acl_len)
- xdr_read_pages(xdr, attrlen);
+ xdr_read_pages(xdr, attrlen);
*acl_len = attrlen;
} else
status = -EOPNOTSUPP;
@@ -4211,6 +4393,29 @@ out:
return status;
}
+/*
+ * FS_LOCATIONS request
+ */
+static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs_locations *res)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
+ status = decode_compound_hdr(&xdr, &hdr);
+ if (status != 0)
+ goto out;
+ if ((status = decode_putfh(&xdr)) != 0)
+ goto out;
+ if ((status = decode_lookup(&xdr)) != 0)
+ goto out;
+ xdr_enter_page(&xdr, PAGE_SIZE);
+ status = decode_getfattr(&xdr, &res->fattr, res->server);
+out:
+ return status;
+}
+
uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus)
{
uint32_t bitmap[2] = {0};
@@ -4382,6 +4587,7 @@ struct rpc_procinfo nfs4_procedures[] = {
PROC(DELEGRETURN, enc_delegreturn, dec_delegreturn),
PROC(GETACL, enc_getacl, dec_getacl),
PROC(SETACL, enc_setacl, dec_setacl),
+ PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations),
};
struct rpc_version nfs_version4 = {
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 106aca3..ef94296 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -325,6 +325,7 @@ out:
/**
* nfs_scan_list - Scan a list for matching requests
+ * @nfsi: NFS inode
* @head: One of the NFS inode request lists
* @dst: Destination list
* @idx_start: lower bound of page->index to scan
@@ -336,14 +337,15 @@ out:
* The requests are *not* checked to ensure that they form a contiguous set.
* You must be holding the inode's req_lock when calling this function
*/
-int
-nfs_scan_list(struct list_head *head, struct list_head *dst,
- unsigned long idx_start, unsigned int npages)
+int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head,
+ struct list_head *dst, unsigned long idx_start,
+ unsigned int npages)
{
- struct list_head *pos, *tmp;
- struct nfs_page *req;
- unsigned long idx_end;
- int res;
+ struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES];
+ struct nfs_page *req;
+ unsigned long idx_end;
+ int found, i;
+ int res;
res = 0;
if (npages == 0)
@@ -351,25 +353,32 @@ nfs_scan_list(struct list_head *head, struct list_head *dst,
else
idx_end = idx_start + npages - 1;
- list_for_each_safe(pos, tmp, head) {
-
- req = nfs_list_entry(pos);
-
- if (req->wb_index < idx_start)
- continue;
- if (req->wb_index > idx_end)
+ for (;;) {
+ found = radix_tree_gang_lookup(&nfsi->nfs_page_tree,
+ (void **)&pgvec[0], idx_start,
+ NFS_SCAN_MAXENTRIES);
+ if (found <= 0)
break;
+ for (i = 0; i < found; i++) {
+ req = pgvec[i];
+ if (req->wb_index > idx_end)
+ goto out;
+ idx_start = req->wb_index + 1;
+ if (req->wb_list_head != head)
+ continue;
+ if (nfs_set_page_writeback_locked(req)) {
+ nfs_list_remove_request(req);
+ nfs_list_add_request(req, dst);
+ res++;
+ }
+ }
- if (!nfs_set_page_writeback_locked(req))
- continue;
- nfs_list_remove_request(req);
- nfs_list_add_request(req, dst);
- res++;
}
+out:
return res;
}
-int nfs_init_nfspagecache(void)
+int __init nfs_init_nfspagecache(void)
{
nfs_page_cachep = kmem_cache_create("nfs_page",
sizeof(struct nfs_page),
@@ -381,7 +390,7 @@ int nfs_init_nfspagecache(void)
return 0;
}
-void nfs_destroy_nfspagecache(void)
+void __exit nfs_destroy_nfspagecache(void)
{
if (kmem_cache_destroy(nfs_page_cachep))
printk(KERN_INFO "nfs_page: not all structures were freed\n");
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 9dd85ca..b3899ea 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -44,11 +44,10 @@
#include <linux/nfs_page.h>
#include <linux/lockd/bind.h>
#include <linux/smp_lock.h>
+#include "internal.h"
#define NFSDBG_FACILITY NFSDBG_PROC
-extern struct rpc_procinfo nfs_procedures[];
-
/*
* Bare-bones access to getattr: this is for nfs_read_super.
*/
@@ -611,8 +610,6 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
return 0;
}
-extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
-
static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data)
{
if (task->tk_status >= 0) {
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 624ca71..41c2ffe 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -51,14 +51,11 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount)
if (p) {
memset(p, 0, sizeof(*p));
INIT_LIST_HEAD(&p->pages);
- if (pagecount < NFS_PAGEVEC_SIZE)
- p->pagevec = &p->page_array[0];
+ if (pagecount <= ARRAY_SIZE(p->page_array))
+ p->pagevec = p->page_array;
else {
- size_t size = ++pagecount * sizeof(struct page *);
- p->pagevec = kmalloc(size, GFP_NOFS);
- if (p->pagevec) {
- memset(p->pagevec, 0, size);
- } else {
+ p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS);
+ if (!p->pagevec) {
mempool_free(p, nfs_rdata_mempool);
p = NULL;
}
@@ -104,6 +101,28 @@ int nfs_return_empty_page(struct page *page)
return 0;
}
+static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data)
+{
+ unsigned int remainder = data->args.count - data->res.count;
+ unsigned int base = data->args.pgbase + data->res.count;
+ unsigned int pglen;
+ struct page **pages;
+
+ if (data->res.eof == 0 || remainder == 0)
+ return;
+ /*
+ * Note: "remainder" can never be negative, since we check for
+ * this in the XDR code.
+ */
+ pages = &data->args.pages[base >> PAGE_CACHE_SHIFT];
+ base &= ~PAGE_CACHE_MASK;
+ pglen = PAGE_CACHE_SIZE - base;
+ if (pglen < remainder)
+ memclear_highpage_flush(*pages, base, pglen);
+ else
+ memclear_highpage_flush(*pages, base, remainder);
+}
+
/*
* Read a page synchronously.
*/
@@ -177,11 +196,9 @@ static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode,
NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME;
spin_unlock(&inode->i_lock);
- if (count)
- memclear_highpage_flush(page, rdata->args.pgbase, count);
- SetPageUptodate(page);
- if (PageError(page))
- ClearPageError(page);
+ nfs_readpage_truncate_uninitialised_page(rdata);
+ if (rdata->res.eof || rdata->res.count == rdata->args.count)
+ SetPageUptodate(page);
result = 0;
io_error:
@@ -436,20 +453,12 @@ static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata)
struct nfs_page *req = data->req;
struct page *page = req->wb_page;
+ if (likely(task->tk_status >= 0))
+ nfs_readpage_truncate_uninitialised_page(data);
+ else
+ SetPageError(page);
if (nfs_readpage_result(task, data) != 0)
return;
- if (task->tk_status >= 0) {
- unsigned int request = data->args.count;
- unsigned int result = data->res.count;
-
- if (result < request) {
- memclear_highpage_flush(page,
- data->args.pgbase + result,
- request - result);
- }
- } else
- SetPageError(page);
-
if (atomic_dec_and_test(&req->wb_complete)) {
if (!PageError(page))
SetPageUptodate(page);
@@ -462,6 +471,40 @@ static const struct rpc_call_ops nfs_read_partial_ops = {
.rpc_release = nfs_readdata_release,
};
+static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data)
+{
+ unsigned int count = data->res.count;
+ unsigned int base = data->args.pgbase;
+ struct page **pages;
+
+ if (unlikely(count == 0))
+ return;
+ pages = &data->args.pages[base >> PAGE_CACHE_SHIFT];
+ base &= ~PAGE_CACHE_MASK;
+ count += base;
+ for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++)
+ SetPageUptodate(*pages);
+ /*
+ * Was this an eof or a short read? If the latter, don't mark the page
+ * as uptodate yet.
+ */
+ if (count > 0 && (data->res.eof || data->args.count == data->res.count))
+ SetPageUptodate(*pages);
+}
+
+static void nfs_readpage_set_pages_error(struct nfs_read_data *data)
+{
+ unsigned int count = data->args.count;
+ unsigned int base = data->args.pgbase;
+ struct page **pages;
+
+ pages = &data->args.pages[base >> PAGE_CACHE_SHIFT];
+ base &= ~PAGE_CACHE_MASK;
+ count += base;
+ for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++)
+ SetPageError(*pages);
+}
+
/*
* This is the callback from RPC telling us whether a reply was
* received or some error occurred (timeout or socket shutdown).
@@ -469,27 +512,24 @@ static const struct rpc_call_ops nfs_read_partial_ops = {
static void nfs_readpage_result_full(struct rpc_task *task, void *calldata)
{
struct nfs_read_data *data = calldata;
- unsigned int count = data->res.count;
+ /*
+ * Note: nfs_readpage_result may change the values of
+ * data->args. In the multi-page case, we therefore need
+ * to ensure that we call the next nfs_readpage_set_page_uptodate()
+ * first in the multi-page case.
+ */
+ if (likely(task->tk_status >= 0)) {
+ nfs_readpage_truncate_uninitialised_page(data);
+ nfs_readpage_set_pages_uptodate(data);
+ } else
+ nfs_readpage_set_pages_error(data);
if (nfs_readpage_result(task, data) != 0)
return;
while (!list_empty(&data->pages)) {
struct nfs_page *req = nfs_list_entry(data->pages.next);
- struct page *page = req->wb_page;
- nfs_list_remove_request(req);
- if (task->tk_status >= 0) {
- if (count < PAGE_CACHE_SIZE) {
- if (count < req->wb_bytes)
- memclear_highpage_flush(page,
- req->wb_pgbase + count,
- req->wb_bytes - count);
- count = 0;
- } else
- count -= PAGE_CACHE_SIZE;
- SetPageUptodate(page);
- } else
- SetPageError(page);
+ nfs_list_remove_request(req);
nfs_readpage_release(req);
}
}
@@ -654,7 +694,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
return ret;
}
-int nfs_init_readpagecache(void)
+int __init nfs_init_readpagecache(void)
{
nfs_rdata_cachep = kmem_cache_create("nfs_read_data",
sizeof(struct nfs_read_data),
@@ -671,7 +711,7 @@ int nfs_init_readpagecache(void)
return 0;
}
-void nfs_destroy_readpagecache(void)
+void __exit nfs_destroy_readpagecache(void)
{
mempool_destroy(nfs_rdata_mempool);
if (kmem_cache_destroy(nfs_rdata_cachep))
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
new file mode 100644
index 0000000..e8a9bee
--- /dev/null
+++ b/fs/nfs/super.c
@@ -0,0 +1,1537 @@
+/*
+ * linux/fs/nfs/super.c
+ *
+ * Copyright (C) 1992 Rick Sladkey
+ *
+ * nfs superblock handling functions
+ *
+ * Modularised by Alan Cox <Alan.Cox@linux.org>, while hacking some
+ * experimental NFS changes. Modularisation taken straight from SYS5 fs.
+ *
+ * Change to nfs_read_super() to permit NFS mounts to multi-homed hosts.
+ * J.S.Peatfield@damtp.cam.ac.uk
+ *
+ * Split from inode.c by David Howells <dhowells@redhat.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/time.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/stats.h>
+#include <linux/sunrpc/metrics.h>
+#include <linux/nfs_fs.h>
+#include <linux/nfs_mount.h>
+#include <linux/nfs4_mount.h>
+#include <linux/lockd/bind.h>
+#include <linux/smp_lock.h>
+#include <linux/seq_file.h>
+#include <linux/mount.h>
+#include <linux/nfs_idmap.h>
+#include <linux/vfs.h>
+#include <linux/inet.h>
+#include <linux/nfs_xdr.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include "nfs4_fs.h"
+#include "callback.h"
+#include "delegation.h"
+#include "iostat.h"
+#include "internal.h"
+
+#define NFSDBG_FACILITY NFSDBG_VFS
+
+/* Maximum number of readahead requests
+ * FIXME: this should really be a sysctl so that users may tune it to suit
+ * their needs. People that do NFS over a slow network, might for
+ * instance want to reduce it to something closer to 1 for improved
+ * interactive response.
+ */
+#define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1)
+
+/*
+ * RPC cruft for NFS
+ */
+static struct rpc_version * nfs_version[] = {
+ NULL,
+ NULL,
+ &nfs_version2,
+#if defined(CONFIG_NFS_V3)
+ &nfs_version3,
+#elif defined(CONFIG_NFS_V4)
+ NULL,
+#endif
+#if defined(CONFIG_NFS_V4)
+ &nfs_version4,
+#endif
+};
+
+static struct rpc_program nfs_program = {
+ .name = "nfs",
+ .number = NFS_PROGRAM,
+ .nrvers = ARRAY_SIZE(nfs_version),
+ .version = nfs_version,
+ .stats = &nfs_rpcstat,
+ .pipe_dir_name = "/nfs",
+};
+
+struct rpc_stat nfs_rpcstat = {
+ .program = &nfs_program
+};
+
+
+#ifdef CONFIG_NFS_V3_ACL
+static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program };
+static struct rpc_version * nfsacl_version[] = {
+ [3] = &nfsacl_version3,
+};
+
+struct rpc_program nfsacl_program = {
+ .name = "nfsacl",
+ .number = NFS_ACL_PROGRAM,
+ .nrvers = ARRAY_SIZE(nfsacl_version),
+ .version = nfsacl_version,
+ .stats = &nfsacl_rpcstat,
+};
+#endif /* CONFIG_NFS_V3_ACL */
+
+static void nfs_umount_begin(struct vfsmount *, int);
+static int nfs_statfs(struct dentry *, struct kstatfs *);
+static int nfs_show_options(struct seq_file *, struct vfsmount *);
+static int nfs_show_stats(struct seq_file *, struct vfsmount *);
+static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *);
+static int nfs_clone_nfs_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
+static void nfs_kill_super(struct super_block *);
+
+static struct file_system_type nfs_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "nfs",
+ .get_sb = nfs_get_sb,
+ .kill_sb = nfs_kill_super,
+ .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+};
+
+struct file_system_type clone_nfs_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "nfs",
+ .get_sb = nfs_clone_nfs_sb,
+ .kill_sb = nfs_kill_super,
+ .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+};
+
+static struct super_operations nfs_sops = {
+ .alloc_inode = nfs_alloc_inode,
+ .destroy_inode = nfs_destroy_inode,
+ .write_inode = nfs_write_inode,
+ .statfs = nfs_statfs,
+ .clear_inode = nfs_clear_inode,
+ .umount_begin = nfs_umount_begin,
+ .show_options = nfs_show_options,
+ .show_stats = nfs_show_stats,
+};
+
+#ifdef CONFIG_NFS_V4
+static int nfs4_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
+static int nfs_clone_nfs4_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
+static int nfs_referral_nfs4_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
+static void nfs4_kill_super(struct super_block *sb);
+
+static struct file_system_type nfs4_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "nfs4",
+ .get_sb = nfs4_get_sb,
+ .kill_sb = nfs4_kill_super,
+ .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+};
+
+struct file_system_type clone_nfs4_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "nfs4",
+ .get_sb = nfs_clone_nfs4_sb,
+ .kill_sb = nfs4_kill_super,
+ .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+};
+
+struct file_system_type nfs_referral_nfs4_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "nfs4",
+ .get_sb = nfs_referral_nfs4_sb,
+ .kill_sb = nfs4_kill_super,
+ .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+};
+
+static struct super_operations nfs4_sops = {
+ .alloc_inode = nfs_alloc_inode,
+ .destroy_inode = nfs_destroy_inode,
+ .write_inode = nfs_write_inode,
+ .statfs = nfs_statfs,
+ .clear_inode = nfs4_clear_inode,
+ .umount_begin = nfs_umount_begin,
+ .show_options = nfs_show_options,
+ .show_stats = nfs_show_stats,
+};
+#endif
+
+#ifdef CONFIG_NFS_V4
+static const int nfs_set_port_min = 0;
+static const int nfs_set_port_max = 65535;
+
+static int param_set_port(const char *val, struct kernel_param *kp)
+{
+ char *endp;
+ int num = simple_strtol(val, &endp, 0);
+ if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max)
+ return -EINVAL;
+ *((int *)kp->arg) = num;
+ return 0;
+}
+
+module_param_call(callback_tcpport, param_set_port, param_get_int,
+ &nfs_callback_set_tcpport, 0644);
+#endif
+
+#ifdef CONFIG_NFS_V4
+static int param_set_idmap_timeout(const char *val, struct kernel_param *kp)
+{
+ char *endp;
+ int num = simple_strtol(val, &endp, 0);
+ int jif = num * HZ;
+ if (endp == val || *endp || num < 0 || jif < num)
+ return -EINVAL;
+ *((int *)kp->arg) = jif;
+ return 0;
+}
+
+module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int,
+ &nfs_idmap_cache_timeout, 0644);
+#endif
+
+/*
+ * Register the NFS filesystems
+ */
+int __init register_nfs_fs(void)
+{
+ int ret;
+
+ ret = register_filesystem(&nfs_fs_type);
+ if (ret < 0)
+ goto error_0;
+
+#ifdef CONFIG_NFS_V4
+ ret = nfs_register_sysctl();
+ if (ret < 0)
+ goto error_1;
+ ret = register_filesystem(&nfs4_fs_type);
+ if (ret < 0)
+ goto error_2;
+#endif
+ return 0;
+
+#ifdef CONFIG_NFS_V4
+error_2:
+ nfs_unregister_sysctl();
+error_1:
+ unregister_filesystem(&nfs_fs_type);
+#endif
+error_0:
+ return ret;
+}
+
+/*
+ * Unregister the NFS filesystems
+ */
+void __exit unregister_nfs_fs(void)
+{
+#ifdef CONFIG_NFS_V4
+ unregister_filesystem(&nfs4_fs_type);
+ nfs_unregister_sysctl();
+#endif
+ unregister_filesystem(&nfs_fs_type);
+}
+
+/*
+ * Deliver file system statistics to userspace
+ */
+static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+ struct super_block *sb = dentry->d_sb;
+ struct nfs_server *server = NFS_SB(sb);
+ unsigned char blockbits;
+ unsigned long blockres;
+ struct nfs_fh *rootfh = NFS_FH(sb->s_root->d_inode);
+ struct nfs_fattr fattr;
+ struct nfs_fsstat res = {
+ .fattr = &fattr,
+ };
+ int error;
+
+ lock_kernel();
+
+ error = server->rpc_ops->statfs(server, rootfh, &res);
+ buf->f_type = NFS_SUPER_MAGIC;
+ if (error < 0)
+ goto out_err;
+
+ /*
+ * Current versions of glibc do not correctly handle the
+ * case where f_frsize != f_bsize. Eventually we want to
+ * report the value of wtmult in this field.
+ */
+ buf->f_frsize = sb->s_blocksize;
+
+ /*
+ * On most *nix systems, f_blocks, f_bfree, and f_bavail
+ * are reported in units of f_frsize. Linux hasn't had
+ * an f_frsize field in its statfs struct until recently,
+ * thus historically Linux's sys_statfs reports these
+ * fields in units of f_bsize.
+ */
+ buf->f_bsize = sb->s_blocksize;
+ blockbits = sb->s_blocksize_bits;
+ blockres = (1 << blockbits) - 1;
+ buf->f_blocks = (res.tbytes + blockres) >> blockbits;
+ buf->f_bfree = (res.fbytes + blockres) >> blockbits;
+ buf->f_bavail = (res.abytes + blockres) >> blockbits;
+
+ buf->f_files = res.tfiles;
+ buf->f_ffree = res.afiles;
+
+ buf->f_namelen = server->namelen;
+ out:
+ unlock_kernel();
+ return 0;
+
+ out_err:
+ dprintk("%s: statfs error = %d\n", __FUNCTION__, -error);
+ buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1;
+ goto out;
+
+}
+
+static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour)
+{
+ static struct {
+ rpc_authflavor_t flavour;
+ const char *str;
+ } sec_flavours[] = {
+ { RPC_AUTH_NULL, "null" },
+ { RPC_AUTH_UNIX, "sys" },
+ { RPC_AUTH_GSS_KRB5, "krb5" },
+ { RPC_AUTH_GSS_KRB5I, "krb5i" },
+ { RPC_AUTH_GSS_KRB5P, "krb5p" },
+ { RPC_AUTH_GSS_LKEY, "lkey" },
+ { RPC_AUTH_GSS_LKEYI, "lkeyi" },
+ { RPC_AUTH_GSS_LKEYP, "lkeyp" },
+ { RPC_AUTH_GSS_SPKM, "spkm" },
+ { RPC_AUTH_GSS_SPKMI, "spkmi" },
+ { RPC_AUTH_GSS_SPKMP, "spkmp" },
+ { -1, "unknown" }
+ };
+ int i;
+
+ for (i=0; sec_flavours[i].flavour != -1; i++) {
+ if (sec_flavours[i].flavour == flavour)
+ break;
+ }
+ return sec_flavours[i].str;
+}
+
+/*
+ * Describe the mount options in force on this server representation
+ */
+static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, int showdefaults)
+{
+ static struct proc_nfs_info {
+ int flag;
+ char *str;
+ char *nostr;
+ } nfs_info[] = {
+ { NFS_MOUNT_SOFT, ",soft", ",hard" },
+ { NFS_MOUNT_INTR, ",intr", "" },
+ { NFS_MOUNT_NOCTO, ",nocto", "" },
+ { NFS_MOUNT_NOAC, ",noac", "" },
+ { NFS_MOUNT_NONLM, ",nolock", "" },
+ { NFS_MOUNT_NOACL, ",noacl", "" },
+ { 0, NULL, NULL }
+ };
+ struct proc_nfs_info *nfs_infop;
+ char buf[12];
+ char *proto;
+
+ seq_printf(m, ",vers=%d", nfss->rpc_ops->version);
+ seq_printf(m, ",rsize=%d", nfss->rsize);
+ seq_printf(m, ",wsize=%d", nfss->wsize);
+ if (nfss->acregmin != 3*HZ || showdefaults)
+ seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ);
+ if (nfss->acregmax != 60*HZ || showdefaults)
+ seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ);
+ if (nfss->acdirmin != 30*HZ || showdefaults)
+ seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ);
+ if (nfss->acdirmax != 60*HZ || showdefaults)
+ seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ);
+ for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
+ if (nfss->flags & nfs_infop->flag)
+ seq_puts(m, nfs_infop->str);
+ else
+ seq_puts(m, nfs_infop->nostr);
+ }
+ switch (nfss->client->cl_xprt->prot) {
+ case IPPROTO_TCP:
+ proto = "tcp";
+ break;
+ case IPPROTO_UDP:
+ proto = "udp";
+ break;
+ default:
+ snprintf(buf, sizeof(buf), "%u", nfss->client->cl_xprt->prot);
+ proto = buf;
+ }
+ seq_printf(m, ",proto=%s", proto);
+ seq_printf(m, ",timeo=%lu", 10U * nfss->retrans_timeo / HZ);
+ seq_printf(m, ",retrans=%u", nfss->retrans_count);
+ seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor));
+}
+
+/*
+ * Describe the mount options on this VFS mountpoint
+ */
+static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
+{
+ struct nfs_server *nfss = NFS_SB(mnt->mnt_sb);
+
+ nfs_show_mount_options(m, nfss, 0);
+
+ seq_puts(m, ",addr=");
+ seq_escape(m, nfss->hostname, " \t\n\\");
+
+ return 0;
+}
+
+/*
+ * Present statistical information for this VFS mountpoint
+ */
+static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
+{
+ int i, cpu;
+ struct nfs_server *nfss = NFS_SB(mnt->mnt_sb);
+ struct rpc_auth *auth = nfss->client->cl_auth;
+ struct nfs_iostats totals = { };
+
+ seq_printf(m, "statvers=%s", NFS_IOSTAT_VERS);
+
+ /*
+ * Display all mount option settings
+ */
+ seq_printf(m, "\n\topts:\t");
+ seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? "ro" : "rw");
+ seq_puts(m, mnt->mnt_sb->s_flags & MS_SYNCHRONOUS ? ",sync" : "");
+ seq_puts(m, mnt->mnt_sb->s_flags & MS_NOATIME ? ",noatime" : "");
+ seq_puts(m, mnt->mnt_sb->s_flags & MS_NODIRATIME ? ",nodiratime" : "");
+ nfs_show_mount_options(m, nfss, 1);
+
+ seq_printf(m, "\n\tage:\t%lu", (jiffies - nfss->mount_time) / HZ);
+
+ seq_printf(m, "\n\tcaps:\t");
+ seq_printf(m, "caps=0x%x", nfss->caps);
+ seq_printf(m, ",wtmult=%d", nfss->wtmult);
+ seq_printf(m, ",dtsize=%d", nfss->dtsize);
+ seq_printf(m, ",bsize=%d", nfss->bsize);
+ seq_printf(m, ",namelen=%d", nfss->namelen);
+
+#ifdef CONFIG_NFS_V4
+ if (nfss->rpc_ops->version == 4) {
+ seq_printf(m, "\n\tnfsv4:\t");
+ seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]);
+ seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]);
+ seq_printf(m, ",acl=0x%x", nfss->acl_bitmask);
+ }
+#endif
+
+ /*
+ * Display security flavor in effect for this mount
+ */
+ seq_printf(m, "\n\tsec:\tflavor=%d", auth->au_ops->au_flavor);
+ if (auth->au_flavor)
+ seq_printf(m, ",pseudoflavor=%d", auth->au_flavor);
+
+ /*
+ * Display superblock I/O counters
+ */
+ for_each_possible_cpu(cpu) {
+ struct nfs_iostats *stats;
+
+ preempt_disable();
+ stats = per_cpu_ptr(nfss->io_stats, cpu);
+
+ for (i = 0; i < __NFSIOS_COUNTSMAX; i++)
+ totals.events[i] += stats->events[i];
+ for (i = 0; i < __NFSIOS_BYTESMAX; i++)
+ totals.bytes[i] += stats->bytes[i];
+
+ preempt_enable();
+ }
+
+ seq_printf(m, "\n\tevents:\t");
+ for (i = 0; i < __NFSIOS_COUNTSMAX; i++)
+ seq_printf(m, "%lu ", totals.events[i]);
+ seq_printf(m, "\n\tbytes:\t");
+ for (i = 0; i < __NFSIOS_BYTESMAX; i++)
+ seq_printf(m, "%Lu ", totals.bytes[i]);
+ seq_printf(m, "\n");
+
+ rpc_print_iostats(m, nfss->client);
+
+ return 0;
+}
+
+/*
+ * Begin unmount by attempting to remove all automounted mountpoints we added
+ * in response to traversals
+ */
+static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags)
+{
+ struct nfs_server *server;
+ struct rpc_clnt *rpc;
+
+ shrink_submounts(vfsmnt, &nfs_automount_list);
+ if (!(flags & MNT_FORCE))
+ return;
+ /* -EIO all pending I/O */
+ server = NFS_SB(vfsmnt->mnt_sb);
+ rpc = server->client;
+ if (!IS_ERR(rpc))
+ rpc_killall_tasks(rpc);
+ rpc = server->client_acl;
+ if (!IS_ERR(rpc))
+ rpc_killall_tasks(rpc);
+}
+
+/*
+ * Obtain the root inode of the file system.
+ */
+static struct inode *
+nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo)
+{
+ struct nfs_server *server = NFS_SB(sb);
+ int error;
+
+ error = server->rpc_ops->getroot(server, rootfh, fsinfo);
+ if (error < 0) {
+ dprintk("nfs_get_root: getattr error = %d\n", -error);
+ return ERR_PTR(error);
+ }
+
+ server->fsid = fsinfo->fattr->fsid;
+ return nfs_fhget(sb, rootfh, fsinfo->fattr);
+}
+
+/*
+ * Do NFS version-independent mount processing, and sanity checking
+ */
+static int
+nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
+{
+ struct nfs_server *server;
+ struct inode *root_inode;
+ struct nfs_fattr fattr;
+ struct nfs_fsinfo fsinfo = {
+ .fattr = &fattr,
+ };
+ struct nfs_pathconf pathinfo = {
+ .fattr = &fattr,
+ };
+ int no_root_error = 0;
+ unsigned long max_rpc_payload;
+
+ /* We probably want something more informative here */
+ snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
+
+ server = NFS_SB(sb);
+
+ sb->s_magic = NFS_SUPER_MAGIC;
+
+ server->io_stats = nfs_alloc_iostats();
+ if (server->io_stats == NULL)
+ return -ENOMEM;
+
+ root_inode = nfs_get_root(sb, &server->fh, &fsinfo);
+ /* Did getting the root inode fail? */
+ if (IS_ERR(root_inode)) {
+ no_root_error = PTR_ERR(root_inode);
+ goto out_no_root;
+ }
+ sb->s_root = d_alloc_root(root_inode);
+ if (!sb->s_root) {
+ no_root_error = -ENOMEM;
+ goto out_no_root;
+ }
+ sb->s_root->d_op = server->rpc_ops->dentry_ops;
+
+ /* mount time stamp, in seconds */
+ server->mount_time = jiffies;
+
+ /* Get some general file system info */
+ if (server->namelen == 0 &&
+ server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0)
+ server->namelen = pathinfo.max_namelen;
+ /* Work out a lot of parameters */
+ if (server->rsize == 0)
+ server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
+ if (server->wsize == 0)
+ server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
+
+ if (fsinfo.rtmax >= 512 && server->rsize > fsinfo.rtmax)
+ server->rsize = nfs_block_size(fsinfo.rtmax, NULL);
+ if (fsinfo.wtmax >= 512 && server->wsize > fsinfo.wtmax)
+ server->wsize = nfs_block_size(fsinfo.wtmax, NULL);
+
+ max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL);
+ if (server->rsize > max_rpc_payload)
+ server->rsize = max_rpc_payload;
+ if (server->rsize > NFS_MAX_FILE_IO_SIZE)
+ server->rsize = NFS_MAX_FILE_IO_SIZE;
+ server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+
+ if (server->wsize > max_rpc_payload)
+ server->wsize = max_rpc_payload;
+ if (server->wsize > NFS_MAX_FILE_IO_SIZE)
+ server->wsize = NFS_MAX_FILE_IO_SIZE;
+ server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+
+ if (sb->s_blocksize == 0)
+ sb->s_blocksize = nfs_block_bits(server->wsize,
+ &sb->s_blocksize_bits);
+ server->wtmult = nfs_block_bits(fsinfo.wtmult, NULL);
+
+ server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
+ if (server->dtsize > PAGE_CACHE_SIZE)
+ server->dtsize = PAGE_CACHE_SIZE;
+ if (server->dtsize > server->rsize)
+ server->dtsize = server->rsize;
+
+ if (server->flags & NFS_MOUNT_NOAC) {
+ server->acregmin = server->acregmax = 0;
+ server->acdirmin = server->acdirmax = 0;
+ sb->s_flags |= MS_SYNCHRONOUS;
+ }
+ server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD;
+
+ nfs_super_set_maxbytes(sb, fsinfo.maxfilesize);
+
+ server->client->cl_intr = (server->flags & NFS_MOUNT_INTR) ? 1 : 0;
+ server->client->cl_softrtry = (server->flags & NFS_MOUNT_SOFT) ? 1 : 0;
+
+ /* We're airborne Set socket buffersize */
+ rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
+ return 0;
+ /* Yargs. It didn't work out. */
+out_no_root:
+ dprintk("nfs_sb_init: get root inode failed: errno %d\n", -no_root_error);
+ if (!IS_ERR(root_inode))
+ iput(root_inode);
+ return no_root_error;
+}
+
+/*
+ * Initialise the timeout values for a connection
+ */
+static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, unsigned int timeo, unsigned int retrans)
+{
+ to->to_initval = timeo * HZ / 10;
+ to->to_retries = retrans;
+ if (!to->to_retries)
+ to->to_retries = 2;
+
+ switch (proto) {
+ case IPPROTO_TCP:
+ if (!to->to_initval)
+ to->to_initval = 60 * HZ;
+ if (to->to_initval > NFS_MAX_TCP_TIMEOUT)
+ to->to_initval = NFS_MAX_TCP_TIMEOUT;
+ to->to_increment = to->to_initval;
+ to->to_maxval = to->to_initval + (to->to_increment * to->to_retries);
+ to->to_exponential = 0;
+ break;
+ case IPPROTO_UDP:
+ default:
+ if (!to->to_initval)
+ to->to_initval = 11 * HZ / 10;
+ if (to->to_initval > NFS_MAX_UDP_TIMEOUT)
+ to->to_initval = NFS_MAX_UDP_TIMEOUT;
+ to->to_maxval = NFS_MAX_UDP_TIMEOUT;
+ to->to_exponential = 1;
+ break;
+ }
+}
+
+/*
+ * Create an RPC client handle.
+ */
+static struct rpc_clnt *
+nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data)
+{
+ struct rpc_timeout timeparms;
+ struct rpc_xprt *xprt = NULL;
+ struct rpc_clnt *clnt = NULL;
+ int proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
+
+ nfs_init_timeout_values(&timeparms, proto, data->timeo, data->retrans);
+
+ server->retrans_timeo = timeparms.to_initval;
+ server->retrans_count = timeparms.to_retries;
+
+ /* create transport and client */
+ xprt = xprt_create_proto(proto, &server->addr, &timeparms);
+ if (IS_ERR(xprt)) {
+ dprintk("%s: cannot create RPC transport. Error = %ld\n",
+ __FUNCTION__, PTR_ERR(xprt));
+ return (struct rpc_clnt *)xprt;
+ }
+ clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
+ server->rpc_ops->version, data->pseudoflavor);
+ if (IS_ERR(clnt)) {
+ dprintk("%s: cannot create RPC client. Error = %ld\n",
+ __FUNCTION__, PTR_ERR(xprt));
+ goto out_fail;
+ }
+
+ clnt->cl_intr = 1;
+ clnt->cl_softrtry = 1;
+
+ return clnt;
+
+out_fail:
+ return clnt;
+}
+
+/*
+ * Clone a server record
+ */
+static struct nfs_server *nfs_clone_server(struct super_block *sb, struct nfs_clone_mount *data)
+{
+ struct nfs_server *server = NFS_SB(sb);
+ struct nfs_server *parent = NFS_SB(data->sb);
+ struct inode *root_inode;
+ struct nfs_fsinfo fsinfo;
+ void *err = ERR_PTR(-ENOMEM);
+
+ sb->s_op = data->sb->s_op;
+ sb->s_blocksize = data->sb->s_blocksize;
+ sb->s_blocksize_bits = data->sb->s_blocksize_bits;
+ sb->s_maxbytes = data->sb->s_maxbytes;
+
+ server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
+ server->io_stats = nfs_alloc_iostats();
+ if (server->io_stats == NULL)
+ goto out;
+
+ server->client = rpc_clone_client(parent->client);
+ if (IS_ERR((err = server->client)))
+ goto out;
+
+ if (!IS_ERR(parent->client_sys)) {
+ server->client_sys = rpc_clone_client(parent->client_sys);
+ if (IS_ERR((err = server->client_sys)))
+ goto out;
+ }
+ if (!IS_ERR(parent->client_acl)) {
+ server->client_acl = rpc_clone_client(parent->client_acl);
+ if (IS_ERR((err = server->client_acl)))
+ goto out;
+ }
+ root_inode = nfs_fhget(sb, data->fh, data->fattr);
+ if (!root_inode)
+ goto out;
+ sb->s_root = d_alloc_root(root_inode);
+ if (!sb->s_root)
+ goto out_put_root;
+ fsinfo.fattr = data->fattr;
+ if (NFS_PROTO(root_inode)->fsinfo(server, data->fh, &fsinfo) == 0)
+ nfs_super_set_maxbytes(sb, fsinfo.maxfilesize);
+ sb->s_root->d_op = server->rpc_ops->dentry_ops;
+ sb->s_flags |= MS_ACTIVE;
+ return server;
+out_put_root:
+ iput(root_inode);
+out:
+ return err;
+}
+
+/*
+ * Copy an existing superblock and attach revised data
+ */
+static int nfs_clone_generic_sb(struct nfs_clone_mount *data,
+ struct super_block *(*fill_sb)(struct nfs_server *, struct nfs_clone_mount *),
+ struct nfs_server *(*fill_server)(struct super_block *, struct nfs_clone_mount *),
+ struct vfsmount *mnt)
+{
+ struct nfs_server *server;
+ struct nfs_server *parent = NFS_SB(data->sb);
+ struct super_block *sb = ERR_PTR(-EINVAL);
+ char *hostname;
+ int error = -ENOMEM;
+ int len;
+
+ server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL);
+ if (server == NULL)
+ goto out_err;
+ memcpy(server, parent, sizeof(*server));
+ hostname = (data->hostname != NULL) ? data->hostname : parent->hostname;
+ len = strlen(hostname) + 1;
+ server->hostname = kmalloc(len, GFP_KERNEL);
+ if (server->hostname == NULL)
+ goto free_server;
+ memcpy(server->hostname, hostname, len);
+ error = rpciod_up();
+ if (error != 0)
+ goto free_hostname;
+
+ sb = fill_sb(server, data);
+ if (IS_ERR(sb)) {
+ error = PTR_ERR(sb);
+ goto kill_rpciod;
+ }
+
+ if (sb->s_root)
+ goto out_rpciod_down;
+
+ server = fill_server(sb, data);
+ if (IS_ERR(server)) {
+ error = PTR_ERR(server);
+ goto out_deactivate;
+ }
+ return simple_set_mnt(mnt, sb);
+out_deactivate:
+ up_write(&sb->s_umount);
+ deactivate_super(sb);
+ return error;
+out_rpciod_down:
+ rpciod_down();
+ kfree(server->hostname);
+ kfree(server);
+ return simple_set_mnt(mnt, sb);
+kill_rpciod:
+ rpciod_down();
+free_hostname:
+ kfree(server->hostname);
+free_server:
+ kfree(server);
+out_err:
+ return error;
+}
+
+/*
+ * Set up an NFS2/3 superblock
+ *
+ * The way this works is that the mount process passes a structure
+ * in the data argument which contains the server's IP address
+ * and the root file handle obtained from the server's mount
+ * daemon. We stash these away in the private superblock fields.
+ */
+static int
+nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent)
+{
+ struct nfs_server *server;
+ rpc_authflavor_t authflavor;
+
+ server = NFS_SB(sb);
+ sb->s_blocksize_bits = 0;
+ sb->s_blocksize = 0;
+ if (data->bsize)
+ sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
+ if (data->rsize)
+ server->rsize = nfs_block_size(data->rsize, NULL);
+ if (data->wsize)
+ server->wsize = nfs_block_size(data->wsize, NULL);
+ server->flags = data->flags & NFS_MOUNT_FLAGMASK;
+
+ server->acregmin = data->acregmin*HZ;
+ server->acregmax = data->acregmax*HZ;
+ server->acdirmin = data->acdirmin*HZ;
+ server->acdirmax = data->acdirmax*HZ;
+
+ /* Start lockd here, before we might error out */
+ if (!(server->flags & NFS_MOUNT_NONLM))
+ lockd_up();
+
+ server->namelen = data->namlen;
+ server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL);
+ if (!server->hostname)
+ return -ENOMEM;
+ strcpy(server->hostname, data->hostname);
+
+ /* Check NFS protocol revision and initialize RPC op vector
+ * and file handle pool. */
+#ifdef CONFIG_NFS_V3
+ if (server->flags & NFS_MOUNT_VER3) {
+ server->rpc_ops = &nfs_v3_clientops;
+ server->caps |= NFS_CAP_READDIRPLUS;
+ } else {
+ server->rpc_ops = &nfs_v2_clientops;
+ }
+#else
+ server->rpc_ops = &nfs_v2_clientops;
+#endif
+
+ /* Fill in pseudoflavor for mount version < 5 */
+ if (!(data->flags & NFS_MOUNT_SECFLAVOUR))
+ data->pseudoflavor = RPC_AUTH_UNIX;
+ authflavor = data->pseudoflavor; /* save for sb_init() */
+ /* XXX maybe we want to add a server->pseudoflavor field */
+
+ /* Create RPC client handles */
+ server->client = nfs_create_client(server, data);
+ if (IS_ERR(server->client))
+ return PTR_ERR(server->client);
+ /* RFC 2623, sec 2.3.2 */
+ if (authflavor != RPC_AUTH_UNIX) {
+ struct rpc_auth *auth;
+
+ server->client_sys = rpc_clone_client(server->client);
+ if (IS_ERR(server->client_sys))
+ return PTR_ERR(server->client_sys);
+ auth = rpcauth_create(RPC_AUTH_UNIX, server->client_sys);
+ if (IS_ERR(auth))
+ return PTR_ERR(auth);
+ } else {
+ atomic_inc(&server->client->cl_count);
+ server->client_sys = server->client;
+ }
+ if (server->flags & NFS_MOUNT_VER3) {
+#ifdef CONFIG_NFS_V3_ACL
+ if (!(server->flags & NFS_MOUNT_NOACL)) {
+ server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3);
+ /* No errors! Assume that Sun nfsacls are supported */
+ if (!IS_ERR(server->client_acl))
+ server->caps |= NFS_CAP_ACLS;
+ }
+#else
+ server->flags &= ~NFS_MOUNT_NOACL;
+#endif /* CONFIG_NFS_V3_ACL */
+ /*
+ * The VFS shouldn't apply the umask to mode bits. We will
+ * do so ourselves when necessary.
+ */
+ sb->s_flags |= MS_POSIXACL;
+ if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
+ server->namelen = NFS3_MAXNAMLEN;
+ sb->s_time_gran = 1;
+ } else {
+ if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
+ server->namelen = NFS2_MAXNAMLEN;
+ }
+
+ sb->s_op = &nfs_sops;
+ return nfs_sb_init(sb, authflavor);
+}
+
+static int nfs_set_super(struct super_block *s, void *data)
+{
+ s->s_fs_info = data;
+ return set_anon_super(s, data);
+}
+
+static int nfs_compare_super(struct super_block *sb, void *data)
+{
+ struct nfs_server *server = data;
+ struct nfs_server *old = NFS_SB(sb);
+
+ if (old->addr.sin_addr.s_addr != server->addr.sin_addr.s_addr)
+ return 0;
+ if (old->addr.sin_port != server->addr.sin_port)
+ return 0;
+ return !nfs_compare_fh(&old->fh, &server->fh);
+}
+
+static int nfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
+{
+ int error;
+ struct nfs_server *server = NULL;
+ struct super_block *s;
+ struct nfs_fh *root;
+ struct nfs_mount_data *data = raw_data;
+
+ error = -EINVAL;
+ if (data == NULL) {
+ dprintk("%s: missing data argument\n", __FUNCTION__);
+ goto out_err_noserver;
+ }
+ if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) {
+ dprintk("%s: bad mount version\n", __FUNCTION__);
+ goto out_err_noserver;
+ }
+ switch (data->version) {
+ case 1:
+ data->namlen = 0;
+ case 2:
+ data->bsize = 0;
+ case 3:
+ if (data->flags & NFS_MOUNT_VER3) {
+ dprintk("%s: mount structure version %d does not support NFSv3\n",
+ __FUNCTION__,
+ data->version);
+ goto out_err_noserver;
+ }
+ data->root.size = NFS2_FHSIZE;
+ memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
+ case 4:
+ if (data->flags & NFS_MOUNT_SECFLAVOUR) {
+ dprintk("%s: mount structure version %d does not support strong security\n",
+ __FUNCTION__,
+ data->version);
+ goto out_err_noserver;
+ }
+ case 5:
+ memset(data->context, 0, sizeof(data->context));
+ }
+#ifndef CONFIG_NFS_V3
+ /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */
+ error = -EPROTONOSUPPORT;
+ if (data->flags & NFS_MOUNT_VER3) {
+ dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__);
+ goto out_err_noserver;
+ }
+#endif /* CONFIG_NFS_V3 */
+
+ error = -ENOMEM;
+ server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
+ if (!server)
+ goto out_err_noserver;
+ /* Zero out the NFS state stuff */
+ init_nfsv4_state(server);
+ server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
+
+ root = &server->fh;
+ if (data->flags & NFS_MOUNT_VER3)
+ root->size = data->root.size;
+ else
+ root->size = NFS2_FHSIZE;
+ error = -EINVAL;
+ if (root->size > sizeof(root->data)) {
+ dprintk("%s: invalid root filehandle\n", __FUNCTION__);
+ goto out_err;
+ }
+ memcpy(root->data, data->root.data, root->size);
+
+ /* We now require that the mount process passes the remote address */
+ memcpy(&server->addr, &data->addr, sizeof(server->addr));
+ if (server->addr.sin_addr.s_addr == INADDR_ANY) {
+ dprintk("%s: mount program didn't pass remote address!\n",
+ __FUNCTION__);
+ goto out_err;
+ }
+
+ /* Fire up rpciod if not yet running */
+ error = rpciod_up();
+ if (error < 0) {
+ dprintk("%s: couldn't start rpciod! Error = %d\n",
+ __FUNCTION__, error);
+ goto out_err;
+ }
+
+ s = sget(fs_type, nfs_compare_super, nfs_set_super, server);
+ if (IS_ERR(s)) {
+ error = PTR_ERR(s);
+ goto out_err_rpciod;
+ }
+
+ if (s->s_root)
+ goto out_rpciod_down;
+
+ s->s_flags = flags;
+
+ error = nfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
+ if (error) {
+ up_write(&s->s_umount);
+ deactivate_super(s);
+ return error;
+ }
+ s->s_flags |= MS_ACTIVE;
+ return simple_set_mnt(mnt, s);
+
+out_rpciod_down:
+ rpciod_down();
+ kfree(server);
+ return simple_set_mnt(mnt, s);
+
+out_err_rpciod:
+ rpciod_down();
+out_err:
+ kfree(server);
+out_err_noserver:
+ return error;
+}
+
+static void nfs_kill_super(struct super_block *s)
+{
+ struct nfs_server *server = NFS_SB(s);
+
+ kill_anon_super(s);
+
+ if (!IS_ERR(server->client))
+ rpc_shutdown_client(server->client);
+ if (!IS_ERR(server->client_sys))
+ rpc_shutdown_client(server->client_sys);
+ if (!IS_ERR(server->client_acl))
+ rpc_shutdown_client(server->client_acl);
+
+ if (!(server->flags & NFS_MOUNT_NONLM))
+ lockd_down(); /* release rpc.lockd */
+
+ rpciod_down(); /* release rpciod */
+
+ nfs_free_iostats(server->io_stats);
+ kfree(server->hostname);
+ kfree(server);
+ nfs_release_automount_timer();
+}
+
+static struct super_block *nfs_clone_sb(struct nfs_server *server, struct nfs_clone_mount *data)
+{
+ struct super_block *sb;
+
+ server->fsid = data->fattr->fsid;
+ nfs_copy_fh(&server->fh, data->fh);
+ sb = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
+ if (!IS_ERR(sb) && sb->s_root == NULL && !(server->flags & NFS_MOUNT_NONLM))
+ lockd_up();
+ return sb;
+}
+
+static int nfs_clone_nfs_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
+{
+ struct nfs_clone_mount *data = raw_data;
+ return nfs_clone_generic_sb(data, nfs_clone_sb, nfs_clone_server, mnt);
+}
+
+#ifdef CONFIG_NFS_V4
+static struct rpc_clnt *nfs4_create_client(struct nfs_server *server,
+ struct rpc_timeout *timeparms, int proto, rpc_authflavor_t flavor)
+{
+ struct nfs4_client *clp;
+ struct rpc_xprt *xprt = NULL;
+ struct rpc_clnt *clnt = NULL;
+ int err = -EIO;
+
+ clp = nfs4_get_client(&server->addr.sin_addr);
+ if (!clp) {
+ dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__);
+ return ERR_PTR(err);
+ }
+
+ /* Now create transport and client */
+ down_write(&clp->cl_sem);
+ if (IS_ERR(clp->cl_rpcclient)) {
+ xprt = xprt_create_proto(proto, &server->addr, timeparms);
+ if (IS_ERR(xprt)) {
+ up_write(&clp->cl_sem);
+ err = PTR_ERR(xprt);
+ dprintk("%s: cannot create RPC transport. Error = %d\n",
+ __FUNCTION__, err);
+ goto out_fail;
+ }
+ /* Bind to a reserved port! */
+ xprt->resvport = 1;
+ clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
+ server->rpc_ops->version, flavor);
+ if (IS_ERR(clnt)) {
+ up_write(&clp->cl_sem);
+ err = PTR_ERR(clnt);
+ dprintk("%s: cannot create RPC client. Error = %d\n",
+ __FUNCTION__, err);
+ goto out_fail;
+ }
+ clnt->cl_intr = 1;
+ clnt->cl_softrtry = 1;
+ clp->cl_rpcclient = clnt;
+ memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr));
+ nfs_idmap_new(clp);
+ }
+ list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
+ clnt = rpc_clone_client(clp->cl_rpcclient);
+ if (!IS_ERR(clnt))
+ server->nfs4_state = clp;
+ up_write(&clp->cl_sem);
+ clp = NULL;
+
+ if (IS_ERR(clnt)) {
+ dprintk("%s: cannot create RPC client. Error = %d\n",
+ __FUNCTION__, err);
+ return clnt;
+ }
+
+ if (server->nfs4_state->cl_idmap == NULL) {
+ dprintk("%s: failed to create idmapper.\n", __FUNCTION__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ if (clnt->cl_auth->au_flavor != flavor) {
+ struct rpc_auth *auth;
+
+ auth = rpcauth_create(flavor, clnt);
+ if (IS_ERR(auth)) {
+ dprintk("%s: couldn't create credcache!\n", __FUNCTION__);
+ return (struct rpc_clnt *)auth;
+ }
+ }
+ return clnt;
+
+ out_fail:
+ if (clp)
+ nfs4_put_client(clp);
+ return ERR_PTR(err);
+}
+
+/*
+ * Set up an NFS4 superblock
+ */
+static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, int silent)
+{
+ struct nfs_server *server;
+ struct rpc_timeout timeparms;
+ rpc_authflavor_t authflavour;
+ int err = -EIO;
+
+ sb->s_blocksize_bits = 0;
+ sb->s_blocksize = 0;
+ server = NFS_SB(sb);
+ if (data->rsize != 0)
+ server->rsize = nfs_block_size(data->rsize, NULL);
+ if (data->wsize != 0)
+ server->wsize = nfs_block_size(data->wsize, NULL);
+ server->flags = data->flags & NFS_MOUNT_FLAGMASK;
+ server->caps = NFS_CAP_ATOMIC_OPEN;
+
+ server->acregmin = data->acregmin*HZ;
+ server->acregmax = data->acregmax*HZ;
+ server->acdirmin = data->acdirmin*HZ;
+ server->acdirmax = data->acdirmax*HZ;
+
+ server->rpc_ops = &nfs_v4_clientops;
+
+ nfs_init_timeout_values(&timeparms, data->proto, data->timeo, data->retrans);
+
+ server->retrans_timeo = timeparms.to_initval;
+ server->retrans_count = timeparms.to_retries;
+
+ /* Now create transport and client */
+ authflavour = RPC_AUTH_UNIX;
+ if (data->auth_flavourlen != 0) {
+ if (data->auth_flavourlen != 1) {
+ dprintk("%s: Invalid number of RPC auth flavours %d.\n",
+ __FUNCTION__, data->auth_flavourlen);
+ err = -EINVAL;
+ goto out_fail;
+ }
+ if (copy_from_user(&authflavour, data->auth_flavours, sizeof(authflavour))) {
+ err = -EFAULT;
+ goto out_fail;
+ }
+ }
+
+ server->client = nfs4_create_client(server, &timeparms, data->proto, authflavour);
+ if (IS_ERR(server->client)) {
+ err = PTR_ERR(server->client);
+ dprintk("%s: cannot create RPC client. Error = %d\n",
+ __FUNCTION__, err);
+ goto out_fail;
+ }
+
+ sb->s_time_gran = 1;
+
+ sb->s_op = &nfs4_sops;
+ err = nfs_sb_init(sb, authflavour);
+
+ out_fail:
+ return err;
+}
+
+static int nfs4_compare_super(struct super_block *sb, void *data)
+{
+ struct nfs_server *server = data;
+ struct nfs_server *old = NFS_SB(sb);
+
+ if (strcmp(server->hostname, old->hostname) != 0)
+ return 0;
+ if (strcmp(server->mnt_path, old->mnt_path) != 0)
+ return 0;
+ return 1;
+}
+
+static void *
+nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen)
+{
+ void *p = NULL;
+
+ if (!src->len)
+ return ERR_PTR(-EINVAL);
+ if (src->len < maxlen)
+ maxlen = src->len;
+ if (dst == NULL) {
+ p = dst = kmalloc(maxlen + 1, GFP_KERNEL);
+ if (p == NULL)
+ return ERR_PTR(-ENOMEM);
+ }
+ if (copy_from_user(dst, src->data, maxlen)) {
+ kfree(p);
+ return ERR_PTR(-EFAULT);
+ }
+ dst[maxlen] = '\0';
+ return dst;
+}
+
+static int nfs4_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
+{
+ int error;
+ struct nfs_server *server;
+ struct super_block *s;
+ struct nfs4_mount_data *data = raw_data;
+ void *p;
+
+ if (data == NULL) {
+ dprintk("%s: missing data argument\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ if (data->version <= 0 || data->version > NFS4_MOUNT_VERSION) {
+ dprintk("%s: bad mount version\n", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
+ if (!server)
+ return -ENOMEM;
+ /* Zero out the NFS state stuff */
+ init_nfsv4_state(server);
+ server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
+
+ p = nfs_copy_user_string(NULL, &data->hostname, 256);
+ if (IS_ERR(p))
+ goto out_err;
+ server->hostname = p;
+
+ p = nfs_copy_user_string(NULL, &data->mnt_path, 1024);
+ if (IS_ERR(p))
+ goto out_err;
+ server->mnt_path = p;
+
+ p = nfs_copy_user_string(server->ip_addr, &data->client_addr,
+ sizeof(server->ip_addr) - 1);
+ if (IS_ERR(p))
+ goto out_err;
+
+ /* We now require that the mount process passes the remote address */
+ if (data->host_addrlen != sizeof(server->addr)) {
+ error = -EINVAL;
+ goto out_free;
+ }
+ if (copy_from_user(&server->addr, data->host_addr, sizeof(server->addr))) {
+ error = -EFAULT;
+ goto out_free;
+ }
+ if (server->addr.sin_family != AF_INET ||
+ server->addr.sin_addr.s_addr == INADDR_ANY) {
+ dprintk("%s: mount program didn't pass remote IP address!\n",
+ __FUNCTION__);
+ error = -EINVAL;
+ goto out_free;
+ }
+
+ /* Fire up rpciod if not yet running */
+ error = rpciod_up();
+ if (error < 0) {
+ dprintk("%s: couldn't start rpciod! Error = %d\n",
+ __FUNCTION__, error);
+ goto out_free;
+ }
+
+ s = sget(fs_type, nfs4_compare_super, nfs_set_super, server);
+
+ if (IS_ERR(s)) {
+ error = PTR_ERR(s);
+ goto out_free;
+ }
+
+ if (s->s_root) {
+ kfree(server->mnt_path);
+ kfree(server->hostname);
+ kfree(server);
+ return simple_set_mnt(mnt, s);
+ }
+
+ s->s_flags = flags;
+
+ error = nfs4_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
+ if (error) {
+ up_write(&s->s_umount);
+ deactivate_super(s);
+ return error;
+ }
+ s->s_flags |= MS_ACTIVE;
+ return simple_set_mnt(mnt, s);
+out_err:
+ error = PTR_ERR(p);
+out_free:
+ kfree(server->mnt_path);
+ kfree(server->hostname);
+ kfree(server);
+ return error;
+}
+
+static void nfs4_kill_super(struct super_block *sb)
+{
+ struct nfs_server *server = NFS_SB(sb);
+
+ nfs_return_all_delegations(sb);
+ kill_anon_super(sb);
+
+ nfs4_renewd_prepare_shutdown(server);
+
+ if (server->client != NULL && !IS_ERR(server->client))
+ rpc_shutdown_client(server->client);
+
+ destroy_nfsv4_state(server);
+
+ rpciod_down();
+
+ nfs_free_iostats(server->io_stats);
+ kfree(server->hostname);
+ kfree(server);
+ nfs_release_automount_timer();
+}
+
+/*
+ * Constructs the SERVER-side path
+ */
+static inline char *nfs4_dup_path(const struct dentry *dentry)
+{
+ char *page = (char *) __get_free_page(GFP_USER);
+ char *path;
+
+ path = nfs4_path(dentry, page, PAGE_SIZE);
+ if (!IS_ERR(path)) {
+ int len = PAGE_SIZE + page - path;
+ char *tmp = path;
+
+ path = kmalloc(len, GFP_KERNEL);
+ if (path)
+ memcpy(path, tmp, len);
+ else
+ path = ERR_PTR(-ENOMEM);
+ }
+ free_page((unsigned long)page);
+ return path;
+}
+
+static struct super_block *nfs4_clone_sb(struct nfs_server *server, struct nfs_clone_mount *data)
+{
+ const struct dentry *dentry = data->dentry;
+ struct nfs4_client *clp = server->nfs4_state;
+ struct super_block *sb;
+
+ server->fsid = data->fattr->fsid;
+ nfs_copy_fh(&server->fh, data->fh);
+ server->mnt_path = nfs4_dup_path(dentry);
+ if (IS_ERR(server->mnt_path)) {
+ sb = (struct super_block *)server->mnt_path;
+ goto err;
+ }
+ sb = sget(&nfs4_fs_type, nfs4_compare_super, nfs_set_super, server);
+ if (IS_ERR(sb) || sb->s_root)
+ goto free_path;
+ nfs4_server_capabilities(server, &server->fh);
+
+ down_write(&clp->cl_sem);
+ atomic_inc(&clp->cl_count);
+ list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
+ up_write(&clp->cl_sem);
+ return sb;
+free_path:
+ kfree(server->mnt_path);
+err:
+ server->mnt_path = NULL;
+ return sb;
+}
+
+static int nfs_clone_nfs4_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
+{
+ struct nfs_clone_mount *data = raw_data;
+ return nfs_clone_generic_sb(data, nfs4_clone_sb, nfs_clone_server, mnt);
+}
+
+static struct super_block *nfs4_referral_sb(struct nfs_server *server, struct nfs_clone_mount *data)
+{
+ struct super_block *sb = ERR_PTR(-ENOMEM);
+ int len;
+
+ len = strlen(data->mnt_path) + 1;
+ server->mnt_path = kmalloc(len, GFP_KERNEL);
+ if (server->mnt_path == NULL)
+ goto err;
+ memcpy(server->mnt_path, data->mnt_path, len);
+ memcpy(&server->addr, data->addr, sizeof(struct sockaddr_in));
+
+ sb = sget(&nfs4_fs_type, nfs4_compare_super, nfs_set_super, server);
+ if (IS_ERR(sb) || sb->s_root)
+ goto free_path;
+ return sb;
+free_path:
+ kfree(server->mnt_path);
+err:
+ server->mnt_path = NULL;
+ return sb;
+}
+
+static struct nfs_server *nfs4_referral_server(struct super_block *sb, struct nfs_clone_mount *data)
+{
+ struct nfs_server *server = NFS_SB(sb);
+ struct rpc_timeout timeparms;
+ int proto, timeo, retrans;
+ void *err;
+
+ proto = IPPROTO_TCP;
+ /* Since we are following a referral and there may be alternatives,
+ set the timeouts and retries to low values */
+ timeo = 2;
+ retrans = 1;
+ nfs_init_timeout_values(&timeparms, proto, timeo, retrans);
+
+ server->client = nfs4_create_client(server, &timeparms, proto, data->authflavor);
+ if (IS_ERR((err = server->client)))
+ goto out_err;
+
+ sb->s_time_gran = 1;
+ sb->s_op = &nfs4_sops;
+ err = ERR_PTR(nfs_sb_init(sb, data->authflavor));
+ if (!IS_ERR(err))
+ return server;
+out_err:
+ return (struct nfs_server *)err;
+}
+
+static int nfs_referral_nfs4_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
+{
+ struct nfs_clone_mount *data = raw_data;
+ return nfs_clone_generic_sb(data, nfs4_referral_sb, nfs4_referral_server, mnt);
+}
+
+#endif
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index 18dc95b..600bbe6 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -52,7 +52,7 @@ static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct inode *inode = dentry->d_inode;
struct page *page;
- void *err = ERR_PTR(nfs_revalidate_inode(NFS_SERVER(inode), inode));
+ void *err = ERR_PTR(nfs_revalidate_mapping(inode, inode->i_mapping));
if (err)
goto read_failed;
page = read_cache_page(&inode->i_data, 0,
@@ -75,22 +75,13 @@ read_failed:
return NULL;
}
-static void nfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
-{
- if (cookie) {
- struct page *page = cookie;
- kunmap(page);
- page_cache_release(page);
- }
-}
-
/*
* symlinks can't do much...
*/
struct inode_operations nfs_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = nfs_follow_link,
- .put_link = nfs_put_link,
+ .put_link = page_put_link,
.getattr = nfs_getattr,
.setattr = nfs_setattr,
};
diff --git a/fs/nfs/sysctl.c b/fs/nfs/sysctl.c
index 4c486eb..db61e51 100644
--- a/fs/nfs/sysctl.c
+++ b/fs/nfs/sysctl.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/nfs4.h>
#include <linux/nfs_idmap.h>
+#include <linux/nfs_fs.h>
#include "callback.h"
@@ -46,6 +47,15 @@ static ctl_table nfs_cb_sysctls[] = {
.strategy = &sysctl_jiffies,
},
#endif
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "nfs_mountpoint_timeout",
+ .data = &nfs_mountpoint_expiry_timeout,
+ .maxlen = sizeof(nfs_mountpoint_expiry_timeout),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_jiffies,
+ .strategy = &sysctl_jiffies,
+ },
{ .ctl_name = 0 }
};
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 4cfada2..b383fdd 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -98,11 +98,10 @@ struct nfs_write_data *nfs_commit_alloc(unsigned int pagecount)
if (p) {
memset(p, 0, sizeof(*p));
INIT_LIST_HEAD(&p->pages);
- if (pagecount < NFS_PAGEVEC_SIZE)
- p->pagevec = &p->page_array[0];
+ if (pagecount <= ARRAY_SIZE(p->page_array))
+ p->pagevec = p->page_array;
else {
- size_t size = ++pagecount * sizeof(struct page *);
- p->pagevec = kzalloc(size, GFP_NOFS);
+ p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS);
if (!p->pagevec) {
mempool_free(p, nfs_commit_mempool);
p = NULL;
@@ -126,14 +125,11 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
if (p) {
memset(p, 0, sizeof(*p));
INIT_LIST_HEAD(&p->pages);
- if (pagecount < NFS_PAGEVEC_SIZE)
- p->pagevec = &p->page_array[0];
+ if (pagecount <= ARRAY_SIZE(p->page_array))
+ p->pagevec = p->page_array;
else {
- size_t size = ++pagecount * sizeof(struct page *);
- p->pagevec = kmalloc(size, GFP_NOFS);
- if (p->pagevec) {
- memset(p->pagevec, 0, size);
- } else {
+ p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS);
+ if (!p->pagevec) {
mempool_free(p, nfs_wdata_mempool);
p = NULL;
}
@@ -583,6 +579,17 @@ static int nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, un
return ret;
}
+static void nfs_cancel_requests(struct list_head *head)
+{
+ struct nfs_page *req;
+ while(!list_empty(head)) {
+ req = nfs_list_entry(head->next);
+ nfs_list_remove_request(req);
+ nfs_inode_remove_request(req);
+ nfs_clear_page_writeback(req);
+ }
+}
+
/*
* nfs_scan_dirty - Scan an inode for dirty requests
* @inode: NFS inode to scan
@@ -627,7 +634,7 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_st
int res = 0;
if (nfsi->ncommit != 0) {
- res = nfs_scan_list(&nfsi->commit, dst, idx_start, npages);
+ res = nfs_scan_list(nfsi, &nfsi->commit, dst, idx_start, npages);
nfsi->ncommit -= res;
if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit))
printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");
@@ -1495,15 +1502,25 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
pages = nfs_scan_dirty(inode, &head, idx_start, npages);
if (pages != 0) {
spin_unlock(&nfsi->req_lock);
- ret = nfs_flush_list(inode, &head, pages, how);
+ if (how & FLUSH_INVALIDATE)
+ nfs_cancel_requests(&head);
+ else
+ ret = nfs_flush_list(inode, &head, pages, how);
spin_lock(&nfsi->req_lock);
continue;
}
if (nocommit)
break;
- pages = nfs_scan_commit(inode, &head, 0, 0);
+ pages = nfs_scan_commit(inode, &head, idx_start, npages);
if (pages == 0)
break;
+ if (how & FLUSH_INVALIDATE) {
+ spin_unlock(&nfsi->req_lock);
+ nfs_cancel_requests(&head);
+ spin_lock(&nfsi->req_lock);
+ continue;
+ }
+ pages += nfs_scan_commit(inode, &head, 0, 0);
spin_unlock(&nfsi->req_lock);
ret = nfs_commit_list(inode, &head, how);
spin_lock(&nfsi->req_lock);
@@ -1512,7 +1529,7 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
return ret;
}
-int nfs_init_writepagecache(void)
+int __init nfs_init_writepagecache(void)
{
nfs_wdata_cachep = kmem_cache_create("nfs_write_data",
sizeof(struct nfs_write_data),
@@ -1534,7 +1551,7 @@ int nfs_init_writepagecache(void)
return 0;
}
-void nfs_destroy_writepagecache(void)
+void __exit nfs_destroy_writepagecache(void)
{
mempool_destroy(nfs_commit_mempool);
mempool_destroy(nfs_wdata_mempool);
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index de3998f..5446a08 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1310,7 +1310,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL)) ||
(bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
FATTR4_WORD1_SPACE_TOTAL))) {
- status = vfs_statfs(dentry->d_inode->i_sb, &statfs);
+ status = vfs_statfs(dentry, &statfs);
if (status)
goto out_nfserr;
}
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 3ef017b..a1810e6 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -494,10 +494,10 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
return simple_fill_super(sb, 0x6e667364, nfsd_files);
}
-static struct super_block *nfsd_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int nfsd_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, nfsd_fill_super);
+ return get_sb_single(fs_type, flags, data, nfsd_fill_super, mnt);
}
static struct file_system_type nfsd_fs_type = {
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 1d65f13..245eaa1 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1737,7 +1737,7 @@ int
nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
{
int err = fh_verify(rqstp, fhp, 0, MAY_NOP);
- if (!err && vfs_statfs(fhp->fh_dentry->d_inode->i_sb,stat))
+ if (!err && vfs_statfs(fhp->fh_dentry,stat))
err = nfserr_io;
return err;
}
diff --git a/fs/ntfs/aops.h b/fs/ntfs/aops.h
index 3b74e66..325ce26 100644
--- a/fs/ntfs/aops.h
+++ b/fs/ntfs/aops.h
@@ -86,8 +86,7 @@ static inline void ntfs_unmap_page(struct page *page)
static inline struct page *ntfs_map_page(struct address_space *mapping,
unsigned long index)
{
- struct page *page = read_cache_page(mapping, index,
- (filler_t*)mapping->a_ops->readpage, NULL);
+ struct page *page = read_mapping_page(mapping, index, NULL);
if (!IS_ERR(page)) {
wait_on_page_locked(page);
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
index 1663f5c..6708e1d 100644
--- a/fs/ntfs/attrib.c
+++ b/fs/ntfs/attrib.c
@@ -2529,8 +2529,7 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val)
end >>= PAGE_CACHE_SHIFT;
/* If there is a first partial page, need to do it the slow way. */
if (start_ofs) {
- page = read_cache_page(mapping, idx,
- (filler_t*)mapping->a_ops->readpage, NULL);
+ page = read_mapping_page(mapping, idx, NULL);
if (IS_ERR(page)) {
ntfs_error(vol->sb, "Failed to read first partial "
"page (sync error, index 0x%lx).", idx);
@@ -2600,8 +2599,7 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val)
}
/* If there is a last partial page, need to do it the slow way. */
if (end_ofs) {
- page = read_cache_page(mapping, idx,
- (filler_t*)mapping->a_ops->readpage, NULL);
+ page = read_mapping_page(mapping, idx, NULL);
if (IS_ERR(page)) {
ntfs_error(vol->sb, "Failed to read last partial page "
"(sync error, index 0x%lx).", idx);
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index c63a83e..2e42c2d 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -231,8 +231,7 @@ do_non_resident_extend:
* Read the page. If the page is not present, this will zero
* the uninitialized regions for us.
*/
- page = read_cache_page(mapping, index,
- (filler_t*)mapping->a_ops->readpage, NULL);
+ page = read_mapping_page(mapping, index, NULL);
if (IS_ERR(page)) {
err = PTR_ERR(page);
goto init_err_out;
@@ -1359,7 +1358,7 @@ err_out:
goto out;
}
-static size_t __ntfs_copy_from_user_iovec(char *vaddr,
+static size_t __ntfs_copy_from_user_iovec_inatomic(char *vaddr,
const struct iovec *iov, size_t iov_ofs, size_t bytes)
{
size_t total = 0;
@@ -1377,10 +1376,6 @@ static size_t __ntfs_copy_from_user_iovec(char *vaddr,
bytes -= len;
vaddr += len;
if (unlikely(left)) {
- /*
- * Zero the rest of the target like __copy_from_user().
- */
- memset(vaddr, 0, bytes);
total -= left;
break;
}
@@ -1421,11 +1416,13 @@ static inline void ntfs_set_next_iovec(const struct iovec **iovp,
* pages (out to offset + bytes), to emulate ntfs_copy_from_user()'s
* single-segment behaviour.
*
- * We call the same helper (__ntfs_copy_from_user_iovec()) both when atomic and
- * when not atomic. This is ok because __ntfs_copy_from_user_iovec() calls
- * __copy_from_user_inatomic() and it is ok to call this when non-atomic. In
- * fact, the only difference between __copy_from_user_inatomic() and
- * __copy_from_user() is that the latter calls might_sleep(). And on many
+ * We call the same helper (__ntfs_copy_from_user_iovec_inatomic()) both
+ * when atomic and when not atomic. This is ok because
+ * __ntfs_copy_from_user_iovec_inatomic() calls __copy_from_user_inatomic()
+ * and it is ok to call this when non-atomic.
+ * Infact, the only difference between __copy_from_user_inatomic() and
+ * __copy_from_user() is that the latter calls might_sleep() and the former
+ * should not zero the tail of the buffer on error. And on many
* architectures __copy_from_user_inatomic() is just defined to
* __copy_from_user() so it makes no difference at all on those architectures.
*/
@@ -1442,14 +1439,18 @@ static inline size_t ntfs_copy_from_user_iovec(struct page **pages,
if (len > bytes)
len = bytes;
kaddr = kmap_atomic(*pages, KM_USER0);
- copied = __ntfs_copy_from_user_iovec(kaddr + ofs,
+ copied = __ntfs_copy_from_user_iovec_inatomic(kaddr + ofs,
*iov, *iov_ofs, len);
kunmap_atomic(kaddr, KM_USER0);
if (unlikely(copied != len)) {
/* Do it the slow way. */
kaddr = kmap(*pages);
- copied = __ntfs_copy_from_user_iovec(kaddr + ofs,
+ copied = __ntfs_copy_from_user_iovec_inatomic(kaddr + ofs,
*iov, *iov_ofs, len);
+ /*
+ * Zero the rest of the target like __copy_from_user().
+ */
+ memset(kaddr + ofs + copied, 0, len - copied);
kunmap(*pages);
if (unlikely(copied != len))
goto err_out;
@@ -1484,14 +1485,15 @@ static inline void ntfs_flush_dcache_pages(struct page **pages,
unsigned nr_pages)
{
BUG_ON(!nr_pages);
+ /*
+ * Warning: Do not do the decrement at the same time as the call to
+ * flush_dcache_page() because it is a NULL macro on i386 and hence the
+ * decrement never happens so the loop never terminates.
+ */
do {
- /*
- * Warning: Do not do the decrement at the same time as the
- * call because flush_dcache_page() is a NULL macro on i386
- * and hence the decrement never happens.
- */
+ --nr_pages;
flush_dcache_page(pages[nr_pages]);
- } while (--nr_pages > 0);
+ } while (nr_pages > 0);
}
/**
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index 27833f6..0e14ace 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -2601,10 +2601,10 @@ static unsigned long __get_nr_free_mft_records(ntfs_volume *vol,
/**
* ntfs_statfs - return information about mounted NTFS volume
- * @sb: super block of mounted volume
+ * @dentry: dentry from mounted volume
* @sfs: statfs structure in which to return the information
*
- * Return information about the mounted NTFS volume @sb in the statfs structure
+ * Return information about the mounted NTFS volume @dentry in the statfs structure
* pointed to by @sfs (this is initialized with zeros before ntfs_statfs is
* called). We interpret the values to be correct of the moment in time at
* which we are called. Most values are variable otherwise and this isn't just
@@ -2617,8 +2617,9 @@ static unsigned long __get_nr_free_mft_records(ntfs_volume *vol,
*
* Return 0 on success or -errno on error.
*/
-static int ntfs_statfs(struct super_block *sb, struct kstatfs *sfs)
+static int ntfs_statfs(struct dentry *dentry, struct kstatfs *sfs)
{
+ struct super_block *sb = dentry->d_sb;
s64 size;
ntfs_volume *vol = NTFS_SB(sb);
ntfs_inode *mft_ni = NTFS_I(vol->mft_ino);
@@ -3093,10 +3094,11 @@ struct kmem_cache *ntfs_index_ctx_cache;
/* Driver wide mutex. */
DEFINE_MUTEX(ntfs_lock);
-static struct super_block *ntfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int ntfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, ntfs_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, ntfs_fill_super,
+ mnt);
}
static struct file_system_type ntfs_fs_type = {
diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c
index 7e88e24..7273d9f 100644
--- a/fs/ocfs2/dlm/dlmfs.c
+++ b/fs/ocfs2/dlm/dlmfs.c
@@ -574,10 +574,10 @@ static struct inode_operations dlmfs_file_inode_operations = {
.getattr = simple_getattr,
};
-static struct super_block *dlmfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int dlmfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_nodev(fs_type, flags, data, dlmfs_fill_super);
+ return get_sb_nodev(fs_type, flags, data, dlmfs_fill_super, mnt);
}
static struct file_system_type dlmfs_fs_type = {
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 949b3da..cdf7339 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -100,7 +100,7 @@ static int ocfs2_initialize_mem_caches(void);
static void ocfs2_free_mem_caches(void);
static void ocfs2_delete_osb(struct ocfs2_super *osb);
-static int ocfs2_statfs(struct super_block *sb, struct kstatfs *buf);
+static int ocfs2_statfs(struct dentry *dentry, struct kstatfs *buf);
static int ocfs2_sync_fs(struct super_block *sb, int wait);
@@ -672,12 +672,14 @@ read_super_error:
return status;
}
-static struct super_block *ocfs2_get_sb(struct file_system_type *fs_type,
- int flags,
- const char *dev_name,
- void *data)
+static int ocfs2_get_sb(struct file_system_type *fs_type,
+ int flags,
+ const char *dev_name,
+ void *data,
+ struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, ocfs2_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, ocfs2_fill_super,
+ mnt);
}
static struct file_system_type ocfs2_fs_type = {
@@ -855,7 +857,7 @@ static void ocfs2_put_super(struct super_block *sb)
mlog_exit_void();
}
-static int ocfs2_statfs(struct super_block *sb, struct kstatfs *buf)
+static int ocfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct ocfs2_super *osb;
u32 numbits, freebits;
@@ -864,9 +866,9 @@ static int ocfs2_statfs(struct super_block *sb, struct kstatfs *buf)
struct buffer_head *bh = NULL;
struct inode *inode = NULL;
- mlog_entry("(%p, %p)\n", sb, buf);
+ mlog_entry("(%p, %p)\n", dentry->d_sb, buf);
- osb = OCFS2_SB(sb);
+ osb = OCFS2_SB(dentry->d_sb);
inode = ocfs2_get_system_file_inode(osb,
GLOBAL_BITMAP_SYSTEM_INODE,
@@ -889,7 +891,7 @@ static int ocfs2_statfs(struct super_block *sb, struct kstatfs *buf)
freebits = numbits - le32_to_cpu(bm_lock->id1.bitmap1.i_used);
buf->f_type = OCFS2_SUPER_MAGIC;
- buf->f_bsize = sb->s_blocksize;
+ buf->f_bsize = dentry->d_sb->s_blocksize;
buf->f_namelen = OCFS2_MAX_FILENAME_LEN;
buf->f_blocks = ((sector_t) numbits) *
(osb->s_clustersize >> osb->sb->s_blocksize_bits);
diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c
index f6986bd..0c8a129 100644
--- a/fs/ocfs2/symlink.c
+++ b/fs/ocfs2/symlink.c
@@ -64,8 +64,7 @@ static char *ocfs2_page_getlink(struct dentry * dentry,
{
struct page * page;
struct address_space *mapping = dentry->d_inode->i_mapping;
- page = read_cache_page(mapping, 0,
- (filler_t *)mapping->a_ops->readpage, NULL);
+ page = read_mapping_page(mapping, 0, NULL);
if (IS_ERR(page))
goto sync_fail;
wait_on_page_locked(page);
diff --git a/fs/open.c b/fs/open.c
index 4f178ac..303f06d 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -31,18 +31,18 @@
#include <asm/unistd.h>
-int vfs_statfs(struct super_block *sb, struct kstatfs *buf)
+int vfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
int retval = -ENODEV;
- if (sb) {
+ if (dentry) {
retval = -ENOSYS;
- if (sb->s_op->statfs) {
+ if (dentry->d_sb->s_op->statfs) {
memset(buf, 0, sizeof(*buf));
- retval = security_sb_statfs(sb);
+ retval = security_sb_statfs(dentry);
if (retval)
return retval;
- retval = sb->s_op->statfs(sb, buf);
+ retval = dentry->d_sb->s_op->statfs(dentry, buf);
if (retval == 0 && buf->f_frsize == 0)
buf->f_frsize = buf->f_bsize;
}
@@ -52,12 +52,12 @@ int vfs_statfs(struct super_block *sb, struct kstatfs *buf)
EXPORT_SYMBOL(vfs_statfs);
-static int vfs_statfs_native(struct super_block *sb, struct statfs *buf)
+static int vfs_statfs_native(struct dentry *dentry, struct statfs *buf)
{
struct kstatfs st;
int retval;
- retval = vfs_statfs(sb, &st);
+ retval = vfs_statfs(dentry, &st);
if (retval)
return retval;
@@ -95,12 +95,12 @@ static int vfs_statfs_native(struct super_block *sb, struct statfs *buf)
return 0;
}
-static int vfs_statfs64(struct super_block *sb, struct statfs64 *buf)
+static int vfs_statfs64(struct dentry *dentry, struct statfs64 *buf)
{
struct kstatfs st;
int retval;
- retval = vfs_statfs(sb, &st);
+ retval = vfs_statfs(dentry, &st);
if (retval)
return retval;
@@ -130,7 +130,7 @@ asmlinkage long sys_statfs(const char __user * path, struct statfs __user * buf)
error = user_path_walk(path, &nd);
if (!error) {
struct statfs tmp;
- error = vfs_statfs_native(nd.dentry->d_inode->i_sb, &tmp);
+ error = vfs_statfs_native(nd.dentry, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
path_release(&nd);
@@ -149,7 +149,7 @@ asmlinkage long sys_statfs64(const char __user *path, size_t sz, struct statfs64
error = user_path_walk(path, &nd);
if (!error) {
struct statfs64 tmp;
- error = vfs_statfs64(nd.dentry->d_inode->i_sb, &tmp);
+ error = vfs_statfs64(nd.dentry, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
path_release(&nd);
@@ -168,7 +168,7 @@ asmlinkage long sys_fstatfs(unsigned int fd, struct statfs __user * buf)
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs_native(file->f_dentry->d_inode->i_sb, &tmp);
+ error = vfs_statfs_native(file->f_dentry, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
fput(file);
@@ -189,7 +189,7 @@ asmlinkage long sys_fstatfs64(unsigned int fd, size_t sz, struct statfs64 __user
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs64(file->f_dentry->d_inode->i_sb, &tmp);
+ error = vfs_statfs64(file->f_dentry, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
fput(file);
@@ -322,7 +322,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
error = locks_verify_truncate(inode, file, length);
if (!error)
- error = do_truncate(dentry, length, 0, file);
+ error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
out_putf:
fput(file);
out:
@@ -1152,7 +1152,7 @@ int filp_close(struct file *filp, fl_owner_t id)
}
if (filp->f_op && filp->f_op->flush)
- retval = filp->f_op->flush(filp);
+ retval = filp->f_op->flush(filp, id);
dnotify_flush(filp, id);
locks_remove_posix(filp, id);
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index 0f14276..efc7c911 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -64,6 +64,11 @@ static int openpromfs_readdir(struct file *, void *, filldir_t);
static struct dentry *openpromfs_lookup(struct inode *, struct dentry *dentry, struct nameidata *nd);
static int openpromfs_unlink (struct inode *, struct dentry *dentry);
+static inline u16 ptr_nod(void *p)
+{
+ return (long)p & 0xFFFF;
+}
+
static ssize_t nodenum_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -72,7 +77,7 @@ static ssize_t nodenum_read(struct file *file, char __user *buf,
if (count < 0 || !inode->u.generic_ip)
return -EINVAL;
- sprintf (buffer, "%8.8x\n", (u32)(long)(inode->u.generic_ip));
+ sprintf (buffer, "%8.8lx\n", (long)inode->u.generic_ip);
if (file->f_pos >= 9)
return 0;
if (count > 9 - file->f_pos)
@@ -95,9 +100,9 @@ static ssize_t property_read(struct file *filp, char __user *buf,
char buffer[64];
if (!filp->private_data) {
- node = nodes[(u16)((long)inode->u.generic_ip)].node;
+ node = nodes[ptr_nod(inode->u.generic_ip)].node;
i = ((u32)(long)inode->u.generic_ip) >> 16;
- if ((u16)((long)inode->u.generic_ip) == aliases) {
+ if (ptr_nod(inode->u.generic_ip) == aliases) {
if (i >= aliases_nodes)
p = NULL;
else
@@ -111,7 +116,7 @@ static ssize_t property_read(struct file *filp, char __user *buf,
return -EIO;
i = prom_getproplen (node, p);
if (i < 0) {
- if ((u16)((long)inode->u.generic_ip) == aliases)
+ if (ptr_nod(inode->u.generic_ip) == aliases)
i = 0;
else
return -EIO;
@@ -123,7 +128,7 @@ static ssize_t property_read(struct file *filp, char __user *buf,
GFP_KERNEL);
if (!filp->private_data)
return -ENOMEM;
- op = (openprom_property *)filp->private_data;
+ op = filp->private_data;
op->flag = 0;
op->alloclen = 2 * i;
strcpy (op->name, p);
@@ -163,7 +168,7 @@ static ssize_t property_read(struct file *filp, char __user *buf,
op->len--;
}
} else
- op = (openprom_property *)filp->private_data;
+ op = filp->private_data;
if (!count || !(op->len || (op->flag & OPP_ASCIIZ)))
return 0;
if (*ppos >= 0xffffff || count >= 0xffffff)
@@ -335,7 +340,7 @@ static ssize_t property_write(struct file *filp, const char __user *buf,
return i;
}
k = *ppos;
- op = (openprom_property *)filp->private_data;
+ op = filp->private_data;
if (!(op->flag & OPP_STRING)) {
u32 *first, *last;
int first_off, last_cnt;
@@ -388,13 +393,13 @@ static ssize_t property_write(struct file *filp, const char __user *buf,
memcpy (b, filp->private_data,
sizeof (openprom_property)
+ strlen (op->name) + op->alloclen);
- memset (((char *)b) + sizeof (openprom_property)
+ memset (b + sizeof (openprom_property)
+ strlen (op->name) + op->alloclen,
0, 2 * i - op->alloclen);
- op = (openprom_property *)b;
+ op = b;
op->alloclen = 2*i;
b = filp->private_data;
- filp->private_data = (void *)op;
+ filp->private_data = op;
kfree (b);
}
first = ((u32 *)op->value) + (k / 9);
@@ -448,10 +453,11 @@ static ssize_t property_write(struct file *filp, const char __user *buf,
*q |= simple_strtoul (tmp, NULL, 16);
buf += last_cnt;
} else {
- char tchars[17]; /* XXX yuck... */
+ char tchars[2 * sizeof(long) + 1];
- if (copy_from_user(tchars, buf, 16))
+ if (copy_from_user(tchars, buf, sizeof(tchars) - 1))
return -EFAULT;
+ tchars[sizeof(tchars) - 1] = '\0';
*q = simple_strtoul (tchars, NULL, 16);
buf += 9;
}
@@ -497,13 +503,13 @@ write_try_string:
memcpy (b, filp->private_data,
sizeof (openprom_property)
+ strlen (op->name) + op->alloclen);
- memset (((char *)b) + sizeof (openprom_property)
+ memset (b + sizeof (openprom_property)
+ strlen (op->name) + op->alloclen,
0, 2*(count - *ppos) - op->alloclen);
- op = (openprom_property *)b;
+ op = b;
op->alloclen = 2*(count + *ppos);
b = filp->private_data;
- filp->private_data = (void *)op;
+ filp->private_data = op;
kfree (b);
}
p = op->value + *ppos - ((op->flag & OPP_QUOTED) ? 1 : 0);
@@ -532,15 +538,15 @@ write_try_string:
int property_release (struct inode *inode, struct file *filp)
{
- openprom_property *op = (openprom_property *)filp->private_data;
+ openprom_property *op = filp->private_data;
int error;
u32 node;
if (!op)
return 0;
lock_kernel();
- node = nodes[(u16)((long)inode->u.generic_ip)].node;
- if ((u16)((long)inode->u.generic_ip) == aliases) {
+ node = nodes[ptr_nod(inode->u.generic_ip)].node;
+ if (ptr_nod(inode->u.generic_ip) == aliases) {
if ((op->flag & OPP_DIRTY) && (op->flag & OPP_STRING)) {
char *p = op->name;
int i = (op->value - op->name) - strlen (op->name) - 1;
@@ -931,7 +937,7 @@ static int __init check_space (u16 n)
return -1;
if (nodes) {
- memcpy ((char *)pages, (char *)nodes,
+ memcpy ((char *)pages, nodes,
(1 << alloced) * PAGE_SIZE);
free_pages ((unsigned long)nodes, alloced);
}
@@ -1054,10 +1060,10 @@ out_no_root:
return -ENOMEM;
}
-static struct super_block *openprom_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int openprom_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, openprom_fill_super);
+ return get_sb_single(fs_type, flags, data, openprom_fill_super, mnt);
}
static struct file_system_type openprom_fs_type = {
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 8851b81..2ef313a 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -484,6 +484,10 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
sector_t from = state->parts[p].from;
if (!size)
continue;
+ if (from + size > get_capacity(disk)) {
+ printk(" %s: p%d exceeds device capacity\n",
+ disk->disk_name, p);
+ }
add_partition(disk, p, from, size);
#ifdef CONFIG_BLK_DEV_MD
if (state->parts[p].flags)
@@ -499,8 +503,8 @@ unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p)
struct address_space *mapping = bdev->bd_inode->i_mapping;
struct page *page;
- page = read_cache_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)),
- (filler_t *)mapping->a_ops->readpage, NULL);
+ page = read_mapping_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)),
+ NULL);
if (!IS_ERR(page)) {
wait_on_page_locked(page);
if (!PageUptodate(page))
diff --git a/fs/pipe.c b/fs/pipe.c
index 5acd895..2035257 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -979,12 +979,11 @@ no_files:
* any operations on the root directory. However, we need a non-trivial
* d_name - pipe: will go nicely and kill the special-casing in procfs.
*/
-
-static struct super_block *
-pipefs_get_sb(struct file_system_type *fs_type, int flags,
- const char *dev_name, void *data)
+static int pipefs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data,
+ struct vfsmount *mnt)
{
- return get_sb_pseudo(fs_type, "pipe:", NULL, PIPEFS_MAGIC);
+ return get_sb_pseudo(fs_type, "pipe:", NULL, PIPEFS_MAGIC, mnt);
}
static struct file_system_type pipe_fs_type = {
diff --git a/fs/proc/root.c b/fs/proc/root.c
index c3fd361..9995356 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -26,10 +26,10 @@ struct proc_dir_entry *proc_net, *proc_net_stat, *proc_bus, *proc_root_fs, *proc
struct proc_dir_entry *proc_sys_root;
#endif
-static struct super_block *proc_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int proc_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, proc_fill_super);
+ return get_sb_single(fs_type, flags, data, proc_fill_super, mnt);
}
static struct file_system_type proc_fs_type = {
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 2ecd46f..2f24c46 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -128,7 +128,7 @@ static struct inode *qnx4_alloc_inode(struct super_block *sb);
static void qnx4_destroy_inode(struct inode *inode);
static void qnx4_read_inode(struct inode *);
static int qnx4_remount(struct super_block *sb, int *flags, char *data);
-static int qnx4_statfs(struct super_block *, struct kstatfs *);
+static int qnx4_statfs(struct dentry *, struct kstatfs *);
static struct super_operations qnx4_sops =
{
@@ -282,8 +282,10 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock )
return block;
}
-static int qnx4_statfs(struct super_block *sb, struct kstatfs *buf)
+static int qnx4_statfs(struct dentry *dentry, struct kstatfs *buf)
{
+ struct super_block *sb = dentry->d_sb;
+
lock_kernel();
buf->f_type = sb->s_magic;
@@ -561,10 +563,11 @@ static void destroy_inodecache(void)
"qnx4_inode_cache: not all structures were freed\n");
}
-static struct super_block *qnx4_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int qnx4_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, qnx4_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, qnx4_fill_super,
+ mnt);
}
static struct file_system_type qnx4_fs_type = {
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index 14bd224..b967733 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -185,16 +185,17 @@ static int ramfs_fill_super(struct super_block * sb, void * data, int silent)
return 0;
}
-struct super_block *ramfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+int ramfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_nodev(fs_type, flags, data, ramfs_fill_super);
+ return get_sb_nodev(fs_type, flags, data, ramfs_fill_super, mnt);
}
-static struct super_block *rootfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int rootfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super);
+ return get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super,
+ mnt);
}
static struct file_system_type ramfs_fs_type = {
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index cae2abb..00f1321 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -60,7 +60,7 @@ static int is_any_reiserfs_magic_string(struct reiserfs_super_block *rs)
}
static int reiserfs_remount(struct super_block *s, int *flags, char *data);
-static int reiserfs_statfs(struct super_block *s, struct kstatfs *buf);
+static int reiserfs_statfs(struct dentry *dentry, struct kstatfs *buf);
static int reiserfs_sync_fs(struct super_block *s, int wait)
{
@@ -1938,15 +1938,15 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
return errval;
}
-static int reiserfs_statfs(struct super_block *s, struct kstatfs *buf)
+static int reiserfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
- struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(s);
+ struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(dentry->d_sb);
buf->f_namelen = (REISERFS_MAX_NAME(s->s_blocksize));
buf->f_bfree = sb_free_blocks(rs);
buf->f_bavail = buf->f_bfree;
buf->f_blocks = sb_block_count(rs) - sb_bmap_nr(rs) - 1;
- buf->f_bsize = s->s_blocksize;
+ buf->f_bsize = dentry->d_sb->s_blocksize;
/* changed to accommodate gcc folks. */
buf->f_type = REISERFS_SUPER_MAGIC;
return 0;
@@ -2249,11 +2249,12 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type,
#endif
-static struct super_block *get_super_block(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data)
+static int get_super_block(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, reiserfs_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, reiserfs_fill_super,
+ mnt);
}
static int __init init_reiserfs_fs(void)
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index ffb79c4..39fedaa 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -452,8 +452,7 @@ static struct page *reiserfs_get_page(struct inode *dir, unsigned long n)
/* We can deadlock if we try to free dentries,
and an unlink/rmdir has just occured - GFP_NOFS avoids this */
mapping_set_gfp_mask(mapping, GFP_NOFS);
- page = read_cache_page(mapping, n,
- (filler_t *) mapping->a_ops->readpage, NULL);
+ page = read_mapping_page(mapping, n, NULL);
if (!IS_ERR(page)) {
wait_on_page_locked(page);
kmap(page);
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index 9b9eda7..283fbc6 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -179,12 +179,12 @@ outnobh:
/* That's simple too. */
static int
-romfs_statfs(struct super_block *sb, struct kstatfs *buf)
+romfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
buf->f_type = ROMFS_MAGIC;
buf->f_bsize = ROMBSIZE;
buf->f_bfree = buf->f_bavail = buf->f_ffree;
- buf->f_blocks = (romfs_maxsize(sb)+ROMBSIZE-1)>>ROMBSBITS;
+ buf->f_blocks = (romfs_maxsize(dentry->d_sb)+ROMBSIZE-1)>>ROMBSBITS;
buf->f_namelen = ROMFS_MAXFN;
return 0;
}
@@ -607,10 +607,11 @@ static struct super_operations romfs_ops = {
.remount_fs = romfs_remount,
};
-static struct super_block *romfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int romfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, romfs_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, romfs_fill_super,
+ mnt);
}
static struct file_system_type romfs_fs_type = {
diff --git a/fs/select.c b/fs/select.c
index a8109ba..33b72ba 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -546,37 +546,38 @@ struct poll_list {
#define POLLFD_PER_PAGE ((PAGE_SIZE-sizeof(struct poll_list)) / sizeof(struct pollfd))
-static void do_pollfd(unsigned int num, struct pollfd * fdpage,
- poll_table ** pwait, int *count)
+/*
+ * Fish for pollable events on the pollfd->fd file descriptor. We're only
+ * interested in events matching the pollfd->events mask, and the result
+ * matching that mask is both recorded in pollfd->revents and returned. The
+ * pwait poll_table will be used by the fd-provided poll handler for waiting,
+ * if non-NULL.
+ */
+static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait)
{
- int i;
-
- for (i = 0; i < num; i++) {
- int fd;
- unsigned int mask;
- struct pollfd *fdp;
-
- mask = 0;
- fdp = fdpage+i;
- fd = fdp->fd;
- if (fd >= 0) {
- int fput_needed;
- struct file * file = fget_light(fd, &fput_needed);
- mask = POLLNVAL;
- if (file != NULL) {
- mask = DEFAULT_POLLMASK;
- if (file->f_op && file->f_op->poll)
- mask = file->f_op->poll(file, *pwait);
- mask &= fdp->events | POLLERR | POLLHUP;
- fput_light(file, fput_needed);
- }
- if (mask) {
- *pwait = NULL;
- (*count)++;
- }
+ unsigned int mask;
+ int fd;
+
+ mask = 0;
+ fd = pollfd->fd;
+ if (fd >= 0) {
+ int fput_needed;
+ struct file * file;
+
+ file = fget_light(fd, &fput_needed);
+ mask = POLLNVAL;
+ if (file != NULL) {
+ mask = DEFAULT_POLLMASK;
+ if (file->f_op && file->f_op->poll)
+ mask = file->f_op->poll(file, pwait);
+ /* Mask out unneeded events. */
+ mask &= pollfd->events | POLLERR | POLLHUP;
+ fput_light(file, fput_needed);
}
- fdp->revents = mask;
}
+ pollfd->revents = mask;
+
+ return mask;
}
static int do_poll(unsigned int nfds, struct poll_list *list,
@@ -594,11 +595,29 @@ static int do_poll(unsigned int nfds, struct poll_list *list,
long __timeout;
set_current_state(TASK_INTERRUPTIBLE);
- walk = list;
- while(walk != NULL) {
- do_pollfd( walk->len, walk->entries, &pt, &count);
- walk = walk->next;
+ for (walk = list; walk != NULL; walk = walk->next) {
+ struct pollfd * pfd, * pfd_end;
+
+ pfd = walk->entries;
+ pfd_end = pfd + walk->len;
+ for (; pfd != pfd_end; pfd++) {
+ /*
+ * Fish for events. If we found one, record it
+ * and kill the poll_table, so we don't
+ * needlessly register any other waiters after
+ * this. They'll get immediately deregistered
+ * when we break out and return.
+ */
+ if (do_pollfd(pfd, pt)) {
+ count++;
+ pt = NULL;
+ }
+ }
}
+ /*
+ * All waiters have already been registered, so don't provide
+ * a poll_table to them on the next loop iteration.
+ */
pt = NULL;
if (count || !*timeout || signal_pending(current))
break;
@@ -727,9 +746,9 @@ out_fds:
asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,
long timeout_msecs)
{
- s64 timeout_jiffies = 0;
+ s64 timeout_jiffies;
- if (timeout_msecs) {
+ if (timeout_msecs > 0) {
#if HZ > 1000
/* We can only overflow if HZ > 1000 */
if (timeout_msecs / 1000 > (s64)0x7fffffffffffffffULL / (s64)HZ)
@@ -737,6 +756,9 @@ asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,
else
#endif
timeout_jiffies = msecs_to_jiffies(timeout_msecs);
+ } else {
+ /* Infinite (< 0) or no (0) timeout */
+ timeout_jiffies = timeout_msecs;
}
return do_sys_poll(ufds, nfds, &timeout_jiffies);
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index fdeabc0..506ff87 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -48,7 +48,7 @@
static void smb_delete_inode(struct inode *);
static void smb_put_super(struct super_block *);
-static int smb_statfs(struct super_block *, struct kstatfs *);
+static int smb_statfs(struct dentry *, struct kstatfs *);
static int smb_show_options(struct seq_file *, struct vfsmount *);
static kmem_cache_t *smb_inode_cachep;
@@ -641,13 +641,13 @@ out_no_server:
}
static int
-smb_statfs(struct super_block *sb, struct kstatfs *buf)
+smb_statfs(struct dentry *dentry, struct kstatfs *buf)
{
int result;
lock_kernel();
- result = smb_proc_dskattr(sb, buf);
+ result = smb_proc_dskattr(dentry, buf);
unlock_kernel();
@@ -782,10 +782,10 @@ out:
return error;
}
-static struct super_block *smb_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int smb_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_nodev(fs_type, flags, data, smb_fill_super);
+ return get_sb_nodev(fs_type, flags, data, smb_fill_super, mnt);
}
static struct file_system_type smb_fs_type = {
diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c
index b1b878b..c349505 100644
--- a/fs/smbfs/proc.c
+++ b/fs/smbfs/proc.c
@@ -3226,9 +3226,9 @@ smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr)
}
int
-smb_proc_dskattr(struct super_block *sb, struct kstatfs *attr)
+smb_proc_dskattr(struct dentry *dentry, struct kstatfs *attr)
{
- struct smb_sb_info *server = SMB_SB(sb);
+ struct smb_sb_info *server = SMB_SB(dentry->d_sb);
int result;
char *p;
long unit;
diff --git a/fs/smbfs/proto.h b/fs/smbfs/proto.h
index 4766459..972ed7d 100644
--- a/fs/smbfs/proto.h
+++ b/fs/smbfs/proto.h
@@ -29,7 +29,7 @@ extern int smb_proc_getattr(struct dentry *dir, struct smb_fattr *fattr);
extern int smb_proc_setattr(struct dentry *dir, struct smb_fattr *fattr);
extern int smb_proc_setattr_unix(struct dentry *d, struct iattr *attr, unsigned int major, unsigned int minor);
extern int smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr);
-extern int smb_proc_dskattr(struct super_block *sb, struct kstatfs *attr);
+extern int smb_proc_dskattr(struct dentry *dentry, struct kstatfs *attr);
extern int smb_proc_read_link(struct smb_sb_info *server, struct dentry *d, char *buffer, int len);
extern int smb_proc_symlink(struct smb_sb_info *server, struct dentry *d, const char *oldpath);
extern int smb_proc_link(struct smb_sb_info *server, struct dentry *dentry, struct dentry *new_dentry);
diff --git a/fs/smbfs/smbiod.c b/fs/smbfs/smbiod.c
index 481a97a42..3f71384 100644
--- a/fs/smbfs/smbiod.c
+++ b/fs/smbfs/smbiod.c
@@ -20,6 +20,7 @@
#include <linux/smp_lock.h>
#include <linux/module.h>
#include <linux/net.h>
+#include <linux/kthread.h>
#include <net/ip.h>
#include <linux/smb_fs.h>
@@ -40,7 +41,7 @@ enum smbiod_state {
};
static enum smbiod_state smbiod_state = SMBIOD_DEAD;
-static pid_t smbiod_pid;
+static struct task_struct *smbiod_thread;
static DECLARE_WAIT_QUEUE_HEAD(smbiod_wait);
static LIST_HEAD(smb_servers);
static DEFINE_SPINLOCK(servers_lock);
@@ -67,20 +68,29 @@ void smbiod_wake_up(void)
*/
static int smbiod_start(void)
{
- pid_t pid;
+ struct task_struct *tsk;
+ int err = 0;
+
if (smbiod_state != SMBIOD_DEAD)
return 0;
smbiod_state = SMBIOD_STARTING;
__module_get(THIS_MODULE);
spin_unlock(&servers_lock);
- pid = kernel_thread(smbiod, NULL, 0);
- if (pid < 0)
+ tsk = kthread_run(smbiod, NULL, "smbiod");
+ if (IS_ERR(tsk)) {
+ err = PTR_ERR(tsk);
module_put(THIS_MODULE);
+ }
spin_lock(&servers_lock);
- smbiod_state = pid < 0 ? SMBIOD_DEAD : SMBIOD_RUNNING;
- smbiod_pid = pid;
- return pid;
+ if (err < 0) {
+ smbiod_state = SMBIOD_DEAD;
+ smbiod_thread = NULL;
+ } else {
+ smbiod_state = SMBIOD_RUNNING;
+ smbiod_thread = tsk;
+ }
+ return err;
}
/*
@@ -290,8 +300,6 @@ out:
*/
static int smbiod(void *unused)
{
- daemonize("smbiod");
-
allow_signal(SIGKILL);
VERBOSE("SMB Kernel thread starting (%d) ...\n", current->pid);
diff --git a/fs/splice.c b/fs/splice.c
index a285fd7..05fd278 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -55,31 +55,43 @@ static int page_cache_pipe_buf_steal(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
{
struct page *page = buf->page;
- struct address_space *mapping = page_mapping(page);
+ struct address_space *mapping;
lock_page(page);
- WARN_ON(!PageUptodate(page));
+ mapping = page_mapping(page);
+ if (mapping) {
+ WARN_ON(!PageUptodate(page));
- /*
- * At least for ext2 with nobh option, we need to wait on writeback
- * completing on this page, since we'll remove it from the pagecache.
- * Otherwise truncate wont wait on the page, allowing the disk
- * blocks to be reused by someone else before we actually wrote our
- * data to them. fs corruption ensues.
- */
- wait_on_page_writeback(page);
+ /*
+ * At least for ext2 with nobh option, we need to wait on
+ * writeback completing on this page, since we'll remove it
+ * from the pagecache. Otherwise truncate wont wait on the
+ * page, allowing the disk blocks to be reused by someone else
+ * before we actually wrote our data to them. fs corruption
+ * ensues.
+ */
+ wait_on_page_writeback(page);
- if (PagePrivate(page))
- try_to_release_page(page, mapping_gfp_mask(mapping));
+ if (PagePrivate(page))
+ try_to_release_page(page, mapping_gfp_mask(mapping));
- if (!remove_mapping(mapping, page)) {
- unlock_page(page);
- return 1;
+ /*
+ * If we succeeded in removing the mapping, set LRU flag
+ * and return good.
+ */
+ if (remove_mapping(mapping, page)) {
+ buf->flags |= PIPE_BUF_FLAG_LRU;
+ return 0;
+ }
}
- buf->flags |= PIPE_BUF_FLAG_LRU;
- return 0;
+ /*
+ * Raced with truncate or failed to remove page from current
+ * address space, unlock and return failure.
+ */
+ unlock_page(page);
+ return 1;
}
static void page_cache_pipe_buf_release(struct pipe_inode_info *pipe,
diff --git a/fs/super.c b/fs/super.c
index a66f66b..8a669f6 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -231,7 +231,7 @@ void generic_shutdown_super(struct super_block *sb)
if (root) {
sb->s_root = NULL;
shrink_dcache_parent(root);
- shrink_dcache_anon(&sb->s_anon);
+ shrink_dcache_sb(sb);
dput(root);
fsync_super(sb);
lock_super(sb);
@@ -486,7 +486,7 @@ asmlinkage long sys_ustat(unsigned dev, struct ustat __user * ubuf)
s = user_get_super(new_decode_dev(dev));
if (s == NULL)
goto out;
- err = vfs_statfs(s, &sbuf);
+ err = vfs_statfs(s->s_root, &sbuf);
drop_super(s);
if (err)
goto out;
@@ -676,9 +676,10 @@ static void bdev_uevent(struct block_device *bdev, enum kobject_action action)
}
}
-struct super_block *get_sb_bdev(struct file_system_type *fs_type,
+int get_sb_bdev(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data,
- int (*fill_super)(struct super_block *, void *, int))
+ int (*fill_super)(struct super_block *, void *, int),
+ struct vfsmount *mnt)
{
struct block_device *bdev;
struct super_block *s;
@@ -686,7 +687,7 @@ struct super_block *get_sb_bdev(struct file_system_type *fs_type,
bdev = open_bdev_excl(dev_name, flags, fs_type);
if (IS_ERR(bdev))
- return (struct super_block *)bdev;
+ return PTR_ERR(bdev);
/*
* once the super is inserted into the list by sget, s_umount
@@ -697,15 +698,17 @@ struct super_block *get_sb_bdev(struct file_system_type *fs_type,
s = sget(fs_type, test_bdev_super, set_bdev_super, bdev);
mutex_unlock(&bdev->bd_mount_mutex);
if (IS_ERR(s))
- goto out;
+ goto error_s;
if (s->s_root) {
if ((flags ^ s->s_flags) & MS_RDONLY) {
up_write(&s->s_umount);
deactivate_super(s);
- s = ERR_PTR(-EBUSY);
+ error = -EBUSY;
+ goto error_bdev;
}
- goto out;
+
+ close_bdev_excl(bdev);
} else {
char b[BDEVNAME_SIZE];
@@ -716,18 +719,21 @@ struct super_block *get_sb_bdev(struct file_system_type *fs_type,
if (error) {
up_write(&s->s_umount);
deactivate_super(s);
- s = ERR_PTR(error);
- } else {
- s->s_flags |= MS_ACTIVE;
- bdev_uevent(bdev, KOBJ_MOUNT);
+ goto error;
}
+
+ s->s_flags |= MS_ACTIVE;
+ bdev_uevent(bdev, KOBJ_MOUNT);
}
- return s;
+ return simple_set_mnt(mnt, s);
-out:
+error_s:
+ error = PTR_ERR(s);
+error_bdev:
close_bdev_excl(bdev);
- return s;
+error:
+ return error;
}
EXPORT_SYMBOL(get_sb_bdev);
@@ -744,15 +750,16 @@ void kill_block_super(struct super_block *sb)
EXPORT_SYMBOL(kill_block_super);
-struct super_block *get_sb_nodev(struct file_system_type *fs_type,
+int get_sb_nodev(struct file_system_type *fs_type,
int flags, void *data,
- int (*fill_super)(struct super_block *, void *, int))
+ int (*fill_super)(struct super_block *, void *, int),
+ struct vfsmount *mnt)
{
int error;
struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
if (IS_ERR(s))
- return s;
+ return PTR_ERR(s);
s->s_flags = flags;
@@ -760,10 +767,10 @@ struct super_block *get_sb_nodev(struct file_system_type *fs_type,
if (error) {
up_write(&s->s_umount);
deactivate_super(s);
- return ERR_PTR(error);
+ return error;
}
s->s_flags |= MS_ACTIVE;
- return s;
+ return simple_set_mnt(mnt, s);
}
EXPORT_SYMBOL(get_sb_nodev);
@@ -773,94 +780,100 @@ static int compare_single(struct super_block *s, void *p)
return 1;
}
-struct super_block *get_sb_single(struct file_system_type *fs_type,
+int get_sb_single(struct file_system_type *fs_type,
int flags, void *data,
- int (*fill_super)(struct super_block *, void *, int))
+ int (*fill_super)(struct super_block *, void *, int),
+ struct vfsmount *mnt)
{
struct super_block *s;
int error;
s = sget(fs_type, compare_single, set_anon_super, NULL);
if (IS_ERR(s))
- return s;
+ return PTR_ERR(s);
if (!s->s_root) {
s->s_flags = flags;
error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
if (error) {
up_write(&s->s_umount);
deactivate_super(s);
- return ERR_PTR(error);
+ return error;
}
s->s_flags |= MS_ACTIVE;
}
do_remount_sb(s, flags, data, 0);
- return s;
+ return simple_set_mnt(mnt, s);
}
EXPORT_SYMBOL(get_sb_single);
struct vfsmount *
-do_kern_mount(const char *fstype, int flags, const char *name, void *data)
+vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
{
- struct file_system_type *type = get_fs_type(fstype);
- struct super_block *sb = ERR_PTR(-ENOMEM);
struct vfsmount *mnt;
- int error;
char *secdata = NULL;
+ int error;
if (!type)
return ERR_PTR(-ENODEV);
+ error = -ENOMEM;
mnt = alloc_vfsmnt(name);
if (!mnt)
goto out;
if (data) {
secdata = alloc_secdata();
- if (!secdata) {
- sb = ERR_PTR(-ENOMEM);
+ if (!secdata)
goto out_mnt;
- }
error = security_sb_copy_data(type, data, secdata);
- if (error) {
- sb = ERR_PTR(error);
+ if (error)
goto out_free_secdata;
- }
}
- sb = type->get_sb(type, flags, name, data);
- if (IS_ERR(sb))
+ error = type->get_sb(type, flags, name, data, mnt);
+ if (error < 0)
goto out_free_secdata;
- error = security_sb_kern_mount(sb, secdata);
+
+ error = security_sb_kern_mount(mnt->mnt_sb, secdata);
if (error)
goto out_sb;
- mnt->mnt_sb = sb;
- mnt->mnt_root = dget(sb->s_root);
- mnt->mnt_mountpoint = sb->s_root;
+
+ mnt->mnt_mountpoint = mnt->mnt_root;
mnt->mnt_parent = mnt;
- up_write(&sb->s_umount);
+ up_write(&mnt->mnt_sb->s_umount);
free_secdata(secdata);
- put_filesystem(type);
return mnt;
out_sb:
- up_write(&sb->s_umount);
- deactivate_super(sb);
- sb = ERR_PTR(error);
+ dput(mnt->mnt_root);
+ up_write(&mnt->mnt_sb->s_umount);
+ deactivate_super(mnt->mnt_sb);
out_free_secdata:
free_secdata(secdata);
out_mnt:
free_vfsmnt(mnt);
out:
- put_filesystem(type);
- return (struct vfsmount *)sb;
+ return ERR_PTR(error);
}
-EXPORT_SYMBOL_GPL(do_kern_mount);
+EXPORT_SYMBOL_GPL(vfs_kern_mount);
+
+struct vfsmount *
+do_kern_mount(const char *fstype, int flags, const char *name, void *data)
+{
+ struct file_system_type *type = get_fs_type(fstype);
+ struct vfsmount *mnt;
+ if (!type)
+ return ERR_PTR(-ENODEV);
+ mnt = vfs_kern_mount(type, flags, name, data);
+ put_filesystem(type);
+ return mnt;
+}
struct vfsmount *kern_mount(struct file_system_type *type)
{
- return do_kern_mount(type->name, 0, type->name, NULL);
+ return vfs_kern_mount(type, 0, type->name, NULL);
}
EXPORT_SYMBOL(kern_mount);
diff --git a/fs/sync.c b/fs/sync.c
index aab5ffe..955aef0 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -100,7 +100,7 @@ asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes,
}
if (nbytes == 0)
- endbyte = -1;
+ endbyte = LLONG_MAX;
else
endbyte--; /* inclusive */
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index f1117e8..40190c4 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -66,10 +66,10 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
return 0;
}
-static struct super_block *sysfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int sysfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, sysfs_fill_super);
+ return get_sb_single(fs_type, flags, data, sysfs_fill_super, mnt);
}
static struct file_system_type sysfs_fs_type = {
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c
index d707434..f2bef96 100644
--- a/fs/sysv/dir.c
+++ b/fs/sysv/dir.c
@@ -53,8 +53,7 @@ static int dir_commit_chunk(struct page *page, unsigned from, unsigned to)
static struct page * dir_get_page(struct inode *dir, unsigned long n)
{
struct address_space *mapping = dir->i_mapping;
- struct page *page = read_cache_page(mapping, n,
- (filler_t*)mapping->a_ops->readpage, NULL);
+ struct page *page = read_mapping_page(mapping, n, NULL);
if (!IS_ERR(page)) {
wait_on_page_locked(page);
kmap(page);
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 3ff89cc..58b2d22 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -85,8 +85,9 @@ static void sysv_put_super(struct super_block *sb)
kfree(sbi);
}
-static int sysv_statfs(struct super_block *sb, struct kstatfs *buf)
+static int sysv_statfs(struct dentry *dentry, struct kstatfs *buf)
{
+ struct super_block *sb = dentry->d_sb;
struct sysv_sb_info *sbi = SYSV_SB(sb);
buf->f_type = sb->s_magic;
diff --git a/fs/sysv/super.c b/fs/sysv/super.c
index e92b991..876639b 100644
--- a/fs/sysv/super.c
+++ b/fs/sysv/super.c
@@ -506,16 +506,17 @@ failed:
/* Every kernel module contains stuff like this. */
-static struct super_block *sysv_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int sysv_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, sysv_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, sysv_fill_super,
+ mnt);
}
-static struct super_block *v7_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int v7_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, v7_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, v7_fill_super, mnt);
}
static struct file_system_type sysv_fs_type = {
diff --git a/fs/udf/super.c b/fs/udf/super.c
index e45789f..44fe2cb 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -91,13 +91,13 @@ static void udf_load_partdesc(struct super_block *, struct buffer_head *);
static void udf_open_lvid(struct super_block *);
static void udf_close_lvid(struct super_block *);
static unsigned int udf_count_free(struct super_block *);
-static int udf_statfs(struct super_block *, struct kstatfs *);
+static int udf_statfs(struct dentry *, struct kstatfs *);
/* UDF filesystem type */
-static struct super_block *udf_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int udf_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, udf_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, udf_fill_super, mnt);
}
static struct file_system_type udf_fstype = {
@@ -1779,8 +1779,10 @@ udf_put_super(struct super_block *sb)
* Written, tested, and released.
*/
static int
-udf_statfs(struct super_block *sb, struct kstatfs *buf)
+udf_statfs(struct dentry *dentry, struct kstatfs *buf)
{
+ struct super_block *sb = dentry->d_sb;
+
buf->f_type = UDF_SUPER_MAGIC;
buf->f_bsize = sb->s_blocksize;
buf->f_blocks = UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb));
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c
index 3ada9dc..95b878e 100644
--- a/fs/ufs/balloc.c
+++ b/fs/ufs/balloc.c
@@ -21,14 +21,6 @@
#include "swab.h"
#include "util.h"
-#undef UFS_BALLOC_DEBUG
-
-#ifdef UFS_BALLOC_DEBUG
-#define UFSD(x) printk("(%s, %d), %s:", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
static unsigned ufs_add_fragments (struct inode *, unsigned, unsigned, unsigned, int *);
static unsigned ufs_alloc_fragments (struct inode *, unsigned, unsigned, unsigned, int *);
static unsigned ufs_alloccg_block (struct inode *, struct ufs_cg_private_info *, unsigned, int *);
@@ -39,7 +31,8 @@ static void ufs_clusteracct(struct super_block *, struct ufs_cg_private_info *,
/*
* Free 'count' fragments from fragment number 'fragment'
*/
-void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count) {
+void ufs_free_fragments(struct inode *inode, unsigned fragment, unsigned count)
+{
struct super_block * sb;
struct ufs_sb_private_info * uspi;
struct ufs_super_block_first * usb1;
@@ -51,7 +44,7 @@ void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count
uspi = UFS_SB(sb)->s_uspi;
usb1 = ubh_get_usb_first(uspi);
- UFSD(("ENTER, fragment %u, count %u\n", fragment, count))
+ UFSD("ENTER, fragment %u, count %u\n", fragment, count);
if (ufs_fragnum(fragment) + count > uspi->s_fpg)
ufs_error (sb, "ufs_free_fragments", "internal error");
@@ -68,7 +61,7 @@ void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count
ucpi = ufs_load_cylinder (sb, cgno);
if (!ucpi)
goto failed;
- ucg = ubh_get_ucg (UCPI_UBH);
+ ucg = ubh_get_ucg (UCPI_UBH(ucpi));
if (!ufs_cg_chkmagic(sb, ucg)) {
ufs_panic (sb, "ufs_free_fragments", "internal error, bad magic number on cg %u", cgno);
goto failed;
@@ -76,11 +69,11 @@ void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count
end_bit = bit + count;
bbase = ufs_blknum (bit);
- blkmap = ubh_blkmap (UCPI_UBH, ucpi->c_freeoff, bbase);
+ blkmap = ubh_blkmap (UCPI_UBH(ucpi), ucpi->c_freeoff, bbase);
ufs_fragacct (sb, blkmap, ucg->cg_frsum, -1);
for (i = bit; i < end_bit; i++) {
- if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, i))
- ubh_setbit (UCPI_UBH, ucpi->c_freeoff, i);
+ if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, i))
+ ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, i);
else
ufs_error (sb, "ufs_free_fragments",
"bit already cleared for fragment %u", i);
@@ -90,51 +83,52 @@ void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count
fs32_add(sb, &ucg->cg_cs.cs_nffree, count);
- fs32_add(sb, &usb1->fs_cstotal.cs_nffree, count);
+ uspi->cs_total.cs_nffree += count;
fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
- blkmap = ubh_blkmap (UCPI_UBH, ucpi->c_freeoff, bbase);
+ blkmap = ubh_blkmap (UCPI_UBH(ucpi), ucpi->c_freeoff, bbase);
ufs_fragacct(sb, blkmap, ucg->cg_frsum, 1);
/*
* Trying to reassemble free fragments into block
*/
blkno = ufs_fragstoblks (bbase);
- if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, blkno)) {
+ if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
fs32_sub(sb, &ucg->cg_cs.cs_nffree, uspi->s_fpb);
- fs32_sub(sb, &usb1->fs_cstotal.cs_nffree, uspi->s_fpb);
+ uspi->cs_total.cs_nffree -= uspi->s_fpb;
fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, uspi->s_fpb);
if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
ufs_clusteracct (sb, ucpi, blkno, 1);
fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
- fs32_add(sb, &usb1->fs_cstotal.cs_nbfree, 1);
+ uspi->cs_total.cs_nbfree++;
fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1);
cylno = ufs_cbtocylno (bbase);
fs16_add(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(bbase)), 1);
fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1);
}
- ubh_mark_buffer_dirty (USPI_UBH);
- ubh_mark_buffer_dirty (UCPI_UBH);
+ ubh_mark_buffer_dirty (USPI_UBH(uspi));
+ ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
if (sb->s_flags & MS_SYNCHRONOUS) {
- ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi);
- ubh_wait_on_buffer (UCPI_UBH);
+ ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
+ ubh_wait_on_buffer (UCPI_UBH(ucpi));
}
sb->s_dirt = 1;
unlock_super (sb);
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
return;
failed:
unlock_super (sb);
- UFSD(("EXIT (FAILED)\n"))
+ UFSD("EXIT (FAILED)\n");
return;
}
/*
* Free 'count' fragments from fragment number 'fragment' (free whole blocks)
*/
-void ufs_free_blocks (struct inode * inode, unsigned fragment, unsigned count) {
+void ufs_free_blocks(struct inode *inode, unsigned fragment, unsigned count)
+{
struct super_block * sb;
struct ufs_sb_private_info * uspi;
struct ufs_super_block_first * usb1;
@@ -146,7 +140,7 @@ void ufs_free_blocks (struct inode * inode, unsigned fragment, unsigned count) {
uspi = UFS_SB(sb)->s_uspi;
usb1 = ubh_get_usb_first(uspi);
- UFSD(("ENTER, fragment %u, count %u\n", fragment, count))
+ UFSD("ENTER, fragment %u, count %u\n", fragment, count);
if ((fragment & uspi->s_fpbmask) || (count & uspi->s_fpbmask)) {
ufs_error (sb, "ufs_free_blocks", "internal error, "
@@ -162,7 +156,7 @@ do_more:
bit = ufs_dtogd (fragment);
if (cgno >= uspi->s_ncg) {
ufs_panic (sb, "ufs_free_blocks", "freeing blocks are outside device");
- goto failed;
+ goto failed_unlock;
}
end_bit = bit + count;
if (end_bit > uspi->s_fpg) {
@@ -173,36 +167,36 @@ do_more:
ucpi = ufs_load_cylinder (sb, cgno);
if (!ucpi)
- goto failed;
- ucg = ubh_get_ucg (UCPI_UBH);
+ goto failed_unlock;
+ ucg = ubh_get_ucg (UCPI_UBH(ucpi));
if (!ufs_cg_chkmagic(sb, ucg)) {
ufs_panic (sb, "ufs_free_blocks", "internal error, bad magic number on cg %u", cgno);
- goto failed;
+ goto failed_unlock;
}
for (i = bit; i < end_bit; i += uspi->s_fpb) {
blkno = ufs_fragstoblks(i);
- if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, blkno)) {
+ if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
ufs_error(sb, "ufs_free_blocks", "freeing free fragment");
}
- ubh_setblock(UCPI_UBH, ucpi->c_freeoff, blkno);
+ ubh_setblock(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
ufs_clusteracct (sb, ucpi, blkno, 1);
DQUOT_FREE_BLOCK(inode, uspi->s_fpb);
fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
- fs32_add(sb, &usb1->fs_cstotal.cs_nbfree, 1);
+ uspi->cs_total.cs_nbfree++;
fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1);
cylno = ufs_cbtocylno(i);
fs16_add(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(i)), 1);
fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1);
}
- ubh_mark_buffer_dirty (USPI_UBH);
- ubh_mark_buffer_dirty (UCPI_UBH);
+ ubh_mark_buffer_dirty (USPI_UBH(uspi));
+ ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
if (sb->s_flags & MS_SYNCHRONOUS) {
- ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi);
- ubh_wait_on_buffer (UCPI_UBH);
+ ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
+ ubh_wait_on_buffer (UCPI_UBH(ucpi));
}
if (overflow) {
@@ -213,38 +207,127 @@ do_more:
sb->s_dirt = 1;
unlock_super (sb);
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
return;
-failed:
+failed_unlock:
unlock_super (sb);
- UFSD(("EXIT (FAILED)\n"))
+failed:
+ UFSD("EXIT (FAILED)\n");
return;
}
+static struct page *ufs_get_locked_page(struct address_space *mapping,
+ unsigned long index)
+{
+ struct page *page;
+
+try_again:
+ page = find_lock_page(mapping, index);
+ if (!page) {
+ page = read_cache_page(mapping, index,
+ (filler_t*)mapping->a_ops->readpage,
+ NULL);
+ if (IS_ERR(page)) {
+ printk(KERN_ERR "ufs_change_blocknr: "
+ "read_cache_page error: ino %lu, index: %lu\n",
+ mapping->host->i_ino, index);
+ goto out;
+ }
+ lock_page(page);
-#define NULLIFY_FRAGMENTS \
- for (i = oldcount; i < newcount; i++) { \
- bh = sb_getblk(sb, result + i); \
- memset (bh->b_data, 0, sb->s_blocksize); \
- set_buffer_uptodate(bh); \
- mark_buffer_dirty (bh); \
- if (IS_SYNC(inode)) \
- sync_dirty_buffer(bh); \
- brelse (bh); \
+ if (!PageUptodate(page) || PageError(page)) {
+ unlock_page(page);
+ page_cache_release(page);
+
+ printk(KERN_ERR "ufs_change_blocknr: "
+ "can not read page: ino %lu, index: %lu\n",
+ mapping->host->i_ino, index);
+
+ page = ERR_PTR(-EIO);
+ goto out;
+ }
}
-unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment,
- unsigned goal, unsigned count, int * err )
+ if (unlikely(!page->mapping || !page_has_buffers(page))) {
+ unlock_page(page);
+ page_cache_release(page);
+ goto try_again;/*we really need these buffers*/
+ }
+out:
+ return page;
+}
+
+/*
+ * Modify inode page cache in such way:
+ * have - blocks with b_blocknr equal to oldb...oldb+count-1
+ * get - blocks with b_blocknr equal to newb...newb+count-1
+ * also we suppose that oldb...oldb+count-1 blocks
+ * situated at the end of file.
+ *
+ * We can come here from ufs_writepage or ufs_prepare_write,
+ * locked_page is argument of these functions, so we already lock it.
+ */
+static void ufs_change_blocknr(struct inode *inode, unsigned int baseblk,
+ unsigned int count, unsigned int oldb,
+ unsigned int newb, struct page *locked_page)
+{
+ unsigned int blk_per_page = 1 << (PAGE_CACHE_SHIFT - inode->i_blkbits);
+ struct address_space *mapping = inode->i_mapping;
+ pgoff_t index, cur_index = locked_page->index;
+ unsigned int i, j;
+ struct page *page;
+ struct buffer_head *head, *bh;
+
+ UFSD("ENTER, ino %lu, count %u, oldb %u, newb %u\n",
+ inode->i_ino, count, oldb, newb);
+
+ BUG_ON(!PageLocked(locked_page));
+
+ for (i = 0; i < count; i += blk_per_page) {
+ index = (baseblk+i) >> (PAGE_CACHE_SHIFT - inode->i_blkbits);
+
+ if (likely(cur_index != index)) {
+ page = ufs_get_locked_page(mapping, index);
+ if (IS_ERR(page))
+ continue;
+ } else
+ page = locked_page;
+
+ j = i;
+ head = page_buffers(page);
+ bh = head;
+ do {
+ if (likely(bh->b_blocknr == j + oldb && j < count)) {
+ unmap_underlying_metadata(bh->b_bdev,
+ bh->b_blocknr);
+ bh->b_blocknr = newb + j++;
+ mark_buffer_dirty(bh);
+ }
+
+ bh = bh->b_this_page;
+ } while (bh != head);
+
+ set_page_dirty(page);
+
+ if (likely(cur_index != index)) {
+ unlock_page(page);
+ page_cache_release(page);
+ }
+ }
+ UFSD("EXIT\n");
+}
+
+unsigned ufs_new_fragments(struct inode * inode, __fs32 * p, unsigned fragment,
+ unsigned goal, unsigned count, int * err, struct page *locked_page)
{
struct super_block * sb;
struct ufs_sb_private_info * uspi;
struct ufs_super_block_first * usb1;
- struct buffer_head * bh;
- unsigned cgno, oldcount, newcount, tmp, request, i, result;
+ unsigned cgno, oldcount, newcount, tmp, request, result;
- UFSD(("ENTER, ino %lu, fragment %u, goal %u, count %u\n", inode->i_ino, fragment, goal, count))
+ UFSD("ENTER, ino %lu, fragment %u, goal %u, count %u\n", inode->i_ino, fragment, goal, count);
sb = inode->i_sb;
uspi = UFS_SB(sb)->s_uspi;
@@ -273,14 +356,14 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment,
return (unsigned)-1;
}
if (fragment < UFS_I(inode)->i_lastfrag) {
- UFSD(("EXIT (ALREADY ALLOCATED)\n"))
+ UFSD("EXIT (ALREADY ALLOCATED)\n");
unlock_super (sb);
return 0;
}
}
else {
if (tmp) {
- UFSD(("EXIT (ALREADY ALLOCATED)\n"))
+ UFSD("EXIT (ALREADY ALLOCATED)\n");
unlock_super(sb);
return 0;
}
@@ -289,9 +372,9 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment,
/*
* There is not enough space for user on the device
*/
- if (!capable(CAP_SYS_RESOURCE) && ufs_freespace(usb1, UFS_MINFREE) <= 0) {
+ if (!capable(CAP_SYS_RESOURCE) && ufs_freespace(uspi, UFS_MINFREE) <= 0) {
unlock_super (sb);
- UFSD(("EXIT (FAILED)\n"))
+ UFSD("EXIT (FAILED)\n");
return 0;
}
@@ -310,12 +393,10 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment,
if (result) {
*p = cpu_to_fs32(sb, result);
*err = 0;
- inode->i_blocks += count << uspi->s_nspfshift;
UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
- NULLIFY_FRAGMENTS
}
unlock_super(sb);
- UFSD(("EXIT, result %u\n", result))
+ UFSD("EXIT, result %u\n", result);
return result;
}
@@ -325,11 +406,9 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment,
result = ufs_add_fragments (inode, tmp, oldcount, newcount, err);
if (result) {
*err = 0;
- inode->i_blocks += count << uspi->s_nspfshift;
UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
- NULLIFY_FRAGMENTS
unlock_super(sb);
- UFSD(("EXIT, result %u\n", result))
+ UFSD("EXIT, result %u\n", result);
return result;
}
@@ -339,8 +418,8 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment,
switch (fs32_to_cpu(sb, usb1->fs_optim)) {
case UFS_OPTSPACE:
request = newcount;
- if (uspi->s_minfree < 5 || fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree)
- > uspi->s_dsize * uspi->s_minfree / (2 * 100) )
+ if (uspi->s_minfree < 5 || uspi->cs_total.cs_nffree
+ > uspi->s_dsize * uspi->s_minfree / (2 * 100))
break;
usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
break;
@@ -349,7 +428,7 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment,
case UFS_OPTTIME:
request = uspi->s_fpb;
- if (fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree) < uspi->s_dsize *
+ if (uspi->cs_total.cs_nffree < uspi->s_dsize *
(uspi->s_minfree - 2) / 100)
break;
usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
@@ -357,39 +436,22 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment,
}
result = ufs_alloc_fragments (inode, cgno, goal, request, err);
if (result) {
- for (i = 0; i < oldcount; i++) {
- bh = sb_bread(sb, tmp + i);
- if(bh)
- {
- clear_buffer_dirty(bh);
- bh->b_blocknr = result + i;
- mark_buffer_dirty (bh);
- if (IS_SYNC(inode))
- sync_dirty_buffer(bh);
- brelse (bh);
- }
- else
- {
- printk(KERN_ERR "ufs_new_fragments: bread fail\n");
- unlock_super(sb);
- return 0;
- }
- }
+ ufs_change_blocknr(inode, fragment - oldcount, oldcount, tmp,
+ result, locked_page);
+
*p = cpu_to_fs32(sb, result);
*err = 0;
- inode->i_blocks += count << uspi->s_nspfshift;
UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
- NULLIFY_FRAGMENTS
unlock_super(sb);
if (newcount < request)
ufs_free_fragments (inode, result + newcount, request - newcount);
ufs_free_fragments (inode, tmp, oldcount);
- UFSD(("EXIT, result %u\n", result))
+ UFSD("EXIT, result %u\n", result);
return result;
}
unlock_super(sb);
- UFSD(("EXIT (FAILED)\n"))
+ UFSD("EXIT (FAILED)\n");
return 0;
}
@@ -404,7 +466,7 @@ ufs_add_fragments (struct inode * inode, unsigned fragment,
struct ufs_cylinder_group * ucg;
unsigned cgno, fragno, fragoff, count, fragsize, i;
- UFSD(("ENTER, fragment %u, oldcount %u, newcount %u\n", fragment, oldcount, newcount))
+ UFSD("ENTER, fragment %u, oldcount %u, newcount %u\n", fragment, oldcount, newcount);
sb = inode->i_sb;
uspi = UFS_SB(sb)->s_uspi;
@@ -419,7 +481,7 @@ ufs_add_fragments (struct inode * inode, unsigned fragment,
ucpi = ufs_load_cylinder (sb, cgno);
if (!ucpi)
return 0;
- ucg = ubh_get_ucg (UCPI_UBH);
+ ucg = ubh_get_ucg (UCPI_UBH(ucpi));
if (!ufs_cg_chkmagic(sb, ucg)) {
ufs_panic (sb, "ufs_add_fragments",
"internal error, bad magic number on cg %u", cgno);
@@ -429,14 +491,14 @@ ufs_add_fragments (struct inode * inode, unsigned fragment,
fragno = ufs_dtogd (fragment);
fragoff = ufs_fragnum (fragno);
for (i = oldcount; i < newcount; i++)
- if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, fragno + i))
+ if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
return 0;
/*
* Block can be extended
*/
ucg->cg_time = cpu_to_fs32(sb, get_seconds());
for (i = newcount; i < (uspi->s_fpb - fragoff); i++)
- if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, fragno + i))
+ if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
break;
fragsize = i - oldcount;
if (!fs32_to_cpu(sb, ucg->cg_frsum[fragsize]))
@@ -446,7 +508,7 @@ ufs_add_fragments (struct inode * inode, unsigned fragment,
if (fragsize != count)
fs32_add(sb, &ucg->cg_frsum[fragsize - count], 1);
for (i = oldcount; i < newcount; i++)
- ubh_clrbit (UCPI_UBH, ucpi->c_freeoff, fragno + i);
+ ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i);
if(DQUOT_ALLOC_BLOCK(inode, count)) {
*err = -EDQUOT;
return 0;
@@ -454,17 +516,17 @@ ufs_add_fragments (struct inode * inode, unsigned fragment,
fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
- fs32_sub(sb, &usb1->fs_cstotal.cs_nffree, count);
+ uspi->cs_total.cs_nffree -= count;
- ubh_mark_buffer_dirty (USPI_UBH);
- ubh_mark_buffer_dirty (UCPI_UBH);
+ ubh_mark_buffer_dirty (USPI_UBH(uspi));
+ ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
if (sb->s_flags & MS_SYNCHRONOUS) {
- ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi);
- ubh_wait_on_buffer (UCPI_UBH);
+ ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
+ ubh_wait_on_buffer (UCPI_UBH(ucpi));
}
sb->s_dirt = 1;
- UFSD(("EXIT, fragment %u\n", fragment))
+ UFSD("EXIT, fragment %u\n", fragment);
return fragment;
}
@@ -487,7 +549,7 @@ static unsigned ufs_alloc_fragments (struct inode * inode, unsigned cgno,
struct ufs_cylinder_group * ucg;
unsigned oldcg, i, j, k, result, allocsize;
- UFSD(("ENTER, ino %lu, cgno %u, goal %u, count %u\n", inode->i_ino, cgno, goal, count))
+ UFSD("ENTER, ino %lu, cgno %u, goal %u, count %u\n", inode->i_ino, cgno, goal, count);
sb = inode->i_sb;
uspi = UFS_SB(sb)->s_uspi;
@@ -521,14 +583,14 @@ static unsigned ufs_alloc_fragments (struct inode * inode, unsigned cgno,
UFS_TEST_FREE_SPACE_CG
}
- UFSD(("EXIT (FAILED)\n"))
+ UFSD("EXIT (FAILED)\n");
return 0;
cg_found:
ucpi = ufs_load_cylinder (sb, cgno);
if (!ucpi)
return 0;
- ucg = ubh_get_ucg (UCPI_UBH);
+ ucg = ubh_get_ucg (UCPI_UBH(ucpi));
if (!ufs_cg_chkmagic(sb, ucg))
ufs_panic (sb, "ufs_alloc_fragments",
"internal error, bad magic number on cg %u", cgno);
@@ -551,12 +613,12 @@ cg_found:
return 0;
goal = ufs_dtogd (result);
for (i = count; i < uspi->s_fpb; i++)
- ubh_setbit (UCPI_UBH, ucpi->c_freeoff, goal + i);
+ ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i);
i = uspi->s_fpb - count;
DQUOT_FREE_BLOCK(inode, i);
fs32_add(sb, &ucg->cg_cs.cs_nffree, i);
- fs32_add(sb, &usb1->fs_cstotal.cs_nffree, i);
+ uspi->cs_total.cs_nffree += i;
fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, i);
fs32_add(sb, &ucg->cg_frsum[i], 1);
goto succed;
@@ -570,10 +632,10 @@ cg_found:
return 0;
}
for (i = 0; i < count; i++)
- ubh_clrbit (UCPI_UBH, ucpi->c_freeoff, result + i);
+ ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, result + i);
fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
- fs32_sub(sb, &usb1->fs_cstotal.cs_nffree, count);
+ uspi->cs_total.cs_nffree -= count;
fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
fs32_sub(sb, &ucg->cg_frsum[allocsize], 1);
@@ -581,16 +643,16 @@ cg_found:
fs32_add(sb, &ucg->cg_frsum[allocsize - count], 1);
succed:
- ubh_mark_buffer_dirty (USPI_UBH);
- ubh_mark_buffer_dirty (UCPI_UBH);
+ ubh_mark_buffer_dirty (USPI_UBH(uspi));
+ ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
if (sb->s_flags & MS_SYNCHRONOUS) {
- ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi);
- ubh_wait_on_buffer (UCPI_UBH);
+ ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
+ ubh_wait_on_buffer (UCPI_UBH(ucpi));
}
sb->s_dirt = 1;
result += cgno * uspi->s_fpg;
- UFSD(("EXIT3, result %u\n", result))
+ UFSD("EXIT3, result %u\n", result);
return result;
}
@@ -603,12 +665,12 @@ static unsigned ufs_alloccg_block (struct inode * inode,
struct ufs_cylinder_group * ucg;
unsigned result, cylno, blkno;
- UFSD(("ENTER, goal %u\n", goal))
+ UFSD("ENTER, goal %u\n", goal);
sb = inode->i_sb;
uspi = UFS_SB(sb)->s_uspi;
usb1 = ubh_get_usb_first(uspi);
- ucg = ubh_get_ucg(UCPI_UBH);
+ ucg = ubh_get_ucg(UCPI_UBH(ucpi));
if (goal == 0) {
goal = ucpi->c_rotor;
@@ -620,7 +682,7 @@ static unsigned ufs_alloccg_block (struct inode * inode,
/*
* If the requested block is available, use it.
*/
- if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, ufs_fragstoblks(goal))) {
+ if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, ufs_fragstoblks(goal))) {
result = goal;
goto gotit;
}
@@ -632,7 +694,7 @@ norot:
ucpi->c_rotor = result;
gotit:
blkno = ufs_fragstoblks(result);
- ubh_clrblock (UCPI_UBH, ucpi->c_freeoff, blkno);
+ ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
ufs_clusteracct (sb, ucpi, blkno, -1);
if(DQUOT_ALLOC_BLOCK(inode, uspi->s_fpb)) {
@@ -641,31 +703,76 @@ gotit:
}
fs32_sub(sb, &ucg->cg_cs.cs_nbfree, 1);
- fs32_sub(sb, &usb1->fs_cstotal.cs_nbfree, 1);
+ uspi->cs_total.cs_nbfree--;
fs32_sub(sb, &UFS_SB(sb)->fs_cs(ucpi->c_cgx).cs_nbfree, 1);
cylno = ufs_cbtocylno(result);
fs16_sub(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(result)), 1);
fs32_sub(sb, &ubh_cg_blktot(ucpi, cylno), 1);
- UFSD(("EXIT, result %u\n", result))
+ UFSD("EXIT, result %u\n", result);
return result;
}
-static unsigned ufs_bitmap_search (struct super_block * sb,
- struct ufs_cg_private_info * ucpi, unsigned goal, unsigned count)
+static unsigned ubh_scanc(struct ufs_sb_private_info *uspi,
+ struct ufs_buffer_head *ubh,
+ unsigned begin, unsigned size,
+ unsigned char *table, unsigned char mask)
{
- struct ufs_sb_private_info * uspi;
- struct ufs_super_block_first * usb1;
- struct ufs_cylinder_group * ucg;
- unsigned start, length, location, result;
- unsigned possition, fragsize, blockmap, mask;
-
- UFSD(("ENTER, cg %u, goal %u, count %u\n", ucpi->c_cgx, goal, count))
+ unsigned rest, offset;
+ unsigned char *cp;
+
+
+ offset = begin & ~uspi->s_fmask;
+ begin >>= uspi->s_fshift;
+ for (;;) {
+ if ((offset + size) < uspi->s_fsize)
+ rest = size;
+ else
+ rest = uspi->s_fsize - offset;
+ size -= rest;
+ cp = ubh->bh[begin]->b_data + offset;
+ while ((table[*cp++] & mask) == 0 && --rest)
+ ;
+ if (rest || !size)
+ break;
+ begin++;
+ offset = 0;
+ }
+ return (size + rest);
+}
+
+/*
+ * Find a block of the specified size in the specified cylinder group.
+ * @sp: pointer to super block
+ * @ucpi: pointer to cylinder group info
+ * @goal: near which block we want find new one
+ * @count: specified size
+ */
+static unsigned ufs_bitmap_search(struct super_block *sb,
+ struct ufs_cg_private_info *ucpi,
+ unsigned goal, unsigned count)
+{
+ /*
+ * Bit patterns for identifying fragments in the block map
+ * used as ((map & mask_arr) == want_arr)
+ */
+ static const int mask_arr[9] = {
+ 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff
+ };
+ static const int want_arr[9] = {
+ 0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe
+ };
+ struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
+ struct ufs_super_block_first *usb1;
+ struct ufs_cylinder_group *ucg;
+ unsigned start, length, loc, result;
+ unsigned pos, want, blockmap, mask, end;
+
+ UFSD("ENTER, cg %u, goal %u, count %u\n", ucpi->c_cgx, goal, count);
- uspi = UFS_SB(sb)->s_uspi;
usb1 = ubh_get_usb_first (uspi);
- ucg = ubh_get_ucg(UCPI_UBH);
+ ucg = ubh_get_ucg(UCPI_UBH(ucpi));
if (goal)
start = ufs_dtogd(goal) >> 3;
@@ -673,53 +780,50 @@ static unsigned ufs_bitmap_search (struct super_block * sb,
start = ucpi->c_frotor >> 3;
length = ((uspi->s_fpg + 7) >> 3) - start;
- location = ubh_scanc(UCPI_UBH, ucpi->c_freeoff + start, length,
+ loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff + start, length,
(uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other,
1 << (count - 1 + (uspi->s_fpb & 7)));
- if (location == 0) {
+ if (loc == 0) {
length = start + 1;
- location = ubh_scanc(UCPI_UBH, ucpi->c_freeoff, length,
- (uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other,
- 1 << (count - 1 + (uspi->s_fpb & 7)));
- if (location == 0) {
- ufs_error (sb, "ufs_bitmap_search",
- "bitmap corrupted on cg %u, start %u, length %u, count %u, freeoff %u\n",
- ucpi->c_cgx, start, length, count, ucpi->c_freeoff);
+ loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff, length,
+ (uspi->s_fpb == 8) ? ufs_fragtable_8fpb :
+ ufs_fragtable_other,
+ 1 << (count - 1 + (uspi->s_fpb & 7)));
+ if (loc == 0) {
+ ufs_error(sb, "ufs_bitmap_search",
+ "bitmap corrupted on cg %u, start %u,"
+ " length %u, count %u, freeoff %u\n",
+ ucpi->c_cgx, start, length, count,
+ ucpi->c_freeoff);
return (unsigned)-1;
}
start = 0;
}
- result = (start + length - location) << 3;
+ result = (start + length - loc) << 3;
ucpi->c_frotor = result;
/*
* found the byte in the map
*/
- blockmap = ubh_blkmap(UCPI_UBH, ucpi->c_freeoff, result);
- fragsize = 0;
- for (possition = 0, mask = 1; possition < 8; possition++, mask <<= 1) {
- if (blockmap & mask) {
- if (!(possition & uspi->s_fpbmask))
- fragsize = 1;
- else
- fragsize++;
- }
- else {
- if (fragsize == count) {
- result += possition - count;
- UFSD(("EXIT, result %u\n", result))
- return result;
- }
- fragsize = 0;
- }
- }
- if (fragsize == count) {
- result += possition - count;
- UFSD(("EXIT, result %u\n", result))
- return result;
- }
- ufs_error (sb, "ufs_bitmap_search", "block not in map on cg %u\n", ucpi->c_cgx);
- UFSD(("EXIT (FAILED)\n"))
+
+ for (end = result + 8; result < end; result += uspi->s_fpb) {
+ blockmap = ubh_blkmap(UCPI_UBH(ucpi), ucpi->c_freeoff, result);
+ blockmap <<= 1;
+ mask = mask_arr[count];
+ want = want_arr[count];
+ for (pos = 0; pos <= uspi->s_fpb - count; pos++) {
+ if ((blockmap & mask) == want) {
+ UFSD("EXIT, result %u\n", result);
+ return result + pos;
+ }
+ mask <<= 1;
+ want <<= 1;
+ }
+ }
+
+ ufs_error(sb, "ufs_bitmap_search", "block not in map on cg %u\n",
+ ucpi->c_cgx);
+ UFSD("EXIT (FAILED)\n");
return (unsigned)-1;
}
@@ -734,9 +838,9 @@ static void ufs_clusteracct(struct super_block * sb,
return;
if (cnt > 0)
- ubh_setbit(UCPI_UBH, ucpi->c_clusteroff, blkno);
+ ubh_setbit(UCPI_UBH(ucpi), ucpi->c_clusteroff, blkno);
else
- ubh_clrbit(UCPI_UBH, ucpi->c_clusteroff, blkno);
+ ubh_clrbit(UCPI_UBH(ucpi), ucpi->c_clusteroff, blkno);
/*
* Find the size of the cluster going forward.
@@ -745,7 +849,7 @@ static void ufs_clusteracct(struct super_block * sb,
end = start + uspi->s_contigsumsize;
if ( end >= ucpi->c_nclusterblks)
end = ucpi->c_nclusterblks;
- i = ubh_find_next_zero_bit (UCPI_UBH, ucpi->c_clusteroff, end, start);
+ i = ubh_find_next_zero_bit (UCPI_UBH(ucpi), ucpi->c_clusteroff, end, start);
if (i > end)
i = end;
forw = i - start;
@@ -757,7 +861,7 @@ static void ufs_clusteracct(struct super_block * sb,
end = start - uspi->s_contigsumsize;
if (end < 0 )
end = -1;
- i = ubh_find_last_zero_bit (UCPI_UBH, ucpi->c_clusteroff, start, end);
+ i = ubh_find_last_zero_bit (UCPI_UBH(ucpi), ucpi->c_clusteroff, start, end);
if ( i < end)
i = end;
back = start - i;
@@ -769,11 +873,11 @@ static void ufs_clusteracct(struct super_block * sb,
i = back + forw + 1;
if (i > uspi->s_contigsumsize)
i = uspi->s_contigsumsize;
- fs32_add(sb, (__fs32*)ubh_get_addr(UCPI_UBH, ucpi->c_clustersumoff + (i << 2)), cnt);
+ fs32_add(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (i << 2)), cnt);
if (back > 0)
- fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH, ucpi->c_clustersumoff + (back << 2)), cnt);
+ fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (back << 2)), cnt);
if (forw > 0)
- fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH, ucpi->c_clustersumoff + (forw << 2)), cnt);
+ fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (forw << 2)), cnt);
}
diff --git a/fs/ufs/cylinder.c b/fs/ufs/cylinder.c
index 14abb8b..09c39e5 100644
--- a/fs/ufs/cylinder.c
+++ b/fs/ufs/cylinder.c
@@ -20,15 +20,6 @@
#include "swab.h"
#include "util.h"
-#undef UFS_CYLINDER_DEBUG
-
-#ifdef UFS_CYLINDER_DEBUG
-#define UFSD(x) printk("(%s, %d), %s:", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
-
/*
* Read cylinder group into cache. The memory space for ufs_cg_private_info
* structure is already allocated during ufs_read_super.
@@ -42,19 +33,19 @@ static void ufs_read_cylinder (struct super_block * sb,
struct ufs_cylinder_group * ucg;
unsigned i, j;
- UFSD(("ENTER, cgno %u, bitmap_nr %u\n", cgno, bitmap_nr))
+ UFSD("ENTER, cgno %u, bitmap_nr %u\n", cgno, bitmap_nr);
uspi = sbi->s_uspi;
ucpi = sbi->s_ucpi[bitmap_nr];
ucg = (struct ufs_cylinder_group *)sbi->s_ucg[cgno]->b_data;
- UCPI_UBH->fragment = ufs_cgcmin(cgno);
- UCPI_UBH->count = uspi->s_cgsize >> sb->s_blocksize_bits;
+ UCPI_UBH(ucpi)->fragment = ufs_cgcmin(cgno);
+ UCPI_UBH(ucpi)->count = uspi->s_cgsize >> sb->s_blocksize_bits;
/*
* We have already the first fragment of cylinder group block in buffer
*/
- UCPI_UBH->bh[0] = sbi->s_ucg[cgno];
- for (i = 1; i < UCPI_UBH->count; i++)
- if (!(UCPI_UBH->bh[i] = sb_bread(sb, UCPI_UBH->fragment + i)))
+ UCPI_UBH(ucpi)->bh[0] = sbi->s_ucg[cgno];
+ for (i = 1; i < UCPI_UBH(ucpi)->count; i++)
+ if (!(UCPI_UBH(ucpi)->bh[i] = sb_bread(sb, UCPI_UBH(ucpi)->fragment + i)))
goto failed;
sbi->s_cgno[bitmap_nr] = cgno;
@@ -73,7 +64,7 @@ static void ufs_read_cylinder (struct super_block * sb,
ucpi->c_clustersumoff = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_clustersumoff);
ucpi->c_clusteroff = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_clusteroff);
ucpi->c_nclusterblks = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_nclusterblks);
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
return;
failed:
@@ -95,15 +86,15 @@ void ufs_put_cylinder (struct super_block * sb, unsigned bitmap_nr)
struct ufs_cylinder_group * ucg;
unsigned i;
- UFSD(("ENTER, bitmap_nr %u\n", bitmap_nr))
+ UFSD("ENTER, bitmap_nr %u\n", bitmap_nr);
uspi = sbi->s_uspi;
if (sbi->s_cgno[bitmap_nr] == UFS_CGNO_EMPTY) {
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
return;
}
ucpi = sbi->s_ucpi[bitmap_nr];
- ucg = ubh_get_ucg(UCPI_UBH);
+ ucg = ubh_get_ucg(UCPI_UBH(ucpi));
if (uspi->s_ncg > UFS_MAX_GROUP_LOADED && bitmap_nr >= sbi->s_cg_loaded) {
ufs_panic (sb, "ufs_put_cylinder", "internal error");
@@ -116,13 +107,13 @@ void ufs_put_cylinder (struct super_block * sb, unsigned bitmap_nr)
ucg->cg_rotor = cpu_to_fs32(sb, ucpi->c_rotor);
ucg->cg_frotor = cpu_to_fs32(sb, ucpi->c_frotor);
ucg->cg_irotor = cpu_to_fs32(sb, ucpi->c_irotor);
- ubh_mark_buffer_dirty (UCPI_UBH);
- for (i = 1; i < UCPI_UBH->count; i++) {
- brelse (UCPI_UBH->bh[i]);
+ ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
+ for (i = 1; i < UCPI_UBH(ucpi)->count; i++) {
+ brelse (UCPI_UBH(ucpi)->bh[i]);
}
sbi->s_cgno[bitmap_nr] = UFS_CGNO_EMPTY;
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
}
/*
@@ -139,7 +130,7 @@ struct ufs_cg_private_info * ufs_load_cylinder (
struct ufs_cg_private_info * ucpi;
unsigned cg, i, j;
- UFSD(("ENTER, cgno %u\n", cgno))
+ UFSD("ENTER, cgno %u\n", cgno);
uspi = sbi->s_uspi;
if (cgno >= uspi->s_ncg) {
@@ -150,7 +141,7 @@ struct ufs_cg_private_info * ufs_load_cylinder (
* Cylinder group number cg it in cache and it was last used
*/
if (sbi->s_cgno[0] == cgno) {
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
return sbi->s_ucpi[0];
}
/*
@@ -160,16 +151,16 @@ struct ufs_cg_private_info * ufs_load_cylinder (
if (sbi->s_cgno[cgno] != UFS_CGNO_EMPTY) {
if (sbi->s_cgno[cgno] != cgno) {
ufs_panic (sb, "ufs_load_cylinder", "internal error, wrong number of cg in cache");
- UFSD(("EXIT (FAILED)\n"))
+ UFSD("EXIT (FAILED)\n");
return NULL;
}
else {
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
return sbi->s_ucpi[cgno];
}
} else {
ufs_read_cylinder (sb, cgno, cgno);
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
return sbi->s_ucpi[cgno];
}
}
@@ -204,6 +195,6 @@ struct ufs_cg_private_info * ufs_load_cylinder (
sbi->s_ucpi[0] = ucpi;
ufs_read_cylinder (sb, cgno, 0);
}
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
return sbi->s_ucpi[0];
}
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index 1a56120..7f0a0aa 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -11,31 +11,20 @@
* 4.4BSD (FreeBSD) support added on February 1st 1998 by
* Niels Kristian Bech Jensen <nkbj@image.dk> partially based
* on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
+ *
+ * Migration to usage of "page cache" on May 2006 by
+ * Evgeniy Dushistov <dushistov@mail.ru> based on ext2 code base.
*/
#include <linux/time.h>
#include <linux/fs.h>
#include <linux/ufs_fs.h>
#include <linux/smp_lock.h>
-#include <linux/buffer_head.h>
#include <linux/sched.h>
#include "swab.h"
#include "util.h"
-#undef UFS_DIR_DEBUG
-
-#ifdef UFS_DIR_DEBUG
-#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
-static int
-ufs_check_dir_entry (const char *, struct inode *, struct ufs_dir_entry *,
- struct buffer_head *, unsigned long);
-
-
/*
* NOTE! unlike strncmp, ufs_match returns 1 for success, 0 for failure.
*
@@ -51,495 +40,541 @@ static inline int ufs_match(struct super_block *sb, int len,
return !memcmp(name, de->d_name, len);
}
-/*
- * This is blatantly stolen from ext2fs
- */
-static int
-ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
+static int ufs_commit_chunk(struct page *page, unsigned from, unsigned to)
{
- struct inode *inode = filp->f_dentry->d_inode;
- int error = 0;
- unsigned long offset, lblk;
- int i, stored;
- struct buffer_head * bh;
- struct ufs_dir_entry * de;
- struct super_block * sb;
- int de_reclen;
- unsigned flags;
- u64 blk= 0L;
-
- lock_kernel();
-
- sb = inode->i_sb;
- flags = UFS_SB(sb)->s_flags;
-
- UFSD(("ENTER, ino %lu f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos))
-
- stored = 0;
- bh = NULL;
- offset = filp->f_pos & (sb->s_blocksize - 1);
-
- while (!error && !stored && filp->f_pos < inode->i_size) {
- lblk = (filp->f_pos) >> sb->s_blocksize_bits;
- blk = ufs_frag_map(inode, lblk);
- if (!blk || !(bh = sb_bread(sb, blk))) {
- /* XXX - error - skip to the next block */
- printk("ufs_readdir: "
- "dir inode %lu has a hole at offset %lu\n",
- inode->i_ino, (unsigned long int)filp->f_pos);
- filp->f_pos += sb->s_blocksize - offset;
- continue;
- }
-
-revalidate:
- /* If the dir block has changed since the last call to
- * readdir(2), then we might be pointing to an invalid
- * dirent right now. Scan from the start of the block
- * to make sure. */
- if (filp->f_version != inode->i_version) {
- for (i = 0; i < sb->s_blocksize && i < offset; ) {
- de = (struct ufs_dir_entry *)(bh->b_data + i);
- /* It's too expensive to do a full
- * dirent test each time round this
- * loop, but we do have to test at
- * least that it is non-zero. A
- * failure will be detected in the
- * dirent test below. */
- de_reclen = fs16_to_cpu(sb, de->d_reclen);
- if (de_reclen < 1)
- break;
- i += de_reclen;
- }
- offset = i;
- filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
- | offset;
- filp->f_version = inode->i_version;
- }
+ struct inode *dir = page->mapping->host;
+ int err = 0;
+ dir->i_version++;
+ page->mapping->a_ops->commit_write(NULL, page, from, to);
+ if (IS_DIRSYNC(dir))
+ err = write_one_page(page, 1);
+ else
+ unlock_page(page);
+ return err;
+}
- while (!error && filp->f_pos < inode->i_size
- && offset < sb->s_blocksize) {
- de = (struct ufs_dir_entry *) (bh->b_data + offset);
- /* XXX - put in a real ufs_check_dir_entry() */
- if ((de->d_reclen == 0) || (ufs_get_de_namlen(sb, de) == 0)) {
- filp->f_pos = (filp->f_pos &
- (sb->s_blocksize - 1)) +
- sb->s_blocksize;
- brelse(bh);
- unlock_kernel();
- return stored;
- }
- if (!ufs_check_dir_entry ("ufs_readdir", inode, de,
- bh, offset)) {
- /* On error, skip the f_pos to the
- next block. */
- filp->f_pos = (filp->f_pos |
- (sb->s_blocksize - 1)) +
- 1;
- brelse (bh);
- unlock_kernel();
- return stored;
- }
- offset += fs16_to_cpu(sb, de->d_reclen);
- if (de->d_ino) {
- /* We might block in the next section
- * if the data destination is
- * currently swapped out. So, use a
- * version stamp to detect whether or
- * not the directory has been modified
- * during the copy operation. */
- unsigned long version = filp->f_version;
- unsigned char d_type = DT_UNKNOWN;
+static inline void ufs_put_page(struct page *page)
+{
+ kunmap(page);
+ page_cache_release(page);
+}
- UFSD(("filldir(%s,%u)\n", de->d_name,
- fs32_to_cpu(sb, de->d_ino)))
- UFSD(("namlen %u\n", ufs_get_de_namlen(sb, de)))
+static inline unsigned long ufs_dir_pages(struct inode *inode)
+{
+ return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT;
+}
- if ((flags & UFS_DE_MASK) == UFS_DE_44BSD)
- d_type = de->d_u.d_44.d_type;
- error = filldir(dirent, de->d_name,
- ufs_get_de_namlen(sb, de), filp->f_pos,
- fs32_to_cpu(sb, de->d_ino), d_type);
- if (error)
- break;
- if (version != filp->f_version)
- goto revalidate;
- stored ++;
- }
- filp->f_pos += fs16_to_cpu(sb, de->d_reclen);
- }
- offset = 0;
- brelse (bh);
+ino_t ufs_inode_by_name(struct inode *dir, struct dentry *dentry)
+{
+ ino_t res = 0;
+ struct ufs_dir_entry *de;
+ struct page *page;
+
+ de = ufs_find_entry(dir, dentry, &page);
+ if (de) {
+ res = fs32_to_cpu(dir->i_sb, de->d_ino);
+ ufs_put_page(page);
}
- unlock_kernel();
- return 0;
+ return res;
}
-/*
- * define how far ahead to read directories while searching them.
- */
-#define NAMEI_RA_CHUNKS 2
-#define NAMEI_RA_BLOCKS 4
-#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
-#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b))
-/*
- * ufs_find_entry()
- *
- * finds an entry in the specified directory with the wanted name. It
- * returns the cache buffer in which the entry was found, and the entry
- * itself (as a parameter - res_bh). It does NOT read the inode of the
- * entry - you'll have to do that yourself if you want to.
- */
-struct ufs_dir_entry * ufs_find_entry (struct dentry *dentry,
- struct buffer_head ** res_bh)
+/* Releases the page */
+void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
+ struct page *page, struct inode *inode)
{
- struct super_block * sb;
- struct buffer_head * bh_use[NAMEI_RA_SIZE];
- struct buffer_head * bh_read[NAMEI_RA_SIZE];
- unsigned long offset;
- int block, toread, i, err;
- struct inode *dir = dentry->d_parent->d_inode;
- const char *name = dentry->d_name.name;
- int namelen = dentry->d_name.len;
+ unsigned from = (char *) de - (char *) page_address(page);
+ unsigned to = from + fs16_to_cpu(dir->i_sb, de->d_reclen);
+ int err;
- UFSD(("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen))
-
- *res_bh = NULL;
-
- sb = dir->i_sb;
-
- if (namelen > UFS_MAXNAMLEN)
- return NULL;
+ lock_page(page);
+ err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
+ BUG_ON(err);
+ de->d_ino = cpu_to_fs32(dir->i_sb, inode->i_ino);
+ ufs_set_de_type(dir->i_sb, de, inode->i_mode);
+ err = ufs_commit_chunk(page, from, to);
+ ufs_put_page(page);
+ dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+ mark_inode_dirty(dir);
+}
- memset (bh_use, 0, sizeof (bh_use));
- toread = 0;
- for (block = 0; block < NAMEI_RA_SIZE; ++block) {
- struct buffer_head * bh;
- if ((block << sb->s_blocksize_bits) >= dir->i_size)
- break;
- bh = ufs_getfrag (dir, block, 0, &err);
- bh_use[block] = bh;
- if (bh && !buffer_uptodate(bh))
- bh_read[toread++] = bh;
+static void ufs_check_page(struct page *page)
+{
+ struct inode *dir = page->mapping->host;
+ struct super_block *sb = dir->i_sb;
+ char *kaddr = page_address(page);
+ unsigned offs, rec_len;
+ unsigned limit = PAGE_CACHE_SIZE;
+ struct ufs_dir_entry *p;
+ char *error;
+
+ if ((dir->i_size >> PAGE_CACHE_SHIFT) == page->index) {
+ limit = dir->i_size & ~PAGE_CACHE_MASK;
+ if (limit & (UFS_SECTOR_SIZE - 1))
+ goto Ebadsize;
+ if (!limit)
+ goto out;
}
+ for (offs = 0; offs <= limit - UFS_DIR_REC_LEN(1); offs += rec_len) {
+ p = (struct ufs_dir_entry *)(kaddr + offs);
+ rec_len = fs16_to_cpu(sb, p->d_reclen);
+
+ if (rec_len < UFS_DIR_REC_LEN(1))
+ goto Eshort;
+ if (rec_len & 3)
+ goto Ealign;
+ if (rec_len < UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, p)))
+ goto Enamelen;
+ if (((offs + rec_len - 1) ^ offs) & ~(UFS_SECTOR_SIZE-1))
+ goto Espan;
+ if (fs32_to_cpu(sb, p->d_ino) > (UFS_SB(sb)->s_uspi->s_ipg *
+ UFS_SB(sb)->s_uspi->s_ncg))
+ goto Einumber;
+ }
+ if (offs != limit)
+ goto Eend;
+out:
+ SetPageChecked(page);
+ return;
+
+ /* Too bad, we had an error */
+
+Ebadsize:
+ ufs_error(sb, "ufs_check_page",
+ "size of directory #%lu is not a multiple of chunk size",
+ dir->i_ino
+ );
+ goto fail;
+Eshort:
+ error = "rec_len is smaller than minimal";
+ goto bad_entry;
+Ealign:
+ error = "unaligned directory entry";
+ goto bad_entry;
+Enamelen:
+ error = "rec_len is too small for name_len";
+ goto bad_entry;
+Espan:
+ error = "directory entry across blocks";
+ goto bad_entry;
+Einumber:
+ error = "inode out of bounds";
+bad_entry:
+ ufs_error (sb, "ufs_check_page", "bad entry in directory #%lu: %s - "
+ "offset=%lu, rec_len=%d, name_len=%d",
+ dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
+ rec_len, ufs_get_de_namlen(sb, p));
+ goto fail;
+Eend:
+ p = (struct ufs_dir_entry *)(kaddr + offs);
+ ufs_error (sb, "ext2_check_page",
+ "entry in directory #%lu spans the page boundary"
+ "offset=%lu",
+ dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs);
+fail:
+ SetPageChecked(page);
+ SetPageError(page);
+}
- for (block = 0, offset = 0; offset < dir->i_size; block++) {
- struct buffer_head * bh;
- struct ufs_dir_entry * de;
- char * dlimit;
-
- if ((block % NAMEI_RA_BLOCKS) == 0 && toread) {
- ll_rw_block (READ, toread, bh_read);
- toread = 0;
- }
- bh = bh_use[block % NAMEI_RA_SIZE];
- if (!bh) {
- ufs_error (sb, "ufs_find_entry",
- "directory #%lu contains a hole at offset %lu",
- dir->i_ino, offset);
- offset += sb->s_blocksize;
- continue;
- }
- wait_on_buffer (bh);
- if (!buffer_uptodate(bh)) {
- /*
- * read error: all bets are off
- */
- break;
- }
-
- de = (struct ufs_dir_entry *) bh->b_data;
- dlimit = bh->b_data + sb->s_blocksize;
- while ((char *) de < dlimit && offset < dir->i_size) {
- /* this code is executed quadratically often */
- /* do minimal checking by hand */
- int de_len;
-
- if ((char *) de + namelen <= dlimit &&
- ufs_match(sb, namelen, name, de)) {
- /* found a match -
- just to be sure, do a full check */
- if (!ufs_check_dir_entry("ufs_find_entry",
- dir, de, bh, offset))
- goto failed;
- for (i = 0; i < NAMEI_RA_SIZE; ++i) {
- if (bh_use[i] != bh)
- brelse (bh_use[i]);
- }
- *res_bh = bh;
- return de;
- }
- /* prevent looping on a bad block */
- de_len = fs16_to_cpu(sb, de->d_reclen);
- if (de_len <= 0)
- goto failed;
- offset += de_len;
- de = (struct ufs_dir_entry *) ((char *) de + de_len);
- }
-
- brelse (bh);
- if (((block + NAMEI_RA_SIZE) << sb->s_blocksize_bits ) >=
- dir->i_size)
- bh = NULL;
- else
- bh = ufs_getfrag (dir, block + NAMEI_RA_SIZE, 0, &err);
- bh_use[block % NAMEI_RA_SIZE] = bh;
- if (bh && !buffer_uptodate(bh))
- bh_read[toread++] = bh;
+static struct page *ufs_get_page(struct inode *dir, unsigned long n)
+{
+ struct address_space *mapping = dir->i_mapping;
+ struct page *page = read_cache_page(mapping, n,
+ (filler_t*)mapping->a_ops->readpage, NULL);
+ if (!IS_ERR(page)) {
+ wait_on_page_locked(page);
+ kmap(page);
+ if (!PageUptodate(page))
+ goto fail;
+ if (!PageChecked(page))
+ ufs_check_page(page);
+ if (PageError(page))
+ goto fail;
}
+ return page;
-failed:
- for (i = 0; i < NAMEI_RA_SIZE; ++i) brelse (bh_use[i]);
- UFSD(("EXIT\n"))
- return NULL;
+fail:
+ ufs_put_page(page);
+ return ERR_PTR(-EIO);
}
-static int
-ufs_check_dir_entry (const char *function, struct inode *dir,
- struct ufs_dir_entry *de, struct buffer_head *bh,
- unsigned long offset)
+/*
+ * Return the offset into page `page_nr' of the last valid
+ * byte in that page, plus one.
+ */
+static unsigned
+ufs_last_byte(struct inode *inode, unsigned long page_nr)
{
- struct super_block *sb = dir->i_sb;
- const char *error_msg = NULL;
- int rlen = fs16_to_cpu(sb, de->d_reclen);
-
- if (rlen < UFS_DIR_REC_LEN(1))
- error_msg = "reclen is smaller than minimal";
- else if (rlen % 4 != 0)
- error_msg = "reclen % 4 != 0";
- else if (rlen < UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de)))
- error_msg = "reclen is too small for namlen";
- else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize)
- error_msg = "directory entry across blocks";
- else if (fs32_to_cpu(sb, de->d_ino) > (UFS_SB(sb)->s_uspi->s_ipg *
- UFS_SB(sb)->s_uspi->s_ncg))
- error_msg = "inode out of bounds";
-
- if (error_msg != NULL)
- ufs_error (sb, function, "bad entry in directory #%lu, size %Lu: %s - "
- "offset=%lu, inode=%lu, reclen=%d, namlen=%d",
- dir->i_ino, dir->i_size, error_msg, offset,
- (unsigned long)fs32_to_cpu(sb, de->d_ino),
- rlen, ufs_get_de_namlen(sb, de));
-
- return (error_msg == NULL ? 1 : 0);
+ unsigned last_byte = inode->i_size;
+
+ last_byte -= page_nr << PAGE_CACHE_SHIFT;
+ if (last_byte > PAGE_CACHE_SIZE)
+ last_byte = PAGE_CACHE_SIZE;
+ return last_byte;
}
-struct ufs_dir_entry *ufs_dotdot(struct inode *dir, struct buffer_head **p)
+static inline struct ufs_dir_entry *
+ufs_next_entry(struct super_block *sb, struct ufs_dir_entry *p)
{
- int err;
- struct buffer_head *bh = ufs_bread (dir, 0, 0, &err);
- struct ufs_dir_entry *res = NULL;
-
- if (bh) {
- res = (struct ufs_dir_entry *) bh->b_data;
- res = (struct ufs_dir_entry *)((char *)res +
- fs16_to_cpu(dir->i_sb, res->d_reclen));
- }
- *p = bh;
- return res;
+ return (struct ufs_dir_entry *)((char *)p +
+ fs16_to_cpu(sb, p->d_reclen));
}
-ino_t ufs_inode_by_name(struct inode * dir, struct dentry *dentry)
+
+struct ufs_dir_entry *ufs_dotdot(struct inode *dir, struct page **p)
{
- ino_t res = 0;
- struct ufs_dir_entry * de;
- struct buffer_head *bh;
+ struct page *page = ufs_get_page(dir, 0);
+ struct ufs_dir_entry *de = NULL;
- de = ufs_find_entry (dentry, &bh);
- if (de) {
- res = fs32_to_cpu(dir->i_sb, de->d_ino);
- brelse(bh);
+ if (!IS_ERR(page)) {
+ de = ufs_next_entry(dir->i_sb,
+ (struct ufs_dir_entry *)page_address(page));
+ *p = page;
}
- return res;
+ return de;
}
-void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
- struct buffer_head *bh, struct inode *inode)
+/*
+ * ufs_find_entry()
+ *
+ * finds an entry in the specified directory with the wanted name. It
+ * returns the page in which the entry was found, and the entry itself
+ * (as a parameter - res_dir). Page is returned mapped and unlocked.
+ * Entry is guaranteed to be valid.
+ */
+struct ufs_dir_entry *ufs_find_entry(struct inode *dir, struct dentry *dentry,
+ struct page **res_page)
{
- dir->i_version++;
- de->d_ino = cpu_to_fs32(dir->i_sb, inode->i_ino);
- mark_buffer_dirty(bh);
- if (IS_DIRSYNC(dir))
- sync_dirty_buffer(bh);
- brelse (bh);
+ struct super_block *sb = dir->i_sb;
+ const char *name = dentry->d_name.name;
+ int namelen = dentry->d_name.len;
+ unsigned reclen = UFS_DIR_REC_LEN(namelen);
+ unsigned long start, n;
+ unsigned long npages = ufs_dir_pages(dir);
+ struct page *page = NULL;
+ struct ufs_inode_info *ui = UFS_I(dir);
+ struct ufs_dir_entry *de;
+
+ UFSD("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen);
+
+ if (npages == 0 || namelen > UFS_MAXNAMLEN)
+ goto out;
+
+ /* OFFSET_CACHE */
+ *res_page = NULL;
+
+ start = ui->i_dir_start_lookup;
+
+ if (start >= npages)
+ start = 0;
+ n = start;
+ do {
+ char *kaddr;
+ page = ufs_get_page(dir, n);
+ if (!IS_ERR(page)) {
+ kaddr = page_address(page);
+ de = (struct ufs_dir_entry *) kaddr;
+ kaddr += ufs_last_byte(dir, n) - reclen;
+ while ((char *) de <= kaddr) {
+ if (de->d_reclen == 0) {
+ ufs_error(dir->i_sb, __FUNCTION__,
+ "zero-length directory entry");
+ ufs_put_page(page);
+ goto out;
+ }
+ if (ufs_match(sb, namelen, name, de))
+ goto found;
+ de = ufs_next_entry(sb, de);
+ }
+ ufs_put_page(page);
+ }
+ if (++n >= npages)
+ n = 0;
+ } while (n != start);
+out:
+ return NULL;
+
+found:
+ *res_page = page;
+ ui->i_dir_start_lookup = n;
+ return de;
}
/*
- * ufs_add_entry()
- *
- * adds a file entry to the specified directory, using the same
- * semantics as ufs_find_entry(). It returns NULL if it failed.
+ * Parent is locked.
*/
int ufs_add_link(struct dentry *dentry, struct inode *inode)
{
- struct super_block * sb;
- struct ufs_sb_private_info * uspi;
- unsigned long offset;
- unsigned fragoff;
- unsigned short rec_len;
- struct buffer_head * bh;
- struct ufs_dir_entry * de, * de1;
struct inode *dir = dentry->d_parent->d_inode;
const char *name = dentry->d_name.name;
int namelen = dentry->d_name.len;
+ struct super_block *sb = dir->i_sb;
+ unsigned reclen = UFS_DIR_REC_LEN(namelen);
+ unsigned short rec_len, name_len;
+ struct page *page = NULL;
+ struct ufs_dir_entry *de;
+ unsigned long npages = ufs_dir_pages(dir);
+ unsigned long n;
+ char *kaddr;
+ unsigned from, to;
int err;
- UFSD(("ENTER, name %s, namelen %u\n", name, namelen))
-
- sb = dir->i_sb;
- uspi = UFS_SB(sb)->s_uspi;
-
- if (!namelen)
- return -EINVAL;
- bh = ufs_bread (dir, 0, 0, &err);
- if (!bh)
- return err;
- rec_len = UFS_DIR_REC_LEN(namelen);
- offset = 0;
- de = (struct ufs_dir_entry *) bh->b_data;
- while (1) {
- if ((char *)de >= UFS_SECTOR_SIZE + bh->b_data) {
- fragoff = offset & ~uspi->s_fmask;
- if (fragoff != 0 && fragoff != UFS_SECTOR_SIZE)
- ufs_error (sb, "ufs_add_entry", "internal error"
- " fragoff %u", fragoff);
- if (!fragoff) {
- brelse (bh);
- bh = ufs_bread (dir, offset >> sb->s_blocksize_bits, 1, &err);
- if (!bh)
- return err;
- }
- if (dir->i_size <= offset) {
- if (dir->i_size == 0) {
- brelse(bh);
- return -ENOENT;
- }
- de = (struct ufs_dir_entry *) (bh->b_data + fragoff);
- de->d_ino = 0;
+ UFSD("ENTER, name %s, namelen %u\n", name, namelen);
+
+ /*
+ * We take care of directory expansion in the same loop.
+ * This code plays outside i_size, so it locks the page
+ * to protect that region.
+ */
+ for (n = 0; n <= npages; n++) {
+ char *dir_end;
+
+ page = ufs_get_page(dir, n);
+ err = PTR_ERR(page);
+ if (IS_ERR(page))
+ goto out;
+ lock_page(page);
+ kaddr = page_address(page);
+ dir_end = kaddr + ufs_last_byte(dir, n);
+ de = (struct ufs_dir_entry *)kaddr;
+ kaddr += PAGE_CACHE_SIZE - reclen;
+ while ((char *)de <= kaddr) {
+ if ((char *)de == dir_end) {
+ /* We hit i_size */
+ name_len = 0;
+ rec_len = UFS_SECTOR_SIZE;
de->d_reclen = cpu_to_fs16(sb, UFS_SECTOR_SIZE);
- ufs_set_de_namlen(sb, de, 0);
- dir->i_size = offset + UFS_SECTOR_SIZE;
- mark_inode_dirty(dir);
- } else {
- de = (struct ufs_dir_entry *) bh->b_data;
+ de->d_ino = 0;
+ goto got_it;
}
+ if (de->d_reclen == 0) {
+ ufs_error(dir->i_sb, __FUNCTION__,
+ "zero-length directory entry");
+ err = -EIO;
+ goto out_unlock;
+ }
+ err = -EEXIST;
+ if (ufs_match(sb, namelen, name, de))
+ goto out_unlock;
+ name_len = UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de));
+ rec_len = fs16_to_cpu(sb, de->d_reclen);
+ if (!de->d_ino && rec_len >= reclen)
+ goto got_it;
+ if (rec_len >= name_len + reclen)
+ goto got_it;
+ de = (struct ufs_dir_entry *) ((char *) de + rec_len);
}
- if (!ufs_check_dir_entry ("ufs_add_entry", dir, de, bh, offset)) {
- brelse (bh);
- return -ENOENT;
- }
- if (ufs_match(sb, namelen, name, de)) {
- brelse (bh);
- return -EEXIST;
- }
- if (de->d_ino == 0 && fs16_to_cpu(sb, de->d_reclen) >= rec_len)
- break;
-
- if (fs16_to_cpu(sb, de->d_reclen) >=
- UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de)) + rec_len)
- break;
- offset += fs16_to_cpu(sb, de->d_reclen);
- de = (struct ufs_dir_entry *) ((char *) de + fs16_to_cpu(sb, de->d_reclen));
+ unlock_page(page);
+ ufs_put_page(page);
}
-
+ BUG();
+ return -EINVAL;
+
+got_it:
+ from = (char*)de - (char*)page_address(page);
+ to = from + rec_len;
+ err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
+ if (err)
+ goto out_unlock;
if (de->d_ino) {
- de1 = (struct ufs_dir_entry *) ((char *) de +
- UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de)));
- de1->d_reclen =
- cpu_to_fs16(sb, fs16_to_cpu(sb, de->d_reclen) -
- UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de)));
- de->d_reclen =
- cpu_to_fs16(sb, UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de)));
+ struct ufs_dir_entry *de1 =
+ (struct ufs_dir_entry *) ((char *) de + name_len);
+ de1->d_reclen = cpu_to_fs16(sb, rec_len - name_len);
+ de->d_reclen = cpu_to_fs16(sb, name_len);
+
de = de1;
}
- de->d_ino = 0;
+
ufs_set_de_namlen(sb, de, namelen);
- memcpy (de->d_name, name, namelen + 1);
+ memcpy(de->d_name, name, namelen + 1);
de->d_ino = cpu_to_fs32(sb, inode->i_ino);
ufs_set_de_type(sb, de, inode->i_mode);
- mark_buffer_dirty(bh);
- if (IS_DIRSYNC(dir))
- sync_dirty_buffer(bh);
- brelse (bh);
+
+ err = ufs_commit_chunk(page, from, to);
dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
- dir->i_version++;
+
mark_inode_dirty(dir);
+ /* OFFSET_CACHE */
+out_put:
+ ufs_put_page(page);
+out:
+ return err;
+out_unlock:
+ unlock_page(page);
+ goto out_put;
+}
- UFSD(("EXIT\n"))
+static inline unsigned
+ufs_validate_entry(struct super_block *sb, char *base,
+ unsigned offset, unsigned mask)
+{
+ struct ufs_dir_entry *de = (struct ufs_dir_entry*)(base + offset);
+ struct ufs_dir_entry *p = (struct ufs_dir_entry*)(base + (offset&mask));
+ while ((char*)p < (char*)de) {
+ if (p->d_reclen == 0)
+ break;
+ p = ufs_next_entry(sb, p);
+ }
+ return (char *)p - base;
+}
+
+
+/*
+ * This is blatantly stolen from ext2fs
+ */
+static int
+ufs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+ loff_t pos = filp->f_pos;
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct super_block *sb = inode->i_sb;
+ unsigned int offset = pos & ~PAGE_CACHE_MASK;
+ unsigned long n = pos >> PAGE_CACHE_SHIFT;
+ unsigned long npages = ufs_dir_pages(inode);
+ unsigned chunk_mask = ~(UFS_SECTOR_SIZE - 1);
+ int need_revalidate = filp->f_version != inode->i_version;
+ unsigned flags = UFS_SB(sb)->s_flags;
+
+ UFSD("BEGIN\n");
+
+ if (pos > inode->i_size - UFS_DIR_REC_LEN(1))
+ return 0;
+
+ for ( ; n < npages; n++, offset = 0) {
+ char *kaddr, *limit;
+ struct ufs_dir_entry *de;
+
+ struct page *page = ufs_get_page(inode, n);
+
+ if (IS_ERR(page)) {
+ ufs_error(sb, __FUNCTION__,
+ "bad page in #%lu",
+ inode->i_ino);
+ filp->f_pos += PAGE_CACHE_SIZE - offset;
+ return -EIO;
+ }
+ kaddr = page_address(page);
+ if (unlikely(need_revalidate)) {
+ if (offset) {
+ offset = ufs_validate_entry(sb, kaddr, offset, chunk_mask);
+ filp->f_pos = (n<<PAGE_CACHE_SHIFT) + offset;
+ }
+ filp->f_version = inode->i_version;
+ need_revalidate = 0;
+ }
+ de = (struct ufs_dir_entry *)(kaddr+offset);
+ limit = kaddr + ufs_last_byte(inode, n) - UFS_DIR_REC_LEN(1);
+ for ( ;(char*)de <= limit; de = ufs_next_entry(sb, de)) {
+ if (de->d_reclen == 0) {
+ ufs_error(sb, __FUNCTION__,
+ "zero-length directory entry");
+ ufs_put_page(page);
+ return -EIO;
+ }
+ if (de->d_ino) {
+ int over;
+ unsigned char d_type = DT_UNKNOWN;
+
+ offset = (char *)de - kaddr;
+
+ UFSD("filldir(%s,%u)\n", de->d_name,
+ fs32_to_cpu(sb, de->d_ino));
+ UFSD("namlen %u\n", ufs_get_de_namlen(sb, de));
+
+ if ((flags & UFS_DE_MASK) == UFS_DE_44BSD)
+ d_type = de->d_u.d_44.d_type;
+
+ over = filldir(dirent, de->d_name,
+ ufs_get_de_namlen(sb, de),
+ (n<<PAGE_CACHE_SHIFT) | offset,
+ fs32_to_cpu(sb, de->d_ino), d_type);
+ if (over) {
+ ufs_put_page(page);
+ return 0;
+ }
+ }
+ filp->f_pos += fs16_to_cpu(sb, de->d_reclen);
+ }
+ ufs_put_page(page);
+ }
return 0;
}
+
/*
* ufs_delete_entry deletes a directory entry by merging it with the
* previous entry.
*/
-int ufs_delete_entry (struct inode * inode, struct ufs_dir_entry * dir,
- struct buffer_head * bh )
-
+int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir,
+ struct page * page)
{
- struct super_block * sb;
- struct ufs_dir_entry * de, * pde;
- unsigned i;
-
- UFSD(("ENTER\n"))
+ struct super_block *sb = inode->i_sb;
+ struct address_space *mapping = page->mapping;
+ char *kaddr = page_address(page);
+ unsigned from = ((char*)dir - kaddr) & ~(UFS_SECTOR_SIZE - 1);
+ unsigned to = ((char*)dir - kaddr) + fs16_to_cpu(sb, dir->d_reclen);
+ struct ufs_dir_entry *pde = NULL;
+ struct ufs_dir_entry *de = (struct ufs_dir_entry *) (kaddr + from);
+ int err;
- sb = inode->i_sb;
- i = 0;
- pde = NULL;
- de = (struct ufs_dir_entry *) bh->b_data;
-
- UFSD(("ino %u, reclen %u, namlen %u, name %s\n",
- fs32_to_cpu(sb, de->d_ino),
- fs16_to_cpu(sb, de->d_reclen),
- ufs_get_de_namlen(sb, de), de->d_name))
-
- while (i < bh->b_size) {
- if (!ufs_check_dir_entry ("ufs_delete_entry", inode, de, bh, i)) {
- brelse(bh);
- return -EIO;
- }
- if (de == dir) {
- if (pde)
- fs16_add(sb, &pde->d_reclen,
- fs16_to_cpu(sb, dir->d_reclen));
- dir->d_ino = 0;
- inode->i_version++;
- inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
- mark_inode_dirty(inode);
- mark_buffer_dirty(bh);
- if (IS_DIRSYNC(inode))
- sync_dirty_buffer(bh);
- brelse(bh);
- UFSD(("EXIT\n"))
- return 0;
+ UFSD("ENTER\n");
+
+ UFSD("ino %u, reclen %u, namlen %u, name %s\n",
+ fs32_to_cpu(sb, de->d_ino),
+ fs16_to_cpu(sb, de->d_reclen),
+ ufs_get_de_namlen(sb, de), de->d_name);
+
+ while ((char*)de < (char*)dir) {
+ if (de->d_reclen == 0) {
+ ufs_error(inode->i_sb, __FUNCTION__,
+ "zero-length directory entry");
+ err = -EIO;
+ goto out;
}
- i += fs16_to_cpu(sb, de->d_reclen);
- if (i == UFS_SECTOR_SIZE) pde = NULL;
- else pde = de;
- de = (struct ufs_dir_entry *)
- ((char *) de + fs16_to_cpu(sb, de->d_reclen));
- if (i == UFS_SECTOR_SIZE && de->d_reclen == 0)
- break;
+ pde = de;
+ de = ufs_next_entry(sb, de);
}
- UFSD(("EXIT\n"))
- brelse(bh);
- return -ENOENT;
+ if (pde)
+ from = (char*)pde - (char*)page_address(page);
+ lock_page(page);
+ err = mapping->a_ops->prepare_write(NULL, page, from, to);
+ BUG_ON(err);
+ if (pde)
+ pde->d_reclen = cpu_to_fs16(sb, to-from);
+ dir->d_ino = 0;
+ err = ufs_commit_chunk(page, from, to);
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
+ mark_inode_dirty(inode);
+out:
+ ufs_put_page(page);
+ UFSD("EXIT\n");
+ return err;
}
int ufs_make_empty(struct inode * inode, struct inode *dir)
{
struct super_block * sb = dir->i_sb;
- struct buffer_head * dir_block;
+ struct address_space *mapping = inode->i_mapping;
+ struct page *page = grab_cache_page(mapping, 0);
struct ufs_dir_entry * de;
+ char *base;
int err;
- dir_block = ufs_bread (inode, 0, 1, &err);
- if (!dir_block)
- return err;
+ if (!page)
+ return -ENOMEM;
+ kmap(page);
+ err = mapping->a_ops->prepare_write(NULL, page, 0, UFS_SECTOR_SIZE);
+ if (err) {
+ unlock_page(page);
+ goto fail;
+ }
+
+
+ base = (char*)page_address(page);
+ memset(base, 0, PAGE_CACHE_SIZE);
+
+ de = (struct ufs_dir_entry *) base;
- inode->i_blocks = sb->s_blocksize / UFS_SECTOR_SIZE;
- de = (struct ufs_dir_entry *) dir_block->b_data;
de->d_ino = cpu_to_fs32(sb, inode->i_ino);
ufs_set_de_type(sb, de, inode->i_mode);
ufs_set_de_namlen(sb, de, 1);
@@ -552,72 +587,65 @@ int ufs_make_empty(struct inode * inode, struct inode *dir)
de->d_reclen = cpu_to_fs16(sb, UFS_SECTOR_SIZE - UFS_DIR_REC_LEN(1));
ufs_set_de_namlen(sb, de, 2);
strcpy (de->d_name, "..");
- mark_buffer_dirty(dir_block);
- brelse (dir_block);
- mark_inode_dirty(inode);
- return 0;
+
+ err = ufs_commit_chunk(page, 0, UFS_SECTOR_SIZE);
+fail:
+ kunmap(page);
+ page_cache_release(page);
+ return err;
}
/*
* routine to check that the specified directory is empty (for rmdir)
*/
-int ufs_empty_dir (struct inode * inode)
+int ufs_empty_dir(struct inode * inode)
{
- struct super_block * sb;
- unsigned long offset;
- struct buffer_head * bh;
- struct ufs_dir_entry * de, * de1;
- int err;
-
- sb = inode->i_sb;
-
- if (inode->i_size < UFS_DIR_REC_LEN(1) + UFS_DIR_REC_LEN(2) ||
- !(bh = ufs_bread (inode, 0, 0, &err))) {
- ufs_warning (inode->i_sb, "empty_dir",
- "bad directory (dir #%lu) - no data block",
- inode->i_ino);
- return 1;
- }
- de = (struct ufs_dir_entry *) bh->b_data;
- de1 = (struct ufs_dir_entry *)
- ((char *)de + fs16_to_cpu(sb, de->d_reclen));
- if (fs32_to_cpu(sb, de->d_ino) != inode->i_ino || de1->d_ino == 0 ||
- strcmp (".", de->d_name) || strcmp ("..", de1->d_name)) {
- ufs_warning (inode->i_sb, "empty_dir",
- "bad directory (dir #%lu) - no `.' or `..'",
- inode->i_ino);
- return 1;
- }
- offset = fs16_to_cpu(sb, de->d_reclen) + fs16_to_cpu(sb, de1->d_reclen);
- de = (struct ufs_dir_entry *)
- ((char *)de1 + fs16_to_cpu(sb, de1->d_reclen));
- while (offset < inode->i_size ) {
- if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
- brelse (bh);
- bh = ufs_bread (inode, offset >> sb->s_blocksize_bits, 1, &err);
- if (!bh) {
- ufs_error (sb, "empty_dir",
- "directory #%lu contains a hole at offset %lu",
- inode->i_ino, offset);
- offset += sb->s_blocksize;
- continue;
+ struct super_block *sb = inode->i_sb;
+ struct page *page = NULL;
+ unsigned long i, npages = ufs_dir_pages(inode);
+
+ for (i = 0; i < npages; i++) {
+ char *kaddr;
+ struct ufs_dir_entry *de;
+ page = ufs_get_page(inode, i);
+
+ if (IS_ERR(page))
+ continue;
+
+ kaddr = page_address(page);
+ de = (struct ufs_dir_entry *)kaddr;
+ kaddr += ufs_last_byte(inode, i) - UFS_DIR_REC_LEN(1);
+
+ while ((char *)de <= kaddr) {
+ if (de->d_reclen == 0) {
+ ufs_error(inode->i_sb, __FUNCTION__,
+ "zero-length directory entry: "
+ "kaddr=%p, de=%p\n", kaddr, de);
+ goto not_empty;
}
- de = (struct ufs_dir_entry *) bh->b_data;
- }
- if (!ufs_check_dir_entry ("empty_dir", inode, de, bh, offset)) {
- brelse (bh);
- return 1;
- }
- if (de->d_ino) {
- brelse (bh);
- return 0;
+ if (de->d_ino) {
+ u16 namelen=ufs_get_de_namlen(sb, de);
+ /* check for . and .. */
+ if (de->d_name[0] != '.')
+ goto not_empty;
+ if (namelen > 2)
+ goto not_empty;
+ if (namelen < 2) {
+ if (inode->i_ino !=
+ fs32_to_cpu(sb, de->d_ino))
+ goto not_empty;
+ } else if (de->d_name[1] != '.')
+ goto not_empty;
+ }
+ de = ufs_next_entry(sb, de);
}
- offset += fs16_to_cpu(sb, de->d_reclen);
- de = (struct ufs_dir_entry *)
- ((char *)de + fs16_to_cpu(sb, de->d_reclen));
+ ufs_put_page(page);
}
- brelse (bh);
return 1;
+
+not_empty:
+ ufs_put_page(page);
+ return 0;
}
const struct file_operations ufs_dir_operations = {
diff --git a/fs/ufs/file.c b/fs/ufs/file.c
index 312fd3f..0e50015 100644
--- a/fs/ufs/file.c
+++ b/fs/ufs/file.c
@@ -25,6 +25,26 @@
#include <linux/fs.h>
#include <linux/ufs_fs.h>
+#include <linux/buffer_head.h> /* for sync_mapping_buffers() */
+
+static int ufs_sync_file(struct file *file, struct dentry *dentry, int datasync)
+{
+ struct inode *inode = dentry->d_inode;
+ int err;
+ int ret;
+
+ ret = sync_mapping_buffers(inode->i_mapping);
+ if (!(inode->i_state & I_DIRTY))
+ return ret;
+ if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+ return ret;
+
+ err = ufs_sync_inode(inode);
+ if (ret == 0)
+ ret = err;
+ return ret;
+}
+
/*
* We have mostly NULL's here: the current defaults are ok for
@@ -37,6 +57,7 @@ const struct file_operations ufs_file_operations = {
.write = generic_file_write,
.mmap = generic_file_mmap,
.open = generic_file_open,
+ .fsync = ufs_sync_file,
.sendfile = generic_file_sendfile,
};
diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c
index c7a47ed..9501dcd 100644
--- a/fs/ufs/ialloc.c
+++ b/fs/ufs/ialloc.c
@@ -34,14 +34,6 @@
#include "swab.h"
#include "util.h"
-#undef UFS_IALLOC_DEBUG
-
-#ifdef UFS_IALLOC_DEBUG
-#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
/*
* NOTE! When we get the inode, we're the only people
* that have access to it, and as such there are no
@@ -68,7 +60,7 @@ void ufs_free_inode (struct inode * inode)
int is_directory;
unsigned ino, cg, bit;
- UFSD(("ENTER, ino %lu\n", inode->i_ino))
+ UFSD("ENTER, ino %lu\n", inode->i_ino);
sb = inode->i_sb;
uspi = UFS_SB(sb)->s_uspi;
@@ -91,7 +83,7 @@ void ufs_free_inode (struct inode * inode)
unlock_super (sb);
return;
}
- ucg = ubh_get_ucg(UCPI_UBH);
+ ucg = ubh_get_ucg(UCPI_UBH(ucpi));
if (!ufs_cg_chkmagic(sb, ucg))
ufs_panic (sb, "ufs_free_fragments", "internal error, bad cg magic number");
@@ -104,33 +96,33 @@ void ufs_free_inode (struct inode * inode)
clear_inode (inode);
- if (ubh_isclr (UCPI_UBH, ucpi->c_iusedoff, bit))
+ if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit))
ufs_error(sb, "ufs_free_inode", "bit already cleared for inode %u", ino);
else {
- ubh_clrbit (UCPI_UBH, ucpi->c_iusedoff, bit);
+ ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit);
if (ino < ucpi->c_irotor)
ucpi->c_irotor = ino;
fs32_add(sb, &ucg->cg_cs.cs_nifree, 1);
- fs32_add(sb, &usb1->fs_cstotal.cs_nifree, 1);
+ uspi->cs_total.cs_nifree++;
fs32_add(sb, &UFS_SB(sb)->fs_cs(cg).cs_nifree, 1);
if (is_directory) {
fs32_sub(sb, &ucg->cg_cs.cs_ndir, 1);
- fs32_sub(sb, &usb1->fs_cstotal.cs_ndir, 1);
+ uspi->cs_total.cs_ndir--;
fs32_sub(sb, &UFS_SB(sb)->fs_cs(cg).cs_ndir, 1);
}
}
- ubh_mark_buffer_dirty (USPI_UBH);
- ubh_mark_buffer_dirty (UCPI_UBH);
+ ubh_mark_buffer_dirty (USPI_UBH(uspi));
+ ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
if (sb->s_flags & MS_SYNCHRONOUS) {
- ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **) &ucpi);
- ubh_wait_on_buffer (UCPI_UBH);
+ ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
+ ubh_wait_on_buffer (UCPI_UBH(ucpi));
}
sb->s_dirt = 1;
unlock_super (sb);
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
}
/*
@@ -155,7 +147,7 @@ struct inode * ufs_new_inode(struct inode * dir, int mode)
unsigned cg, bit, i, j, start;
struct ufs_inode_info *ufsi;
- UFSD(("ENTER\n"))
+ UFSD("ENTER\n");
/* Cannot create files in a deleted directory */
if (!dir || !dir->i_nlink)
@@ -213,43 +205,43 @@ cg_found:
ucpi = ufs_load_cylinder (sb, cg);
if (!ucpi)
goto failed;
- ucg = ubh_get_ucg(UCPI_UBH);
+ ucg = ubh_get_ucg(UCPI_UBH(ucpi));
if (!ufs_cg_chkmagic(sb, ucg))
ufs_panic (sb, "ufs_new_inode", "internal error, bad cg magic number");
start = ucpi->c_irotor;
- bit = ubh_find_next_zero_bit (UCPI_UBH, ucpi->c_iusedoff, uspi->s_ipg, start);
+ bit = ubh_find_next_zero_bit (UCPI_UBH(ucpi), ucpi->c_iusedoff, uspi->s_ipg, start);
if (!(bit < uspi->s_ipg)) {
- bit = ubh_find_first_zero_bit (UCPI_UBH, ucpi->c_iusedoff, start);
+ bit = ubh_find_first_zero_bit (UCPI_UBH(ucpi), ucpi->c_iusedoff, start);
if (!(bit < start)) {
ufs_error (sb, "ufs_new_inode",
"cylinder group %u corrupted - error in inode bitmap\n", cg);
goto failed;
}
}
- UFSD(("start = %u, bit = %u, ipg = %u\n", start, bit, uspi->s_ipg))
- if (ubh_isclr (UCPI_UBH, ucpi->c_iusedoff, bit))
- ubh_setbit (UCPI_UBH, ucpi->c_iusedoff, bit);
+ UFSD("start = %u, bit = %u, ipg = %u\n", start, bit, uspi->s_ipg);
+ if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit))
+ ubh_setbit (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit);
else {
ufs_panic (sb, "ufs_new_inode", "internal error");
goto failed;
}
fs32_sub(sb, &ucg->cg_cs.cs_nifree, 1);
- fs32_sub(sb, &usb1->fs_cstotal.cs_nifree, 1);
+ uspi->cs_total.cs_nifree--;
fs32_sub(sb, &sbi->fs_cs(cg).cs_nifree, 1);
if (S_ISDIR(mode)) {
fs32_add(sb, &ucg->cg_cs.cs_ndir, 1);
- fs32_add(sb, &usb1->fs_cstotal.cs_ndir, 1);
+ uspi->cs_total.cs_ndir++;
fs32_add(sb, &sbi->fs_cs(cg).cs_ndir, 1);
}
- ubh_mark_buffer_dirty (USPI_UBH);
- ubh_mark_buffer_dirty (UCPI_UBH);
+ ubh_mark_buffer_dirty (USPI_UBH(uspi));
+ ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
if (sb->s_flags & MS_SYNCHRONOUS) {
- ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **) &ucpi);
- ubh_wait_on_buffer (UCPI_UBH);
+ ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
+ ubh_wait_on_buffer (UCPI_UBH(ucpi));
}
sb->s_dirt = 1;
@@ -272,6 +264,7 @@ cg_found:
ufsi->i_shadow = 0;
ufsi->i_osync = 0;
ufsi->i_oeftflag = 0;
+ ufsi->i_dir_start_lookup = 0;
memset(&ufsi->i_u1, 0, sizeof(ufsi->i_u1));
insert_inode_hash(inode);
@@ -287,14 +280,14 @@ cg_found:
return ERR_PTR(-EDQUOT);
}
- UFSD(("allocating inode %lu\n", inode->i_ino))
- UFSD(("EXIT\n"))
+ UFSD("allocating inode %lu\n", inode->i_ino);
+ UFSD("EXIT\n");
return inode;
failed:
unlock_super (sb);
make_bad_inode(inode);
iput (inode);
- UFSD(("EXIT (FAILED)\n"))
+ UFSD("EXIT (FAILED)\n");
return ERR_PTR(-ENOSPC);
}
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index 3c3f62c..f2dbdf5 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -41,14 +41,7 @@
#include "swab.h"
#include "util.h"
-#undef UFS_INODE_DEBUG
-#undef UFS_INODE_DEBUG_MORE
-
-#ifdef UFS_INODE_DEBUG
-#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
+static u64 ufs_frag_map(struct inode *inode, sector_t frag);
static int ufs_block_to_path(struct inode *inode, sector_t i_block, sector_t offsets[4])
{
@@ -61,7 +54,7 @@ static int ufs_block_to_path(struct inode *inode, sector_t i_block, sector_t off
int n = 0;
- UFSD(("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks));
+ UFSD("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks);
if (i_block < 0) {
ufs_warning(inode->i_sb, "ufs_block_to_path", "block < 0");
} else if (i_block < direct_blocks) {
@@ -89,7 +82,7 @@ static int ufs_block_to_path(struct inode *inode, sector_t i_block, sector_t off
* the begining of the filesystem.
*/
-u64 ufs_frag_map(struct inode *inode, sector_t frag)
+static u64 ufs_frag_map(struct inode *inode, sector_t frag)
{
struct ufs_inode_info *ufsi = UFS_I(inode);
struct super_block *sb = inode->i_sb;
@@ -104,8 +97,8 @@ u64 ufs_frag_map(struct inode *inode, sector_t frag)
unsigned flags = UFS_SB(sb)->s_flags;
u64 temp = 0L;
- UFSD((": frag = %llu depth = %d\n", (unsigned long long)frag, depth));
- UFSD((": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n",uspi->s_fpbshift,uspi->s_apbmask,mask));
+ UFSD(": frag = %llu depth = %d\n", (unsigned long long)frag, depth);
+ UFSD(": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n",uspi->s_fpbshift,uspi->s_apbmask,mask);
if (depth == 0)
return 0;
@@ -161,26 +154,64 @@ out:
return ret;
}
-static struct buffer_head * ufs_inode_getfrag (struct inode *inode,
- unsigned int fragment, unsigned int new_fragment,
- unsigned int required, int *err, int metadata, long *phys, int *new)
+static void ufs_clear_frag(struct inode *inode, struct buffer_head *bh)
+{
+ lock_buffer(bh);
+ memset(bh->b_data, 0, inode->i_sb->s_blocksize);
+ set_buffer_uptodate(bh);
+ mark_buffer_dirty(bh);
+ unlock_buffer(bh);
+ if (IS_SYNC(inode))
+ sync_dirty_buffer(bh);
+}
+
+static struct buffer_head *
+ufs_clear_frags(struct inode *inode, sector_t beg,
+ unsigned int n)
+{
+ struct buffer_head *res, *bh;
+ sector_t end = beg + n;
+
+ res = sb_getblk(inode->i_sb, beg);
+ ufs_clear_frag(inode, res);
+ for (++beg; beg < end; ++beg) {
+ bh = sb_getblk(inode->i_sb, beg);
+ ufs_clear_frag(inode, bh);
+ brelse(bh);
+ }
+ return res;
+}
+
+/**
+ * ufs_inode_getfrag() - allocate new fragment(s)
+ * @inode - pointer to inode
+ * @fragment - number of `fragment' which hold pointer
+ * to new allocated fragment(s)
+ * @new_fragment - number of new allocated fragment(s)
+ * @required - how many fragment(s) we require
+ * @err - we set it if something wrong
+ * @phys - pointer to where we save physical number of new allocated fragments,
+ * NULL if we allocate not data(indirect blocks for example).
+ * @new - we set it if we allocate new block
+ * @locked_page - for ufs_new_fragments()
+ */
+static struct buffer_head *
+ufs_inode_getfrag(struct inode *inode, unsigned int fragment,
+ sector_t new_fragment, unsigned int required, int *err,
+ long *phys, int *new, struct page *locked_page)
{
struct ufs_inode_info *ufsi = UFS_I(inode);
- struct super_block * sb;
- struct ufs_sb_private_info * uspi;
+ struct super_block *sb = inode->i_sb;
+ struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
struct buffer_head * result;
unsigned block, blockoff, lastfrag, lastblock, lastblockoff;
unsigned tmp, goal;
__fs32 * p, * p2;
- unsigned flags = 0;
- UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u, required %u\n",
- inode->i_ino, fragment, new_fragment, required))
+ UFSD("ENTER, ino %lu, fragment %u, new_fragment %llu, required %u, "
+ "metadata %d\n", inode->i_ino, fragment,
+ (unsigned long long)new_fragment, required, !phys);
- sb = inode->i_sb;
- uspi = UFS_SB(sb)->s_uspi;
-
- flags = UFS_SB(sb)->s_flags;
/* TODO : to be done for write support
if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
goto ufs2;
@@ -195,16 +226,16 @@ repeat:
tmp = fs32_to_cpu(sb, *p);
lastfrag = ufsi->i_lastfrag;
if (tmp && fragment < lastfrag) {
- if (metadata) {
+ if (!phys) {
result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff);
if (tmp == fs32_to_cpu(sb, *p)) {
- UFSD(("EXIT, result %u\n", tmp + blockoff))
+ UFSD("EXIT, result %u\n", tmp + blockoff);
return result;
}
brelse (result);
goto repeat;
} else {
- *phys = tmp;
+ *phys = tmp + blockoff;
return NULL;
}
}
@@ -221,7 +252,8 @@ repeat:
if (lastblockoff) {
p2 = ufsi->i_u1.i_data + lastblock;
tmp = ufs_new_fragments (inode, p2, lastfrag,
- fs32_to_cpu(sb, *p2), uspi->s_fpb - lastblockoff, err);
+ fs32_to_cpu(sb, *p2), uspi->s_fpb - lastblockoff,
+ err, locked_page);
if (!tmp) {
if (lastfrag != ufsi->i_lastfrag)
goto repeat;
@@ -233,14 +265,16 @@ repeat:
}
goal = fs32_to_cpu(sb, ufsi->i_u1.i_data[lastblock]) + uspi->s_fpb;
tmp = ufs_new_fragments (inode, p, fragment - blockoff,
- goal, required + blockoff, err);
+ goal, required + blockoff,
+ err, locked_page);
}
/*
* We will extend last allocated block
*/
else if (lastblock == block) {
- tmp = ufs_new_fragments (inode, p, fragment - (blockoff - lastblockoff),
- fs32_to_cpu(sb, *p), required + (blockoff - lastblockoff), err);
+ tmp = ufs_new_fragments(inode, p, fragment - (blockoff - lastblockoff),
+ fs32_to_cpu(sb, *p), required + (blockoff - lastblockoff),
+ err, locked_page);
}
/*
* We will allocate new block before last allocated block
@@ -248,8 +282,8 @@ repeat:
else /* (lastblock > block) */ {
if (lastblock && (tmp = fs32_to_cpu(sb, ufsi->i_u1.i_data[lastblock-1])))
goal = tmp + uspi->s_fpb;
- tmp = ufs_new_fragments (inode, p, fragment - blockoff,
- goal, uspi->s_fpb, err);
+ tmp = ufs_new_fragments(inode, p, fragment - blockoff,
+ goal, uspi->s_fpb, err, locked_page);
}
if (!tmp) {
if ((!blockoff && *p) ||
@@ -259,14 +293,10 @@ repeat:
return NULL;
}
- /* The nullification of framgents done in ufs/balloc.c is
- * something I don't have the stomache to move into here right
- * now. -DaveM
- */
- if (metadata) {
- result = sb_getblk(inode->i_sb, tmp + blockoff);
+ if (!phys) {
+ result = ufs_clear_frags(inode, tmp + blockoff, required);
} else {
- *phys = tmp;
+ *phys = tmp + blockoff;
result = NULL;
*err = 0;
*new = 1;
@@ -276,7 +306,7 @@ repeat:
if (IS_SYNC(inode))
ufs_sync_inode (inode);
mark_inode_dirty(inode);
- UFSD(("EXIT, result %u\n", tmp + blockoff))
+ UFSD("EXIT, result %u\n", tmp + blockoff);
return result;
/* This part : To be implemented ....
@@ -295,22 +325,35 @@ repeat2:
*/
}
-static struct buffer_head * ufs_block_getfrag (struct inode *inode,
- struct buffer_head *bh, unsigned int fragment, unsigned int new_fragment,
- unsigned int blocksize, int * err, int metadata, long *phys, int *new)
+/**
+ * ufs_inode_getblock() - allocate new block
+ * @inode - pointer to inode
+ * @bh - pointer to block which hold "pointer" to new allocated block
+ * @fragment - number of `fragment' which hold pointer
+ * to new allocated block
+ * @new_fragment - number of new allocated fragment
+ * (block will hold this fragment and also uspi->s_fpb-1)
+ * @err - see ufs_inode_getfrag()
+ * @phys - see ufs_inode_getfrag()
+ * @new - see ufs_inode_getfrag()
+ * @locked_page - see ufs_inode_getfrag()
+ */
+static struct buffer_head *
+ufs_inode_getblock(struct inode *inode, struct buffer_head *bh,
+ unsigned int fragment, sector_t new_fragment, int *err,
+ long *phys, int *new, struct page *locked_page)
{
- struct super_block * sb;
- struct ufs_sb_private_info * uspi;
+ struct super_block *sb = inode->i_sb;
+ struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
struct buffer_head * result;
unsigned tmp, goal, block, blockoff;
__fs32 * p;
- sb = inode->i_sb;
- uspi = UFS_SB(sb)->s_uspi;
block = ufs_fragstoblks (fragment);
blockoff = ufs_fragnum (fragment);
- UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u\n", inode->i_ino, fragment, new_fragment))
+ UFSD("ENTER, ino %lu, fragment %u, new_fragment %llu, metadata %d\n",
+ inode->i_ino, fragment, (unsigned long long)new_fragment, !phys);
result = NULL;
if (!bh)
@@ -326,14 +369,14 @@ static struct buffer_head * ufs_block_getfrag (struct inode *inode,
repeat:
tmp = fs32_to_cpu(sb, *p);
if (tmp) {
- if (metadata) {
+ if (!phys) {
result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff);
if (tmp == fs32_to_cpu(sb, *p))
goto out;
brelse (result);
goto repeat;
} else {
- *phys = tmp;
+ *phys = tmp + blockoff;
goto out;
}
}
@@ -342,21 +385,19 @@ repeat:
goal = tmp + uspi->s_fpb;
else
goal = bh->b_blocknr + uspi->s_fpb;
- tmp = ufs_new_fragments (inode, p, ufs_blknum(new_fragment), goal, uspi->s_fpb, err);
+ tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), goal,
+ uspi->s_fpb, err, locked_page);
if (!tmp) {
if (fs32_to_cpu(sb, *p))
goto repeat;
goto out;
}
- /* The nullification of framgents done in ufs/balloc.c is
- * something I don't have the stomache to move into here right
- * now. -DaveM
- */
- if (metadata) {
- result = sb_getblk(sb, tmp + blockoff);
+
+ if (!phys) {
+ result = ufs_clear_frags(inode, tmp + blockoff, uspi->s_fpb);
} else {
- *phys = tmp;
+ *phys = tmp + blockoff;
*new = 1;
}
@@ -365,18 +406,19 @@ repeat:
sync_dirty_buffer(bh);
inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
- UFSD(("result %u\n", tmp + blockoff));
+ UFSD("result %u\n", tmp + blockoff);
out:
brelse (bh);
- UFSD(("EXIT\n"));
+ UFSD("EXIT\n");
return result;
}
-/*
- * This function gets the block which contains the fragment.
+/**
+ * ufs_getfrag_bloc() - `get_block_t' function, interface between UFS and
+ * readpage, writepage and so on
*/
-int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create)
+int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create)
{
struct super_block * sb = inode->i_sb;
struct ufs_sb_private_info * uspi = UFS_SB(sb)->s_uspi;
@@ -387,7 +429,7 @@ int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_hea
if (!create) {
phys64 = ufs_frag_map(inode, fragment);
- UFSD(("phys64 = %llu \n",phys64));
+ UFSD("phys64 = %llu \n",phys64);
if (phys64)
map_bh(bh_result, sb, phys64);
return 0;
@@ -402,7 +444,7 @@ int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_hea
lock_kernel();
- UFSD(("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment))
+ UFSD("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment);
if (fragment < 0)
goto abort_negative;
if (fragment >
@@ -418,15 +460,15 @@ int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_hea
* it much more readable:
*/
#define GET_INODE_DATABLOCK(x) \
- ufs_inode_getfrag(inode, x, fragment, 1, &err, 0, &phys, &new)
+ ufs_inode_getfrag(inode, x, fragment, 1, &err, &phys, &new, bh_result->b_page)
#define GET_INODE_PTR(x) \
- ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, 1, NULL, NULL)
+ ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, NULL, NULL, bh_result->b_page)
#define GET_INDIRECT_DATABLOCK(x) \
- ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \
- &err, 0, &phys, &new);
+ ufs_inode_getblock(inode, bh, x, fragment, \
+ &err, &phys, &new, bh_result->b_page);
#define GET_INDIRECT_PTR(x) \
- ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \
- &err, 1, NULL, NULL);
+ ufs_inode_getblock(inode, bh, x, fragment, \
+ &err, NULL, NULL, bh_result->b_page);
if (ptr < UFS_NDIR_FRAGMENT) {
bh = GET_INODE_DATABLOCK(ptr);
@@ -474,8 +516,9 @@ abort_too_big:
goto abort;
}
-struct buffer_head *ufs_getfrag(struct inode *inode, unsigned int fragment,
- int create, int *err)
+static struct buffer_head *ufs_getfrag(struct inode *inode,
+ unsigned int fragment,
+ int create, int *err)
{
struct buffer_head dummy;
int error;
@@ -502,7 +545,7 @@ struct buffer_head * ufs_bread (struct inode * inode, unsigned fragment,
{
struct buffer_head * bh;
- UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment))
+ UFSD("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment);
bh = ufs_getfrag (inode, fragment, create, err);
if (!bh || buffer_uptodate(bh))
return bh;
@@ -540,6 +583,28 @@ struct address_space_operations ufs_aops = {
.bmap = ufs_bmap
};
+static void ufs_set_inode_ops(struct inode *inode)
+{
+ if (S_ISREG(inode->i_mode)) {
+ inode->i_op = &ufs_file_inode_operations;
+ inode->i_fop = &ufs_file_operations;
+ inode->i_mapping->a_ops = &ufs_aops;
+ } else if (S_ISDIR(inode->i_mode)) {
+ inode->i_op = &ufs_dir_inode_operations;
+ inode->i_fop = &ufs_dir_operations;
+ inode->i_mapping->a_ops = &ufs_aops;
+ } else if (S_ISLNK(inode->i_mode)) {
+ if (!inode->i_blocks)
+ inode->i_op = &ufs_fast_symlink_inode_operations;
+ else {
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_mapping->a_ops = &ufs_aops;
+ }
+ } else
+ init_special_inode(inode, inode->i_mode,
+ ufs_get_inode_dev(inode->i_sb, UFS_I(inode)));
+}
+
void ufs_read_inode (struct inode * inode)
{
struct ufs_inode_info *ufsi = UFS_I(inode);
@@ -552,7 +617,7 @@ void ufs_read_inode (struct inode * inode)
unsigned i;
unsigned flags;
- UFSD(("ENTER, ino %lu\n", inode->i_ino))
+ UFSD("ENTER, ino %lu\n", inode->i_ino);
sb = inode->i_sb;
uspi = UFS_SB(sb)->s_uspi;
@@ -603,38 +668,22 @@ void ufs_read_inode (struct inode * inode)
ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow);
ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag);
ufsi->i_lastfrag = (inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift;
+ ufsi->i_dir_start_lookup = 0;
if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) {
for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++)
ufsi->i_u1.i_data[i] = ufs_inode->ui_u2.ui_addr.ui_db[i];
- }
- else {
+ } else {
for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++)
ufsi->i_u1.i_symlink[i] = ufs_inode->ui_u2.ui_symlink[i];
}
ufsi->i_osync = 0;
- if (S_ISREG(inode->i_mode)) {
- inode->i_op = &ufs_file_inode_operations;
- inode->i_fop = &ufs_file_operations;
- inode->i_mapping->a_ops = &ufs_aops;
- } else if (S_ISDIR(inode->i_mode)) {
- inode->i_op = &ufs_dir_inode_operations;
- inode->i_fop = &ufs_dir_operations;
- } else if (S_ISLNK(inode->i_mode)) {
- if (!inode->i_blocks)
- inode->i_op = &ufs_fast_symlink_inode_operations;
- else {
- inode->i_op = &page_symlink_inode_operations;
- inode->i_mapping->a_ops = &ufs_aops;
- }
- } else
- init_special_inode(inode, inode->i_mode,
- ufs_get_inode_dev(sb, ufsi));
+ ufs_set_inode_ops(inode);
brelse (bh);
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
return;
bad_inode:
@@ -642,7 +691,7 @@ bad_inode:
return;
ufs2_inode :
- UFSD(("Reading ufs2 inode, ino %lu\n", inode->i_ino))
+ UFSD("Reading ufs2 inode, ino %lu\n", inode->i_ino);
ufs2_inode = (struct ufs2_inode *)(bh->b_data + sizeof(struct ufs2_inode) * ufs_inotofsbo(inode->i_ino));
@@ -690,27 +739,11 @@ ufs2_inode :
}
ufsi->i_osync = 0;
- if (S_ISREG(inode->i_mode)) {
- inode->i_op = &ufs_file_inode_operations;
- inode->i_fop = &ufs_file_operations;
- inode->i_mapping->a_ops = &ufs_aops;
- } else if (S_ISDIR(inode->i_mode)) {
- inode->i_op = &ufs_dir_inode_operations;
- inode->i_fop = &ufs_dir_operations;
- } else if (S_ISLNK(inode->i_mode)) {
- if (!inode->i_blocks)
- inode->i_op = &ufs_fast_symlink_inode_operations;
- else {
- inode->i_op = &page_symlink_inode_operations;
- inode->i_mapping->a_ops = &ufs_aops;
- }
- } else /* TODO : here ...*/
- init_special_inode(inode, inode->i_mode,
- ufs_get_inode_dev(sb, ufsi));
+ ufs_set_inode_ops(inode);
brelse(bh);
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
return;
}
@@ -724,7 +757,7 @@ static int ufs_update_inode(struct inode * inode, int do_sync)
unsigned i;
unsigned flags;
- UFSD(("ENTER, ino %lu\n", inode->i_ino))
+ UFSD("ENTER, ino %lu\n", inode->i_ino);
sb = inode->i_sb;
uspi = UFS_SB(sb)->s_uspi;
@@ -785,7 +818,7 @@ static int ufs_update_inode(struct inode * inode, int do_sync)
sync_dirty_buffer(bh);
brelse (bh);
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
return 0;
}
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
index 8d5f98a..abd5f23 100644
--- a/fs/ufs/namei.c
+++ b/fs/ufs/namei.c
@@ -1,6 +1,9 @@
/*
* linux/fs/ufs/namei.c
*
+ * Migration to usage of "page cache" on May 2006 by
+ * Evgeniy Dushistov <dushistov@mail.ru> based on ext2 code base.
+ *
* Copyright (C) 1998
* Daniel Pirkl <daniel.pirkl@email.cz>
* Charles University, Faculty of Mathematics and Physics
@@ -28,21 +31,9 @@
#include <linux/fs.h>
#include <linux/ufs_fs.h>
#include <linux/smp_lock.h>
-#include <linux/buffer_head.h>
#include "swab.h" /* will go away - see comment in mknod() */
#include "util.h"
-/*
-#undef UFS_NAMEI_DEBUG
-*/
-#define UFS_NAMEI_DEBUG
-
-#ifdef UFS_NAMEI_DEBUG
-#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
static inline int ufs_add_nondir(struct dentry *dentry, struct inode *inode)
{
int err = ufs_add_link(dentry, inode);
@@ -88,8 +79,13 @@ static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, stru
static int ufs_create (struct inode * dir, struct dentry * dentry, int mode,
struct nameidata *nd)
{
- struct inode * inode = ufs_new_inode(dir, mode);
- int err = PTR_ERR(inode);
+ struct inode *inode;
+ int err;
+
+ UFSD("BEGIN\n");
+ inode = ufs_new_inode(dir, mode);
+ err = PTR_ERR(inode);
+
if (!IS_ERR(inode)) {
inode->i_op = &ufs_file_inode_operations;
inode->i_fop = &ufs_file_operations;
@@ -99,6 +95,7 @@ static int ufs_create (struct inode * dir, struct dentry * dentry, int mode,
err = ufs_add_nondir(dentry, inode);
unlock_kernel();
}
+ UFSD("END: err=%d\n", err);
return err;
}
@@ -205,6 +202,7 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
inode->i_op = &ufs_dir_inode_operations;
inode->i_fop = &ufs_dir_operations;
+ inode->i_mapping->a_ops = &ufs_aops;
inode_inc_link_count(inode);
@@ -231,19 +229,18 @@ out_dir:
goto out;
}
-static int ufs_unlink(struct inode * dir, struct dentry *dentry)
+static int ufs_unlink(struct inode *dir, struct dentry *dentry)
{
struct inode * inode = dentry->d_inode;
- struct buffer_head * bh;
- struct ufs_dir_entry * de;
+ struct ufs_dir_entry *de;
+ struct page *page;
int err = -ENOENT;
- lock_kernel();
- de = ufs_find_entry (dentry, &bh);
+ de = ufs_find_entry(dir, dentry, &page);
if (!de)
goto out;
- err = ufs_delete_entry (dir, de, bh);
+ err = ufs_delete_entry(dir, de, page);
if (err)
goto out;
@@ -251,7 +248,6 @@ static int ufs_unlink(struct inode * dir, struct dentry *dentry)
inode_dec_link_count(inode);
err = 0;
out:
- unlock_kernel();
return err;
}
@@ -273,42 +269,42 @@ static int ufs_rmdir (struct inode * dir, struct dentry *dentry)
return err;
}
-static int ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
- struct inode * new_dir, struct dentry * new_dentry )
+static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
{
struct inode *old_inode = old_dentry->d_inode;
struct inode *new_inode = new_dentry->d_inode;
- struct buffer_head *dir_bh = NULL;
- struct ufs_dir_entry *dir_de = NULL;
- struct buffer_head *old_bh;
+ struct page *dir_page = NULL;
+ struct ufs_dir_entry * dir_de = NULL;
+ struct page *old_page;
struct ufs_dir_entry *old_de;
int err = -ENOENT;
- lock_kernel();
- old_de = ufs_find_entry (old_dentry, &old_bh);
+ old_de = ufs_find_entry(old_dir, old_dentry, &old_page);
if (!old_de)
goto out;
if (S_ISDIR(old_inode->i_mode)) {
err = -EIO;
- dir_de = ufs_dotdot(old_inode, &dir_bh);
+ dir_de = ufs_dotdot(old_inode, &dir_page);
if (!dir_de)
goto out_old;
}
if (new_inode) {
- struct buffer_head *new_bh;
+ struct page *new_page;
struct ufs_dir_entry *new_de;
err = -ENOTEMPTY;
- if (dir_de && !ufs_empty_dir (new_inode))
+ if (dir_de && !ufs_empty_dir(new_inode))
goto out_dir;
+
err = -ENOENT;
- new_de = ufs_find_entry (new_dentry, &new_bh);
+ new_de = ufs_find_entry(new_dir, new_dentry, &new_page);
if (!new_de)
goto out_dir;
inode_inc_link_count(old_inode);
- ufs_set_link(new_dir, new_de, new_bh, old_inode);
+ ufs_set_link(new_dir, new_de, new_page, old_inode);
new_inode->i_ctime = CURRENT_TIME_SEC;
if (dir_de)
new_inode->i_nlink--;
@@ -329,24 +325,32 @@ static int ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
inode_inc_link_count(new_dir);
}
- ufs_delete_entry (old_dir, old_de, old_bh);
+ /*
+ * Like most other Unix systems, set the ctime for inodes on a
+ * rename.
+ * inode_dec_link_count() will mark the inode dirty.
+ */
+ old_inode->i_ctime = CURRENT_TIME_SEC;
+ ufs_delete_entry(old_dir, old_de, old_page);
inode_dec_link_count(old_inode);
if (dir_de) {
- ufs_set_link(old_inode, dir_de, dir_bh, new_dir);
+ ufs_set_link(old_inode, dir_de, dir_page, new_dir);
inode_dec_link_count(old_dir);
}
- unlock_kernel();
return 0;
+
out_dir:
- if (dir_de)
- brelse(dir_bh);
+ if (dir_de) {
+ kunmap(dir_page);
+ page_cache_release(dir_page);
+ }
out_old:
- brelse (old_bh);
+ kunmap(old_page);
+ page_cache_release(old_page);
out:
- unlock_kernel();
return err;
}
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index db98a4c..74ef5e9 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -90,95 +90,84 @@
#include "swab.h"
#include "util.h"
-#undef UFS_SUPER_DEBUG
-#undef UFS_SUPER_DEBUG_MORE
-
-
-#undef UFS_SUPER_DEBUG_MORE
-#ifdef UFS_SUPER_DEBUG
-#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
-#ifdef UFS_SUPER_DEBUG_MORE
+#ifdef CONFIG_UFS_DEBUG
/*
* Print contents of ufs_super_block, useful for debugging
*/
-void ufs_print_super_stuff(struct super_block *sb,
- struct ufs_super_block_first * usb1,
- struct ufs_super_block_second * usb2,
- struct ufs_super_block_third * usb3)
+static void ufs_print_super_stuff(struct super_block *sb, unsigned flags,
+ struct ufs_super_block_first *usb1,
+ struct ufs_super_block_second *usb2,
+ struct ufs_super_block_third *usb3)
{
printk("ufs_print_super_stuff\n");
- printk("size of usb: %u\n", sizeof(struct ufs_super_block));
- printk(" magic: 0x%x\n", fs32_to_cpu(sb, usb3->fs_magic));
- printk(" sblkno: %u\n", fs32_to_cpu(sb, usb1->fs_sblkno));
- printk(" cblkno: %u\n", fs32_to_cpu(sb, usb1->fs_cblkno));
- printk(" iblkno: %u\n", fs32_to_cpu(sb, usb1->fs_iblkno));
- printk(" dblkno: %u\n", fs32_to_cpu(sb, usb1->fs_dblkno));
- printk(" cgoffset: %u\n", fs32_to_cpu(sb, usb1->fs_cgoffset));
- printk(" ~cgmask: 0x%x\n", ~fs32_to_cpu(sb, usb1->fs_cgmask));
- printk(" size: %u\n", fs32_to_cpu(sb, usb1->fs_size));
- printk(" dsize: %u\n", fs32_to_cpu(sb, usb1->fs_dsize));
- printk(" ncg: %u\n", fs32_to_cpu(sb, usb1->fs_ncg));
- printk(" bsize: %u\n", fs32_to_cpu(sb, usb1->fs_bsize));
- printk(" fsize: %u\n", fs32_to_cpu(sb, usb1->fs_fsize));
- printk(" frag: %u\n", fs32_to_cpu(sb, usb1->fs_frag));
- printk(" fragshift: %u\n", fs32_to_cpu(sb, usb1->fs_fragshift));
- printk(" ~fmask: %u\n", ~fs32_to_cpu(sb, usb1->fs_fmask));
- printk(" fshift: %u\n", fs32_to_cpu(sb, usb1->fs_fshift));
- printk(" sbsize: %u\n", fs32_to_cpu(sb, usb1->fs_sbsize));
- printk(" spc: %u\n", fs32_to_cpu(sb, usb1->fs_spc));
- printk(" cpg: %u\n", fs32_to_cpu(sb, usb1->fs_cpg));
- printk(" ipg: %u\n", fs32_to_cpu(sb, usb1->fs_ipg));
- printk(" fpg: %u\n", fs32_to_cpu(sb, usb1->fs_fpg));
- printk(" csaddr: %u\n", fs32_to_cpu(sb, usb1->fs_csaddr));
- printk(" cssize: %u\n", fs32_to_cpu(sb, usb1->fs_cssize));
- printk(" cgsize: %u\n", fs32_to_cpu(sb, usb1->fs_cgsize));
- printk(" fstodb: %u\n", fs32_to_cpu(sb, usb1->fs_fsbtodb));
- printk(" contigsumsize: %d\n", fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_contigsumsize));
- printk(" postblformat: %u\n", fs32_to_cpu(sb, usb3->fs_postblformat));
- printk(" nrpos: %u\n", fs32_to_cpu(sb, usb3->fs_nrpos));
- printk(" ndir %u\n", fs32_to_cpu(sb, usb1->fs_cstotal.cs_ndir));
- printk(" nifree %u\n", fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree));
- printk(" nbfree %u\n", fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree));
- printk(" nffree %u\n", fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree));
- printk("\n");
-}
-
-/*
- * Print contents of ufs2 ufs_super_block, useful for debugging
- */
-void ufs2_print_super_stuff(
- struct super_block *sb,
- struct ufs_super_block *usb)
-{
- printk("ufs_print_super_stuff\n");
- printk("size of usb: %u\n", sizeof(struct ufs_super_block));
- printk(" magic: 0x%x\n", fs32_to_cpu(sb, usb->fs_magic));
- printk(" fs_size: %u\n",fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_size));
- printk(" fs_dsize: %u\n",fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize));
- printk(" bsize: %u\n", fs32_to_cpu(usb, usb->fs_bsize));
- printk(" fsize: %u\n", fs32_to_cpu(usb, usb->fs_fsize));
- printk(" fs_volname: %s\n", usb->fs_u11.fs_u2.fs_volname);
- printk(" fs_fsmnt: %s\n", usb->fs_u11.fs_u2.fs_fsmnt);
- printk(" fs_sblockloc: %u\n",fs64_to_cpu(sb,
- usb->fs_u11.fs_u2.fs_sblockloc));
- printk(" cs_ndir(No of dirs): %u\n",fs64_to_cpu(sb,
- usb->fs_u11.fs_u2.fs_cstotal.cs_ndir));
- printk(" cs_nbfree(No of free blocks): %u\n",fs64_to_cpu(sb,
- usb->fs_u11.fs_u2.fs_cstotal.cs_nbfree));
+ printk(" magic: 0x%x\n", fs32_to_cpu(sb, usb3->fs_magic));
+ if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
+ printk(" fs_size: %llu\n", (unsigned long long)
+ fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_size));
+ printk(" fs_dsize: %llu\n", (unsigned long long)
+ fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_dsize));
+ printk(" bsize: %u\n",
+ fs32_to_cpu(sb, usb1->fs_bsize));
+ printk(" fsize: %u\n",
+ fs32_to_cpu(sb, usb1->fs_fsize));
+ printk(" fs_volname: %s\n", usb2->fs_un.fs_u2.fs_volname);
+ printk(" fs_sblockloc: %llu\n", (unsigned long long)
+ fs64_to_cpu(sb, usb2->fs_un.fs_u2.fs_sblockloc));
+ printk(" cs_ndir(No of dirs): %llu\n", (unsigned long long)
+ fs64_to_cpu(sb, usb2->fs_un.fs_u2.cs_ndir));
+ printk(" cs_nbfree(No of free blocks): %llu\n",
+ (unsigned long long)
+ fs64_to_cpu(sb, usb2->fs_un.fs_u2.cs_nbfree));
+ } else {
+ printk(" sblkno: %u\n", fs32_to_cpu(sb, usb1->fs_sblkno));
+ printk(" cblkno: %u\n", fs32_to_cpu(sb, usb1->fs_cblkno));
+ printk(" iblkno: %u\n", fs32_to_cpu(sb, usb1->fs_iblkno));
+ printk(" dblkno: %u\n", fs32_to_cpu(sb, usb1->fs_dblkno));
+ printk(" cgoffset: %u\n",
+ fs32_to_cpu(sb, usb1->fs_cgoffset));
+ printk(" ~cgmask: 0x%x\n",
+ ~fs32_to_cpu(sb, usb1->fs_cgmask));
+ printk(" size: %u\n", fs32_to_cpu(sb, usb1->fs_size));
+ printk(" dsize: %u\n", fs32_to_cpu(sb, usb1->fs_dsize));
+ printk(" ncg: %u\n", fs32_to_cpu(sb, usb1->fs_ncg));
+ printk(" bsize: %u\n", fs32_to_cpu(sb, usb1->fs_bsize));
+ printk(" fsize: %u\n", fs32_to_cpu(sb, usb1->fs_fsize));
+ printk(" frag: %u\n", fs32_to_cpu(sb, usb1->fs_frag));
+ printk(" fragshift: %u\n",
+ fs32_to_cpu(sb, usb1->fs_fragshift));
+ printk(" ~fmask: %u\n", ~fs32_to_cpu(sb, usb1->fs_fmask));
+ printk(" fshift: %u\n", fs32_to_cpu(sb, usb1->fs_fshift));
+ printk(" sbsize: %u\n", fs32_to_cpu(sb, usb1->fs_sbsize));
+ printk(" spc: %u\n", fs32_to_cpu(sb, usb1->fs_spc));
+ printk(" cpg: %u\n", fs32_to_cpu(sb, usb1->fs_cpg));
+ printk(" ipg: %u\n", fs32_to_cpu(sb, usb1->fs_ipg));
+ printk(" fpg: %u\n", fs32_to_cpu(sb, usb1->fs_fpg));
+ printk(" csaddr: %u\n", fs32_to_cpu(sb, usb1->fs_csaddr));
+ printk(" cssize: %u\n", fs32_to_cpu(sb, usb1->fs_cssize));
+ printk(" cgsize: %u\n", fs32_to_cpu(sb, usb1->fs_cgsize));
+ printk(" fstodb: %u\n",
+ fs32_to_cpu(sb, usb1->fs_fsbtodb));
+ printk(" nrpos: %u\n", fs32_to_cpu(sb, usb3->fs_nrpos));
+ printk(" ndir %u\n",
+ fs32_to_cpu(sb, usb1->fs_cstotal.cs_ndir));
+ printk(" nifree %u\n",
+ fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree));
+ printk(" nbfree %u\n",
+ fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree));
+ printk(" nffree %u\n",
+ fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree));
+ }
printk("\n");
}
/*
* Print contents of ufs_cylinder_group, useful for debugging
*/
-void ufs_print_cylinder_stuff(struct super_block *sb, struct ufs_cylinder_group *cg)
+static void ufs_print_cylinder_stuff(struct super_block *sb,
+ struct ufs_cylinder_group *cg)
{
printk("\nufs_print_cylinder_stuff\n");
- printk("size of ucg: %u\n", sizeof(struct ufs_cylinder_group));
+ printk("size of ucg: %zu\n", sizeof(struct ufs_cylinder_group));
printk(" magic: %x\n", fs32_to_cpu(sb, cg->cg_magic));
printk(" time: %u\n", fs32_to_cpu(sb, cg->cg_time));
printk(" cgx: %u\n", fs32_to_cpu(sb, cg->cg_cgx));
@@ -202,12 +191,18 @@ void ufs_print_cylinder_stuff(struct super_block *sb, struct ufs_cylinder_group
printk(" iuseoff: %u\n", fs32_to_cpu(sb, cg->cg_iusedoff));
printk(" freeoff: %u\n", fs32_to_cpu(sb, cg->cg_freeoff));
printk(" nextfreeoff: %u\n", fs32_to_cpu(sb, cg->cg_nextfreeoff));
- printk(" clustersumoff %u\n", fs32_to_cpu(sb, cg->cg_u.cg_44.cg_clustersumoff));
- printk(" clusteroff %u\n", fs32_to_cpu(sb, cg->cg_u.cg_44.cg_clusteroff));
- printk(" nclusterblks %u\n", fs32_to_cpu(sb, cg->cg_u.cg_44.cg_nclusterblks));
+ printk(" clustersumoff %u\n",
+ fs32_to_cpu(sb, cg->cg_u.cg_44.cg_clustersumoff));
+ printk(" clusteroff %u\n",
+ fs32_to_cpu(sb, cg->cg_u.cg_44.cg_clusteroff));
+ printk(" nclusterblks %u\n",
+ fs32_to_cpu(sb, cg->cg_u.cg_44.cg_nclusterblks));
printk("\n");
}
-#endif /* UFS_SUPER_DEBUG_MORE */
+#else
+# define ufs_print_super_stuff(sb, flags, usb1, usb2, usb3) /**/
+# define ufs_print_cylinder_stuff(sb, cg) /**/
+#endif /* CONFIG_UFS_DEBUG */
static struct super_operations ufs_super_ops;
@@ -225,7 +220,7 @@ void ufs_error (struct super_block * sb, const char * function,
if (!(sb->s_flags & MS_RDONLY)) {
usb1->fs_clean = UFS_FSBAD;
- ubh_mark_buffer_dirty(USPI_UBH);
+ ubh_mark_buffer_dirty(USPI_UBH(uspi));
sb->s_dirt = 1;
sb->s_flags |= MS_RDONLY;
}
@@ -257,7 +252,7 @@ void ufs_panic (struct super_block * sb, const char * function,
if (!(sb->s_flags & MS_RDONLY)) {
usb1->fs_clean = UFS_FSBAD;
- ubh_mark_buffer_dirty(USPI_UBH);
+ ubh_mark_buffer_dirty(USPI_UBH(uspi));
sb->s_dirt = 1;
}
va_start (args, fmt);
@@ -309,7 +304,7 @@ static int ufs_parse_options (char * options, unsigned * mount_options)
{
char * p;
- UFSD(("ENTER\n"))
+ UFSD("ENTER\n");
if (!options)
return 1;
@@ -386,27 +381,57 @@ static int ufs_parse_options (char * options, unsigned * mount_options)
}
/*
+ * Diffrent types of UFS hold fs_cstotal in different
+ * places, and use diffrent data structure for it.
+ * To make things simplier we just copy fs_cstotal to ufs_sb_private_info
+ */
+static void ufs_setup_cstotal(struct super_block *sb)
+{
+ struct ufs_sb_info *sbi = UFS_SB(sb);
+ struct ufs_sb_private_info *uspi = sbi->s_uspi;
+ struct ufs_super_block_first *usb1;
+ struct ufs_super_block_second *usb2;
+ struct ufs_super_block_third *usb3;
+ unsigned mtype = sbi->s_mount_opt & UFS_MOUNT_UFSTYPE;
+
+ UFSD("ENTER, mtype=%u\n", mtype);
+ usb1 = ubh_get_usb_first(uspi);
+ usb2 = ubh_get_usb_second(uspi);
+ usb3 = ubh_get_usb_third(uspi);
+
+ if ((mtype == UFS_MOUNT_UFSTYPE_44BSD &&
+ (usb1->fs_flags & UFS_FLAGS_UPDATED)) ||
+ mtype == UFS_MOUNT_UFSTYPE_UFS2) {
+ /*we have statistic in different place, then usual*/
+ uspi->cs_total.cs_ndir = fs64_to_cpu(sb, usb2->fs_un.fs_u2.cs_ndir);
+ uspi->cs_total.cs_nbfree = fs64_to_cpu(sb, usb2->fs_un.fs_u2.cs_nbfree);
+ uspi->cs_total.cs_nifree = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.cs_nifree);
+ uspi->cs_total.cs_nffree = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.cs_nffree);
+ } else {
+ uspi->cs_total.cs_ndir = fs32_to_cpu(sb, usb1->fs_cstotal.cs_ndir);
+ uspi->cs_total.cs_nbfree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree);
+ uspi->cs_total.cs_nifree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree);
+ uspi->cs_total.cs_nffree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree);
+ }
+ UFSD("EXIT\n");
+}
+
+/*
* Read on-disk structures associated with cylinder groups
*/
-static int ufs_read_cylinder_structures (struct super_block *sb)
+static int ufs_read_cylinder_structures(struct super_block *sb)
{
- struct ufs_sb_info * sbi = UFS_SB(sb);
- struct ufs_sb_private_info * uspi;
- struct ufs_super_block *usb;
+ struct ufs_sb_info *sbi = UFS_SB(sb);
+ struct ufs_sb_private_info *uspi = sbi->s_uspi;
+ unsigned flags = sbi->s_flags;
struct ufs_buffer_head * ubh;
unsigned char * base, * space;
unsigned size, blks, i;
- unsigned flags = 0;
-
- UFSD(("ENTER\n"))
-
- uspi = sbi->s_uspi;
+ struct ufs_super_block_third *usb3;
- usb = (struct ufs_super_block *)
- ((struct ufs_buffer_head *)uspi)->bh[0]->b_data;
+ UFSD("ENTER\n");
- flags = UFS_SB(sb)->s_flags;
-
+ usb3 = ubh_get_usb_third(uspi);
/*
* Read cs structures from (usually) first data block
* on the device.
@@ -424,7 +449,7 @@ static int ufs_read_cylinder_structures (struct super_block *sb)
if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
ubh = ubh_bread(sb,
- fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_csaddr) + i, size);
+ fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_csaddr) + i, size);
else
ubh = ubh_bread(sb, uspi->s_csaddr + i, size);
@@ -451,14 +476,13 @@ static int ufs_read_cylinder_structures (struct super_block *sb)
sbi->s_cgno[i] = UFS_CGNO_EMPTY;
}
for (i = 0; i < uspi->s_ncg; i++) {
- UFSD(("read cg %u\n", i))
+ UFSD("read cg %u\n", i);
if (!(sbi->s_ucg[i] = sb_bread(sb, ufs_cgcmin(i))))
goto failed;
if (!ufs_cg_chkmagic (sb, (struct ufs_cylinder_group *) sbi->s_ucg[i]->b_data))
goto failed;
-#ifdef UFS_SUPER_DEBUG_MORE
+
ufs_print_cylinder_stuff(sb, (struct ufs_cylinder_group *) sbi->s_ucg[i]->b_data);
-#endif
}
for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) {
if (!(sbi->s_ucpi[i] = kmalloc (sizeof(struct ufs_cg_private_info), GFP_KERNEL)))
@@ -466,7 +490,7 @@ static int ufs_read_cylinder_structures (struct super_block *sb)
sbi->s_cgno[i] = UFS_CGNO_EMPTY;
}
sbi->s_cg_loaded = 0;
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
return 1;
failed:
@@ -479,26 +503,69 @@ failed:
for (i = 0; i < UFS_MAX_GROUP_LOADED; i++)
kfree (sbi->s_ucpi[i]);
}
- UFSD(("EXIT (FAILED)\n"))
+ UFSD("EXIT (FAILED)\n");
return 0;
}
/*
- * Put on-disk structures associated with cylinder groups and
- * write them back to disk
+ * Sync our internal copy of fs_cstotal with disk
*/
-static void ufs_put_cylinder_structures (struct super_block *sb)
+static void ufs_put_cstotal(struct super_block *sb)
{
- struct ufs_sb_info * sbi = UFS_SB(sb);
- struct ufs_sb_private_info * uspi;
+ unsigned mtype = UFS_SB(sb)->s_mount_opt & UFS_MOUNT_UFSTYPE;
+ struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
+ struct ufs_super_block_first *usb1;
+ struct ufs_super_block_second *usb2;
+ struct ufs_super_block_third *usb3;
+
+ UFSD("ENTER\n");
+ usb1 = ubh_get_usb_first(uspi);
+ usb2 = ubh_get_usb_second(uspi);
+ usb3 = ubh_get_usb_third(uspi);
+
+ if ((mtype == UFS_MOUNT_UFSTYPE_44BSD &&
+ (usb1->fs_flags & UFS_FLAGS_UPDATED)) ||
+ mtype == UFS_MOUNT_UFSTYPE_UFS2) {
+ /*we have statistic in different place, then usual*/
+ usb2->fs_un.fs_u2.cs_ndir =
+ cpu_to_fs64(sb, uspi->cs_total.cs_ndir);
+ usb2->fs_un.fs_u2.cs_nbfree =
+ cpu_to_fs64(sb, uspi->cs_total.cs_nbfree);
+ usb3->fs_un1.fs_u2.cs_nifree =
+ cpu_to_fs64(sb, uspi->cs_total.cs_nifree);
+ usb3->fs_un1.fs_u2.cs_nffree =
+ cpu_to_fs64(sb, uspi->cs_total.cs_nffree);
+ } else {
+ usb1->fs_cstotal.cs_ndir =
+ cpu_to_fs32(sb, uspi->cs_total.cs_ndir);
+ usb1->fs_cstotal.cs_nbfree =
+ cpu_to_fs32(sb, uspi->cs_total.cs_nbfree);
+ usb1->fs_cstotal.cs_nifree =
+ cpu_to_fs32(sb, uspi->cs_total.cs_nifree);
+ usb1->fs_cstotal.cs_nffree =
+ cpu_to_fs32(sb, uspi->cs_total.cs_nffree);
+ }
+ ubh_mark_buffer_dirty(USPI_UBH(uspi));
+ UFSD("EXIT\n");
+}
+
+/**
+ * ufs_put_super_internal() - put on-disk intrenal structures
+ * @sb: pointer to super_block structure
+ * Put on-disk structures associated with cylinder groups
+ * and write them back to disk, also update cs_total on disk
+ */
+static void ufs_put_super_internal(struct super_block *sb)
+{
+ struct ufs_sb_info *sbi = UFS_SB(sb);
+ struct ufs_sb_private_info *uspi = sbi->s_uspi;
struct ufs_buffer_head * ubh;
unsigned char * base, * space;
unsigned blks, size, i;
-
- UFSD(("ENTER\n"))
-
- uspi = sbi->s_uspi;
+
+ UFSD("ENTER\n");
+ ufs_put_cstotal(sb);
size = uspi->s_cssize;
blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift;
base = space = (char*) sbi->s_csp;
@@ -523,7 +590,7 @@ static void ufs_put_cylinder_structures (struct super_block *sb)
brelse (sbi->s_ucg[i]);
kfree (sbi->s_ucg);
kfree (base);
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
}
static int ufs_fill_super(struct super_block *sb, void *data, int silent)
@@ -533,7 +600,6 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
struct ufs_super_block_first * usb1;
struct ufs_super_block_second * usb2;
struct ufs_super_block_third * usb3;
- struct ufs_super_block *usb;
struct ufs_buffer_head * ubh;
struct inode *inode;
unsigned block_size, super_block_size;
@@ -544,7 +610,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
ubh = NULL;
flags = 0;
- UFSD(("ENTER\n"))
+ UFSD("ENTER\n");
sbi = kmalloc(sizeof(struct ufs_sb_info), GFP_KERNEL);
if (!sbi)
@@ -552,7 +618,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_fs_info = sbi;
memset(sbi, 0, sizeof(struct ufs_sb_info));
- UFSD(("flag %u\n", (int)(sb->s_flags & MS_RDONLY)))
+ UFSD("flag %u\n", (int)(sb->s_flags & MS_RDONLY));
#ifndef CONFIG_UFS_FS_WRITE
if (!(sb->s_flags & MS_RDONLY)) {
@@ -593,7 +659,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
the rules */
switch (sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) {
case UFS_MOUNT_UFSTYPE_44BSD:
- UFSD(("ufstype=44bsd\n"))
+ UFSD("ufstype=44bsd\n");
uspi->s_fsize = block_size = 512;
uspi->s_fmask = ~(512 - 1);
uspi->s_fshift = 9;
@@ -602,7 +668,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD;
break;
case UFS_MOUNT_UFSTYPE_UFS2:
- UFSD(("ufstype=ufs2\n"));
+ UFSD("ufstype=ufs2\n");
super_block_offset=SBLOCK_UFS2;
uspi->s_fsize = block_size = 512;
uspi->s_fmask = ~(512 - 1);
@@ -617,7 +683,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
break;
case UFS_MOUNT_UFSTYPE_SUN:
- UFSD(("ufstype=sun\n"))
+ UFSD("ufstype=sun\n");
uspi->s_fsize = block_size = 1024;
uspi->s_fmask = ~(1024 - 1);
uspi->s_fshift = 10;
@@ -628,7 +694,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
break;
case UFS_MOUNT_UFSTYPE_SUNx86:
- UFSD(("ufstype=sunx86\n"))
+ UFSD("ufstype=sunx86\n");
uspi->s_fsize = block_size = 1024;
uspi->s_fmask = ~(1024 - 1);
uspi->s_fshift = 10;
@@ -639,7 +705,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
break;
case UFS_MOUNT_UFSTYPE_OLD:
- UFSD(("ufstype=old\n"))
+ UFSD("ufstype=old\n");
uspi->s_fsize = block_size = 1024;
uspi->s_fmask = ~(1024 - 1);
uspi->s_fshift = 10;
@@ -654,7 +720,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
break;
case UFS_MOUNT_UFSTYPE_NEXTSTEP:
- UFSD(("ufstype=nextstep\n"))
+ UFSD("ufstype=nextstep\n");
uspi->s_fsize = block_size = 1024;
uspi->s_fmask = ~(1024 - 1);
uspi->s_fshift = 10;
@@ -669,7 +735,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
break;
case UFS_MOUNT_UFSTYPE_NEXTSTEP_CD:
- UFSD(("ufstype=nextstep-cd\n"))
+ UFSD("ufstype=nextstep-cd\n");
uspi->s_fsize = block_size = 2048;
uspi->s_fmask = ~(2048 - 1);
uspi->s_fshift = 11;
@@ -684,7 +750,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
break;
case UFS_MOUNT_UFSTYPE_OPENSTEP:
- UFSD(("ufstype=openstep\n"))
+ UFSD("ufstype=openstep\n");
uspi->s_fsize = block_size = 1024;
uspi->s_fmask = ~(1024 - 1);
uspi->s_fshift = 10;
@@ -699,7 +765,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
break;
case UFS_MOUNT_UFSTYPE_HP:
- UFSD(("ufstype=hp\n"))
+ UFSD("ufstype=hp\n");
uspi->s_fsize = block_size = 1024;
uspi->s_fmask = ~(1024 - 1);
uspi->s_fshift = 10;
@@ -737,8 +803,6 @@ again:
usb1 = ubh_get_usb_first(uspi);
usb2 = ubh_get_usb_second(uspi);
usb3 = ubh_get_usb_third(uspi);
- usb = (struct ufs_super_block *)
- ((struct ufs_buffer_head *)uspi)->bh[0]->b_data ;
/*
* Check ufs magic number
@@ -820,16 +884,12 @@ magic_found:
ubh = NULL;
block_size = uspi->s_fsize;
super_block_size = uspi->s_sbsize;
- UFSD(("another value of block_size or super_block_size %u, %u\n", block_size, super_block_size))
+ UFSD("another value of block_size or super_block_size %u, %u\n", block_size, super_block_size);
goto again;
}
-#ifdef UFS_SUPER_DEBUG_MORE
- if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
- ufs2_print_super_stuff(sb,usb);
- else
- ufs_print_super_stuff(sb, usb1, usb2, usb3);
-#endif
+
+ ufs_print_super_stuff(sb, flags, usb1, usb2, usb3);
/*
* Check, if file system was correctly unmounted.
@@ -842,13 +902,13 @@ magic_found:
(ufs_get_fs_state(sb, usb1, usb3) == (UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time))))) {
switch(usb1->fs_clean) {
case UFS_FSCLEAN:
- UFSD(("fs is clean\n"))
+ UFSD("fs is clean\n");
break;
case UFS_FSSTABLE:
- UFSD(("fs is stable\n"))
+ UFSD("fs is stable\n");
break;
case UFS_FSOSF1:
- UFSD(("fs is DEC OSF/1\n"))
+ UFSD("fs is DEC OSF/1\n");
break;
case UFS_FSACTIVE:
printk("ufs_read_super: fs is active\n");
@@ -863,8 +923,7 @@ magic_found:
sb->s_flags |= MS_RDONLY;
break;
}
- }
- else {
+ } else {
printk("ufs_read_super: fs needs fsck\n");
sb->s_flags |= MS_RDONLY;
}
@@ -884,10 +943,9 @@ magic_found:
uspi->s_cgmask = fs32_to_cpu(sb, usb1->fs_cgmask);
if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
- uspi->s_u2_size = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_size);
- uspi->s_u2_dsize = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize);
- }
- else {
+ uspi->s_u2_size = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_size);
+ uspi->s_u2_dsize = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_dsize);
+ } else {
uspi->s_size = fs32_to_cpu(sb, usb1->fs_size);
uspi->s_dsize = fs32_to_cpu(sb, usb1->fs_dsize);
}
@@ -901,8 +959,8 @@ magic_found:
uspi->s_fmask = fs32_to_cpu(sb, usb1->fs_fmask);
uspi->s_bshift = fs32_to_cpu(sb, usb1->fs_bshift);
uspi->s_fshift = fs32_to_cpu(sb, usb1->fs_fshift);
- UFSD(("uspi->s_bshift = %d,uspi->s_fshift = %d", uspi->s_bshift,
- uspi->s_fshift));
+ UFSD("uspi->s_bshift = %d,uspi->s_fshift = %d", uspi->s_bshift,
+ uspi->s_fshift);
uspi->s_fpbshift = fs32_to_cpu(sb, usb1->fs_fragshift);
uspi->s_fsbtodb = fs32_to_cpu(sb, usb1->fs_fsbtodb);
/* s_sbsize already set */
@@ -922,8 +980,8 @@ magic_found:
uspi->s_spc = fs32_to_cpu(sb, usb1->fs_spc);
uspi->s_ipg = fs32_to_cpu(sb, usb1->fs_ipg);
uspi->s_fpg = fs32_to_cpu(sb, usb1->fs_fpg);
- uspi->s_cpc = fs32_to_cpu(sb, usb2->fs_cpc);
- uspi->s_contigsumsize = fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_contigsumsize);
+ uspi->s_cpc = fs32_to_cpu(sb, usb2->fs_un.fs_u1.fs_cpc);
+ uspi->s_contigsumsize = fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_contigsumsize);
uspi->s_qbmask = ufs_get_fs_qbmask(sb, usb3);
uspi->s_qfmask = ufs_get_fs_qfmask(sb, usb3);
uspi->s_postblformat = fs32_to_cpu(sb, usb3->fs_postblformat);
@@ -935,12 +993,11 @@ magic_found:
* Compute another frequently used values
*/
uspi->s_fpbmask = uspi->s_fpb - 1;
- if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
+ if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
uspi->s_apbshift = uspi->s_bshift - 3;
- }
- else {
+ else
uspi->s_apbshift = uspi->s_bshift - 2;
- }
+
uspi->s_2apbshift = uspi->s_apbshift * 2;
uspi->s_3apbshift = uspi->s_apbshift * 3;
uspi->s_apb = 1 << uspi->s_apbshift;
@@ -956,7 +1013,7 @@ magic_found:
if ((sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) ==
UFS_MOUNT_UFSTYPE_44BSD)
uspi->s_maxsymlinklen =
- fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_maxsymlinklen);
+ fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_maxsymlinklen);
sbi->s_flags = flags;
@@ -967,7 +1024,7 @@ magic_found:
if (!sb->s_root)
goto dalloc_failed;
-
+ ufs_setup_cstotal(sb);
/*
* Read cylinder group structures
*/
@@ -975,7 +1032,7 @@ magic_found:
if (!ufs_read_cylinder_structures(sb))
goto failed;
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
return 0;
dalloc_failed:
@@ -986,15 +1043,16 @@ failed:
kfree (uspi);
kfree(sbi);
sb->s_fs_info = NULL;
- UFSD(("EXIT (FAILED)\n"))
+ UFSD("EXIT (FAILED)\n");
return -EINVAL;
failed_nomem:
- UFSD(("EXIT (NOMEM)\n"))
+ UFSD("EXIT (NOMEM)\n");
return -ENOMEM;
}
-static void ufs_write_super (struct super_block *sb) {
+static void ufs_write_super(struct super_block *sb)
+{
struct ufs_sb_private_info * uspi;
struct ufs_super_block_first * usb1;
struct ufs_super_block_third * usb3;
@@ -1002,7 +1060,7 @@ static void ufs_write_super (struct super_block *sb) {
lock_kernel();
- UFSD(("ENTER\n"))
+ UFSD("ENTER\n");
flags = UFS_SB(sb)->s_flags;
uspi = UFS_SB(sb)->s_uspi;
usb1 = ubh_get_usb_first(uspi);
@@ -1014,26 +1072,27 @@ static void ufs_write_super (struct super_block *sb) {
|| (flags & UFS_ST_MASK) == UFS_ST_SUNx86)
ufs_set_fs_state(sb, usb1, usb3,
UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time));
- ubh_mark_buffer_dirty (USPI_UBH);
+ ufs_put_cstotal(sb);
}
sb->s_dirt = 0;
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
unlock_kernel();
}
-static void ufs_put_super (struct super_block *sb)
+static void ufs_put_super(struct super_block *sb)
{
struct ufs_sb_info * sbi = UFS_SB(sb);
- UFSD(("ENTER\n"))
+ UFSD("ENTER\n");
if (!(sb->s_flags & MS_RDONLY))
- ufs_put_cylinder_structures (sb);
+ ufs_put_super_internal(sb);
ubh_brelse_uspi (sbi->s_uspi);
kfree (sbi->s_uspi);
kfree (sbi);
sb->s_fs_info = NULL;
+ UFSD("EXIT\n");
return;
}
@@ -1062,8 +1121,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)
return -EINVAL;
if (!(new_mount_opt & UFS_MOUNT_UFSTYPE)) {
new_mount_opt |= ufstype;
- }
- else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) {
+ } else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) {
printk("ufstype can't be changed during remount\n");
return -EINVAL;
}
@@ -1077,20 +1135,19 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)
* fs was mouted as rw, remounting ro
*/
if (*mount_flags & MS_RDONLY) {
- ufs_put_cylinder_structures(sb);
+ ufs_put_super_internal(sb);
usb1->fs_time = cpu_to_fs32(sb, get_seconds());
if ((flags & UFS_ST_MASK) == UFS_ST_SUN
|| (flags & UFS_ST_MASK) == UFS_ST_SUNx86)
ufs_set_fs_state(sb, usb1, usb3,
UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time));
- ubh_mark_buffer_dirty (USPI_UBH);
+ ubh_mark_buffer_dirty (USPI_UBH(uspi));
sb->s_dirt = 0;
sb->s_flags |= MS_RDONLY;
- }
+ } else {
/*
* fs was mounted as ro, remounting rw
*/
- else {
#ifndef CONFIG_UFS_FS_WRITE
printk("ufs was compiled with read-only support, "
"can't be mounted as read-write\n");
@@ -1102,7 +1159,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)
printk("this ufstype is read-only supported\n");
return -EINVAL;
}
- if (!ufs_read_cylinder_structures (sb)) {
+ if (!ufs_read_cylinder_structures(sb)) {
printk("failed during remounting\n");
return -EPERM;
}
@@ -1113,36 +1170,31 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)
return 0;
}
-static int ufs_statfs (struct super_block *sb, struct kstatfs *buf)
+static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
- struct ufs_sb_private_info * uspi;
- struct ufs_super_block_first * usb1;
- struct ufs_super_block * usb;
- unsigned flags = 0;
+ struct super_block *sb = dentry->d_sb;
+ struct ufs_sb_private_info *uspi= UFS_SB(sb)->s_uspi;
+ unsigned flags = UFS_SB(sb)->s_flags;
+ struct ufs_super_block_first *usb1;
+ struct ufs_super_block_second *usb2;
+ struct ufs_super_block_third *usb3;
lock_kernel();
- uspi = UFS_SB(sb)->s_uspi;
- usb1 = ubh_get_usb_first (uspi);
- usb = (struct ufs_super_block *)
- ((struct ufs_buffer_head *)uspi)->bh[0]->b_data ;
+ usb1 = ubh_get_usb_first(uspi);
+ usb2 = ubh_get_usb_second(uspi);
+ usb3 = ubh_get_usb_third(uspi);
- flags = UFS_SB(sb)->s_flags;
if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
buf->f_type = UFS2_MAGIC;
- buf->f_blocks = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize);
- buf->f_bfree = ufs_blkstofrags(fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_cstotal.cs_nbfree)) +
- fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_cstotal.cs_nffree);
- buf->f_ffree = fs64_to_cpu(sb,
- usb->fs_u11.fs_u2.fs_cstotal.cs_nifree);
- }
- else {
+ buf->f_blocks = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_dsize);
+ } else {
buf->f_type = UFS_MAGIC;
buf->f_blocks = uspi->s_dsize;
- buf->f_bfree = ufs_blkstofrags(fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree)) +
- fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree);
- buf->f_ffree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree);
}
+ buf->f_bfree = ufs_blkstofrags(uspi->cs_total.cs_nbfree) +
+ uspi->cs_total.cs_nffree;
+ buf->f_ffree = uspi->cs_total.cs_nifree;
buf->f_bsize = sb->s_blocksize;
buf->f_bavail = (buf->f_bfree > (((long)buf->f_blocks / 100) * uspi->s_minfree))
? (buf->f_bfree - (((long)buf->f_blocks / 100) * uspi->s_minfree)) : 0;
@@ -1311,10 +1363,10 @@ out:
#endif
-static struct super_block *ufs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int ufs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, ufs_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, ufs_fill_super, mnt);
}
static struct file_system_type ufs_fs_type = {
diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c
index 02e8629..3c3b301 100644
--- a/fs/ufs/truncate.c
+++ b/fs/ufs/truncate.c
@@ -49,14 +49,6 @@
#include "swab.h"
#include "util.h"
-#undef UFS_TRUNCATE_DEBUG
-
-#ifdef UFS_TRUNCATE_DEBUG
-#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
/*
* Secure deletion currently doesn't work. It interacts very badly
* with buffers shared with memory mappings, and for that reason
@@ -82,7 +74,7 @@ static int ufs_trunc_direct (struct inode * inode)
unsigned i, tmp;
int retry;
- UFSD(("ENTER\n"))
+ UFSD("ENTER\n");
sb = inode->i_sb;
uspi = UFS_SB(sb)->s_uspi;
@@ -105,7 +97,7 @@ static int ufs_trunc_direct (struct inode * inode)
block2 = ufs_fragstoblks (frag3);
}
- UFSD(("frag1 %u, frag2 %u, block1 %u, block2 %u, frag3 %u, frag4 %u\n", frag1, frag2, block1, block2, frag3, frag4))
+ UFSD("frag1 %u, frag2 %u, block1 %u, block2 %u, frag3 %u, frag4 %u\n", frag1, frag2, block1, block2, frag3, frag4);
if (frag1 >= frag2)
goto next1;
@@ -120,9 +112,8 @@ static int ufs_trunc_direct (struct inode * inode)
frag1 = ufs_fragnum (frag1);
frag2 = ufs_fragnum (frag2);
- inode->i_blocks -= (frag2-frag1) << uspi->s_nspfshift;
- mark_inode_dirty(inode);
ufs_free_fragments (inode, tmp + frag1, frag2 - frag1);
+ mark_inode_dirty(inode);
frag_to_free = tmp + frag1;
next1:
@@ -136,8 +127,7 @@ next1:
continue;
*p = 0;
- inode->i_blocks -= uspi->s_nspb;
- mark_inode_dirty(inode);
+
if (free_count == 0) {
frag_to_free = tmp;
free_count = uspi->s_fpb;
@@ -148,6 +138,7 @@ next1:
frag_to_free = tmp;
free_count = uspi->s_fpb;
}
+ mark_inode_dirty(inode);
}
if (free_count > 0)
@@ -166,12 +157,12 @@ next1:
frag4 = ufs_fragnum (frag4);
*p = 0;
- inode->i_blocks -= frag4 << uspi->s_nspfshift;
- mark_inode_dirty(inode);
+
ufs_free_fragments (inode, tmp, frag4);
+ mark_inode_dirty(inode);
next3:
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
return retry;
}
@@ -186,7 +177,7 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p)
unsigned frag_to_free, free_count;
int retry;
- UFSD(("ENTER\n"))
+ UFSD("ENTER\n");
sb = inode->i_sb;
uspi = UFS_SB(sb)->s_uspi;
@@ -227,7 +218,7 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p)
frag_to_free = tmp;
free_count = uspi->s_fpb;
}
- inode->i_blocks -= uspi->s_nspb;
+
mark_inode_dirty(inode);
}
@@ -238,26 +229,21 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p)
if (*ubh_get_addr32(ind_ubh,i))
break;
if (i >= uspi->s_apb) {
- if (ubh_max_bcount(ind_ubh) != 1) {
- retry = 1;
- }
- else {
- tmp = fs32_to_cpu(sb, *p);
- *p = 0;
- inode->i_blocks -= uspi->s_nspb;
- mark_inode_dirty(inode);
- ufs_free_blocks (inode, tmp, uspi->s_fpb);
- ubh_bforget(ind_ubh);
- ind_ubh = NULL;
- }
+ tmp = fs32_to_cpu(sb, *p);
+ *p = 0;
+
+ ufs_free_blocks (inode, tmp, uspi->s_fpb);
+ mark_inode_dirty(inode);
+ ubh_bforget(ind_ubh);
+ ind_ubh = NULL;
}
if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) {
- ubh_ll_rw_block (SWRITE, 1, &ind_ubh);
+ ubh_ll_rw_block(SWRITE, ind_ubh);
ubh_wait_on_buffer (ind_ubh);
}
ubh_brelse (ind_ubh);
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
return retry;
}
@@ -271,7 +257,7 @@ static int ufs_trunc_dindirect (struct inode *inode, unsigned offset, __fs32 *p)
__fs32 * dind;
int retry = 0;
- UFSD(("ENTER\n"))
+ UFSD("ENTER\n");
sb = inode->i_sb;
uspi = UFS_SB(sb)->s_uspi;
@@ -306,25 +292,21 @@ static int ufs_trunc_dindirect (struct inode *inode, unsigned offset, __fs32 *p)
if (*ubh_get_addr32 (dind_bh, i))
break;
if (i >= uspi->s_apb) {
- if (ubh_max_bcount(dind_bh) != 1)
- retry = 1;
- else {
- tmp = fs32_to_cpu(sb, *p);
- *p = 0;
- inode->i_blocks -= uspi->s_nspb;
- mark_inode_dirty(inode);
- ufs_free_blocks (inode, tmp, uspi->s_fpb);
- ubh_bforget(dind_bh);
- dind_bh = NULL;
- }
+ tmp = fs32_to_cpu(sb, *p);
+ *p = 0;
+
+ ufs_free_blocks(inode, tmp, uspi->s_fpb);
+ mark_inode_dirty(inode);
+ ubh_bforget(dind_bh);
+ dind_bh = NULL;
}
if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) {
- ubh_ll_rw_block (SWRITE, 1, &dind_bh);
+ ubh_ll_rw_block(SWRITE, dind_bh);
ubh_wait_on_buffer (dind_bh);
}
ubh_brelse (dind_bh);
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
return retry;
}
@@ -339,7 +321,7 @@ static int ufs_trunc_tindirect (struct inode * inode)
__fs32 * tind, * p;
int retry;
- UFSD(("ENTER\n"))
+ UFSD("ENTER\n");
sb = inode->i_sb;
uspi = UFS_SB(sb)->s_uspi;
@@ -370,25 +352,21 @@ static int ufs_trunc_tindirect (struct inode * inode)
if (*ubh_get_addr32 (tind_bh, i))
break;
if (i >= uspi->s_apb) {
- if (ubh_max_bcount(tind_bh) != 1)
- retry = 1;
- else {
- tmp = fs32_to_cpu(sb, *p);
- *p = 0;
- inode->i_blocks -= uspi->s_nspb;
- mark_inode_dirty(inode);
- ufs_free_blocks (inode, tmp, uspi->s_fpb);
- ubh_bforget(tind_bh);
- tind_bh = NULL;
- }
+ tmp = fs32_to_cpu(sb, *p);
+ *p = 0;
+
+ ufs_free_blocks(inode, tmp, uspi->s_fpb);
+ mark_inode_dirty(inode);
+ ubh_bforget(tind_bh);
+ tind_bh = NULL;
}
if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) {
- ubh_ll_rw_block (SWRITE, 1, &tind_bh);
+ ubh_ll_rw_block(SWRITE, tind_bh);
ubh_wait_on_buffer (tind_bh);
}
ubh_brelse (tind_bh);
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
return retry;
}
@@ -399,7 +377,7 @@ void ufs_truncate (struct inode * inode)
struct ufs_sb_private_info * uspi;
int retry;
- UFSD(("ENTER\n"))
+ UFSD("ENTER\n");
sb = inode->i_sb;
uspi = UFS_SB(sb)->s_uspi;
@@ -430,5 +408,5 @@ void ufs_truncate (struct inode * inode)
ufsi->i_lastfrag = DIRECT_FRAGMENT;
unlock_kernel();
mark_inode_dirty(inode);
- UFSD(("EXIT\n"))
+ UFSD("EXIT\n");
}
diff --git a/fs/ufs/util.c b/fs/ufs/util.c
index 59acc8f..a2f13f4 100644
--- a/fs/ufs/util.c
+++ b/fs/ufs/util.c
@@ -14,15 +14,6 @@
#include "swab.h"
#include "util.h"
-#undef UFS_UTILS_DEBUG
-
-#ifdef UFS_UTILS_DEBUG
-#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
-
struct ufs_buffer_head * _ubh_bread_ (struct ufs_sb_private_info * uspi,
struct super_block *sb, u64 fragment, u64 size)
{
@@ -63,17 +54,17 @@ struct ufs_buffer_head * ubh_bread_uspi (struct ufs_sb_private_info * uspi,
count = size >> uspi->s_fshift;
if (count <= 0 || count > UFS_MAXFRAG)
return NULL;
- USPI_UBH->fragment = fragment;
- USPI_UBH->count = count;
+ USPI_UBH(uspi)->fragment = fragment;
+ USPI_UBH(uspi)->count = count;
for (i = 0; i < count; i++)
- if (!(USPI_UBH->bh[i] = sb_bread(sb, fragment + i)))
+ if (!(USPI_UBH(uspi)->bh[i] = sb_bread(sb, fragment + i)))
goto failed;
for (; i < UFS_MAXFRAG; i++)
- USPI_UBH->bh[i] = NULL;
- return USPI_UBH;
+ USPI_UBH(uspi)->bh[i] = NULL;
+ return USPI_UBH(uspi);
failed:
for (j = 0; j < i; j++)
- brelse (USPI_UBH->bh[j]);
+ brelse (USPI_UBH(uspi)->bh[j]);
return NULL;
}
@@ -90,11 +81,11 @@ void ubh_brelse (struct ufs_buffer_head * ubh)
void ubh_brelse_uspi (struct ufs_sb_private_info * uspi)
{
unsigned i;
- if (!USPI_UBH)
+ if (!USPI_UBH(uspi))
return;
- for ( i = 0; i < USPI_UBH->count; i++ ) {
- brelse (USPI_UBH->bh[i]);
- USPI_UBH->bh[i] = NULL;
+ for ( i = 0; i < USPI_UBH(uspi)->count; i++ ) {
+ brelse (USPI_UBH(uspi)->bh[i]);
+ USPI_UBH(uspi)->bh[i] = NULL;
}
}
@@ -121,13 +112,12 @@ void ubh_mark_buffer_uptodate (struct ufs_buffer_head * ubh, int flag)
}
}
-void ubh_ll_rw_block (int rw, unsigned nr, struct ufs_buffer_head * ubh[])
+void ubh_ll_rw_block(int rw, struct ufs_buffer_head *ubh)
{
- unsigned i;
if (!ubh)
return;
- for ( i = 0; i < nr; i++ )
- ll_rw_block (rw, ubh[i]->count, ubh[i]->bh);
+
+ ll_rw_block(rw, ubh->count, ubh->bh);
}
void ubh_wait_on_buffer (struct ufs_buffer_head * ubh)
@@ -139,18 +129,6 @@ void ubh_wait_on_buffer (struct ufs_buffer_head * ubh)
wait_on_buffer (ubh->bh[i]);
}
-unsigned ubh_max_bcount (struct ufs_buffer_head * ubh)
-{
- unsigned i;
- unsigned max = 0;
- if (!ubh)
- return 0;
- for ( i = 0; i < ubh->count; i++ )
- if ( atomic_read(&ubh->bh[i]->b_count) > max )
- max = atomic_read(&ubh->bh[i]->b_count);
- return max;
-}
-
void ubh_bforget (struct ufs_buffer_head * ubh)
{
unsigned i;
diff --git a/fs/ufs/util.h b/fs/ufs/util.h
index 48d6d9b..406981f 100644
--- a/fs/ufs/util.h
+++ b/fs/ufs/util.h
@@ -17,10 +17,16 @@
#define in_range(b,first,len) ((b)>=(first)&&(b)<(first)+(len))
/*
- * macros used for retyping
+ * functions used for retyping
*/
-#define UCPI_UBH ((struct ufs_buffer_head *)ucpi)
-#define USPI_UBH ((struct ufs_buffer_head *)uspi)
+static inline struct ufs_buffer_head *UCPI_UBH(struct ufs_cg_private_info *cpi)
+{
+ return &cpi->c_ubh;
+}
+static inline struct ufs_buffer_head *USPI_UBH(struct ufs_sb_private_info *spi)
+{
+ return &spi->s_ubh;
+}
@@ -33,12 +39,12 @@ ufs_get_fs_state(struct super_block *sb, struct ufs_super_block_first *usb1,
{
switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
case UFS_ST_SUN:
- return fs32_to_cpu(sb, usb3->fs_u2.fs_sun.fs_state);
+ return fs32_to_cpu(sb, usb3->fs_un2.fs_sun.fs_state);
case UFS_ST_SUNx86:
return fs32_to_cpu(sb, usb1->fs_u1.fs_sunx86.fs_state);
case UFS_ST_44BSD:
default:
- return fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_state);
+ return fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_state);
}
}
@@ -48,13 +54,13 @@ ufs_set_fs_state(struct super_block *sb, struct ufs_super_block_first *usb1,
{
switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
case UFS_ST_SUN:
- usb3->fs_u2.fs_sun.fs_state = cpu_to_fs32(sb, value);
+ usb3->fs_un2.fs_sun.fs_state = cpu_to_fs32(sb, value);
break;
case UFS_ST_SUNx86:
usb1->fs_u1.fs_sunx86.fs_state = cpu_to_fs32(sb, value);
break;
case UFS_ST_44BSD:
- usb3->fs_u2.fs_44.fs_state = cpu_to_fs32(sb, value);
+ usb3->fs_un2.fs_44.fs_state = cpu_to_fs32(sb, value);
break;
}
}
@@ -64,7 +70,7 @@ ufs_get_fs_npsect(struct super_block *sb, struct ufs_super_block_first *usb1,
struct ufs_super_block_third *usb3)
{
if ((UFS_SB(sb)->s_flags & UFS_ST_MASK) == UFS_ST_SUNx86)
- return fs32_to_cpu(sb, usb3->fs_u2.fs_sunx86.fs_npsect);
+ return fs32_to_cpu(sb, usb3->fs_un2.fs_sunx86.fs_npsect);
else
return fs32_to_cpu(sb, usb1->fs_u1.fs_sun.fs_npsect);
}
@@ -76,16 +82,16 @@ ufs_get_fs_qbmask(struct super_block *sb, struct ufs_super_block_third *usb3)
switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
case UFS_ST_SUN:
- ((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_sun.fs_qbmask[0];
- ((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_sun.fs_qbmask[1];
+ ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_sun.fs_qbmask[0];
+ ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_sun.fs_qbmask[1];
break;
case UFS_ST_SUNx86:
- ((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_sunx86.fs_qbmask[0];
- ((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_sunx86.fs_qbmask[1];
+ ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_sunx86.fs_qbmask[0];
+ ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_sunx86.fs_qbmask[1];
break;
case UFS_ST_44BSD:
- ((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_44.fs_qbmask[0];
- ((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_44.fs_qbmask[1];
+ ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_44.fs_qbmask[0];
+ ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_44.fs_qbmask[1];
break;
}
@@ -99,16 +105,16 @@ ufs_get_fs_qfmask(struct super_block *sb, struct ufs_super_block_third *usb3)
switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
case UFS_ST_SUN:
- ((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_sun.fs_qfmask[0];
- ((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_sun.fs_qfmask[1];
+ ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_sun.fs_qfmask[0];
+ ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_sun.fs_qfmask[1];
break;
case UFS_ST_SUNx86:
- ((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_sunx86.fs_qfmask[0];
- ((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_sunx86.fs_qfmask[1];
+ ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_sunx86.fs_qfmask[0];
+ ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_sunx86.fs_qfmask[1];
break;
case UFS_ST_44BSD:
- ((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_44.fs_qfmask[0];
- ((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_44.fs_qfmask[1];
+ ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_44.fs_qfmask[0];
+ ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_44.fs_qfmask[1];
break;
}
@@ -236,9 +242,8 @@ extern void ubh_brelse (struct ufs_buffer_head *);
extern void ubh_brelse_uspi (struct ufs_sb_private_info *);
extern void ubh_mark_buffer_dirty (struct ufs_buffer_head *);
extern void ubh_mark_buffer_uptodate (struct ufs_buffer_head *, int);
-extern void ubh_ll_rw_block (int, unsigned, struct ufs_buffer_head **);
+extern void ubh_ll_rw_block(int, struct ufs_buffer_head *);
extern void ubh_wait_on_buffer (struct ufs_buffer_head *);
-extern unsigned ubh_max_bcount (struct ufs_buffer_head *);
extern void ubh_bforget (struct ufs_buffer_head *);
extern int ubh_buffer_dirty (struct ufs_buffer_head *);
#define ubh_ubhcpymem(mem,ubh,size) _ubh_ubhcpymem_(uspi,mem,ubh,size)
@@ -297,40 +302,26 @@ static inline void *get_usb_offset(struct ufs_sb_private_info *uspi,
#define ubh_blkmap(ubh,begin,bit) \
((*ubh_get_addr(ubh, (begin) + ((bit) >> 3)) >> ((bit) & 7)) & (0xff >> (UFS_MAXFRAG - uspi->s_fpb)))
-
-/*
- * Macros for access to superblock array structures
- */
-#define ubh_postbl(ubh,cylno,i) \
- ((uspi->s_postblformat != UFS_DYNAMICPOSTBLFMT) \
- ? (*(__s16*)(ubh_get_addr(ubh, \
- (unsigned)(&((struct ufs_super_block *)0)->fs_opostbl) \
- + (((cylno) * 16 + (i)) << 1) ) )) \
- : (*(__s16*)(ubh_get_addr(ubh, \
- uspi->s_postbloff + (((cylno) * uspi->s_nrpos + (i)) << 1) ))))
-
-#define ubh_rotbl(ubh,i) \
- ((uspi->s_postblformat != UFS_DYNAMICPOSTBLFMT) \
- ? (*(__u8*)(ubh_get_addr(ubh, \
- (unsigned)(&((struct ufs_super_block *)0)->fs_space) + (i)))) \
- : (*(__u8*)(ubh_get_addr(ubh, uspi->s_rotbloff + (i)))))
-
/*
* Determine the number of available frags given a
* percentage to hold in reserve.
*/
-#define ufs_freespace(usb, percentreserved) \
- (ufs_blkstofrags(fs32_to_cpu(sb, (usb)->fs_cstotal.cs_nbfree)) + \
- fs32_to_cpu(sb, (usb)->fs_cstotal.cs_nffree) - (uspi->s_dsize * (percentreserved) / 100))
+static inline u64
+ufs_freespace(struct ufs_sb_private_info *uspi, int percentreserved)
+{
+ return ufs_blkstofrags(uspi->cs_total.cs_nbfree) +
+ uspi->cs_total.cs_nffree -
+ (uspi->s_dsize * (percentreserved) / 100);
+}
/*
* Macros to access cylinder group array structures
*/
#define ubh_cg_blktot(ucpi,cylno) \
- (*((__fs32*)ubh_get_addr(UCPI_UBH, (ucpi)->c_btotoff + ((cylno) << 2))))
+ (*((__fs32*)ubh_get_addr(UCPI_UBH(ucpi), (ucpi)->c_btotoff + ((cylno) << 2))))
#define ubh_cg_blks(ucpi,cylno,rpos) \
- (*((__fs16*)ubh_get_addr(UCPI_UBH, \
+ (*((__fs16*)ubh_get_addr(UCPI_UBH(ucpi), \
(ucpi)->c_boff + (((cylno) * uspi->s_nrpos + (rpos)) << 1 ))))
/*
@@ -508,29 +499,3 @@ static inline void ufs_fragacct (struct super_block * sb, unsigned blockmap,
if (fragsize > 0 && fragsize < uspi->s_fpb)
fs32_add(sb, &fraglist[fragsize], cnt);
}
-
-#define ubh_scanc(ubh,begin,size,table,mask) _ubh_scanc_(uspi,ubh,begin,size,table,mask)
-static inline unsigned _ubh_scanc_(struct ufs_sb_private_info * uspi, struct ufs_buffer_head * ubh,
- unsigned begin, unsigned size, unsigned char * table, unsigned char mask)
-{
- unsigned rest, offset;
- unsigned char * cp;
-
-
- offset = begin & ~uspi->s_fmask;
- begin >>= uspi->s_fshift;
- for (;;) {
- if ((offset + size) < uspi->s_fsize)
- rest = size;
- else
- rest = uspi->s_fsize - offset;
- size -= rest;
- cp = ubh->bh[begin]->b_data + offset;
- while ((table[*cp++] & mask) == 0 && --rest);
- if (rest || !size)
- break;
- begin++;
- offset = 0;
- }
- return (size + rest);
-}
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index a56cec3..9a8f48b 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -1023,11 +1023,12 @@ static int vfat_fill_super(struct super_block *sb, void *data, int silent)
return 0;
}
-static struct super_block *vfat_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data)
+static int vfat_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data, struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, vfat_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, vfat_fill_super,
+ mnt);
}
static struct file_system_type vfat_fs_type = {
diff --git a/fs/xfs/linux-2.6/xfs_stats.c b/fs/xfs/linux-2.6/xfs_stats.c
index 1f0589a..e480b61 100644
--- a/fs/xfs/linux-2.6/xfs_stats.c
+++ b/fs/xfs/linux-2.6/xfs_stats.c
@@ -62,7 +62,7 @@ xfs_read_xfsstats(
while (j < xstats[i].endpoint) {
val = 0;
/* sum over all cpus */
- for_each_cpu(c)
+ for_each_possible_cpu(c)
val += *(((__u32*)&per_cpu(xfsstats, c) + j));
len += sprintf(buffer + len, " %u", val);
j++;
@@ -70,7 +70,7 @@ xfs_read_xfsstats(
buffer[len++] = '\n';
}
/* extra precision counters */
- for_each_cpu(i) {
+ for_each_possible_cpu(i) {
xs_xstrat_bytes += per_cpu(xfsstats, i).xs_xstrat_bytes;
xs_write_bytes += per_cpu(xfsstats, i).xs_write_bytes;
xs_read_bytes += per_cpu(xfsstats, i).xs_read_bytes;
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index f2a0778..9bdef9d 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -684,10 +684,11 @@ xfs_fs_sync_super(
STATIC int
xfs_fs_statfs(
- struct super_block *sb,
+ struct dentry *dentry,
struct kstatfs *statp)
{
- return -bhv_vfs_statvfs(vfs_from_sb(sb), statp, NULL);
+ return -bhv_vfs_statvfs(vfs_from_sb(dentry->d_sb), statp,
+ vn_from_inode(dentry->d_inode));
}
STATIC int
@@ -853,14 +854,16 @@ fail_vfsop:
return -error;
}
-STATIC struct super_block *
+STATIC int
xfs_fs_get_sb(
struct file_system_type *fs_type,
int flags,
const char *dev_name,
- void *data)
+ void *data,
+ struct vfsmount *mnt)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super,
+ mnt);
}
STATIC struct super_operations xfs_super_operations = {
diff --git a/fs/xfs/linux-2.6/xfs_sysctl.c b/fs/xfs/linux-2.6/xfs_sysctl.c
index 4af9768..af24653 100644
--- a/fs/xfs/linux-2.6/xfs_sysctl.c
+++ b/fs/xfs/linux-2.6/xfs_sysctl.c
@@ -38,7 +38,7 @@ xfs_stats_clear_proc_handler(
if (!ret && write && *valp) {
printk("XFS Clearing xfsstats\n");
- for_each_cpu(c) {
+ for_each_possible_cpu(c) {
preempt_disable();
/* save vn_active, it's a universal truth! */
vn_active = per_cpu(xfsstats, c).vn_active;
diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h
index e27dc8f..b9beceb 100644
--- a/include/acpi/acconfig.h
+++ b/include/acpi/acconfig.h
@@ -63,7 +63,7 @@
/* Current ACPICA subsystem version in YYYYMMDD format */
-#define ACPI_CA_VERSION 0x20060127
+#define ACPI_CA_VERSION 0x20060608
/*
* OS name, used for the _OS object. The _OS object is essentially obsolete,
@@ -81,6 +81,7 @@
#define ACPI_MAX_PARSE_CACHE_DEPTH 96 /* Parse tree objects */
#define ACPI_MAX_EXTPARSE_CACHE_DEPTH 96 /* Parse tree objects */
#define ACPI_MAX_OBJECT_CACHE_DEPTH 96 /* Interpreter operand objects */
+#define ACPI_MAX_NAMESPACE_CACHE_DEPTH 96 /* Namespace objects */
/*
* Should the subsystem abort the loading of an ACPI table if the
@@ -102,9 +103,9 @@
#define ACPI_MAX_SEMAPHORE_COUNT 256
-/* Max reference count (for debug only) */
+/* Maximum object reference count (detects object deletion issues) */
-#define ACPI_MAX_REFERENCE_COUNT 0x400
+#define ACPI_MAX_REFERENCE_COUNT 0x800
/* Size of cached memory mapping for system memory operation region */
@@ -171,12 +172,7 @@
/* Array sizes. Used for range checking also */
-#define ACPI_NUM_ACCESS_TYPES 6
-#define ACPI_NUM_UPDATE_RULES 3
-#define ACPI_NUM_LOCK_RULES 2
-#define ACPI_NUM_MATCH_OPS 6
-#define ACPI_NUM_OPCODES 256
-#define ACPI_NUM_FIELD_NAMES 2
+#define ACPI_MAX_MATCH_OPCODE 5
/* RSDP checksums */
@@ -187,10 +183,6 @@
#define ACPI_SMBUS_BUFFER_SIZE 34
-/* Number of strings associated with the _OSI reserved method */
-
-#define ACPI_NUM_OSI_STRINGS 10
-
/******************************************************************************
*
* ACPI AML Debugger
diff --git a/include/acpi/acdisasm.h b/include/acpi/acdisasm.h
index 11a8fe3..9a7d692 100644
--- a/include/acpi/acdisasm.h
+++ b/include/acpi/acdisasm.h
@@ -50,26 +50,72 @@
#define BLOCK_PAREN 1
#define BLOCK_BRACE 2
#define BLOCK_COMMA_LIST 4
+#define ACPI_DEFAULT_RESNAME *(u32 *) "__RD"
struct acpi_external_list {
char *path;
+ char *internal_path;
struct acpi_external_list *next;
+ u32 value;
+ u16 length;
+ u8 type;
};
extern struct acpi_external_list *acpi_gbl_external_list;
-/* Strings used for decoding flags to ASL keywords */
+typedef const struct acpi_dmtable_info {
+ u8 opcode;
+ u8 offset;
+ char *name;
+
+} acpi_dmtable_info;
+
+/*
+ * Values for Opcode above.
+ * Note: 0-7 must not change, used as a flag shift value
+ */
+#define ACPI_DMT_FLAG0 0
+#define ACPI_DMT_FLAG1 1
+#define ACPI_DMT_FLAG2 2
+#define ACPI_DMT_FLAG3 3
+#define ACPI_DMT_FLAG4 4
+#define ACPI_DMT_FLAG5 5
+#define ACPI_DMT_FLAG6 6
+#define ACPI_DMT_FLAG7 7
+#define ACPI_DMT_FLAGS0 8
+#define ACPI_DMT_FLAGS2 9
+#define ACPI_DMT_UINT8 10
+#define ACPI_DMT_UINT16 11
+#define ACPI_DMT_UINT24 12
+#define ACPI_DMT_UINT32 13
+#define ACPI_DMT_UINT56 14
+#define ACPI_DMT_UINT64 15
+#define ACPI_DMT_STRING 16
+#define ACPI_DMT_NAME4 17
+#define ACPI_DMT_NAME6 18
+#define ACPI_DMT_NAME8 19
+#define ACPI_DMT_CHKSUM 20
+#define ACPI_DMT_SPACEID 21
+#define ACPI_DMT_GAS 22
+#define ACPI_DMT_MADT 23
+#define ACPI_DMT_SRAT 24
+#define ACPI_DMT_EXIT 25
-extern const char *acpi_gbl_word_decode[4];
-extern const char *acpi_gbl_irq_decode[2];
-extern const char *acpi_gbl_lock_rule[ACPI_NUM_LOCK_RULES];
-extern const char *acpi_gbl_access_types[ACPI_NUM_ACCESS_TYPES];
-extern const char *acpi_gbl_update_rules[ACPI_NUM_UPDATE_RULES];
-extern const char *acpi_gbl_match_ops[ACPI_NUM_MATCH_OPS];
+typedef
+void (*ACPI_TABLE_HANDLER) (struct acpi_table_header * table);
+
+struct acpi_dmtable_data {
+ char *signature;
+ struct acpi_dmtable_info *table_info;
+ ACPI_TABLE_HANDLER table_handler;
+};
struct acpi_op_walk_info {
u32 level;
+ u32 last_level;
+ u32 count;
u32 bit_offset;
+ u32 flags;
struct acpi_walk_state *walk_state;
};
@@ -77,6 +123,100 @@ typedef
acpi_status(*asl_walk_callback) (union acpi_parse_object * op,
u32 level, void *context);
+struct acpi_resource_tag {
+ u32 bit_index;
+ char *tag;
+};
+
+/* Strings used for decoding flags to ASL keywords */
+
+extern const char *acpi_gbl_word_decode[];
+extern const char *acpi_gbl_irq_decode[];
+extern const char *acpi_gbl_lock_rule[];
+extern const char *acpi_gbl_access_types[];
+extern const char *acpi_gbl_update_rules[];
+extern const char *acpi_gbl_match_ops[];
+
+extern struct acpi_dmtable_info acpi_dm_table_info_asf0[];
+extern struct acpi_dmtable_info acpi_dm_table_info_asf1[];
+extern struct acpi_dmtable_info acpi_dm_table_info_asf2[];
+extern struct acpi_dmtable_info acpi_dm_table_info_asf3[];
+extern struct acpi_dmtable_info acpi_dm_table_info_asf4[];
+extern struct acpi_dmtable_info acpi_dm_table_info_asf_hdr[];
+extern struct acpi_dmtable_info acpi_dm_table_info_boot[];
+extern struct acpi_dmtable_info acpi_dm_table_info_cpep[];
+extern struct acpi_dmtable_info acpi_dm_table_info_cpep0[];
+extern struct acpi_dmtable_info acpi_dm_table_info_dbgp[];
+extern struct acpi_dmtable_info acpi_dm_table_info_ecdt[];
+extern struct acpi_dmtable_info acpi_dm_table_info_facs[];
+extern struct acpi_dmtable_info acpi_dm_table_info_fadt1[];
+extern struct acpi_dmtable_info acpi_dm_table_info_fadt2[];
+extern struct acpi_dmtable_info acpi_dm_table_info_gas[];
+extern struct acpi_dmtable_info acpi_dm_table_info_header[];
+extern struct acpi_dmtable_info acpi_dm_table_info_hpet[];
+extern struct acpi_dmtable_info acpi_dm_table_info_madt[];
+extern struct acpi_dmtable_info acpi_dm_table_info_madt0[];
+extern struct acpi_dmtable_info acpi_dm_table_info_madt1[];
+extern struct acpi_dmtable_info acpi_dm_table_info_madt2[];
+extern struct acpi_dmtable_info acpi_dm_table_info_madt3[];
+extern struct acpi_dmtable_info acpi_dm_table_info_madt4[];
+extern struct acpi_dmtable_info acpi_dm_table_info_madt5[];
+extern struct acpi_dmtable_info acpi_dm_table_info_madt6[];
+extern struct acpi_dmtable_info acpi_dm_table_info_madt7[];
+extern struct acpi_dmtable_info acpi_dm_table_info_madt8[];
+extern struct acpi_dmtable_info acpi_dm_table_info_madt_hdr[];
+extern struct acpi_dmtable_info acpi_dm_table_info_mcfg[];
+extern struct acpi_dmtable_info acpi_dm_table_info_mcfg0[];
+extern struct acpi_dmtable_info acpi_dm_table_info_rsdp1[];
+extern struct acpi_dmtable_info acpi_dm_table_info_rsdp2[];
+extern struct acpi_dmtable_info acpi_dm_table_info_sbst[];
+extern struct acpi_dmtable_info acpi_dm_table_info_slit[];
+extern struct acpi_dmtable_info acpi_dm_table_info_spcr[];
+extern struct acpi_dmtable_info acpi_dm_table_info_spmi[];
+extern struct acpi_dmtable_info acpi_dm_table_info_srat[];
+extern struct acpi_dmtable_info acpi_dm_table_info_srat0[];
+extern struct acpi_dmtable_info acpi_dm_table_info_srat1[];
+extern struct acpi_dmtable_info acpi_dm_table_info_tcpa[];
+extern struct acpi_dmtable_info acpi_dm_table_info_wdrt[];
+
+/*
+ * dmtable
+ */
+void acpi_dm_dump_data_table(struct acpi_table_header *table);
+
+void
+acpi_dm_dump_table(u32 table_length,
+ u32 table_offset,
+ void *table,
+ u32 sub_table_length, struct acpi_dmtable_info *info);
+
+void acpi_dm_line_header(u32 offset, u32 byte_length, char *name);
+
+void acpi_dm_line_header2(u32 offset, u32 byte_length, char *name, u32 value);
+
+/*
+ * dmtbdump
+ */
+void acpi_dm_dump_asf(struct acpi_table_header *table);
+
+void acpi_dm_dump_cpep(struct acpi_table_header *table);
+
+void acpi_dm_dump_fadt(struct acpi_table_header *table);
+
+void acpi_dm_dump_srat(struct acpi_table_header *table);
+
+void acpi_dm_dump_mcfg(struct acpi_table_header *table);
+
+void acpi_dm_dump_madt(struct acpi_table_header *table);
+
+u32 acpi_dm_dump_rsdp(struct acpi_table_header *table);
+
+void acpi_dm_dump_rsdt(struct acpi_table_header *table);
+
+void acpi_dm_dump_slit(struct acpi_table_header *table);
+
+void acpi_dm_dump_xsdt(struct acpi_table_header *table);
+
/*
* dmwalk
*/
@@ -84,6 +224,11 @@ void
acpi_dm_disassemble(struct acpi_walk_state *walk_state,
union acpi_parse_object *origin, u32 num_opcodes);
+void
+acpi_dm_walk_parse_tree(union acpi_parse_object *op,
+ asl_walk_callback descending_callback,
+ asl_walk_callback ascending_callback, void *context);
+
/*
* dmopcode
*/
@@ -166,6 +311,7 @@ void acpi_dm_dump_integer64(u64 value, char *name);
void
acpi_dm_resource_template(struct acpi_op_walk_info *info,
+ union acpi_parse_object *op,
u8 * byte_data, u32 byte_count);
u8 acpi_dm_is_resource_template(union acpi_parse_object *op);
@@ -176,6 +322,8 @@ void acpi_dm_bit_list(u16 mask);
void acpi_dm_decode_attribute(u8 attribute);
+void acpi_dm_descriptor_name(void);
+
/*
* dmresrcl
*/
@@ -248,6 +396,15 @@ acpi_dm_vendor_small_descriptor(union aml_resource *resource,
/*
* dmutils
*/
-void acpi_dm_add_to_external_list(char *path);
+void acpi_dm_add_to_external_list(char *path, u8 type, u32 value);
+
+/*
+ * dmrestag
+ */
+void acpi_dm_find_resources(union acpi_parse_object *root);
+
+void
+acpi_dm_check_resource_reference(union acpi_parse_object *op,
+ struct acpi_walk_state *walk_state);
#endif /* __ACDISASM_H__ */
diff --git a/include/acpi/acdispat.h b/include/acpi/acdispat.h
index c41a926..288f849 100644
--- a/include/acpi/acdispat.h
+++ b/include/acpi/acdispat.h
@@ -194,7 +194,9 @@ acpi_status
acpi_ds_restart_control_method(struct acpi_walk_state *walk_state,
union acpi_operand_object *return_desc);
-void acpi_ds_terminate_control_method(struct acpi_walk_state *walk_state);
+void
+acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
+ struct acpi_walk_state *walk_state);
acpi_status
acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
@@ -302,7 +304,7 @@ acpi_ds_init_aml_walk(struct acpi_walk_state *walk_state,
struct acpi_namespace_node *method_node,
u8 * aml_start,
u32 aml_length,
- struct acpi_parameter_info *info, u8 pass_number);
+ struct acpi_evaluate_info *info, u8 pass_number);
acpi_status
acpi_ds_obj_stack_pop_and_delete(u32 pop_count,
diff --git a/include/acpi/acevents.h b/include/acpi/acevents.h
index f2717be..23414282 100644
--- a/include/acpi/acevents.h
+++ b/include/acpi/acevents.h
@@ -93,7 +93,7 @@ struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device,
*/
u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info);
-acpi_status acpi_ev_walk_gpe_list(ACPI_GPE_CALLBACK gpe_walk_callback);
+acpi_status acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback);
acpi_status
acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
@@ -138,7 +138,7 @@ acpi_status
acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
u32 function,
acpi_physical_address address,
- u32 bit_width, void *value);
+ u32 bit_width, acpi_integer * value);
acpi_status
acpi_ev_attach_region(union acpi_operand_object *handler_obj,
diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h
index dc768aa..797ca1e 100644
--- a/include/acpi/acexcep.h
+++ b/include/acpi/acexcep.h
@@ -160,8 +160,9 @@
#define AE_AML_BAD_RESOURCE_VALUE (acpi_status) (0x001F | AE_CODE_AML)
#define AE_AML_CIRCULAR_REFERENCE (acpi_status) (0x0020 | AE_CODE_AML)
#define AE_AML_BAD_RESOURCE_LENGTH (acpi_status) (0x0021 | AE_CODE_AML)
+#define AE_AML_ILLEGAL_ADDRESS (acpi_status) (0x0022 | AE_CODE_AML)
-#define AE_CODE_AML_MAX 0x0021
+#define AE_CODE_AML_MAX 0x0022
/*
* Internal exceptions used for control
@@ -275,7 +276,8 @@ char const *acpi_gbl_exception_names_aml[] = {
"AE_AML_NO_RESOURCE_END_TAG",
"AE_AML_BAD_RESOURCE_VALUE",
"AE_AML_CIRCULAR_REFERENCE",
- "AE_AML_BAD_RESOURCE_LENGTH"
+ "AE_AML_BAD_RESOURCE_LENGTH",
+ "AE_AML_ILLEGAL_ADDRESS"
};
char const *acpi_gbl_exception_names_ctrl[] = {
diff --git a/include/acpi/acglobal.h b/include/acpi/acglobal.h
index 734cc77..14531d4 100644
--- a/include/acpi/acglobal.h
+++ b/include/acpi/acglobal.h
@@ -107,6 +107,7 @@ ACPI_EXTERN u32 acpi_gbl_trace_flags;
* 3) Allow access to uninitialized locals/args (auto-init to integer 0)
* 4) Allow ANY object type to be a source operand for the Store() operator
* 5) Allow unresolved references (invalid target name) in package objects
+ * 6) Enable warning messages for behavior that is not ACPI spec compliant
*/
ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_interpreter_slack, FALSE);
@@ -114,7 +115,7 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_interpreter_slack, FALSE);
* Automatically serialize ALL control methods? Default is FALSE, meaning
* to use the Serialized/not_serialized method flags on a per method basis.
* Only change this if the ASL code is poorly written and cannot handle
- * reentrancy even though methods are marked "not_serialized".
+ * reentrancy even though methods are marked "NotSerialized".
*/
ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_all_methods_serialized, FALSE);
@@ -149,10 +150,10 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_leave_wake_gpes_disabled, TRUE);
ACPI_EXTERN u32 acpi_gbl_table_flags;
ACPI_EXTERN u32 acpi_gbl_rsdt_table_count;
ACPI_EXTERN struct rsdp_descriptor *acpi_gbl_RSDP;
-ACPI_EXTERN XSDT_DESCRIPTOR *acpi_gbl_XSDT;
-ACPI_EXTERN FADT_DESCRIPTOR *acpi_gbl_FADT;
+ACPI_EXTERN struct xsdt_descriptor *acpi_gbl_XSDT;
+ACPI_EXTERN struct fadt_descriptor *acpi_gbl_FADT;
ACPI_EXTERN struct acpi_table_header *acpi_gbl_DSDT;
-ACPI_EXTERN FACS_DESCRIPTOR *acpi_gbl_FACS;
+ACPI_EXTERN struct facs_descriptor *acpi_gbl_FACS;
ACPI_EXTERN struct acpi_common_facs acpi_gbl_common_fACS;
/*
* Since there may be multiple SSDTs and PSDTs, a single pointer is not
@@ -177,15 +178,15 @@ ACPI_EXTERN u8 acpi_gbl_integer_nybble_width;
/*
* ACPI Table info arrays
*/
-extern struct acpi_table_list acpi_gbl_table_lists[NUM_ACPI_TABLE_TYPES];
-extern struct acpi_table_support acpi_gbl_table_data[NUM_ACPI_TABLE_TYPES];
+extern struct acpi_table_list acpi_gbl_table_lists[ACPI_TABLE_ID_MAX + 1];
+extern struct acpi_table_support acpi_gbl_table_data[ACPI_TABLE_ID_MAX + 1];
/*
* Predefined mutex objects. This array contains the
* actual OS mutex handles, indexed by the local ACPI_MUTEX_HANDLEs.
* (The table maps local handles to the real OS handles)
*/
-ACPI_EXTERN struct acpi_mutex_info acpi_gbl_mutex_info[NUM_MUTEX];
+ACPI_EXTERN struct acpi_mutex_info acpi_gbl_mutex_info[ACPI_NUM_MUTEX];
/*****************************************************************************
*
@@ -203,6 +204,7 @@ ACPI_EXTERN struct acpi_memory_list *acpi_gbl_ns_node_list;
/* Object caches */
+ACPI_EXTERN acpi_cache_t *acpi_gbl_namespace_cache;
ACPI_EXTERN acpi_cache_t *acpi_gbl_state_cache;
ACPI_EXTERN acpi_cache_t *acpi_gbl_ps_node_cache;
ACPI_EXTERN acpi_cache_t *acpi_gbl_ps_node_ext_cache;
@@ -244,7 +246,6 @@ extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT];
extern const char *acpi_gbl_highest_dstate_names[4];
extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES];
extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS];
-extern const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS];
/*****************************************************************************
*
@@ -291,14 +292,6 @@ ACPI_EXTERN u8 acpi_gbl_cm_single_step;
/*****************************************************************************
*
- * Parser globals
- *
- ****************************************************************************/
-
-ACPI_EXTERN union acpi_parse_object *acpi_gbl_parsed_namespace_root;
-
-/*****************************************************************************
- *
* Hardware globals
*
****************************************************************************/
@@ -321,7 +314,11 @@ ACPI_EXTERN struct acpi_fixed_event_handler
ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head;
ACPI_EXTERN struct acpi_gpe_block_info
*acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS];
+
+/* Spinlocks */
+
ACPI_EXTERN acpi_handle acpi_gbl_gpe_lock;
+ACPI_EXTERN acpi_handle acpi_gbl_hardware_lock;
/*****************************************************************************
*
diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h
index 8361820..1eeca7a 100644
--- a/include/acpi/aclocal.h
+++ b/include/acpi/aclocal.h
@@ -44,7 +44,10 @@
#ifndef __ACLOCAL_H__
#define __ACLOCAL_H__
+/* acpisrc:struct_defs -- for acpisrc conversion */
+
#define ACPI_WAIT_FOREVER 0xFFFF /* u16, as per ACPI spec */
+#define ACPI_INFINITE_CONCURRENCY 0xFF
typedef void *acpi_mutex;
typedef u32 acpi_mutex_handle;
@@ -69,52 +72,55 @@ union acpi_parse_object;
* Predefined handles for the mutex objects used within the subsystem
* All mutex objects are automatically created by acpi_ut_mutex_initialize.
*
- * The acquire/release ordering protocol is implied via this list. Mutexes
+ * The acquire/release ordering protocol is implied via this list. Mutexes
* with a lower value must be acquired before mutexes with a higher value.
*
- * NOTE: any changes here must be reflected in the acpi_gbl_mutex_names table also!
+ * NOTE: any changes here must be reflected in the acpi_gbl_mutex_names
+ * table below also!
*/
-#define ACPI_MTX_EXECUTE 0
-#define ACPI_MTX_INTERPRETER 1
-#define ACPI_MTX_PARSER 2
-#define ACPI_MTX_DISPATCHER 3
-#define ACPI_MTX_TABLES 4
-#define ACPI_MTX_OP_REGIONS 5
-#define ACPI_MTX_NAMESPACE 6
-#define ACPI_MTX_EVENTS 7
-#define ACPI_MTX_HARDWARE 8
-#define ACPI_MTX_CACHES 9
-#define ACPI_MTX_MEMORY 10
-#define ACPI_MTX_DEBUG_CMD_COMPLETE 11
-#define ACPI_MTX_DEBUG_CMD_READY 12
-
-#define MAX_MUTEX 12
-#define NUM_MUTEX MAX_MUTEX+1
+#define ACPI_MTX_INTERPRETER 0 /* AML Interpreter, main lock */
+#define ACPI_MTX_CONTROL_METHOD 1 /* Control method termination [TBD: may no longer be necessary] */
+#define ACPI_MTX_TABLES 2 /* Data for ACPI tables */
+#define ACPI_MTX_NAMESPACE 3 /* ACPI Namespace */
+#define ACPI_MTX_EVENTS 4 /* Data for ACPI events */
+#define ACPI_MTX_CACHES 5 /* Internal caches, general purposes */
+#define ACPI_MTX_MEMORY 6 /* Debug memory tracking lists */
+#define ACPI_MTX_DEBUG_CMD_COMPLETE 7 /* AML debugger */
+#define ACPI_MTX_DEBUG_CMD_READY 8 /* AML debugger */
+
+#define ACPI_MAX_MUTEX 8
+#define ACPI_NUM_MUTEX ACPI_MAX_MUTEX+1
#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
#ifdef DEFINE_ACPI_GLOBALS
-/* Names for the mutexes used in the subsystem */
+/* Debug names for the mutexes above */
-static char *acpi_gbl_mutex_names[] = {
- "ACPI_MTX_Execute",
+static char *acpi_gbl_mutex_names[ACPI_NUM_MUTEX] = {
"ACPI_MTX_Interpreter",
- "ACPI_MTX_Parser",
- "ACPI_MTX_Dispatcher",
+ "ACPI_MTX_Method",
"ACPI_MTX_Tables",
- "ACPI_MTX_op_regions",
"ACPI_MTX_Namespace",
"ACPI_MTX_Events",
- "ACPI_MTX_Hardware",
"ACPI_MTX_Caches",
"ACPI_MTX_Memory",
- "ACPI_MTX_debug_cmd_complete",
- "ACPI_MTX_debug_cmd_ready",
+ "ACPI_MTX_DebugCmdComplete",
+ "ACPI_MTX_DebugCmdReady"
};
#endif
#endif
+/*
+ * Predefined handles for spinlocks used within the subsystem.
+ * These spinlocks are created by acpi_ut_mutex_initialize
+ */
+#define ACPI_LOCK_GPES 0
+#define ACPI_LOCK_HARDWARE 1
+
+#define ACPI_MAX_LOCK 1
+#define ACPI_NUM_LOCK ACPI_MAX_LOCK+1
+
/* Owner IDs are used to track namespace nodes for selective deletion */
typedef u8 acpi_owner_id;
@@ -129,7 +135,7 @@ typedef u8 acpi_owner_id;
struct acpi_mutex_info {
acpi_mutex mutex;
u32 use_count;
- u32 thread_id;
+ acpi_thread_id thread_id;
};
/* Lock flag parameter for various interfaces */
@@ -144,6 +150,8 @@ struct acpi_mutex_info {
#define ACPI_FIELD_DWORD_GRANULARITY 4
#define ACPI_FIELD_QWORD_GRANULARITY 8
+#define ACPI_ENTRY_NOT_FOUND NULL
+
/*****************************************************************************
*
* Namespace typedefs and structs
@@ -158,49 +166,55 @@ typedef enum {
ACPI_IMODE_EXECUTE = 0x0E
} acpi_interpreter_mode;
-/*
- * The Node describes a named object that appears in the AML
- * An acpi_node is used to store Nodes.
- *
- * data_type is used to differentiate between internal descriptors, and MUST
- * be the first byte in this structure.
- */
union acpi_name_union {
u32 integer;
char ascii[4];
};
+/*
+ * The Namespace Node describes a named object that appears in the AML.
+ * descriptor_type is used to differentiate between internal descriptors.
+ *
+ * The node is optimized for both 32-bit and 64-bit platforms:
+ * 20 bytes for the 32-bit case, 32 bytes for the 64-bit case.
+ *
+ * Note: The descriptor_type and Type fields must appear in the identical
+ * position in both the struct acpi_namespace_node and union acpi_operand_object
+ * structures.
+ */
struct acpi_namespace_node {
- u8 descriptor; /* Used to differentiate object descriptor types */
- u8 type; /* Type associated with this name */
- u16 reference_count; /* Current count of references and children */
+ union acpi_operand_object *object; /* Interpreter object */
+ u8 descriptor_type; /* Differentiate object descriptor types */
+ u8 type; /* ACPI Type associated with this name */
+ u8 flags; /* Miscellaneous flags */
+ acpi_owner_id owner_id; /* Node creator */
union acpi_name_union name; /* ACPI Name, always 4 chars per ACPI spec */
- union acpi_operand_object *object; /* Pointer to attached ACPI object (optional) */
struct acpi_namespace_node *child; /* First child */
- struct acpi_namespace_node *peer; /* Next peer */
- u8 owner_id; /* Who created this node */
- u8 flags;
-
- /* Fields used by the ASL compiler only */
+ struct acpi_namespace_node *peer; /* Peer. Parent if ANOBJ_END_OF_PEER_LIST set */
-#ifdef ACPI_ASL_COMPILER
- u32 value;
+ /*
+ * The following fields are used by the ASL compiler and disassembler only
+ */
+#ifdef ACPI_LARGE_NAMESPACE_NODE
union acpi_parse_object *op;
+ u32 value;
+ u32 length;
#endif
};
-#define ACPI_ENTRY_NOT_FOUND NULL
+/* Namespace Node flags */
-/* Node flags */
+#define ANOBJ_END_OF_PEER_LIST 0x01 /* End-of-list, Peer field points to parent */
+#define ANOBJ_DATA_WIDTH_32 0x02 /* Parent table uses 32-bit math */
+#define ANOBJ_METHOD_ARG 0x04 /* Node is a method argument */
+#define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */
+#define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */
-#define ANOBJ_RESERVED 0x01
-#define ANOBJ_END_OF_PEER_LIST 0x02
-#define ANOBJ_DATA_WIDTH_32 0x04 /* Parent table is 64-bits */
-#define ANOBJ_METHOD_ARG 0x08
-#define ANOBJ_METHOD_LOCAL 0x10
-#define ANOBJ_METHOD_NO_RETVAL 0x20
-#define ANOBJ_METHOD_SOME_NO_RETVAL 0x40
-#define ANOBJ_IS_BIT_OFFSET 0x80
+#define ANOBJ_IS_EXTERNAL 0x08 /* i_aSL only: This object created via External() */
+#define ANOBJ_METHOD_NO_RETVAL 0x10 /* i_aSL only: Method has no return value */
+#define ANOBJ_METHOD_SOME_NO_RETVAL 0x20 /* i_aSL only: Method has at least one return value */
+#define ANOBJ_IS_BIT_OFFSET 0x40 /* i_aSL only: Reference is a bit offset */
+#define ANOBJ_IS_REFERENCED 0x80 /* i_aSL only: Object was referenced */
/*
* ACPI Table Descriptor. One per ACPI table
@@ -212,8 +226,8 @@ struct acpi_table_desc {
struct acpi_table_header *pointer;
u8 *aml_start;
u64 physical_address;
- u32 aml_length;
acpi_size length;
+ u32 aml_length;
acpi_owner_id owner_id;
u8 type;
u8 allocation;
@@ -276,6 +290,9 @@ struct acpi_create_field_info {
u8 field_type;
};
+typedef
+acpi_status(*ACPI_INTERNAL_METHOD) (struct acpi_walk_state * walk_state);
+
/*
* Bitmapped ACPI types. Used internally only
*/
@@ -377,7 +394,7 @@ struct acpi_gpe_walk_info {
struct acpi_gpe_block_info *gpe_block;
};
-typedef acpi_status(*ACPI_GPE_CALLBACK) (struct acpi_gpe_xrupt_info *
+typedef acpi_status(*acpi_gpe_callback) (struct acpi_gpe_xrupt_info *
gpe_xrupt_info,
struct acpi_gpe_block_info *
gpe_block);
@@ -416,13 +433,14 @@ struct acpi_field_info {
#define ACPI_CONTROL_PREDICATE_FALSE 0xC3
#define ACPI_CONTROL_PREDICATE_TRUE 0xC4
-#define ACPI_STATE_COMMON /* Two 32-bit fields and a pointer */\
- u8 data_type; /* To differentiate various internal objs */\
- u8 flags; \
- u16 value; \
- u16 state; \
- u16 reserved; \
- void *next;
+#define ACPI_STATE_COMMON \
+ void *next; \
+ u8 descriptor_type; /* To differentiate various internal objs */\
+ u8 flags; \
+ u16 value; \
+ u16 state;
+
+ /* There are 2 bytes available here until the next natural alignment boundary */
struct acpi_common_state {
ACPI_STATE_COMMON};
@@ -438,12 +456,12 @@ struct acpi_update_state {
* Pkg state - used to traverse nested package structures
*/
struct acpi_pkg_state {
- ACPI_STATE_COMMON union acpi_operand_object *source_object;
+ ACPI_STATE_COMMON u16 index;
+ union acpi_operand_object *source_object;
union acpi_operand_object *dest_object;
struct acpi_walk_state *walk_state;
void *this_target_obj;
u32 num_packages;
- u16 index;
};
/*
@@ -451,10 +469,10 @@ struct acpi_pkg_state {
* Allows nesting of these constructs
*/
struct acpi_control_state {
- ACPI_STATE_COMMON union acpi_parse_object *predicate_op;
+ ACPI_STATE_COMMON u16 opcode;
+ union acpi_parse_object *predicate_op;
u8 *aml_predicate_start; /* Start of if/while predicate */
u8 *package_end; /* End of if/while block */
- u16 opcode;
};
/*
@@ -465,11 +483,11 @@ struct acpi_scope_state {
};
struct acpi_pscope_state {
- ACPI_STATE_COMMON union acpi_parse_object *op; /* Current op being parsed */
+ ACPI_STATE_COMMON u32 arg_count; /* Number of fixed arguments */
+ union acpi_parse_object *op; /* Current op being parsed */
u8 *arg_end; /* Current argument end */
u8 *pkg_end; /* Current package end */
u32 arg_list; /* Next argument to parse */
- u32 arg_count; /* Number of fixed arguments */
};
/*
@@ -477,10 +495,10 @@ struct acpi_pscope_state {
* states are created when there are nested control methods executing.
*/
struct acpi_thread_state {
- ACPI_STATE_COMMON struct acpi_walk_state *walk_state_list; /* Head of list of walk_states for this thread */
+ ACPI_STATE_COMMON u8 current_sync_level; /* Mutex Sync (nested acquire) level */
+ struct acpi_walk_state *walk_state_list; /* Head of list of walk_states for this thread */
union acpi_operand_object *acquired_mutex_list; /* List of all currently acquired mutexes */
- u32 thread_id; /* Running thread ID */
- u8 current_sync_level; /* Mutex Sync (nested acquire) level */
+ acpi_thread_id thread_id; /* Running thread ID */
};
/*
@@ -488,10 +506,9 @@ struct acpi_thread_state {
* AML arguments
*/
struct acpi_result_values {
- ACPI_STATE_COMMON
- union acpi_operand_object *obj_desc[ACPI_OBJ_NUM_OPERANDS];
- u8 num_results;
+ ACPI_STATE_COMMON u8 num_results;
u8 last_insert;
+ union acpi_operand_object *obj_desc[ACPI_OBJ_NUM_OPERANDS];
};
typedef
@@ -546,7 +563,7 @@ struct acpi_opcode_info {
#endif
u32 parse_args; /* Grammar/Parse time arguments */
u32 runtime_args; /* Interpret time arguments */
- u32 flags; /* Misc flags */
+ u16 flags; /* Misc flags */
u8 object_type; /* Corresponding internal object type */
u8 class; /* Opcode class */
u8 type; /* Opcode type */
@@ -563,29 +580,31 @@ union acpi_parse_value {
};
#define ACPI_PARSE_COMMON \
- u8 data_type; /* To differentiate various internal objs */\
- u8 flags; /* Type of Op */\
- u16 aml_opcode; /* AML opcode */\
- u32 aml_offset; /* Offset of declaration in AML */\
- union acpi_parse_object *parent; /* Parent op */\
- union acpi_parse_object *next; /* Next op */\
+ union acpi_parse_object *parent; /* Parent op */\
+ u8 descriptor_type; /* To differentiate various internal objs */\
+ u8 flags; /* Type of Op */\
+ u16 aml_opcode; /* AML opcode */\
+ u32 aml_offset; /* Offset of declaration in AML */\
+ union acpi_parse_object *next; /* Next op */\
+ struct acpi_namespace_node *node; /* For use by interpreter */\
+ union acpi_parse_value value; /* Value or args associated with the opcode */\
ACPI_DISASM_ONLY_MEMBERS (\
- u8 disasm_flags; /* Used during AML disassembly */\
- u8 disasm_opcode; /* Subtype used for disassembly */\
- char aml_op_name[16]) /* Op name (debug only) */\
- /* NON-DEBUG members below: */\
- struct acpi_namespace_node *node; /* For use by interpreter */\
- union acpi_parse_value value; /* Value or args associated with the opcode */
-
-#define ACPI_DASM_BUFFER 0x00
-#define ACPI_DASM_RESOURCE 0x01
-#define ACPI_DASM_STRING 0x02
-#define ACPI_DASM_UNICODE 0x03
-#define ACPI_DASM_EISAID 0x04
-#define ACPI_DASM_MATCHOP 0x05
+ u8 disasm_flags; /* Used during AML disassembly */\
+ u8 disasm_opcode; /* Subtype used for disassembly */\
+ char aml_op_name[16]) /* Op name (debug only) */
+
+#define ACPI_DASM_BUFFER 0x00
+#define ACPI_DASM_RESOURCE 0x01
+#define ACPI_DASM_STRING 0x02
+#define ACPI_DASM_UNICODE 0x03
+#define ACPI_DASM_EISAID 0x04
+#define ACPI_DASM_MATCHOP 0x05
+#define ACPI_DASM_LNOT_PREFIX 0x06
+#define ACPI_DASM_LNOT_SUFFIX 0x07
+#define ACPI_DASM_IGNORE 0x08
/*
- * generic operation (for example: If, While, Store)
+ * Generic operation (for example: If, While, Store)
*/
struct acpi_parse_obj_common {
ACPI_PARSE_COMMON};
@@ -601,7 +620,7 @@ struct acpi_parse_obj_named {
u32 name; /* 4-byte name or zero if no name */
};
-/* The parse node is the fundamental element of the parse tree */
+/* This version is used by the i_aSL compiler only */
#define ACPI_MAX_PARSEOP_NAME 20
@@ -643,7 +662,6 @@ union acpi_parse_object {
* method.
*/
struct acpi_parse_state {
- u32 aml_size;
u8 *aml_start; /* First AML byte */
u8 *aml; /* Next AML byte */
u8 *aml_end; /* (last + 1) AML byte */
@@ -653,22 +671,23 @@ struct acpi_parse_state {
struct acpi_namespace_node *start_node;
union acpi_generic_state *scope; /* Current scope */
union acpi_parse_object *start_scope;
+ u32 aml_size;
};
/* Parse object flags */
-#define ACPI_PARSEOP_GENERIC 0x01
-#define ACPI_PARSEOP_NAMED 0x02
-#define ACPI_PARSEOP_DEFERRED 0x04
-#define ACPI_PARSEOP_BYTELIST 0x08
-#define ACPI_PARSEOP_IN_CACHE 0x80
+#define ACPI_PARSEOP_GENERIC 0x01
+#define ACPI_PARSEOP_NAMED 0x02
+#define ACPI_PARSEOP_DEFERRED 0x04
+#define ACPI_PARSEOP_BYTELIST 0x08
+#define ACPI_PARSEOP_IN_CACHE 0x80
/* Parse object disasm_flags */
-#define ACPI_PARSEOP_IGNORE 0x01
-#define ACPI_PARSEOP_PARAMLIST 0x02
-#define ACPI_PARSEOP_EMPTY_TERMLIST 0x04
-#define ACPI_PARSEOP_SPECIAL 0x10
+#define ACPI_PARSEOP_IGNORE 0x01
+#define ACPI_PARSEOP_PARAMLIST 0x02
+#define ACPI_PARSEOP_EMPTY_TERMLIST 0x04
+#define ACPI_PARSEOP_SPECIAL 0x10
/*****************************************************************************
*
@@ -676,8 +695,8 @@ struct acpi_parse_state {
*
****************************************************************************/
-#define PCI_ROOT_HID_STRING "PNP0A03"
-#define PCI_EXPRESS_ROOT_HID_STRING "PNP0A08"
+#define PCI_ROOT_HID_STRING "PNP0A03"
+#define PCI_EXPRESS_ROOT_HID_STRING "PNP0A08"
struct acpi_bit_register_info {
u8 parent_register;
@@ -710,13 +729,14 @@ struct acpi_bit_register_info {
#define ACPI_BITMASK_PCIEXP_WAKE_STATUS 0x4000 /* ACPI 3.0 */
#define ACPI_BITMASK_WAKE_STATUS 0x8000
-#define ACPI_BITMASK_ALL_FIXED_STATUS (ACPI_BITMASK_TIMER_STATUS | \
- ACPI_BITMASK_BUS_MASTER_STATUS | \
- ACPI_BITMASK_GLOBAL_LOCK_STATUS | \
- ACPI_BITMASK_POWER_BUTTON_STATUS | \
- ACPI_BITMASK_SLEEP_BUTTON_STATUS | \
- ACPI_BITMASK_RT_CLOCK_STATUS | \
- ACPI_BITMASK_WAKE_STATUS)
+#define ACPI_BITMASK_ALL_FIXED_STATUS (\
+ ACPI_BITMASK_TIMER_STATUS | \
+ ACPI_BITMASK_BUS_MASTER_STATUS | \
+ ACPI_BITMASK_GLOBAL_LOCK_STATUS | \
+ ACPI_BITMASK_POWER_BUTTON_STATUS | \
+ ACPI_BITMASK_SLEEP_BUTTON_STATUS | \
+ ACPI_BITMASK_RT_CLOCK_STATUS | \
+ ACPI_BITMASK_WAKE_STATUS)
#define ACPI_BITMASK_TIMER_ENABLE 0x0001
#define ACPI_BITMASK_GLOBAL_LOCK_ENABLE 0x0020
@@ -820,7 +840,7 @@ struct acpi_bit_register_info {
*
****************************************************************************/
-#define ACPI_ASCII_ZERO 0x30
+#define ACPI_ASCII_ZERO 0x30
/*****************************************************************************
*
@@ -842,9 +862,9 @@ struct acpi_integrity_info {
u32 objects;
};
-#define ACPI_DB_REDIRECTABLE_OUTPUT 0x01
-#define ACPI_DB_CONSOLE_OUTPUT 0x02
-#define ACPI_DB_DUPLICATE_OUTPUT 0x03
+#define ACPI_DB_REDIRECTABLE_OUTPUT 0x01
+#define ACPI_DB_CONSOLE_OUTPUT 0x02
+#define ACPI_DB_DUPLICATE_OUTPUT 0x03
/*****************************************************************************
*
@@ -854,18 +874,18 @@ struct acpi_integrity_info {
/* Entry for a memory allocation (debug only) */
-#define ACPI_MEM_MALLOC 0
-#define ACPI_MEM_CALLOC 1
-#define ACPI_MAX_MODULE_NAME 16
+#define ACPI_MEM_MALLOC 0
+#define ACPI_MEM_CALLOC 1
+#define ACPI_MAX_MODULE_NAME 16
#define ACPI_COMMON_DEBUG_MEM_HEADER \
- struct acpi_debug_mem_block *previous; \
- struct acpi_debug_mem_block *next; \
- u32 size; \
- u32 component; \
- u32 line; \
- char module[ACPI_MAX_MODULE_NAME]; \
- u8 alloc_type;
+ struct acpi_debug_mem_block *previous; \
+ struct acpi_debug_mem_block *next; \
+ u32 size; \
+ u32 component; \
+ u32 line; \
+ char module[ACPI_MAX_MODULE_NAME]; \
+ u8 alloc_type;
struct acpi_debug_mem_header {
ACPI_COMMON_DEBUG_MEM_HEADER};
diff --git a/include/acpi/acmacros.h b/include/acpi/acmacros.h
index f2be2a8..38f9aa4 100644
--- a/include/acpi/acmacros.h
+++ b/include/acpi/acmacros.h
@@ -56,6 +56,10 @@
#define ACPI_CLEAR_BIT(target,bit) ((target) &= ~(bit))
#define ACPI_MIN(a,b) (((a)<(b))?(a):(b))
+/* Size calculation */
+
+#define ACPI_ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0]))
+
#if ACPI_MACHINE_WIDTH == 16
/*
@@ -99,7 +103,7 @@
* printf() format helpers
*/
-/* Split 64-bit integer into two 32-bit values. Use with %8.8X%8.8X */
+/* Split 64-bit integer into two 32-bit values. Use with %8.8_x%8.8_x */
#define ACPI_FORMAT_UINT64(i) ACPI_HIDWORD(i),ACPI_LODWORD(i)
@@ -130,7 +134,6 @@
#define ACPI_TO_POINTER(i) ACPI_ADD_PTR (void,(void *) NULL,(acpi_native_uint) i)
#define ACPI_TO_INTEGER(p) ACPI_PTR_DIFF (p,(void *) NULL)
#define ACPI_OFFSET(d,f) (acpi_size) ACPI_PTR_DIFF (&(((d *)0)->f),(void *) NULL)
-#define ACPI_FADT_OFFSET(f) ACPI_OFFSET (FADT_DESCRIPTOR, f)
#if ACPI_MACHINE_WIDTH == 16
#define ACPI_STORE_POINTER(d,s) ACPI_MOVE_32_TO_32(d,s)
@@ -141,6 +144,12 @@
#define ACPI_PTR_TO_PHYSADDR(i) ACPI_TO_INTEGER(i)
#endif
+#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED
+#define ACPI_COMPARE_NAME(a,b) (*ACPI_CAST_PTR (u32,(a)) == *ACPI_CAST_PTR (u32,(b)))
+#else
+#define ACPI_COMPARE_NAME(a,b) (!ACPI_STRNCMP (ACPI_CAST_PTR (char,(a)), ACPI_CAST_PTR (char,(b)), ACPI_NAME_SIZE))
+#endif
+
/*
* Macros for moving data around to/from buffers that are possibly unaligned.
* If the hardware supports the transfer of unaligned data, just do the store.
@@ -341,29 +350,33 @@
/*
* Rounding macros (Power of two boundaries only)
*/
-#define ACPI_ROUND_DOWN(value,boundary) (((acpi_native_uint)(value)) & \
+#define ACPI_ROUND_DOWN(value,boundary) (((acpi_native_uint)(value)) & \
(~(((acpi_native_uint) boundary)-1)))
-#define ACPI_ROUND_UP(value,boundary) ((((acpi_native_uint)(value)) + \
+#define ACPI_ROUND_UP(value,boundary) ((((acpi_native_uint)(value)) + \
(((acpi_native_uint) boundary)-1)) & \
(~(((acpi_native_uint) boundary)-1)))
-#define ACPI_ROUND_DOWN_TO_32_BITS(a) ACPI_ROUND_DOWN(a,4)
-#define ACPI_ROUND_DOWN_TO_64_BITS(a) ACPI_ROUND_DOWN(a,8)
-#define ACPI_ROUND_DOWN_TO_NATIVE_WORD(a) ACPI_ROUND_DOWN(a,ALIGNED_ADDRESS_BOUNDARY)
+/* Note: sizeof(acpi_native_uint) evaluates to either 2, 4, or 8 */
+
+#define ACPI_ROUND_DOWN_TO_32BIT(a) ACPI_ROUND_DOWN(a,4)
+#define ACPI_ROUND_DOWN_TO_64BIT(a) ACPI_ROUND_DOWN(a,8)
+#define ACPI_ROUND_DOWN_TO_NATIVE_WORD(a) ACPI_ROUND_DOWN(a,sizeof(acpi_native_uint))
-#define ACPI_ROUND_UP_to_32_bITS(a) ACPI_ROUND_UP(a,4)
-#define ACPI_ROUND_UP_to_64_bITS(a) ACPI_ROUND_UP(a,8)
-#define ACPI_ROUND_UP_TO_NATIVE_WORD(a) ACPI_ROUND_UP(a,ALIGNED_ADDRESS_BOUNDARY)
+#define ACPI_ROUND_UP_TO_32BIT(a) ACPI_ROUND_UP(a,4)
+#define ACPI_ROUND_UP_TO_64BIT(a) ACPI_ROUND_UP(a,8)
+#define ACPI_ROUND_UP_TO_NATIVE_WORD(a) ACPI_ROUND_UP(a,sizeof(acpi_native_uint))
-#define ACPI_ROUND_BITS_UP_TO_BYTES(a) ACPI_DIV_8((a) + 7)
-#define ACPI_ROUND_BITS_DOWN_TO_BYTES(a) ACPI_DIV_8((a))
+#define ACPI_ROUND_BITS_UP_TO_BYTES(a) ACPI_DIV_8((a) + 7)
+#define ACPI_ROUND_BITS_DOWN_TO_BYTES(a) ACPI_DIV_8((a))
-#define ACPI_ROUND_UP_TO_1K(a) (((a) + 1023) >> 10)
+#define ACPI_ROUND_UP_TO_1K(a) (((a) + 1023) >> 10)
/* Generic (non-power-of-two) rounding */
-#define ACPI_ROUND_UP_TO(value,boundary) (((value) + ((boundary)-1)) / (boundary))
+#define ACPI_ROUND_UP_TO(value,boundary) (((value) + ((boundary)-1)) / (boundary))
+
+#define ACPI_IS_MISALIGNED(value) (((acpi_native_uint)value) & (sizeof(acpi_native_uint)-1))
/*
* Bitmask creation
@@ -371,10 +384,10 @@
* MASK_BITS_ABOVE creates a mask starting AT the position and above
* MASK_BITS_BELOW creates a mask starting one bit BELOW the position
*/
-#define ACPI_MASK_BITS_ABOVE(position) (~((ACPI_INTEGER_MAX) << ((u32) (position))))
-#define ACPI_MASK_BITS_BELOW(position) ((ACPI_INTEGER_MAX) << ((u32) (position)))
+#define ACPI_MASK_BITS_ABOVE(position) (~((ACPI_INTEGER_MAX) << ((u32) (position))))
+#define ACPI_MASK_BITS_BELOW(position) ((ACPI_INTEGER_MAX) << ((u32) (position)))
-#define ACPI_IS_OCTAL_DIGIT(d) (((char)(d) >= '0') && ((char)(d) <= '7'))
+#define ACPI_IS_OCTAL_DIGIT(d) (((char)(d) >= '0') && ((char)(d) <= '7'))
/* Bitfields within ACPI registers */
@@ -396,8 +409,8 @@
*
* The "Descriptor" field is the first field in both structures.
*/
-#define ACPI_GET_DESCRIPTOR_TYPE(d) (((union acpi_descriptor *)(void *)(d))->descriptor_id)
-#define ACPI_SET_DESCRIPTOR_TYPE(d,t) (((union acpi_descriptor *)(void *)(d))->descriptor_id = t)
+#define ACPI_GET_DESCRIPTOR_TYPE(d) (((union acpi_descriptor *)(void *)(d))->common.descriptor_type)
+#define ACPI_SET_DESCRIPTOR_TYPE(d,t) (((union acpi_descriptor *)(void *)(d))->common.descriptor_type = t)
/* Macro to test the object type */
@@ -486,7 +499,6 @@
#define ACPI_ERROR(plist)
#define ACPI_ERROR_NAMESPACE(s,e)
#define ACPI_ERROR_METHOD(s,n,p,e)
-
#endif
/*
@@ -514,12 +526,12 @@
#define ACPI_GET_FUNCTION_NAME _acpi_function_name
/*
* The Name parameter should be the procedure name as a quoted string.
- * This is declared as a local string ("my_function_name") so that it can
+ * This is declared as a local string ("MyFunctionName") so that it can
* be also used by the function exit macros below.
* Note: (const char) is used to be compatible with the debug interfaces
* and macros such as __FUNCTION__.
*/
-#define ACPI_FUNCTION_NAME(name) const char *_acpi_function_name = name;
+#define ACPI_FUNCTION_NAME(name) const char *_acpi_function_name = #name;
#else
/* Compiler supports __FUNCTION__ (or equivalent) -- Ignore this macro */
@@ -528,13 +540,13 @@
#endif
#define ACPI_FUNCTION_TRACE(a) ACPI_FUNCTION_NAME(a) \
- acpi_ut_trace(ACPI_DEBUG_PARAMETERS)
+ acpi_ut_trace(ACPI_DEBUG_PARAMETERS)
#define ACPI_FUNCTION_TRACE_PTR(a,b) ACPI_FUNCTION_NAME(a) \
- acpi_ut_trace_ptr(ACPI_DEBUG_PARAMETERS,(void *)b)
+ acpi_ut_trace_ptr(ACPI_DEBUG_PARAMETERS,(void *)b)
#define ACPI_FUNCTION_TRACE_U32(a,b) ACPI_FUNCTION_NAME(a) \
- acpi_ut_trace_u32(ACPI_DEBUG_PARAMETERS,(u32)b)
+ acpi_ut_trace_u32(ACPI_DEBUG_PARAMETERS,(u32)b)
#define ACPI_FUNCTION_TRACE_STR(a,b) ACPI_FUNCTION_NAME(a) \
- acpi_ut_trace_str(ACPI_DEBUG_PARAMETERS,(char *)b)
+ acpi_ut_trace_str(ACPI_DEBUG_PARAMETERS,(char *)b)
#define ACPI_FUNCTION_ENTRY() acpi_ut_track_stack_ptr()
@@ -543,7 +555,7 @@
* WARNING: These macros include a return statement. This is usually considered
* bad form, but having a separate exit macro is very ugly and difficult to maintain.
* One of the FUNCTION_TRACE macros above must be used in conjunction with these macros
- * so that "_acpi_function_name" is defined.
+ * so that "_AcpiFunctionName" is defined.
*
* Note: the DO_WHILE0 macro is used to prevent some compilers from complaining
* about these constructs.
@@ -654,6 +666,7 @@
#define ACPI_DUMP_STACK_ENTRY(a)
#define ACPI_DUMP_OPERANDS(a,b,c,d,e)
#define ACPI_DUMP_ENTRY(a,b)
+#define ACPI_DUMP_TABLES(a,b)
#define ACPI_DUMP_PATHNAME(a,b,c,d)
#define ACPI_DUMP_RESOURCE_LIST(a)
#define ACPI_DUMP_BUFFER(a,b)
@@ -709,19 +722,19 @@
/* Memory allocation */
-#define ACPI_MEM_ALLOCATE(a) acpi_ut_allocate((acpi_size)(a),_COMPONENT,_acpi_module_name,__LINE__)
-#define ACPI_MEM_CALLOCATE(a) acpi_ut_callocate((acpi_size)(a), _COMPONENT,_acpi_module_name,__LINE__)
-#define ACPI_MEM_FREE(a) acpi_os_free(a)
+#define ACPI_ALLOCATE(a) acpi_ut_allocate((acpi_size)(a),_COMPONENT,_acpi_module_name,__LINE__)
+#define ACPI_ALLOCATE_ZEROED(a) acpi_ut_allocate_zeroed((acpi_size)(a), _COMPONENT,_acpi_module_name,__LINE__)
+#define ACPI_FREE(a) acpi_os_free(a)
#define ACPI_MEM_TRACKING(a)
#else
/* Memory allocation */
-#define ACPI_MEM_ALLOCATE(a) acpi_ut_allocate_and_track((acpi_size)(a),_COMPONENT,_acpi_module_name,__LINE__)
-#define ACPI_MEM_CALLOCATE(a) acpi_ut_callocate_and_track((acpi_size)(a), _COMPONENT,_acpi_module_name,__LINE__)
-#define ACPI_MEM_FREE(a) acpi_ut_free_and_track(a,_COMPONENT,_acpi_module_name,__LINE__)
-#define ACPI_MEM_TRACKING(a) a
+#define ACPI_ALLOCATE(a) acpi_ut_allocate_and_track((acpi_size)(a),_COMPONENT,_acpi_module_name,__LINE__)
+#define ACPI_ALLOCATE_ZEROED(a) acpi_ut_allocate_zeroed_and_track((acpi_size)(a), _COMPONENT,_acpi_module_name,__LINE__)
+#define ACPI_FREE(a) acpi_ut_free_and_track(a,_COMPONENT,_acpi_module_name,__LINE__)
+#define ACPI_MEM_TRACKING(a) a
#endif /* ACPI_DBG_TRACK_ALLOCATIONS */
diff --git a/include/acpi/acnamesp.h b/include/acpi/acnamesp.h
index b667a80..83b52f9 100644
--- a/include/acpi/acnamesp.h
+++ b/include/acpi/acnamesp.h
@@ -63,6 +63,8 @@
#define ACPI_NS_DONT_OPEN_SCOPE 0x02
#define ACPI_NS_NO_PEER_SEARCH 0x04
#define ACPI_NS_ERROR_IF_FOUND 0x08
+#define ACPI_NS_PREFIX_IS_SCOPE 0x10
+#define ACPI_NS_EXTERNAL 0x20
#define ACPI_NS_WALK_UNLOCK TRUE
#define ACPI_NS_WALK_NO_UNLOCK FALSE
@@ -171,19 +173,17 @@ acpi_ns_dump_objects(acpi_object_type type,
/*
* nseval - Namespace evaluation functions
*/
-acpi_status acpi_ns_evaluate_by_handle(struct acpi_parameter_info *info);
-
-acpi_status
-acpi_ns_evaluate_by_name(char *pathname, struct acpi_parameter_info *info);
-
-acpi_status
-acpi_ns_evaluate_relative(char *pathname, struct acpi_parameter_info *info);
+acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info);
/*
* nsnames - Name and Scope manipulation
*/
u32 acpi_ns_opens_scope(acpi_object_type type);
+void
+acpi_ns_build_external_path(struct acpi_namespace_node *node,
+ acpi_size size, char *name_buffer);
+
char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node);
char *acpi_ns_name_of_current_scope(struct acpi_walk_state *walk_state);
@@ -196,9 +196,9 @@ u8
acpi_ns_pattern_match(struct acpi_namespace_node *obj_node, char *search_for);
acpi_status
-acpi_ns_get_node_by_path(char *external_pathname,
- struct acpi_namespace_node *in_prefix_node,
- u32 flags, struct acpi_namespace_node **out_node);
+acpi_ns_get_node(struct acpi_namespace_node *prefix_node,
+ char *external_pathname,
+ u32 flags, struct acpi_namespace_node **out_node);
acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node);
@@ -241,10 +241,10 @@ acpi_ns_search_and_enter(u32 entry_name,
u32 flags, struct acpi_namespace_node **ret_node);
acpi_status
-acpi_ns_search_node(u32 entry_name,
- struct acpi_namespace_node *node,
- acpi_object_type type,
- struct acpi_namespace_node **ret_node);
+acpi_ns_search_one_scope(u32 entry_name,
+ struct acpi_namespace_node *node,
+ acpi_object_type type,
+ struct acpi_namespace_node **ret_node);
void
acpi_ns_install_node(struct acpi_walk_state *walk_state,
diff --git a/include/acpi/acobject.h b/include/acpi/acobject.h
index d130cfe..1747d94 100644
--- a/include/acpi/acobject.h
+++ b/include/acpi/acobject.h
@@ -1,7 +1,7 @@
/******************************************************************************
*
- * Name: acobject.h - Definition of union acpi_operand_object (Internal object only)
+ * Name: acobject.h - Definition of union acpi_operand_object (Internal object only)
*
*****************************************************************************/
@@ -45,10 +45,12 @@
#ifndef _ACOBJECT_H
#define _ACOBJECT_H
+/* acpisrc:struct_defs -- for acpisrc conversion */
+
/*
- * The union acpi_operand_object is used to pass AML operands from the dispatcher
+ * The union acpi_operand_object is used to pass AML operands from the dispatcher
* to the interpreter, and to keep track of the various handlers such as
- * address space handlers and notify handlers. The object is a constant
+ * address space handlers and notify handlers. The object is a constant
* size in order to allow it to be cached and reused.
*/
@@ -61,17 +63,25 @@
/*
* Common area for all objects.
*
- * data_type is used to differentiate between internal descriptors, and MUST
- * be the first byte in this structure.
+ * descriptor_type is used to differentiate between internal descriptors, and
+ * must be in the same place across all descriptors
+ *
+ * Note: The descriptor_type and Type fields must appear in the identical
+ * position in both the struct acpi_namespace_node and union acpi_operand_object
+ * structures.
*/
-#define ACPI_OBJECT_COMMON_HEADER /* SIZE/ALIGNMENT: 32 bits, one ptr plus trailing 8-bit flag */\
- u8 descriptor; /* To differentiate various internal objs */\
- u8 type; /* acpi_object_type */\
- u16 reference_count; /* For object deletion management */\
- union acpi_operand_object *next_object; /* Objects linked to parent NS node */\
- u8 flags;
-
-/* Values for flag byte above */
+#define ACPI_OBJECT_COMMON_HEADER \
+ union acpi_operand_object *next_object; /* Objects linked to parent NS node */\
+ u8 descriptor_type; /* To differentiate various internal objs */\
+ u8 type; /* acpi_object_type */\
+ u16 reference_count; /* For object deletion management */\
+ u8 flags;
+ /*
+ * Note: There are 3 bytes available here before the
+ * next natural alignment boundary (for both 32/64 cases)
+ */
+
+/* Values for Flag byte above */
#define AOPOBJ_AML_CONSTANT 0x01
#define AOPOBJ_STATIC_POINTER 0x02
@@ -79,36 +89,7 @@
#define AOPOBJ_OBJECT_INITIALIZED 0x08
#define AOPOBJ_SETUP_COMPLETE 0x10
#define AOPOBJ_SINGLE_DATUM 0x20
-
-/*
- * Common bitfield for the field objects
- * "Field Datum" -- a datum from the actual field object
- * "Buffer Datum" -- a datum from a user buffer, read from or to be written to the field
- */
-#define ACPI_COMMON_FIELD_INFO /* SIZE/ALIGNMENT: 24 bits + three 32-bit values */\
- u8 field_flags; /* Access, update, and lock bits */\
- u8 attribute; /* From access_as keyword */\
- u8 access_byte_width; /* Read/Write size in bytes */\
- u32 bit_length; /* Length of field in bits */\
- u32 base_byte_offset; /* Byte offset within containing object */\
- u8 start_field_bit_offset;/* Bit offset within first field datum (0-63) */\
- u8 access_bit_width; /* Read/Write size in bits (8-64) */\
- u32 value; /* Value to store into the Bank or Index register */\
- struct acpi_namespace_node *node; /* Link back to parent node */
-
-/*
- * Fields common to both Strings and Buffers
- */
-#define ACPI_COMMON_BUFFER_INFO \
- u32 length;
-
-/*
- * Common fields for objects that support ASL notifications
- */
-#define ACPI_COMMON_NOTIFY_INFO \
- union acpi_operand_object *system_notify; /* Handler for system notifies */\
- union acpi_operand_object *device_notify; /* Handler for driver notifies */\
- union acpi_operand_object *handler; /* Handler for Address space */
+#define AOPOBJ_INVALID 0x40 /* Used if host OS won't allow an op_region address */
/******************************************************************************
*
@@ -125,25 +106,31 @@ struct acpi_object_integer {
/*
* Note: The String and Buffer object must be identical through the Pointer
- * element. There is code that depends on this.
+ * and length elements. There is code that depends on this.
+ *
+ * Fields common to both Strings and Buffers
*/
+#define ACPI_COMMON_BUFFER_INFO(_type) \
+ _type *pointer; \
+ u32 length;
+
struct acpi_object_string { /* Null terminated, ASCII characters only */
- ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_BUFFER_INFO char *pointer; /* String in AML stream or allocated string */
+ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_BUFFER_INFO(char) /* String in AML stream or allocated string */
};
struct acpi_object_buffer {
- ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_BUFFER_INFO u8 * pointer; /* Buffer in AML stream or allocated buffer */
- struct acpi_namespace_node *node; /* Link back to parent node */
- u8 *aml_start;
+ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_BUFFER_INFO(u8) /* Buffer in AML stream or allocated buffer */
u32 aml_length;
+ u8 *aml_start;
+ struct acpi_namespace_node *node; /* Link back to parent node */
};
struct acpi_object_package {
- ACPI_OBJECT_COMMON_HEADER u32 count; /* # of elements in package */
- u32 aml_length;
- u8 *aml_start;
- struct acpi_namespace_node *node; /* Link back to parent node */
+ ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *node; /* Link back to parent node */
union acpi_operand_object **elements; /* Array of pointers to acpi_objects */
+ u8 *aml_start;
+ u32 aml_length;
+ u32 count; /* # of elements in package */
};
/******************************************************************************
@@ -156,23 +143,6 @@ struct acpi_object_event {
ACPI_OBJECT_COMMON_HEADER void *semaphore;
};
-#define ACPI_INFINITE_CONCURRENCY 0xFF
-
-typedef
-acpi_status(*ACPI_INTERNAL_METHOD) (struct acpi_walk_state * walk_state);
-
-struct acpi_object_method {
- ACPI_OBJECT_COMMON_HEADER u8 method_flags;
- u8 param_count;
- u32 aml_length;
- void *semaphore;
- u8 *aml_start;
- ACPI_INTERNAL_METHOD implementation;
- u8 concurrency;
- u8 thread_count;
- acpi_owner_id owner_id;
-};
-
struct acpi_object_mutex {
ACPI_OBJECT_COMMON_HEADER u8 sync_level; /* 0-15, specified in Mutex() call */
u16 acquisition_depth; /* Allow multiple Acquires, same thread */
@@ -186,11 +156,23 @@ struct acpi_object_mutex {
struct acpi_object_region {
ACPI_OBJECT_COMMON_HEADER u8 space_id;
- union acpi_operand_object *handler; /* Handler for region access */
struct acpi_namespace_node *node; /* Containing namespace node */
+ union acpi_operand_object *handler; /* Handler for region access */
union acpi_operand_object *next;
- u32 length;
acpi_physical_address address;
+ u32 length;
+};
+
+struct acpi_object_method {
+ ACPI_OBJECT_COMMON_HEADER u8 method_flags;
+ u8 param_count;
+ u8 concurrency;
+ void *semaphore;
+ u8 *aml_start;
+ ACPI_INTERNAL_METHOD implementation;
+ u32 aml_length;
+ u8 thread_count;
+ acpi_owner_id owner_id;
};
/******************************************************************************
@@ -199,6 +181,14 @@ struct acpi_object_region {
*
*****************************************************************************/
+/*
+ * Common fields for objects that support ASL notifications
+ */
+#define ACPI_COMMON_NOTIFY_INFO \
+ union acpi_operand_object *system_notify; /* Handler for system notifies */\
+ union acpi_operand_object *device_notify; /* Handler for driver notifies */\
+ union acpi_operand_object *handler; /* Handler for Address space */
+
struct acpi_object_notify_common { /* COMMON NOTIFY for POWER, PROCESSOR, DEVICE, and THERMAL */
ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO};
@@ -213,9 +203,9 @@ struct acpi_object_power_resource {
};
struct acpi_object_processor {
- ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO u32 proc_id;
- u32 length;
- acpi_io_address address;
+ ACPI_OBJECT_COMMON_HEADER u8 proc_id;
+ u8 length;
+ ACPI_COMMON_NOTIFY_INFO acpi_io_address address;
};
struct acpi_object_thermal_zone {
@@ -227,9 +217,24 @@ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO};
*
*****************************************************************************/
+/*
+ * Common bitfield for the field objects
+ * "Field Datum" -- a datum from the actual field object
+ * "Buffer Datum" -- a datum from a user buffer, read from or to be written to the field
+ */
+#define ACPI_COMMON_FIELD_INFO \
+ u8 field_flags; /* Access, update, and lock bits */\
+ u8 attribute; /* From access_as keyword */\
+ u8 access_byte_width; /* Read/Write size in bytes */\
+ struct acpi_namespace_node *node; /* Link back to parent node */\
+ u32 bit_length; /* Length of field in bits */\
+ u32 base_byte_offset; /* Byte offset within containing object */\
+ u32 value; /* Value to store into the Bank or Index register */\
+ u8 start_field_bit_offset;/* Bit offset within first field datum (0-63) */\
+ u8 access_bit_width; /* Read/Write size in bits (8-64) */
+
struct acpi_object_field_common { /* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */
- ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *region_obj; /* Containing Operation Region object */
- /* (REGION/BANK fields only) */
+ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *region_obj; /* Parent Operation Region object (REGION/BANK fields only) */
};
struct acpi_object_region_field {
@@ -244,7 +249,7 @@ struct acpi_object_bank_field {
struct acpi_object_index_field {
ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO
/*
- * No "region_obj" pointer needed since the Index and Data registers
+ * No "RegionObj" pointer needed since the Index and Data registers
* are each field definitions unto themselves.
*/
union acpi_operand_object *index_obj; /* Index register */
@@ -269,13 +274,9 @@ struct acpi_object_notify_handler {
void *context;
};
-/* Flags for address handler */
-
-#define ACPI_ADDR_HANDLER_DEFAULT_INSTALLED 0x1
-
struct acpi_object_addr_handler {
ACPI_OBJECT_COMMON_HEADER u8 space_id;
- u16 hflags;
+ u8 handler_flags;
acpi_adr_space_handler handler;
struct acpi_namespace_node *node; /* Parent device */
void *context;
@@ -284,6 +285,10 @@ struct acpi_object_addr_handler {
union acpi_operand_object *next;
};
+/* Flags for address handler (handler_flags) */
+
+#define ACPI_ADDR_HANDLER_DEFAULT_INSTALLED 0x01
+
/******************************************************************************
*
* Special internal objects
@@ -297,10 +302,10 @@ struct acpi_object_addr_handler {
struct acpi_object_reference {
ACPI_OBJECT_COMMON_HEADER u8 target_type; /* Used for index_op */
u16 opcode;
- u32 offset; /* Used for arg_op, local_op, and index_op */
- void *object; /* name_op=>HANDLE to obj, index_op=>union acpi_operand_object */
+ void *object; /* name_op=>HANDLE to obj, index_op=>union acpi_operand_object */
struct acpi_namespace_node *node;
union acpi_operand_object **where;
+ u32 offset; /* Used for arg_op, local_op, and index_op */
};
/*
@@ -311,12 +316,10 @@ struct acpi_object_reference {
* Currently: Region and field_unit types
*/
struct acpi_object_extra {
- ACPI_OBJECT_COMMON_HEADER u8 byte_fill1;
- u16 word_fill1;
- u32 aml_length;
- u8 *aml_start;
- struct acpi_namespace_node *method_REG; /* _REG method for this region (if any) */
+ ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *method_REG; /* _REG method for this region (if any) */
void *region_context; /* Region-specific data */
+ u8 *aml_start;
+ u32 aml_length;
};
/* Additional data that can be attached to namespace nodes */
@@ -391,8 +394,13 @@ union acpi_operand_object {
#define ACPI_DESC_TYPE_NAMED 0x0F
#define ACPI_DESC_TYPE_MAX 0x0F
+struct acpi_common_descriptor {
+ void *common_pointer;
+ u8 descriptor_type; /* To differentiate various internal objs */
+};
+
union acpi_descriptor {
- u8 descriptor_id; /* To differentiate various internal objs */
+ struct acpi_common_descriptor common;
union acpi_operand_object object;
struct acpi_namespace_node node;
union acpi_parse_object op;
diff --git a/include/acpi/acopcode.h b/include/acpi/acopcode.h
index e6d78bd..7659a46 100644
--- a/include/acpi/acopcode.h
+++ b/include/acpi/acopcode.h
@@ -94,7 +94,7 @@
#define ARGP_CONCAT_RES_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
#define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SUPERNAME)
#define ARGP_CONTINUE_OP ARG_NONE
-#define ARGP_COPY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SIMPLENAME)
+#define ARGP_COPY_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SIMPLENAME)
#define ARGP_CREATE_BIT_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
#define ARGP_CREATE_BYTE_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
#define ARGP_CREATE_DWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h
index 7785d48..8d5039d 100644
--- a/include/acpi/acoutput.h
+++ b/include/acpi/acoutput.h
@@ -50,7 +50,7 @@
* component basis and a per-exception-type basis.
*/
-/* Component IDs are used in the global "debug_layer" */
+/* Component IDs are used in the global "DebugLayer" */
#define ACPI_UTILITIES 0x00000001
#define ACPI_HARDWARE 0x00000002
@@ -121,7 +121,7 @@
#define ACPI_LV_INTERRUPTS 0x08000000
#define ACPI_LV_VERBOSITY3 0x0F000000 | ACPI_LV_VERBOSITY2
-/* Exceptionally verbose output -- also used in the global "debug_level" */
+/* Exceptionally verbose output -- also used in the global "DebugLevel" */
#define ACPI_LV_AML_DISASSEMBLE 0x10000000
#define ACPI_LV_VERBOSE_INFO 0x20000000
@@ -135,7 +135,7 @@
*/
#define ACPI_DEBUG_LEVEL(dl) (u32) dl,ACPI_DEBUG_PARAMETERS
-/* Exception level -- used in the global "debug_level" */
+/* Exception level -- used in the global "DebugLevel" */
#define ACPI_DB_INIT ACPI_DEBUG_LEVEL (ACPI_LV_INIT)
#define ACPI_DB_DEBUG_OBJECT ACPI_DEBUG_LEVEL (ACPI_LV_DEBUG_OBJECT)
@@ -144,13 +144,13 @@
/*
* These two levels are essentially obsolete, all instances in the
- * ACPICA core code have been replaced by REPORT_ERROR and REPORT_WARNING
+ * ACPICA core code have been replaced by ACPI_ERROR and ACPI_WARNING
* (Kept here because some drivers may still use them)
*/
#define ACPI_DB_ERROR ACPI_DEBUG_LEVEL (ACPI_LV_ERROR)
#define ACPI_DB_WARN ACPI_DEBUG_LEVEL (ACPI_LV_WARN)
-/* Trace level -- also used in the global "debug_level" */
+/* Trace level -- also used in the global "DebugLevel" */
#define ACPI_DB_INIT_NAMES ACPI_DEBUG_LEVEL (ACPI_LV_INIT_NAMES)
#define ACPI_DB_THREADS ACPI_DEBUG_LEVEL (ACPI_LV_THREADS)
diff --git a/include/acpi/acparser.h b/include/acpi/acparser.h
index 5a1ff484..9d49d3c 100644
--- a/include/acpi/acparser.h
+++ b/include/acpi/acparser.h
@@ -46,7 +46,7 @@
#define OP_HAS_RETURN_VALUE 1
-/* variable # arguments */
+/* Variable number of arguments. This field must be 32 bits */
#define ACPI_VAR_ARGS ACPI_UINT32_MAX
@@ -71,7 +71,7 @@
/*
* psxface - Parser external interfaces
*/
-acpi_status acpi_ps_execute_method(struct acpi_parameter_info *info);
+acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info);
/*
* psargs - Parse AML opcode arguments
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 6dca3d5..a2b3e39 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -26,7 +26,7 @@
#ifndef __ACPI_BUS_H__
#define __ACPI_BUS_H__
-#include <linux/kobject.h>
+#include <linux/device.h>
#include <acpi/acpi.h>
@@ -59,7 +59,7 @@ acpi_evaluate_reference(acpi_handle handle,
#define ACPI_BUS_FILE_ROOT "acpi"
extern struct proc_dir_entry *acpi_root_dir;
-extern FADT_DESCRIPTOR acpi_fadt;
+extern struct fadt_descriptor acpi_fadt;
enum acpi_bus_removal_type {
ACPI_BUS_REMOVAL_NORMAL = 0,
@@ -169,7 +169,8 @@ struct acpi_device_flags {
u32 power_manageable:1;
u32 performance_manageable:1;
u32 wake_capable:1; /* Wakeup(_PRW) supported? */
- u32 reserved:20;
+ u32 force_power_state:1;
+ u32 reserved:19;
};
/* File System */
@@ -296,6 +297,7 @@ struct acpi_device {
struct acpi_driver *driver;
void *driver_data;
struct kobject kobj;
+ struct device dev;
};
#define acpi_driver_data(d) ((d)->driver_data)
@@ -327,7 +329,7 @@ int acpi_bus_set_power(acpi_handle handle, int state);
int acpi_bus_generate_event(struct acpi_device *device, u8 type, int data);
int acpi_bus_receive_event(struct acpi_bus_event *event);
int acpi_bus_register_driver(struct acpi_driver *driver);
-int acpi_bus_unregister_driver(struct acpi_driver *driver);
+void acpi_bus_unregister_driver(struct acpi_driver *driver);
int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent,
acpi_handle handle, int type);
int acpi_bus_trim(struct acpi_device *start, int rmdevice);
diff --git a/include/acpi/acpi_numa.h b/include/acpi/acpi_numa.h
new file mode 100644
index 0000000..1049f2a
--- /dev/null
+++ b/include/acpi/acpi_numa.h
@@ -0,0 +1,23 @@
+#ifndef __ACPI_NUMA_H
+#define __ACPI_NUMA_H
+
+#ifdef CONFIG_ACPI_NUMA
+#include <linux/kernel.h>
+
+/* Proximity bitmap length */
+#if MAX_NUMNODES > 256
+#define MAX_PXM_DOMAINS MAX_NUMNODES
+#else
+#define MAX_PXM_DOMAINS (256) /* Old pxm spec is defined 8 bit */
+#endif
+
+extern int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS];
+extern int __cpuinitdata node_to_pxm_map[MAX_NUMNODES];
+
+extern int __cpuinit pxm_to_node(int);
+extern int __cpuinit node_to_pxm(int);
+extern int __cpuinit acpi_map_pxm_to_node(int);
+extern void __cpuinit acpi_unmap_pxm_to_node(int);
+
+#endif /* CONFIG_ACPI_NUMA */
+#endif /* __ACP_NUMA_H */
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index 970e9a6..8f473c8 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -50,12 +50,16 @@
#include "platform/acenv.h"
#include "actypes.h"
-/* Priorities for acpi_os_queue_for_execution */
+/* Types for acpi_os_execute */
-#define OSD_PRIORITY_GPE 1
-#define OSD_PRIORITY_HIGH 2
-#define OSD_PRIORITY_MED 3
-#define OSD_PRIORITY_LO 4
+typedef enum {
+ OSL_GLOBAL_LOCK_HANDLER,
+ OSL_NOTIFY_HANDLER,
+ OSL_GPE_HANDLER,
+ OSL_DEBUGGER_THREAD,
+ OSL_EC_POLL_HANDLER,
+ OSL_EC_BURST_HANDLER
+} acpi_execute_type;
#define ACPI_NO_UNIT_LIMIT ((u32) -1)
#define ACPI_MUTEX_SEM 1
@@ -161,13 +165,11 @@ acpi_os_remove_interrupt_handler(u32 gsi, acpi_osd_handler service_routine);
/*
* Threads and Scheduling
*/
-u32 acpi_os_get_thread_id(void);
+acpi_thread_id acpi_os_get_thread_id(void);
acpi_status
-acpi_os_queue_for_execution(u32 priority,
- acpi_osd_exec_callback function, void *context);
-
-void acpi_os_wait_events_complete(void *context);
+acpi_os_execute(acpi_execute_type type,
+ acpi_osd_exec_callback function, void *context);
void acpi_os_wait_events_complete(void *context);
@@ -214,6 +216,12 @@ acpi_os_derive_pci_id(acpi_handle rhandle,
/*
* Miscellaneous
*/
+acpi_status acpi_os_validate_interface(char *interface);
+
+acpi_status
+acpi_os_validate_address(u8 space_id,
+ acpi_physical_address address, acpi_size length);
+
u8 acpi_os_readable(void *pointer, acpi_size length);
#ifdef ACPI_FUTURE_USAGE
@@ -255,11 +263,4 @@ char *acpi_os_get_next_filename(void *dir_handle);
void acpi_os_close_directory(void *dir_handle);
-/*
- * Debug
- */
-void
-acpi_os_dbg_assert(void *failed_assertion,
- void *file_name, u32 line_number, char *message);
-
#endif /* __ACPIOSXF_H__ */
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 66cf2ec..049e9aa 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -268,7 +268,7 @@ acpi_status acpi_remove_gpe_block(acpi_handle gpe_device);
* Resource interfaces
*/
typedef
-acpi_status(*ACPI_WALK_RESOURCE_CALLBACK) (struct acpi_resource * resource,
+acpi_status(*acpi_walk_resource_callback) (struct acpi_resource * resource,
void *context);
acpi_status
@@ -290,7 +290,7 @@ acpi_get_possible_resources(acpi_handle device_handle,
acpi_status
acpi_walk_resources(acpi_handle device_handle,
char *name,
- ACPI_WALK_RESOURCE_CALLBACK user_function, void *context);
+ acpi_walk_resource_callback user_function, void *context);
acpi_status
acpi_set_current_resources(acpi_handle device_handle,
diff --git a/include/acpi/acresrc.h b/include/acpi/acresrc.h
index fa02e80..ad11fc1 100644
--- a/include/acpi/acresrc.h
+++ b/include/acpi/acresrc.h
@@ -164,23 +164,26 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
/*
* rsutils
*/
+
acpi_status
-acpi_rs_get_prt_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer);
+acpi_rs_get_prt_method_data(struct acpi_namespace_node *node,
+ struct acpi_buffer *ret_buffer);
acpi_status
-acpi_rs_get_crs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer);
+acpi_rs_get_crs_method_data(struct acpi_namespace_node *node,
+ struct acpi_buffer *ret_buffer);
-#ifdef ACPI_FUTURE_USAGE
acpi_status
-acpi_rs_get_prs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer);
-#endif /* ACPI_FUTURE_USAGE */
+acpi_rs_get_prs_method_data(struct acpi_namespace_node *node,
+ struct acpi_buffer *ret_buffer);
acpi_status
acpi_rs_get_method_data(acpi_handle handle,
char *path, struct acpi_buffer *ret_buffer);
acpi_status
-acpi_rs_set_srs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer);
+acpi_rs_set_srs_method_data(struct acpi_namespace_node *node,
+ struct acpi_buffer *ret_buffer);
/*
* rscalc
@@ -198,8 +201,9 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
acpi_size * buffer_size_needed);
acpi_status
-acpi_rs_convert_aml_to_resources(u8 * aml_buffer,
- u32 aml_buffer_length, u8 * output_buffer);
+acpi_rs_convert_aml_to_resources(u8 * aml,
+ u32 length,
+ u32 offset, u8 resource_index, void **context);
acpi_status
acpi_rs_convert_resources_to_aml(struct acpi_resource *resource,
diff --git a/include/acpi/acstruct.h b/include/acpi/acstruct.h
index d8c1c2c..5e8095f 100644
--- a/include/acpi/acstruct.h
+++ b/include/acpi/acstruct.h
@@ -44,6 +44,8 @@
#ifndef __ACSTRUCT_H__
#define __ACSTRUCT_H__
+/* acpisrc:struct_defs -- for acpisrc conversion */
+
/*****************************************************************************
*
* Tree walking typedefs and structs
@@ -51,67 +53,76 @@
****************************************************************************/
/*
- * Walk state - current state of a parse tree walk. Used for both a leisurely stroll through
- * the tree (for whatever reason), and for control method execution.
+ * Walk state - current state of a parse tree walk. Used for both a leisurely
+ * stroll through the tree (for whatever reason), and for control method
+ * execution.
*/
#define ACPI_NEXT_OP_DOWNWARD 1
#define ACPI_NEXT_OP_UPWARD 2
+/*
+ * Groups of definitions for walk_type used for different implementations of
+ * walkers (never simultaneously) - flags for interpreter:
+ */
#define ACPI_WALK_NON_METHOD 0
-#define ACPI_WALK_METHOD 1
-#define ACPI_WALK_METHOD_RESTART 2
-#define ACPI_WALK_CONST_REQUIRED 3
-#define ACPI_WALK_CONST_OPTIONAL 4
+#define ACPI_WALK_METHOD 0x01
+#define ACPI_WALK_METHOD_RESTART 0x02
+
+/* Flags for i_aSL compiler only */
+
+#define ACPI_WALK_CONST_REQUIRED 0x10
+#define ACPI_WALK_CONST_OPTIONAL 0x20
struct acpi_walk_state {
- u8 data_type; /* To differentiate various internal objs MUST BE FIRST! */
+ struct acpi_walk_state *next; /* Next walk_state in list */
+ u8 descriptor_type; /* To differentiate various internal objs */
u8 walk_type;
- acpi_owner_id owner_id; /* Owner of objects created during the walk */
- u8 last_predicate; /* Result of last predicate */
- u8 current_result; /* */
+ u16 opcode; /* Current AML opcode */
u8 next_op_info; /* Info about next_op */
u8 num_operands; /* Stack pointer for Operands[] array */
+ acpi_owner_id owner_id; /* Owner of objects created during the walk */
+ u8 last_predicate; /* Result of last predicate */
+ u8 current_result;
u8 return_used;
- u16 opcode; /* Current AML opcode */
u8 scope_depth;
u8 pass_number; /* Parse pass during table load */
- u32 arg_count; /* push for fixed or var args */
u32 aml_offset;
u32 arg_types;
u32 method_breakpoint; /* For single stepping */
u32 user_breakpoint; /* User AML breakpoint */
u32 parse_flags;
+
+ struct acpi_parse_state parser_state; /* Current state of parser */
u32 prev_arg_types;
+ u32 arg_count; /* push for fixed or var args */
- u8 *aml_last_while;
struct acpi_namespace_node arguments[ACPI_METHOD_NUM_ARGS]; /* Control method arguments */
+ struct acpi_namespace_node local_variables[ACPI_METHOD_NUM_LOCALS]; /* Control method locals */
+ union acpi_operand_object *operands[ACPI_OBJ_NUM_OPERANDS + 1]; /* Operands passed to the interpreter (+1 for NULL terminator) */
+ union acpi_operand_object **params;
+
+ u8 *aml_last_while;
union acpi_operand_object **caller_return_desc;
union acpi_generic_state *control_state; /* List of control states (nested IFs) */
struct acpi_namespace_node *deferred_node; /* Used when executing deferred opcodes */
struct acpi_gpe_event_info *gpe_event_info; /* Info for GPE (_Lxx/_Exx methods only */
union acpi_operand_object *implicit_return_obj;
- struct acpi_namespace_node local_variables[ACPI_METHOD_NUM_LOCALS]; /* Control method locals */
struct acpi_namespace_node *method_call_node; /* Called method Node */
union acpi_parse_object *method_call_op; /* method_call Op if running a method */
union acpi_operand_object *method_desc; /* Method descriptor if running a method */
struct acpi_namespace_node *method_node; /* Method node if running a method. */
union acpi_parse_object *op; /* Current parser op */
- union acpi_operand_object *operands[ACPI_OBJ_NUM_OPERANDS + 1]; /* Operands passed to the interpreter (+1 for NULL terminator) */
const struct acpi_opcode_info *op_info; /* Info on current opcode */
union acpi_parse_object *origin; /* Start of walk [Obsolete] */
- union acpi_operand_object **params;
- struct acpi_parse_state parser_state; /* Current state of parser */
union acpi_operand_object *result_obj;
union acpi_generic_state *results; /* Stack of accumulated results */
union acpi_operand_object *return_desc; /* Return object, if any */
union acpi_generic_state *scope_info; /* Stack of nested scopes */
-
union acpi_parse_object *prev_op; /* Last op that was processed */
union acpi_parse_object *next_op; /* next op to be processed */
+ struct acpi_thread_state *thread;
acpi_parse_downwards descending_callback;
acpi_parse_upwards ascending_callback;
- struct acpi_thread_state *thread;
- struct acpi_walk_state *next; /* Next walk_state in list */
};
/* Info used by acpi_ps_init_objects */
@@ -131,32 +142,6 @@ struct acpi_init_walk_info {
struct acpi_table_desc *table_desc;
};
-/* Info used by acpi_ns_initialize_devices */
-
-struct acpi_device_walk_info {
- u16 device_count;
- u16 num_STA;
- u16 num_INI;
- struct acpi_table_desc *table_desc;
-};
-
-/* TBD: [Restructure] Merge with struct above */
-
-struct acpi_walk_info {
- u32 debug_level;
- u32 count;
- acpi_owner_id owner_id;
- u8 display_type;
-};
-
-/* Display Types */
-
-#define ACPI_DISPLAY_SUMMARY (u8) 0
-#define ACPI_DISPLAY_OBJECTS (u8) 1
-#define ACPI_DISPLAY_MASK (u8) 1
-
-#define ACPI_DISPLAY_SHORT (u8) 2
-
struct acpi_get_devices_info {
acpi_walk_callback user_function;
void *context;
@@ -189,16 +174,21 @@ union acpi_aml_operands {
} mid;
};
-/* Internal method parameter list */
-
-struct acpi_parameter_info {
- struct acpi_namespace_node *node;
+/*
+ * Structure used to pass object evaluation parameters.
+ * Purpose is to reduce CPU stack use.
+ */
+struct acpi_evaluate_info {
+ struct acpi_namespace_node *prefix_node;
+ char *pathname;
union acpi_operand_object *obj_desc;
union acpi_operand_object **parameters;
+ struct acpi_namespace_node *resolved_node;
union acpi_operand_object *return_object;
u8 pass_number;
u8 parameter_type;
u8 return_object_type;
+ u8 flags;
};
/* Types for parameter_type above */
@@ -206,4 +196,35 @@ struct acpi_parameter_info {
#define ACPI_PARAM_ARGS 0
#define ACPI_PARAM_GPE 1
+/* Values for Flags above */
+
+#define ACPI_IGNORE_RETURN_VALUE 1
+
+/* Info used by acpi_ns_initialize_devices */
+
+struct acpi_device_walk_info {
+ u16 device_count;
+ u16 num_STA;
+ u16 num_INI;
+ struct acpi_table_desc *table_desc;
+ struct acpi_evaluate_info *evaluate_info;
+};
+
+/* TBD: [Restructure] Merge with struct above */
+
+struct acpi_walk_info {
+ u32 debug_level;
+ u32 count;
+ acpi_owner_id owner_id;
+ u8 display_type;
+};
+
+/* Display Types */
+
+#define ACPI_DISPLAY_SUMMARY (u8) 0
+#define ACPI_DISPLAY_OBJECTS (u8) 1
+#define ACPI_DISPLAY_MASK (u8) 1
+
+#define ACPI_DISPLAY_SHORT (u8) 2
+
#endif
diff --git a/include/acpi/actables.h b/include/acpi/actables.h
index 30a4754..4dbaf02 100644
--- a/include/acpi/actables.h
+++ b/include/acpi/actables.h
@@ -136,7 +136,11 @@ acpi_status acpi_tb_is_table_installed(struct acpi_table_desc *new_table_desc);
acpi_status
acpi_tb_verify_table_checksum(struct acpi_table_header *table_header);
-u8 acpi_tb_generate_checksum(void *buffer, u32 length);
+u8 acpi_tb_sum_table(void *buffer, u32 length);
+
+u8 acpi_tb_generate_checksum(struct acpi_table_header *table);
+
+void acpi_tb_set_checksum(struct acpi_table_header *table);
acpi_status
acpi_tb_validate_table_header(struct acpi_table_header *table_header);
diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h
index ed53f84..b125cee 100644
--- a/include/acpi/actbl.h
+++ b/include/acpi/actbl.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Name: actbl.h - Table data structures defined in ACPI specification
+ * Name: actbl.h - Basic ACPI Table Definitions
*
*****************************************************************************/
@@ -45,66 +45,45 @@
#define __ACTBL_H__
/*
- * Note about bitfields: The u8 type is used for bitfields in ACPI tables.
- * This is the only type that is even remotely portable. Anything else is not
- * portable, so do not use any other bitfield types.
- */
-
-/*
- * Values for description table header signatures
+ * Values for description table header signatures. Useful because they make
+ * it more difficult to inadvertently type in the wrong signature.
*/
-#define RSDP_NAME "RSDP"
-#define RSDP_SIG "RSD PTR " /* RSDT Pointer signature */
-#define APIC_SIG "APIC" /* Multiple APIC Description Table */
#define DSDT_SIG "DSDT" /* Differentiated System Description Table */
#define FADT_SIG "FACP" /* Fixed ACPI Description Table */
#define FACS_SIG "FACS" /* Firmware ACPI Control Structure */
#define PSDT_SIG "PSDT" /* Persistent System Description Table */
+#define RSDP_SIG "RSD PTR " /* Root System Description Pointer */
#define RSDT_SIG "RSDT" /* Root System Description Table */
#define XSDT_SIG "XSDT" /* Extended System Description Table */
#define SSDT_SIG "SSDT" /* Secondary System Description Table */
-#define SBST_SIG "SBST" /* Smart Battery Specification Table */
-#define SPIC_SIG "SPIC" /* IOSAPIC table */
-#define BOOT_SIG "BOOT" /* Boot table */
-
-#define GL_OWNED 0x02 /* Ownership of global lock is bit 1 */
+#define RSDP_NAME "RSDP"
/*
- * Common table types. The base code can remain
- * constant if the underlying tables are changed
+ * All tables and structures must be byte-packed to match the ACPI
+ * specification, since the tables are provided by the system BIOS
*/
-#define RSDT_DESCRIPTOR struct rsdt_descriptor_rev2
-#define XSDT_DESCRIPTOR struct xsdt_descriptor_rev2
-#define FACS_DESCRIPTOR struct facs_descriptor_rev2
-#define FADT_DESCRIPTOR struct fadt_descriptor_rev2
-
#pragma pack(1)
/*
- * ACPI Version-independent tables
+ * These are the ACPI tables that are directly consumed by the subsystem.
+ *
+ * The RSDP and FACS do not use the common ACPI table header. All other ACPI
+ * tables use the header.
*
- * NOTE: The tables that are specific to ACPI versions (1.0, 2.0, etc.)
- * are in separate files.
+ * Note about bitfields: The u8 type is used for bitfields in ACPI tables.
+ * This is the only type that is even remotely portable. Anything else is not
+ * portable, so do not use any other bitfield types.
*/
-struct rsdp_descriptor { /* Root System Descriptor Pointer */
- char signature[8]; /* ACPI signature, contains "RSD PTR " */
- u8 checksum; /* ACPI 1.0 checksum */
- char oem_id[6]; /* OEM identification */
- u8 revision; /* Must be (0) for ACPI 1.0 or (2) for ACPI 2.0+ */
- u32 rsdt_physical_address; /* 32-bit physical address of the RSDT */
- u32 length; /* XSDT Length in bytes, including header */
- u64 xsdt_physical_address; /* 64-bit physical address of the XSDT */
- u8 extended_checksum; /* Checksum of entire table (ACPI 2.0) */
- char reserved[3]; /* Reserved, must be zero */
-};
-struct acpi_common_facs { /* Common FACS for internal use */
- u32 *global_lock;
- u64 *firmware_waking_vector;
- u8 vector_width;
-};
+/*******************************************************************************
+ *
+ * ACPI Table Header. This common header is used by all tables except the
+ * RSDP and FACS. The define is used for direct inclusion of header into
+ * other ACPI tables
+ *
+ ******************************************************************************/
-#define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \
+#define ACPI_TABLE_HEADER_DEF \
char signature[4]; /* ASCII table signature */\
u32 length; /* Length of table in bytes, including this header */\
u8 revision; /* ACPI Specification minor version # */\
@@ -112,154 +91,239 @@ struct acpi_common_facs { /* Common FACS for internal use */
char oem_id[6]; /* ASCII OEM identification */\
char oem_table_id[8]; /* ASCII OEM table identification */\
u32 oem_revision; /* OEM revision number */\
- char asl_compiler_id [4]; /* ASCII ASL compiler vendor ID */\
+ char asl_compiler_id[4]; /* ASCII ASL compiler vendor ID */\
u32 asl_compiler_revision; /* ASL compiler version */
-struct acpi_table_header { /* ACPI common table header */
+struct acpi_table_header {
ACPI_TABLE_HEADER_DEF};
/*
- * MADT values and structures
+ * GAS - Generic Address Structure (ACPI 2.0+)
*/
+struct acpi_generic_address {
+ u8 address_space_id; /* Address space where struct or register exists */
+ u8 register_bit_width; /* Size in bits of given register */
+ u8 register_bit_offset; /* Bit offset within the register */
+ u8 access_width; /* Minimum Access size (ACPI 3.0) */
+ u64 address; /* 64-bit address of struct or register */
+};
-/* Values for MADT PCATCompat */
+/*******************************************************************************
+ *
+ * RSDP - Root System Description Pointer (Signature is "RSD PTR ")
+ *
+ ******************************************************************************/
+
+struct rsdp_descriptor {
+ char signature[8]; /* ACPI signature, contains "RSD PTR " */
+ u8 checksum; /* ACPI 1.0 checksum */
+ char oem_id[6]; /* OEM identification */
+ u8 revision; /* Must be (0) for ACPI 1.0 or (2) for ACPI 2.0+ */
+ u32 rsdt_physical_address; /* 32-bit physical address of the RSDT */
+ u32 length; /* Table length in bytes, including header (ACPI 2.0+) */
+ u64 xsdt_physical_address; /* 64-bit physical address of the XSDT (ACPI 2.0+) */
+ u8 extended_checksum; /* Checksum of entire table (ACPI 2.0+) */
+ u8 reserved[3]; /* Reserved, must be zero */
+};
-#define DUAL_PIC 0
-#define MULTIPLE_APIC 1
+#define ACPI_RSDP_REV0_SIZE 20 /* Size of original ACPI 1.0 RSDP */
-/* Master MADT */
+/*******************************************************************************
+ *
+ * RSDT/XSDT - Root System Description Tables
+ *
+ ******************************************************************************/
-struct multiple_apic_table {
- ACPI_TABLE_HEADER_DEF /* ACPI common table header */
- u32 local_apic_address; /* Physical address of local APIC */
+struct rsdt_descriptor {
+ ACPI_TABLE_HEADER_DEF u32 table_offset_entry[1]; /* Array of pointers to ACPI tables */
+};
+
+struct xsdt_descriptor {
+ ACPI_TABLE_HEADER_DEF u64 table_offset_entry[1]; /* Array of pointers to ACPI tables */
+};
+
+/*******************************************************************************
+ *
+ * FACS - Firmware ACPI Control Structure (FACS)
+ *
+ ******************************************************************************/
+
+struct facs_descriptor {
+ char signature[4]; /* ASCII table signature */
+ u32 length; /* Length of structure, in bytes */
+ u32 hardware_signature; /* Hardware configuration signature */
+ u32 firmware_waking_vector; /* 32-bit physical address of the Firmware Waking Vector */
+ u32 global_lock; /* Global Lock for shared hardware resources */
/* Flags (32 bits) */
- u8 PCATcompat:1; /* 00: System also has dual 8259s */
+ u8 S4bios_f:1; /* 00: S4BIOS support is present */
u8:7; /* 01-07: Reserved, must be zero */
u8 reserved1[3]; /* 08-31: Reserved, must be zero */
-};
-/* Values for Type in APIC_HEADER_DEF */
+ u64 xfirmware_waking_vector; /* 64-bit version of the Firmware Waking Vector (ACPI 2.0+) */
+ u8 version; /* Version of this table (ACPI 2.0+) */
+ u8 reserved[31]; /* Reserved, must be zero */
+};
-#define APIC_PROCESSOR 0
-#define APIC_IO 1
-#define APIC_XRUPT_OVERRIDE 2
-#define APIC_NMI 3
-#define APIC_LOCAL_NMI 4
-#define APIC_ADDRESS_OVERRIDE 5
-#define APIC_IO_SAPIC 6
-#define APIC_LOCAL_SAPIC 7
-#define APIC_XRUPT_SOURCE 8
-#define APIC_RESERVED 9 /* 9 and greater are reserved */
+#define ACPI_GLOCK_PENDING 0x01 /* 00: Pending global lock ownership */
+#define ACPI_GLOCK_OWNED 0x02 /* 01: Global lock is owned */
/*
- * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE)
+ * Common FACS - This is a version-independent FACS structure used for internal use only
*/
-#define APIC_HEADER_DEF /* Common APIC sub-structure header */\
- u8 type; \
- u8 length;
-
-struct apic_header {
-APIC_HEADER_DEF};
-
-/* Values for MPS INTI flags */
-
-#define POLARITY_CONFORMS 0
-#define POLARITY_ACTIVE_HIGH 1
-#define POLARITY_RESERVED 2
-#define POLARITY_ACTIVE_LOW 3
-
-#define TRIGGER_CONFORMS 0
-#define TRIGGER_EDGE 1
-#define TRIGGER_RESERVED 2
-#define TRIGGER_LEVEL 3
-
-/* Common flag definitions (16 bits each) */
-
-#define MPS_INTI_FLAGS \
- u8 polarity : 2; /* 00-01: Polarity of APIC I/O input signals */\
- u8 trigger_mode : 2; /* 02-03: Trigger mode of APIC input signals */\
- u8 : 4; /* 04-07: Reserved, must be zero */\
- u8 reserved1; /* 08-15: Reserved, must be zero */
-
-#define LOCAL_APIC_FLAGS \
- u8 processor_enabled: 1; /* 00: Processor is usable if set */\
- u8 : 7; /* 01-07: Reserved, must be zero */\
- u8 reserved2; /* 08-15: Reserved, must be zero */
-
-/* Sub-structures for MADT */
-
-struct madt_processor_apic {
- APIC_HEADER_DEF u8 processor_id; /* ACPI processor id */
- u8 local_apic_id; /* Processor's local APIC id */
- LOCAL_APIC_FLAGS};
-
-struct madt_io_apic {
- APIC_HEADER_DEF u8 io_apic_id; /* I/O APIC ID */
- u8 reserved; /* Reserved - must be zero */
- u32 address; /* APIC physical address */
- u32 interrupt; /* Global system interrupt where INTI
- * lines start */
+struct acpi_common_facs {
+ u32 *global_lock;
+ u64 *firmware_waking_vector;
+ u8 vector_width;
};
-struct madt_interrupt_override {
- APIC_HEADER_DEF u8 bus; /* 0 - ISA */
- u8 source; /* Interrupt source (IRQ) */
- u32 interrupt; /* Global system interrupt */
- MPS_INTI_FLAGS};
+/*******************************************************************************
+ *
+ * FADT - Fixed ACPI Description Table (Signature "FACP")
+ *
+ ******************************************************************************/
+
+/* Fields common to all versions of the FADT */
+
+#define ACPI_FADT_COMMON \
+ ACPI_TABLE_HEADER_DEF \
+ u32 V1_firmware_ctrl; /* 32-bit physical address of FACS */ \
+ u32 V1_dsdt; /* 32-bit physical address of DSDT */ \
+ u8 reserved1; /* System Interrupt Model isn't used in ACPI 2.0*/ \
+ u8 prefer_PM_profile; /* Conveys preferred power management profile to OSPM. */ \
+ u16 sci_int; /* System vector of SCI interrupt */ \
+ u32 smi_cmd; /* Port address of SMI command port */ \
+ u8 acpi_enable; /* Value to write to smi_cmd to enable ACPI */ \
+ u8 acpi_disable; /* Value to write to smi_cmd to disable ACPI */ \
+ u8 S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ \
+ u8 pstate_cnt; /* Processor performance state control*/ \
+ u32 V1_pm1a_evt_blk; /* Port address of Power Mgt 1a Event Reg Blk */ \
+ u32 V1_pm1b_evt_blk; /* Port address of Power Mgt 1b Event Reg Blk */ \
+ u32 V1_pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ \
+ u32 V1_pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ \
+ u32 V1_pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ \
+ u32 V1_pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ \
+ u32 V1_gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ \
+ u32 V1_gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ \
+ u8 pm1_evt_len; /* Byte Length of ports at pm1_x_evt_blk */ \
+ u8 pm1_cnt_len; /* Byte Length of ports at pm1_x_cnt_blk */ \
+ u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ \
+ u8 pm_tm_len; /* Byte Length of ports at pm_tm_blk */ \
+ u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ \
+ u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ \
+ u8 gpe1_base; /* Offset in gpe model where gpe1 events start */ \
+ u8 cst_cnt; /* Support for the _CST object and C States change notification.*/ \
+ u16 plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ \
+ u16 plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ \
+ u16 flush_size; /* Processor's memory cache line width, in bytes */ \
+ u16 flush_stride; /* Number of flush strides that need to be read */ \
+ u8 duty_offset; /* Processor's duty cycle index in processor's P_CNT reg*/ \
+ u8 duty_width; /* Processor's duty cycle value bit width in P_CNT register.*/ \
+ u8 day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ \
+ u8 mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ \
+ u8 century; /* Index to century in RTC CMOS RAM */ \
+ u16 iapc_boot_arch; /* IA-PC Boot Architecture Flags. See Table 5-10 for description*/ \
+ u8 reserved2; /* Reserved, must be zero */
-struct madt_nmi_source {
- APIC_HEADER_DEF MPS_INTI_FLAGS u32 interrupt; /* Global system interrupt */
+/*
+ * ACPI 2.0+ FADT
+ */
+struct fadt_descriptor {
+ ACPI_FADT_COMMON
+ /* Flags (32 bits) */
+ u8 wb_invd:1; /* 00: The wbinvd instruction works properly */
+ u8 wb_invd_flush:1; /* 01: The wbinvd flushes but does not invalidate */
+ u8 proc_c1:1; /* 02: All processors support C1 state */
+ u8 plvl2_up:1; /* 03: C2 state works on MP system */
+ u8 pwr_button:1; /* 04: Power button is handled as a generic feature */
+ u8 sleep_button:1; /* 05: Sleep button is handled as a generic feature, or not present */
+ u8 fixed_rTC:1; /* 06: RTC wakeup stat not in fixed register space */
+ u8 rtcs4:1; /* 07: RTC wakeup stat not possible from S4 */
+ u8 tmr_val_ext:1; /* 08: tmr_val is 32 bits 0=24-bits */
+ u8 dock_cap:1; /* 09: Docking supported */
+ u8 reset_reg_sup:1; /* 10: System reset via the FADT RESET_REG supported */
+ u8 sealed_case:1; /* 11: No internal expansion capabilities and case is sealed */
+ u8 headless:1; /* 12: No local video capabilities or local input devices */
+ u8 cpu_sw_sleep:1; /* 13: Must execute native instruction after writing SLP_TYPx register */
+
+ u8 pci_exp_wak:1; /* 14: System supports PCIEXP_WAKE (STS/EN) bits (ACPI 3.0) */
+ u8 use_platform_clock:1; /* 15: OSPM should use platform-provided timer (ACPI 3.0) */
+ u8 S4rtc_sts_valid:1; /* 16: Contents of RTC_STS valid after S4 wake (ACPI 3.0) */
+ u8 remote_power_on_capable:1; /* 17: System is compatible with remote power on (ACPI 3.0) */
+ u8 force_apic_cluster_model:1; /* 18: All local APICs must use cluster model (ACPI 3.0) */
+ u8 force_apic_physical_destination_mode:1; /* 19: All local x_aPICs must use physical dest mode (ACPI 3.0) */
+ u8:4; /* 20-23: Reserved, must be zero */
+ u8 reserved3; /* 24-31: Reserved, must be zero */
+
+ struct acpi_generic_address reset_register; /* Reset register address in GAS format */
+ u8 reset_value; /* Value to write to the reset_register port to reset the system */
+ u8 reserved4[3]; /* These three bytes must be zero */
+ u64 xfirmware_ctrl; /* 64-bit physical address of FACS */
+ u64 Xdsdt; /* 64-bit physical address of DSDT */
+ struct acpi_generic_address xpm1a_evt_blk; /* Extended Power Mgt 1a acpi_event Reg Blk address */
+ struct acpi_generic_address xpm1b_evt_blk; /* Extended Power Mgt 1b acpi_event Reg Blk address */
+ struct acpi_generic_address xpm1a_cnt_blk; /* Extended Power Mgt 1a Control Reg Blk address */
+ struct acpi_generic_address xpm1b_cnt_blk; /* Extended Power Mgt 1b Control Reg Blk address */
+ struct acpi_generic_address xpm2_cnt_blk; /* Extended Power Mgt 2 Control Reg Blk address */
+ struct acpi_generic_address xpm_tmr_blk; /* Extended Power Mgt Timer Ctrl Reg Blk address */
+ struct acpi_generic_address xgpe0_blk; /* Extended General Purpose acpi_event 0 Reg Blk address */
+ struct acpi_generic_address xgpe1_blk; /* Extended General Purpose acpi_event 1 Reg Blk address */
};
-struct madt_local_apic_nmi {
- APIC_HEADER_DEF u8 processor_id; /* ACPI processor id */
- MPS_INTI_FLAGS u8 lint; /* LINTn to which NMI is connected */
+/*
+ * "Down-revved" ACPI 2.0 FADT descriptor
+ * Defined here to allow compiler to generate the length of the struct
+ */
+struct fadt_descriptor_rev2_minus {
+ ACPI_FADT_COMMON u32 flags;
+ struct acpi_generic_address reset_register; /* Reset register address in GAS format */
+ u8 reset_value; /* Value to write to the reset_register port to reset the system. */
+ u8 reserved7[3]; /* Reserved, must be zero */
};
-struct madt_address_override {
- APIC_HEADER_DEF u16 reserved; /* Reserved, must be zero */
- u64 address; /* APIC physical address */
+/*
+ * ACPI 1.0 FADT
+ * Defined here to allow compiler to generate the length of the struct
+ */
+struct fadt_descriptor_rev1 {
+ ACPI_FADT_COMMON u32 flags;
};
-struct madt_io_sapic {
- APIC_HEADER_DEF u8 io_sapic_id; /* I/O SAPIC ID */
- u8 reserved; /* Reserved, must be zero */
- u32 interrupt_base; /* Glocal interrupt for SAPIC start */
- u64 address; /* SAPIC physical address */
-};
+/* FADT: Prefered Power Management Profiles */
-struct madt_local_sapic {
- APIC_HEADER_DEF u8 processor_id; /* ACPI processor id */
- u8 local_sapic_id; /* SAPIC ID */
- u8 local_sapic_eid; /* SAPIC EID */
- u8 reserved[3]; /* Reserved, must be zero */
- LOCAL_APIC_FLAGS u32 processor_uID; /* Numeric UID - ACPI 3.0 */
- char processor_uIDstring[1]; /* String UID - ACPI 3.0 */
-};
+#define PM_UNSPECIFIED 0
+#define PM_DESKTOP 1
+#define PM_MOBILE 2
+#define PM_WORKSTATION 3
+#define PM_ENTERPRISE_SERVER 4
+#define PM_SOHO_SERVER 5
+#define PM_APPLIANCE_PC 6
-struct madt_interrupt_source {
- APIC_HEADER_DEF MPS_INTI_FLAGS u8 interrupt_type; /* 1=PMI, 2=INIT, 3=corrected */
- u8 processor_id; /* Processor ID */
- u8 processor_eid; /* Processor EID */
- u8 io_sapic_vector; /* Vector value for PMI interrupts */
- u32 interrupt; /* Global system interrupt */
- u32 flags; /* Interrupt Source Flags */
-};
+/* FADT: Boot Arch Flags */
-/*
- * Smart Battery
- */
-struct smart_battery_table {
- ACPI_TABLE_HEADER_DEF u32 warning_level;
- u32 low_level;
- u32 critical_level;
-};
+#define BAF_LEGACY_DEVICES 0x0001
+#define BAF_8042_KEYBOARD_CONTROLLER 0x0002
+
+#define FADT2_REVISION_ID 3
+#define FADT2_MINUS_REVISION_ID 2
+
+/* Reset to default packing */
#pragma pack()
/*
+ * This macro is temporary until the table bitfield flag definitions
+ * are removed and replaced by a Flags field.
+ */
+#define ACPI_FLAG_OFFSET(d,f,o) (u8) (ACPI_OFFSET (d,f) + \
+ sizeof(((d *)0)->f) + o)
+/*
+ * Get the remaining ACPI tables
+ */
+#include "actbl1.h"
+
+/*
* ACPI Table information. We save the table address, length,
* and type of memory allocation (mapped or allocated) for each
* table for 1) when we exit, and 2) if a new table is installed
@@ -290,27 +354,17 @@ struct acpi_table_support {
u8 flags;
};
-/*
- * Get the ACPI version-specific tables
- */
-#include "actbl1.h" /* Acpi 1.0 table definitions */
-#include "actbl2.h" /* Acpi 2.0 table definitions */
-
extern u8 acpi_fadt_is_v1; /* is set to 1 if FADT is revision 1,
* needed for certain workarounds */
+/* Macros used to generate offsets to specific table fields */
-#pragma pack(1)
-/*
- * High performance timer
- */
-struct hpet_table {
- ACPI_TABLE_HEADER_DEF u32 hardware_id;
- struct acpi_generic_address base_address;
- u8 hpet_number;
- u16 clock_tick;
- u8 attributes;
-};
+#define ACPI_FACS_OFFSET(f) (u8) ACPI_OFFSET (struct facs_descriptor,f)
+#define ACPI_FADT_OFFSET(f) (u8) ACPI_OFFSET (struct fadt_descriptor, f)
+#define ACPI_GAS_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_generic_address,f)
+#define ACPI_HDR_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_header,f)
+#define ACPI_RSDP_OFFSET(f) (u8) ACPI_OFFSET (struct rsdp_descriptor,f)
-#pragma pack()
+#define ACPI_FADT_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct fadt_descriptor,f,o)
+#define ACPI_FACS_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct facs_descriptor,f,o)
#endif /* __ACTBL_H__ */
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
index cd428d5..745a644 100644
--- a/include/acpi/actbl1.h
+++ b/include/acpi/actbl1.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Name: actbl1.h - ACPI 1.0 tables
+ * Name: actbl1.h - Additional ACPI table definitions
*
*****************************************************************************/
@@ -44,92 +44,599 @@
#ifndef __ACTBL1_H__
#define __ACTBL1_H__
+/*******************************************************************************
+ *
+ * Additional ACPI Tables
+ *
+ * These tables are not consumed directly by the ACPICA subsystem, but are
+ * included here to support device drivers and the AML disassembler.
+ *
+ ******************************************************************************/
+
+/*
+ * Values for description table header signatures. Useful because they make
+ * it more difficult to inadvertently type in the wrong signature.
+ */
+#define ACPI_SIG_ASF "ASF!" /* Alert Standard Format table */
+#define ACPI_SIG_BOOT "BOOT" /* Simple Boot Flag Table */
+#define ACPI_SIG_CPEP "CPEP" /* Corrected Platform Error Polling table */
+#define ACPI_SIG_DBGP "DBGP" /* Debug Port table */
+#define ACPI_SIG_ECDT "ECDT" /* Embedded Controller Boot Resources Table */
+#define ACPI_SIG_HPET "HPET" /* High Precision Event Timer table */
+#define ACPI_SIG_MADT "APIC" /* Multiple APIC Description Table */
+#define ACPI_SIG_MCFG "MCFG" /* PCI Memory Mapped Configuration table */
+#define ACPI_SIG_SBST "SBST" /* Smart Battery Specification Table */
+#define ACPI_SIG_SLIT "SLIT" /* System Locality Distance Information Table */
+#define ACPI_SIG_SPCR "SPCR" /* Serial Port Console Redirection table */
+#define ACPI_SIG_SPMI "SPMI" /* Server Platform Management Interface table */
+#define ACPI_SIG_SRAT "SRAT" /* System Resource Affinity Table */
+#define ACPI_SIG_TCPA "TCPA" /* Trusted Computing Platform Alliance table */
+#define ACPI_SIG_WDRT "WDRT" /* Watchdog Resource Table */
+
+/* Legacy names */
+
+#define APIC_SIG "APIC" /* Multiple APIC Description Table */
+#define BOOT_SIG "BOOT" /* Simple Boot Flag Table */
+#define SBST_SIG "SBST" /* Smart Battery Specification Table */
+
+/*
+ * All tables must be byte-packed to match the ACPI specification, since
+ * the tables are provided by the system BIOS.
+ */
#pragma pack(1)
/*
- * ACPI 1.0 Root System Description Table (RSDT)
+ * Note about bitfields: The u8 type is used for bitfields in ACPI tables.
+ * This is the only type that is even remotely portable. Anything else is not
+ * portable, so do not use any other bitfield types.
*/
-struct rsdt_descriptor_rev1 {
- ACPI_TABLE_HEADER_DEF /* ACPI common table header */
- u32 table_offset_entry[1]; /* Array of pointers to ACPI tables */
-};
+
+/*******************************************************************************
+ *
+ * ASF - Alert Standard Format table (Signature "ASF!")
+ *
+ ******************************************************************************/
+
+struct acpi_table_asf {
+ACPI_TABLE_HEADER_DEF};
+
+#define ACPI_ASF_HEADER_DEF \
+ u8 type; \
+ u8 reserved; \
+ u16 length;
+
+struct acpi_asf_header {
+ACPI_ASF_HEADER_DEF};
+
+/* Values for Type field */
+
+#define ASF_INFO 0
+#define ASF_ALERT 1
+#define ASF_CONTROL 2
+#define ASF_BOOT 3
+#define ASF_ADDRESS 4
+#define ASF_RESERVED 5
/*
- * ACPI 1.0 Firmware ACPI Control Structure (FACS)
+ * ASF subtables
*/
-struct facs_descriptor_rev1 {
- char signature[4]; /* ASCII table signature */
- u32 length; /* Length of structure in bytes */
- u32 hardware_signature; /* Hardware configuration signature */
- u32 firmware_waking_vector; /* ACPI OS waking vector */
- u32 global_lock; /* Global Lock */
+
+/* 0: ASF Information */
+
+struct acpi_asf_info {
+ ACPI_ASF_HEADER_DEF u8 min_reset_value;
+ u8 min_poll_interval;
+ u16 system_id;
+ u32 mfg_id;
+ u8 flags;
+ u8 reserved2[3];
+};
+
+/* 1: ASF Alerts */
+
+struct acpi_asf_alert {
+ ACPI_ASF_HEADER_DEF u8 assert_mask;
+ u8 deassert_mask;
+ u8 alerts;
+ u8 data_length;
+ u8 array[1];
+};
+
+/* 2: ASF Remote Control */
+
+struct acpi_asf_remote {
+ ACPI_ASF_HEADER_DEF u8 controls;
+ u8 data_length;
+ u16 reserved2;
+ u8 array[1];
+};
+
+/* 3: ASF RMCP Boot Options */
+
+struct acpi_asf_rmcp {
+ ACPI_ASF_HEADER_DEF u8 capabilities[7];
+ u8 completion_code;
+ u32 enterprise_id;
+ u8 command;
+ u16 parameter;
+ u16 boot_options;
+ u16 oem_parameters;
+};
+
+/* 4: ASF Address */
+
+struct acpi_asf_address {
+ ACPI_ASF_HEADER_DEF u8 eprom_address;
+ u8 devices;
+ u8 smbus_addresses[1];
+};
+
+/*******************************************************************************
+ *
+ * BOOT - Simple Boot Flag Table
+ *
+ ******************************************************************************/
+
+struct acpi_table_boot {
+ ACPI_TABLE_HEADER_DEF u8 cmos_index; /* Index in CMOS RAM for the boot register */
+ u8 reserved[3];
+};
+
+/*******************************************************************************
+ *
+ * CPEP - Corrected Platform Error Polling table
+ *
+ ******************************************************************************/
+
+struct acpi_table_cpep {
+ ACPI_TABLE_HEADER_DEF u64 reserved;
+};
+
+/* Subtable */
+
+struct acpi_cpep_polling {
+ u8 type;
+ u8 length;
+ u8 processor_id; /* Processor ID */
+ u8 processor_eid; /* Processor EID */
+ u32 polling_interval; /* Polling interval (msec) */
+};
+
+/*******************************************************************************
+ *
+ * DBGP - Debug Port table
+ *
+ ******************************************************************************/
+
+struct acpi_table_dbgp {
+ ACPI_TABLE_HEADER_DEF u8 interface_type; /* 0=full 16550, 1=subset of 16550 */
+ u8 reserved[3];
+ struct acpi_generic_address debug_port;
+};
+
+/*******************************************************************************
+ *
+ * ECDT - Embedded Controller Boot Resources Table
+ *
+ ******************************************************************************/
+
+struct ec_boot_resources {
+ ACPI_TABLE_HEADER_DEF struct acpi_generic_address ec_control; /* Address of EC command/status register */
+ struct acpi_generic_address ec_data; /* Address of EC data register */
+ u32 uid; /* Unique ID - must be same as the EC _UID method */
+ u8 gpe_bit; /* The GPE for the EC */
+ u8 ec_id[1]; /* Full namepath of the EC in the ACPI namespace */
+};
+
+/*******************************************************************************
+ *
+ * HPET - High Precision Event Timer table
+ *
+ ******************************************************************************/
+
+struct acpi_hpet_table {
+ ACPI_TABLE_HEADER_DEF u32 hardware_id; /* Hardware ID of event timer block */
+ struct acpi_generic_address base_address; /* Address of event timer block */
+ u8 hpet_number; /* HPET sequence number */
+ u16 clock_tick; /* Main counter min tick, periodic mode */
+ u8 attributes;
+};
+
+#if 0 /* HPET flags to be converted to macros */
+struct { /* Flags (8 bits) */
+ u8 page_protect:1; /* 00: No page protection */
+ u8 page_protect4:1; /* 01: 4_kB page protected */
+ u8 page_protect64:1; /* 02: 64_kB page protected */
+ u8:5; /* 03-07: Reserved, must be zero */
+} flags;
+#endif
+
+/*******************************************************************************
+ *
+ * MADT - Multiple APIC Description Table
+ *
+ ******************************************************************************/
+
+struct multiple_apic_table {
+ ACPI_TABLE_HEADER_DEF u32 local_apic_address; /* Physical address of local APIC */
/* Flags (32 bits) */
- u8 S4bios_f:1; /* 00: S4BIOS support is present */
+ u8 PCATcompat:1; /* 00: System also has dual 8259s */
u8:7; /* 01-07: Reserved, must be zero */
u8 reserved1[3]; /* 08-31: Reserved, must be zero */
-
- u8 reserved2[40]; /* Reserved, must be zero */
};
+/* Values for MADT PCATCompat */
+
+#define DUAL_PIC 0
+#define MULTIPLE_APIC 1
+
+/* Common MADT Sub-table header */
+
+#define APIC_HEADER_DEF \
+ u8 type; \
+ u8 length;
+
+struct apic_header {
+APIC_HEADER_DEF};
+
+/* Values for Type in struct apic_header */
+
+#define APIC_PROCESSOR 0
+#define APIC_IO 1
+#define APIC_XRUPT_OVERRIDE 2
+#define APIC_NMI 3
+#define APIC_LOCAL_NMI 4
+#define APIC_ADDRESS_OVERRIDE 5
+#define APIC_IO_SAPIC 6
+#define APIC_LOCAL_SAPIC 7
+#define APIC_XRUPT_SOURCE 8
+#define APIC_RESERVED 9 /* 9 and greater are reserved */
+
+/* Flag definitions for MADT sub-tables */
+
+#define ACPI_MADT_IFLAGS /* INTI flags (16 bits) */ \
+ u8 polarity : 2; /* 00-01: Polarity of APIC I/O input signals */\
+ u8 trigger_mode : 2; /* 02-03: Trigger mode of APIC input signals */\
+ u8 : 4; /* 04-07: Reserved, must be zero */\
+ u8 reserved1; /* 08-15: Reserved, must be zero */
+
+#define ACPI_MADT_LFLAGS /* Local Sapic flags (32 bits) */ \
+ u8 processor_enabled: 1; /* 00: Processor is usable if set */\
+ u8 : 7; /* 01-07: Reserved, must be zero */\
+ u8 reserved2[3]; /* 08-31: Reserved, must be zero */
+
+/* Values for MPS INTI flags */
+
+#define POLARITY_CONFORMS 0
+#define POLARITY_ACTIVE_HIGH 1
+#define POLARITY_RESERVED 2
+#define POLARITY_ACTIVE_LOW 3
+
+#define TRIGGER_CONFORMS 0
+#define TRIGGER_EDGE 1
+#define TRIGGER_RESERVED 2
+#define TRIGGER_LEVEL 3
+
/*
- * ACPI 1.0 Fixed ACPI Description Table (FADT)
+ * MADT Sub-tables, correspond to Type in struct apic_header
*/
-struct fadt_descriptor_rev1 {
- ACPI_TABLE_HEADER_DEF /* ACPI common table header */
- u32 firmware_ctrl; /* Physical address of FACS */
- u32 dsdt; /* Physical address of DSDT */
- u8 model; /* System Interrupt Model */
- u8 reserved1; /* Reserved, must be zero */
- u16 sci_int; /* System vector of SCI interrupt */
- u32 smi_cmd; /* Port address of SMI command port */
- u8 acpi_enable; /* Value to write to smi_cmd to enable ACPI */
- u8 acpi_disable; /* Value to write to smi_cmd to disable ACPI */
- u8 S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */
- u8 reserved2; /* Reserved, must be zero */
- u32 pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */
- u32 pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */
- u32 pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */
- u32 pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */
- u32 pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */
- u32 pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */
- u32 gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */
- u32 gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */
- u8 pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */
- u8 pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */
- u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */
- u8 pm_tm_len; /* Byte Length of ports at pm_tm_blk */
- u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */
- u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */
- u8 gpe1_base; /* Offset in gpe model where gpe1 events start */
- u8 reserved3; /* Reserved, must be zero */
- u16 plvl2_lat; /* Worst case HW latency to enter/exit C2 state */
- u16 plvl3_lat; /* Worst case HW latency to enter/exit C3 state */
- u16 flush_size; /* Size of area read to flush caches */
- u16 flush_stride; /* Stride used in flushing caches */
- u8 duty_offset; /* Bit location of duty cycle field in p_cnt reg */
- u8 duty_width; /* Bit width of duty cycle field in p_cnt reg */
- u8 day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */
- u8 mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */
- u8 century; /* Index to century in RTC CMOS RAM */
- u8 reserved4[3]; /* Reserved, must be zero */
+
+/* 0: processor APIC */
+
+struct madt_processor_apic {
+ APIC_HEADER_DEF u8 processor_id; /* ACPI processor id */
+ u8 local_apic_id; /* Processor's local APIC id */
+ ACPI_MADT_LFLAGS};
+
+/* 1: IO APIC */
+
+struct madt_io_apic {
+ APIC_HEADER_DEF u8 io_apic_id; /* I/O APIC ID */
+ u8 reserved; /* Reserved - must be zero */
+ u32 address; /* APIC physical address */
+ u32 interrupt; /* Global system interrupt where INTI lines start */
+};
+
+/* 2: Interrupt Override */
+
+struct madt_interrupt_override {
+ APIC_HEADER_DEF u8 bus; /* 0 - ISA */
+ u8 source; /* Interrupt source (IRQ) */
+ u32 interrupt; /* Global system interrupt */
+ ACPI_MADT_IFLAGS};
+
+/* 3: NMI Sources */
+
+struct madt_nmi_source {
+ APIC_HEADER_DEF ACPI_MADT_IFLAGS u32 interrupt; /* Global system interrupt */
+};
+
+/* 4: Local APIC NMI */
+
+struct madt_local_apic_nmi {
+ APIC_HEADER_DEF u8 processor_id; /* ACPI processor id */
+ ACPI_MADT_IFLAGS u8 lint; /* LINTn to which NMI is connected */
+};
+
+/* 5: Address Override */
+
+struct madt_address_override {
+ APIC_HEADER_DEF u16 reserved; /* Reserved, must be zero */
+ u64 address; /* APIC physical address */
+};
+
+/* 6: I/O Sapic */
+
+struct madt_io_sapic {
+ APIC_HEADER_DEF u8 io_sapic_id; /* I/O SAPIC ID */
+ u8 reserved; /* Reserved, must be zero */
+ u32 interrupt_base; /* Glocal interrupt for SAPIC start */
+ u64 address; /* SAPIC physical address */
+};
+
+/* 7: Local Sapic */
+
+struct madt_local_sapic {
+ APIC_HEADER_DEF u8 processor_id; /* ACPI processor id */
+ u8 local_sapic_id; /* SAPIC ID */
+ u8 local_sapic_eid; /* SAPIC EID */
+ u8 reserved[3]; /* Reserved, must be zero */
+ ACPI_MADT_LFLAGS u32 processor_uID; /* Numeric UID - ACPI 3.0 */
+ char processor_uIDstring[1]; /* String UID - ACPI 3.0 */
+};
+
+/* 8: Platform Interrupt Source */
+
+struct madt_interrupt_source {
+ APIC_HEADER_DEF ACPI_MADT_IFLAGS u8 interrupt_type; /* 1=PMI, 2=INIT, 3=corrected */
+ u8 processor_id; /* Processor ID */
+ u8 processor_eid; /* Processor EID */
+ u8 io_sapic_vector; /* Vector value for PMI interrupts */
+ u32 interrupt; /* Global system interrupt */
+ u32 flags; /* Interrupt Source Flags */
+};
+
+#ifdef DUPLICATE_DEFINITION_WITH_LINUX_ACPI_H
+/*******************************************************************************
+ *
+ * MCFG - PCI Memory Mapped Configuration table and sub-table
+ *
+ ******************************************************************************/
+
+struct acpi_table_mcfg {
+ ACPI_TABLE_HEADER_DEF u8 reserved[8];
+};
+
+struct acpi_mcfg_allocation {
+ u64 base_address; /* Base address, processor-relative */
+ u16 pci_segment; /* PCI segment group number */
+ u8 start_bus_number; /* Starting PCI Bus number */
+ u8 end_bus_number; /* Final PCI Bus number */
+ u32 reserved;
+};
+#endif
+
+/*******************************************************************************
+ *
+ * SBST - Smart Battery Specification Table
+ *
+ ******************************************************************************/
+
+struct smart_battery_table {
+ ACPI_TABLE_HEADER_DEF u32 warning_level;
+ u32 low_level;
+ u32 critical_level;
+};
+
+/*******************************************************************************
+ *
+ * SLIT - System Locality Distance Information Table
+ *
+ ******************************************************************************/
+
+struct system_locality_info {
+ ACPI_TABLE_HEADER_DEF u64 locality_count;
+ u8 entry[1][1];
+};
+
+/*******************************************************************************
+ *
+ * SPCR - Serial Port Console Redirection table
+ *
+ ******************************************************************************/
+
+struct acpi_table_spcr {
+ ACPI_TABLE_HEADER_DEF u8 interface_type; /* 0=full 16550, 1=subset of 16550 */
+ u8 reserved[3];
+ struct acpi_generic_address serial_port;
+ u8 interrupt_type;
+ u8 pc_interrupt;
+ u32 interrupt;
+ u8 baud_rate;
+ u8 parity;
+ u8 stop_bits;
+ u8 flow_control;
+ u8 terminal_type;
+ u8 reserved2;
+ u16 pci_device_id;
+ u16 pci_vendor_id;
+ u8 pci_bus;
+ u8 pci_device;
+ u8 pci_function;
+ u32 pci_flags;
+ u8 pci_segment;
+ u32 reserved3;
+};
+
+/*******************************************************************************
+ *
+ * SPMI - Server Platform Management Interface table
+ *
+ ******************************************************************************/
+
+struct acpi_table_spmi {
+ ACPI_TABLE_HEADER_DEF u8 reserved;
+ u8 interface_type;
+ u16 spec_revision; /* Version of IPMI */
+ u8 interrupt_type;
+ u8 gpe_number; /* GPE assigned */
+ u8 reserved2;
+ u8 pci_device_flag;
+ u32 interrupt;
+ struct acpi_generic_address ipmi_register;
+ u8 pci_segment;
+ u8 pci_bus;
+ u8 pci_device;
+ u8 pci_function;
+};
+
+/*******************************************************************************
+ *
+ * SRAT - System Resource Affinity Table
+ *
+ ******************************************************************************/
+
+struct system_resource_affinity {
+ ACPI_TABLE_HEADER_DEF u32 reserved1; /* Must be value '1' */
+ u64 reserved2; /* Reserved, must be zero */
+};
+
+/* SRAT common sub-table header */
+
+#define SRAT_SUBTABLE_HEADER \
+ u8 type; \
+ u8 length;
+
+/* Values for Type above */
+
+#define SRAT_CPU_AFFINITY 0
+#define SRAT_MEMORY_AFFINITY 1
+#define SRAT_RESERVED 2
+
+/* SRAT sub-tables */
+
+struct static_resource_alloc {
+ SRAT_SUBTABLE_HEADER u8 proximity_domain_lo;
+ u8 apic_id;
+
+ /* Flags (32 bits) */
+
+ u8 enabled:1; /* 00: Use affinity structure */
+ u8:7; /* 01-07: Reserved, must be zero */
+ u8 reserved3[3]; /* 08-31: Reserved, must be zero */
+
+ u8 local_sapic_eid;
+ u8 proximity_domain_hi[3];
+ u32 reserved4; /* Reserved, must be zero */
+};
+
+struct memory_affinity {
+ SRAT_SUBTABLE_HEADER u32 proximity_domain;
+ u16 reserved3;
+ u64 base_address;
+ u64 address_length;
+ u32 reserved4;
/* Flags (32 bits) */
- u8 wb_invd:1; /* 00: The wbinvd instruction works properly */
- u8 wb_invd_flush:1; /* 01: The wbinvd flushes but does not invalidate */
- u8 proc_c1:1; /* 02: All processors support C1 state */
- u8 plvl2_up:1; /* 03: C2 state works on MP system */
- u8 pwr_button:1; /* 04: Power button is handled as a generic feature */
- u8 sleep_button:1; /* 05: Sleep button is handled as a generic feature, or not present */
- u8 fixed_rTC:1; /* 06: RTC wakeup stat not in fixed register space */
- u8 rtcs4:1; /* 07: RTC wakeup stat not possible from S4 */
- u8 tmr_val_ext:1; /* 08: tmr_val width is 32 bits (0 = 24 bits) */
- u8:7; /* 09-15: Reserved, must be zero */
- u8 reserved5[2]; /* 16-31: Reserved, must be zero */
+ u8 enabled:1; /* 00: Use affinity structure */
+ u8 hot_pluggable:1; /* 01: Memory region is hot pluggable */
+ u8 non_volatile:1; /* 02: Memory is non-volatile */
+ u8:5; /* 03-07: Reserved, must be zero */
+ u8 reserved5[3]; /* 08-31: Reserved, must be zero */
+
+ u64 reserved6; /* Reserved, must be zero */
+};
+
+/*******************************************************************************
+ *
+ * TCPA - Trusted Computing Platform Alliance table
+ *
+ ******************************************************************************/
+
+struct acpi_table_tcpa {
+ ACPI_TABLE_HEADER_DEF u16 reserved;
+ u32 max_log_length; /* Maximum length for the event log area */
+ u64 log_address; /* Address of the event log area */
};
+/*******************************************************************************
+ *
+ * WDRT - Watchdog Resource Table
+ *
+ ******************************************************************************/
+
+struct acpi_table_wdrt {
+ ACPI_TABLE_HEADER_DEF u32 header_length; /* Watchdog Header Length */
+ u8 pci_segment; /* PCI Segment number */
+ u8 pci_bus; /* PCI Bus number */
+ u8 pci_device; /* PCI Device number */
+ u8 pci_function; /* PCI Function number */
+ u32 timer_period; /* Period of one timer count (msec) */
+ u32 max_count; /* Maximum counter value supported */
+ u32 min_count; /* Minimum counter value */
+ u8 flags;
+ u8 reserved[3];
+ u32 entries; /* Number of watchdog entries that follow */
+};
+
+#if 0 /* Flags, will be converted to macros */
+u8 enabled:1; /* 00: Timer enabled */
+u8:6; /* 01-06: Reserved */
+u8 sleep_stop:1; /* 07: Timer stopped in sleep state */
+#endif
+
+/* Macros used to generate offsets to specific table fields */
+
+#define ACPI_ASF0_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_asf_info,f)
+#define ACPI_ASF1_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_asf_alert,f)
+#define ACPI_ASF2_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_asf_remote,f)
+#define ACPI_ASF3_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_asf_rmcp,f)
+#define ACPI_ASF4_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_asf_address,f)
+#define ACPI_BOOT_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_boot,f)
+#define ACPI_CPEP_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_cpep,f)
+#define ACPI_CPEP0_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_cpep_polling,f)
+#define ACPI_DBGP_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_dbgp,f)
+#define ACPI_ECDT_OFFSET(f) (u8) ACPI_OFFSET (struct ec_boot_resources,f)
+#define ACPI_HPET_OFFSET(f) (u8) ACPI_OFFSET (struct hpet_table,f)
+#define ACPI_MADT_OFFSET(f) (u8) ACPI_OFFSET (struct multiple_apic_table,f)
+#define ACPI_MADT0_OFFSET(f) (u8) ACPI_OFFSET (struct madt_processor_apic,f)
+#define ACPI_MADT1_OFFSET(f) (u8) ACPI_OFFSET (struct madt_io_apic,f)
+#define ACPI_MADT2_OFFSET(f) (u8) ACPI_OFFSET (struct madt_interrupt_override,f)
+#define ACPI_MADT3_OFFSET(f) (u8) ACPI_OFFSET (struct madt_nmi_source,f)
+#define ACPI_MADT4_OFFSET(f) (u8) ACPI_OFFSET (struct madt_local_apic_nmi,f)
+#define ACPI_MADT5_OFFSET(f) (u8) ACPI_OFFSET (struct madt_address_override,f)
+#define ACPI_MADT6_OFFSET(f) (u8) ACPI_OFFSET (struct madt_io_sapic,f)
+#define ACPI_MADT7_OFFSET(f) (u8) ACPI_OFFSET (struct madt_local_sapic,f)
+#define ACPI_MADT8_OFFSET(f) (u8) ACPI_OFFSET (struct madt_interrupt_source,f)
+#define ACPI_MADTH_OFFSET(f) (u8) ACPI_OFFSET (struct apic_header,f)
+#define ACPI_MCFG_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_mcfg,f)
+#define ACPI_MCFG0_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_mcfg_allocation,f)
+#define ACPI_SBST_OFFSET(f) (u8) ACPI_OFFSET (struct smart_battery_table,f)
+#define ACPI_SLIT_OFFSET(f) (u8) ACPI_OFFSET (struct system_locality_info,f)
+#define ACPI_SPCR_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_spcr,f)
+#define ACPI_SPMI_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_spmi,f)
+#define ACPI_SRAT_OFFSET(f) (u8) ACPI_OFFSET (struct system_resource_affinity,f)
+#define ACPI_SRAT0_OFFSET(f) (u8) ACPI_OFFSET (struct static_resource_alloc,f)
+#define ACPI_SRAT1_OFFSET(f) (u8) ACPI_OFFSET (struct memory_affinity,f)
+#define ACPI_TCPA_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_tcpa,f)
+#define ACPI_WDRT_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_wdrt,f)
+
+#define ACPI_HPET_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct hpet_table,f,o)
+#define ACPI_SRAT0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct static_resource_alloc,f,o)
+#define ACPI_SRAT1_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct memory_affinity,f,o)
+#define ACPI_MADT_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct multiple_apic_table,f,o)
+#define ACPI_MADT0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_processor_apic,f,o)
+#define ACPI_MADT2_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_interrupt_override,f,o)
+#define ACPI_MADT3_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_nmi_source,f,o)
+#define ACPI_MADT4_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_local_apic_nmi,f,o)
+#define ACPI_MADT7_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_local_sapic,f,o)
+#define ACPI_MADT8_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_interrupt_source,f,o)
+
+/* Reset to default packing */
+
#pragma pack()
#endif /* __ACTBL1_H__ */
diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
index dfc7ac1..67efe6c 100644
--- a/include/acpi/actbl2.h
+++ b/include/acpi/actbl2.h
@@ -44,234 +44,6 @@
#ifndef __ACTBL2_H__
#define __ACTBL2_H__
-/*
- * Prefered Power Management Profiles
- */
-#define PM_UNSPECIFIED 0
-#define PM_DESKTOP 1
-#define PM_MOBILE 2
-#define PM_WORKSTATION 3
-#define PM_ENTERPRISE_SERVER 4
-#define PM_SOHO_SERVER 5
-#define PM_APPLIANCE_PC 6
-
-/*
- * ACPI Boot Arch Flags
- */
-#define BAF_LEGACY_DEVICES 0x0001
-#define BAF_8042_KEYBOARD_CONTROLLER 0x0002
-
-#define FADT2_REVISION_ID 3
-#define FADT2_MINUS_REVISION_ID 2
-
-#pragma pack(1)
-
-/*
- * ACPI 2.0 Root System Description Table (RSDT)
- */
-struct rsdt_descriptor_rev2 {
- ACPI_TABLE_HEADER_DEF /* ACPI common table header */
- u32 table_offset_entry[1]; /* Array of pointers to ACPI tables */
-};
-
-/*
- * ACPI 2.0 Extended System Description Table (XSDT)
- */
-struct xsdt_descriptor_rev2 {
- ACPI_TABLE_HEADER_DEF /* ACPI common table header */
- u64 table_offset_entry[1]; /* Array of pointers to ACPI tables */
-};
-
-/*
- * ACPI 2.0 Firmware ACPI Control Structure (FACS)
- */
-struct facs_descriptor_rev2 {
- char signature[4]; /* ASCII table signature */
- u32 length; /* Length of structure, in bytes */
- u32 hardware_signature; /* Hardware configuration signature */
- u32 firmware_waking_vector; /* 32-bit physical address of the Firmware Waking Vector. */
- u32 global_lock; /* Global Lock used to synchronize access to shared hardware resources */
-
- /* Flags (32 bits) */
-
- u8 S4bios_f:1; /* 00: S4BIOS support is present */
- u8:7; /* 01-07: Reserved, must be zero */
- u8 reserved1[3]; /* 08-31: Reserved, must be zero */
-
- u64 xfirmware_waking_vector; /* 64-bit physical address of the Firmware Waking Vector. */
- u8 version; /* Version of this table */
- u8 reserved3[31]; /* Reserved, must be zero */
-};
-
-/*
- * ACPI 2.0+ Generic Address Structure (GAS)
- */
-struct acpi_generic_address {
- u8 address_space_id; /* Address space where struct or register exists. */
- u8 register_bit_width; /* Size in bits of given register */
- u8 register_bit_offset; /* Bit offset within the register */
- u8 access_width; /* Minimum Access size (ACPI 3.0) */
- u64 address; /* 64-bit address of struct or register */
-};
-
-#define FADT_REV2_COMMON \
- u32 V1_firmware_ctrl; /* 32-bit physical address of FACS */ \
- u32 V1_dsdt; /* 32-bit physical address of DSDT */ \
- u8 reserved1; /* System Interrupt Model isn't used in ACPI 2.0*/ \
- u8 prefer_PM_profile; /* Conveys preferred power management profile to OSPM. */ \
- u16 sci_int; /* System vector of SCI interrupt */ \
- u32 smi_cmd; /* Port address of SMI command port */ \
- u8 acpi_enable; /* Value to write to smi_cmd to enable ACPI */ \
- u8 acpi_disable; /* Value to write to smi_cmd to disable ACPI */ \
- u8 S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ \
- u8 pstate_cnt; /* Processor performance state control*/ \
- u32 V1_pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */ \
- u32 V1_pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */ \
- u32 V1_pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ \
- u32 V1_pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ \
- u32 V1_pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ \
- u32 V1_pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ \
- u32 V1_gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ \
- u32 V1_gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ \
- u8 pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */ \
- u8 pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */ \
- u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ \
- u8 pm_tm_len; /* Byte Length of ports at pm_tm_blk */ \
- u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ \
- u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ \
- u8 gpe1_base; /* Offset in gpe model where gpe1 events start */ \
- u8 cst_cnt; /* Support for the _CST object and C States change notification.*/ \
- u16 plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ \
- u16 plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ \
- u16 flush_size; /* Number of flush strides that need to be read */ \
- u16 flush_stride; /* Processor's memory cache line width, in bytes */ \
- u8 duty_offset; /* Processor's duty cycle index in processor's P_CNT reg*/ \
- u8 duty_width; /* Processor's duty cycle value bit width in P_CNT register.*/ \
- u8 day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ \
- u8 mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ \
- u8 century; /* Index to century in RTC CMOS RAM */ \
- u16 iapc_boot_arch; /* IA-PC Boot Architecture Flags. See Table 5-10 for description*/
-
-/*
- * ACPI 2.0+ Fixed ACPI Description Table (FADT)
- */
-struct fadt_descriptor_rev2 {
- ACPI_TABLE_HEADER_DEF /* ACPI common table header */
- FADT_REV2_COMMON u8 reserved2; /* Reserved, must be zero */
-
- /* Flags (32 bits) */
-
- u8 wb_invd:1; /* 00: The wbinvd instruction works properly */
- u8 wb_invd_flush:1; /* 01: The wbinvd flushes but does not invalidate */
- u8 proc_c1:1; /* 02: All processors support C1 state */
- u8 plvl2_up:1; /* 03: C2 state works on MP system */
- u8 pwr_button:1; /* 04: Power button is handled as a generic feature */
- u8 sleep_button:1; /* 05: Sleep button is handled as a generic feature, or not present */
- u8 fixed_rTC:1; /* 06: RTC wakeup stat not in fixed register space */
- u8 rtcs4:1; /* 07: RTC wakeup stat not possible from S4 */
- u8 tmr_val_ext:1; /* 08: tmr_val is 32 bits 0=24-bits */
- u8 dock_cap:1; /* 09: Docking supported */
- u8 reset_reg_sup:1; /* 10: System reset via the FADT RESET_REG supported */
- u8 sealed_case:1; /* 11: No internal expansion capabilities and case is sealed */
- u8 headless:1; /* 12: No local video capabilities or local input devices */
- u8 cpu_sw_sleep:1; /* 13: Must execute native instruction after writing SLP_TYPx register */
-
- u8 pci_exp_wak:1; /* 14: System supports PCIEXP_WAKE (STS/EN) bits (ACPI 3.0) */
- u8 use_platform_clock:1; /* 15: OSPM should use platform-provided timer (ACPI 3.0) */
- u8 S4rtc_sts_valid:1; /* 16: Contents of RTC_STS valid after S4 wake (ACPI 3.0) */
- u8 remote_power_on_capable:1; /* 17: System is compatible with remote power on (ACPI 3.0) */
- u8 force_apic_cluster_model:1; /* 18: All local APICs must use cluster model (ACPI 3.0) */
- u8 force_apic_physical_destination_mode:1; /* 19: all local x_aPICs must use physical dest mode (ACPI 3.0) */
- u8:4; /* 20-23: Reserved, must be zero */
- u8 reserved3; /* 24-31: Reserved, must be zero */
-
- struct acpi_generic_address reset_register; /* Reset register address in GAS format */
- u8 reset_value; /* Value to write to the reset_register port to reset the system */
- u8 reserved4[3]; /* These three bytes must be zero */
- u64 xfirmware_ctrl; /* 64-bit physical address of FACS */
- u64 Xdsdt; /* 64-bit physical address of DSDT */
- struct acpi_generic_address xpm1a_evt_blk; /* Extended Power Mgt 1a acpi_event Reg Blk address */
- struct acpi_generic_address xpm1b_evt_blk; /* Extended Power Mgt 1b acpi_event Reg Blk address */
- struct acpi_generic_address xpm1a_cnt_blk; /* Extended Power Mgt 1a Control Reg Blk address */
- struct acpi_generic_address xpm1b_cnt_blk; /* Extended Power Mgt 1b Control Reg Blk address */
- struct acpi_generic_address xpm2_cnt_blk; /* Extended Power Mgt 2 Control Reg Blk address */
- struct acpi_generic_address xpm_tmr_blk; /* Extended Power Mgt Timer Ctrl Reg Blk address */
- struct acpi_generic_address xgpe0_blk; /* Extended General Purpose acpi_event 0 Reg Blk address */
- struct acpi_generic_address xgpe1_blk; /* Extended General Purpose acpi_event 1 Reg Blk address */
-};
-
-/* "Down-revved" ACPI 2.0 FADT descriptor */
-
-struct fadt_descriptor_rev2_minus {
- ACPI_TABLE_HEADER_DEF /* ACPI common table header */
- FADT_REV2_COMMON u8 reserved2; /* Reserved, must be zero */
- u32 flags;
- struct acpi_generic_address reset_register; /* Reset register address in GAS format */
- u8 reset_value; /* Value to write to the reset_register port to reset the system. */
- u8 reserved7[3]; /* Reserved, must be zero */
-};
-
-/* ECDT - Embedded Controller Boot Resources Table */
-
-struct ec_boot_resources {
- ACPI_TABLE_HEADER_DEF struct acpi_generic_address ec_control; /* Address of EC command/status register */
- struct acpi_generic_address ec_data; /* Address of EC data register */
- u32 uid; /* Unique ID - must be same as the EC _UID method */
- u8 gpe_bit; /* The GPE for the EC */
- u8 ec_id[1]; /* Full namepath of the EC in the ACPI namespace */
-};
-
-/* SRAT - System Resource Affinity Table */
-
-struct static_resource_alloc {
- u8 type;
- u8 length;
- u8 proximity_domain_lo;
- u8 apic_id;
-
- /* Flags (32 bits) */
-
- u8 enabled:1; /* 00: Use affinity structure */
- u8:7; /* 01-07: Reserved, must be zero */
- u8 reserved3[3]; /* 08-31: Reserved, must be zero */
-
- u8 local_sapic_eid;
- u8 proximity_domain_hi[3];
- u32 reserved4; /* Reserved, must be zero */
-};
-
-struct memory_affinity {
- u8 type;
- u8 length;
- u32 proximity_domain;
- u16 reserved3;
- u64 base_address;
- u64 address_length;
- u32 reserved4;
-
- /* Flags (32 bits) */
-
- u8 enabled:1; /* 00: Use affinity structure */
- u8 hot_pluggable:1; /* 01: Memory region is hot pluggable */
- u8 non_volatile:1; /* 02: Memory is non-volatile */
- u8:5; /* 03-07: Reserved, must be zero */
- u8 reserved5[3]; /* 08-31: Reserved, must be zero */
-
- u64 reserved6; /* Reserved, must be zero */
-};
-
-struct system_resource_affinity {
- ACPI_TABLE_HEADER_DEF u32 reserved1; /* Must be value '1' */
- u64 reserved2; /* Reserved, must be zero */
-};
-
-/* SLIT - System Locality Distance Information Table */
-
-struct system_locality_info {
- ACPI_TABLE_HEADER_DEF u64 locality_count;
- u8 entry[1][1];
-};
-
-#pragma pack()
+/* Code moved to both actbl.h and actbl1.h */
#endif /* __ACTBL2_H__ */
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
index 7ca89cd..77cf123 100644
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -44,6 +44,8 @@
#ifndef __ACTYPES_H__
#define __ACTYPES_H__
+/* acpisrc:struct_defs -- for acpisrc conversion */
+
/*
* ACPI_MACHINE_WIDTH must be specified in an OS- or compiler-dependent header
* and must be either 16, 32, or 64
@@ -154,7 +156,6 @@ typedef u64 acpi_physical_address;
#define ACPI_MAX_PTR ACPI_UINT64_MAX
#define ACPI_SIZE_MAX ACPI_UINT64_MAX
-#define ALIGNED_ADDRESS_BOUNDARY 0x00000008
#define ACPI_USE_NATIVE_DIVIDE /* Has native 64-bit integer support */
/*
@@ -195,8 +196,6 @@ typedef u64 acpi_physical_address;
#define ACPI_MAX_PTR ACPI_UINT32_MAX
#define ACPI_SIZE_MAX ACPI_UINT32_MAX
-#define ALIGNED_ADDRESS_BOUNDARY 0x00000004
-
/*******************************************************************************
*
* Types specific to 16-bit targets
@@ -223,7 +222,6 @@ typedef char *acpi_physical_address;
#define ACPI_MAX_PTR ACPI_UINT16_MAX
#define ACPI_SIZE_MAX ACPI_UINT16_MAX
-#define ALIGNED_ADDRESS_BOUNDARY 0x00000002
#define ACPI_USE_NATIVE_DIVIDE /* No 64-bit integers, ok to use native divide */
/* 64-bit integers cannot be supported */
@@ -254,7 +252,7 @@ typedef acpi_native_uint acpi_size;
/* Use C99 uintptr_t for pointer casting if available, "void *" otherwise */
#ifndef acpi_uintptr_t
-#define acpi_uintptr_t void *
+#define acpi_uintptr_t void *
#endif
/*
@@ -263,7 +261,7 @@ typedef acpi_native_uint acpi_size;
* manager implementation is to be used (ACPI_USE_LOCAL_CACHE)
*/
#ifndef acpi_cache_t
-#define acpi_cache_t struct acpi_memory_list
+#define acpi_cache_t struct acpi_memory_list
#endif
/*
@@ -271,7 +269,7 @@ typedef acpi_native_uint acpi_size;
* lock and unlock OSL interfaces.
*/
#ifndef acpi_cpu_flags
-#define acpi_cpu_flags acpi_native_uint
+#define acpi_cpu_flags acpi_native_uint
#endif
/*
@@ -292,6 +290,21 @@ typedef acpi_native_uint acpi_size;
#define ACPI_UNUSED_VAR
#endif
+/*
+ * All ACPICA functions that are available to the rest of the kernel are
+ * tagged with this macro which can be defined as appropriate for the host.
+ */
+#ifndef ACPI_EXPORT_SYMBOL
+#define ACPI_EXPORT_SYMBOL(symbol)
+#endif
+
+/*
+ * thread_id is returned by acpi_os_get_thread_id.
+ */
+#ifndef acpi_thread_id
+#define acpi_thread_id acpi_native_uint
+#endif
+
/*******************************************************************************
*
* Independent types
@@ -477,15 +490,15 @@ typedef u64 acpi_integer;
*/
typedef u32 acpi_table_type;
-#define ACPI_TABLE_RSDP (acpi_table_type) 0
-#define ACPI_TABLE_DSDT (acpi_table_type) 1
-#define ACPI_TABLE_FADT (acpi_table_type) 2
-#define ACPI_TABLE_FACS (acpi_table_type) 3
-#define ACPI_TABLE_PSDT (acpi_table_type) 4
-#define ACPI_TABLE_SSDT (acpi_table_type) 5
-#define ACPI_TABLE_XSDT (acpi_table_type) 6
-#define ACPI_TABLE_MAX 6
-#define NUM_ACPI_TABLE_TYPES (ACPI_TABLE_MAX+1)
+#define ACPI_TABLE_ID_RSDP (acpi_table_type) 0
+#define ACPI_TABLE_ID_DSDT (acpi_table_type) 1
+#define ACPI_TABLE_ID_FADT (acpi_table_type) 2
+#define ACPI_TABLE_ID_FACS (acpi_table_type) 3
+#define ACPI_TABLE_ID_PSDT (acpi_table_type) 4
+#define ACPI_TABLE_ID_SSDT (acpi_table_type) 5
+#define ACPI_TABLE_ID_XSDT (acpi_table_type) 6
+#define ACPI_TABLE_ID_MAX 6
+#define ACPI_NUM_TABLE_TYPES (ACPI_TABLE_ID_MAX+1)
/*
* Types associated with ACPI names and objects. The first group of
@@ -816,7 +829,7 @@ struct acpi_system_info {
u32 debug_level;
u32 debug_layer;
u32 num_table_types;
- struct acpi_table_info table_info[NUM_ACPI_TABLE_TYPES];
+ struct acpi_table_info table_info[ACPI_TABLE_ID_MAX + 1];
};
/*
@@ -858,7 +871,7 @@ acpi_status(*acpi_adr_space_handler) (u32 function,
void *handler_context,
void *region_context);
-#define ACPI_DEFAULT_HANDLER NULL
+#define ACPI_DEFAULT_HANDLER NULL
typedef
acpi_status(*acpi_adr_space_setup) (acpi_handle region_handle,
@@ -911,12 +924,13 @@ struct acpi_compatible_id_list {
#define ACPI_STA_DEVICE_PRESENT 0x01
#define ACPI_STA_DEVICE_ENABLED 0x02
#define ACPI_STA_DEVICE_UI 0x04
-#define ACPI_STA_DEVICE_OK 0x08
+#define ACPI_STA_DEVICE_FUNCTIONING 0x08
+#define ACPI_STA_DEVICE_OK 0x08 /* Synonym */
#define ACPI_STA_BATTERY_PRESENT 0x10
#define ACPI_COMMON_OBJ_INFO \
- acpi_object_type type; /* ACPI object type */ \
- acpi_name name /* ACPI object Name */
+ acpi_object_type type; /* ACPI object type */ \
+ acpi_name name /* ACPI object Name */
struct acpi_obj_info_header {
ACPI_COMMON_OBJ_INFO;
@@ -957,7 +971,7 @@ struct acpi_mem_space_context {
* Definitions for Resource Attributes
*/
typedef u16 acpi_rs_length; /* Resource Length field is fixed at 16 bits */
-typedef u32 acpi_rsdesc_size; /* Max Resource Descriptor size is (length+3) = (64_k-1)+3 */
+typedef u32 acpi_rsdesc_size; /* Max Resource Descriptor size is (Length+3) = (64_k-1)+3 */
/*
* Memory Attributes
@@ -972,8 +986,8 @@ typedef u32 acpi_rsdesc_size; /* Max Resource Descriptor size is (length+3) = (6
/*
* IO Attributes
- * The ISA Io ranges are: n000-n0_ffh, n400-n4_ffh, n800-n8_ffh, n_c00-n_cFFh.
- * The non-ISA Io ranges are: n100-n3_ffh, n500-n7_ffh, n900-n_bFfh, n_cd0-n_fFFh.
+ * The ISA IO ranges are: n000-n0_fFh, n400-n4_fFh, n800-n8_fFh, n_c00-n_cFFh.
+ * The non-ISA IO ranges are: n100-n3_fFh, n500-n7_fFh, n900-n_bFFh, n_cd0-n_fFFh.
*/
#define ACPI_NON_ISA_ONLY_RANGES (u8) 0x01
#define ACPI_ISA_ONLY_RANGES (u8) 0x02
@@ -1171,12 +1185,12 @@ struct acpi_resource_source {
/* Fields common to all address descriptors, 16/32/64 bit */
#define ACPI_RESOURCE_ADDRESS_COMMON \
- u8 resource_type; \
- u8 producer_consumer; \
- u8 decode; \
- u8 min_address_fixed; \
- u8 max_address_fixed; \
- union acpi_resource_attribute info;
+ u8 resource_type; \
+ u8 producer_consumer; \
+ u8 decode; \
+ u8 min_address_fixed; \
+ u8 max_address_fixed; \
+ union acpi_resource_attribute info;
struct acpi_resource_address {
ACPI_RESOURCE_ADDRESS_COMMON};
@@ -1297,16 +1311,6 @@ struct acpi_resource {
#define ACPI_NEXT_RESOURCE(res) (struct acpi_resource *)((u8 *) res + res->length)
-#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED
-#define ACPI_ALIGN_RESOURCE_SIZE(length) (length)
-#else
-#define ACPI_ALIGN_RESOURCE_SIZE(length) ACPI_ROUND_UP_TO_NATIVE_WORD(length)
-#endif
-
-/*
- * END: of definitions for Resource Attributes
- */
-
struct acpi_pci_routing_table {
u32 length;
u32 pin;
@@ -1315,8 +1319,4 @@ struct acpi_pci_routing_table {
char source[4]; /* pad to 64 bits so sizeof() works in all cases */
};
-/*
- * END: of definitions for PCI Routing tables
- */
-
#endif /* __ACTYPES_H__ */
diff --git a/include/acpi/acutils.h b/include/acpi/acutils.h
index 0927765..ba039ea 100644
--- a/include/acpi/acutils.h
+++ b/include/acpi/acutils.h
@@ -50,24 +50,24 @@ extern const u8 acpi_gbl_resource_aml_sizes[];
#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER)
-extern const char *acpi_gbl_BMdecode[2];
-extern const char *acpi_gbl_config_decode[4];
-extern const char *acpi_gbl_consume_decode[2];
-extern const char *acpi_gbl_DECdecode[2];
-extern const char *acpi_gbl_HEdecode[2];
-extern const char *acpi_gbl_io_decode[2];
-extern const char *acpi_gbl_LLdecode[2];
-extern const char *acpi_gbl_max_decode[2];
-extern const char *acpi_gbl_MEMdecode[4];
-extern const char *acpi_gbl_min_decode[2];
-extern const char *acpi_gbl_MTPdecode[4];
-extern const char *acpi_gbl_RNGdecode[4];
-extern const char *acpi_gbl_RWdecode[2];
-extern const char *acpi_gbl_SHRdecode[2];
-extern const char *acpi_gbl_SIZdecode[4];
-extern const char *acpi_gbl_TRSdecode[2];
-extern const char *acpi_gbl_TTPdecode[2];
-extern const char *acpi_gbl_TYPdecode[4];
+extern const char *acpi_gbl_bm_decode[];
+extern const char *acpi_gbl_config_decode[];
+extern const char *acpi_gbl_consume_decode[];
+extern const char *acpi_gbl_dec_decode[];
+extern const char *acpi_gbl_he_decode[];
+extern const char *acpi_gbl_io_decode[];
+extern const char *acpi_gbl_ll_decode[];
+extern const char *acpi_gbl_max_decode[];
+extern const char *acpi_gbl_mem_decode[];
+extern const char *acpi_gbl_min_decode[];
+extern const char *acpi_gbl_mtp_decode[];
+extern const char *acpi_gbl_rng_decode[];
+extern const char *acpi_gbl_rw_decode[];
+extern const char *acpi_gbl_shr_decode[];
+extern const char *acpi_gbl_siz_decode[];
+extern const char *acpi_gbl_trs_decode[];
+extern const char *acpi_gbl_ttp_decode[];
+extern const char *acpi_gbl_typ_decode[];
#endif
/* Types for Resource descriptor entries */
@@ -78,6 +78,12 @@ extern const char *acpi_gbl_TYPdecode[4];
#define ACPI_SMALL_VARIABLE_LENGTH 3
typedef
+acpi_status(*acpi_walk_aml_callback) (u8 * aml,
+ u32 length,
+ u32 offset,
+ u8 resource_index, void **context);
+
+typedef
acpi_status(*acpi_pkg_callback) (u8 object_type,
union acpi_operand_object * source_object,
union acpi_generic_state * state,
@@ -277,6 +283,8 @@ acpi_ut_ptr_exit(u32 line_number,
void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id);
+void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display);
+
void acpi_ut_report_error(char *module_name, u32 line_number);
void acpi_ut_report_info(char *module_name, u32 line_number);
@@ -445,6 +453,8 @@ acpi_ut_short_divide(acpi_integer in_dividend,
/*
* utmisc
*/
+u8 acpi_ut_is_aml_table(struct acpi_table_header *table);
+
acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id);
void acpi_ut_release_owner_id(acpi_owner_id * owner_id);
@@ -460,7 +470,9 @@ void acpi_ut_print_string(char *string, u8 max_length);
u8 acpi_ut_valid_acpi_name(u32 name);
-u8 acpi_ut_valid_acpi_character(char character);
+acpi_name acpi_ut_repair_name(acpi_name name);
+
+u8 acpi_ut_valid_acpi_char(char character, acpi_native_uint position);
acpi_status
acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer);
@@ -469,6 +481,25 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer);
#define ACPI_ANY_BASE 0
+u32 acpi_ut_dword_byte_swap(u32 value);
+
+void acpi_ut_set_integer_width(u8 revision);
+
+#ifdef ACPI_DEBUG_OUTPUT
+void
+acpi_ut_display_init_pathname(u8 type,
+ struct acpi_namespace_node *obj_handle,
+ char *path);
+#endif
+
+/*
+ * utresrc
+ */
+acpi_status
+acpi_ut_walk_aml_resources(u8 * aml,
+ acpi_size aml_length,
+ acpi_walk_aml_callback user_function, void **context);
+
acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index);
u32 acpi_ut_get_descriptor_length(void *aml);
@@ -483,20 +514,6 @@ acpi_status
acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc,
u8 ** end_tag);
-u8 acpi_ut_generate_checksum(u8 * buffer, u32 length);
-
-u32 acpi_ut_dword_byte_swap(u32 value);
-
-void acpi_ut_set_integer_width(u8 revision);
-
-#ifdef ACPI_DEBUG_OUTPUT
-void
-acpi_ut_display_init_pathname(u8 type,
- struct acpi_namespace_node *obj_handle,
- char *path);
-
-#endif
-
/*
* utmutex - mutex support
*/
@@ -523,14 +540,15 @@ acpi_ut_initialize_buffer(struct acpi_buffer *buffer,
void *acpi_ut_allocate(acpi_size size, u32 component, char *module, u32 line);
-void *acpi_ut_callocate(acpi_size size, u32 component, char *module, u32 line);
+void *acpi_ut_allocate_zeroed(acpi_size size,
+ u32 component, char *module, u32 line);
#ifdef ACPI_DBG_TRACK_ALLOCATIONS
void *acpi_ut_allocate_and_track(acpi_size size,
u32 component, char *module, u32 line);
-void *acpi_ut_callocate_and_track(acpi_size size,
- u32 component, char *module, u32 line);
+void *acpi_ut_allocate_zeroed_and_track(acpi_size size,
+ u32 component, char *module, u32 line);
void
acpi_ut_free_and_track(void *address, u32 component, char *module, u32 line);
@@ -540,6 +558,11 @@ void acpi_ut_dump_allocation_info(void);
#endif /* ACPI_FUTURE_USAGE */
void acpi_ut_dump_allocations(u32 component, char *module);
+
+acpi_status
+acpi_ut_create_list(char *list_name,
+ u16 object_size, struct acpi_memory_list **return_cache);
+
#endif
#endif /* _ACUTILS_H */
diff --git a/include/acpi/amlcode.h b/include/acpi/amlcode.h
index 37964a5..cf18426 100644
--- a/include/acpi/amlcode.h
+++ b/include/acpi/amlcode.h
@@ -180,8 +180,10 @@
#define AML_BANK_FIELD_OP (u16) 0x5b87
#define AML_DATA_REGION_OP (u16) 0x5b88 /* ACPI 2.0 */
-/* Bogus opcodes (they are actually two separate opcodes) */
-
+/*
+ * Combination opcodes (actually two one-byte opcodes)
+ * Used by the disassembler and i_aSL compiler
+ */
#define AML_LGREATEREQUAL_OP (u16) 0x9295
#define AML_LLESSEQUAL_OP (u16) 0x9294
#define AML_LNOTEQUAL_OP (u16) 0x9293
diff --git a/include/acpi/amlresrc.h b/include/acpi/amlresrc.h
index fb47353..be03818 100644
--- a/include/acpi/amlresrc.h
+++ b/include/acpi/amlresrc.h
@@ -42,39 +42,45 @@
* POSSIBILITY OF SUCH DAMAGES.
*/
+/* acpisrc:struct_defs -- for acpisrc conversion */
+
#ifndef __AMLRESRC_H
#define __AMLRESRC_H
-#define ASL_RESNAME_ADDRESS "_ADR"
-#define ASL_RESNAME_ALIGNMENT "_ALN"
-#define ASL_RESNAME_ADDRESSSPACE "_ASI"
-#define ASL_RESNAME_ACCESSSIZE "_ASZ"
-#define ASL_RESNAME_TYPESPECIFICATTRIBUTES "_ATT"
-#define ASL_RESNAME_BASEADDRESS "_BAS"
-#define ASL_RESNAME_BUSMASTER "_BM_" /* Master(1), Slave(0) */
-#define ASL_RESNAME_DECODE "_DEC"
-#define ASL_RESNAME_DMA "_DMA"
-#define ASL_RESNAME_DMATYPE "_TYP" /* Compatible(0), A(1), B(2), F(3) */
-#define ASL_RESNAME_GRANULARITY "_GRA"
-#define ASL_RESNAME_INTERRUPT "_INT"
-#define ASL_RESNAME_INTERRUPTLEVEL "_LL_" /* active_lo(1), active_hi(0) */
-#define ASL_RESNAME_INTERRUPTSHARE "_SHR" /* Shareable(1), no_share(0) */
-#define ASL_RESNAME_INTERRUPTTYPE "_HE_" /* Edge(1), Level(0) */
-#define ASL_RESNAME_LENGTH "_LEN"
-#define ASL_RESNAME_MEMATTRIBUTES "_MTP" /* Memory(0), Reserved(1), ACPI(2), NVS(3) */
-#define ASL_RESNAME_MEMTYPE "_MEM" /* non_cache(0), Cacheable(1) Cache+combine(2), Cache+prefetch(3) */
-#define ASL_RESNAME_MAXADDR "_MAX"
-#define ASL_RESNAME_MINADDR "_MIN"
-#define ASL_RESNAME_MAXTYPE "_MAF"
-#define ASL_RESNAME_MINTYPE "_MIF"
-#define ASL_RESNAME_REGISTERBITOFFSET "_RBO"
-#define ASL_RESNAME_REGISTERBITWIDTH "_RBW"
-#define ASL_RESNAME_RANGETYPE "_RNG"
-#define ASL_RESNAME_READWRITETYPE "_RW_" /* read_only(0), Writeable (1) */
-#define ASL_RESNAME_TRANSLATION "_TRA"
-#define ASL_RESNAME_TRANSTYPE "_TRS" /* Sparse(1), Dense(0) */
-#define ASL_RESNAME_TYPE "_TTP" /* Translation(1), Static (0) */
-#define ASL_RESNAME_XFERTYPE "_SIz" /* 8(0), 8_and16(1), 16(2) */
+/*
+ * Resource descriptor tags, as defined in the ACPI specification.
+ * Used to symbolically reference fields within a descriptor.
+ */
+#define ACPI_RESTAG_ADDRESS "_ADR"
+#define ACPI_RESTAG_ALIGNMENT "_ALN"
+#define ACPI_RESTAG_ADDRESSSPACE "_ASI"
+#define ACPI_RESTAG_ACCESSSIZE "_ASZ"
+#define ACPI_RESTAG_TYPESPECIFICATTRIBUTES "_ATT"
+#define ACPI_RESTAG_BASEADDRESS "_BAS"
+#define ACPI_RESTAG_BUSMASTER "_BM_" /* Master(1), Slave(0) */
+#define ACPI_RESTAG_DECODE "_DEC"
+#define ACPI_RESTAG_DMA "_DMA"
+#define ACPI_RESTAG_DMATYPE "_TYP" /* Compatible(0), A(1), B(2), F(3) */
+#define ACPI_RESTAG_GRANULARITY "_GRA"
+#define ACPI_RESTAG_INTERRUPT "_INT"
+#define ACPI_RESTAG_INTERRUPTLEVEL "_LL_" /* active_lo(1), active_hi(0) */
+#define ACPI_RESTAG_INTERRUPTSHARE "_SHR" /* Shareable(1), no_share(0) */
+#define ACPI_RESTAG_INTERRUPTTYPE "_HE_" /* Edge(1), Level(0) */
+#define ACPI_RESTAG_LENGTH "_LEN"
+#define ACPI_RESTAG_MEMATTRIBUTES "_MTP" /* Memory(0), Reserved(1), ACPI(2), NVS(3) */
+#define ACPI_RESTAG_MEMTYPE "_MEM" /* non_cache(0), Cacheable(1) Cache+combine(2), Cache+prefetch(3) */
+#define ACPI_RESTAG_MAXADDR "_MAX"
+#define ACPI_RESTAG_MINADDR "_MIN"
+#define ACPI_RESTAG_MAXTYPE "_MAF"
+#define ACPI_RESTAG_MINTYPE "_MIF"
+#define ACPI_RESTAG_REGISTERBITOFFSET "_RBO"
+#define ACPI_RESTAG_REGISTERBITWIDTH "_RBW"
+#define ACPI_RESTAG_RANGETYPE "_RNG"
+#define ACPI_RESTAG_READWRITETYPE "_RW_" /* read_only(0), Writeable (1) */
+#define ACPI_RESTAG_TRANSLATION "_TRA"
+#define ACPI_RESTAG_TRANSTYPE "_TRS" /* Sparse(1), Dense(0) */
+#define ACPI_RESTAG_TYPE "_TTP" /* Translation(1), Static (0) */
+#define ACPI_RESTAG_XFERTYPE "_SIZ" /* 8(0), 8_and16(1), 16(2) */
/* Default sizes for "small" resource descriptors */
@@ -109,7 +115,7 @@ struct asl_resource_node {
* SMALL descriptors
*/
#define AML_RESOURCE_SMALL_HEADER_COMMON \
- u8 descriptor_type;
+ u8 descriptor_type;
struct aml_resource_small_header {
AML_RESOURCE_SMALL_HEADER_COMMON};
@@ -162,8 +168,8 @@ struct aml_resource_end_tag {
* LARGE descriptors
*/
#define AML_RESOURCE_LARGE_HEADER_COMMON \
- u8 descriptor_type;\
- u16 resource_length;
+ u8 descriptor_type;\
+ u16 resource_length;
struct aml_resource_large_header {
AML_RESOURCE_LARGE_HEADER_COMMON};
@@ -194,9 +200,9 @@ struct aml_resource_fixed_memory32 {
};
#define AML_RESOURCE_ADDRESS_COMMON \
- u8 resource_type; \
- u8 flags; \
- u8 specific_flags;
+ u8 resource_type; \
+ u8 flags; \
+ u8 specific_flags;
struct aml_resource_address {
AML_RESOURCE_LARGE_HEADER_COMMON AML_RESOURCE_ADDRESS_COMMON};
@@ -266,6 +272,7 @@ struct aml_resource_generic_register {
union aml_resource {
/* Descriptor headers */
+ u8 descriptor_type;
struct aml_resource_small_header small_header;
struct aml_resource_large_header large_header;
@@ -296,9 +303,9 @@ union aml_resource {
/* Utility overlays */
struct aml_resource_address address;
- u32 u32_item;
- u16 u16_item;
- u8 U8item;
+ u32 dword_item;
+ u16 word_item;
+ u8 byte_item;
};
#endif
diff --git a/include/acpi/pdc_intel.h b/include/acpi/pdc_intel.h
index 3fa81d5..c5472be 100644
--- a/include/acpi/pdc_intel.h
+++ b/include/acpi/pdc_intel.h
@@ -18,6 +18,11 @@
ACPI_PDC_C_C1_HALT | \
ACPI_PDC_P_FFH)
+#define ACPI_PDC_EST_CAPABILITY_SWSMP (ACPI_PDC_SMP_C1PT | \
+ ACPI_PDC_C_C1_HALT | \
+ ACPI_PDC_SMP_P_SWCOORD | \
+ ACPI_PDC_P_FFH)
+
#define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \
ACPI_PDC_SMP_C1PT | \
ACPI_PDC_C_C1_HALT)
diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h
index 223ec64..453a469 100644
--- a/include/acpi/platform/acenv.h
+++ b/include/acpi/platform/acenv.h
@@ -49,33 +49,41 @@
*/
#ifdef ACPI_LIBRARY
+/*
+ * Note: The non-debug version of the acpi_library does not contain any
+ * debug support, for minimimal size. The debug version uses ACPI_FULL_DEBUG
+ */
#define ACPI_USE_LOCAL_CACHE
#endif
-#ifdef ACPI_DUMP_APP
-#ifndef MSDOS
+#ifdef ACPI_ASL_COMPILER
#define ACPI_DEBUG_OUTPUT
-#endif
#define ACPI_APPLICATION
#define ACPI_DISASSEMBLER
-#define ACPI_NO_METHOD_EXECUTION
+#define ACPI_CONSTANT_EVAL_ONLY
+#define ACPI_LARGE_NAMESPACE_NODE
+#define ACPI_DATA_TABLE_DISASSEMBLY
#endif
#ifdef ACPI_EXEC_APP
#undef DEBUGGER_THREADING
#define DEBUGGER_THREADING DEBUGGER_SINGLE_THREADED
-#define ACPI_DEBUG_OUTPUT
+#define ACPI_FULL_DEBUG
#define ACPI_APPLICATION
#define ACPI_DEBUGGER
-#define ACPI_DISASSEMBLER
#define ACPI_MUTEX_DEBUG
+#define ACPI_DBG_TRACK_ALLOCATIONS
#endif
-#ifdef ACPI_ASL_COMPILER
+#ifdef ACPI_DASM_APP
+#ifndef MSDOS
#define ACPI_DEBUG_OUTPUT
+#endif
#define ACPI_APPLICATION
#define ACPI_DISASSEMBLER
-#define ACPI_CONSTANT_EVAL_ONLY
+#define ACPI_NO_METHOD_EXECUTION
+#define ACPI_LARGE_NAMESPACE_NODE
+#define ACPI_DATA_TABLE_DISASSEMBLY
#endif
#ifdef ACPI_APPLICATION
@@ -83,6 +91,12 @@
#define ACPI_USE_LOCAL_CACHE
#endif
+#ifdef ACPI_FULL_DEBUG
+#define ACPI_DEBUGGER
+#define ACPI_DEBUG_OUTPUT
+#define ACPI_DISASSEMBLER
+#endif
+
/*
* Environment configuration. The purpose of this file is to interface to the
* local generation environment.
@@ -137,7 +151,7 @@
#elif defined(MSDOS) /* Must appear after WIN32 and WIN64 check */
#include "acdos16.h"
-#elif defined(__FreeBSD__)
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#include "acfreebsd.h"
#elif defined(__NetBSD__)
@@ -163,17 +177,6 @@
#endif
-/*
- * Memory allocation tracking. Used only if
- * 1) This is the debug version
- * 2) This is NOT a 16-bit version of the code (not enough real-mode memory)
- */
-#ifdef ACPI_DEBUG_OUTPUT
-#if ACPI_MACHINE_WIDTH != 16
-#define ACPI_DBG_TRACK_ALLOCATIONS
-#endif
-#endif
-
/*! [End] no source code translation !*/
/*
@@ -271,8 +274,8 @@ typedef char *va_list;
/*
* Storage alignment properties
*/
-#define _AUPBND (sizeof (acpi_native_uint) - 1)
-#define _ADNBND (sizeof (acpi_native_uint) - 1)
+#define _AUPBND (sizeof (acpi_native_int) - 1)
+#define _ADNBND (sizeof (acpi_native_int) - 1)
/*
* Variable argument list macro definitions
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 3c6a620..277d35b 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -51,27 +51,22 @@
#include <linux/string.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/ctype.h>
#include <asm/system.h>
#include <asm/atomic.h>
#include <asm/div64.h>
#include <asm/acpi.h>
+#include <linux/slab.h>
-#define strtoul simple_strtoul
-
-#define ACPI_MACHINE_WIDTH BITS_PER_LONG
+/* Host-dependent types and defines */
-/* Type(s) for the OSL */
-
-#ifdef ACPI_USE_LOCAL_CACHE
-#define acpi_cache_t struct acpi_memory_list
-#else
-#include <linux/slab.h>
-#define acpi_cache_t kmem_cache_t
-#endif
+#define ACPI_MACHINE_WIDTH BITS_PER_LONG
+#define acpi_cache_t kmem_cache_t
+#define ACPI_EXPORT_SYMBOL(symbol) EXPORT_SYMBOL(symbol);
+#define strtoul simple_strtoul
/* Full namespace pathname length limit - arbitrary */
-
#define ACPI_PATHNAME_MAX 256
#else /* !__KERNEL__ */
@@ -103,4 +98,8 @@
#define acpi_cpu_flags unsigned long
+#define acpi_thread_id u32
+
+static inline acpi_thread_id acpi_os_get_thread_id(void) { return 0; }
+
#endif /* __ACLINUX_H__ */
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index ef7d83a..77371b3 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -2,6 +2,7 @@
#define __ACPI_PROCESSOR_H
#include <linux/kernel.h>
+#include <linux/cpu.h>
#include <asm/acpi.h>
@@ -17,6 +18,17 @@
#define ACPI_PDC_REVISION_ID 0x1
+#define ACPI_PSD_REV0_REVISION 0 /* Support for _PSD as in ACPI 3.0 */
+#define ACPI_PSD_REV0_ENTRIES 5
+
+/*
+ * Types of coordination defined in ACPI 3.0. Same macros can be used across
+ * P, C and T states
+ */
+#define DOMAIN_COORD_TYPE_SW_ALL 0xfc
+#define DOMAIN_COORD_TYPE_SW_ANY 0xfd
+#define DOMAIN_COORD_TYPE_HW_ALL 0xfe
+
/* Power Management */
struct acpi_processor_cx;
@@ -65,6 +77,14 @@ struct acpi_processor_power {
/* Performance Management */
+struct acpi_psd_package {
+ acpi_integer num_entries;
+ acpi_integer revision;
+ acpi_integer domain;
+ acpi_integer coord_type;
+ acpi_integer num_processors;
+} __attribute__ ((packed));
+
struct acpi_pct_register {
u8 descriptor;
u16 length;
@@ -91,7 +111,9 @@ struct acpi_processor_performance {
struct acpi_pct_register status_register;
unsigned int state_count;
struct acpi_processor_px *states;
-
+ struct acpi_psd_package domain_info;
+ cpumask_t shared_cpu_map;
+ unsigned int shared_type;
};
/* Throttling Control */
@@ -160,6 +182,9 @@ struct acpi_processor_errata {
} piix4;
};
+extern int acpi_processor_preregister_performance(
+ struct acpi_processor_performance **performance);
+
extern int acpi_processor_register_performance(struct acpi_processor_performance
*performance, unsigned int cpu);
extern void acpi_processor_unregister_performance(struct
diff --git a/include/asm-alpha/floppy.h b/include/asm-alpha/floppy.h
index e177d41..21816d3 100644
--- a/include/asm-alpha/floppy.h
+++ b/include/asm-alpha/floppy.h
@@ -25,9 +25,8 @@
#define fd_enable_irq() enable_irq(FLOPPY_IRQ)
#define fd_disable_irq() disable_irq(FLOPPY_IRQ)
#define fd_cacheflush(addr,size) /* nothing */
-#define fd_request_irq() request_irq(FLOPPY_IRQ, floppy_interrupt, \
- SA_INTERRUPT|SA_SAMPLE_RANDOM, \
- "floppy", NULL)
+#define fd_request_irq() request_irq(FLOPPY_IRQ, floppy_interrupt,\
+ SA_INTERRUPT, "floppy", NULL)
#define fd_free_irq() free_irq(FLOPPY_IRQ, NULL);
#ifdef CONFIG_PCI
diff --git a/include/asm-alpha/irq.h b/include/asm-alpha/irq.h
index f6de033..917b9fe 100644
--- a/include/asm-alpha/irq.h
+++ b/include/asm-alpha/irq.h
@@ -92,8 +92,4 @@ extern void enable_irq(unsigned int);
struct pt_regs;
extern void (*perf_irq)(unsigned long, struct pt_regs *);
-struct irqaction;
-int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
-
-
#endif /* _ALPHA_IRQ_H */
diff --git a/include/asm-alpha/vga.h b/include/asm-alpha/vga.h
index 8ca4f6b..ed06f59b 100644
--- a/include/asm-alpha/vga.h
+++ b/include/asm-alpha/vga.h
@@ -46,6 +46,6 @@ extern void scr_memcpyw(u16 *d, const u16 *s, unsigned int count);
#define vga_readb(a) readb((u8 __iomem *)(a))
#define vga_writeb(v,a) writeb(v, (u8 __iomem *)(a))
-#define VGA_MAP_MEM(x) ((unsigned long) ioremap(x, 0))
+#define VGA_MAP_MEM(x,s) ((unsigned long) ioremap(x, s))
#endif
diff --git a/include/asm-arm/arch-aaec2000/io.h b/include/asm-arm/arch-aaec2000/io.h
index 8d67907..d710204 100644
--- a/include/asm-arm/arch-aaec2000/io.h
+++ b/include/asm-arm/arch-aaec2000/io.h
@@ -16,6 +16,5 @@
*/
#define __io(a) ((void __iomem *)(a))
#define __mem_pci(a) (a)
-#define __mem_isa(a) (a)
#endif
diff --git a/include/asm-arm/arch-clps711x/io.h b/include/asm-arm/arch-clps711x/io.h
index 62613b0..53d7902 100644
--- a/include/asm-arm/arch-clps711x/io.h
+++ b/include/asm-arm/arch-clps711x/io.h
@@ -26,7 +26,6 @@
#define __io(a) ((void __iomem *)(a))
#define __mem_pci(a) (a)
-#define __mem_isa(a) (a)
/*
* We don't support ins[lb]/outs[lb]. Make them fault.
diff --git a/include/asm-arm/arch-ebsa285/io.h b/include/asm-arm/arch-ebsa285/io.h
index 776f9d3..f9c7291 100644
--- a/include/asm-arm/arch-ebsa285/io.h
+++ b/include/asm-arm/arch-ebsa285/io.h
@@ -24,7 +24,6 @@
#define __io(a) ((void __iomem *)(PCIO_BASE + (a)))
#if 1
#define __mem_pci(a) (a)
-#define __mem_isa(a) ((a) + PCIMEM_BASE)
#else
static inline void __iomem *___mem_pci(void __iomem *p)
@@ -34,14 +33,7 @@ static inline void __iomem *___mem_pci(void __iomem *p)
return p;
}
-static inline void __iomem *___mem_isa(void __iomem *p)
-{
- unsigned long a = (unsigned long)p;
- BUG_ON(a >= 16*1048576);
- return p + PCIMEM_BASE;
-}
#define __mem_pci(a) ___mem_pci(a)
-#define __mem_isa(a) ___mem_isa(a)
#endif
#endif
diff --git a/include/asm-arm/arch-ep93xx/ep93xx-regs.h b/include/asm-arm/arch-ep93xx/ep93xx-regs.h
index 71cea0b..8c32297 100644
--- a/include/asm-arm/arch-ep93xx/ep93xx-regs.h
+++ b/include/asm-arm/arch-ep93xx/ep93xx-regs.h
@@ -115,6 +115,8 @@
#define EP93XX_SYSCON_CLOCK_USH_EN 0x10000000
#define EP93XX_SYSCON_HALT EP93XX_SYSCON_REG(0x08)
#define EP93XX_SYSCON_STANDBY EP93XX_SYSCON_REG(0x0c)
+#define EP93XX_SYSCON_CLOCK_SET1 EP93XX_SYSCON_REG(0x20)
+#define EP93XX_SYSCON_CLOCK_SET2 EP93XX_SYSCON_REG(0x24)
#define EP93XX_SYSCON_DEVICE_CONFIG EP93XX_SYSCON_REG(0x80)
#define EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE 0x00800000
#define EP93XX_SYSCON_SWLOCK EP93XX_SYSCON_REG(0xc0)
diff --git a/include/asm-arm/arch-ep93xx/platform.h b/include/asm-arm/arch-ep93xx/platform.h
index df9cbb6..d7a34ce 100644
--- a/include/asm-arm/arch-ep93xx/platform.h
+++ b/include/asm-arm/arch-ep93xx/platform.h
@@ -8,6 +8,7 @@ void ep93xx_map_io(void);
void ep93xx_init_irq(void);
void ep93xx_init_time(unsigned long);
void ep93xx_init_devices(void);
+void ep93xx_clock_init(void);
extern struct sys_timer ep93xx_timer;
diff --git a/include/asm-arm/arch-imx/imx-dma.h b/include/asm-arm/arch-imx/imx-dma.h
index f2063c1..599f03e 100644
--- a/include/asm-arm/arch-imx/imx-dma.h
+++ b/include/asm-arm/arch-imx/imx-dma.h
@@ -46,7 +46,7 @@
struct imx_dma_channel {
const char *name;
void (*irq_handler) (int, void *, struct pt_regs *);
- void (*err_handler) (int, void *, struct pt_regs *);
+ void (*err_handler) (int, void *, struct pt_regs *, int errcode);
void *data;
dmamode_t dma_mode;
struct scatterlist *sg;
@@ -58,6 +58,10 @@ struct imx_dma_channel {
extern struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS];
+#define IMX_DMA_ERR_BURST 1
+#define IMX_DMA_ERR_REQUEST 2
+#define IMX_DMA_ERR_TRANSFER 4
+#define IMX_DMA_ERR_BUFFER 8
/* The type to distinguish channel numbers parameter from ordinal int type */
typedef int imx_dmach_t;
@@ -74,7 +78,7 @@ imx_dma_setup_sg(imx_dmach_t dma_ch,
int
imx_dma_setup_handlers(imx_dmach_t dma_ch,
void (*irq_handler) (int, void *, struct pt_regs *),
- void (*err_handler) (int, void *, struct pt_regs *), void *data);
+ void (*err_handler) (int, void *, struct pt_regs *, int), void *data);
void imx_dma_enable(imx_dmach_t dma_ch);
diff --git a/include/asm-arm/arch-integrator/io.h b/include/asm-arm/arch-integrator/io.h
index 31f2dea..c8f2175 100644
--- a/include/asm-arm/arch-integrator/io.h
+++ b/include/asm-arm/arch-integrator/io.h
@@ -32,6 +32,5 @@
#define __io(a) ((void __iomem *)(PCI_IO_VADDR + (a)))
#define __mem_pci(a) (a)
-#define __mem_isa(a) ((a) + PCI_MEMORY_VADDR)
#endif
diff --git a/include/asm-arm/arch-iop3xx/io.h b/include/asm-arm/arch-iop3xx/io.h
index f39046a..36adbdf 100644
--- a/include/asm-arm/arch-iop3xx/io.h
+++ b/include/asm-arm/arch-iop3xx/io.h
@@ -17,6 +17,5 @@
#define __io(p) ((void __iomem *)(p))
#define __mem_pci(a) (a)
-#define __mem_isa(a) (a)
#endif
diff --git a/include/asm-arm/arch-ixp23xx/ixp23xx.h b/include/asm-arm/arch-ixp23xx/ixp23xx.h
index 01efdbd..d0a7220 100644
--- a/include/asm-arm/arch-ixp23xx/ixp23xx.h
+++ b/include/asm-arm/arch-ixp23xx/ixp23xx.h
@@ -124,6 +124,7 @@
#define IXP23XX_EXP_UNIT_FUSE IXP23XX_EXP_CFG_REG(0x28)
#define IXP23XX_EXP_MSF_MUX IXP23XX_EXP_CFG_REG(0x30)
+#define IXP23XX_EXP_CFG_FUSE IXP23XX_EXP_CFG_REG(0x34)
#define IXP23XX_EXP_BUS_PHYS 0x90000000
#define IXP23XX_EXP_BUS_WINDOW_SIZE 0x01000000
@@ -265,6 +266,8 @@
#define IXP23XX_PCI_UNIT_RESET (1 << 1)
#define IXP23XX_XSCALE_RESET (1 << 0)
+#define IXP23XX_UENGINE_CSR_VIRT_BASE (IXP23XX_CAP_CSR_VIRT + 0x18000)
+
/****************************************************************************
* PCI CSRs.
diff --git a/include/asm-arm/arch-ixp23xx/platform.h b/include/asm-arm/arch-ixp23xx/platform.h
index e4d9906..19a73b3 100644
--- a/include/asm-arm/arch-ixp23xx/platform.h
+++ b/include/asm-arm/arch-ixp23xx/platform.h
@@ -14,6 +14,21 @@
#ifndef __ASSEMBLY__
+extern inline unsigned long ixp2000_reg_read(volatile void *reg)
+{
+ return *((volatile unsigned long *)reg);
+}
+
+extern inline void ixp2000_reg_write(volatile void *reg, unsigned long val)
+{
+ *((volatile unsigned long *)reg) = val;
+}
+
+extern inline void ixp2000_reg_wrb(volatile void *reg, unsigned long val)
+{
+ *((volatile unsigned long *)reg) = val;
+}
+
struct pci_sys_data;
void ixp23xx_map_io(void);
diff --git a/include/asm-arm/arch-l7200/io.h b/include/asm-arm/arch-l7200/io.h
index cab8ad0..cd080d8 100644
--- a/include/asm-arm/arch-l7200/io.h
+++ b/include/asm-arm/arch-l7200/io.h
@@ -19,7 +19,6 @@
*/
#define __io_pci(a) ((void __iomem *)(PCIO_BASE + (a)))
#define __mem_pci(a) (a)
-#define __mem_isa(a) (a)
#define __ioaddr(p) __io_pci(p)
diff --git a/include/asm-arm/arch-lh7a40x/io.h b/include/asm-arm/arch-lh7a40x/io.h
index bbcd433..17bc94097 100644
--- a/include/asm-arm/arch-lh7a40x/io.h
+++ b/include/asm-arm/arch-lh7a40x/io.h
@@ -18,6 +18,5 @@
/* No ISA or PCI bus on this machine. */
#define __io(a) ((void __iomem *)(a))
#define __mem_pci(a) (a)
-#define __mem_isa(a) (a)
#endif /* __ASM_ARCH_IO_H */
diff --git a/include/asm-arm/arch-netx/eth.h b/include/asm-arm/arch-netx/eth.h
new file mode 100644
index 0000000..643c90e
--- /dev/null
+++ b/include/asm-arm/arch-netx/eth.h
@@ -0,0 +1,27 @@
+/*
+ * include/asm-arm/arch-netx/eth.h
+ *
+ * Copyright (c) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef ASMARM_ARCH_ETH_H
+#define ASMARM_ARCH_ETH_H
+
+struct netxeth_platform_data {
+ unsigned int xcno; /* number of xmac/xpec engine this eth uses */
+};
+
+#endif
diff --git a/include/asm-arm/arch-netx/io.h b/include/asm-arm/arch-netx/io.h
index 81b7bc4..a7a53f8 100644
--- a/include/asm-arm/arch-netx/io.h
+++ b/include/asm-arm/arch-netx/io.h
@@ -24,6 +24,5 @@
#define __io(a) ((void __iomem *)(a))
#define __mem_pci(a) (a)
-#define __mem_isa(a) (a)
#endif
diff --git a/include/asm-arm/arch-omap/io.h b/include/asm-arm/arch-omap/io.h
index b726acf..78f68e6 100644
--- a/include/asm-arm/arch-omap/io.h
+++ b/include/asm-arm/arch-omap/io.h
@@ -44,7 +44,6 @@
*/
#define __io(a) ((void __iomem *)(PCIO_BASE + (a)))
#define __mem_pci(a) (a)
-#define __mem_isa(a) (a)
/*
* ----------------------------------------------------------------------------
diff --git a/include/asm-arm/arch-pnx4008/debug-macro.S b/include/asm-arm/arch-pnx4008/debug-macro.S
index eb3839d..67d18a2 100644
--- a/include/asm-arm/arch-pnx4008/debug-macro.S
+++ b/include/asm-arm/arch-pnx4008/debug-macro.S
@@ -19,9 +19,5 @@
addne \rx, \rx, #0xf4000000
.endm
- .macro senduart,rd,rx
- strb \rd, [\rx, #0x0]
- .endm
-
#define UART_SHIFT 2
#include <asm/hardware/debug-8250.S>
diff --git a/include/asm-arm/arch-pnx4008/gpio.h b/include/asm-arm/arch-pnx4008/gpio.h
index 1fa5a77..d01bf83 100644
--- a/include/asm-arm/arch-pnx4008/gpio.h
+++ b/include/asm-arm/arch-pnx4008/gpio.h
@@ -127,6 +127,79 @@
#define GPIO_ISOUT(K) ((GPIO_TYPE_MASK(K) == GPIO_OUT) && (GPIO_BIT(K) & GPIO_OUT_MASK))
#define GPIO_ISIN(K) ((GPIO_TYPE_MASK(K) == GPIO_IN) && (GPIO_BIT(K) & GPIO_IN_MASK))
+/* Start Enable Pin Interrupts - table 58 page 66 */
+
+#define SE_PIN_BASE_INT 32
+
+#define SE_U7_RX_INT 63
+#define SE_U7_HCTS_INT 62
+#define SE_BT_CLKREQ_INT 61
+#define SE_U6_IRRX_INT 60
+/*59 unused*/
+#define SE_U5_RX_INT 58
+#define SE_GPI_11_INT 57
+#define SE_U3_RX_INT 56
+#define SE_U2_HCTS_INT 55
+#define SE_U2_RX_INT 54
+#define SE_U1_RX_INT 53
+#define SE_DISP_SYNC_INT 52
+/*51 unused*/
+#define SE_SDIO_INT_N 50
+#define SE_MSDIO_START_INT 49
+#define SE_GPI_06_INT 48
+#define SE_GPI_05_INT 47
+#define SE_GPI_04_INT 46
+#define SE_GPI_03_INT 45
+#define SE_GPI_02_INT 44
+#define SE_GPI_01_INT 43
+#define SE_GPI_00_INT 42
+#define SE_SYSCLKEN_PIN_INT 41
+#define SE_SPI1_DATAIN_INT 40
+#define SE_GPI_07_INT 39
+#define SE_SPI2_DATAIN_INT 38
+#define SE_GPI_10_INT 37
+#define SE_GPI_09_INT 36
+#define SE_GPI_08_INT 35
+/*34-32 unused*/
+
+/* Start Enable Internal Interrupts - table 57 page 65 */
+
+#define SE_INT_BASE_INT 0
+
+#define SE_TS_IRQ 31
+#define SE_TS_P_INT 30
+#define SE_TS_AUX_INT 29
+/*27-28 unused*/
+#define SE_USB_AHB_NEED_CLK_INT 26
+#define SE_MSTIMER_INT 25
+#define SE_RTC_INT 24
+#define SE_USB_NEED_CLK_INT 23
+#define SE_USB_INT 22
+#define SE_USB_I2C_INT 21
+#define SE_USB_OTG_TIMER_INT 20
+#define SE_USB_OTG_ATX_INT_N 19
+/*18 unused*/
+#define SE_DSP_GPIO4_INT 17
+#define SE_KEY_IRQ 16
+#define SE_DSP_SLAVEPORT_INT 15
+#define SE_DSP_GPIO1_INT 14
+#define SE_DSP_GPIO0_INT 13
+#define SE_DSP_AHB_INT 12
+/*11-6 unused*/
+#define SE_GPIO_05_INT 5
+#define SE_GPIO_04_INT 4
+#define SE_GPIO_03_INT 3
+#define SE_GPIO_02_INT 2
+#define SE_GPIO_01_INT 1
+#define SE_GPIO_00_INT 0
+
+#define START_INT_REG_BIT(irq) (1<<((irq)&0x1F))
+
+#define START_INT_ER_REG(irq) IO_ADDRESS((PNX4008_PWRMAN_BASE + 0x20 + (((irq)&(0x1<<5))>>1)))
+#define START_INT_RSR_REG(irq) IO_ADDRESS((PNX4008_PWRMAN_BASE + 0x24 + (((irq)&(0x1<<5))>>1)))
+#define START_INT_SR_REG(irq) IO_ADDRESS((PNX4008_PWRMAN_BASE + 0x28 + (((irq)&(0x1<<5))>>1)))
+#define START_INT_APR_REG(irq) IO_ADDRESS((PNX4008_PWRMAN_BASE + 0x2C + (((irq)&(0x1<<5))>>1)))
+
extern int pnx4008_gpio_register_pin(unsigned short pin);
extern int pnx4008_gpio_unregister_pin(unsigned short pin);
extern unsigned long pnx4008_gpio_read_pin(unsigned short pin);
@@ -136,4 +209,33 @@ extern int pnx4008_gpio_read_pin_direction(unsigned short pin);
extern int pnx4008_gpio_set_pin_mux(unsigned short pin, int output);
extern int pnx4008_gpio_read_pin_mux(unsigned short pin);
+static inline void start_int_umask(u8 irq)
+{
+ __raw_writel(__raw_readl(START_INT_ER_REG(irq)) |
+ START_INT_REG_BIT(irq), START_INT_ER_REG(irq));
+}
+
+static inline void start_int_mask(u8 irq)
+{
+ __raw_writel(__raw_readl(START_INT_ER_REG(irq)) &
+ ~START_INT_REG_BIT(irq), START_INT_ER_REG(irq));
+}
+
+static inline void start_int_ack(u8 irq)
+{
+ __raw_writel(START_INT_REG_BIT(irq), START_INT_RSR_REG(irq));
+}
+
+static inline void start_int_set_falling_edge(u8 irq)
+{
+ __raw_writel(__raw_readl(START_INT_APR_REG(irq)) &
+ ~START_INT_REG_BIT(irq), START_INT_APR_REG(irq));
+}
+
+static inline void start_int_set_rising_edge(u8 irq)
+{
+ __raw_writel(__raw_readl(START_INT_APR_REG(irq)) |
+ START_INT_REG_BIT(irq), START_INT_APR_REG(irq));
+}
+
#endif /* _PNX4008_GPIO_H_ */
diff --git a/include/asm-arm/arch-pnx4008/pm.h b/include/asm-arm/arch-pnx4008/pm.h
index c660486..bac1634c 100644
--- a/include/asm-arm/arch-pnx4008/pm.h
+++ b/include/asm-arm/arch-pnx4008/pm.h
@@ -29,34 +29,5 @@ extern void pnx4008_cpu_standby(void);
extern int pnx4008_startup_pll(struct clk *);
extern int pnx4008_shutdown_pll(struct clk *);
-static inline void start_int_umask(u8 irq)
-{
- __raw_writel(__raw_readl(START_INT_ER_REG(irq)) |
- START_INT_REG_BIT(irq), START_INT_ER_REG(irq));
-}
-
-static inline void start_int_mask(u8 irq)
-{
- __raw_writel(__raw_readl(START_INT_ER_REG(irq)) &
- ~START_INT_REG_BIT(irq), START_INT_ER_REG(irq));
-}
-
-static inline void start_int_ack(u8 irq)
-{
- __raw_writel(START_INT_REG_BIT(irq), START_INT_RSR_REG(irq));
-}
-
-static inline void start_int_set_falling_edge(u8 irq)
-{
- __raw_writel(__raw_readl(START_INT_APR_REG(irq)) &
- ~START_INT_REG_BIT(irq), START_INT_APR_REG(irq));
-}
-
-static inline void start_int_set_rising_edge(u8 irq)
-{
- __raw_writel(__raw_readl(START_INT_APR_REG(irq)) |
- START_INT_REG_BIT(irq), START_INT_APR_REG(irq));
-}
-
#endif /* ASSEMBLER */
#endif /* __ASM_ARCH_PNX4008_PM_H */
diff --git a/include/asm-arm/arch-pxa/io.h b/include/asm-arm/arch-pxa/io.h
index eb2dd58..7f8d817 100644
--- a/include/asm-arm/arch-pxa/io.h
+++ b/include/asm-arm/arch-pxa/io.h
@@ -16,6 +16,5 @@
*/
#define __io(a) ((void __iomem *)(a))
#define __mem_pci(a) (a)
-#define __mem_isa(a) (a)
#endif
diff --git a/include/asm-arm/arch-realview/io.h b/include/asm-arm/arch-realview/io.h
index d444a68..c70f1df 100644
--- a/include/asm-arm/arch-realview/io.h
+++ b/include/asm-arm/arch-realview/io.h
@@ -29,6 +29,5 @@ static inline void __iomem *__io(unsigned long addr)
#define __io(a) __io(a)
#define __mem_pci(a) (a)
-#define __mem_isa(a) (a)
#endif
diff --git a/include/asm-arm/arch-s3c2410/debug-macro.S b/include/asm-arm/arch-s3c2410/debug-macro.S
index 5f8223e..b7d15d1 100644
--- a/include/asm-arm/arch-s3c2410/debug-macro.S
+++ b/include/asm-arm/arch-s3c2410/debug-macro.S
@@ -33,7 +33,7 @@
.endm
.macro senduart,rd,rx
- str \rd, [\rx, # S3C2410_UTXH ]
+ strb \rd, [\rx, # S3C2410_UTXH ]
.endm
.macro busyuart, rd, rx
@@ -42,6 +42,12 @@
beq 1001f @
@ FIFO enabled...
1003:
+ @ check for arm920 vs arm926. currently assume all arm926
+ @ devices have an 64 byte FIFO identical to the s3c2440
+ mrc p15, 0, \rd, c0, c0
+ and \rd, \rd, #0xff0
+ teq \rd, #0x260
+ beq 1004f
mrc p15, 0, \rd, c1, c0
tst \rd, #1
addeq \rd, \rx, #(S3C24XX_PA_GPIO - S3C24XX_PA_UART)
@@ -50,7 +56,7 @@
ldr \rd, [ \rd, # S3C2410_GSTATUS1 - S3C2410_GPIOREG(0) ]
and \rd, \rd, #0x00ff0000
teq \rd, #0x00440000 @ is it 2440?
-
+1004:
ldr \rd, [ \rx, # S3C2410_UFSTAT ]
moveq \rd, \rd, lsr #SHIFT_2440TXF
tst \rd, #S3C2410_UFSTAT_TXFULL
diff --git a/include/asm-arm/arch-s3c2410/entry-macro.S b/include/asm-arm/arch-s3c2410/entry-macro.S
index 894c35c..e09a6b8 100644
--- a/include/asm-arm/arch-s3c2410/entry-macro.S
+++ b/include/asm-arm/arch-s3c2410/entry-macro.S
@@ -18,8 +18,6 @@
#define INTPND (0x10)
#define INTOFFSET (0x14)
-#define EXTINTPEND (0xa8)
-#define EXTINTMASK (0xa4)
#include <asm/hardware.h>
#include <asm/arch/irqs.h>
@@ -28,37 +26,23 @@
mov \base, #S3C24XX_VA_IRQ
- ldr \irqstat, [ \base, #INTPND]
- bics \irqnr, \irqstat, #3<<4 @@ only an GPIO IRQ
- beq 2000f
-
@@ try the interrupt offset register, since it is there
+ ldr \irqstat, [ \base, #INTPND ]
+ teq \irqstat, #0
+ beq 1002f
ldr \irqnr, [ \base, #INTOFFSET ]
mov \tmp, #1
tst \irqstat, \tmp, lsl \irqnr
- addne \irqnr, \irqnr, #IRQ_EINT0
bne 1001f
@@ the number specified is not a valid irq, so try
@@ and work it out for ourselves
- mov \irqnr, #IRQ_EINT0 @@ start here
- b 3000f
-
-2000:
- @@ load the GPIO interrupt register, and check it
-
- add \tmp, \base, #S3C24XX_VA_GPIO - S3C24XX_VA_IRQ
- ldr \irqstat, [ \tmp, # EXTINTPEND ]
- ldr \irqnr, [ \tmp, # EXTINTMASK ]
- bics \irqstat, \irqstat, \irqnr
- beq 1001f
-
- mov \irqnr, #(IRQ_EINT4 - 4)
+ mov \irqnr, #0 @@ start here
@@ work out which irq (if any) we got
-3000:
+
movs \tmp, \irqstat, lsl#16
addeq \irqnr, \irqnr, #16
moveq \irqstat, \irqstat, lsr#16
@@ -75,9 +59,9 @@
addeq \irqnr, \irqnr, #1
@@ we have the value
- movs \irqnr, \irqnr
-
1001:
+ adds \irqnr, \irqnr, #IRQ_EINT0
+1002:
@@ exit here, Z flag unset if IRQ
.endm
diff --git a/include/asm-arm/arch-s3c2410/map.h b/include/asm-arm/arch-s3c2410/map.h
index 5e4c8c3..fae2766 100644
--- a/include/asm-arm/arch-s3c2410/map.h
+++ b/include/asm-arm/arch-s3c2410/map.h
@@ -236,4 +236,20 @@
#define S3C24XX_PA_SPI S3C2410_PA_SPI
#endif
+/* deal with the registers that move under the 2412/2413 */
+
+#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
+#ifndef __ASSEMBLY__
+extern void __iomem *s3c24xx_va_gpio2;
+#endif
+#ifdef CONFIG_CPU_S3C2412_ONLY
+#define S3C24XX_VA_GPIO2 (S3C24XX_VA_GPIO + 0x10)
+#else
+#define S3C24XX_VA_GPIO2 s3c24xx_va_gpio2
+#endif
+#else
+#define s3c24xx_va_gpio2 S3C24XX_VA_GPIO
+#define S3C24XX_VA_GPIO2 S3C24XX_VA_GPIO
+#endif
+
#endif /* __ASM_ARCH_MAP_H */
diff --git a/include/asm-arm/arch-s3c2410/regs-clock.h b/include/asm-arm/arch-s3c2410/regs-clock.h
index 6c92faf..a7c61fe 100644
--- a/include/asm-arm/arch-s3c2410/regs-clock.h
+++ b/include/asm-arm/arch-s3c2410/regs-clock.h
@@ -1,6 +1,6 @@
/* linux/include/asm/arch-s3c2410/regs-clock.h
*
- * Copyright (c) 2003,2004,2005 Simtec Electronics <linux@simtec.co.uk>
+ * Copyright (c) 2003,2004,2005,2006 Simtec Electronics <linux@simtec.co.uk>
* http://armlinux.simtec.co.uk/
*
* This program is free software; you can redistribute it and/or modify
@@ -140,5 +140,66 @@ s3c2410_get_pll(unsigned int pllval, unsigned int baseclk)
#endif /* CONFIG_CPU_S3C2440 or CONFIG_CPU_S3C2442 */
+#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
+
+#define S3C2412_OSCSET S3C2410_CLKREG(0x18)
+#define S3C2412_CLKSRC S3C2410_CLKREG(0x1C)
+
+#define S3C2412_PLLCON_OFF (1<<20)
+
+#define S3C2412_CLKDIVN_PDIVN (1<<2)
+#define S3C2412_CLKDIVN_HDIVN_MASK (3<<0)
+#define S3C2421_CLKDIVN_ARMDIVN (1<<3)
+#define S3C2412_CLKDIVN_USB48DIV (1<<6)
+#define S3C2412_CLKDIVN_UARTDIV_MASK (15<<8)
+#define S3C2412_CLKDIVN_UARTDIV_SHIFT (8)
+#define S3C2412_CLKDIVN_I2SDIV_MASK (15<<12)
+#define S3C2412_CLKDIVN_I2SDIV_SHIFT (12)
+#define S3C2412_CLKDIVN_CAMDIV_MASK (15<<16)
+#define S3C2412_CLKDIVN_CAMDIV_SHIFT (16)
+
+#define S3C2412_CLKCON_WDT (1<<28)
+#define S3C2412_CLKCON_SPI (1<<27)
+#define S3C2412_CLKCON_IIS (1<<26)
+#define S3C2412_CLKCON_IIC (1<<25)
+#define S3C2412_CLKCON_ADC (1<<24)
+#define S3C2412_CLKCON_RTC (1<<23)
+#define S3C2412_CLKCON_GPIO (1<<22)
+#define S3C2412_CLKCON_UART2 (1<<21)
+#define S3C2412_CLKCON_UART1 (1<<20)
+#define S3C2412_CLKCON_UART0 (1<<19)
+#define S3C2412_CLKCON_SDI (1<<18)
+#define S3C2412_CLKCON_PWMT (1<<17)
+#define S3C2412_CLKCON_USBD (1<<16)
+#define S3C2412_CLKCON_CAMCLK (1<<15)
+#define S3C2412_CLKCON_UARTCLK (1<<14)
+/* missing 13 */
+#define S3C2412_CLKCON_USB_HOST48 (1<<12)
+#define S3C2412_CLKCON_USB_DEV48 (1<<11)
+#define S3C2412_CLKCON_HCLKdiv2 (1<<10)
+#define S3C2412_CLKCON_HCLKx2 (1<<9)
+#define S3C2412_CLKCON_SDRAM (1<<8)
+/* missing 7 */
+#define S3C2412_CLKCON_USBH S3C2410_CLKCON_USBH
+#define S3C2412_CLKCON_LCDC S3C2410_CLKCON_LCDC
+#define S3C2412_CLKCON_NAND S3C2410_CLKCON_NAND
+#define S3C2412_CLKCON_DMA3 (1<<3)
+#define S3C2412_CLKCON_DMA2 (1<<2)
+#define S3C2412_CLKCON_DMA1 (1<<1)
+#define S3C2412_CLKCON_DMA0 (1<<0)
+
+/* clock sourec controls */
+
+#define S3C2412_CLKSRC_EXTCLKDIV_MASK (7 << 0)
+#define S3C2412_CLKSRC_EXTCLKDIV_SHIFT (0)
+#define S3C2412_CLKSRC_MDIVCLK_EXTCLKDIV (1<<3)
+#define S3C2412_CLKSRC_MSYSCLK_MPLL (1<<4)
+#define S3C2412_CLKSRC_USYSCLK_UPLL (1<<5)
+#define S3C2412_CLKSRC_UARTCLK_MPLL (1<<8)
+#define S3C2412_CLKSRC_I2SCLK_MPLL (1<<9)
+#define S3C2412_CLKSRC_USBCLK_HCLK (1<<10)
+#define S3C2412_CLKSRC_CAMCLK_HCLK (1<<11)
+
+#endif /* CONFIG_CPU_S3C2412 | CONFIG_CPU_S3C2413 */
#endif /* __ASM_ARM_REGS_CLOCK */
diff --git a/include/asm-arm/arch-s3c2410/regs-dsc.h b/include/asm-arm/arch-s3c2410/regs-dsc.h
index a023b04..84aca61 100644
--- a/include/asm-arm/arch-s3c2410/regs-dsc.h
+++ b/include/asm-arm/arch-s3c2410/regs-dsc.h
@@ -23,6 +23,9 @@
#define S3C2440_DSC0 S3C2410_GPIOREG(0xc4)
#define S3C2440_DSC1 S3C2410_GPIOREG(0xc8)
+#define S3C2412_DSC0 S3C2410_GPIOREG(0xdc)
+#define S3C2412_DSC1 S3C2410_GPIOREG(0xe0)
+
#define S3C2440_SELECT_DSC0 (0)
#define S3C2440_SELECT_DSC1 (1<<31)
@@ -170,7 +173,7 @@
#define S3C2440_DSC1_CS1_4mA (3<<2)
#define S3C2440_DSC1_CS1_MASK (3<<2)
-#define S3C2440_DSC1_CS0 (S3C2440_SELECT_DSC1 | 0
+#define S3C2440_DSC1_CS0 (S3C2440_SELECT_DSC1 | 0)
#define S3C2440_DSC1_CS0_10mA (0<<0)
#define S3C2440_DSC1_CS0_8mA (1<<0)
#define S3C2440_DSC1_CS0_6mA (2<<0)
diff --git a/include/asm-arm/arch-s3c2410/regs-gpio.h b/include/asm-arm/arch-s3c2410/regs-gpio.h
index 5f10334..6dd17f0f 100644
--- a/include/asm-arm/arch-s3c2410/regs-gpio.h
+++ b/include/asm-arm/arch-s3c2410/regs-gpio.h
@@ -45,7 +45,7 @@
#define S3C24XX_MISCCR S3C2400_MISCCR
#else
#define S3C24XX_GPIO_BASE(x) S3C2410_GPIO_BASE(x)
-#define S3C24XX_MISCCR S3C2410_MISCCR
+#define S3C24XX_MISCCR S3C24XX_GPIOREG2(0x80)
#endif /* CONFIG_CPU_S3C2400 */
@@ -73,9 +73,15 @@
#define S3C2410_GPIO_SFN2 (0xFFFFFFF2) /* not available on A */
#define S3C2410_GPIO_SFN3 (0xFFFFFFF3) /* not available on A */
-/* configure GPIO ports A..G */
+/* register address for the GPIO registers.
+ * S3C24XX_GPIOREG2 is for the second set of registers in the
+ * GPIO which move between s3c2410 and s3c2412 type systems */
#define S3C2410_GPIOREG(x) ((x) + S3C24XX_VA_GPIO)
+#define S3C24XX_GPIOREG2(x) ((x) + S3C24XX_VA_GPIO2)
+
+
+/* configure GPIO ports A..G */
/* port A - S3C2410: 22bits, zero in bit X makes pin X output
* S3C2400: 18bits, zero in bit X makes pin X output
@@ -953,11 +959,18 @@
#define S3C2410_GPH10_OUTP (0x01 << 20)
#define S3C2410_GPH10_CLKOUT1 (0x02 << 20)
+/* The S3C2412 and S3C2413 move the GPJ register set to after
+ * GPH, which means all registers after 0x80 are now offset by 0x10
+ * for the 2412/2413 from the 2410/2440/2442
+*/
+
/* miscellaneous control */
#define S3C2400_MISCCR S3C2410_GPIOREG(0x54)
#define S3C2410_MISCCR S3C2410_GPIOREG(0x80)
#define S3C2410_DCLKCON S3C2410_GPIOREG(0x84)
+#define S3C24XX_DCLKCON S3C24XX_GPIOREG2(0x84)
+
/* see clock.h for dclk definitions */
/* pullup control on databus */
@@ -985,6 +998,8 @@
#define S3C2410_MISCCR_CLK0_DCLK0 (5<<4)
#define S3C2410_MISCCR_CLK0_MASK (7<<4)
+#define S3C2412_MISCCR_CLK0_RTC (2<<4)
+
#define S3C2410_MISCCR_CLK1_MPLL (0<<8)
#define S3C2410_MISCCR_CLK1_UPLL (1<<8)
#define S3C2410_MISCCR_CLK1_FCLK (2<<8)
@@ -993,6 +1008,8 @@
#define S3C2410_MISCCR_CLK1_DCLK1 (5<<8)
#define S3C2410_MISCCR_CLK1_MASK (7<<8)
+#define S3C2412_MISCCR_CLK1_CLKsrc (0<<8)
+
#define S3C2410_MISCCR_USBSUSPND0 (1<<12)
#define S3C2410_MISCCR_USBSUSPND1 (1<<13)
@@ -1000,7 +1017,7 @@
#define S3C2410_MISCCR_nEN_SCLK0 (1<<17)
#define S3C2410_MISCCR_nEN_SCLK1 (1<<18)
-#define S3C2410_MISCCR_nEN_SCLKE (1<<19)
+#define S3C2410_MISCCR_nEN_SCLKE (1<<19) /* not 2412 */
#define S3C2410_MISCCR_SDSLEEP (7<<17)
/* external interrupt control... */
@@ -1017,6 +1034,10 @@
#define S3C2410_EXTINT1 S3C2410_GPIOREG(0x8C)
#define S3C2410_EXTINT2 S3C2410_GPIOREG(0x90)
+#define S3C24XX_EXTINT0 S3C24XX_GPIOREG2(0x88)
+#define S3C24XX_EXTINT1 S3C24XX_GPIOREG2(0x8C)
+#define S3C24XX_EXTINT2 S3C24XX_GPIOREG2(0x90)
+
/* values for S3C2410_EXTINT0/1/2 */
#define S3C2410_EXTINT_LOWLEV (0x00)
#define S3C2410_EXTINT_HILEV (0x01)
@@ -1030,6 +1051,11 @@
#define S3C2410_EINFLT2 S3C2410_GPIOREG(0x9C)
#define S3C2410_EINFLT3 S3C2410_GPIOREG(0xA0)
+#define S3C24XX_EINFLT0 S3C24XX_GPIOREG2(0x94)
+#define S3C24XX_EINFLT1 S3C24XX_GPIOREG2(0x98)
+#define S3C24XX_EINFLT2 S3C24XX_GPIOREG2(0x9C)
+#define S3C24XX_EINFLT3 S3C24XX_GPIOREG2(0xA0)
+
/* values for interrupt filtering */
#define S3C2410_EINTFLT_PCLK (0x00)
#define S3C2410_EINTFLT_EXTCLK (1<<7)
@@ -1039,6 +1065,7 @@
/* GSTATUS have miscellaneous information in them
*
+ * These move between s3c2410 and s3c2412 style systems.
*/
#define S3C2410_GSTATUS0 S3C2410_GPIOREG(0x0AC)
@@ -1047,6 +1074,18 @@
#define S3C2410_GSTATUS3 S3C2410_GPIOREG(0x0B8)
#define S3C2410_GSTATUS4 S3C2410_GPIOREG(0x0BC)
+#define S3C2412_GSTATUS0 S3C2410_GPIOREG(0x0BC)
+#define S3C2412_GSTATUS1 S3C2410_GPIOREG(0x0C0)
+#define S3C2412_GSTATUS2 S3C2410_GPIOREG(0x0C4)
+#define S3C2412_GSTATUS3 S3C2410_GPIOREG(0x0C8)
+#define S3C2412_GSTATUS4 S3C2410_GPIOREG(0x0CC)
+
+#define S3C24XX_GSTATUS0 S3C24XX_GPIOREG2(0x0AC)
+#define S3C24XX_GSTATUS1 S3C24XX_GPIOREG2(0x0B0)
+#define S3C24XX_GSTATUS2 S3C24XX_GPIOREG2(0x0B4)
+#define S3C24XX_GSTATUS3 S3C24XX_GPIOREG2(0x0B8)
+#define S3C24XX_GSTATUS4 S3C24XX_GPIOREG2(0x0BC)
+
#define S3C2410_GSTATUS0_nWAIT (1<<3)
#define S3C2410_GSTATUS0_NCON (1<<2)
#define S3C2410_GSTATUS0_RnB (1<<1)
@@ -1054,6 +1093,7 @@
#define S3C2410_GSTATUS1_IDMASK (0xffff0000)
#define S3C2410_GSTATUS1_2410 (0x32410000)
+#define S3C2410_GSTATUS1_2412 (0x32412001)
#define S3C2410_GSTATUS1_2440 (0x32440000)
#define S3C2410_GSTATUS1_2442 (0x32440aaa)
@@ -1077,5 +1117,22 @@
#define S3C2400_OPENCR_OPC_MOSIDIS (0<<5)
#define S3C2400_OPENCR_OPC_MOSIEN (1<<5)
+/* 2412/2413 sleep configuration registers */
+
+#define S3C2412_GPBSLPCON S3C2410_GPIOREG(0x1C)
+#define S3C2412_GPCSLPCON S3C2410_GPIOREG(0x2C)
+#define S3C2412_GPDSLPCON S3C2410_GPIOREG(0x3C)
+#define S3C2412_GPESLPCON S3C2410_GPIOREG(0x4C)
+#define S3C2412_GPFSLPCON S3C2410_GPIOREG(0x5C)
+#define S3C2412_GPGSLPCON S3C2410_GPIOREG(0x6C)
+#define S3C2412_GPHSLPCON S3C2410_GPIOREG(0x7C)
+
+/* definitions for each pin bit */
+#define S3C2412_SLPCON_LOW(x) ( 0x00 << ((x) * 2))
+#define S3C2412_SLPCON_HI(x) ( 0x01 << ((x) * 2))
+#define S3C2412_SLPCON_IN(x) ( 0x02 << ((x) * 2))
+#define S3C2412_SLPCON_PDWN(x) ( 0x03 << ((x) * 2))
+#define S3C2412_SLPCON_MASK(x) ( 0x03 << ((x) * 2))
+
#endif /* __ASM_ARCH_REGS_GPIO_H */
diff --git a/include/asm-arm/arch-s3c2410/regs-gpioj.h b/include/asm-arm/arch-s3c2410/regs-gpioj.h
index 3ad2324..18edae5 100644
--- a/include/asm-arm/arch-s3c2410/regs-gpioj.h
+++ b/include/asm-arm/arch-s3c2410/regs-gpioj.h
@@ -32,6 +32,11 @@
#define S3C2440_GPJDAT S3C2410_GPIOREG(0xd4)
#define S3C2440_GPJUP S3C2410_GPIOREG(0xd8)
+#define S3C2413_GPJCON S3C2410_GPIOREG(0x80)
+#define S3C2413_GPJDAT S3C2410_GPIOREG(0x84)
+#define S3C2413_GPJUP S3C2410_GPIOREG(0x88)
+#define S3C2413_GPJSLPCON S3C2410_GPIOREG(0x8C)
+
#define S3C2440_GPJ0 S3C2410_GPIONO(S3C2440_GPIO_BANKJ, 0)
#define S3C2440_GPJ0_INP (0x00 << 0)
#define S3C2440_GPJ0_OUTP (0x01 << 0)
diff --git a/include/asm-arm/arch-s3c2410/regs-irq.h b/include/asm-arm/arch-s3c2410/regs-irq.h
index 24b7292..572fca5 100644
--- a/include/asm-arm/arch-s3c2410/regs-irq.h
+++ b/include/asm-arm/arch-s3c2410/regs-irq.h
@@ -23,6 +23,7 @@
#define S3C2410_IRQREG(x) ((x) + S3C24XX_VA_IRQ)
#define S3C2410_EINTREG(x) ((x) + S3C24XX_VA_GPIO)
+#define S3C24XX_EINTREG(x) ((x) + S3C24XX_VA_GPIO2)
#define S3C2410_SRCPND S3C2410_IRQREG(0x000)
#define S3C2410_INTMOD S3C2410_IRQREG(0x004)
@@ -40,5 +41,10 @@
#define S3C2410_EINTMASK S3C2410_EINTREG(0x0A4)
#define S3C2410_EINTPEND S3C2410_EINTREG(0X0A8)
+#define S3C2412_EINTMASK S3C2410_EINTREG(0x0B4)
+#define S3C2412_EINTPEND S3C2410_EINTREG(0X0B8)
+
+#define S3C24XX_EINTMASK S3C24XX_EINTREG(0x0A4)
+#define S3C24XX_EINTPEND S3C24XX_EINTREG(0X0A8)
#endif /* ___ASM_ARCH_REGS_IRQ_H */
diff --git a/include/asm-arm/arch-s3c2410/regs-serial.h b/include/asm-arm/arch-s3c2410/regs-serial.h
index 83b0125..93f651a 100644
--- a/include/asm-arm/arch-s3c2410/regs-serial.h
+++ b/include/asm-arm/arch-s3c2410/regs-serial.h
@@ -82,6 +82,12 @@
#define S3C2440_UCON2_DIVMASK (7 << 12)
#define S3C2440_UCON_DIVSHIFT (12)
+#define S3C2412_UCON_CLKMASK (3<<10)
+#define S3C2412_UCON_UCLK (1<<10)
+#define S3C2412_UCON_USYSCLK (3<<10)
+#define S3C2412_UCON_PCLK (0<<10)
+#define S3C2412_UCON_PCLK2 (2<<10)
+
#define S3C2410_UCON_UCLK (1<<10)
#define S3C2410_UCON_SBREAK (1<<4)
@@ -124,6 +130,15 @@
#define S3C2410_UMCOM_AFC (1<<4)
#define S3C2410_UMCOM_RTS_LOW (1<<0)
+#define S3C2412_UMCON_AFC_63 (0<<5)
+#define S3C2412_UMCON_AFC_56 (1<<5)
+#define S3C2412_UMCON_AFC_48 (2<<5)
+#define S3C2412_UMCON_AFC_40 (3<<5)
+#define S3C2412_UMCON_AFC_32 (4<<5)
+#define S3C2412_UMCON_AFC_24 (5<<5)
+#define S3C2412_UMCON_AFC_16 (6<<5)
+#define S3C2412_UMCON_AFC_8 (7<<5)
+
#define S3C2410_UFSTAT_TXFULL (1<<9)
#define S3C2410_UFSTAT_RXFULL (1<<8)
#define S3C2410_UFSTAT_TXMASK (15<<4)
diff --git a/include/asm-arm/arch-sa1100/io.h b/include/asm-arm/arch-sa1100/io.h
index 040ccde..0756269 100644
--- a/include/asm-arm/arch-sa1100/io.h
+++ b/include/asm-arm/arch-sa1100/io.h
@@ -22,6 +22,5 @@ static inline void __iomem *__io(unsigned long addr)
}
#define __io(a) __io(a)
#define __mem_pci(a) (a)
-#define __mem_isa(a) (a)
#endif
diff --git a/include/asm-arm/arch-versatile/io.h b/include/asm-arm/arch-versatile/io.h
index 47e904c..c4d0194 100644
--- a/include/asm-arm/arch-versatile/io.h
+++ b/include/asm-arm/arch-versatile/io.h
@@ -28,6 +28,5 @@ static inline void __iomem *__io(unsigned long addr)
}
#define __io(a) __io(a)
#define __mem_pci(a) (a)
-#define __mem_isa(a) (a)
#endif
diff --git a/include/asm-arm/floppy.h b/include/asm-arm/floppy.h
index 6ea657c..aa0c8d2 100644
--- a/include/asm-arm/floppy.h
+++ b/include/asm-arm/floppy.h
@@ -25,7 +25,7 @@
#define fd_inb(port) inb((port))
#define fd_request_irq() request_irq(IRQ_FLOPPYDISK,floppy_interrupt,\
- SA_INTERRUPT|SA_SAMPLE_RANDOM,"floppy",NULL)
+ SA_INTERRUPT,"floppy",NULL)
#define fd_free_irq() free_irq(IRQ_FLOPPYDISK,NULL)
#define fd_disable_irq() disable_irq(IRQ_FLOPPYDISK)
#define fd_enable_irq() enable_irq(IRQ_FLOPPYDISK)
diff --git a/include/asm-arm/irq.h b/include/asm-arm/irq.h
index 60b5105..66e67e6 100644
--- a/include/asm-arm/irq.h
+++ b/include/asm-arm/irq.h
@@ -47,10 +47,6 @@ void disable_irq_wake(unsigned int irq);
void enable_irq_wake(unsigned int irq);
int setup_irq(unsigned int, struct irqaction *);
-struct irqaction;
-struct pt_regs;
-int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
-
extern void migrate_irqs(void);
#endif
diff --git a/include/asm-arm/thread_notify.h b/include/asm-arm/thread_notify.h
new file mode 100644
index 0000000..8866e52
--- /dev/null
+++ b/include/asm-arm/thread_notify.h
@@ -0,0 +1,48 @@
+/*
+ * linux/include/asm-arm/thread_notify.h
+ *
+ * Copyright (C) 2006 Russell King.
+ *
+ * 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 ASMARM_THREAD_NOTIFY_H
+#define ASMARM_THREAD_NOTIFY_H
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+
+#include <linux/notifier.h>
+#include <asm/thread_info.h>
+
+static inline int thread_register_notifier(struct notifier_block *n)
+{
+ extern struct atomic_notifier_head thread_notify_head;
+ return atomic_notifier_chain_register(&thread_notify_head, n);
+}
+
+static inline void thread_unregister_notifier(struct notifier_block *n)
+{
+ extern struct atomic_notifier_head thread_notify_head;
+ atomic_notifier_chain_unregister(&thread_notify_head, n);
+}
+
+static inline void thread_notify(unsigned long rc, struct thread_info *thread)
+{
+ extern struct atomic_notifier_head thread_notify_head;
+ atomic_notifier_call_chain(&thread_notify_head, rc, thread);
+}
+
+#endif
+
+/*
+ * These are the reason codes for the thread notifier.
+ */
+#define THREAD_NOTIFY_FLUSH 0
+#define THREAD_NOTIFY_RELEASE 1
+#define THREAD_NOTIFY_SWITCH 2
+
+#endif
+#endif
diff --git a/include/asm-arm/ucontext.h b/include/asm-arm/ucontext.h
index f853130..9e6f7ca 100644
--- a/include/asm-arm/ucontext.h
+++ b/include/asm-arm/ucontext.h
@@ -1,12 +1,89 @@
#ifndef _ASMARM_UCONTEXT_H
#define _ASMARM_UCONTEXT_H
+#include <asm/fpstate.h>
+
+/*
+ * struct sigcontext only has room for the basic registers, but struct
+ * ucontext now has room for all registers which need to be saved and
+ * restored. Coprocessor registers are stored in uc_regspace. Each
+ * coprocessor's saved state should start with a documented 32-bit magic
+ * number, followed by a 32-bit word giving the coproccesor's saved size.
+ * uc_regspace may be expanded if necessary, although this takes some
+ * coordination with glibc.
+ */
+
struct ucontext {
unsigned long uc_flags;
struct ucontext *uc_link;
stack_t uc_stack;
struct sigcontext uc_mcontext;
- sigset_t uc_sigmask; /* mask last for extensibility */
+ sigset_t uc_sigmask;
+ /* Allow for uc_sigmask growth. Glibc uses a 1024-bit sigset_t. */
+ int __unused[32 - (sizeof (sigset_t) / sizeof (int))];
+ /* Last for extensibility. Eight byte aligned because some
+ coprocessors require eight byte alignment. */
+ unsigned long uc_regspace[128] __attribute__((__aligned__(8)));
};
+#ifdef __KERNEL__
+
+/*
+ * Coprocessor save state. The magic values and specific
+ * coprocessor's layouts are part of the userspace ABI. Each one of
+ * these should be a multiple of eight bytes and aligned to eight
+ * bytes, to prevent unpredictable padding in the signal frame.
+ */
+
+#ifdef CONFIG_IWMMXT
+/* iwmmxt_area is 0x98 bytes long, preceeded by 8 bytes of signature */
+#define IWMMXT_MAGIC 0x12ef842a
+#define IWMMXT_STORAGE_SIZE (IWMMXT_SIZE + 8)
+
+struct iwmmxt_sigframe {
+ unsigned long magic;
+ unsigned long size;
+ struct iwmmxt_struct storage;
+} __attribute__((__aligned__(8)));
+#endif /* CONFIG_IWMMXT */
+
+#ifdef CONFIG_VFP
+#if __LINUX_ARM_ARCH__ < 6
+/* For ARM pre-v6, we use fstmiax and fldmiax. This adds one extra
+ * word after the registers, and a word of padding at the end for
+ * alignment. */
+#define VFP_MAGIC 0x56465001
+#define VFP_STORAGE_SIZE 152
+#else
+#define VFP_MAGIC 0x56465002
+#define VFP_STORAGE_SIZE 144
+#endif
+
+struct vfp_sigframe
+{
+ unsigned long magic;
+ unsigned long size;
+ union vfp_state storage;
+};
+#endif /* CONFIG_VFP */
+
+/*
+ * Auxiliary signal frame. This saves stuff like FP state.
+ * The layout of this structure is not part of the user ABI,
+ * because the config options aren't. uc_regspace is really
+ * one of these.
+ */
+struct aux_sigframe {
+#ifdef CONFIG_IWMMXT
+ struct iwmmxt_sigframe iwmmxt;
+#endif
+#if 0 && defined CONFIG_VFP /* Not yet saved. */
+ struct vfp_sigframe vfp;
+#endif
+ /* Something that isn't a valid magic number for any coprocessor. */
+ unsigned long end_magic;
+} __attribute__((__aligned__(8)));
+
+#endif
+
#endif /* !_ASMARM_UCONTEXT_H */
diff --git a/include/asm-arm/vga.h b/include/asm-arm/vga.h
index 926e5ee..1e0b913 100644
--- a/include/asm-arm/vga.h
+++ b/include/asm-arm/vga.h
@@ -4,7 +4,7 @@
#include <asm/hardware.h>
#include <asm/io.h>
-#define VGA_MAP_MEM(x) (PCIMEM_BASE + (x))
+#define VGA_MAP_MEM(x,s) (PCIMEM_BASE + (x))
#define vga_readb(x) (*((volatile unsigned char *)x))
#define vga_writeb(x,y) (*((volatile unsigned char *)y) = (x))
diff --git a/include/asm-arm26/floppy.h b/include/asm-arm26/floppy.h
index 9e090ad..a18af06 100644
--- a/include/asm-arm26/floppy.h
+++ b/include/asm-arm26/floppy.h
@@ -22,7 +22,7 @@
#define fd_inb(port) inb((port))
#define fd_request_irq() request_irq(IRQ_FLOPPYDISK,floppy_interrupt,\
- SA_INTERRUPT|SA_SAMPLE_RANDOM,"floppy",NULL)
+ SA_INTERRUPT,"floppy",NULL)
#define fd_free_irq() free_irq(IRQ_FLOPPYDISK,NULL)
#define fd_disable_irq() disable_irq(IRQ_FLOPPYDISK)
#define fd_enable_irq() enable_irq(IRQ_FLOPPYDISK)
diff --git a/include/asm-arm26/irq.h b/include/asm-arm26/irq.h
index 06bd5a5..9aaac87 100644
--- a/include/asm-arm26/irq.h
+++ b/include/asm-arm26/irq.h
@@ -44,9 +44,5 @@ extern void enable_irq(unsigned int);
int set_irq_type(unsigned int irq, unsigned int type);
-int setup_irq(unsigned int, struct irqaction *);
-struct pt_regs;
-int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
-
#endif
diff --git a/include/asm-frv/atomic.h b/include/asm-frv/atomic.h
index 9a4ff03..066386a 100644
--- a/include/asm-frv/atomic.h
+++ b/include/asm-frv/atomic.h
@@ -227,7 +227,7 @@ extern unsigned long atomic_test_and_XOR_mask(unsigned long mask, volatile unsig
break; \
\
default: \
- __xg_orig = 0; \
+ __xg_orig = (__typeof__(__xg_orig))0; \
asm volatile("break"); \
break; \
} \
@@ -247,7 +247,7 @@ extern uint32_t __xchg_32(uint32_t i, volatile void *v);
switch (sizeof(__xg_orig)) { \
case 4: __xg_orig = (__typeof__(*(ptr))) __xchg_32((uint32_t) x, __xg_ptr); break; \
default: \
- __xg_orig = 0; \
+ __xg_orig = (__typeof__(__xg_orig))0; \
asm volatile("break"); \
break; \
} \
diff --git a/include/asm-frv/checksum.h b/include/asm-frv/checksum.h
index 10236f68..42bf0db 100644
--- a/include/asm-frv/checksum.h
+++ b/include/asm-frv/checksum.h
@@ -43,7 +43,7 @@ unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum);
* here even more important to align src and dst on a 32-bit (or even
* better 64-bit) boundary
*/
-extern unsigned int csum_partial_copy_from_user(const char *src, char *dst,
+extern unsigned int csum_partial_copy_from_user(const char __user *src, char *dst,
int len, int sum, int *csum_err);
#define csum_partial_copy_nocheck(src, dst, len, sum) \
diff --git a/include/asm-frv/highmem.h b/include/asm-frv/highmem.h
index cfbf7d3..e2247c2 100644
--- a/include/asm-frv/highmem.h
+++ b/include/asm-frv/highmem.h
@@ -134,7 +134,7 @@ static inline void *kmap_atomic(struct page *page, enum km_type type)
default:
BUG();
- return 0;
+ return NULL;
}
}
diff --git a/include/asm-frv/io.h b/include/asm-frv/io.h
index b56eba5..7765f55 100644
--- a/include/asm-frv/io.h
+++ b/include/asm-frv/io.h
@@ -40,13 +40,13 @@ static inline unsigned long _swapl(unsigned long v)
//#define __iormb() asm volatile("membar")
//#define __iowmb() asm volatile("membar")
-#define __raw_readb(addr) __builtin_read8((void *) (addr))
-#define __raw_readw(addr) __builtin_read16((void *) (addr))
-#define __raw_readl(addr) __builtin_read32((void *) (addr))
+#define __raw_readb __builtin_read8
+#define __raw_readw __builtin_read16
+#define __raw_readl __builtin_read32
-#define __raw_writeb(datum, addr) __builtin_write8((void *) (addr), datum)
-#define __raw_writew(datum, addr) __builtin_write16((void *) (addr), datum)
-#define __raw_writel(datum, addr) __builtin_write32((void *) (addr), datum)
+#define __raw_writeb(datum, addr) __builtin_write8(addr, datum)
+#define __raw_writew(datum, addr) __builtin_write16(addr, datum)
+#define __raw_writel(datum, addr) __builtin_write32(addr, datum)
static inline void io_outsb(unsigned int addr, const void *buf, int len)
{
@@ -116,7 +116,7 @@ static inline void memset_io(volatile void __iomem *addr, unsigned char val, int
memset((void __force *) addr, val, count);
}
-static inline void memcpy_fromio(void *dst, volatile void __iomem *src, int count)
+static inline void memcpy_fromio(void *dst, const volatile void __iomem *src, int count)
{
memcpy(dst, (void __force *) src, count);
}
@@ -128,12 +128,12 @@ static inline void memcpy_toio(volatile void __iomem *dst, const void *src, int
static inline uint8_t inb(unsigned long addr)
{
- return __builtin_read8((void *)addr);
+ return __builtin_read8((void __iomem *)addr);
}
static inline uint16_t inw(unsigned long addr)
{
- uint16_t ret = __builtin_read16((void *)addr);
+ uint16_t ret = __builtin_read16((void __iomem *)addr);
if (__is_PCI_IO(addr))
ret = _swapw(ret);
@@ -143,7 +143,7 @@ static inline uint16_t inw(unsigned long addr)
static inline uint32_t inl(unsigned long addr)
{
- uint32_t ret = __builtin_read32((void *)addr);
+ uint32_t ret = __builtin_read32((void __iomem *)addr);
if (__is_PCI_IO(addr))
ret = _swapl(ret);
@@ -153,21 +153,21 @@ static inline uint32_t inl(unsigned long addr)
static inline void outb(uint8_t datum, unsigned long addr)
{
- __builtin_write8((void *)addr, datum);
+ __builtin_write8((void __iomem *)addr, datum);
}
static inline void outw(uint16_t datum, unsigned long addr)
{
if (__is_PCI_IO(addr))
datum = _swapw(datum);
- __builtin_write16((void *)addr, datum);
+ __builtin_write16((void __iomem *)addr, datum);
}
static inline void outl(uint32_t datum, unsigned long addr)
{
if (__is_PCI_IO(addr))
datum = _swapl(datum);
- __builtin_write32((void *)addr, datum);
+ __builtin_write32((void __iomem *)addr, datum);
}
#define inb_p(addr) inb(addr)
@@ -189,12 +189,12 @@ static inline void outl(uint32_t datum, unsigned long addr)
static inline uint8_t readb(const volatile void __iomem *addr)
{
- return __builtin_read8((volatile uint8_t __force *) addr);
+ return __builtin_read8((__force void volatile __iomem *) addr);
}
static inline uint16_t readw(const volatile void __iomem *addr)
{
- uint16_t ret = __builtin_read16((volatile uint16_t __force *)addr);
+ uint16_t ret = __builtin_read16((__force void volatile __iomem *)addr);
if (__is_PCI_MEM(addr))
ret = _swapw(ret);
@@ -203,7 +203,7 @@ static inline uint16_t readw(const volatile void __iomem *addr)
static inline uint32_t readl(const volatile void __iomem *addr)
{
- uint32_t ret = __builtin_read32((volatile uint32_t __force *)addr);
+ uint32_t ret = __builtin_read32((__force void volatile __iomem *)addr);
if (__is_PCI_MEM(addr))
ret = _swapl(ret);
@@ -217,7 +217,7 @@ static inline uint32_t readl(const volatile void __iomem *addr)
static inline void writeb(uint8_t datum, volatile void __iomem *addr)
{
- __builtin_write8((volatile uint8_t __force *) addr, datum);
+ __builtin_write8(addr, datum);
if (__is_PCI_MEM(addr))
__flush_PCI_writes();
}
@@ -227,7 +227,7 @@ static inline void writew(uint16_t datum, volatile void __iomem *addr)
if (__is_PCI_MEM(addr))
datum = _swapw(datum);
- __builtin_write16((volatile uint16_t __force *) addr, datum);
+ __builtin_write16(addr, datum);
if (__is_PCI_MEM(addr))
__flush_PCI_writes();
}
@@ -237,7 +237,7 @@ static inline void writel(uint32_t datum, volatile void __iomem *addr)
if (__is_PCI_MEM(addr))
datum = _swapl(datum);
- __builtin_write32((volatile uint32_t __force *) addr, datum);
+ __builtin_write32(addr, datum);
if (__is_PCI_MEM(addr))
__flush_PCI_writes();
}
@@ -271,7 +271,7 @@ static inline void __iomem *ioremap_fullcache(unsigned long physaddr, unsigned l
return __ioremap(physaddr, size, IOMAP_FULL_CACHING);
}
-extern void iounmap(void __iomem *addr);
+extern void iounmap(void volatile __iomem *addr);
static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
{
diff --git a/include/asm-frv/mb-regs.h b/include/asm-frv/mb-regs.h
index 93fa732..219e5f9 100644
--- a/include/asm-frv/mb-regs.h
+++ b/include/asm-frv/mb-regs.h
@@ -16,6 +16,17 @@
#include <asm/sections.h>
#include <asm/mem-layout.h>
+#ifndef __ASSEMBLY__
+/* gcc builtins, annotated */
+
+unsigned long __builtin_read8(volatile void __iomem *);
+unsigned long __builtin_read16(volatile void __iomem *);
+unsigned long __builtin_read32(volatile void __iomem *);
+void __builtin_write8(volatile void __iomem *, unsigned char);
+void __builtin_write16(volatile void __iomem *, unsigned short);
+void __builtin_write32(volatile void __iomem *, unsigned long);
+#endif
+
#define __region_IO KERNEL_IO_START /* the region from 0xe0000000 to 0xffffffff has suitable
* protection laid over the top for use in memory-mapped
* I/O
@@ -59,7 +70,7 @@
#define __region_PCI_MEM (__region_CS2 + 0x08000000UL)
#define __flush_PCI_writes() \
do { \
- __builtin_write8((volatile void *) __region_PCI_MEM, 0); \
+ __builtin_write8((volatile void __iomem *) __region_PCI_MEM, 0); \
} while(0)
#define __is_PCI_IO(addr) \
@@ -83,15 +94,15 @@ extern int __nongprelbss mb93090_mb00_detected;
#define __set_LEDS(X) \
do { \
if (mb93090_mb00_detected) \
- __builtin_write32((void *) __addr_LEDS(), ~(X)); \
+ __builtin_write32((void __iomem *) __addr_LEDS(), ~(X)); \
} while (0)
#else
#define __set_LEDS(X)
#endif
#define __addr_LCD() (__region_CS2 + 0x01200008UL)
-#define __get_LCD(B) __builtin_read32((volatile void *) (B))
-#define __set_LCD(B,X) __builtin_write32((volatile void *) (B), (X))
+#define __get_LCD(B) __builtin_read32((volatile void __iomem *) (B))
+#define __set_LCD(B,X) __builtin_write32((volatile void __iomem *) (B), (X))
#define LCD_D 0x000000ff /* LCD data bus */
#define LCD_RW 0x00000100 /* LCD R/W signal */
@@ -161,11 +172,11 @@ do { \
#define __get_CLKIN() 66000000UL
#define __addr_LEDS() (__region_CS2 + 0x00000023UL)
-#define __set_LEDS(X) __builtin_write8((volatile void *) __addr_LEDS(), (X))
+#define __set_LEDS(X) __builtin_write8((volatile void __iomem *) __addr_LEDS(), (X))
#define __addr_FPGATR() (__region_CS2 + 0x00000030UL)
-#define __set_FPGATR(X) __builtin_write32((volatile void *) __addr_FPGATR(), (X))
-#define __get_FPGATR() __builtin_read32((volatile void *) __addr_FPGATR())
+#define __set_FPGATR(X) __builtin_write32((volatile void __iomem *) __addr_FPGATR(), (X))
+#define __get_FPGATR() __builtin_read32((volatile void __iomem *) __addr_FPGATR())
#define MB93093_FPGA_FPGATR_AUDIO_CLK 0x00000003
@@ -180,7 +191,7 @@ do { \
#define MB93093_FPGA_SWR_PUSHSWMASK (0x1F<<26)
#define MB93093_FPGA_SWR_PUSHSW4 (1<<29)
-#define __addr_FPGA_SWR ((volatile void *)(__region_CS2 + 0x28UL))
+#define __addr_FPGA_SWR ((volatile void __iomem *)(__region_CS2 + 0x28UL))
#define __get_FPGA_PUSHSW1_5() (__builtin_read32(__addr_FPGA_SWR) & MB93093_FPGA_SWR_PUSHSWMASK)
diff --git a/include/asm-frv/signal.h b/include/asm-frv/signal.h
index 6736689..dcc1b35 100644
--- a/include/asm-frv/signal.h
+++ b/include/asm-frv/signal.h
@@ -114,13 +114,13 @@ struct old_sigaction {
__sighandler_t sa_handler;
old_sigset_t sa_mask;
unsigned long sa_flags;
- void (*sa_restorer)(void);
+ __sigrestore_t sa_restorer;
};
struct sigaction {
__sighandler_t sa_handler;
unsigned long sa_flags;
- void (*sa_restorer)(void);
+ __sigrestore_t sa_restorer;
sigset_t sa_mask; /* mask last for extensibility */
};
@@ -146,7 +146,7 @@ struct sigaction {
#endif /* __KERNEL__ */
typedef struct sigaltstack {
- void *ss_sp;
+ void __user *ss_sp;
int ss_flags;
size_t ss_size;
} stack_t;
diff --git a/include/asm-frv/uaccess.h b/include/asm-frv/uaccess.h
index a1d1404..3d90e10 100644
--- a/include/asm-frv/uaccess.h
+++ b/include/asm-frv/uaccess.h
@@ -22,7 +22,7 @@
#define HAVE_ARCH_UNMAPPED_AREA /* we decide where to put mmaps */
-#define __ptr(x) ((unsigned long *)(x))
+#define __ptr(x) ((unsigned long __force *)(x))
#define VERIFY_READ 0
#define VERIFY_WRITE 1
@@ -64,7 +64,7 @@ static inline int ___range_ok(unsigned long addr, unsigned long size)
#define __range_ok(addr,size) ___range_ok((unsigned long) (addr), (unsigned long) (size))
-#define access_ok(type,addr,size) (__range_ok((addr), (size)) == 0)
+#define access_ok(type,addr,size) (__range_ok((void __user *)(addr), (size)) == 0)
#define __access_ok(addr,size) (__range_ok((addr), (size)) == 0)
/*
@@ -97,6 +97,7 @@ extern unsigned long search_exception_table(unsigned long);
int __pu_err = 0; \
\
typeof(*(ptr)) __pu_val = (x); \
+ __chk_user_ptr(ptr); \
\
switch (sizeof (*(ptr))) { \
case 1: \
@@ -120,7 +121,7 @@ extern unsigned long search_exception_table(unsigned long);
#define put_user(x, ptr) \
({ \
- typeof(&*ptr) _p = (ptr); \
+ typeof(*(ptr)) __user *_p = (ptr); \
int _e; \
\
_e = __range_ok(_p, sizeof(*_p)); \
@@ -175,33 +176,44 @@ do { \
*/
#define __get_user(x, ptr) \
({ \
- typeof(*(ptr)) __gu_val = 0; \
int __gu_err = 0; \
+ __chk_user_ptr(ptr); \
\
switch (sizeof(*(ptr))) { \
- case 1: \
- __get_user_asm(__gu_err, *(u8*)&__gu_val, ptr, "ub", "=r"); \
+ case 1: { \
+ unsigned char __gu_val; \
+ __get_user_asm(__gu_err, __gu_val, ptr, "ub", "=r"); \
+ (x) = *(__force __typeof__(*(ptr)) *) &__gu_val; \
break; \
- case 2: \
- __get_user_asm(__gu_err, *(u16*)&__gu_val, ptr, "uh", "=r"); \
+ } \
+ case 2: { \
+ unsigned short __gu_val; \
+ __get_user_asm(__gu_err, __gu_val, ptr, "uh", "=r"); \
+ (x) = *(__force __typeof__(*(ptr)) *) &__gu_val; \
break; \
- case 4: \
- __get_user_asm(__gu_err, *(u32*)&__gu_val, ptr, "", "=r"); \
+ } \
+ case 4: { \
+ unsigned int __gu_val; \
+ __get_user_asm(__gu_err, __gu_val, ptr, "", "=r"); \
+ (x) = *(__force __typeof__(*(ptr)) *) &__gu_val; \
break; \
- case 8: \
- __get_user_asm(__gu_err, *(u64*)&__gu_val, ptr, "d", "=e"); \
+ } \
+ case 8: { \
+ unsigned long long __gu_val; \
+ __get_user_asm(__gu_err, __gu_val, ptr, "d", "=e"); \
+ (x) = *(__force __typeof__(*(ptr)) *) &__gu_val; \
break; \
+ } \
default: \
__gu_err = __get_user_bad(); \
break; \
} \
- (x) = __gu_val; \
__gu_err; \
})
#define get_user(x, ptr) \
({ \
- typeof(&*ptr) _p = (ptr); \
+ const typeof(*(ptr)) __user *_p = (ptr);\
int _e; \
\
_e = __range_ok(_p, sizeof(*_p)); \
@@ -248,19 +260,20 @@ do { \
/*
*
*/
+#define ____force(x) (__force void *)(void __user *)(x)
#ifdef CONFIG_MMU
extern long __memset_user(void *dst, unsigned long count);
extern long __memcpy_user(void *dst, const void *src, unsigned long count);
-#define clear_user(dst,count) __memset_user((dst), (count))
-#define __copy_from_user_inatomic(to, from, n) __memcpy_user((to), (from), (n))
-#define __copy_to_user_inatomic(to, from, n) __memcpy_user((to), (from), (n))
+#define clear_user(dst,count) __memset_user(____force(dst), (count))
+#define __copy_from_user_inatomic(to, from, n) __memcpy_user((to), ____force(from), (n))
+#define __copy_to_user_inatomic(to, from, n) __memcpy_user(____force(to), (from), (n))
#else
-#define clear_user(dst,count) (memset((dst), 0, (count)), 0)
-#define __copy_from_user_inatomic(to, from, n) (memcpy((to), (from), (n)), 0)
-#define __copy_to_user_inatomic(to, from, n) (memcpy((to), (from), (n)), 0)
+#define clear_user(dst,count) (memset(____force(dst), 0, (count)), 0)
+#define __copy_from_user_inatomic(to, from, n) (memcpy((to), ____force(from), (n)), 0)
+#define __copy_to_user_inatomic(to, from, n) (memcpy(____force(to), (from), (n)), 0)
#endif
@@ -278,7 +291,7 @@ __copy_from_user(void *to, const void __user *from, unsigned long n)
return __copy_from_user_inatomic(to, from, n);
}
-static inline long copy_from_user(void *to, const void *from, unsigned long n)
+static inline long copy_from_user(void *to, const void __user *from, unsigned long n)
{
unsigned long ret = n;
@@ -291,16 +304,13 @@ static inline long copy_from_user(void *to, const void *from, unsigned long n)
return ret;
}
-static inline long copy_to_user(void *to, const void *from, unsigned long n)
+static inline long copy_to_user(void __user *to, const void *from, unsigned long n)
{
return likely(__access_ok(to, n)) ? __copy_to_user(to, from, n) : n;
}
-#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; })
-#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; })
-
-extern long strncpy_from_user(char *dst, const char *src, long count);
-extern long strnlen_user(const char *src, long count);
+extern long strncpy_from_user(char *dst, const char __user *src, long count);
+extern long strnlen_user(const char __user *src, long count);
#define strlen_user(str) strnlen_user(str, 32767)
diff --git a/include/asm-frv/unistd.h b/include/asm-frv/unistd.h
index 7c2e712..b80dbd8 100644
--- a/include/asm-frv/unistd.h
+++ b/include/asm-frv/unistd.h
@@ -306,7 +306,7 @@
#define __NR_mknodat 297
#define __NR_fchownat 298
#define __NR_futimesat 299
-#define __NR_newfstatat 300
+#define __NR_fstatat64 300
#define __NR_unlinkat 301
#define __NR_renameat 302
#define __NR_linkat 303
@@ -460,24 +460,7 @@ type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg
* some others too.
*/
#define __NR__exit __NR_exit
-static inline _syscall0(int,pause)
-static inline _syscall0(int,sync)
-static inline _syscall0(pid_t,setsid)
-static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
-static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
-static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
-static inline _syscall1(int,dup,int,fd)
static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
-static inline _syscall1(int,close,int,fd)
-static inline _syscall1(int,_exit,int,exitcode)
-static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
-static inline _syscall1(int,delete_module,const char *,name)
-
-static inline pid_t wait(int * wait_stat)
-{
- return waitpid(-1,wait_stat,0);
-}
#endif /* __KERNEL_SYSCALLS__ */
diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
index 0cd9711..845cb67 100644
--- a/include/asm-generic/bug.h
+++ b/include/asm-generic/bug.h
@@ -38,4 +38,17 @@
#endif
#endif
+#define WARN_ON_ONCE(condition) \
+({ \
+ static int __warn_once = 1; \
+ int __ret = 0; \
+ \
+ if (unlikely((condition) && __warn_once)) { \
+ __warn_once = 0; \
+ WARN_ON(1); \
+ __ret = 1; \
+ } \
+ __ret; \
+})
+
#endif
diff --git a/include/asm-generic/memory_model.h b/include/asm-generic/memory_model.h
index 0cfb086..8078cbd 100644
--- a/include/asm-generic/memory_model.h
+++ b/include/asm-generic/memory_model.h
@@ -23,29 +23,23 @@
#endif /* CONFIG_DISCONTIGMEM */
-#ifdef CONFIG_OUT_OF_LINE_PFN_TO_PAGE
-struct page;
-/* this is useful when inlined pfn_to_page is too big */
-extern struct page *pfn_to_page(unsigned long pfn);
-extern unsigned long page_to_pfn(struct page *page);
-#else
/*
* supports 3 memory models.
*/
#if defined(CONFIG_FLATMEM)
-#define pfn_to_page(pfn) (mem_map + ((pfn) - ARCH_PFN_OFFSET))
-#define page_to_pfn(page) ((unsigned long)((page) - mem_map) + \
+#define __pfn_to_page(pfn) (mem_map + ((pfn) - ARCH_PFN_OFFSET))
+#define __page_to_pfn(page) ((unsigned long)((page) - mem_map) + \
ARCH_PFN_OFFSET)
#elif defined(CONFIG_DISCONTIGMEM)
-#define pfn_to_page(pfn) \
+#define __pfn_to_page(pfn) \
({ unsigned long __pfn = (pfn); \
unsigned long __nid = arch_pfn_to_nid(pfn); \
NODE_DATA(__nid)->node_mem_map + arch_local_page_offset(__pfn, __nid);\
})
-#define page_to_pfn(pg) \
+#define __page_to_pfn(pg) \
({ struct page *__pg = (pg); \
struct pglist_data *__pgdat = NODE_DATA(page_to_nid(__pg)); \
(unsigned long)(__pg - __pgdat->node_mem_map) + \
@@ -57,18 +51,27 @@ extern unsigned long page_to_pfn(struct page *page);
* Note: section's mem_map is encorded to reflect its start_pfn.
* section[i].section_mem_map == mem_map's address - start_pfn;
*/
-#define page_to_pfn(pg) \
+#define __page_to_pfn(pg) \
({ struct page *__pg = (pg); \
int __sec = page_to_section(__pg); \
__pg - __section_mem_map_addr(__nr_to_section(__sec)); \
})
-#define pfn_to_page(pfn) \
+#define __pfn_to_page(pfn) \
({ unsigned long __pfn = (pfn); \
struct mem_section *__sec = __pfn_to_section(__pfn); \
__section_mem_map_addr(__sec) + __pfn; \
})
#endif /* CONFIG_FLATMEM/DISCONTIGMEM/SPARSEMEM */
+
+#ifdef CONFIG_OUT_OF_LINE_PFN_TO_PAGE
+struct page;
+/* this is useful when inlined pfn_to_page is too big */
+extern struct page *pfn_to_page(unsigned long pfn);
+extern unsigned long page_to_pfn(struct page *page);
+#else
+#define page_to_pfn __page_to_pfn
+#define pfn_to_page __pfn_to_page
#endif /* CONFIG_OUT_OF_LINE_PFN_TO_PAGE */
#endif /* __ASSEMBLY__ */
diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h
index c0caf43..c745211 100644
--- a/include/asm-generic/percpu.h
+++ b/include/asm-generic/percpu.h
@@ -14,6 +14,7 @@ extern unsigned long __per_cpu_offset[NR_CPUS];
/* var is in discarded region: offset to particular copy we want */
#define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]))
#define __get_cpu_var(var) per_cpu(var, smp_processor_id())
+#define __raw_get_cpu_var(var) per_cpu(var, raw_smp_processor_id())
/* A macro to avoid #include hell... */
#define percpu_modcopy(pcpudst, src, size) \
@@ -30,6 +31,7 @@ do { \
#define per_cpu(var, cpu) (*((void)(cpu), &per_cpu__##var))
#define __get_cpu_var(var) per_cpu__##var
+#define __raw_get_cpu_var(var) per_cpu__##var
#endif /* SMP */
diff --git a/include/asm-generic/rtc.h b/include/asm-generic/rtc.h
index cef08db..4087037 100644
--- a/include/asm-generic/rtc.h
+++ b/include/asm-generic/rtc.h
@@ -114,6 +114,7 @@ static inline unsigned int get_rtc_time(struct rtc_time *time)
/* Set the current date and time in the real time clock. */
static inline int set_rtc_time(struct rtc_time *time)
{
+ unsigned long flags;
unsigned char mon, day, hrs, min, sec;
unsigned char save_control, save_freq_select;
unsigned int yrs;
@@ -131,7 +132,7 @@ static inline int set_rtc_time(struct rtc_time *time)
if (yrs > 255) /* They are unsigned */
return -EINVAL;
- spin_lock_irq(&rtc_lock);
+ spin_lock_irqsave(&rtc_lock, flags);
#ifdef CONFIG_MACH_DECSTATION
real_yrs = yrs;
leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) ||
@@ -152,7 +153,7 @@ static inline int set_rtc_time(struct rtc_time *time)
* whether the chip is in binary mode or not.
*/
if (yrs > 169) {
- spin_unlock_irq(&rtc_lock);
+ spin_unlock_irqrestore(&rtc_lock, flags);
return -EINVAL;
}
@@ -187,7 +188,7 @@ static inline int set_rtc_time(struct rtc_time *time)
CMOS_WRITE(save_control, RTC_CONTROL);
CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
- spin_unlock_irq(&rtc_lock);
+ spin_unlock_irqrestore(&rtc_lock, flags);
return 0;
}
diff --git a/include/asm-h8300/irq.h b/include/asm-h8300/irq.h
index 73065f5..42a3ac4 100644
--- a/include/asm-h8300/irq.h
+++ b/include/asm-h8300/irq.h
@@ -63,8 +63,4 @@ extern void enable_irq(unsigned int);
extern void disable_irq(unsigned int);
#define disable_irq_nosync(x) disable_irq(x)
-struct irqaction;
-struct pt_regs;
-int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
-
#endif /* _H8300_IRQ_H_ */
diff --git a/include/asm-i386/alternative.h b/include/asm-i386/alternative.h
index e201dec..d79e9ee 100644
--- a/include/asm-i386/alternative.h
+++ b/include/asm-i386/alternative.h
@@ -3,6 +3,8 @@
#ifdef __KERNEL__
+#include <asm/types.h>
+
struct alt_instr {
u8 *instr; /* original instruction */
u8 *replacement;
diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h
index cc9b940f..1d8362c 100644
--- a/include/asm-i386/apic.h
+++ b/include/asm-i386/apic.h
@@ -138,8 +138,6 @@ void switch_ipi_to_APIC_timer(void *cpumask);
extern int timer_over_8254;
-extern int modern_apic(void);
-
#else /* !CONFIG_X86_LOCAL_APIC */
static inline void lapic_shutdown(void) { }
diff --git a/include/asm-i386/apicdef.h b/include/asm-i386/apicdef.h
index 5e4a35a..9f69953 100644
--- a/include/asm-i386/apicdef.h
+++ b/include/asm-i386/apicdef.h
@@ -121,7 +121,6 @@
*/
#define u32 unsigned int
-#define lapic ((volatile struct local_apic *)APIC_BASE)
struct local_apic {
diff --git a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h
index b44bfc6..3ecedba 100644
--- a/include/asm-i386/cpufeature.h
+++ b/include/asm-i386/cpufeature.h
@@ -88,6 +88,12 @@
#define X86_FEATURE_XSTORE_EN (5*32+ 3) /* on-CPU RNG enabled */
#define X86_FEATURE_XCRYPT (5*32+ 6) /* on-CPU crypto (xcrypt insn) */
#define X86_FEATURE_XCRYPT_EN (5*32+ 7) /* on-CPU crypto enabled */
+#define X86_FEATURE_ACE2 (5*32+ 8) /* Advanced Cryptography Engine v2 */
+#define X86_FEATURE_ACE2_EN (5*32+ 9) /* ACE v2 enabled */
+#define X86_FEATURE_PHE (5*32+ 10) /* PadLock Hash Engine */
+#define X86_FEATURE_PHE_EN (5*32+ 11) /* PHE enabled */
+#define X86_FEATURE_PMM (5*32+ 12) /* PadLock Montgomery Multiplier */
+#define X86_FEATURE_PMM_EN (5*32+ 13) /* PMM enabled */
/* More extended AMD flags: CPUID level 0x80000001, ecx, word 6 */
#define X86_FEATURE_LAHF_LM (6*32+ 0) /* LAHF/SAHF in long mode */
@@ -121,6 +127,12 @@
#define cpu_has_xstore_enabled boot_cpu_has(X86_FEATURE_XSTORE_EN)
#define cpu_has_xcrypt boot_cpu_has(X86_FEATURE_XCRYPT)
#define cpu_has_xcrypt_enabled boot_cpu_has(X86_FEATURE_XCRYPT_EN)
+#define cpu_has_ace2 boot_cpu_has(X86_FEATURE_ACE2)
+#define cpu_has_ace2_enabled boot_cpu_has(X86_FEATURE_ACE2_EN)
+#define cpu_has_phe boot_cpu_has(X86_FEATURE_PHE)
+#define cpu_has_phe_enabled boot_cpu_has(X86_FEATURE_PHE_EN)
+#define cpu_has_pmm boot_cpu_has(X86_FEATURE_PMM)
+#define cpu_has_pmm_enabled boot_cpu_has(X86_FEATURE_PMM_EN)
#endif /* __ASM_I386_CPUFEATURE_H */
diff --git a/include/asm-i386/floppy.h b/include/asm-i386/floppy.h
index 03403045..9cb2793 100644
--- a/include/asm-i386/floppy.h
+++ b/include/asm-i386/floppy.h
@@ -147,9 +147,8 @@ static int fd_request_irq(void)
return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
"floppy", NULL);
else
- return request_irq(FLOPPY_IRQ, floppy_interrupt,
- SA_INTERRUPT|SA_SAMPLE_RANDOM,
- "floppy", NULL);
+ return request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT,
+ "floppy", NULL);
}
diff --git a/include/asm-i386/mach-default/setup_arch_pre.h b/include/asm-i386/mach-default/setup_arch.h
index fb42099e..fb42099e 100644
--- a/include/asm-i386/mach-default/setup_arch_pre.h
+++ b/include/asm-i386/mach-default/setup_arch.h
diff --git a/include/asm-i386/mach-default/setup_arch_post.h b/include/asm-i386/mach-default/setup_arch_post.h
deleted file mode 100644
index 2fc4888..0000000
--- a/include/asm-i386/mach-default/setup_arch_post.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * machine_specific_memory_setup - Hook for machine specific memory setup.
- *
- * Description:
- * This is included late in kernel/setup.c so that it can make
- * use of all of the static functions.
- **/
-
-static char * __init machine_specific_memory_setup(void)
-{
- char *who;
-
-
- who = "BIOS-e820";
-
- /*
- * Try to copy the BIOS-supplied E820-map.
- *
- * Otherwise fake a memory map; one section from 0k->640k,
- * the next section from 1mb->appropriate_mem_k
- */
- sanitize_e820_map(E820_MAP, &E820_MAP_NR);
- if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
- unsigned long mem_size;
-
- /* compare results from other methods and take the greater */
- if (ALT_MEM_K < EXT_MEM_K) {
- mem_size = EXT_MEM_K;
- who = "BIOS-88";
- } else {
- mem_size = ALT_MEM_K;
- who = "BIOS-e801";
- }
-
- e820.nr_map = 0;
- add_memory_region(0, LOWMEMSIZE(), E820_RAM);
- add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
- }
- return who;
-}
diff --git a/include/asm-i386/mach-visws/setup_arch_pre.h b/include/asm-i386/mach-visws/setup_arch.h
index b92d6d9..b92d6d9 100644
--- a/include/asm-i386/mach-visws/setup_arch_pre.h
+++ b/include/asm-i386/mach-visws/setup_arch.h
diff --git a/include/asm-i386/mach-visws/setup_arch_post.h b/include/asm-i386/mach-visws/setup_arch_post.h
deleted file mode 100644
index cdbd895..0000000
--- a/include/asm-i386/mach-visws/setup_arch_post.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Hook for machine specific memory setup.
- *
- * This is included late in kernel/setup.c so that it can make use of all of
- * the static functions. */
-
-#define MB (1024 * 1024)
-
-unsigned long sgivwfb_mem_phys;
-unsigned long sgivwfb_mem_size;
-
-long long mem_size __initdata = 0;
-
-static char * __init machine_specific_memory_setup(void)
-{
- long long gfx_mem_size = 8 * MB;
-
- mem_size = ALT_MEM_K;
-
- if (!mem_size) {
- printk(KERN_WARNING "Bootloader didn't set memory size, upgrade it !\n");
- mem_size = 128 * MB;
- }
-
- /*
- * this hardcodes the graphics memory to 8 MB
- * it really should be sized dynamically (or at least
- * set as a boot param)
- */
- if (!sgivwfb_mem_size) {
- printk(KERN_WARNING "Defaulting to 8 MB framebuffer size\n");
- sgivwfb_mem_size = 8 * MB;
- }
-
- /*
- * Trim to nearest MB
- */
- sgivwfb_mem_size &= ~((1 << 20) - 1);
- sgivwfb_mem_phys = mem_size - gfx_mem_size;
-
- add_memory_region(0, LOWMEMSIZE(), E820_RAM);
- add_memory_region(HIGH_MEMORY, mem_size - sgivwfb_mem_size - HIGH_MEMORY, E820_RAM);
- add_memory_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED);
-
- return "PROM";
-
- /* Remove gcc warnings */
- (void) sanitize_e820_map(NULL, NULL);
- (void) copy_e820_map(NULL, 0);
-}
diff --git a/include/asm-i386/mach-voyager/setup_arch_pre.h b/include/asm-i386/mach-voyager/setup_arch.h
index 48f7e6f..84d01ad 100644
--- a/include/asm-i386/mach-voyager/setup_arch_pre.h
+++ b/include/asm-i386/mach-voyager/setup_arch.h
@@ -3,7 +3,7 @@
/* Hook to call BIOS initialisation function */
-/* for voyager, pass the voyager BIOS/SUS info area to the detection
+/* for voyager, pass the voyager BIOS/SUS info area to the detection
* routines */
#define ARCH_SETUP voyager_detect(VOYAGER_BIOS_INFO);
diff --git a/include/asm-i386/mach-voyager/setup_arch_post.h b/include/asm-i386/mach-voyager/setup_arch_post.h
deleted file mode 100644
index f6f6c2c..0000000
--- a/include/asm-i386/mach-voyager/setup_arch_post.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* Hook for machine specific memory setup.
- *
- * This is included late in kernel/setup.c so that it can make use of all of
- * the static functions. */
-
-static char * __init machine_specific_memory_setup(void)
-{
- char *who;
-
- who = "NOT VOYAGER";
-
- if(voyager_level == 5) {
- __u32 addr, length;
- int i;
-
- who = "Voyager-SUS";
-
- e820.nr_map = 0;
- for(i=0; voyager_memory_detect(i, &addr, &length); i++) {
- add_memory_region(addr, length, E820_RAM);
- }
- return who;
- } else if(voyager_level == 4) {
- __u32 tom;
- __u16 catbase = inb(VOYAGER_SSPB_RELOCATION_PORT)<<8;
- /* select the DINO config space */
- outb(VOYAGER_DINO, VOYAGER_CAT_CONFIG_PORT);
- /* Read DINO top of memory register */
- tom = ((inb(catbase + 0x4) & 0xf0) << 16)
- + ((inb(catbase + 0x5) & 0x7f) << 24);
-
- if(inb(catbase) != VOYAGER_DINO) {
- printk(KERN_ERR "Voyager: Failed to get DINO for L4, setting tom to EXT_MEM_K\n");
- tom = (EXT_MEM_K)<<10;
- }
- who = "Voyager-TOM";
- add_memory_region(0, 0x9f000, E820_RAM);
- /* map from 1M to top of memory */
- add_memory_region(1*1024*1024, tom - 1*1024*1024, E820_RAM);
- /* FIXME: Should check the ASICs to see if I need to
- * take out the 8M window. Just do it at the moment
- * */
- add_memory_region(8*1024*1024, 8*1024*1024, E820_RESERVED);
- return who;
- }
-
- who = "BIOS-e820";
-
- /*
- * Try to copy the BIOS-supplied E820-map.
- *
- * Otherwise fake a memory map; one section from 0k->640k,
- * the next section from 1mb->appropriate_mem_k
- */
- sanitize_e820_map(E820_MAP, &E820_MAP_NR);
- if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
- unsigned long mem_size;
-
- /* compare results from other methods and take the greater */
- if (ALT_MEM_K < EXT_MEM_K) {
- mem_size = EXT_MEM_K;
- who = "BIOS-88";
- } else {
- mem_size = ALT_MEM_K;
- who = "BIOS-e801";
- }
-
- e820.nr_map = 0;
- add_memory_region(0, LOWMEMSIZE(), E820_RAM);
- add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
- }
- return who;
-}
diff --git a/include/asm-i386/mce.h b/include/asm-i386/mce.h
new file mode 100644
index 0000000..7cc1a973
--- /dev/null
+++ b/include/asm-i386/mce.h
@@ -0,0 +1,5 @@
+#ifdef CONFIG_X86_MCE
+extern void mcheck_init(struct cpuinfo_x86 *c);
+#else
+#define mcheck_init(c) do {} while(0)
+#endif
diff --git a/include/asm-i386/msi.h b/include/asm-i386/msi.h
index f041d44..b11c4b7 100644
--- a/include/asm-i386/msi.h
+++ b/include/asm-i386/msi.h
@@ -9,7 +9,15 @@
#include <asm/desc.h>
#include <mach_apic.h>
-#define LAST_DEVICE_VECTOR 232
+#define LAST_DEVICE_VECTOR (FIRST_SYSTEM_VECTOR - 1)
#define MSI_TARGET_CPU_SHIFT 12
+extern struct msi_ops msi_apic_ops;
+
+static inline int msi_arch_init(void)
+{
+ msi_register(&msi_apic_ops);
+ return 0;
+}
+
#endif /* ASM_MSI_H */
diff --git a/include/asm-i386/mtrr.h b/include/asm-i386/mtrr.h
index 5a46de0..07f063a 100644
--- a/include/asm-i386/mtrr.h
+++ b/include/asm-i386/mtrr.h
@@ -76,6 +76,8 @@ extern int mtrr_add_page (unsigned long base, unsigned long size,
extern int mtrr_del (int reg, unsigned long base, unsigned long size);
extern int mtrr_del_page (int reg, unsigned long base, unsigned long size);
extern void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi);
+extern void mtrr_ap_init(void);
+extern void mtrr_bp_init(void);
# else
static __inline__ int mtrr_add (unsigned long base, unsigned long size,
unsigned int type, char increment)
@@ -100,6 +102,8 @@ static __inline__ int mtrr_del_page (int reg, unsigned long base,
static __inline__ void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) {;}
+#define mtrr_ap_init() do {} while (0)
+#define mtrr_bp_init() do {} while (0)
# endif
#endif
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index 4df3818..0c83cf1 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -728,18 +728,4 @@ extern unsigned long boot_option_idle_override;
extern void enable_sep_cpu(void);
extern int sysenter_setup(void);
-#ifdef CONFIG_MTRR
-extern void mtrr_ap_init(void);
-extern void mtrr_bp_init(void);
-#else
-#define mtrr_ap_init() do {} while (0)
-#define mtrr_bp_init() do {} while (0)
-#endif
-
-#ifdef CONFIG_X86_MCE
-extern void mcheck_init(struct cpuinfo_x86 *c);
-#else
-#define mcheck_init(c) do {} while(0)
-#endif
-
#endif /* __ASM_I386_PROCESSOR_H */
diff --git a/include/asm-i386/setup.h b/include/asm-i386/setup.h
index ee94145..f737e42 100644
--- a/include/asm-i386/setup.h
+++ b/include/asm-i386/setup.h
@@ -59,6 +59,21 @@ extern unsigned char boot_params[PARAM_SIZE];
#define EDD_MBR_SIGNATURE ((unsigned int *) (PARAM+EDD_MBR_SIG_BUF))
#define EDD_BUF ((struct edd_info *) (PARAM+EDDBUF))
+/*
+ * Do NOT EVER look at the BIOS memory size location.
+ * It does not work on many machines.
+ */
+#define LOWMEMSIZE() (0x9f000)
+
+struct e820entry;
+
+char * __init machine_specific_memory_setup(void);
+
+int __init copy_e820_map(struct e820entry * biosmap, int nr_map);
+int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map);
+void __init add_memory_region(unsigned long long start,
+ unsigned long long size, int type);
+
#endif /* __ASSEMBLY__ */
#endif /* _i386_SETUP_H */
diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h
index 1ec6552..54d905e 100644
--- a/include/asm-i386/uaccess.h
+++ b/include/asm-i386/uaccess.h
@@ -58,7 +58,7 @@ extern struct movsl_mask {
__chk_user_ptr(addr); \
asm("addl %3,%1 ; sbbl %0,%0; cmpl %1,%4; sbbl $0,%0" \
:"=&r" (flag), "=r" (sum) \
- :"1" (addr),"g" ((int)(size)),"g" (current_thread_info()->addr_limit.seg)); \
+ :"1" (addr),"g" ((int)(size)),"rm" (current_thread_info()->addr_limit.seg)); \
flag; })
/**
@@ -390,6 +390,12 @@ unsigned long __must_check __copy_to_user_ll(void __user *to,
const void *from, unsigned long n);
unsigned long __must_check __copy_from_user_ll(void *to,
const void __user *from, unsigned long n);
+unsigned long __must_check __copy_from_user_ll_nozero(void *to,
+ const void __user *from, unsigned long n);
+unsigned long __must_check __copy_from_user_ll_nocache(void *to,
+ const void __user *from, unsigned long n);
+unsigned long __must_check __copy_from_user_ll_nocache_nozero(void *to,
+ const void __user *from, unsigned long n);
/*
* Here we special-case 1, 2 and 4-byte copy_*_user invocations. On a fault
@@ -456,10 +462,41 @@ __copy_to_user(void __user *to, const void *from, unsigned long n)
*
* If some data could not be copied, this function will pad the copied
* data to the requested size using zero bytes.
+ *
+ * An alternate version - __copy_from_user_inatomic() - may be called from
+ * atomic context and will fail rather than sleep. In this case the
+ * uncopied bytes will *NOT* be padded with zeros. See fs/filemap.h
+ * for explanation of why this is needed.
*/
static __always_inline unsigned long
__copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
{
+ /* Avoid zeroing the tail if the copy fails..
+ * If 'n' is constant and 1, 2, or 4, we do still zero on a failure,
+ * but as the zeroing behaviour is only significant when n is not
+ * constant, that shouldn't be a problem.
+ */
+ if (__builtin_constant_p(n)) {
+ unsigned long ret;
+
+ switch (n) {
+ case 1:
+ __get_user_size(*(u8 *)to, from, 1, ret, 1);
+ return ret;
+ case 2:
+ __get_user_size(*(u16 *)to, from, 2, ret, 2);
+ return ret;
+ case 4:
+ __get_user_size(*(u32 *)to, from, 4, ret, 4);
+ return ret;
+ }
+ }
+ return __copy_from_user_ll_nozero(to, from, n);
+}
+static __always_inline unsigned long
+__copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+ might_sleep();
if (__builtin_constant_p(n)) {
unsigned long ret;
@@ -478,12 +515,36 @@ __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
return __copy_from_user_ll(to, from, n);
}
+#define ARCH_HAS_NOCACHE_UACCESS
+
+static __always_inline unsigned long __copy_from_user_nocache(void *to,
+ const void __user *from, unsigned long n)
+{
+ might_sleep();
+ if (__builtin_constant_p(n)) {
+ unsigned long ret;
+
+ switch (n) {
+ case 1:
+ __get_user_size(*(u8 *)to, from, 1, ret, 1);
+ return ret;
+ case 2:
+ __get_user_size(*(u16 *)to, from, 2, ret, 2);
+ return ret;
+ case 4:
+ __get_user_size(*(u32 *)to, from, 4, ret, 4);
+ return ret;
+ }
+ }
+ return __copy_from_user_ll_nocache(to, from, n);
+}
+
static __always_inline unsigned long
-__copy_from_user(void *to, const void __user *from, unsigned long n)
+__copy_from_user_inatomic_nocache(void *to, const void __user *from, unsigned long n)
{
- might_sleep();
- return __copy_from_user_inatomic(to, from, n);
+ return __copy_from_user_ll_nocache_nozero(to, from, n);
}
+
unsigned long __must_check copy_to_user(void __user *to,
const void *from, unsigned long n);
unsigned long __must_check copy_from_user(void *to,
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
index de2ccc1..fc1c8dd 100644
--- a/include/asm-i386/unistd.h
+++ b/include/asm-i386/unistd.h
@@ -322,10 +322,11 @@
#define __NR_sync_file_range 314
#define __NR_tee 315
#define __NR_vmsplice 316
+#define __NR_move_pages 317
#ifdef __KERNEL__
-#define NR_syscalls 317
+#define NR_syscalls 318
/*
* user-visible error numbers are in the range -1 - -128: see
diff --git a/include/asm-i386/vga.h b/include/asm-i386/vga.h
index ef0c0e5..0ecf68a 100644
--- a/include/asm-i386/vga.h
+++ b/include/asm-i386/vga.h
@@ -12,7 +12,7 @@
* access the videoram directly without any black magic.
*/
-#define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x)
+#define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x)
#define vga_readb(x) (*(x))
#define vga_writeb(x,y) (*(y) = (x))
diff --git a/include/asm-ia64/hw_irq.h b/include/asm-ia64/hw_irq.h
index 0cf119b..ea8b8c4 100644
--- a/include/asm-ia64/hw_irq.h
+++ b/include/asm-ia64/hw_irq.h
@@ -47,9 +47,19 @@ typedef u8 ia64_vector;
#define IA64_CMC_VECTOR 0x1f /* corrected machine-check interrupt vector */
/*
* Vectors 0x20-0x2f are reserved for legacy ISA IRQs.
+ * Use vectors 0x30-0xe7 as the default device vector range for ia64.
+ * Platforms may choose to reduce this range in platform_irq_setup, but the
+ * platform range must fall within
+ * [IA64_DEF_FIRST_DEVICE_VECTOR..IA64_DEF_LAST_DEVICE_VECTOR]
*/
-#define IA64_FIRST_DEVICE_VECTOR 0x30
-#define IA64_LAST_DEVICE_VECTOR 0xe7
+extern int ia64_first_device_vector;
+extern int ia64_last_device_vector;
+
+#define IA64_DEF_FIRST_DEVICE_VECTOR 0x30
+#define IA64_DEF_LAST_DEVICE_VECTOR 0xe7
+#define IA64_FIRST_DEVICE_VECTOR ia64_first_device_vector
+#define IA64_LAST_DEVICE_VECTOR ia64_last_device_vector
+#define IA64_MAX_DEVICE_VECTORS (IA64_DEF_LAST_DEVICE_VECTOR - IA64_DEF_FIRST_DEVICE_VECTOR + 1)
#define IA64_NUM_DEVICE_VECTORS (IA64_LAST_DEVICE_VECTOR - IA64_FIRST_DEVICE_VECTOR + 1)
#define IA64_MCA_RENDEZ_VECTOR 0xe8 /* MCA rendez interrupt */
@@ -83,6 +93,7 @@ extern struct hw_interrupt_type irq_type_ia64_lsapic; /* CPU-internal interrupt
extern int assign_irq_vector (int irq); /* allocate a free vector */
extern void free_irq_vector (int vector);
+extern int reserve_irq_vector (int vector);
extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect);
extern void register_percpu_irq (ia64_vector vec, struct irqaction *action);
diff --git a/include/asm-ia64/io.h b/include/asm-ia64/io.h
index c2e3742..781ee2c 100644
--- a/include/asm-ia64/io.h
+++ b/include/asm-ia64/io.h
@@ -88,6 +88,7 @@ phys_to_virt (unsigned long address)
}
#define ARCH_HAS_VALID_PHYS_ADDR_RANGE
+extern u64 kern_mem_attribute (unsigned long phys_addr, unsigned long size);
extern int valid_phys_addr_range (unsigned long addr, size_t count); /* efi.c */
extern int valid_mmap_phys_addr_range (unsigned long addr, size_t count);
diff --git a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h
index 0df72a1..15b545a 100644
--- a/include/asm-ia64/machvec.h
+++ b/include/asm-ia64/machvec.h
@@ -75,6 +75,7 @@ typedef unsigned char ia64_mv_readb_relaxed_t (const volatile void __iomem *);
typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *);
typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *);
typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *);
+typedef int ia64_mv_msi_init_t (void);
static inline void
machvec_noop (void)
@@ -153,6 +154,7 @@ extern void machvec_tlb_migrate_finish (struct mm_struct *);
# define platform_readl_relaxed ia64_mv.readl_relaxed
# define platform_readq_relaxed ia64_mv.readq_relaxed
# define platform_migrate ia64_mv.migrate
+# define platform_msi_init ia64_mv.msi_init
# endif
/* __attribute__((__aligned__(16))) is required to make size of the
@@ -202,6 +204,7 @@ struct ia64_machine_vector {
ia64_mv_readl_relaxed_t *readl_relaxed;
ia64_mv_readq_relaxed_t *readq_relaxed;
ia64_mv_migrate_t *migrate;
+ ia64_mv_msi_init_t *msi_init;
} __attribute__((__aligned__(16))); /* align attrib? see above comment */
#define MACHVEC_INIT(name) \
@@ -247,6 +250,7 @@ struct ia64_machine_vector {
platform_readl_relaxed, \
platform_readq_relaxed, \
platform_migrate, \
+ platform_msi_init, \
}
extern struct ia64_machine_vector ia64_mv;
@@ -400,5 +404,8 @@ extern int ia64_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size
#ifndef platform_migrate
# define platform_migrate machvec_noop_task
#endif
+#ifndef platform_msi_init
+# define platform_msi_init ((ia64_mv_msi_init_t*)NULL)
+#endif
#endif /* _ASM_IA64_MACHVEC_H */
diff --git a/include/asm-ia64/machvec_sn2.h b/include/asm-ia64/machvec_sn2.h
index da1d437..cf724dc 100644
--- a/include/asm-ia64/machvec_sn2.h
+++ b/include/asm-ia64/machvec_sn2.h
@@ -67,6 +67,8 @@ extern ia64_mv_dma_sync_sg_for_device sn_dma_sync_sg_for_device;
extern ia64_mv_dma_mapping_error sn_dma_mapping_error;
extern ia64_mv_dma_supported sn_dma_supported;
extern ia64_mv_migrate_t sn_migrate;
+extern ia64_mv_msi_init_t sn_msi_init;
+
/*
* This stuff has dual use!
@@ -117,6 +119,11 @@ extern ia64_mv_migrate_t sn_migrate;
#define platform_dma_mapping_error sn_dma_mapping_error
#define platform_dma_supported sn_dma_supported
#define platform_migrate sn_migrate
+#ifdef CONFIG_PCI_MSI
+#define platform_msi_init sn_msi_init
+#else
+#define platform_msi_init ((ia64_mv_msi_init_t*)NULL)
+#endif
#include <asm/sn/io.h>
diff --git a/include/asm-ia64/mca.h b/include/asm-ia64/mca.h
index 9c5389b..ee97f7c 100644
--- a/include/asm-ia64/mca.h
+++ b/include/asm-ia64/mca.h
@@ -69,14 +69,16 @@ typedef struct ia64_mc_info_s {
*/
struct ia64_sal_os_state {
- /* SAL to OS, must be at offset 0 */
+
+ /* SAL to OS */
u64 os_gp; /* GP of the os registered with the SAL, physical */
u64 pal_proc; /* PAL_PROC entry point, physical */
u64 sal_proc; /* SAL_PROC entry point, physical */
u64 rv_rc; /* MCA - Rendezvous state, INIT - reason code */
u64 proc_state_param; /* from R18 */
u64 monarch; /* 1 for a monarch event, 0 for a slave */
- /* common, must follow SAL to OS */
+
+ /* common */
u64 sal_ra; /* Return address in SAL, physical */
u64 sal_gp; /* GP of the SAL - physical */
pal_min_state_area_t *pal_min_state; /* from R17. physical in asm, virtual in C */
@@ -98,7 +100,8 @@ struct ia64_sal_os_state {
u64 iipa;
u64 iim;
u64 iha;
- /* OS to SAL, must follow common */
+
+ /* OS to SAL */
u64 os_status; /* OS status to SAL, enum below */
u64 context; /* 0 if return to same context
1 if return to new context */
diff --git a/include/asm-ia64/msi.h b/include/asm-ia64/msi.h
index 97890f7..bb92b0d 100644
--- a/include/asm-ia64/msi.h
+++ b/include/asm-ia64/msi.h
@@ -14,4 +14,16 @@ static inline void set_intr_gate (int nr, void *func) {}
#define ack_APIC_irq ia64_eoi
#define MSI_TARGET_CPU_SHIFT 4
+extern struct msi_ops msi_apic_ops;
+
+static inline int msi_arch_init(void)
+{
+ if (platform_msi_init)
+ return platform_msi_init();
+
+ /* default ops for most ia64 platforms */
+ msi_register(&msi_apic_ops);
+ return 0;
+}
+
#endif /* ASM_MSI_H */
diff --git a/include/asm-ia64/percpu.h b/include/asm-ia64/percpu.h
index ae357d5..24d898b 100644
--- a/include/asm-ia64/percpu.h
+++ b/include/asm-ia64/percpu.h
@@ -42,6 +42,7 @@ DECLARE_PER_CPU(unsigned long, local_per_cpu_offset);
#define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]))
#define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __ia64_per_cpu_var(local_per_cpu_offset)))
+#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __ia64_per_cpu_var(local_per_cpu_offset)))
extern void percpu_modcopy(void *pcpudst, const void *src, unsigned long size);
extern void setup_per_cpu_areas (void);
@@ -51,6 +52,7 @@ extern void *per_cpu_init(void);
#define per_cpu(var, cpu) (*((void)(cpu), &per_cpu__##var))
#define __get_cpu_var(var) per_cpu__##var
+#define __raw_get_cpu_var(var) per_cpu__##var
#define per_cpu_init() (__phys_per_cpu_start)
#endif /* SMP */
diff --git a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h
index eaac08d..228981c 100644
--- a/include/asm-ia64/pgtable.h
+++ b/include/asm-ia64/pgtable.h
@@ -316,22 +316,20 @@ ia64_phys_addr_valid (unsigned long addr)
#define pte_mkhuge(pte) (__pte(pte_val(pte)))
/*
- * Macro to a page protection value as "uncacheable". Note that "protection" is really a
- * misnomer here as the protection value contains the memory attribute bits, dirty bits,
- * and various other bits as well.
+ * Make page protection values cacheable, uncacheable, or write-
+ * combining. Note that "protection" is really a misnomer here as the
+ * protection value contains the memory attribute bits, dirty bits, and
+ * various other bits as well.
*/
+#define pgprot_cacheable(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_WB)
#define pgprot_noncached(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_UC)
-
-/*
- * Macro to make mark a page protection value as "write-combining".
- * Note that "protection" is really a misnomer here as the protection
- * value contains the memory attribute bits, dirty bits, and various
- * other bits as well. Accesses through a write-combining translation
- * works bypasses the caches, but does allow for consecutive writes to
- * be combined into single (but larger) write transactions.
- */
#define pgprot_writecombine(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_WC)
+struct file;
+extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+ unsigned long size, pgprot_t vma_prot);
+#define __HAVE_PHYS_MEM_ACCESS_PROT
+
static inline unsigned long
pgd_index (unsigned long address)
{
diff --git a/include/asm-ia64/sn/intr.h b/include/asm-ia64/sn/intr.h
index 60a51a4..12b54dd 100644
--- a/include/asm-ia64/sn/intr.h
+++ b/include/asm-ia64/sn/intr.h
@@ -10,6 +10,7 @@
#define _ASM_IA64_SN_INTR_H
#include <linux/rcupdate.h>
+#include <asm/sn/types.h>
#define SGI_UART_VECTOR 0xe9
@@ -40,6 +41,7 @@ struct sn_irq_info {
int irq_cpuid; /* kernel logical cpuid */
int irq_irq; /* the IRQ number */
int irq_int_bit; /* Bridge interrupt pin */
+ /* <0 means MSI */
u64 irq_xtalkaddr; /* xtalkaddr IRQ is sent to */
int irq_bridge_type;/* pciio asic type (pciio.h) */
void *irq_bridge; /* bridge generating irq */
@@ -53,6 +55,12 @@ struct sn_irq_info {
};
extern void sn_send_IPI_phys(int, long, int, int);
+extern u64 sn_intr_alloc(nasid_t, int,
+ struct sn_irq_info *,
+ int, nasid_t, int);
+extern void sn_intr_free(nasid_t, int, struct sn_irq_info *);
+extern struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *, nasid_t, int);
+extern struct list_head **sn_irq_lh;
#define CPU_VECTOR_TO_IRQ(cpuid,vector) (vector)
diff --git a/include/asm-ia64/sn/pcibr_provider.h b/include/asm-ia64/sn/pcibr_provider.h
index 51260ab..e3b0c3f 100644
--- a/include/asm-ia64/sn/pcibr_provider.h
+++ b/include/asm-ia64/sn/pcibr_provider.h
@@ -55,6 +55,7 @@
#define PCI32_ATE_V (0x1 << 0)
#define PCI32_ATE_CO (0x1 << 1)
#define PCI32_ATE_PREC (0x1 << 2)
+#define PCI32_ATE_MSI (0x1 << 2)
#define PCI32_ATE_PREF (0x1 << 3)
#define PCI32_ATE_BAR (0x1 << 4)
#define PCI32_ATE_ADDR_SHFT 12
@@ -117,8 +118,8 @@ struct pcibus_info {
extern int pcibr_init_provider(void);
extern void *pcibr_bus_fixup(struct pcibus_bussoft *, struct pci_controller *);
-extern dma_addr_t pcibr_dma_map(struct pci_dev *, unsigned long, size_t);
-extern dma_addr_t pcibr_dma_map_consistent(struct pci_dev *, unsigned long, size_t);
+extern dma_addr_t pcibr_dma_map(struct pci_dev *, unsigned long, size_t, int type);
+extern dma_addr_t pcibr_dma_map_consistent(struct pci_dev *, unsigned long, size_t, int type);
extern void pcibr_dma_unmap(struct pci_dev *, dma_addr_t, int);
/*
diff --git a/include/asm-ia64/sn/pcibus_provider_defs.h b/include/asm-ia64/sn/pcibus_provider_defs.h
index ce3f6c3..8f7c83d 100644
--- a/include/asm-ia64/sn/pcibus_provider_defs.h
+++ b/include/asm-ia64/sn/pcibus_provider_defs.h
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
*/
#ifndef _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H
#define _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H
@@ -45,13 +45,24 @@ struct pci_controller;
*/
struct sn_pcibus_provider {
- dma_addr_t (*dma_map)(struct pci_dev *, unsigned long, size_t);
- dma_addr_t (*dma_map_consistent)(struct pci_dev *, unsigned long, size_t);
+ dma_addr_t (*dma_map)(struct pci_dev *, unsigned long, size_t, int flags);
+ dma_addr_t (*dma_map_consistent)(struct pci_dev *, unsigned long, size_t, int flags);
void (*dma_unmap)(struct pci_dev *, dma_addr_t, int);
void * (*bus_fixup)(struct pcibus_bussoft *, struct pci_controller *);
void (*force_interrupt)(struct sn_irq_info *);
void (*target_interrupt)(struct sn_irq_info *);
};
+/*
+ * Flags used by the map interfaces
+ * bits 3:0 specifies format of passed in address
+ * bit 4 specifies that address is to be used for MSI
+ */
+
+#define SN_DMA_ADDRTYPE(x) ((x) & 0xf)
+#define SN_DMA_ADDR_PHYS 1 /* address is an xio address. */
+#define SN_DMA_ADDR_XIO 2 /* address is phys memory */
+#define SN_DMA_MSI 0x10 /* Bus address is to be used for MSI */
+
extern struct sn_pcibus_provider *sn_pci_provider[];
#endif /* _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H */
diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h
index 8c865e4..cd490b2 100644
--- a/include/asm-ia64/sn/sn_sal.h
+++ b/include/asm-ia64/sn/sn_sal.h
@@ -345,7 +345,7 @@ ia64_sn_plat_set_error_handling_features(void)
ret_stuff.v1 = 0;
ret_stuff.v2 = 0;
SAL_CALL_REENTRANT(ret_stuff, SN_SAL_SET_ERROR_HANDLING_FEATURES,
- (SAL_ERR_FEAT_MCA_SLV_TO_OS_INIT_SLV | SAL_ERR_FEAT_LOG_SBES),
+ SAL_ERR_FEAT_LOG_SBES,
0, 0, 0, 0, 0, 0);
return ret_stuff.status;
diff --git a/include/asm-ia64/sn/tiocp.h b/include/asm-ia64/sn/tiocp.h
index f47c08a..e8ad0bb 100644
--- a/include/asm-ia64/sn/tiocp.h
+++ b/include/asm-ia64/sn/tiocp.h
@@ -3,13 +3,14 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2003-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2003-2005 Silicon Graphics, Inc. All rights reserved.
*/
#ifndef _ASM_IA64_SN_PCI_TIOCP_H
#define _ASM_IA64_SN_PCI_TIOCP_H
#define TIOCP_HOST_INTR_ADDR 0x003FFFFFFFFFFFFFUL
#define TIOCP_PCI64_CMDTYPE_MEM (0x1ull << 60)
+#define TIOCP_PCI64_CMDTYPE_MSI (0x3ull << 60)
/*****************************************************************************
diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h
index 632f2ee..bb0eb72 100644
--- a/include/asm-ia64/unistd.h
+++ b/include/asm-ia64/unistd.h
@@ -265,7 +265,7 @@
#define __NR_keyctl 1273
#define __NR_ioprio_set 1274
#define __NR_ioprio_get 1275
-/* 1276 is available for reuse (was briefly sys_set_zone_reclaim) */
+#define __NR_move_pages 1276
#define __NR_inotify_init 1277
#define __NR_inotify_add_watch 1278
#define __NR_inotify_rm_watch 1279
diff --git a/include/asm-ia64/vga.h b/include/asm-ia64/vga.h
index 091177c..02184ec 100644
--- a/include/asm-ia64/vga.h
+++ b/include/asm-ia64/vga.h
@@ -17,7 +17,7 @@
extern unsigned long vga_console_iobase;
extern unsigned long vga_console_membase;
-#define VGA_MAP_MEM(x) ((unsigned long) ioremap_nocache(vga_console_membase + (x), 0))
+#define VGA_MAP_MEM(x,s) ((unsigned long) ioremap_nocache(vga_console_membase + (x), s))
#define vga_readb(x) (*(x))
#define vga_writeb(x,y) (*(y) = (x))
diff --git a/include/asm-m32r/vga.h b/include/asm-m32r/vga.h
index d0f4b6e..5331634 100644
--- a/include/asm-m32r/vga.h
+++ b/include/asm-m32r/vga.h
@@ -14,7 +14,7 @@
* access the videoram directly without any black magic.
*/
-#define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x)
+#define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x)
#define vga_readb(x) (*(x))
#define vga_writeb(x,y) (*(y) = (x))
diff --git a/include/asm-m68k/amigaints.h b/include/asm-m68k/amigaints.h
index aa968d0..7c87134 100644
--- a/include/asm-m68k/amigaints.h
+++ b/include/asm-m68k/amigaints.h
@@ -13,6 +13,8 @@
#ifndef _ASMm68k_AMIGAINTS_H_
#define _ASMm68k_AMIGAINTS_H_
+#include <asm/irq.h>
+
/*
** Amiga Interrupt sources.
**
@@ -23,72 +25,52 @@
#define CIA_IRQS (5)
#define AMI_IRQS (32) /* AUTO_IRQS+AMI_STD_IRQS+2*CIA_IRQS */
-/* vertical blanking interrupt */
-#define IRQ_AMIGA_VERTB 0
+/* builtin serial port interrupts */
+#define IRQ_AMIGA_TBE (IRQ_USER+0)
+#define IRQ_AMIGA_RBF (IRQ_USER+11)
-/* copper interrupt */
-#define IRQ_AMIGA_COPPER 1
+/* floppy disk interrupts */
+#define IRQ_AMIGA_DSKBLK (IRQ_USER+1)
+#define IRQ_AMIGA_DSKSYN (IRQ_USER+12)
-/* Audio interrupts */
-#define IRQ_AMIGA_AUD0 2
-#define IRQ_AMIGA_AUD1 3
-#define IRQ_AMIGA_AUD2 4
-#define IRQ_AMIGA_AUD3 5
+/* software interrupts */
+#define IRQ_AMIGA_SOFT (IRQ_USER+2)
-/* Blitter done interrupt */
-#define IRQ_AMIGA_BLIT 6
+/* interrupts from external hardware */
+#define IRQ_AMIGA_PORTS IRQ_AUTO_2
+#define IRQ_AMIGA_EXTER IRQ_AUTO_6
-/* floppy disk interrupts */
-#define IRQ_AMIGA_DSKSYN 7
-#define IRQ_AMIGA_DSKBLK 8
+/* copper interrupt */
+#define IRQ_AMIGA_COPPER (IRQ_USER+4)
-/* builtin serial port interrupts */
-#define IRQ_AMIGA_RBF 9
-#define IRQ_AMIGA_TBE 10
+/* vertical blanking interrupt */
+#define IRQ_AMIGA_VERTB (IRQ_USER+5)
-/* software interrupts */
-#define IRQ_AMIGA_SOFT 11
+/* Blitter done interrupt */
+#define IRQ_AMIGA_BLIT (IRQ_USER+6)
-/* interrupts from external hardware */
-#define IRQ_AMIGA_PORTS 12
-#define IRQ_AMIGA_EXTER 13
+/* Audio interrupts */
+#define IRQ_AMIGA_AUD0 (IRQ_USER+7)
+#define IRQ_AMIGA_AUD1 (IRQ_USER+8)
+#define IRQ_AMIGA_AUD2 (IRQ_USER+9)
+#define IRQ_AMIGA_AUD3 (IRQ_USER+10)
/* CIA interrupt sources */
-#define IRQ_AMIGA_CIAA 14
-#define IRQ_AMIGA_CIAA_TA 14
-#define IRQ_AMIGA_CIAA_TB 15
-#define IRQ_AMIGA_CIAA_ALRM 16
-#define IRQ_AMIGA_CIAA_SP 17
-#define IRQ_AMIGA_CIAA_FLG 18
-#define IRQ_AMIGA_CIAB 19
-#define IRQ_AMIGA_CIAB_TA 19
-#define IRQ_AMIGA_CIAB_TB 20
-#define IRQ_AMIGA_CIAB_ALRM 21
-#define IRQ_AMIGA_CIAB_SP 22
-#define IRQ_AMIGA_CIAB_FLG 23
-
-/* auto-vector interrupts */
-#define IRQ_AMIGA_AUTO 24
-#define IRQ_AMIGA_AUTO_0 24 /* This is just a dummy */
-#define IRQ_AMIGA_AUTO_1 25
-#define IRQ_AMIGA_AUTO_2 26
-#define IRQ_AMIGA_AUTO_3 27
-#define IRQ_AMIGA_AUTO_4 28
-#define IRQ_AMIGA_AUTO_5 29
-#define IRQ_AMIGA_AUTO_6 30
-#define IRQ_AMIGA_AUTO_7 31
-
-#define IRQ_FLOPPY IRQ_AMIGA_DSKBLK
+#define IRQ_AMIGA_CIAA (IRQ_USER+14)
+#define IRQ_AMIGA_CIAA_TA (IRQ_USER+14)
+#define IRQ_AMIGA_CIAA_TB (IRQ_USER+15)
+#define IRQ_AMIGA_CIAA_ALRM (IRQ_USER+16)
+#define IRQ_AMIGA_CIAA_SP (IRQ_USER+17)
+#define IRQ_AMIGA_CIAA_FLG (IRQ_USER+18)
+#define IRQ_AMIGA_CIAB (IRQ_USER+19)
+#define IRQ_AMIGA_CIAB_TA (IRQ_USER+19)
+#define IRQ_AMIGA_CIAB_TB (IRQ_USER+20)
+#define IRQ_AMIGA_CIAB_ALRM (IRQ_USER+21)
+#define IRQ_AMIGA_CIAB_SP (IRQ_USER+22)
+#define IRQ_AMIGA_CIAB_FLG (IRQ_USER+23)
-/* INTREQR masks */
-#define IRQ1_MASK 0x0007 /* INTREQR mask for IRQ 1 */
-#define IRQ2_MASK 0x0008 /* INTREQR mask for IRQ 2 */
-#define IRQ3_MASK 0x0070 /* INTREQR mask for IRQ 3 */
-#define IRQ4_MASK 0x0780 /* INTREQR mask for IRQ 4 */
-#define IRQ5_MASK 0x1800 /* INTREQR mask for IRQ 5 */
-#define IRQ6_MASK 0x2000 /* INTREQR mask for IRQ 6 */
-#define IRQ7_MASK 0x4000 /* INTREQR mask for IRQ 7 */
+/* INTREQR masks */
#define IF_SETCLR 0x8000 /* set/clr bit */
#define IF_INTEN 0x4000 /* master interrupt bit in INT* registers */
#define IF_EXTER 0x2000 /* external level 6 and CIA B interrupt */
@@ -106,9 +88,6 @@
#define IF_DSKBLK 0x0002 /* diskblock DMA finished */
#define IF_TBE 0x0001 /* serial transmit buffer empty interrupt */
-extern void amiga_do_irq(int irq, struct pt_regs *fp);
-extern void amiga_do_irq_list(int irq, struct pt_regs *fp);
-
/* CIA interrupt control register bits */
#define CIA_ICR_TA 0x01
@@ -125,6 +104,7 @@ extern void amiga_do_irq_list(int irq, struct pt_regs *fp);
extern struct ciabase ciaa_base, ciab_base;
+extern void cia_init_IRQ(struct ciabase *base);
extern unsigned char cia_set_irq(struct ciabase *base, unsigned char mask);
extern unsigned char cia_able_irq(struct ciabase *base, unsigned char mask);
diff --git a/include/asm-m68k/apollohw.h b/include/asm-m68k/apollohw.h
index 4304e1c..a1373b9 100644
--- a/include/asm-m68k/apollohw.h
+++ b/include/asm-m68k/apollohw.h
@@ -3,6 +3,8 @@
#ifndef _ASMm68k_APOLLOHW_H_
#define _ASMm68k_APOLLOHW_H_
+#include <linux/types.h>
+
/*
apollo models
*/
@@ -101,4 +103,6 @@ extern u_long timer_physaddr;
#define isaIO2mem(x) (((((x) & 0x3f8) << 7) | (((x) & 0xfc00) >> 6) | ((x) & 0x7)) + 0x40000 + IO_BASE)
+#define IRQ_APOLLO IRQ_USER
+
#endif
diff --git a/include/asm-m68k/atari_stdma.h b/include/asm-m68k/atari_stdma.h
index 64f9288..b4eadf8 100644
--- a/include/asm-m68k/atari_stdma.h
+++ b/include/asm-m68k/atari_stdma.h
@@ -3,7 +3,7 @@
#define _atari_stdma_h
-#include <asm/irq.h>
+#include <linux/interrupt.h>
/***************************** Prototypes *****************************/
diff --git a/include/asm-m68k/atariints.h b/include/asm-m68k/atariints.h
index 42952c8..0ed454f 100644
--- a/include/asm-m68k/atariints.h
+++ b/include/asm-m68k/atariints.h
@@ -45,17 +45,6 @@
#define IRQ_TYPE_FAST 1
#define IRQ_TYPE_PRIO 2
-#define IRQ_SPURIOUS (0)
-
-/* auto-vector interrupts */
-#define IRQ_AUTO_1 (1)
-#define IRQ_AUTO_2 (2)
-#define IRQ_AUTO_3 (3)
-#define IRQ_AUTO_4 (4)
-#define IRQ_AUTO_5 (5)
-#define IRQ_AUTO_6 (6)
-#define IRQ_AUTO_7 (7)
-
/* ST-MFP interrupts */
#define IRQ_MFP_BUSY (8)
#define IRQ_MFP_DCD (9)
diff --git a/include/asm-m68k/bvme6000hw.h b/include/asm-m68k/bvme6000hw.h
index 28a859b..f40d2f8 100644
--- a/include/asm-m68k/bvme6000hw.h
+++ b/include/asm-m68k/bvme6000hw.h
@@ -109,23 +109,23 @@ typedef struct {
#define BVME_IRQ_TYPE_PRIO 0
-#define BVME_IRQ_PRN 0x54
-#define BVME_IRQ_I596 0x1a
-#define BVME_IRQ_SCSI 0x1b
-#define BVME_IRQ_TIMER 0x59
-#define BVME_IRQ_RTC 0x1e
-#define BVME_IRQ_ABORT 0x1f
+#define BVME_IRQ_PRN (IRQ_USER+20)
+#define BVME_IRQ_TIMER (IRQ_USER+25)
+#define BVME_IRQ_I596 IRQ_AUTO_2
+#define BVME_IRQ_SCSI IRQ_AUTO_3
+#define BVME_IRQ_RTC IRQ_AUTO_6
+#define BVME_IRQ_ABORT IRQ_AUTO_7
/* SCC interrupts */
-#define BVME_IRQ_SCC_BASE 0x40
-#define BVME_IRQ_SCCB_TX 0x40
-#define BVME_IRQ_SCCB_STAT 0x42
-#define BVME_IRQ_SCCB_RX 0x44
-#define BVME_IRQ_SCCB_SPCOND 0x46
-#define BVME_IRQ_SCCA_TX 0x48
-#define BVME_IRQ_SCCA_STAT 0x4a
-#define BVME_IRQ_SCCA_RX 0x4c
-#define BVME_IRQ_SCCA_SPCOND 0x4e
+#define BVME_IRQ_SCC_BASE IRQ_USER
+#define BVME_IRQ_SCCB_TX IRQ_USER
+#define BVME_IRQ_SCCB_STAT (IRQ_USER+2)
+#define BVME_IRQ_SCCB_RX (IRQ_USER+4)
+#define BVME_IRQ_SCCB_SPCOND (IRQ_USER+6)
+#define BVME_IRQ_SCCA_TX (IRQ_USER+8)
+#define BVME_IRQ_SCCA_STAT (IRQ_USER+10)
+#define BVME_IRQ_SCCA_RX (IRQ_USER+12)
+#define BVME_IRQ_SCCA_SPCOND (IRQ_USER+14)
/* Address control registers */
diff --git a/include/asm-m68k/cacheflush.h b/include/asm-m68k/cacheflush.h
index 8aba971..24d3ff4 100644
--- a/include/asm-m68k/cacheflush.h
+++ b/include/asm-m68k/cacheflush.h
@@ -3,26 +3,30 @@
#include <linux/mm.h>
+/* cache code */
+#define FLUSH_I_AND_D (0x00000808)
+#define FLUSH_I (0x00000008)
+
/*
* Cache handling functions
*/
-#define flush_icache() \
-({ \
- if (CPU_IS_040_OR_060) \
- __asm__ __volatile__("nop\n\t" \
- ".chip 68040\n\t" \
- "cinva %%ic\n\t" \
- ".chip 68k" : ); \
- else { \
- unsigned long _tmp; \
- __asm__ __volatile__("movec %%cacr,%0\n\t" \
- "orw %1,%0\n\t" \
- "movec %0,%%cacr" \
- : "=&d" (_tmp) \
- : "id" (FLUSH_I)); \
- } \
-})
+static inline void flush_icache(void)
+{
+ if (CPU_IS_040_OR_060)
+ asm volatile ( "nop\n"
+ " .chip 68040\n"
+ " cpusha %bc\n"
+ " .chip 68k");
+ else {
+ unsigned long tmp;
+ asm volatile ( "movec %%cacr,%0\n"
+ " or.w %1,%0\n"
+ " movec %0,%%cacr"
+ : "=&d" (tmp)
+ : "id" (FLUSH_I));
+ }
+}
/*
* invalidate the cache for the specified memory range.
@@ -43,10 +47,6 @@ extern void cache_push(unsigned long paddr, int len);
*/
extern void cache_push_v(unsigned long vaddr, int len);
-/* cache code */
-#define FLUSH_I_AND_D (0x00000808)
-#define FLUSH_I (0x00000008)
-
/* This is needed whenever the virtual mapping of the current
process changes. */
#define __flush_cache_all() \
diff --git a/include/asm-m68k/dma-mapping.h b/include/asm-m68k/dma-mapping.h
index dffd59c..cebbb03 100644
--- a/include/asm-m68k/dma-mapping.h
+++ b/include/asm-m68k/dma-mapping.h
@@ -1,11 +1,91 @@
#ifndef _M68K_DMA_MAPPING_H
#define _M68K_DMA_MAPPING_H
+#include <asm/cache.h>
-#ifdef CONFIG_PCI
-#include <asm-generic/dma-mapping.h>
-#else
-#include <asm-generic/dma-mapping-broken.h>
-#endif
+struct scatterlist;
+
+static inline int dma_supported(struct device *dev, u64 mask)
+{
+ return 1;
+}
+
+static inline int dma_set_mask(struct device *dev, u64 mask)
+{
+ return 0;
+}
+
+static inline int dma_get_cache_alignment(void)
+{
+ return 1 << L1_CACHE_SHIFT;
+}
+
+static inline int dma_is_consistent(dma_addr_t dma_addr)
+{
+ return 0;
+}
+
+extern void *dma_alloc_coherent(struct device *, size_t,
+ dma_addr_t *, int);
+extern void dma_free_coherent(struct device *, size_t,
+ void *, dma_addr_t);
+
+static inline void *dma_alloc_noncoherent(struct device *dev, size_t size,
+ dma_addr_t *handle, int flag)
+{
+ return dma_alloc_coherent(dev, size, handle, flag);
+}
+static inline void dma_free_noncoherent(struct device *dev, size_t size,
+ void *addr, dma_addr_t handle)
+{
+ dma_free_coherent(dev, size, addr, handle);
+}
+static inline void dma_cache_sync(void *vaddr, size_t size,
+ enum dma_data_direction dir)
+{
+ /* we use coherent allocation, so not much to do here. */
+}
+
+extern dma_addr_t dma_map_single(struct device *, void *, size_t,
+ enum dma_data_direction);
+static inline void dma_unmap_single(struct device *dev, dma_addr_t addr,
+ size_t size, enum dma_data_direction dir)
+{
+}
+
+extern dma_addr_t dma_map_page(struct device *, struct page *,
+ unsigned long, size_t size,
+ enum dma_data_direction);
+static inline void dma_unmap_page(struct device *dev, dma_addr_t address,
+ size_t size, enum dma_data_direction dir)
+{
+}
+
+extern int dma_map_sg(struct device *, struct scatterlist *, int,
+ enum dma_data_direction);
+static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nhwentries, enum dma_data_direction dir)
+{
+}
+
+extern void dma_sync_single_for_device(struct device *, dma_addr_t, size_t,
+ enum dma_data_direction);
+extern void dma_sync_sg_for_device(struct device *, struct scatterlist *, int,
+ enum dma_data_direction);
+
+static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle,
+ size_t size, enum dma_data_direction dir)
+{
+}
+
+static inline void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir)
+{
+}
+
+static inline int dma_mapping_error(dma_addr_t handle)
+{
+ return 0;
+}
#endif /* _M68K_DMA_MAPPING_H */
diff --git a/include/asm-m68k/irq.h b/include/asm-m68k/irq.h
index b4f48b2..f4ae7d8 100644
--- a/include/asm-m68k/irq.h
+++ b/include/asm-m68k/irq.h
@@ -1,13 +1,9 @@
#ifndef _M68K_IRQ_H_
#define _M68K_IRQ_H_
-#include <linux/interrupt.h>
-
-/*
- * # of m68k interrupts
- */
-
-#define SYS_IRQS 8
+#include <linux/linkage.h>
+#include <linux/hardirq.h>
+#include <linux/spinlock_types.h>
/*
* This should be the same as the max(NUM_X_SOURCES) for all the
@@ -15,10 +11,20 @@
* Currently the Atari has 72 and the Amiga 24, but if both are
* supported in the kernel it is better to make room for 72.
*/
-#if defined(CONFIG_ATARI) || defined(CONFIG_MAC)
-#define NR_IRQS (72+SYS_IRQS)
+#if defined(CONFIG_VME) || defined(CONFIG_SUN3) || defined(CONFIG_SUN3X)
+#define NR_IRQS 200
+#elif defined(CONFIG_ATARI) || defined(CONFIG_MAC)
+#define NR_IRQS 72
+#elif defined(CONFIG_Q40)
+#define NR_IRQS 43
+#elif defined(CONFIG_AMIGA)
+#define NR_IRQS 32
+#elif defined(CONFIG_APOLLO)
+#define NR_IRQS 24
+#elif defined(CONFIG_HP300)
+#define NR_IRQS 8
#else
-#define NR_IRQS (24+SYS_IRQS)
+#error unknown nr of irqs
#endif
/*
@@ -40,53 +46,25 @@
* that routine requires service.
*/
-#define IRQ1 (1) /* level 1 interrupt */
-#define IRQ2 (2) /* level 2 interrupt */
-#define IRQ3 (3) /* level 3 interrupt */
-#define IRQ4 (4) /* level 4 interrupt */
-#define IRQ5 (5) /* level 5 interrupt */
-#define IRQ6 (6) /* level 6 interrupt */
-#define IRQ7 (7) /* level 7 interrupt (non-maskable) */
+#define IRQ_SPURIOUS 0
-/*
- * "Generic" interrupt sources
- */
-
-#define IRQ_SCHED_TIMER (8) /* interrupt source for scheduling timer */
+#define IRQ_AUTO_1 1 /* level 1 interrupt */
+#define IRQ_AUTO_2 2 /* level 2 interrupt */
+#define IRQ_AUTO_3 3 /* level 3 interrupt */
+#define IRQ_AUTO_4 4 /* level 4 interrupt */
+#define IRQ_AUTO_5 5 /* level 5 interrupt */
+#define IRQ_AUTO_6 6 /* level 6 interrupt */
+#define IRQ_AUTO_7 7 /* level 7 interrupt (non-maskable) */
-static __inline__ int irq_canonicalize(int irq)
-{
- return irq;
-}
-
-/*
- * Machine specific interrupt sources.
- *
- * Adding an interrupt service routine for a source with this bit
- * set indicates a special machine specific interrupt source.
- * The machine specific files define these sources.
- *
- * The IRQ_MACHSPEC bit is now gone - the only thing it did was to
- * introduce unnecessary overhead.
- *
- * All interrupt handling is actually machine specific so it is better
- * to use function pointers, as used by the Sparc port, and select the
- * interrupt handling functions when initializing the kernel. This way
- * we save some unnecessary overhead at run-time.
- * 01/11/97 - Jes
- */
+#define IRQ_USER 8
-extern void (*enable_irq)(unsigned int);
-extern void (*disable_irq)(unsigned int);
+extern unsigned int irq_canonicalize(unsigned int irq);
+extern void enable_irq(unsigned int);
+extern void disable_irq(unsigned int);
#define disable_irq_nosync disable_irq
struct pt_regs;
-extern int cpu_request_irq(unsigned int,
- irqreturn_t (*)(int, void *, struct pt_regs *),
- unsigned long, const char *, void *);
-extern void cpu_free_irq(unsigned int, void *);
-
/*
* various flags for request_irq() - the Amiga now uses the standard
* mechanism like all other architectures - SA_INTERRUPT and SA_SHIRQ
@@ -105,33 +83,45 @@ extern void cpu_free_irq(unsigned int, void *);
* interrupt source (if it supports chaining).
*/
typedef struct irq_node {
- irqreturn_t (*handler)(int, void *, struct pt_regs *);
- unsigned long flags;
+ int (*handler)(int, void *, struct pt_regs *);
void *dev_id;
- const char *devname;
struct irq_node *next;
+ unsigned long flags;
+ const char *devname;
} irq_node_t;
/*
* This structure has only 4 elements for speed reasons
*/
typedef struct irq_handler {
- irqreturn_t (*handler)(int, void *, struct pt_regs *);
+ int (*handler)(int, void *, struct pt_regs *);
unsigned long flags;
void *dev_id;
const char *devname;
} irq_handler_t;
-/* count of spurious interrupts */
-extern volatile unsigned int num_spurious;
+struct irq_controller {
+ const char *name;
+ spinlock_t lock;
+ int (*startup)(unsigned int irq);
+ void (*shutdown)(unsigned int irq);
+ void (*enable)(unsigned int irq);
+ void (*disable)(unsigned int irq);
+};
+
+extern int m68k_irq_startup(unsigned int);
+extern void m68k_irq_shutdown(unsigned int);
/*
* This function returns a new irq_node_t
*/
extern irq_node_t *new_irq_node(void);
-struct irqaction;
-struct pt_regs;
-int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+extern void m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *));
+extern void m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt,
+ void (*handler)(unsigned int, struct pt_regs *));
+extern void m68k_setup_irq_controller(struct irq_controller *, unsigned int, unsigned int);
+
+asmlinkage void m68k_handle_int(unsigned int, struct pt_regs *);
#endif /* _M68K_IRQ_H_ */
diff --git a/include/asm-m68k/mac_oss.h b/include/asm-m68k/mac_oss.h
index 7644a63..7221f72 100644
--- a/include/asm-m68k/mac_oss.h
+++ b/include/asm-m68k/mac_oss.h
@@ -69,12 +69,12 @@
#define OSS_IRQLEV_DISABLED 0
#define OSS_IRQLEV_IOPISM 1 /* ADB? */
-#define OSS_IRQLEV_SCSI 2
-#define OSS_IRQLEV_NUBUS 3 /* keep this on its own level */
-#define OSS_IRQLEV_IOPSCC 4 /* matches VIA alternate mapping */
-#define OSS_IRQLEV_SOUND 5 /* matches VIA alternate mapping */
+#define OSS_IRQLEV_SCSI IRQ_AUTO_2
+#define OSS_IRQLEV_NUBUS IRQ_AUTO_3 /* keep this on its own level */
+#define OSS_IRQLEV_IOPSCC IRQ_AUTO_4 /* matches VIA alternate mapping */
+#define OSS_IRQLEV_SOUND IRQ_AUTO_5 /* matches VIA alternate mapping */
#define OSS_IRQLEV_60HZ 6 /* matches VIA alternate mapping */
-#define OSS_IRQLEV_VIA1 6 /* matches VIA alternate mapping */
+#define OSS_IRQLEV_VIA1 IRQ_AUTO_6 /* matches VIA alternate mapping */
#define OSS_IRQLEV_PARITY 7 /* matches VIA alternate mapping */
#ifndef __ASSEMBLY__
diff --git a/include/asm-m68k/machdep.h b/include/asm-m68k/machdep.h
index 7d3fee3..df898f2 100644
--- a/include/asm-m68k/machdep.h
+++ b/include/asm-m68k/machdep.h
@@ -13,14 +13,8 @@ struct buffer_head;
extern void (*mach_sched_init) (irqreturn_t (*handler)(int, void *, struct pt_regs *));
/* machine dependent irq functions */
extern void (*mach_init_IRQ) (void);
-extern irqreturn_t (*(*mach_default_handler)[]) (int, void *, struct pt_regs *);
-extern int (*mach_request_irq) (unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
- unsigned long flags, const char *devname, void *dev_id);
-extern void (*mach_free_irq) (unsigned int irq, void *dev_id);
extern void (*mach_get_model) (char *model);
extern int (*mach_get_hardware_list) (char *buffer);
-extern int (*mach_get_irq_list) (struct seq_file *p, void *v);
-extern irqreturn_t (*mach_process_int) (int irq, struct pt_regs *fp);
/* machine dependent timer functions */
extern unsigned long (*mach_gettimeoffset)(void);
extern int (*mach_hwclk)(int, struct rtc_time*);
diff --git a/include/asm-m68k/macintosh.h b/include/asm-m68k/macintosh.h
index 6fc3d19..27d11da 100644
--- a/include/asm-m68k/macintosh.h
+++ b/include/asm-m68k/macintosh.h
@@ -11,17 +11,7 @@
extern void mac_reset(void);
extern void mac_poweroff(void);
extern void mac_init_IRQ(void);
-extern int mac_request_irq (unsigned int, irqreturn_t (*)(int, void *,
- struct pt_regs *),
- unsigned long, const char *, void *);
-extern void mac_free_irq(unsigned int, void *);
-extern void mac_enable_irq(unsigned int);
-extern void mac_disable_irq(unsigned int);
extern int mac_irq_pending(unsigned int);
-extern int show_mac_interrupts(struct seq_file *, void *);
-#if 0
-extern void mac_default_handler(int irq);
-#endif
extern void mac_identify(void);
extern void mac_report_hardware(void);
extern void mac_debugging_penguin(int);
diff --git a/include/asm-m68k/macints.h b/include/asm-m68k/macints.h
index fd8c3a9..679c48a 100644
--- a/include/asm-m68k/macints.h
+++ b/include/asm-m68k/macints.h
@@ -59,17 +59,6 @@
#define IRQ_SRC(irq) (irq >> 3)
#define IRQ_IDX(irq) (irq & 7)
-#define IRQ_SPURIOUS (0)
-
-/* auto-vector interrupts */
-#define IRQ_AUTO_1 (1)
-#define IRQ_AUTO_2 (2)
-#define IRQ_AUTO_3 (3)
-#define IRQ_AUTO_4 (4)
-#define IRQ_AUTO_5 (5)
-#define IRQ_AUTO_6 (6)
-#define IRQ_AUTO_7 (7)
-
/* VIA1 interrupts */
#define IRQ_VIA1_0 (8) /* one second int. */
#define IRQ_VIA1_1 (9) /* VBlank int. */
@@ -163,7 +152,4 @@
#define INT_CLK 24576 /* CLK while int_clk =2.456MHz and divide = 100 */
#define INT_TICKS 246 /* to make sched_time = 99.902... HZ */
-extern irq_node_t *mac_irq_list[NUM_MAC_SOURCES];
-extern void mac_do_irq_list(int irq, struct pt_regs *);
-
#endif /* asm/macints.h */
diff --git a/include/asm-m68k/mvme147hw.h b/include/asm-m68k/mvme147hw.h
index f245139..b810431 100644
--- a/include/asm-m68k/mvme147hw.h
+++ b/include/asm-m68k/mvme147hw.h
@@ -1,6 +1,8 @@
#ifndef _MVME147HW_H_
#define _MVME147HW_H_
+#include <asm/irq.h>
+
typedef struct {
unsigned char
ctrl,
@@ -72,39 +74,39 @@ struct pcc_regs {
#define PCC_LEVEL_SCSI_PORT 0x04
#define PCC_LEVEL_SCSI_DMA 0x04
-#define PCC_IRQ_AC_FAIL 0x40
-#define PCC_IRQ_BERR 0x41
-#define PCC_IRQ_ABORT 0x42
-/* #define PCC_IRQ_SERIAL 0x43 */
-#define PCC_IRQ_PRINTER 0x47
-#define PCC_IRQ_TIMER1 0x48
-#define PCC_IRQ_TIMER2 0x49
-#define PCC_IRQ_SOFTWARE1 0x4a
-#define PCC_IRQ_SOFTWARE2 0x4b
+#define PCC_IRQ_AC_FAIL (IRQ_USER+0)
+#define PCC_IRQ_BERR (IRQ_USER+1)
+#define PCC_IRQ_ABORT (IRQ_USER+2)
+/* #define PCC_IRQ_SERIAL (IRQ_USER+3) */
+#define PCC_IRQ_PRINTER (IRQ_USER+7)
+#define PCC_IRQ_TIMER1 (IRQ_USER+8)
+#define PCC_IRQ_TIMER2 (IRQ_USER+9)
+#define PCC_IRQ_SOFTWARE1 (IRQ_USER+10)
+#define PCC_IRQ_SOFTWARE2 (IRQ_USER+11)
#define M147_SCC_A_ADDR 0xfffe3002
#define M147_SCC_B_ADDR 0xfffe3000
#define M147_SCC_PCLK 5000000
-#define MVME147_IRQ_SCSI_PORT 0x45
-#define MVME147_IRQ_SCSI_DMA 0x46
+#define MVME147_IRQ_SCSI_PORT (IRQ_USER+0x45)
+#define MVME147_IRQ_SCSI_DMA (IRQ_USER+0x46)
/* SCC interrupts, for MVME147 */
#define MVME147_IRQ_TYPE_PRIO 0
-#define MVME147_IRQ_SCC_BASE 0x60
-#define MVME147_IRQ_SCCB_TX 0x60
-#define MVME147_IRQ_SCCB_STAT 0x62
-#define MVME147_IRQ_SCCB_RX 0x64
-#define MVME147_IRQ_SCCB_SPCOND 0x66
-#define MVME147_IRQ_SCCA_TX 0x68
-#define MVME147_IRQ_SCCA_STAT 0x6a
-#define MVME147_IRQ_SCCA_RX 0x6c
-#define MVME147_IRQ_SCCA_SPCOND 0x6e
+#define MVME147_IRQ_SCC_BASE (IRQ_USER+32)
+#define MVME147_IRQ_SCCB_TX (IRQ_USER+32)
+#define MVME147_IRQ_SCCB_STAT (IRQ_USER+34)
+#define MVME147_IRQ_SCCB_RX (IRQ_USER+36)
+#define MVME147_IRQ_SCCB_SPCOND (IRQ_USER+38)
+#define MVME147_IRQ_SCCA_TX (IRQ_USER+40)
+#define MVME147_IRQ_SCCA_STAT (IRQ_USER+42)
+#define MVME147_IRQ_SCCA_RX (IRQ_USER+44)
+#define MVME147_IRQ_SCCA_SPCOND (IRQ_USER+46)
#define MVME147_LANCE_BASE 0xfffe1800
-#define MVME147_LANCE_IRQ 0x44
+#define MVME147_LANCE_IRQ (IRQ_USER+4)
#define ETHERNET_ADDRESS 0xfffe0778
diff --git a/include/asm-m68k/mvme16xhw.h b/include/asm-m68k/mvme16xhw.h
index 5d07231..6117f56 100644
--- a/include/asm-m68k/mvme16xhw.h
+++ b/include/asm-m68k/mvme16xhw.h
@@ -66,28 +66,28 @@ typedef struct {
#define MVME162_IRQ_TYPE_PRIO 0
-#define MVME167_IRQ_PRN 0x54
-#define MVME16x_IRQ_I596 0x57
-#define MVME16x_IRQ_SCSI 0x55
-#define MVME16x_IRQ_FLY 0x7f
-#define MVME167_IRQ_SER_ERR 0x5c
-#define MVME167_IRQ_SER_MODEM 0x5d
-#define MVME167_IRQ_SER_TX 0x5e
-#define MVME167_IRQ_SER_RX 0x5f
-#define MVME16x_IRQ_TIMER 0x59
-#define MVME167_IRQ_ABORT 0x6e
-#define MVME162_IRQ_ABORT 0x5e
+#define MVME167_IRQ_PRN (IRQ_USER+20)
+#define MVME16x_IRQ_I596 (IRQ_USER+23)
+#define MVME16x_IRQ_SCSI (IRQ_USER+21)
+#define MVME16x_IRQ_FLY (IRQ_USER+63)
+#define MVME167_IRQ_SER_ERR (IRQ_USER+28)
+#define MVME167_IRQ_SER_MODEM (IRQ_USER+29)
+#define MVME167_IRQ_SER_TX (IRQ_USER+30)
+#define MVME167_IRQ_SER_RX (IRQ_USER+31)
+#define MVME16x_IRQ_TIMER (IRQ_USER+25)
+#define MVME167_IRQ_ABORT (IRQ_USER+46)
+#define MVME162_IRQ_ABORT (IRQ_USER+30)
/* SCC interrupts, for MVME162 */
-#define MVME162_IRQ_SCC_BASE 0x40
-#define MVME162_IRQ_SCCB_TX 0x40
-#define MVME162_IRQ_SCCB_STAT 0x42
-#define MVME162_IRQ_SCCB_RX 0x44
-#define MVME162_IRQ_SCCB_SPCOND 0x46
-#define MVME162_IRQ_SCCA_TX 0x48
-#define MVME162_IRQ_SCCA_STAT 0x4a
-#define MVME162_IRQ_SCCA_RX 0x4c
-#define MVME162_IRQ_SCCA_SPCOND 0x4e
+#define MVME162_IRQ_SCC_BASE (IRQ_USER+0)
+#define MVME162_IRQ_SCCB_TX (IRQ_USER+0)
+#define MVME162_IRQ_SCCB_STAT (IRQ_USER+2)
+#define MVME162_IRQ_SCCB_RX (IRQ_USER+4)
+#define MVME162_IRQ_SCCB_SPCOND (IRQ_USER+6)
+#define MVME162_IRQ_SCCA_TX (IRQ_USER+8)
+#define MVME162_IRQ_SCCA_STAT (IRQ_USER+10)
+#define MVME162_IRQ_SCCA_RX (IRQ_USER+12)
+#define MVME162_IRQ_SCCA_SPCOND (IRQ_USER+14)
/* MVME162 version register */
diff --git a/include/asm-m68k/processor.h b/include/asm-m68k/processor.h
index 352799e..8455f77 100644
--- a/include/asm-m68k/processor.h
+++ b/include/asm-m68k/processor.h
@@ -71,10 +71,10 @@ struct thread_struct {
};
#define INIT_THREAD { \
- ksp: sizeof(init_stack) + (unsigned long) init_stack, \
- sr: PS_S, \
- fs: __KERNEL_DS, \
- info: INIT_THREAD_INFO(init_task) \
+ .ksp = sizeof(init_stack) + (unsigned long) init_stack, \
+ .sr = PS_S, \
+ .fs = __KERNEL_DS, \
+ .info = INIT_THREAD_INFO(init_task), \
}
/*
diff --git a/include/asm-m68k/scatterlist.h b/include/asm-m68k/scatterlist.h
index d7c9b5c..8e61226 100644
--- a/include/asm-m68k/scatterlist.h
+++ b/include/asm-m68k/scatterlist.h
@@ -2,18 +2,17 @@
#define _M68K_SCATTERLIST_H
struct scatterlist {
- /* These two are only valid if ADDRESS member of this
- * struct is NULL.
- */
struct page *page;
unsigned int offset;
-
unsigned int length;
- __u32 dvma_address; /* A place to hang host-specific addresses at. */
+ __u32 dma_address; /* A place to hang host-specific addresses at. */
};
/* This is bogus and should go away. */
#define ISA_DMA_THRESHOLD (0x00ffffff)
+#define sg_dma_address(sg) ((sg)->dma_address)
+#define sg_dma_len(sg) ((sg)->length)
+
#endif /* !(_M68K_SCATTERLIST_H) */
diff --git a/include/asm-m68k/signal.h b/include/asm-m68k/signal.h
index b7b7ea2..85037a3 100644
--- a/include/asm-m68k/signal.h
+++ b/include/asm-m68k/signal.h
@@ -156,13 +156,17 @@ typedef struct sigaltstack {
static inline void sigaddset(sigset_t *set, int _sig)
{
- __asm__("bfset %0{%1,#1}" : "=m" (*set) : "id" ((_sig - 1) ^ 31)
+ asm ("bfset %0{%1,#1}"
+ : "+od" (*set)
+ : "id" ((_sig - 1) ^ 31)
: "cc");
}
static inline void sigdelset(sigset_t *set, int _sig)
{
- __asm__("bfclr %0{%1,#1}" : "=m"(*set) : "id"((_sig - 1) ^ 31)
+ asm ("bfclr %0{%1,#1}"
+ : "+od" (*set)
+ : "id" ((_sig - 1) ^ 31)
: "cc");
}
@@ -175,8 +179,10 @@ static inline int __const_sigismember(sigset_t *set, int _sig)
static inline int __gen_sigismember(sigset_t *set, int _sig)
{
int ret;
- __asm__("bfextu %1{%2,#1},%0"
- : "=d"(ret) : "m"(*set), "id"((_sig-1) ^ 31));
+ asm ("bfextu %1{%2,#1},%0"
+ : "=d" (ret)
+ : "od" (*set), "id" ((_sig-1) ^ 31)
+ : "cc");
return ret;
}
@@ -187,7 +193,10 @@ static inline int __gen_sigismember(sigset_t *set, int _sig)
static inline int sigfindinword(unsigned long word)
{
- __asm__("bfffo %1{#0,#0},%0" : "=d"(word) : "d"(word & -word) : "cc");
+ asm ("bfffo %1{#0,#0},%0"
+ : "=d" (word)
+ : "d" (word & -word)
+ : "cc");
return word ^ 31;
}
diff --git a/include/asm-m68k/sun3ints.h b/include/asm-m68k/sun3ints.h
index bd038fc..de91fa0 100644
--- a/include/asm-m68k/sun3ints.h
+++ b/include/asm-m68k/sun3ints.h
@@ -12,37 +12,25 @@
#define SUN3INTS_H
#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
#include <linux/interrupt.h>
-#include <linux/seq_file.h>
-#include <asm/segment.h>
#include <asm/intersil.h>
#include <asm/oplib.h>
+#include <asm/traps.h>
#define SUN3_INT_VECS 192
void sun3_enable_irq(unsigned int irq);
void sun3_disable_irq(unsigned int irq);
-int sun3_request_irq(unsigned int irq,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
- unsigned long flags, const char *devname, void *dev_id
- );
extern void sun3_init_IRQ (void);
-extern irqreturn_t (*sun3_default_handler[]) (int, void *, struct pt_regs *);
-extern void sun3_free_irq (unsigned int irq, void *dev_id);
extern void sun3_enable_interrupts (void);
extern void sun3_disable_interrupts (void);
-extern int show_sun3_interrupts(struct seq_file *, void *);
-extern irqreturn_t sun3_process_int(int, struct pt_regs *);
extern volatile unsigned char* sun3_intreg;
/* master list of VME vectors -- don't fuck with this */
-#define SUN3_VEC_FLOPPY 0x40
-#define SUN3_VEC_VMESCSI0 0x40
-#define SUN3_VEC_VMESCSI1 0x41
-#define SUN3_VEC_CG 0xA8
+#define SUN3_VEC_FLOPPY (IRQ_USER+0)
+#define SUN3_VEC_VMESCSI0 (IRQ_USER+0)
+#define SUN3_VEC_VMESCSI1 (IRQ_USER+1)
+#define SUN3_VEC_CG (IRQ_USER+104)
#endif /* SUN3INTS_H */
diff --git a/include/asm-m68k/traps.h b/include/asm-m68k/traps.h
index 4750561..8caef25 100644
--- a/include/asm-m68k/traps.h
+++ b/include/asm-m68k/traps.h
@@ -13,8 +13,15 @@
#ifndef __ASSEMBLY__
+#include <linux/linkage.h>
+#include <asm/ptrace.h>
+
typedef void (*e_vector)(void);
+asmlinkage void auto_inthandler(void);
+asmlinkage void user_inthandler(void);
+asmlinkage void bad_inthandler(void);
+
extern e_vector vectors[];
#endif
diff --git a/include/asm-m68k/uaccess.h b/include/asm-m68k/uaccess.h
index 2ffd87b..88b1f47 100644
--- a/include/asm-m68k/uaccess.h
+++ b/include/asm-m68k/uaccess.h
@@ -4,8 +4,9 @@
/*
* User space memory access functions
*/
+#include <linux/compiler.h>
#include <linux/errno.h>
-#include <linux/sched.h>
+#include <linux/types.h>
#include <asm/segment.h>
#define VERIFY_READ 0
@@ -32,858 +33,335 @@ struct exception_table_entry
unsigned long insn, fixup;
};
+extern int __put_user_bad(void);
+extern int __get_user_bad(void);
+
+#define __put_user_asm(res, x, ptr, bwl, reg, err) \
+asm volatile ("\n" \
+ "1: moves."#bwl" %2,%1\n" \
+ "2:\n" \
+ " .section .fixup,\"ax\"\n" \
+ " .even\n" \
+ "10: moveq.l %3,%0\n" \
+ " jra 2b\n" \
+ " .previous\n" \
+ "\n" \
+ " .section __ex_table,\"a\"\n" \
+ " .align 4\n" \
+ " .long 1b,10b\n" \
+ " .long 2b,10b\n" \
+ " .previous" \
+ : "+d" (res), "=m" (*(ptr)) \
+ : #reg (x), "i" (err))
/*
* These are the main single-value transfer routines. They automatically
* use the right size if we just have the right pointer type.
*/
-#define put_user(x, ptr) \
-({ \
- int __pu_err; \
- typeof(*(ptr)) __pu_val = (x); \
- __chk_user_ptr(ptr); \
- switch (sizeof (*(ptr))) { \
- case 1: \
- __put_user_asm(__pu_err, __pu_val, ptr, b); \
- break; \
- case 2: \
- __put_user_asm(__pu_err, __pu_val, ptr, w); \
- break; \
- case 4: \
- __put_user_asm(__pu_err, __pu_val, ptr, l); \
- break; \
- case 8: \
- __pu_err = __constant_copy_to_user(ptr, &__pu_val, 8); \
- break; \
- default: \
- __pu_err = __put_user_bad(); \
- break; \
- } \
- __pu_err; \
+#define __put_user(x, ptr) \
+({ \
+ typeof(*(ptr)) __pu_val = (x); \
+ int __pu_err = 0; \
+ __chk_user_ptr(ptr); \
+ switch (sizeof (*(ptr))) { \
+ case 1: \
+ __put_user_asm(__pu_err, __pu_val, ptr, b, d, -EFAULT); \
+ break; \
+ case 2: \
+ __put_user_asm(__pu_err, __pu_val, ptr, w, d, -EFAULT); \
+ break; \
+ case 4: \
+ __put_user_asm(__pu_err, __pu_val, ptr, l, r, -EFAULT); \
+ break; \
+ case 8: \
+ { \
+ const void *__pu_ptr = (ptr); \
+ asm volatile ("\n" \
+ "1: moves.l %2,(%1)+\n" \
+ "2: moves.l %R2,(%1)\n" \
+ "3:\n" \
+ " .section .fixup,\"ax\"\n" \
+ " .even\n" \
+ "10: movel %3,%0\n" \
+ " jra 3b\n" \
+ " .previous\n" \
+ "\n" \
+ " .section __ex_table,\"a\"\n" \
+ " .align 4\n" \
+ " .long 1b,10b\n" \
+ " .long 2b,10b\n" \
+ " .long 3b,10b\n" \
+ " .previous" \
+ : "+d" (__pu_err), "+a" (__pu_ptr) \
+ : "r" (__pu_val), "i" (-EFAULT) \
+ : "memory"); \
+ break; \
+ } \
+ default: \
+ __pu_err = __put_user_bad(); \
+ break; \
+ } \
+ __pu_err; \
})
-#define __put_user(x, ptr) put_user(x, ptr)
-
-extern int __put_user_bad(void);
+#define put_user(x, ptr) __put_user(x, ptr)
-/*
- * Tell gcc we read from memory instead of writing: this is because
- * we do not write to any memory gcc knows about, so there are no
- * aliasing issues.
- */
-#define __put_user_asm(err,x,ptr,bwl) \
-__asm__ __volatile__ \
- ("21:moves" #bwl " %2,%1\n" \
- "1:\n" \
- ".section .fixup,\"ax\"\n" \
- " .even\n" \
- "2: movel %3,%0\n" \
- " jra 1b\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 21b,2b\n" \
- " .long 1b,2b\n" \
- ".previous" \
- : "=d"(err) \
- : "m"(*(ptr)), "r"(x), "i"(-EFAULT), "0"(0))
-#define get_user(x, ptr) \
-({ \
- int __gu_err; \
- typeof(*(ptr)) __gu_val; \
- __chk_user_ptr(ptr); \
- switch (sizeof(*(ptr))) { \
- case 1: \
- __get_user_asm(__gu_err, __gu_val, ptr, b, "=d"); \
- break; \
- case 2: \
- __get_user_asm(__gu_err, __gu_val, ptr, w, "=r"); \
- break; \
- case 4: \
- __get_user_asm(__gu_err, __gu_val, ptr, l, "=r"); \
- break; \
- case 8: \
- __gu_err = __constant_copy_from_user(&__gu_val, ptr, 8); \
- break; \
- default: \
- __gu_val = (typeof(*(ptr)))0; \
- __gu_err = __get_user_bad(); \
- break; \
- } \
- (x) = __gu_val; \
- __gu_err; \
+#define __get_user_asm(res, x, ptr, type, bwl, reg, err) ({ \
+ type __gu_val; \
+ asm volatile ("\n" \
+ "1: moves."#bwl" %2,%1\n" \
+ "2:\n" \
+ " .section .fixup,\"ax\"\n" \
+ " .even\n" \
+ "10: move.l %3,%0\n" \
+ " sub."#bwl" %1,%1\n" \
+ " jra 2b\n" \
+ " .previous\n" \
+ "\n" \
+ " .section __ex_table,\"a\"\n" \
+ " .align 4\n" \
+ " .long 1b,10b\n" \
+ " .previous" \
+ : "+d" (res), "=&" #reg (__gu_val) \
+ : "m" (*(ptr)), "i" (err)); \
+ (x) = (typeof(*(ptr)))(long)__gu_val; \
})
-#define __get_user(x, ptr) get_user(x, ptr)
-
-extern int __get_user_bad(void);
-
-#define __get_user_asm(err,x,ptr,bwl,reg) \
-__asm__ __volatile__ \
- ("1: moves" #bwl " %2,%1\n" \
- "2:\n" \
- ".section .fixup,\"ax\"\n" \
- " .even\n" \
- "3: movel %3,%0\n" \
- " sub" #bwl " %1,%1\n" \
- " jra 2b\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 1b,3b\n" \
- ".previous" \
- : "=d"(err), reg(x) \
- : "m"(*(ptr)), "i" (-EFAULT), "0"(0))
-static inline unsigned long
-__generic_copy_from_user(void *to, const void __user *from, unsigned long n)
-{
- unsigned long tmp;
- __asm__ __volatile__
- (" tstl %2\n"
- " jeq 2f\n"
- "1: movesl (%1)+,%3\n"
- " movel %3,(%0)+\n"
- " subql #1,%2\n"
- " jne 1b\n"
- "2: movel %4,%2\n"
- " bclr #1,%2\n"
- " jeq 4f\n"
- "3: movesw (%1)+,%3\n"
- " movew %3,(%0)+\n"
- "4: bclr #0,%2\n"
- " jeq 6f\n"
- "5: movesb (%1)+,%3\n"
- " moveb %3,(%0)+\n"
- "6:\n"
- ".section .fixup,\"ax\"\n"
- " .even\n"
- "7: movel %2,%%d0\n"
- "71:clrl (%0)+\n"
- " subql #1,%%d0\n"
- " jne 71b\n"
- " lsll #2,%2\n"
- " addl %4,%2\n"
- " btst #1,%4\n"
- " jne 81f\n"
- " btst #0,%4\n"
- " jne 91f\n"
- " jra 6b\n"
- "8: addql #2,%2\n"
- "81:clrw (%0)+\n"
- " btst #0,%4\n"
- " jne 91f\n"
- " jra 6b\n"
- "9: addql #1,%2\n"
- "91:clrb (%0)+\n"
- " jra 6b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b,7b\n"
- " .long 3b,8b\n"
- " .long 5b,9b\n"
- ".previous"
- : "=a"(to), "=a"(from), "=d"(n), "=&d"(tmp)
- : "d"(n & 3), "0"(to), "1"(from), "2"(n/4)
- : "d0", "memory");
- return n;
-}
+#define __get_user(x, ptr) \
+({ \
+ int __gu_err = 0; \
+ __chk_user_ptr(ptr); \
+ switch (sizeof(*(ptr))) { \
+ case 1: \
+ __get_user_asm(__gu_err, x, ptr, u8, b, d, -EFAULT); \
+ break; \
+ case 2: \
+ __get_user_asm(__gu_err, x, ptr, u16, w, d, -EFAULT); \
+ break; \
+ case 4: \
+ __get_user_asm(__gu_err, x, ptr, u32, l, r, -EFAULT); \
+ break; \
+/* case 8: disabled because gcc-4.1 has a broken typeof \
+ { \
+ const void *__gu_ptr = (ptr); \
+ u64 __gu_val; \
+ asm volatile ("\n" \
+ "1: moves.l (%2)+,%1\n" \
+ "2: moves.l (%2),%R1\n" \
+ "3:\n" \
+ " .section .fixup,\"ax\"\n" \
+ " .even\n" \
+ "10: move.l %3,%0\n" \
+ " sub.l %1,%1\n" \
+ " sub.l %R1,%R1\n" \
+ " jra 3b\n" \
+ " .previous\n" \
+ "\n" \
+ " .section __ex_table,\"a\"\n" \
+ " .align 4\n" \
+ " .long 1b,10b\n" \
+ " .long 2b,10b\n" \
+ " .previous" \
+ : "+d" (__gu_err), "=&r" (__gu_val), \
+ "+a" (__gu_ptr) \
+ : "i" (-EFAULT) \
+ : "memory"); \
+ (x) = (typeof(*(ptr)))__gu_val; \
+ break; \
+ } */ \
+ default: \
+ __gu_err = __get_user_bad(); \
+ break; \
+ } \
+ __gu_err; \
+})
+#define get_user(x, ptr) __get_user(x, ptr)
-static inline unsigned long
-__generic_copy_to_user(void __user *to, const void *from, unsigned long n)
-{
- unsigned long tmp;
- __asm__ __volatile__
- (" tstl %2\n"
- " jeq 3f\n"
- "1: movel (%1)+,%3\n"
- "22:movesl %3,(%0)+\n"
- "2: subql #1,%2\n"
- " jne 1b\n"
- "3: movel %4,%2\n"
- " bclr #1,%2\n"
- " jeq 4f\n"
- " movew (%1)+,%3\n"
- "24:movesw %3,(%0)+\n"
- "4: bclr #0,%2\n"
- " jeq 5f\n"
- " moveb (%1)+,%3\n"
- "25:movesb %3,(%0)+\n"
- "5:\n"
- ".section .fixup,\"ax\"\n"
- " .even\n"
- "60:addql #1,%2\n"
- "6: lsll #2,%2\n"
- " addl %4,%2\n"
- " jra 5b\n"
- "7: addql #2,%2\n"
- " jra 5b\n"
- "8: addql #1,%2\n"
- " jra 5b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b,60b\n"
- " .long 22b,6b\n"
- " .long 2b,6b\n"
- " .long 24b,7b\n"
- " .long 3b,60b\n"
- " .long 4b,7b\n"
- " .long 25b,8b\n"
- " .long 5b,8b\n"
- ".previous"
- : "=a"(to), "=a"(from), "=d"(n), "=&d"(tmp)
- : "r"(n & 3), "0"(to), "1"(from), "2"(n / 4)
- : "memory");
- return n;
-}
+unsigned long __generic_copy_from_user(void *to, const void __user *from, unsigned long n);
+unsigned long __generic_copy_to_user(void __user *to, const void *from, unsigned long n);
-#define __copy_from_user_big(to, from, n, fixup, copy) \
- __asm__ __volatile__ \
- ("10: movesl (%1)+,%%d0\n" \
- " movel %%d0,(%0)+\n" \
- " subql #1,%2\n" \
- " jne 10b\n" \
- ".section .fixup,\"ax\"\n" \
- " .even\n" \
- "11: movel %2,%%d0\n" \
- "13: clrl (%0)+\n" \
- " subql #1,%%d0\n" \
- " jne 13b\n" \
- " lsll #2,%2\n" \
- fixup "\n" \
- " jra 12f\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 10b,11b\n" \
- ".previous\n" \
- copy "\n" \
- "12:" \
- : "=a"(to), "=a"(from), "=d"(n) \
- : "0"(to), "1"(from), "2"(n/4) \
- : "d0", "memory")
+#define __constant_copy_from_user_asm(res, to, from, tmp, n, s1, s2, s3)\
+ asm volatile ("\n" \
+ "1: moves."#s1" (%2)+,%3\n" \
+ " move."#s1" %3,(%1)+\n" \
+ "2: moves."#s2" (%2)+,%3\n" \
+ " move."#s2" %3,(%1)+\n" \
+ " .ifnc \""#s3"\",\"\"\n" \
+ "3: moves."#s3" (%2)+,%3\n" \
+ " move."#s3" %3,(%1)+\n" \
+ " .endif\n" \
+ "4:\n" \
+ " .section __ex_table,\"a\"\n" \
+ " .align 4\n" \
+ " .long 1b,10f\n" \
+ " .long 2b,20f\n" \
+ " .ifnc \""#s3"\",\"\"\n" \
+ " .long 3b,30f\n" \
+ " .endif\n" \
+ " .previous\n" \
+ "\n" \
+ " .section .fixup,\"ax\"\n" \
+ " .even\n" \
+ "10: clr."#s1" (%1)+\n" \
+ "20: clr."#s2" (%1)+\n" \
+ " .ifnc \""#s3"\",\"\"\n" \
+ "30: clr."#s3" (%1)+\n" \
+ " .endif\n" \
+ " moveq.l #"#n",%0\n" \
+ " jra 4b\n" \
+ " .previous\n" \
+ : "+d" (res), "+&a" (to), "+a" (from), "=&d" (tmp) \
+ : : "memory")
-static inline unsigned long
+static __always_inline unsigned long
__constant_copy_from_user(void *to, const void __user *from, unsigned long n)
{
- switch (n) {
- case 0:
- break;
- case 1:
- __asm__ __volatile__
- ("1: movesb (%1)+,%%d0\n"
- " moveb %%d0,(%0)+\n"
- "2:\n"
- ".section .fixup,\"ax\"\n"
- " .even\n"
- "3: addql #1,%2\n"
- " clrb (%0)+\n"
- " jra 2b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b,3b\n"
- ".previous"
- : "=a"(to), "=a"(from), "=d"(n)
- : "0"(to), "1"(from), "2"(0)
- : "d0", "memory");
- break;
- case 2:
- __asm__ __volatile__
- ("1: movesw (%1)+,%%d0\n"
- " movew %%d0,(%0)+\n"
- "2:\n"
- ".section .fixup,\"ax\"\n"
- " .even\n"
- "3: addql #2,%2\n"
- " clrw (%0)+\n"
- " jra 2b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b,3b\n"
- ".previous"
- : "=a"(to), "=a"(from), "=d"(n)
- : "0"(to), "1"(from), "2"(0)
- : "d0", "memory");
- break;
- case 3:
- __asm__ __volatile__
- ("1: movesw (%1)+,%%d0\n"
- " movew %%d0,(%0)+\n"
- "2: movesb (%1)+,%%d0\n"
- " moveb %%d0,(%0)+\n"
- "3:"
- ".section .fixup,\"ax\"\n"
- " .even\n"
- "4: addql #2,%2\n"
- " clrw (%0)+\n"
- "5: addql #1,%2\n"
- " clrb (%0)+\n"
- " jra 3b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b,4b\n"
- " .long 2b,5b\n"
- ".previous"
- : "=a"(to), "=a"(from), "=d"(n)
- : "0"(to), "1"(from), "2"(0)
- : "d0", "memory");
- break;
- case 4:
- __asm__ __volatile__
- ("1: movesl (%1)+,%%d0\n"
- " movel %%d0,(%0)+\n"
- "2:"
- ".section .fixup,\"ax\"\n"
- " .even\n"
- "3: addql #4,%2\n"
- " clrl (%0)+\n"
- " jra 2b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b,3b\n"
- ".previous"
- : "=a"(to), "=a"(from), "=d"(n)
- : "0"(to), "1"(from), "2"(0)
- : "d0", "memory");
- break;
- case 8:
- __asm__ __volatile__
- ("1: movesl (%1)+,%%d0\n"
- " movel %%d0,(%0)+\n"
- "2: movesl (%1)+,%%d0\n"
- " movel %%d0,(%0)+\n"
- "3:"
- ".section .fixup,\"ax\"\n"
- " .even\n"
- "4: addql #4,%2\n"
- " clrl (%0)+\n"
- "5: addql #4,%2\n"
- " clrl (%0)+\n"
- " jra 3b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b,4b\n"
- " .long 2b,5b\n"
- ".previous"
- : "=a"(to), "=a"(from), "=d"(n)
- : "0"(to), "1"(from), "2"(0)
- : "d0", "memory");
- break;
- case 12:
- __asm__ __volatile__
- ("1: movesl (%1)+,%%d0\n"
- " movel %%d0,(%0)+\n"
- "2: movesl (%1)+,%%d0\n"
- " movel %%d0,(%0)+\n"
- "3: movesl (%1)+,%%d0\n"
- " movel %%d0,(%0)+\n"
- "4:"
- ".section .fixup,\"ax\"\n"
- " .even\n"
- "5: addql #4,%2\n"
- " clrl (%0)+\n"
- "6: addql #4,%2\n"
- " clrl (%0)+\n"
- "7: addql #4,%2\n"
- " clrl (%0)+\n"
- " jra 4b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b,5b\n"
- " .long 2b,6b\n"
- " .long 3b,7b\n"
- ".previous"
- : "=a"(to), "=a"(from), "=d"(n)
- : "0"(to), "1"(from), "2"(0)
- : "d0", "memory");
- break;
- case 16:
- __asm__ __volatile__
- ("1: movesl (%1)+,%%d0\n"
- " movel %%d0,(%0)+\n"
- "2: movesl (%1)+,%%d0\n"
- " movel %%d0,(%0)+\n"
- "3: movesl (%1)+,%%d0\n"
- " movel %%d0,(%0)+\n"
- "4: movesl (%1)+,%%d0\n"
- " movel %%d0,(%0)+\n"
- "5:"
- ".section .fixup,\"ax\"\n"
- " .even\n"
- "6: addql #4,%2\n"
- " clrl (%0)+\n"
- "7: addql #4,%2\n"
- " clrl (%0)+\n"
- "8: addql #4,%2\n"
- " clrl (%0)+\n"
- "9: addql #4,%2\n"
- " clrl (%0)+\n"
- " jra 5b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b,6b\n"
- " .long 2b,7b\n"
- " .long 3b,8b\n"
- " .long 4b,9b\n"
- ".previous"
- : "=a"(to), "=a"(from), "=d"(n)
- : "0"(to), "1"(from), "2"(0)
- : "d0", "memory");
- break;
- default:
- switch (n & 3) {
- case 0:
- __copy_from_user_big(to, from, n, "", "");
- break;
+ unsigned long res = 0, tmp;
+
+ switch (n) {
case 1:
- __copy_from_user_big(to, from, n,
- /* fixup */
- "1: addql #1,%2\n"
- " clrb (%0)+",
- /* copy */
- "2: movesb (%1)+,%%d0\n"
- " moveb %%d0,(%0)+\n"
- ".section __ex_table,\"a\"\n"
- " .long 2b,1b\n"
- ".previous");
- break;
+ __get_user_asm(res, *(u8 *)to, (u8 *)from, u8, b, d, 1);
+ break;
case 2:
- __copy_from_user_big(to, from, n,
- /* fixup */
- "1: addql #2,%2\n"
- " clrw (%0)+",
- /* copy */
- "2: movesw (%1)+,%%d0\n"
- " movew %%d0,(%0)+\n"
- ".section __ex_table,\"a\"\n"
- " .long 2b,1b\n"
- ".previous");
- break;
+ __get_user_asm(res, *(u16 *)to, (u16 *)from, u16, w, d, 2);
+ break;
case 3:
- __copy_from_user_big(to, from, n,
- /* fixup */
- "1: addql #2,%2\n"
- " clrw (%0)+\n"
- "2: addql #1,%2\n"
- " clrb (%0)+",
- /* copy */
- "3: movesw (%1)+,%%d0\n"
- " movew %%d0,(%0)+\n"
- "4: movesb (%1)+,%%d0\n"
- " moveb %%d0,(%0)+\n"
- ".section __ex_table,\"a\"\n"
- " .long 3b,1b\n"
- " .long 4b,2b\n"
- ".previous");
- break;
+ __constant_copy_from_user_asm(res, to, from, tmp, 3, w, b,);
+ break;
+ case 4:
+ __get_user_asm(res, *(u32 *)to, (u32 *)from, u32, l, r, 4);
+ break;
+ case 5:
+ __constant_copy_from_user_asm(res, to, from, tmp, 5, l, b,);
+ break;
+ case 6:
+ __constant_copy_from_user_asm(res, to, from, tmp, 6, l, w,);
+ break;
+ case 7:
+ __constant_copy_from_user_asm(res, to, from, tmp, 7, l, w, b);
+ break;
+ case 8:
+ __constant_copy_from_user_asm(res, to, from, tmp, 8, l, l,);
+ break;
+ case 9:
+ __constant_copy_from_user_asm(res, to, from, tmp, 9, l, l, b);
+ break;
+ case 10:
+ __constant_copy_from_user_asm(res, to, from, tmp, 10, l, l, w);
+ break;
+ case 12:
+ __constant_copy_from_user_asm(res, to, from, tmp, 12, l, l, l);
+ break;
+ default:
+ /* we limit the inlined version to 3 moves */
+ return __generic_copy_from_user(to, from, n);
}
- break;
- }
- return n;
-}
-#define __copy_to_user_big(to, from, n, fixup, copy) \
- __asm__ __volatile__ \
- ("10: movel (%1)+,%%d0\n" \
- "31: movesl %%d0,(%0)+\n" \
- "11: subql #1,%2\n" \
- " jne 10b\n" \
- "41:\n" \
- ".section .fixup,\"ax\"\n" \
- " .even\n" \
- "22: addql #1,%2\n" \
- "12: lsll #2,%2\n" \
- fixup "\n" \
- " jra 13f\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 10b,22b\n" \
- " .long 31b,12b\n" \
- " .long 11b,12b\n" \
- " .long 41b,22b\n" \
- ".previous\n" \
- copy "\n" \
- "13:" \
- : "=a"(to), "=a"(from), "=d"(n) \
- : "0"(to), "1"(from), "2"(n/4) \
- : "d0", "memory")
+ return res;
+}
-#define __copy_to_user_inatomic __copy_to_user
-#define __copy_from_user_inatomic __copy_from_user
+#define __constant_copy_to_user_asm(res, to, from, tmp, n, s1, s2, s3) \
+ asm volatile ("\n" \
+ " move."#s1" (%2)+,%3\n" \
+ "11: moves."#s1" %3,(%1)+\n" \
+ "12: move."#s2" (%2)+,%3\n" \
+ "21: moves."#s2" %3,(%1)+\n" \
+ "22:\n" \
+ " .ifnc \""#s3"\",\"\"\n" \
+ " move."#s3" (%2)+,%3\n" \
+ "31: moves."#s3" %3,(%1)+\n" \
+ "32:\n" \
+ " .endif\n" \
+ "4:\n" \
+ "\n" \
+ " .section __ex_table,\"a\"\n" \
+ " .align 4\n" \
+ " .long 11b,5f\n" \
+ " .long 12b,5f\n" \
+ " .long 21b,5f\n" \
+ " .long 22b,5f\n" \
+ " .ifnc \""#s3"\",\"\"\n" \
+ " .long 31b,5f\n" \
+ " .long 32b,5f\n" \
+ " .endif\n" \
+ " .previous\n" \
+ "\n" \
+ " .section .fixup,\"ax\"\n" \
+ " .even\n" \
+ "5: moveq.l #"#n",%0\n" \
+ " jra 4b\n" \
+ " .previous\n" \
+ : "+d" (res), "+a" (to), "+a" (from), "=&d" (tmp) \
+ : : "memory")
-static inline unsigned long
+static __always_inline unsigned long
__constant_copy_to_user(void __user *to, const void *from, unsigned long n)
{
- switch (n) {
- case 0:
- break;
- case 1:
- __asm__ __volatile__
- (" moveb (%1)+,%%d0\n"
- "21:movesb %%d0,(%0)+\n"
- "1:\n"
- ".section .fixup,\"ax\"\n"
- " .even\n"
- "2: addql #1,%2\n"
- " jra 1b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n "
- " .long 21b,2b\n"
- " .long 1b,2b\n"
- ".previous"
- : "=a"(to), "=a"(from), "=d"(n)
- : "0"(to), "1"(from), "2"(0)
- : "d0", "memory");
- break;
- case 2:
- __asm__ __volatile__
- (" movew (%1)+,%%d0\n"
- "21:movesw %%d0,(%0)+\n"
- "1:\n"
- ".section .fixup,\"ax\"\n"
- " .even\n"
- "2: addql #2,%2\n"
- " jra 1b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 21b,2b\n"
- " .long 1b,2b\n"
- ".previous"
- : "=a"(to), "=a"(from), "=d"(n)
- : "0"(to), "1"(from), "2"(0)
- : "d0", "memory");
- break;
- case 3:
- __asm__ __volatile__
- (" movew (%1)+,%%d0\n"
- "21:movesw %%d0,(%0)+\n"
- "1: moveb (%1)+,%%d0\n"
- "22:movesb %%d0,(%0)+\n"
- "2:\n"
- ".section .fixup,\"ax\"\n"
- " .even\n"
- "3: addql #2,%2\n"
- "4: addql #1,%2\n"
- " jra 2b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 21b,3b\n"
- " .long 1b,3b\n"
- " .long 22b,4b\n"
- " .long 2b,4b\n"
- ".previous"
- : "=a"(to), "=a"(from), "=d"(n)
- : "0"(to), "1"(from), "2"(0)
- : "d0", "memory");
- break;
- case 4:
- __asm__ __volatile__
- (" movel (%1)+,%%d0\n"
- "21:movesl %%d0,(%0)+\n"
- "1:\n"
- ".section .fixup,\"ax\"\n"
- " .even\n"
- "2: addql #4,%2\n"
- " jra 1b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 21b,2b\n"
- " .long 1b,2b\n"
- ".previous"
- : "=a"(to), "=a"(from), "=d"(n)
- : "0"(to), "1"(from), "2"(0)
- : "d0", "memory");
- break;
- case 8:
- __asm__ __volatile__
- (" movel (%1)+,%%d0\n"
- "21:movesl %%d0,(%0)+\n"
- "1: movel (%1)+,%%d0\n"
- "22:movesl %%d0,(%0)+\n"
- "2:\n"
- ".section .fixup,\"ax\"\n"
- " .even\n"
- "3: addql #4,%2\n"
- "4: addql #4,%2\n"
- " jra 2b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 21b,3b\n"
- " .long 1b,3b\n"
- " .long 22b,4b\n"
- " .long 2b,4b\n"
- ".previous"
- : "=a"(to), "=a"(from), "=d"(n)
- : "0"(to), "1"(from), "2"(0)
- : "d0", "memory");
- break;
- case 12:
- __asm__ __volatile__
- (" movel (%1)+,%%d0\n"
- "21:movesl %%d0,(%0)+\n"
- "1: movel (%1)+,%%d0\n"
- "22:movesl %%d0,(%0)+\n"
- "2: movel (%1)+,%%d0\n"
- "23:movesl %%d0,(%0)+\n"
- "3:\n"
- ".section .fixup,\"ax\"\n"
- " .even\n"
- "4: addql #4,%2\n"
- "5: addql #4,%2\n"
- "6: addql #4,%2\n"
- " jra 3b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 21b,4b\n"
- " .long 1b,4b\n"
- " .long 22b,5b\n"
- " .long 2b,5b\n"
- " .long 23b,6b\n"
- " .long 3b,6b\n"
- ".previous"
- : "=a"(to), "=a"(from), "=d"(n)
- : "0"(to), "1"(from), "2"(0)
- : "d0", "memory");
- break;
- case 16:
- __asm__ __volatile__
- (" movel (%1)+,%%d0\n"
- "21:movesl %%d0,(%0)+\n"
- "1: movel (%1)+,%%d0\n"
- "22:movesl %%d0,(%0)+\n"
- "2: movel (%1)+,%%d0\n"
- "23:movesl %%d0,(%0)+\n"
- "3: movel (%1)+,%%d0\n"
- "24:movesl %%d0,(%0)+\n"
- "4:"
- ".section .fixup,\"ax\"\n"
- " .even\n"
- "5: addql #4,%2\n"
- "6: addql #4,%2\n"
- "7: addql #4,%2\n"
- "8: addql #4,%2\n"
- " jra 4b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 21b,5b\n"
- " .long 1b,5b\n"
- " .long 22b,6b\n"
- " .long 2b,6b\n"
- " .long 23b,7b\n"
- " .long 3b,7b\n"
- " .long 24b,8b\n"
- " .long 4b,8b\n"
- ".previous"
- : "=a"(to), "=a"(from), "=d"(n)
- : "0"(to), "1"(from), "2"(0)
- : "d0", "memory");
- break;
- default:
- switch (n & 3) {
- case 0:
- __copy_to_user_big(to, from, n, "", "");
- break;
+ unsigned long res = 0, tmp;
+
+ switch (n) {
case 1:
- __copy_to_user_big(to, from, n,
- /* fixup */
- "1: addql #1,%2",
- /* copy */
- " moveb (%1)+,%%d0\n"
- "22:movesb %%d0,(%0)+\n"
- "2:"
- ".section __ex_table,\"a\"\n"
- " .long 22b,1b\n"
- " .long 2b,1b\n"
- ".previous");
- break;
+ __put_user_asm(res, *(u8 *)from, (u8 *)to, b, d, 1);
+ break;
case 2:
- __copy_to_user_big(to, from, n,
- /* fixup */
- "1: addql #2,%2",
- /* copy */
- " movew (%1)+,%%d0\n"
- "22:movesw %%d0,(%0)+\n"
- "2:"
- ".section __ex_table,\"a\"\n"
- " .long 22b,1b\n"
- " .long 2b,1b\n"
- ".previous");
- break;
+ __put_user_asm(res, *(u16 *)from, (u16 *)to, w, d, 2);
+ break;
case 3:
- __copy_to_user_big(to, from, n,
- /* fixup */
- "1: addql #2,%2\n"
- "2: addql #1,%2",
- /* copy */
- " movew (%1)+,%%d0\n"
- "23:movesw %%d0,(%0)+\n"
- "3: moveb (%1)+,%%d0\n"
- "24:movesb %%d0,(%0)+\n"
- "4:"
- ".section __ex_table,\"a\"\n"
- " .long 23b,1b\n"
- " .long 3b,1b\n"
- " .long 24b,2b\n"
- " .long 4b,2b\n"
- ".previous");
- break;
+ __constant_copy_to_user_asm(res, to, from, tmp, 3, w, b,);
+ break;
+ case 4:
+ __put_user_asm(res, *(u32 *)from, (u32 *)to, l, r, 4);
+ break;
+ case 5:
+ __constant_copy_to_user_asm(res, to, from, tmp, 5, l, b,);
+ break;
+ case 6:
+ __constant_copy_to_user_asm(res, to, from, tmp, 6, l, w,);
+ break;
+ case 7:
+ __constant_copy_to_user_asm(res, to, from, tmp, 7, l, w, b);
+ break;
+ case 8:
+ __constant_copy_to_user_asm(res, to, from, tmp, 8, l, l,);
+ break;
+ case 9:
+ __constant_copy_to_user_asm(res, to, from, tmp, 9, l, l, b);
+ break;
+ case 10:
+ __constant_copy_to_user_asm(res, to, from, tmp, 10, l, l, w);
+ break;
+ case 12:
+ __constant_copy_to_user_asm(res, to, from, tmp, 12, l, l, l);
+ break;
+ default:
+ /* limit the inlined version to 3 moves */
+ return __generic_copy_to_user(to, from, n);
}
- break;
- }
- return n;
+
+ return res;
}
-#define copy_from_user(to, from, n) \
+#define __copy_from_user(to, from, n) \
(__builtin_constant_p(n) ? \
__constant_copy_from_user(to, from, n) : \
__generic_copy_from_user(to, from, n))
-#define copy_to_user(to, from, n) \
+#define __copy_to_user(to, from, n) \
(__builtin_constant_p(n) ? \
__constant_copy_to_user(to, from, n) : \
__generic_copy_to_user(to, from, n))
-#define __copy_from_user(to, from, n) copy_from_user(to, from, n)
-#define __copy_to_user(to, from, n) copy_to_user(to, from, n)
-
-/*
- * Copy a null terminated string from userspace.
- */
-
-static inline long
-strncpy_from_user(char *dst, const char __user *src, long count)
-{
- long res;
- if (count == 0) return count;
- __asm__ __volatile__
- ("1: movesb (%2)+,%%d0\n"
- "12:moveb %%d0,(%1)+\n"
- " jeq 2f\n"
- " subql #1,%3\n"
- " jne 1b\n"
- "2: subl %3,%0\n"
- "3:\n"
- ".section .fixup,\"ax\"\n"
- " .even\n"
- "4: movel %4,%0\n"
- " jra 3b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b,4b\n"
- " .long 12b,4b\n"
- ".previous"
- : "=d"(res), "=a"(dst), "=a"(src), "=d"(count)
- : "i"(-EFAULT), "0"(count), "1"(dst), "2"(src), "3"(count)
- : "d0", "memory");
- return res;
-}
+#define __copy_to_user_inatomic __copy_to_user
+#define __copy_from_user_inatomic __copy_from_user
-/*
- * Return the size of a string (including the ending 0)
- *
- * Return 0 on exception, a value greater than N if too long
- */
-static inline long strnlen_user(const char __user *src, long n)
-{
- long res;
+#define copy_from_user(to, from, n) __copy_from_user(to, from, n)
+#define copy_to_user(to, from, n) __copy_to_user(to, from, n)
- res = -(unsigned long)src;
- __asm__ __volatile__
- ("1:\n"
- " tstl %2\n"
- " jeq 3f\n"
- "2: movesb (%1)+,%%d0\n"
- "22:\n"
- " subql #1,%2\n"
- " tstb %%d0\n"
- " jne 1b\n"
- " jra 4f\n"
- "3:\n"
- " addql #1,%0\n"
- "4:\n"
- " addl %1,%0\n"
- "5:\n"
- ".section .fixup,\"ax\"\n"
- " .even\n"
- "6: moveq %3,%0\n"
- " jra 5b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 2b,6b\n"
- " .long 22b,6b\n"
- ".previous"
- : "=d"(res), "=a"(src), "=d"(n)
- : "i"(0), "0"(res), "1"(src), "2"(n)
- : "d0");
- return res;
-}
+long strncpy_from_user(char *dst, const char __user *src, long count);
+long strnlen_user(const char __user *src, long n);
+unsigned long clear_user(void __user *to, unsigned long n);
#define strlen_user(str) strnlen_user(str, 32767)
-/*
- * Zero Userspace
- */
-
-static inline unsigned long
-clear_user(void __user *to, unsigned long n)
-{
- __asm__ __volatile__
- (" tstl %1\n"
- " jeq 3f\n"
- "1: movesl %3,(%0)+\n"
- "2: subql #1,%1\n"
- " jne 1b\n"
- "3: movel %2,%1\n"
- " bclr #1,%1\n"
- " jeq 4f\n"
- "24:movesw %3,(%0)+\n"
- "4: bclr #0,%1\n"
- " jeq 5f\n"
- "25:movesb %3,(%0)+\n"
- "5:\n"
- ".section .fixup,\"ax\"\n"
- " .even\n"
- "61:addql #1,%1\n"
- "6: lsll #2,%1\n"
- " addl %2,%1\n"
- " jra 5b\n"
- "7: addql #2,%1\n"
- " jra 5b\n"
- "8: addql #1,%1\n"
- " jra 5b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b,61b\n"
- " .long 2b,6b\n"
- " .long 3b,61b\n"
- " .long 24b,7b\n"
- " .long 4b,7b\n"
- " .long 25b,8b\n"
- " .long 5b,8b\n"
- ".previous"
- : "=a"(to), "=d"(n)
- : "r"(n & 3), "r"(0), "0"(to), "1"(n/4));
- return n;
-}
-
#endif /* _M68K_UACCESS_H */
diff --git a/include/asm-m68k/unistd.h b/include/asm-m68k/unistd.h
index f236fe9..7c0b629 100644
--- a/include/asm-m68k/unistd.h
+++ b/include/asm-m68k/unistd.h
@@ -410,46 +410,7 @@ __syscall_return(type,__res); \
#ifdef __KERNEL_SYSCALLS__
-#include <linux/compiler.h>
-#include <linux/interrupt.h>
-#include <linux/types.h>
-
-/*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
- */
-#define __NR__exit __NR_exit
-static inline _syscall0(pid_t,setsid)
-static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
-static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
-static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
-static inline _syscall1(int,dup,int,fd)
static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
-static inline _syscall1(int,close,int,fd)
-static inline _syscall1(int,_exit,int,exitcode)
-static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
-
-asmlinkage long sys_mmap2(
- unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long pgoff);
-asmlinkage int sys_execve(char *name, char **argv, char **envp);
-asmlinkage int sys_pipe(unsigned long *fildes);
-struct pt_regs;
-struct sigaction;
-asmlinkage long sys_rt_sigaction(int sig,
- const struct sigaction __user *act,
- struct sigaction __user *oact,
- size_t sigsetsize);
#endif /* __KERNEL_SYSCALLS__ */
diff --git a/include/asm-m68knommu/irq.h b/include/asm-m68knommu/irq.h
index 2b40884..c524751 100644
--- a/include/asm-m68knommu/irq.h
+++ b/include/asm-m68knommu/irq.h
@@ -87,8 +87,4 @@ extern void (*mach_disable_irq)(unsigned int);
#define disable_irq(x) do { } while (0)
#define disable_irq_nosync(x) disable_irq(x)
-struct irqaction;
-struct pt_regs;
-int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
-
#endif /* _M68K_IRQ_H_ */
diff --git a/include/asm-m68knommu/ptrace.h b/include/asm-m68knommu/ptrace.h
index f65bd90..1e19c45 100644
--- a/include/asm-m68knommu/ptrace.h
+++ b/include/asm-m68knommu/ptrace.h
@@ -70,7 +70,7 @@ struct switch_stack {
/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
#define PTRACE_GETREGS 12
#define PTRACE_SETREGS 13
-#ifdef COFNIG_FPU
+#ifdef CONFIG_FPU
#define PTRACE_GETFPREGS 14
#define PTRACE_SETFPREGS 15
#endif
diff --git a/include/asm-mips/compat.h b/include/asm-mips/compat.h
index 986511d..900f472 100644
--- a/include/asm-mips/compat.h
+++ b/include/asm-mips/compat.h
@@ -145,8 +145,5 @@ static inline void __user *compat_alloc_user_space(long len)
return (void __user *) (regs->regs[29] - len);
}
-#if defined (__MIPSEL__)
-#define __COMPAT_ENDIAN_SWAP__ 1
-#endif
#endif /* _ASM_COMPAT_H */
diff --git a/include/asm-mips/mach-au1x00/au1xxx_psc.h b/include/asm-mips/mach-au1x00/au1xxx_psc.h
index 5c3e2a3..d7cbacd 100644
--- a/include/asm-mips/mach-au1x00/au1xxx_psc.h
+++ b/include/asm-mips/mach-au1x00/au1xxx_psc.h
@@ -39,7 +39,12 @@
#define PSC0_BASE_ADDR 0xb1a00000
#define PSC1_BASE_ADDR 0xb1b00000
#define PSC2_BASE_ADDR 0xb0a00000
-#define PSC3_BASE_ADDR 0xb0d00000
+#define PSC3_BASE_ADDR 0xb0b00000
+#endif
+
+#ifdef CONFIG_SOC_AU1200
+#define PSC0_BASE_ADDR 0xb1a00000
+#define PSC1_BASE_ADDR 0xb1b00000
#endif
/* The PSC select and control registers are common to
@@ -227,6 +232,8 @@ typedef struct psc_i2s {
#define PSC_I2SCFG_DD_DISABLE (1 << 27)
#define PSC_I2SCFG_DE_ENABLE (1 << 26)
#define PSC_I2SCFG_SET_WS(x) (((((x) / 2) - 1) & 0x7f) << 16)
+#define PSC_I2SCFG_WS(n) ((n & 0xFF) << 16)
+#define PSC_I2SCFG_WS_MASK (PSC_I2SCFG_WS(0x3F))
#define PSC_I2SCFG_WI (1 << 15)
#define PSC_I2SCFG_DIV_MASK (3 << 13)
diff --git a/include/asm-mips/mach-db1x00/db1x00.h b/include/asm-mips/mach-db1x00/db1x00.h
index 8fbb4b4..0f5f4c2 100644
--- a/include/asm-mips/mach-db1x00/db1x00.h
+++ b/include/asm-mips/mach-db1x00/db1x00.h
@@ -30,8 +30,20 @@
#ifdef CONFIG_MIPS_DB1550
+
+#define DBDMA_AC97_TX_CHAN DSCR_CMD0_PSC1_TX
+#define DBDMA_AC97_RX_CHAN DSCR_CMD0_PSC1_RX
+#define DBDMA_I2S_TX_CHAN DSCR_CMD0_PSC3_TX
+#define DBDMA_I2S_RX_CHAN DSCR_CMD0_PSC3_RX
+
+#define SPI_PSC_BASE PSC0_BASE_ADDR
+#define AC97_PSC_BASE PSC1_BASE_ADDR
+#define SMBUS_PSC_BASE PSC2_BASE_ADDR
+#define I2S_PSC_BASE PSC3_BASE_ADDR
+
#define BCSR_KSEG1_ADDR 0xAF000000
#define NAND_PHYS_ADDR 0x20000000
+
#else
#define BCSR_KSEG1_ADDR 0xAE000000
#endif
diff --git a/include/asm-mips/mach-generic/floppy.h b/include/asm-mips/mach-generic/floppy.h
index 682a585..83cd69e 100644
--- a/include/asm-mips/mach-generic/floppy.h
+++ b/include/asm-mips/mach-generic/floppy.h
@@ -98,7 +98,7 @@ static inline void fd_disable_irq(void)
static inline int fd_request_irq(void)
{
return request_irq(FLOPPY_IRQ, floppy_interrupt,
- SA_INTERRUPT | SA_SAMPLE_RANDOM, "floppy", NULL);
+ SA_INTERRUPT, "floppy", NULL);
}
static inline void fd_free_irq(void)
diff --git a/include/asm-mips/mach-jazz/floppy.h b/include/asm-mips/mach-jazz/floppy.h
index c9dad99..9413117 100644
--- a/include/asm-mips/mach-jazz/floppy.h
+++ b/include/asm-mips/mach-jazz/floppy.h
@@ -90,7 +90,7 @@ static inline void fd_disable_irq(void)
static inline int fd_request_irq(void)
{
return request_irq(FLOPPY_IRQ, floppy_interrupt,
- SA_INTERRUPT | SA_SAMPLE_RANDOM, "floppy", NULL);
+ SA_INTERRUPT, "floppy", NULL);
}
static inline void fd_free_irq(void)
diff --git a/include/asm-mips/mmzone.h b/include/asm-mips/mmzone.h
index dc231c8..f53ec54 100644
--- a/include/asm-mips/mmzone.h
+++ b/include/asm-mips/mmzone.h
@@ -10,7 +10,6 @@
#ifdef CONFIG_DISCONTIGMEM
-#define kvaddr_to_nid(kvaddr) pa_to_nid(__pa(kvaddr))
#define pfn_to_nid(pfn) pa_to_nid((pfn) << PAGE_SHIFT)
#endif /* CONFIG_DISCONTIGMEM */
diff --git a/include/asm-mips/vga.h b/include/asm-mips/vga.h
index 34755c0..c1dd0b1 100644
--- a/include/asm-mips/vga.h
+++ b/include/asm-mips/vga.h
@@ -13,7 +13,7 @@
* access the videoram directly without any black magic.
*/
-#define VGA_MAP_MEM(x) (0xb0000000L + (unsigned long)(x))
+#define VGA_MAP_MEM(x,s) (0xb0000000L + (unsigned long)(x))
#define vga_readb(x) (*(x))
#define vga_writeb(x,y) (*(y) = (x))
diff --git a/include/asm-parisc/floppy.h b/include/asm-parisc/floppy.h
index ca3aed7..458cdb2 100644
--- a/include/asm-parisc/floppy.h
+++ b/include/asm-parisc/floppy.h
@@ -159,10 +159,8 @@ static int fd_request_irq(void)
return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
"floppy", NULL);
else
- return request_irq(FLOPPY_IRQ, floppy_interrupt,
- SA_INTERRUPT|SA_SAMPLE_RANDOM,
- "floppy", NULL);
-
+ return request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT,
+ "floppy", NULL);
}
static unsigned long dma_mem_alloc(unsigned long size)
diff --git a/include/asm-parisc/mmzone.h b/include/asm-parisc/mmzone.h
index ceb9b73..c878136 100644
--- a/include/asm-parisc/mmzone.h
+++ b/include/asm-parisc/mmzone.h
@@ -14,11 +14,6 @@ extern struct node_map_data node_data[];
#define NODE_DATA(nid) (&node_data[nid].pg_data)
-/*
- * Given a kernel address, find the home node of the underlying memory.
- */
-#define kvaddr_to_nid(kaddr) pfn_to_nid(__pa(kaddr) >> PAGE_SHIFT)
-
#define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn)
#define node_end_pfn(nid) \
({ \
diff --git a/include/asm-powerpc/backlight.h b/include/asm-powerpc/backlight.h
index 1ba1f27..a5e9e65 100644
--- a/include/asm-powerpc/backlight.h
+++ b/include/asm-powerpc/backlight.h
@@ -2,30 +2,30 @@
* Routines for handling backlight control on PowerBooks
*
* For now, implementation resides in
- * arch/powerpc/platforms/powermac/pmac_support.c
+ * arch/powerpc/platforms/powermac/backlight.c
*
*/
#ifndef __ASM_POWERPC_BACKLIGHT_H
#define __ASM_POWERPC_BACKLIGHT_H
#ifdef __KERNEL__
-/* Abstract values */
-#define BACKLIGHT_OFF 0
-#define BACKLIGHT_MIN 1
-#define BACKLIGHT_MAX 0xf
+#include <linux/fb.h>
+#include <linux/mutex.h>
-struct backlight_controller {
- int (*set_enable)(int enable, int level, void *data);
- int (*set_level)(int level, void *data);
-};
+/* For locking instructions, see the implementation file */
+extern struct backlight_device *pmac_backlight;
+extern struct mutex pmac_backlight_mutex;
-extern void register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type);
-extern void unregister_backlight_controller(struct backlight_controller *ctrler, void *data);
+extern void pmac_backlight_calc_curve(struct fb_info*);
+extern int pmac_backlight_curve_lookup(struct fb_info *info, int value);
-extern int set_backlight_enable(int enable);
-extern int get_backlight_enable(void);
-extern int set_backlight_level(int level);
-extern int get_backlight_level(void);
+extern int pmac_has_backlight_type(const char *type);
+
+extern void pmac_backlight_key_up(void);
+extern void pmac_backlight_key_down(void);
+
+extern int pmac_backlight_set_legacy_brightness(int brightness);
+extern int pmac_backlight_get_legacy_brightness(void);
#endif /* __KERNEL__ */
#endif
diff --git a/include/asm-powerpc/bitops.h b/include/asm-powerpc/bitops.h
index d1c2a44..76e2f08 100644
--- a/include/asm-powerpc/bitops.h
+++ b/include/asm-powerpc/bitops.h
@@ -288,8 +288,8 @@ static __inline__ int test_le_bit(unsigned long nr,
#define __test_and_clear_le_bit(nr, addr) \
__test_and_clear_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
-#define find_first_zero_le_bit(addr, size) find_next_zero_le_bit((addr), (size), 0)
-unsigned long find_next_zero_le_bit(const unsigned long *addr,
+#define find_first_zero_le_bit(addr, size) generic_find_next_zero_le_bit((addr), (size), 0)
+unsigned long generic_find_next_zero_le_bit(const unsigned long *addr,
unsigned long size, unsigned long offset);
/* Bitmap functions for the ext2 filesystem */
@@ -309,7 +309,7 @@ unsigned long find_next_zero_le_bit(const unsigned long *addr,
#define ext2_find_first_zero_bit(addr, size) \
find_first_zero_le_bit((unsigned long*)addr, size)
#define ext2_find_next_zero_bit(addr, size, off) \
- find_next_zero_le_bit((unsigned long*)addr, size, off)
+ generic_find_next_zero_le_bit((unsigned long*)addr, size, off)
/* Bitmap functions for the minix filesystem. */
diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h
index f6265c2..fab41c2 100644
--- a/include/asm-powerpc/cputable.h
+++ b/include/asm-powerpc/cputable.h
@@ -24,6 +24,9 @@
#define PPC_FEATURE_ICACHE_SNOOP 0x00002000
#define PPC_FEATURE_ARCH_2_05 0x00001000
+#define PPC_FEATURE_TRUE_LE 0x00000002
+#define PPC_FEATURE_PPC_LE 0x00000001
+
#ifdef __KERNEL__
#ifndef __ASSEMBLY__
@@ -69,6 +72,13 @@ struct cpu_spec {
/* Processor specific oprofile operations */
enum powerpc_oprofile_type oprofile_type;
+ /* Bit locations inside the mmcra change */
+ unsigned long oprofile_mmcra_sihv;
+ unsigned long oprofile_mmcra_sipr;
+
+ /* Bits to clear during an oprofile exception */
+ unsigned long oprofile_mmcra_clear;
+
/* Name of processor class, for the ELF AT_PLATFORM entry */
char *platform;
};
@@ -104,6 +114,8 @@ extern void do_cpu_ftr_fixups(unsigned long offset);
#define CPU_FTR_NO_BTIC ASM_CONST(0x0000000000040000)
#define CPU_FTR_BIG_PHYS ASM_CONST(0x0000000000080000)
#define CPU_FTR_NODSISRALIGN ASM_CONST(0x0000000000100000)
+#define CPU_FTR_PPC_LE ASM_CONST(0x0000000000200000)
+#define CPU_FTR_REAL_LE ASM_CONST(0x0000000000400000)
#ifdef __powerpc64__
/* Add the 64b processor unique features in the top half of the word */
@@ -117,7 +129,6 @@ extern void do_cpu_ftr_fixups(unsigned long offset);
#define CPU_FTR_SMT ASM_CONST(0x0000010000000000)
#define CPU_FTR_COHERENT_ICACHE ASM_CONST(0x0000020000000000)
#define CPU_FTR_LOCKLESS_TLBIE ASM_CONST(0x0000040000000000)
-#define CPU_FTR_MMCRA_SIHV ASM_CONST(0x0000080000000000)
#define CPU_FTR_CI_LARGE_PAGE ASM_CONST(0x0000100000000000)
#define CPU_FTR_PAUSE_ZERO ASM_CONST(0x0000200000000000)
#define CPU_FTR_PURR ASM_CONST(0x0000400000000000)
@@ -134,7 +145,6 @@ extern void do_cpu_ftr_fixups(unsigned long offset);
#define CPU_FTR_SMT ASM_CONST(0x0)
#define CPU_FTR_COHERENT_ICACHE ASM_CONST(0x0)
#define CPU_FTR_LOCKLESS_TLBIE ASM_CONST(0x0)
-#define CPU_FTR_MMCRA_SIHV ASM_CONST(0x0)
#define CPU_FTR_CI_LARGE_PAGE ASM_CONST(0x0)
#define CPU_FTR_PURR ASM_CONST(0x0)
#endif
@@ -192,92 +202,95 @@ extern void do_cpu_ftr_fixups(unsigned long offset);
#define CPU_FTRS_PPC601 (CPU_FTR_COMMON | CPU_FTR_601 | CPU_FTR_HPTE_TABLE)
#define CPU_FTRS_603 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \
- CPU_FTR_MAYBE_CAN_NAP)
+ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE)
#define CPU_FTRS_604 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
- CPU_FTR_USE_TB | CPU_FTR_604_PERF_MON | CPU_FTR_HPTE_TABLE)
+ CPU_FTR_USE_TB | CPU_FTR_604_PERF_MON | CPU_FTR_HPTE_TABLE | \
+ CPU_FTR_PPC_LE)
#define CPU_FTRS_740_NOTAU (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
- CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP)
+ CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE)
#define CPU_FTRS_740 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
- CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP)
+ CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
+ CPU_FTR_PPC_LE)
#define CPU_FTRS_750 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
- CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP)
+ CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
+ CPU_FTR_PPC_LE)
#define CPU_FTRS_750FX1 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
- CPU_FTR_DUAL_PLL_750FX | CPU_FTR_NO_DPM)
+ CPU_FTR_DUAL_PLL_750FX | CPU_FTR_NO_DPM | CPU_FTR_PPC_LE)
#define CPU_FTRS_750FX2 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
- CPU_FTR_NO_DPM)
+ CPU_FTR_NO_DPM | CPU_FTR_PPC_LE)
#define CPU_FTRS_750FX (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
- CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS)
+ CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE)
#define CPU_FTRS_750GX (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \
CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | \
CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
- CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS)
+ CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE)
#define CPU_FTRS_7400_NOTAU (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | \
- CPU_FTR_MAYBE_CAN_NAP)
+ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE)
#define CPU_FTRS_7400 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | \
- CPU_FTR_MAYBE_CAN_NAP)
+ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE)
#define CPU_FTRS_7450_20 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
- CPU_FTR_NEED_COHERENT)
+ CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE)
#define CPU_FTRS_7450_21 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_USE_TB | \
CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_L3_DISABLE_NAP | \
- CPU_FTR_NEED_COHERENT)
+ CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE)
#define CPU_FTRS_7450_23 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_USE_TB | \
CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
- CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_NEED_COHERENT)
+ CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE)
#define CPU_FTRS_7455_1 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_USE_TB | \
CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | \
CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_HAS_HIGH_BATS | \
- CPU_FTR_NEED_COHERENT)
+ CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE)
#define CPU_FTRS_7455_20 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_USE_TB | \
CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_L3_DISABLE_NAP | \
- CPU_FTR_NEED_COHERENT | CPU_FTR_HAS_HIGH_BATS)
+ CPU_FTR_NEED_COHERENT | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE)
#define CPU_FTRS_7455 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_USE_TB | \
CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \
- CPU_FTR_NEED_COHERENT)
+ CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE)
#define CPU_FTRS_7447_10 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_USE_TB | \
CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \
- CPU_FTR_NEED_COHERENT | CPU_FTR_NO_BTIC)
+ CPU_FTR_NEED_COHERENT | CPU_FTR_NO_BTIC | CPU_FTR_PPC_LE)
#define CPU_FTRS_7447 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_USE_TB | \
CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \
- CPU_FTR_NEED_COHERENT)
+ CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE)
#define CPU_FTRS_7447A (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_USE_TB | \
CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \
- CPU_FTR_NEED_COHERENT)
+ CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE)
#define CPU_FTRS_82XX (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB)
#define CPU_FTRS_G2_LE (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \
@@ -287,13 +300,6 @@ extern void do_cpu_ftr_fixups(unsigned long offset);
CPU_FTR_COMMON)
#define CPU_FTRS_CLASSIC32 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE)
-#define CPU_FTRS_POWER3_32 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
- CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE)
-#define CPU_FTRS_POWER4_32 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
- CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_NODSISRALIGN)
-#define CPU_FTRS_970_32 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
- CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_ALTIVEC_COMP | \
- CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_NODSISRALIGN)
#define CPU_FTRS_8XX (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB)
#define CPU_FTRS_40X (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
CPU_FTR_NODSISRALIGN)
@@ -307,7 +313,7 @@ extern void do_cpu_ftr_fixups(unsigned long offset);
#define CPU_FTRS_GENERIC_32 (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN)
#ifdef __powerpc64__
#define CPU_FTRS_POWER3 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
- CPU_FTR_HPTE_TABLE | CPU_FTR_IABR)
+ CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | CPU_FTR_PPC_LE)
#define CPU_FTRS_RS64 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | \
CPU_FTR_MMCRA | CPU_FTR_CTRL)
@@ -320,12 +326,12 @@ extern void do_cpu_ftr_fixups(unsigned long offset);
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
CPU_FTR_MMCRA | CPU_FTR_SMT | \
CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
- CPU_FTR_MMCRA_SIHV | CPU_FTR_PURR)
+ CPU_FTR_PURR)
#define CPU_FTRS_POWER6 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
CPU_FTR_MMCRA | CPU_FTR_SMT | \
CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
- CPU_FTR_PURR | CPU_FTR_CI_LARGE_PAGE)
+ CPU_FTR_PURR | CPU_FTR_CI_LARGE_PAGE | CPU_FTR_REAL_LE)
#define CPU_FTRS_CELL (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
@@ -354,12 +360,6 @@ enum {
#else
CPU_FTRS_GENERIC_32 |
#endif
-#ifdef CONFIG_PPC64BRIDGE
- CPU_FTRS_POWER3_32 |
-#endif
-#ifdef CONFIG_POWER4
- CPU_FTRS_POWER4_32 | CPU_FTRS_970_32 |
-#endif
#ifdef CONFIG_8xx
CPU_FTRS_8XX |
#endif
@@ -399,12 +399,6 @@ enum {
#else
CPU_FTRS_GENERIC_32 &
#endif
-#ifdef CONFIG_PPC64BRIDGE
- CPU_FTRS_POWER3_32 &
-#endif
-#ifdef CONFIG_POWER4
- CPU_FTRS_POWER4_32 & CPU_FTRS_970_32 &
-#endif
#ifdef CONFIG_8xx
CPU_FTRS_8XX &
#endif
diff --git a/include/asm-powerpc/delay.h b/include/asm-powerpc/delay.h
index 057a609..f9200a6 100644
--- a/include/asm-powerpc/delay.h
+++ b/include/asm-powerpc/delay.h
@@ -17,5 +17,18 @@
extern void __delay(unsigned long loops);
extern void udelay(unsigned long usecs);
+/*
+ * On shared processor machines the generic implementation of mdelay can
+ * result in large errors. While each iteration of the loop inside mdelay
+ * is supposed to take 1ms, the hypervisor could sleep our partition for
+ * longer (eg 10ms). With the right timing these errors can add up.
+ *
+ * Since there is no 32bit overflow issue on 64bit kernels, just call
+ * udelay directly.
+ */
+#ifdef CONFIG_PPC64
+#define mdelay(n) udelay((n) * 1000)
+#endif
+
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_DELAY_H */
diff --git a/include/asm-powerpc/eeh.h b/include/asm-powerpc/eeh.h
index e9c86b1..4df3e80 100644
--- a/include/asm-powerpc/eeh.h
+++ b/include/asm-powerpc/eeh.h
@@ -292,8 +292,6 @@ static inline void eeh_memcpy_toio(volatile void __iomem *dest, const void *src,
static inline u8 eeh_inb(unsigned long port)
{
u8 val;
- if (!_IO_IS_VALID(port))
- return ~0;
val = in_8((u8 __iomem *)(port+pci_io_base));
if (EEH_POSSIBLE_ERROR(val, u8))
return eeh_check_failure((void __iomem *)(port), val);
@@ -302,15 +300,12 @@ static inline u8 eeh_inb(unsigned long port)
static inline void eeh_outb(u8 val, unsigned long port)
{
- if (_IO_IS_VALID(port))
- out_8((u8 __iomem *)(port+pci_io_base), val);
+ out_8((u8 __iomem *)(port+pci_io_base), val);
}
static inline u16 eeh_inw(unsigned long port)
{
u16 val;
- if (!_IO_IS_VALID(port))
- return ~0;
val = in_le16((u16 __iomem *)(port+pci_io_base));
if (EEH_POSSIBLE_ERROR(val, u16))
return eeh_check_failure((void __iomem *)(port), val);
@@ -319,15 +314,12 @@ static inline u16 eeh_inw(unsigned long port)
static inline void eeh_outw(u16 val, unsigned long port)
{
- if (_IO_IS_VALID(port))
- out_le16((u16 __iomem *)(port+pci_io_base), val);
+ out_le16((u16 __iomem *)(port+pci_io_base), val);
}
static inline u32 eeh_inl(unsigned long port)
{
u32 val;
- if (!_IO_IS_VALID(port))
- return ~0;
val = in_le32((u32 __iomem *)(port+pci_io_base));
if (EEH_POSSIBLE_ERROR(val, u32))
return eeh_check_failure((void __iomem *)(port), val);
@@ -336,8 +328,7 @@ static inline u32 eeh_inl(unsigned long port)
static inline void eeh_outl(u32 val, unsigned long port)
{
- if (_IO_IS_VALID(port))
- out_le32((u32 __iomem *)(port+pci_io_base), val);
+ out_le32((u32 __iomem *)(port+pci_io_base), val);
}
/* in-string eeh macros */
diff --git a/include/asm-powerpc/eeh_event.h b/include/asm-powerpc/eeh_event.h
index 93d55a2..dc6bf0f 100644
--- a/include/asm-powerpc/eeh_event.h
+++ b/include/asm-powerpc/eeh_event.h
@@ -18,8 +18,8 @@
* Copyright (c) 2005 Linas Vepstas <linas@linas.org>
*/
-#ifndef ASM_PPC64_EEH_EVENT_H
-#define ASM_PPC64_EEH_EVENT_H
+#ifndef ASM_POWERPC_EEH_EVENT_H
+#define ASM_POWERPC_EEH_EVENT_H
#ifdef __KERNEL__
/** EEH event -- structure holding pci controller data that describes
@@ -39,7 +39,7 @@ struct eeh_event {
* @dev pci device
*
* This routine builds a PCI error event which will be delivered
- * to all listeners on the peh_notifier_chain.
+ * to all listeners on the eeh_notifier_chain.
*
* This routine can be called within an interrupt context;
* the actual event will be delivered in a normal context
@@ -51,7 +51,7 @@ int eeh_send_failure_event (struct device_node *dn,
int time_unavail);
/* Main recovery function */
-void handle_eeh_events (struct eeh_event *);
+struct pci_dn * handle_eeh_events (struct eeh_event *);
#endif /* __KERNEL__ */
-#endif /* ASM_PPC64_EEH_EVENT_H */
+#endif /* ASM_POWERPC_EEH_EVENT_H */
diff --git a/include/asm-powerpc/elf.h b/include/asm-powerpc/elf.h
index 99c18b7..9a83a98 100644
--- a/include/asm-powerpc/elf.h
+++ b/include/asm-powerpc/elf.h
@@ -293,7 +293,7 @@ do { \
NEW_AUX_ENT(AT_DCACHEBSIZE, dcache_bsize); \
NEW_AUX_ENT(AT_ICACHEBSIZE, icache_bsize); \
NEW_AUX_ENT(AT_UCACHEBSIZE, ucache_bsize); \
- VDSO_AUX_ENT(AT_SYSINFO_EHDR, current->thread.vdso_base) \
+ VDSO_AUX_ENT(AT_SYSINFO_EHDR, current->mm->context.vdso_base) \
} while (0)
/* PowerPC64 relocations defined by the ABIs */
diff --git a/include/asm-powerpc/floppy.h b/include/asm-powerpc/floppy.h
index 7e2d169..9c8d91b 100644
--- a/include/asm-powerpc/floppy.h
+++ b/include/asm-powerpc/floppy.h
@@ -27,8 +27,7 @@
#define fd_disable_irq() disable_irq(FLOPPY_IRQ)
#define fd_cacheflush(addr,size) /* nothing */
#define fd_request_irq() request_irq(FLOPPY_IRQ, floppy_interrupt, \
- SA_INTERRUPT|SA_SAMPLE_RANDOM, \
- "floppy", NULL)
+ SA_INTERRUPT, "floppy", NULL)
#define fd_free_irq() free_irq(FLOPPY_IRQ, NULL);
#ifdef CONFIG_PCI
diff --git a/include/asm-powerpc/hvcall.h b/include/asm-powerpc/hvcall.h
index 6cc7e1f..0d3c4e8 100644
--- a/include/asm-powerpc/hvcall.h
+++ b/include/asm-powerpc/hvcall.h
@@ -102,6 +102,15 @@
#define H_PP1 (1UL<<(63-62))
#define H_PP2 (1UL<<(63-63))
+/* VASI States */
+#define H_VASI_INVALID 0
+#define H_VASI_ENABLED 1
+#define H_VASI_ABORTED 2
+#define H_VASI_SUSPENDING 3
+#define H_VASI_SUSPENDED 4
+#define H_VASI_RESUMED 5
+#define H_VASI_COMPLETED 6
+
/* DABRX flags */
#define H_DABRX_HYPERVISOR (1UL<<(63-61))
#define H_DABRX_KERNEL (1UL<<(63-62))
@@ -190,6 +199,7 @@
#define H_QUERY_INT_STATE 0x1E4
#define H_POLL_PENDING 0x1D8
#define H_JOIN 0x298
+#define H_VASI_STATE 0x2A4
#define H_ENABLE_CRQ 0x2B0
#ifndef __ASSEMBLY__
diff --git a/include/asm-powerpc/immap_86xx.h b/include/asm-powerpc/immap_86xx.h
new file mode 100644
index 0000000..d905b66
--- /dev/null
+++ b/include/asm-powerpc/immap_86xx.h
@@ -0,0 +1,199 @@
+/*
+ * MPC86xx Internal Memory Map
+ *
+ * Author: Jeff Brown
+ *
+ * Copyright 2004 Freescale Semiconductor, Inc
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM_POWERPC_IMMAP_86XX_H__
+#define __ASM_POWERPC_IMMAP_86XX_H__
+#ifdef __KERNEL__
+
+/* Eventually this should define all the IO block registers in 86xx */
+
+/* PCI Registers */
+typedef struct ccsr_pci {
+ uint cfg_addr; /* 0x.000 - PCI Configuration Address Register */
+ uint cfg_data; /* 0x.004 - PCI Configuration Data Register */
+ uint int_ack; /* 0x.008 - PCI Interrupt Acknowledge Register */
+ char res1[3060];
+ uint potar0; /* 0x.c00 - PCI Outbound Transaction Address Register 0 */
+ uint potear0; /* 0x.c04 - PCI Outbound Translation Extended Address Register 0 */
+ uint powbar0; /* 0x.c08 - PCI Outbound Window Base Address Register 0 */
+ char res2[4];
+ uint powar0; /* 0x.c10 - PCI Outbound Window Attributes Register 0 */
+ char res3[12];
+ uint potar1; /* 0x.c20 - PCI Outbound Transaction Address Register 1 */
+ uint potear1; /* 0x.c24 - PCI Outbound Translation Extended Address Register 1 */
+ uint powbar1; /* 0x.c28 - PCI Outbound Window Base Address Register 1 */
+ char res4[4];
+ uint powar1; /* 0x.c30 - PCI Outbound Window Attributes Register 1 */
+ char res5[12];
+ uint potar2; /* 0x.c40 - PCI Outbound Transaction Address Register 2 */
+ uint potear2; /* 0x.c44 - PCI Outbound Translation Extended Address Register 2 */
+ uint powbar2; /* 0x.c48 - PCI Outbound Window Base Address Register 2 */
+ char res6[4];
+ uint powar2; /* 0x.c50 - PCI Outbound Window Attributes Register 2 */
+ char res7[12];
+ uint potar3; /* 0x.c60 - PCI Outbound Transaction Address Register 3 */
+ uint potear3; /* 0x.c64 - PCI Outbound Translation Extended Address Register 3 */
+ uint powbar3; /* 0x.c68 - PCI Outbound Window Base Address Register 3 */
+ char res8[4];
+ uint powar3; /* 0x.c70 - PCI Outbound Window Attributes Register 3 */
+ char res9[12];
+ uint potar4; /* 0x.c80 - PCI Outbound Transaction Address Register 4 */
+ uint potear4; /* 0x.c84 - PCI Outbound Translation Extended Address Register 4 */
+ uint powbar4; /* 0x.c88 - PCI Outbound Window Base Address Register 4 */
+ char res10[4];
+ uint powar4; /* 0x.c90 - PCI Outbound Window Attributes Register 4 */
+ char res11[268];
+ uint pitar3; /* 0x.da0 - PCI Inbound Translation Address Register 3 */
+ char res12[4];
+ uint piwbar3; /* 0x.da8 - PCI Inbound Window Base Address Register 3 */
+ uint piwbear3; /* 0x.dac - PCI Inbound Window Base Extended Address Register 3 */
+ uint piwar3; /* 0x.db0 - PCI Inbound Window Attributes Register 3 */
+ char res13[12];
+ uint pitar2; /* 0x.dc0 - PCI Inbound Translation Address Register 2 */
+ char res14[4];
+ uint piwbar2; /* 0x.dc8 - PCI Inbound Window Base Address Register 2 */
+ uint piwbear2; /* 0x.dcc - PCI Inbound Window Base Extended Address Register 2 */
+ uint piwar2; /* 0x.dd0 - PCI Inbound Window Attributes Register 2 */
+ char res15[12];
+ uint pitar1; /* 0x.de0 - PCI Inbound Translation Address Register 1 */
+ char res16[4];
+ uint piwbar1; /* 0x.de8 - PCI Inbound Window Base Address Register 1 */
+ char res17[4];
+ uint piwar1; /* 0x.df0 - PCI Inbound Window Attributes Register 1 */
+ char res18[12];
+ uint err_dr; /* 0x.e00 - PCI Error Detect Register */
+ uint err_cap_dr; /* 0x.e04 - PCI Error Capture Disable Register */
+ uint err_en; /* 0x.e08 - PCI Error Enable Register */
+ uint err_attrib; /* 0x.e0c - PCI Error Attributes Capture Register */
+ uint err_addr; /* 0x.e10 - PCI Error Address Capture Register */
+ uint err_ext_addr; /* 0x.e14 - PCI Error Extended Address Capture Register */
+ uint err_dl; /* 0x.e18 - PCI Error Data Low Capture Register */
+ uint err_dh; /* 0x.e1c - PCI Error Data High Capture Register */
+ uint gas_timr; /* 0x.e20 - PCI Gasket Timer Register */
+ uint pci_timr; /* 0x.e24 - PCI Timer Register */
+ char res19[472];
+} ccsr_pci_t;
+
+/* PCI Express Registers */
+typedef struct ccsr_pex {
+ uint pex_config_addr; /* 0x.000 - PCI Express Configuration Address Register */
+ uint pex_config_data; /* 0x.004 - PCI Express Configuration Data Register */
+ char res1[4];
+ uint pex_otb_cpl_tor; /* 0x.00c - PCI Express Outbound completion timeout register */
+ uint pex_conf_tor; /* 0x.010 - PCI Express configuration timeout register */
+ char res2[12];
+ uint pex_pme_mes_dr; /* 0x.020 - PCI Express PME and message detect register */
+ uint pex_pme_mes_disr; /* 0x.024 - PCI Express PME and message disable register */
+ uint pex_pme_mes_ier; /* 0x.028 - PCI Express PME and message interrupt enable register */
+ uint pex_pmcr; /* 0x.02c - PCI Express power management command register */
+ char res3[3024];
+ uint pexotar0; /* 0x.c00 - PCI Express outbound translation address register 0 */
+ uint pexotear0; /* 0x.c04 - PCI Express outbound translation extended address register 0*/
+ char res4[8];
+ uint pexowar0; /* 0x.c10 - PCI Express outbound window attributes register 0*/
+ char res5[12];
+ uint pexotar1; /* 0x.c20 - PCI Express outbound translation address register 1 */
+ uint pexotear1; /* 0x.c24 - PCI Express outbound translation extended address register 1*/
+ uint pexowbar1; /* 0x.c28 - PCI Express outbound window base address register 1*/
+ char res6[4];
+ uint pexowar1; /* 0x.c30 - PCI Express outbound window attributes register 1*/
+ char res7[12];
+ uint pexotar2; /* 0x.c40 - PCI Express outbound translation address register 2 */
+ uint pexotear2; /* 0x.c44 - PCI Express outbound translation extended address register 2*/
+ uint pexowbar2; /* 0x.c48 - PCI Express outbound window base address register 2*/
+ char res8[4];
+ uint pexowar2; /* 0x.c50 - PCI Express outbound window attributes register 2*/
+ char res9[12];
+ uint pexotar3; /* 0x.c60 - PCI Express outbound translation address register 3 */
+ uint pexotear3; /* 0x.c64 - PCI Express outbound translation extended address register 3*/
+ uint pexowbar3; /* 0x.c68 - PCI Express outbound window base address register 3*/
+ char res10[4];
+ uint pexowar3; /* 0x.c70 - PCI Express outbound window attributes register 3*/
+ char res11[12];
+ uint pexotar4; /* 0x.c80 - PCI Express outbound translation address register 4 */
+ uint pexotear4; /* 0x.c84 - PCI Express outbound translation extended address register 4*/
+ uint pexowbar4; /* 0x.c88 - PCI Express outbound window base address register 4*/
+ char res12[4];
+ uint pexowar4; /* 0x.c90 - PCI Express outbound window attributes register 4*/
+ char res13[12];
+ char res14[256];
+ uint pexitar3; /* 0x.da0 - PCI Express inbound translation address register 3 */
+ char res15[4];
+ uint pexiwbar3; /* 0x.da8 - PCI Express inbound window base address register 3 */
+ uint pexiwbear3; /* 0x.dac - PCI Express inbound window base extended address register 3 */
+ uint pexiwar3; /* 0x.db0 - PCI Express inbound window attributes register 3 */
+ char res16[12];
+ uint pexitar2; /* 0x.dc0 - PCI Express inbound translation address register 2 */
+ char res17[4];
+ uint pexiwbar2; /* 0x.dc8 - PCI Express inbound window base address register 2 */
+ uint pexiwbear2; /* 0x.dcc - PCI Express inbound window base extended address register 2 */
+ uint pexiwar2; /* 0x.dd0 - PCI Express inbound window attributes register 2 */
+ char res18[12];
+ uint pexitar1; /* 0x.de0 - PCI Express inbound translation address register 2 */
+ char res19[4];
+ uint pexiwbar1; /* 0x.de8 - PCI Express inbound window base address register 2 */
+ uint pexiwbear1; /* 0x.dec - PCI Express inbound window base extended address register 2 */
+ uint pexiwar1; /* 0x.df0 - PCI Express inbound window attributes register 2 */
+ char res20[12];
+ uint pex_err_dr; /* 0x.e00 - PCI Express error detect register */
+ char res21[4];
+ uint pex_err_en; /* 0x.e08 - PCI Express error interrupt enable register */
+ char res22[4];
+ uint pex_err_disr; /* 0x.e10 - PCI Express error disable register */
+ char res23[12];
+ uint pex_err_cap_stat; /* 0x.e20 - PCI Express error capture status register */
+ char res24[4];
+ uint pex_err_cap_r0; /* 0x.e28 - PCI Express error capture register 0 */
+ uint pex_err_cap_r1; /* 0x.e2c - PCI Express error capture register 0 */
+ uint pex_err_cap_r2; /* 0x.e30 - PCI Express error capture register 0 */
+ uint pex_err_cap_r3; /* 0x.e34 - PCI Express error capture register 0 */
+} ccsr_pex_t;
+
+/* Global Utility Registers */
+typedef struct ccsr_guts {
+ uint porpllsr; /* 0x.0000 - POR PLL Ratio Status Register */
+ uint porbmsr; /* 0x.0004 - POR Boot Mode Status Register */
+ uint porimpscr; /* 0x.0008 - POR I/O Impedance Status and Control Register */
+ uint pordevsr; /* 0x.000c - POR I/O Device Status Register */
+ uint pordbgmsr; /* 0x.0010 - POR Debug Mode Status Register */
+ char res1[12];
+ uint gpporcr; /* 0x.0020 - General-Purpose POR Configuration Register */
+ char res2[12];
+ uint gpiocr; /* 0x.0030 - GPIO Control Register */
+ char res3[12];
+ uint gpoutdr; /* 0x.0040 - General-Purpose Output Data Register */
+ char res4[12];
+ uint gpindr; /* 0x.0050 - General-Purpose Input Data Register */
+ char res5[12];
+ uint pmuxcr; /* 0x.0060 - Alternate Function Signal Multiplex Control */
+ char res6[12];
+ uint devdisr; /* 0x.0070 - Device Disable Control */
+ char res7[12];
+ uint powmgtcsr; /* 0x.0080 - Power Management Status and Control Register */
+ char res8[12];
+ uint mcpsumr; /* 0x.0090 - Machine Check Summary Register */
+ char res9[12];
+ uint pvr; /* 0x.00a0 - Processor Version Register */
+ uint svr; /* 0x.00a4 - System Version Register */
+ char res10[3416];
+ uint clkocr; /* 0x.0e00 - Clock Out Select Register */
+ char res11[12];
+ uint ddrdllcr; /* 0x.0e10 - DDR DLL Control Register */
+ char res12[12];
+ uint lbcdllcr; /* 0x.0e20 - LBC DLL Control Register */
+ char res13[61916];
+} ccsr_guts_t;
+
+#endif /* __ASM_POWERPC_IMMAP_86XX_H__ */
+#endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/io.h b/include/asm-powerpc/io.h
index f1c2469..a9496f3 100644
--- a/include/asm-powerpc/io.h
+++ b/include/asm-powerpc/io.h
@@ -40,12 +40,6 @@ extern int check_legacy_ioport(unsigned long base_port);
extern unsigned long isa_io_base;
extern unsigned long pci_io_base;
-extern unsigned long io_page_mask;
-
-#define MAX_ISA_PORT 0x10000
-
-#define _IO_IS_VALID(port) ((port) >= MAX_ISA_PORT || (1 << (port>>PAGE_SHIFT)) \
- & io_page_mask)
#ifdef CONFIG_PPC_ISERIES
/* __raw_* accessors aren't supported on iSeries */
diff --git a/include/asm-powerpc/iommu.h b/include/asm-powerpc/iommu.h
index 2acf7b2..a5e9864 100644
--- a/include/asm-powerpc/iommu.h
+++ b/include/asm-powerpc/iommu.h
@@ -66,7 +66,8 @@ extern void iommu_free_table(struct device_node *dn);
/* Initializes an iommu_table based in values set in the passed-in
* structure
*/
-extern struct iommu_table *iommu_init_table(struct iommu_table * tbl);
+extern struct iommu_table *iommu_init_table(struct iommu_table * tbl,
+ int nid);
extern int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
struct scatterlist *sglist, int nelems, unsigned long mask,
@@ -75,7 +76,8 @@ extern void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
int nelems, enum dma_data_direction direction);
extern void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size,
- dma_addr_t *dma_handle, unsigned long mask, gfp_t flag);
+ dma_addr_t *dma_handle, unsigned long mask,
+ gfp_t flag, int node);
extern void iommu_free_coherent(struct iommu_table *tbl, size_t size,
void *vaddr, dma_addr_t dma_handle);
extern dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr,
diff --git a/include/asm-powerpc/irq.h b/include/asm-powerpc/irq.h
index 1e9f253..a10feec 100644
--- a/include/asm-powerpc/irq.h
+++ b/include/asm-powerpc/irq.h
@@ -347,6 +347,92 @@ extern u64 ppc64_interrupt_controller;
#define SIU_INT_PC1 ((uint)0x3e+CPM_IRQ_OFFSET)
#define SIU_INT_PC0 ((uint)0x3f+CPM_IRQ_OFFSET)
+#elif defined(CONFIG_PPC_86xx)
+#include <asm/mpc86xx.h>
+
+#define NR_EPIC_INTS 48
+#ifndef NR_8259_INTS
+#define NR_8259_INTS 16 /*ULI 1575 can route 12 interrupts */
+#endif
+#define NUM_8259_INTERRUPTS NR_8259_INTS
+
+#ifndef I8259_OFFSET
+#define I8259_OFFSET 0
+#endif
+
+#define NR_IRQS 256
+
+/* Internal IRQs on MPC86xx OpenPIC */
+
+#ifndef MPC86xx_OPENPIC_IRQ_OFFSET
+#define MPC86xx_OPENPIC_IRQ_OFFSET NR_8259_INTS
+#endif
+
+/* The 48 internal sources */
+#define MPC86xx_IRQ_NULL ( 0 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_MCM ( 1 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_DDR ( 2 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_LBC ( 3 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_DMA0 ( 4 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_DMA1 ( 5 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_DMA2 ( 6 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_DMA3 ( 7 + MPC86xx_OPENPIC_IRQ_OFFSET)
+
+/* no 10,11 */
+#define MPC86xx_IRQ_UART2 (12 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_TSEC1_TX (13 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_TSEC1_RX (14 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_TSEC3_TX (15 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_TSEC3_RX (16 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_TSEC3_ERROR (17 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_TSEC1_ERROR (18 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_TSEC2_TX (19 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_TSEC2_RX (20 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_TSEC4_TX (21 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_TSEC4_RX (22 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_TSEC4_ERROR (23 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_TSEC2_ERROR (24 + MPC86xx_OPENPIC_IRQ_OFFSET)
+/* no 25 */
+#define MPC86xx_IRQ_UART1 (26 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_IIC (27 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_PERFMON (28 + MPC86xx_OPENPIC_IRQ_OFFSET)
+/* no 29,30,31 */
+#define MPC86xx_IRQ_SRIO_ERROR (32 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_SRIO_OUT_BELL (33 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_SRIO_IN_BELL (34 + MPC86xx_OPENPIC_IRQ_OFFSET)
+/* no 35,36 */
+#define MPC86xx_IRQ_SRIO_OUT_MSG1 (37 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_SRIO_IN_MSG1 (38 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_SRIO_OUT_MSG2 (39 + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_SRIO_IN_MSG2 (40 + MPC86xx_OPENPIC_IRQ_OFFSET)
+
+/* The 12 external interrupt lines */
+#define MPC86xx_IRQ_EXT_BASE 48
+#define MPC86xx_IRQ_EXT0 (0 + MPC86xx_IRQ_EXT_BASE \
+ + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_EXT1 (1 + MPC86xx_IRQ_EXT_BASE \
+ + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_EXT2 (2 + MPC86xx_IRQ_EXT_BASE \
+ + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_EXT3 (3 + MPC86xx_IRQ_EXT_BASE \
+ + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_EXT4 (4 + MPC86xx_IRQ_EXT_BASE \
+ + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_EXT5 (5 + MPC86xx_IRQ_EXT_BASE \
+ + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_EXT6 (6 + MPC86xx_IRQ_EXT_BASE \
+ + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_EXT7 (7 + MPC86xx_IRQ_EXT_BASE \
+ + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_EXT8 (8 + MPC86xx_IRQ_EXT_BASE \
+ + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_EXT9 (9 + MPC86xx_IRQ_EXT_BASE \
+ + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_EXT10 (10 + MPC86xx_IRQ_EXT_BASE \
+ + MPC86xx_OPENPIC_IRQ_OFFSET)
+#define MPC86xx_IRQ_EXT11 (11 + MPC86xx_IRQ_EXT_BASE \
+ + MPC86xx_OPENPIC_IRQ_OFFSET)
+
#else /* CONFIG_40x + CONFIG_8xx */
/*
* this is the # irq's for all ppc arch's (pmac/chrp/prep)
diff --git a/arch/powerpc/platforms/iseries/iommu.h b/include/asm-powerpc/iseries/iommu.h
index cb5658f..0edbfe1 100644
--- a/arch/powerpc/platforms/iseries/iommu.h
+++ b/include/asm-powerpc/iseries/iommu.h
@@ -1,5 +1,5 @@
-#ifndef _PLATFORMS_ISERIES_IOMMU_H
-#define _PLATFORMS_ISERIES_IOMMU_H
+#ifndef _ASM_POWERPC_ISERIES_IOMMU_H
+#define _ASM_POWERPC_ISERIES_IOMMU_H
/*
* Copyright (C) 2005 Stephen Rothwell, IBM Corporation
@@ -32,4 +32,4 @@ extern void iommu_table_getparms_iSeries(unsigned long busno,
unsigned char slotno, unsigned char virtbus,
struct iommu_table *tbl);
-#endif /* _PLATFORMS_ISERIES_IOMMU_H */
+#endif /* _ASM_POWERPC_ISERIES_IOMMU_H */
diff --git a/include/asm-powerpc/kdump.h b/include/asm-powerpc/kdump.h
index a87aed0..5a5c3b5 100644
--- a/include/asm-powerpc/kdump.h
+++ b/include/asm-powerpc/kdump.h
@@ -1,13 +1,38 @@
#ifndef _PPC64_KDUMP_H
#define _PPC64_KDUMP_H
+/* Kdump kernel runs at 32 MB, change at your peril. */
+#define KDUMP_KERNELBASE 0x2000000
+
/* How many bytes to reserve at zero for kdump. The reserve limit should
- * be greater or equal to the trampoline's end address. */
+ * be greater or equal to the trampoline's end address.
+ * Reserve to the end of the FWNMI area, see head_64.S */
#define KDUMP_RESERVE_LIMIT 0x8000
+#ifdef CONFIG_CRASH_DUMP
+
+#define PHYSICAL_START KDUMP_KERNELBASE
#define KDUMP_TRAMPOLINE_START 0x0100
#define KDUMP_TRAMPOLINE_END 0x3000
-extern void kdump_setup(void);
+#else /* !CONFIG_CRASH_DUMP */
+
+#define PHYSICAL_START 0x0
+
+#endif /* CONFIG_CRASH_DUMP */
+
+#ifndef __ASSEMBLY__
+#ifdef CONFIG_CRASH_DUMP
+
+extern void reserve_kdump_trampoline(void);
+extern void setup_kdump_trampoline(void);
+
+#else /* !CONFIG_CRASH_DUMP */
+
+static inline void reserve_kdump_trampoline(void) { ; }
+static inline void setup_kdump_trampoline(void) { ; }
+
+#endif /* CONFIG_CRASH_DUMP */
+#endif /* __ASSEMBLY__ */
#endif /* __PPC64_KDUMP_H */
diff --git a/include/asm-powerpc/kexec.h b/include/asm-powerpc/kexec.h
index 6a2af2f..efe8872 100644
--- a/include/asm-powerpc/kexec.h
+++ b/include/asm-powerpc/kexec.h
@@ -31,9 +31,10 @@
#define KEXEC_ARCH KEXEC_ARCH_PPC
#endif
+#ifndef __ASSEMBLY__
+
#ifdef CONFIG_KEXEC
-#ifndef __ASSEMBLY__
#ifdef __powerpc64__
/*
* This function is responsible for capturing register states if coming
@@ -123,8 +124,19 @@ extern int default_machine_kexec_prepare(struct kimage *image);
extern void default_machine_crash_shutdown(struct pt_regs *regs);
extern void machine_kexec_simple(struct kimage *image);
+extern int overlaps_crashkernel(unsigned long start, unsigned long size);
+extern void reserve_crashkernel(void);
+
+#else /* !CONFIG_KEXEC */
+
+static inline int overlaps_crashkernel(unsigned long start, unsigned long size)
+{
+ return 0;
+}
+
+static inline void reserve_crashkernel(void) { ; }
-#endif /* ! __ASSEMBLY__ */
#endif /* CONFIG_KEXEC */
+#endif /* ! __ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_KEXEC_H */
diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h
index 3e7d37a..73db1f7 100644
--- a/include/asm-powerpc/machdep.h
+++ b/include/asm-powerpc/machdep.h
@@ -237,6 +237,11 @@ struct machdep_calls {
*/
void (*machine_kexec)(struct kimage *image);
#endif /* CONFIG_KEXEC */
+
+#ifdef CONFIG_PCI_MSI
+ int (*enable_msi)(struct pci_dev *pdev);
+ void (*disable_msi)(struct pci_dev *pdev);
+#endif /* CONFIG_PCI_MSI */
};
extern void power4_idle(void);
diff --git a/include/asm-powerpc/mmu.h b/include/asm-powerpc/mmu.h
index 31f7219..3a5ebe2 100644
--- a/include/asm-powerpc/mmu.h
+++ b/include/asm-powerpc/mmu.h
@@ -96,6 +96,8 @@ extern char initial_stab[];
#define HPTE_R_FLAGS ASM_CONST(0x00000000000003ff)
#define HPTE_R_PP ASM_CONST(0x0000000000000003)
#define HPTE_R_N ASM_CONST(0x0000000000000004)
+#define HPTE_R_C ASM_CONST(0x0000000000000080)
+#define HPTE_R_R ASM_CONST(0x0000000000000100)
/* Values for PP (assumes Ks=0, Kp=1) */
/* pp0 will always be 0 for linux */
@@ -163,6 +165,16 @@ struct mmu_psize_def
extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
extern int mmu_linear_psize;
extern int mmu_virtual_psize;
+extern int mmu_vmalloc_psize;
+extern int mmu_io_psize;
+
+/*
+ * If the processor supports 64k normal pages but not 64k cache
+ * inhibited pages, we have to be prepared to switch processes
+ * to use 4k pages when they create cache-inhibited mappings.
+ * If this is the case, mmu_ci_restrictions will be set to 1.
+ */
+extern int mmu_ci_restrictions;
#ifdef CONFIG_HUGETLB_PAGE
/*
@@ -254,6 +266,7 @@ extern long iSeries_hpte_insert(unsigned long hpte_group,
extern void stabs_alloc(void);
extern void slb_initialize(void);
+extern void slb_flush_and_rebolt(void);
extern void stab_initialize(unsigned long stab);
#endif /* __ASSEMBLY__ */
@@ -357,9 +370,12 @@ typedef unsigned long mm_context_id_t;
typedef struct {
mm_context_id_t id;
+ u16 user_psize; /* page size index */
+ u16 sllp; /* SLB entry page size encoding */
#ifdef CONFIG_HUGETLB_PAGE
u16 low_htlb_areas, high_htlb_areas;
#endif
+ unsigned long vdso_base;
} mm_context_t;
diff --git a/include/asm-powerpc/mmu_context.h b/include/asm-powerpc/mmu_context.h
index 1b8a25f..8c6b1a6d 100644
--- a/include/asm-powerpc/mmu_context.h
+++ b/include/asm-powerpc/mmu_context.h
@@ -20,16 +20,9 @@
* 2 of the License, or (at your option) any later version.
*/
-/*
- * Getting into a kernel thread, there is no valid user segment, mark
- * paca->pgdir NULL so that SLB miss on user addresses will fault
- */
static inline void enter_lazy_tlb(struct mm_struct *mm,
struct task_struct *tsk)
{
-#ifdef CONFIG_PPC_64K_PAGES
- get_paca()->pgdir = NULL;
-#endif /* CONFIG_PPC_64K_PAGES */
}
#define NO_CONTEXT 0
@@ -52,13 +45,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
cpu_set(smp_processor_id(), next->cpu_vm_mask);
/* No need to flush userspace segments if the mm doesnt change */
-#ifdef CONFIG_PPC_64K_PAGES
- if (prev == next && get_paca()->pgdir == next->pgd)
- return;
-#else
if (prev == next)
return;
-#endif /* CONFIG_PPC_64K_PAGES */
#ifdef CONFIG_ALTIVEC
if (cpu_has_feature(CPU_FTR_ALTIVEC))
diff --git a/include/asm-powerpc/mpc86xx.h b/include/asm-powerpc/mpc86xx.h
new file mode 100644
index 0000000..d0a6718
--- /dev/null
+++ b/include/asm-powerpc/mpc86xx.h
@@ -0,0 +1,47 @@
+/*
+ * MPC86xx definitions
+ *
+ * Author: Jeff Brown
+ *
+ * Copyright 2004 Freescale Semiconductor, Inc
+ *
+ * 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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_POWERPC_MPC86xx_H__
+#define __ASM_POWERPC_MPC86xx_H__
+
+#include <linux/config.h>
+#include <asm/mmu.h>
+
+#ifdef CONFIG_PPC_86xx
+
+#ifdef CONFIG_MPC8641_HPCN
+#include <platforms/86xx/mpc8641_hpcn.h>
+#endif
+
+#define _IO_BASE isa_io_base
+#define _ISA_MEM_BASE isa_mem_base
+#ifdef CONFIG_PCI
+#define PCI_DRAM_OFFSET pci_dram_offset
+#else
+#define PCI_DRAM_OFFSET 0
+#endif
+
+#define CPU0_BOOT_RELEASE 0x01000000
+#define CPU1_BOOT_RELEASE 0x02000000
+#define CPU_ALL_RELEASED (CPU0_BOOT_RELEASE | CPU1_BOOT_RELEASE)
+#define MCM_PORT_CONFIG_OFFSET 0x1010
+
+/* Offset from CCSRBAR */
+#define MPC86xx_OPENPIC_OFFSET (0x40000)
+#define MPC86xx_MCM_OFFSET (0x00000)
+#define MPC86xx_MCM_SIZE (0x02000)
+
+#endif /* CONFIG_PPC_86xx */
+#endif /* __ASM_POWERPC_MPC86xx_H__ */
+#endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h
index 6b9e781..f0d22ac 100644
--- a/include/asm-powerpc/mpic.h
+++ b/include/asm-powerpc/mpic.h
@@ -22,6 +22,10 @@
#define MPIC_GREG_GCONF_8259_PTHROU_DIS 0x20000000
#define MPIC_GREG_GCONF_BASE_MASK 0x000fffff
#define MPIC_GREG_GLOBAL_CONF_1 0x00030
+#define MPIC_GREG_GLOBAL_CONF_1_SIE 0x08000000
+#define MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO_MASK 0x70000000
+#define MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO(r) \
+ (((r) << 28) & MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO_MASK)
#define MPIC_GREG_VENDOR_0 0x00040
#define MPIC_GREG_VENDOR_1 0x00050
#define MPIC_GREG_VENDOR_2 0x00060
@@ -284,6 +288,12 @@ extern int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs);
/* This one gets to the primary mpic */
extern int mpic_get_irq(struct pt_regs *regs);
+/* Set the EPIC clock ratio */
+void mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio);
+
+/* Enable/Disable EPIC serial interrupt mode */
+void mpic_set_serial_int(struct mpic *mpic, int enable);
+
/* global mpic for pSeries */
extern struct mpic *pSeries_mpic;
diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h
index 3c6f644..2d4585f 100644
--- a/include/asm-powerpc/paca.h
+++ b/include/asm-powerpc/paca.h
@@ -78,11 +78,9 @@ struct paca_struct {
u64 exmc[10]; /* used for machine checks */
u64 exslb[10]; /* used for SLB/segment table misses
* on the linear mapping */
-#ifdef CONFIG_PPC_64K_PAGES
- pgd_t *pgdir;
-#endif /* CONFIG_PPC_64K_PAGES */
mm_context_t context;
+ u16 vmalloc_sllp;
u16 slb_cache[SLB_CACHE_ENTRIES];
u16 slb_cache_ptr;
diff --git a/include/asm-powerpc/page.h b/include/asm-powerpc/page.h
index f0469b9..fb597b3 100644
--- a/include/asm-powerpc/page.h
+++ b/include/asm-powerpc/page.h
@@ -12,6 +12,7 @@
#ifdef __KERNEL__
#include <asm/asm-compat.h>
+#include <asm/kdump.h>
/*
* On PPC32 page size is 4K. For PPC64 we support either 4K or 64K software
@@ -51,13 +52,6 @@
* If you want to test if something's a kernel address, use is_kernel_addr().
*/
-#ifdef CONFIG_CRASH_DUMP
-/* Kdump kernel runs at 32 MB, change at your peril. */
-#define PHYSICAL_START 0x2000000
-#else
-#define PHYSICAL_START 0x0
-#endif
-
#define PAGE_OFFSET ASM_CONST(CONFIG_KERNEL_START)
#define KERNELBASE (PAGE_OFFSET + PHYSICAL_START)
@@ -197,6 +191,9 @@ extern void copy_user_page(void *to, void *from, unsigned long vaddr,
struct page *p);
extern int page_is_ram(unsigned long pfn);
+struct vm_area_struct;
+extern const char *arch_vma_name(struct vm_area_struct *vma);
+
#include <asm-generic/memory_model.h>
#endif /* __ASSEMBLY__ */
diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h
index 38de92d..4f55573 100644
--- a/include/asm-powerpc/pci-bridge.h
+++ b/include/asm-powerpc/pci-bridge.h
@@ -6,6 +6,7 @@
#include <asm-ppc/pci-bridge.h>
#else
+#include <linux/config.h>
#include <linux/pci.h>
#include <linux/list.h>
@@ -22,6 +23,7 @@
struct pci_controller {
struct pci_bus *bus;
char is_dynamic;
+ int node;
void *arch_data;
struct list_head list_node;
@@ -78,12 +80,6 @@ struct pci_dn {
struct iommu_table *iommu_table; /* for phb's or bridges */
struct pci_dev *pcidev; /* back-pointer to the pci device */
struct device_node *node; /* back-pointer to the device_node */
-#ifdef CONFIG_PPC_ISERIES
- struct list_head Device_List;
- int Irq; /* Assigned IRQ */
- int Flags; /* Possible flags(disable/bist)*/
- u8 LogicalSlot; /* Hv Slot Index for Tces */
-#endif
u32 config_space[16]; /* saved PCI config space */
};
@@ -171,6 +167,12 @@ static inline unsigned long pci_address_to_pio(phys_addr_t address)
#define PCI_PROBE_NORMAL 0 /* Do normal PCI probing */
#define PCI_PROBE_DEVTREE 1 /* Instantiate from device tree */
+#ifdef CONFIG_NUMA
+#define PHB_SET_NODE(PHB, NODE) ((PHB)->node = (NODE))
+#else
+#define PHB_SET_NODE(PHB, NODE) ((PHB)->node = -1)
+#endif
+
#endif /* CONFIG_PPC64 */
#endif /* __KERNEL__ */
#endif
diff --git a/include/asm-powerpc/percpu.h b/include/asm-powerpc/percpu.h
index 184a7a4..faa1fc7 100644
--- a/include/asm-powerpc/percpu.h
+++ b/include/asm-powerpc/percpu.h
@@ -22,6 +22,7 @@
/* var is in discarded region: offset to particular copy we want */
#define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu)))
#define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()))
+#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()))
/* A macro to avoid #include hell... */
#define percpu_modcopy(pcpudst, src, size) \
@@ -41,6 +42,7 @@ extern void setup_per_cpu_areas(void);
#define per_cpu(var, cpu) (*((void)(cpu), &per_cpu__##var))
#define __get_cpu_var(var) per_cpu__##var
+#define __raw_get_cpu_var(var) per_cpu__##var
#endif /* SMP */
diff --git a/include/asm-powerpc/pgtable-4k.h b/include/asm-powerpc/pgtable-4k.h
index b2e1862..e703615 100644
--- a/include/asm-powerpc/pgtable-4k.h
+++ b/include/asm-powerpc/pgtable-4k.h
@@ -78,6 +78,8 @@
#define pte_iterate_hashed_end() } while(0)
+#define pte_pagesize_index(pte) MMU_PAGE_4K
+
/*
* 4-level page tables related bits
*/
diff --git a/include/asm-powerpc/pgtable-64k.h b/include/asm-powerpc/pgtable-64k.h
index 6539150..4b7126c 100644
--- a/include/asm-powerpc/pgtable-64k.h
+++ b/include/asm-powerpc/pgtable-64k.h
@@ -90,6 +90,8 @@
#define pte_iterate_hashed_end() } while(0); } } while(0)
+#define pte_pagesize_index(pte) \
+ (((pte) & _PAGE_COMBO)? MMU_PAGE_4K: MMU_PAGE_64K)
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/pgtable.h b/include/asm-powerpc/pgtable.h
index 964e312..8dbf5ad 100644
--- a/include/asm-powerpc/pgtable.h
+++ b/include/asm-powerpc/pgtable.h
@@ -46,8 +46,8 @@ struct mm_struct;
/*
* Define the address range of the vmalloc VM area.
*/
-#define VMALLOC_START (0xD000000000000000ul)
-#define VMALLOC_SIZE (0x80000000000UL)
+#define VMALLOC_START ASM_CONST(0xD000000000000000)
+#define VMALLOC_SIZE ASM_CONST(0x80000000000)
#define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE)
/*
@@ -412,12 +412,6 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
flush_tlb_pending();
}
pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
-
-#ifdef CONFIG_PPC_64K_PAGES
- if (mmu_virtual_psize != MMU_PAGE_64K)
- pte = __pte(pte_val(pte) | _PAGE_COMBO);
-#endif /* CONFIG_PPC_64K_PAGES */
-
*ptep = pte;
}
diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h
index 93f83ef..22e54a2 100644
--- a/include/asm-powerpc/processor.h
+++ b/include/asm-powerpc/processor.h
@@ -149,11 +149,11 @@ struct thread_struct {
unsigned int val; /* Floating point status */
} fpscr;
int fpexc_mode; /* floating-point exception mode */
+ unsigned int align_ctl; /* alignment handling control */
#ifdef CONFIG_PPC64
unsigned long start_tb; /* Start purr when proc switched in */
unsigned long accum_tb; /* Total accumilated purr for process */
#endif
- unsigned long vdso_base; /* base of the vDSO library */
unsigned long dabr; /* Data address breakpoint register */
#ifdef CONFIG_ALTIVEC
/* Complete AltiVec register set */
@@ -190,7 +190,7 @@ struct thread_struct {
.fs = KERNEL_DS, \
.fpr = {0}, \
.fpscr = { .val = 0, }, \
- .fpexc_mode = MSR_FE0|MSR_FE1, \
+ .fpexc_mode = 0, \
}
#endif
@@ -212,6 +212,18 @@ unsigned long get_wchan(struct task_struct *p);
extern int get_fpexc_mode(struct task_struct *tsk, unsigned long adr);
extern int set_fpexc_mode(struct task_struct *tsk, unsigned int val);
+#define GET_ENDIAN(tsk, adr) get_endian((tsk), (adr))
+#define SET_ENDIAN(tsk, val) set_endian((tsk), (val))
+
+extern int get_endian(struct task_struct *tsk, unsigned long adr);
+extern int set_endian(struct task_struct *tsk, unsigned int val);
+
+#define GET_UNALIGN_CTL(tsk, adr) get_unalign_ctl((tsk), (adr))
+#define SET_UNALIGN_CTL(tsk, val) set_unalign_ctl((tsk), (val))
+
+extern int get_unalign_ctl(struct task_struct *tsk, unsigned long adr);
+extern int set_unalign_ctl(struct task_struct *tsk, unsigned int val);
+
static inline unsigned int __unpack_fe01(unsigned long msr_bits)
{
return ((msr_bits & MSR_FE0) >> 10) | ((msr_bits & MSR_FE1) >> 8);
diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h
index f4e2ca6..010d186 100644
--- a/include/asm-powerpc/prom.h
+++ b/include/asm-powerpc/prom.h
@@ -229,7 +229,16 @@ extern int of_address_to_resource(struct device_node *dev, int index,
extern int of_pci_address_to_resource(struct device_node *dev, int bar,
struct resource *r);
+/* Parse the ibm,dma-window property of an OF node into the busno, phys and
+ * size parameters.
+ */
+void of_parse_dma_window(struct device_node *dn, unsigned char *dma_window_prop,
+ unsigned long *busno, unsigned long *phys, unsigned long *size);
+
extern void kdump_move_device_tree(void);
+/* CPU OF node matching */
+struct device_node *of_get_cpu_node(int cpu, unsigned int *thread);
+
#endif /* __KERNEL__ */
#endif /* _POWERPC_PROM_H */
diff --git a/include/asm-powerpc/ptrace.h b/include/asm-powerpc/ptrace.h
index 9c550b3..dc4cb9c 100644
--- a/include/asm-powerpc/ptrace.h
+++ b/include/asm-powerpc/ptrace.h
@@ -229,13 +229,13 @@ do { \
#define PTRACE_GET_DEBUGREG 25
#define PTRACE_SET_DEBUGREG 26
-#ifdef __powerpc64__
/* Additional PTRACE requests implemented on PowerPC. */
#define PPC_PTRACE_GETREGS 0x99 /* Get GPRs 0 - 31 */
#define PPC_PTRACE_SETREGS 0x98 /* Set GPRs 0 - 31 */
#define PPC_PTRACE_GETFPREGS 0x97 /* Get FPRs 0 - 31 */
#define PPC_PTRACE_SETFPREGS 0x96 /* Set FPRs 0 - 31 */
+#ifdef __powerpc64__
/* Calls to trace a 64bit program from a 32bit program */
#define PPC_PTRACE_PEEKTEXT_3264 0x95
#define PPC_PTRACE_PEEKDATA_3264 0x94
diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h
index bd467bf..cf73475 100644
--- a/include/asm-powerpc/reg.h
+++ b/include/asm-powerpc/reg.h
@@ -93,8 +93,8 @@
#define MSR_LE __MASK(MSR_LE_LG) /* Little Endian */
#ifdef CONFIG_PPC64
-#define MSR_ MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_ISF
-#define MSR_KERNEL MSR_ | MSR_SF | MSR_HV
+#define MSR_ MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_ISF |MSR_HV
+#define MSR_KERNEL MSR_ | MSR_SF
#define MSR_USER32 MSR_ | MSR_PR | MSR_EE
#define MSR_USER64 MSR_USER32 | MSR_SF
@@ -153,7 +153,7 @@
#define SPRN_DABR 0x3F5 /* Data Address Breakpoint Register */
#define DABR_TRANSLATION (1UL << 2)
#define SPRN_DAR 0x013 /* Data Address Register */
-#define SPRN_DSISR 0x012 /* Data Storage Interrupt Status Register */
+#define SPRN_DSISR 0x012 /* Data Storage Interrupt Status Register */
#define DSISR_NOHPTE 0x40000000 /* no translation found */
#define DSISR_PROTFAULT 0x08000000 /* protection fault */
#define DSISR_ISSTORE 0x02000000 /* access was a store */
@@ -258,16 +258,16 @@
#define SPRN_IABR 0x3F2 /* Instruction Address Breakpoint Register */
#define SPRN_HID4 0x3F4 /* 970 HID4 */
#define SPRN_HID5 0x3F6 /* 970 HID5 */
-#define SPRN_HID6 0x3F9 /* BE HID 6 */
-#define HID6_LB (0x0F<<12) /* Concurrent Large Page Modes */
-#define HID6_DLP (1<<20) /* Disable all large page modes (4K only) */
-#define SPRN_TSC_CELL 0x399 /* Thread switch control on Cell */
-#define TSC_CELL_DEC_ENABLE_0 0x400000 /* Decrementer Interrupt */
-#define TSC_CELL_DEC_ENABLE_1 0x200000 /* Decrementer Interrupt */
-#define TSC_CELL_EE_ENABLE 0x100000 /* External Interrupt */
-#define TSC_CELL_EE_BOOST 0x080000 /* External Interrupt Boost */
-#define SPRN_TSC 0x3FD /* Thread switch control on others */
-#define SPRN_TST 0x3FC /* Thread switch timeout on others */
+#define SPRN_HID6 0x3F9 /* BE HID 6 */
+#define HID6_LB (0x0F<<12) /* Concurrent Large Page Modes */
+#define HID6_DLP (1<<20) /* Disable all large page modes (4K only) */
+#define SPRN_TSC_CELL 0x399 /* Thread switch control on Cell */
+#define TSC_CELL_DEC_ENABLE_0 0x400000 /* Decrementer Interrupt */
+#define TSC_CELL_DEC_ENABLE_1 0x200000 /* Decrementer Interrupt */
+#define TSC_CELL_EE_ENABLE 0x100000 /* External Interrupt */
+#define TSC_CELL_EE_BOOST 0x080000 /* External Interrupt Boost */
+#define SPRN_TSC 0x3FD /* Thread switch control on others */
+#define SPRN_TST 0x3FC /* Thread switch timeout on others */
#if !defined(SPRN_IAC1) && !defined(SPRN_IAC2)
#define SPRN_IAC1 0x3F4 /* Instruction Address Compare 1 */
#define SPRN_IAC2 0x3F5 /* Instruction Address Compare 2 */
@@ -362,7 +362,7 @@
#endif
#define SPRN_PTEHI 0x3D5 /* 981 7450 PTE HI word (S/W TLB load) */
#define SPRN_PTELO 0x3D6 /* 982 7450 PTE LO word (S/W TLB load) */
-#define SPRN_PURR 0x135 /* Processor Utilization of Resources Reg */
+#define SPRN_PURR 0x135 /* Processor Utilization of Resources Reg */
#define SPRN_PVR 0x11F /* Processor Version Register */
#define SPRN_RPA 0x3D6 /* Required Physical Address Register */
#define SPRN_SDA 0x3BF /* Sampled Data Address Register */
@@ -386,6 +386,8 @@
#define SRR1_WAKEMT 0x00280000 /* mtctrl */
#define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */
#define SRR1_WAKETHERM 0x00100000 /* Thermal management interrupt */
+#define SPRN_HSRR0 0x13A /* Save/Restore Register 0 */
+#define SPRN_HSRR1 0x13B /* Save/Restore Register 1 */
#ifndef SPRN_SVR
#define SPRN_SVR 0x11E /* System Version Register */
@@ -443,6 +445,10 @@
#define MMCRA_SIHV 0x10000000UL /* state of MSR HV when SIAR set */
#define MMCRA_SIPR 0x08000000UL /* state of MSR PR when SIAR set */
#define MMCRA_SAMPLE_ENABLE 0x00000001UL /* enable sampling */
+#define POWER6_MMCRA_SIHV 0x0000040000000000ULL
+#define POWER6_MMCRA_SIPR 0x0000020000000000ULL
+#define POWER6_MMCRA_THRM 0x00000020UL
+#define POWER6_MMCRA_OTHER 0x0000000EUL
#define SPRN_PMC1 787
#define SPRN_PMC2 788
#define SPRN_PMC3 789
@@ -495,6 +501,19 @@
#define MMCR0_PMC2_LOADMISSTIME 0x5
#endif
+/*
+ * An mtfsf instruction with the L bit set. On CPUs that support this a
+ * full 64bits of FPSCR is restored and on other CPUs it is ignored.
+ *
+ * Until binutils gets the new form of mtfsf, hardwire the instruction.
+ */
+#ifdef CONFIG_PPC64
+#define MTFSF_L(REG) \
+ .long (0xfc00058e | ((0xff) << 17) | ((REG) << 11) | (1 << 25))
+#else
+#define MTFSF_L(REG) mtfsf 0xff, (REG)
+#endif
+
/* Processor Version Register (PVR) field extraction */
#define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */
@@ -559,20 +578,20 @@
/* 64-bit processors */
/* XXX the prefix should be PVR_, we'll do a global sweep to fix it one day */
-#define PV_NORTHSTAR 0x0033
-#define PV_PULSAR 0x0034
-#define PV_POWER4 0x0035
-#define PV_ICESTAR 0x0036
-#define PV_SSTAR 0x0037
-#define PV_POWER4p 0x0038
+#define PV_NORTHSTAR 0x0033
+#define PV_PULSAR 0x0034
+#define PV_POWER4 0x0035
+#define PV_ICESTAR 0x0036
+#define PV_SSTAR 0x0037
+#define PV_POWER4p 0x0038
#define PV_970 0x0039
-#define PV_POWER5 0x003A
+#define PV_POWER5 0x003A
#define PV_POWER5p 0x003B
#define PV_970FX 0x003C
-#define PV_630 0x0040
-#define PV_630p 0x0041
-#define PV_970MP 0x0044
-#define PV_BE 0x0070
+#define PV_630 0x0040
+#define PV_630p 0x0041
+#define PV_970MP 0x0044
+#define PV_BE 0x0070
/*
* Number of entries in the SLB. If this ever changes we should handle
diff --git a/include/asm-powerpc/rtas.h b/include/asm-powerpc/rtas.h
index f43c683..02e213e 100644
--- a/include/asm-powerpc/rtas.h
+++ b/include/asm-powerpc/rtas.h
@@ -24,6 +24,7 @@
#define RTAS_RMOBUF_MAX (64 * 1024)
/* RTAS return status codes */
+#define RTAS_NOT_SUSPENDABLE -9004
#define RTAS_BUSY -2 /* RTAS Busy */
#define RTAS_EXTENDED_DELAY_MIN 9900
#define RTAS_EXTENDED_DELAY_MAX 9905
@@ -177,12 +178,8 @@ extern unsigned long rtas_get_boot_time(void);
extern void rtas_get_rtc_time(struct rtc_time *rtc_time);
extern int rtas_set_rtc_time(struct rtc_time *rtc_time);
-/* Given an RTAS status code of 9900..9905 compute the hinted delay */
-unsigned int rtas_extended_busy_delay_time(int status);
-static inline int rtas_is_extended_busy(int status)
-{
- return status >= 9900 && status <= 9909;
-}
+extern unsigned int rtas_busy_delay_time(int status);
+extern unsigned int rtas_busy_delay(int status);
extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal);
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h
index 95713f3..9609d3e 100644
--- a/include/asm-powerpc/spu.h
+++ b/include/asm-powerpc/spu.h
@@ -24,8 +24,8 @@
#define _SPU_H
#ifdef __KERNEL__
-#include <linux/kref.h>
#include <linux/workqueue.h>
+#include <linux/sysdev.h>
#define LS_SIZE (256 * 1024)
#define LS_ADDR_MASK (LS_SIZE - 1)
@@ -122,7 +122,6 @@ struct spu {
u64 flags;
u64 dar;
u64 dsisr;
- struct kref kref;
size_t ls_size;
unsigned int slb_replace;
struct mm_struct *mm;
@@ -134,7 +133,6 @@ struct spu {
int class_0_pending;
spinlock_t register_lock;
- u32 stop_code;
void (* wbox_callback)(struct spu *spu);
void (* ibox_callback)(struct spu *spu);
void (* stop_callback)(struct spu *spu);
@@ -143,6 +141,8 @@ struct spu {
char irq_c0[8];
char irq_c1[8];
char irq_c2[8];
+
+ struct sys_device sysdev;
};
struct spu *spu_alloc(void);
@@ -181,29 +181,6 @@ static inline void unregister_spu_syscalls(struct spufs_calls *calls)
#endif /* MODULE */
-/* access to priv1 registers */
-void spu_int_mask_and(struct spu *spu, int class, u64 mask);
-void spu_int_mask_or(struct spu *spu, int class, u64 mask);
-void spu_int_mask_set(struct spu *spu, int class, u64 mask);
-u64 spu_int_mask_get(struct spu *spu, int class);
-void spu_int_stat_clear(struct spu *spu, int class, u64 stat);
-u64 spu_int_stat_get(struct spu *spu, int class);
-void spu_int_route_set(struct spu *spu, u64 route);
-u64 spu_mfc_dar_get(struct spu *spu);
-u64 spu_mfc_dsisr_get(struct spu *spu);
-void spu_mfc_dsisr_set(struct spu *spu, u64 dsisr);
-void spu_mfc_sdr_set(struct spu *spu, u64 sdr);
-void spu_mfc_sr1_set(struct spu *spu, u64 sr1);
-u64 spu_mfc_sr1_get(struct spu *spu);
-void spu_mfc_tclass_id_set(struct spu *spu, u64 tclass_id);
-u64 spu_mfc_tclass_id_get(struct spu *spu);
-void spu_tlb_invalidate(struct spu *spu);
-void spu_resource_allocation_groupID_set(struct spu *spu, u64 id);
-u64 spu_resource_allocation_groupID_get(struct spu *spu);
-void spu_resource_allocation_enable_set(struct spu *spu, u64 enable);
-u64 spu_resource_allocation_enable_get(struct spu *spu);
-
-
/*
* This defines the Local Store, Problem Area and Privlege Area of an SPU.
*/
diff --git a/include/asm-powerpc/spu_csa.h b/include/asm-powerpc/spu_csa.h
index ba18d7d..964c2d3 100644
--- a/include/asm-powerpc/spu_csa.h
+++ b/include/asm-powerpc/spu_csa.h
@@ -86,10 +86,18 @@ struct spu_lscsa {
struct spu_reg128 event_mask;
struct spu_reg128 srr0;
struct spu_reg128 stopped_status;
- struct spu_reg128 pad[119]; /* 'ls' must be page-aligned. */
- unsigned char ls[LS_SIZE];
+
+ /*
+ * 'ls' must be page-aligned on all configurations.
+ * Since we don't want to rely on having the spu-gcc
+ * installed to build the kernel and this structure
+ * is used in the SPU-side code, make it 64k-page
+ * aligned for now.
+ */
+ unsigned char ls[LS_SIZE] __attribute__((aligned(65536)));
};
+#ifndef __SPU__
/*
* struct spu_problem_collapsed - condensed problem state area, w/o pads.
*/
@@ -250,6 +258,7 @@ extern int spu_restore(struct spu_state *new, struct spu *spu);
extern int spu_switch(struct spu_state *prev, struct spu_state *new,
struct spu *spu);
+#endif /* !__SPU__ */
#endif /* __KERNEL__ */
#endif /* !__ASSEMBLY__ */
#endif /* _SPU_CSA_H_ */
diff --git a/include/asm-powerpc/spu_priv1.h b/include/asm-powerpc/spu_priv1.h
new file mode 100644
index 0000000..300c458
--- /dev/null
+++ b/include/asm-powerpc/spu_priv1.h
@@ -0,0 +1,182 @@
+/*
+ * Defines an spu hypervisor abstraction layer.
+ *
+ * Copyright 2006 Sony Corp.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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
+ */
+
+#if !defined(_SPU_PRIV1_H)
+#define _SPU_PRIV1_H
+#if defined(__KERNEL__)
+
+struct spu;
+
+/* access to priv1 registers */
+
+struct spu_priv1_ops
+{
+ void (*int_mask_and) (struct spu *spu, int class, u64 mask);
+ void (*int_mask_or) (struct spu *spu, int class, u64 mask);
+ void (*int_mask_set) (struct spu *spu, int class, u64 mask);
+ u64 (*int_mask_get) (struct spu *spu, int class);
+ void (*int_stat_clear) (struct spu *spu, int class, u64 stat);
+ u64 (*int_stat_get) (struct spu *spu, int class);
+ void (*cpu_affinity_set) (struct spu *spu, int cpu);
+ u64 (*mfc_dar_get) (struct spu *spu);
+ u64 (*mfc_dsisr_get) (struct spu *spu);
+ void (*mfc_dsisr_set) (struct spu *spu, u64 dsisr);
+ void (*mfc_sdr_set) (struct spu *spu, u64 sdr);
+ void (*mfc_sr1_set) (struct spu *spu, u64 sr1);
+ u64 (*mfc_sr1_get) (struct spu *spu);
+ void (*mfc_tclass_id_set) (struct spu *spu, u64 tclass_id);
+ u64 (*mfc_tclass_id_get) (struct spu *spu);
+ void (*tlb_invalidate) (struct spu *spu);
+ void (*resource_allocation_groupID_set) (struct spu *spu, u64 id);
+ u64 (*resource_allocation_groupID_get) (struct spu *spu);
+ void (*resource_allocation_enable_set) (struct spu *spu, u64 enable);
+ u64 (*resource_allocation_enable_get) (struct spu *spu);
+};
+
+extern const struct spu_priv1_ops* spu_priv1_ops;
+
+static inline void
+spu_int_mask_and (struct spu *spu, int class, u64 mask)
+{
+ spu_priv1_ops->int_mask_and(spu, class, mask);
+}
+
+static inline void
+spu_int_mask_or (struct spu *spu, int class, u64 mask)
+{
+ spu_priv1_ops->int_mask_or(spu, class, mask);
+}
+
+static inline void
+spu_int_mask_set (struct spu *spu, int class, u64 mask)
+{
+ spu_priv1_ops->int_mask_set(spu, class, mask);
+}
+
+static inline u64
+spu_int_mask_get (struct spu *spu, int class)
+{
+ return spu_priv1_ops->int_mask_get(spu, class);
+}
+
+static inline void
+spu_int_stat_clear (struct spu *spu, int class, u64 stat)
+{
+ spu_priv1_ops->int_stat_clear(spu, class, stat);
+}
+
+static inline u64
+spu_int_stat_get (struct spu *spu, int class)
+{
+ return spu_priv1_ops->int_stat_get (spu, class);
+}
+
+static inline void
+spu_cpu_affinity_set (struct spu *spu, int cpu)
+{
+ spu_priv1_ops->cpu_affinity_set(spu, cpu);
+}
+
+static inline u64
+spu_mfc_dar_get (struct spu *spu)
+{
+ return spu_priv1_ops->mfc_dar_get(spu);
+}
+
+static inline u64
+spu_mfc_dsisr_get (struct spu *spu)
+{
+ return spu_priv1_ops->mfc_dsisr_get(spu);
+}
+
+static inline void
+spu_mfc_dsisr_set (struct spu *spu, u64 dsisr)
+{
+ spu_priv1_ops->mfc_dsisr_set(spu, dsisr);
+}
+
+static inline void
+spu_mfc_sdr_set (struct spu *spu, u64 sdr)
+{
+ spu_priv1_ops->mfc_sdr_set(spu, sdr);
+}
+
+static inline void
+spu_mfc_sr1_set (struct spu *spu, u64 sr1)
+{
+ spu_priv1_ops->mfc_sr1_set(spu, sr1);
+}
+
+static inline u64
+spu_mfc_sr1_get (struct spu *spu)
+{
+ return spu_priv1_ops->mfc_sr1_get(spu);
+}
+
+static inline void
+spu_mfc_tclass_id_set (struct spu *spu, u64 tclass_id)
+{
+ spu_priv1_ops->mfc_tclass_id_set(spu, tclass_id);
+}
+
+static inline u64
+spu_mfc_tclass_id_get (struct spu *spu)
+{
+ return spu_priv1_ops->mfc_tclass_id_get(spu);
+}
+
+static inline void
+spu_tlb_invalidate (struct spu *spu)
+{
+ spu_priv1_ops->tlb_invalidate(spu);
+}
+
+static inline void
+spu_resource_allocation_groupID_set (struct spu *spu, u64 id)
+{
+ spu_priv1_ops->resource_allocation_groupID_set(spu, id);
+}
+
+static inline u64
+spu_resource_allocation_groupID_get (struct spu *spu)
+{
+ return spu_priv1_ops->resource_allocation_groupID_get(spu);
+}
+
+static inline void
+spu_resource_allocation_enable_set (struct spu *spu, u64 enable)
+{
+ spu_priv1_ops->resource_allocation_enable_set(spu, enable);
+}
+
+static inline u64
+spu_resource_allocation_enable_get (struct spu *spu)
+{
+ return spu_priv1_ops->resource_allocation_enable_get(spu);
+}
+
+/* The declarations folowing are put here for convenience
+ * and only intended to be used by the platform setup code
+ * for initializing spu_priv1_ops.
+ */
+
+extern const struct spu_priv1_ops spu_priv1_mmio_ops;
+
+#endif /* __KERNEL__ */
+#endif
diff --git a/include/asm-powerpc/systbl.h b/include/asm-powerpc/systbl.h
new file mode 100644
index 0000000..eac85ce
--- /dev/null
+++ b/include/asm-powerpc/systbl.h
@@ -0,0 +1,306 @@
+/*
+ * List of powerpc syscalls. For the meaning of the _SPU suffix see
+ * arch/powerpc/platforms/cell/spu_callbacks.c
+ */
+
+SYSCALL(restart_syscall)
+SYSCALL(exit)
+PPC_SYS(fork)
+SYSCALL_SPU(read)
+SYSCALL_SPU(write)
+COMPAT_SYS_SPU(open)
+SYSCALL_SPU(close)
+COMPAT_SYS_SPU(waitpid)
+COMPAT_SYS_SPU(creat)
+SYSCALL_SPU(link)
+SYSCALL_SPU(unlink)
+COMPAT_SYS(execve)
+SYSCALL_SPU(chdir)
+COMPAT_SYS_SPU(time)
+SYSCALL_SPU(mknod)
+SYSCALL_SPU(chmod)
+SYSCALL_SPU(lchown)
+SYSCALL(ni_syscall)
+OLDSYS(stat)
+SYSX_SPU(sys_lseek,ppc32_lseek,sys_lseek)
+SYSCALL_SPU(getpid)
+COMPAT_SYS(mount)
+SYSX(sys_ni_syscall,sys_oldumount,sys_oldumount)
+SYSCALL_SPU(setuid)
+SYSCALL_SPU(getuid)
+COMPAT_SYS_SPU(stime)
+COMPAT_SYS(ptrace)
+SYSCALL_SPU(alarm)
+OLDSYS(fstat)
+COMPAT_SYS(pause)
+COMPAT_SYS(utime)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+COMPAT_SYS_SPU(access)
+COMPAT_SYS_SPU(nice)
+SYSCALL(ni_syscall)
+SYSCALL_SPU(sync)
+COMPAT_SYS_SPU(kill)
+SYSCALL_SPU(rename)
+COMPAT_SYS_SPU(mkdir)
+SYSCALL_SPU(rmdir)
+SYSCALL_SPU(dup)
+SYSCALL_SPU(pipe)
+COMPAT_SYS_SPU(times)
+SYSCALL(ni_syscall)
+SYSCALL_SPU(brk)
+SYSCALL_SPU(setgid)
+SYSCALL_SPU(getgid)
+SYSCALL(signal)
+SYSCALL_SPU(geteuid)
+SYSCALL_SPU(getegid)
+SYSCALL(acct)
+SYSCALL(umount)
+SYSCALL(ni_syscall)
+COMPAT_SYS_SPU(ioctl)
+COMPAT_SYS_SPU(fcntl)
+SYSCALL(ni_syscall)
+COMPAT_SYS_SPU(setpgid)
+SYSCALL(ni_syscall)
+SYSX(sys_ni_syscall,sys_olduname, sys_olduname)
+COMPAT_SYS_SPU(umask)
+SYSCALL_SPU(chroot)
+SYSCALL(ustat)
+SYSCALL_SPU(dup2)
+SYSCALL_SPU(getppid)
+SYSCALL_SPU(getpgrp)
+SYSCALL_SPU(setsid)
+SYS32ONLY(sigaction)
+SYSCALL_SPU(sgetmask)
+COMPAT_SYS_SPU(ssetmask)
+SYSCALL_SPU(setreuid)
+SYSCALL_SPU(setregid)
+SYS32ONLY(sigsuspend)
+COMPAT_SYS(sigpending)
+COMPAT_SYS_SPU(sethostname)
+COMPAT_SYS_SPU(setrlimit)
+COMPAT_SYS(old_getrlimit)
+COMPAT_SYS_SPU(getrusage)
+COMPAT_SYS_SPU(gettimeofday)
+COMPAT_SYS_SPU(settimeofday)
+COMPAT_SYS_SPU(getgroups)
+COMPAT_SYS_SPU(setgroups)
+SYSX(sys_ni_syscall,sys_ni_syscall,ppc_select)
+SYSCALL_SPU(symlink)
+OLDSYS(lstat)
+COMPAT_SYS_SPU(readlink)
+SYSCALL(uselib)
+SYSCALL(swapon)
+SYSCALL(reboot)
+SYSX(sys_ni_syscall,old32_readdir,old_readdir)
+SYSCALL_SPU(mmap)
+SYSCALL_SPU(munmap)
+SYSCALL_SPU(truncate)
+SYSCALL_SPU(ftruncate)
+SYSCALL_SPU(fchmod)
+SYSCALL_SPU(fchown)
+COMPAT_SYS_SPU(getpriority)
+COMPAT_SYS_SPU(setpriority)
+SYSCALL(ni_syscall)
+COMPAT_SYS(statfs)
+COMPAT_SYS(fstatfs)
+SYSCALL(ni_syscall)
+COMPAT_SYS_SPU(socketcall)
+COMPAT_SYS_SPU(syslog)
+COMPAT_SYS_SPU(setitimer)
+COMPAT_SYS_SPU(getitimer)
+COMPAT_SYS_SPU(newstat)
+COMPAT_SYS_SPU(newlstat)
+COMPAT_SYS_SPU(newfstat)
+SYSX(sys_ni_syscall,sys_uname,sys_uname)
+SYSCALL(ni_syscall)
+SYSCALL_SPU(vhangup)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+COMPAT_SYS_SPU(wait4)
+SYSCALL(swapoff)
+COMPAT_SYS_SPU(sysinfo)
+COMPAT_SYS(ipc)
+SYSCALL_SPU(fsync)
+SYS32ONLY(sigreturn)
+PPC_SYS(clone)
+COMPAT_SYS_SPU(setdomainname)
+PPC_SYS_SPU(newuname)
+SYSCALL(ni_syscall)
+COMPAT_SYS_SPU(adjtimex)
+SYSCALL_SPU(mprotect)
+SYSX(sys_ni_syscall,compat_sys_sigprocmask,sys_sigprocmask)
+SYSCALL(ni_syscall)
+SYSCALL(init_module)
+SYSCALL(delete_module)
+SYSCALL(ni_syscall)
+SYSCALL(quotactl)
+COMPAT_SYS_SPU(getpgid)
+SYSCALL_SPU(fchdir)
+SYSCALL_SPU(bdflush)
+COMPAT_SYS(sysfs)
+SYSX_SPU(ppc64_personality,ppc64_personality,sys_personality)
+SYSCALL(ni_syscall)
+SYSCALL_SPU(setfsuid)
+SYSCALL_SPU(setfsgid)
+SYSCALL_SPU(llseek)
+COMPAT_SYS_SPU(getdents)
+SYSX_SPU(sys_select,ppc32_select,ppc_select)
+SYSCALL_SPU(flock)
+SYSCALL_SPU(msync)
+COMPAT_SYS_SPU(readv)
+COMPAT_SYS_SPU(writev)
+COMPAT_SYS_SPU(getsid)
+SYSCALL_SPU(fdatasync)
+COMPAT_SYS(sysctl)
+SYSCALL_SPU(mlock)
+SYSCALL_SPU(munlock)
+SYSCALL_SPU(mlockall)
+SYSCALL_SPU(munlockall)
+COMPAT_SYS_SPU(sched_setparam)
+COMPAT_SYS_SPU(sched_getparam)
+COMPAT_SYS_SPU(sched_setscheduler)
+COMPAT_SYS_SPU(sched_getscheduler)
+SYSCALL_SPU(sched_yield)
+COMPAT_SYS_SPU(sched_get_priority_max)
+COMPAT_SYS_SPU(sched_get_priority_min)
+COMPAT_SYS_SPU(sched_rr_get_interval)
+COMPAT_SYS_SPU(nanosleep)
+SYSCALL_SPU(mremap)
+SYSCALL_SPU(setresuid)
+SYSCALL_SPU(getresuid)
+SYSCALL(ni_syscall)
+SYSCALL_SPU(poll)
+COMPAT_SYS(nfsservctl)
+SYSCALL_SPU(setresgid)
+SYSCALL_SPU(getresgid)
+COMPAT_SYS_SPU(prctl)
+COMPAT_SYS(rt_sigreturn)
+COMPAT_SYS(rt_sigaction)
+COMPAT_SYS(rt_sigprocmask)
+COMPAT_SYS(rt_sigpending)
+COMPAT_SYS(rt_sigtimedwait)
+COMPAT_SYS(rt_sigqueueinfo)
+COMPAT_SYS(rt_sigsuspend)
+COMPAT_SYS_SPU(pread64)
+COMPAT_SYS_SPU(pwrite64)
+SYSCALL_SPU(chown)
+SYSCALL_SPU(getcwd)
+SYSCALL_SPU(capget)
+SYSCALL_SPU(capset)
+COMPAT_SYS(sigaltstack)
+SYSX_SPU(sys_sendfile64,compat_sys_sendfile,sys_sendfile)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+PPC_SYS(vfork)
+COMPAT_SYS_SPU(getrlimit)
+COMPAT_SYS_SPU(readahead)
+SYS32ONLY(mmap2)
+SYS32ONLY(truncate64)
+SYS32ONLY(ftruncate64)
+SYSX(sys_ni_syscall,sys_stat64,sys_stat64)
+SYSX(sys_ni_syscall,sys_lstat64,sys_lstat64)
+SYSX(sys_ni_syscall,sys_fstat64,sys_fstat64)
+SYSCALL(pciconfig_read)
+SYSCALL(pciconfig_write)
+SYSCALL(pciconfig_iobase)
+SYSCALL(ni_syscall)
+SYSCALL_SPU(getdents64)
+SYSCALL_SPU(pivot_root)
+SYSX(sys_ni_syscall,compat_sys_fcntl64,sys_fcntl64)
+SYSCALL_SPU(madvise)
+SYSCALL_SPU(mincore)
+SYSCALL_SPU(gettid)
+SYSCALL_SPU(tkill)
+SYSCALL_SPU(setxattr)
+SYSCALL_SPU(lsetxattr)
+SYSCALL_SPU(fsetxattr)
+SYSCALL_SPU(getxattr)
+SYSCALL_SPU(lgetxattr)
+SYSCALL_SPU(fgetxattr)
+SYSCALL_SPU(listxattr)
+SYSCALL_SPU(llistxattr)
+SYSCALL_SPU(flistxattr)
+SYSCALL_SPU(removexattr)
+SYSCALL_SPU(lremovexattr)
+SYSCALL_SPU(fremovexattr)
+COMPAT_SYS_SPU(futex)
+COMPAT_SYS_SPU(sched_setaffinity)
+COMPAT_SYS_SPU(sched_getaffinity)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYS32ONLY(sendfile64)
+COMPAT_SYS_SPU(io_setup)
+SYSCALL_SPU(io_destroy)
+COMPAT_SYS_SPU(io_getevents)
+COMPAT_SYS_SPU(io_submit)
+SYSCALL_SPU(io_cancel)
+SYSCALL(set_tid_address)
+SYSX_SPU(sys_fadvise64,ppc32_fadvise64,sys_fadvise64)
+SYSCALL(exit_group)
+SYSX(sys_lookup_dcookie,ppc32_lookup_dcookie,sys_lookup_dcookie)
+SYSCALL_SPU(epoll_create)
+SYSCALL_SPU(epoll_ctl)
+SYSCALL_SPU(epoll_wait)
+SYSCALL_SPU(remap_file_pages)
+SYSX_SPU(sys_timer_create,compat_sys_timer_create,sys_timer_create)
+COMPAT_SYS_SPU(timer_settime)
+COMPAT_SYS_SPU(timer_gettime)
+SYSCALL_SPU(timer_getoverrun)
+SYSCALL_SPU(timer_delete)
+COMPAT_SYS_SPU(clock_settime)
+COMPAT_SYS_SPU(clock_gettime)
+COMPAT_SYS_SPU(clock_getres)
+COMPAT_SYS_SPU(clock_nanosleep)
+SYSX(ppc64_swapcontext,ppc32_swapcontext,ppc_swapcontext)
+COMPAT_SYS_SPU(tgkill)
+COMPAT_SYS_SPU(utimes)
+COMPAT_SYS_SPU(statfs64)
+COMPAT_SYS_SPU(fstatfs64)
+SYSX(sys_ni_syscall, ppc_fadvise64_64, ppc_fadvise64_64)
+PPC_SYS_SPU(rtas)
+OLDSYS(debug_setcontext)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+COMPAT_SYS(mbind)
+COMPAT_SYS(get_mempolicy)
+COMPAT_SYS(set_mempolicy)
+COMPAT_SYS(mq_open)
+SYSCALL(mq_unlink)
+COMPAT_SYS(mq_timedsend)
+COMPAT_SYS(mq_timedreceive)
+COMPAT_SYS(mq_notify)
+COMPAT_SYS(mq_getsetattr)
+COMPAT_SYS(kexec_load)
+COMPAT_SYS(add_key)
+COMPAT_SYS(request_key)
+COMPAT_SYS(keyctl)
+COMPAT_SYS(waitid)
+COMPAT_SYS(ioprio_set)
+COMPAT_SYS(ioprio_get)
+SYSCALL(inotify_init)
+SYSCALL(inotify_add_watch)
+SYSCALL(inotify_rm_watch)
+SYSCALL(spu_run)
+SYSCALL(spu_create)
+COMPAT_SYS(pselect6)
+COMPAT_SYS(ppoll)
+SYSCALL_SPU(unshare)
+SYSCALL_SPU(splice)
+SYSCALL_SPU(tee)
+SYSCALL_SPU(vmsplice)
+COMPAT_SYS_SPU(openat)
+SYSCALL_SPU(mkdirat)
+SYSCALL_SPU(mknodat)
+SYSCALL_SPU(fchownat)
+COMPAT_SYS_SPU(futimesat)
+SYSX_SPU(sys_newfstatat, sys_fstatat64, sys_fstatat64)
+SYSCALL_SPU(unlinkat)
+SYSCALL_SPU(renameat)
+SYSCALL_SPU(linkat)
+SYSCALL_SPU(symlinkat)
+SYSCALL_SPU(readlinkat)
+SYSCALL_SPU(fchmodat)
+SYSCALL_SPU(faccessat)
+COMPAT_SYS_SPU(get_robust_list)
+COMPAT_SYS_SPU(set_robust_list)
diff --git a/include/asm-powerpc/tce.h b/include/asm-powerpc/tce.h
index 6fa200a..c9483ad 100644
--- a/include/asm-powerpc/tce.h
+++ b/include/asm-powerpc/tce.h
@@ -35,32 +35,15 @@
#define TCE_PAGE_SIZE (1 << TCE_SHIFT)
#define TCE_PAGE_FACTOR (PAGE_SHIFT - TCE_SHIFT)
-
-/* tce_entry
- * Used by pSeries (SMP) and iSeries/pSeries LPAR, but there it's
- * abstracted so layout is irrelevant.
- */
-union tce_entry {
- unsigned long te_word;
- struct {
- unsigned int tb_cacheBits :6; /* Cache hash bits - not used */
- unsigned int tb_rsvd :6;
- unsigned long tb_rpn :40; /* Real page number */
- unsigned int tb_valid :1; /* Tce is valid (vb only) */
- unsigned int tb_allio :1; /* Tce is valid for all lps (vb only) */
- unsigned int tb_lpindex :8; /* LpIndex for user of TCE (vb only) */
- unsigned int tb_pciwr :1; /* Write allowed (pci only) */
- unsigned int tb_rdwr :1; /* Read allowed (pci), Write allowed (vb) */
- } te_bits;
-#define te_cacheBits te_bits.tb_cacheBits
-#define te_rpn te_bits.tb_rpn
-#define te_valid te_bits.tb_valid
-#define te_allio te_bits.tb_allio
-#define te_lpindex te_bits.tb_lpindex
-#define te_pciwr te_bits.tb_pciwr
-#define te_rdwr te_bits.tb_rdwr
-};
-
+#define TCE_ENTRY_SIZE 8 /* each TCE is 64 bits */
+
+#define TCE_RPN_MASK 0xfffffffffful /* 40-bit RPN (4K pages) */
+#define TCE_RPN_SHIFT 12
+#define TCE_VALID 0x800 /* TCE valid */
+#define TCE_ALLIO 0x400 /* TCE valid for all lpars */
+#define TCE_PCI_WRITE 0x2 /* write from PCI allowed */
+#define TCE_PCI_READ 0x1 /* read from PCI allowed */
+#define TCE_VB_WRITE 0x1 /* write from VB allowed */
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_TCE_H */
diff --git a/include/asm-powerpc/topology.h b/include/asm-powerpc/topology.h
index 19c575f..92f3e55 100644
--- a/include/asm-powerpc/topology.h
+++ b/include/asm-powerpc/topology.h
@@ -31,8 +31,13 @@ static inline int node_to_first_cpu(int node)
int of_node_to_nid(struct device_node *device);
-#define pcibus_to_node(node) (-1)
-#define pcibus_to_cpumask(bus) (cpu_online_map)
+struct pci_bus;
+extern int pcibus_to_node(struct pci_bus *bus);
+
+#define pcibus_to_cpumask(bus) (pcibus_to_node(bus) == -1 ? \
+ CPU_MASK_ALL : \
+ node_to_cpumask(pcibus_to_node(bus)) \
+ )
/* sched_domains SD_NODE_INIT for PPC64 machines */
#define SD_NODE_INIT (struct sched_domain) { \
diff --git a/include/asm-powerpc/udbg.h b/include/asm-powerpc/udbg.h
index 5c4236c3..19a1517 100644
--- a/include/asm-powerpc/udbg.h
+++ b/include/asm-powerpc/udbg.h
@@ -23,7 +23,8 @@ extern int udbg_write(const char *s, int n);
extern int udbg_read(char *buf, int buflen);
extern void register_early_udbg_console(void);
-extern void udbg_printf(const char *fmt, ...);
+extern void udbg_printf(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
extern void udbg_progress(char *s, unsigned short hex);
extern void udbg_init_uart(void __iomem *comport, unsigned int speed,
diff --git a/include/asm-powerpc/vga.h b/include/asm-powerpc/vga.h
index eadaf2f..a2eac40 100644
--- a/include/asm-powerpc/vga.h
+++ b/include/asm-powerpc/vga.h
@@ -41,9 +41,9 @@ static inline u16 scr_readw(volatile const u16 *addr)
extern unsigned long vgacon_remap_base;
#ifdef __powerpc64__
-#define VGA_MAP_MEM(x) ((unsigned long) ioremap((x), 0))
+#define VGA_MAP_MEM(x,s) ((unsigned long) ioremap((x), s))
#else
-#define VGA_MAP_MEM(x) (x + vgacon_remap_base)
+#define VGA_MAP_MEM(x,s) (x + vgacon_remap_base)
#endif
#define vga_readb(x) (*(x))
diff --git a/include/asm-powerpc/vio.h b/include/asm-powerpc/vio.h
index be14c59..dc9bd101 100644
--- a/include/asm-powerpc/vio.h
+++ b/include/asm-powerpc/vio.h
@@ -63,32 +63,22 @@ struct vio_driver {
struct device_driver driver;
};
-struct vio_bus_ops {
- int (*match)(const struct vio_device_id *id, const struct vio_dev *dev);
- void (*unregister_device)(struct vio_dev *);
- void (*release_device)(struct device *);
-};
-
extern struct dma_mapping_ops vio_dma_ops;
extern struct bus_type vio_bus_type;
-extern struct vio_dev vio_bus_device;
extern int vio_register_driver(struct vio_driver *drv);
extern void vio_unregister_driver(struct vio_driver *drv);
-extern struct vio_dev * __devinit vio_register_device(struct vio_dev *viodev);
extern void __devinit vio_unregister_device(struct vio_dev *dev);
-extern int vio_bus_init(struct vio_bus_ops *);
-
-#ifdef CONFIG_PPC_PSERIES
struct device_node;
extern struct vio_dev * __devinit vio_register_device_node(
struct device_node *node_vdev);
-extern struct vio_dev *vio_find_node(struct device_node *vnode);
-extern const void *vio_get_attribute(struct vio_dev *vdev, void *which,
+extern const void *vio_get_attribute(struct vio_dev *vdev, char *which,
int *length);
+#ifdef CONFIG_PPC_PSERIES
+extern struct vio_dev *vio_find_node(struct device_node *vnode);
extern int vio_enable_interrupts(struct vio_dev *dev);
extern int vio_disable_interrupts(struct vio_dev *dev);
#endif
diff --git a/include/asm-ppc/floppy.h b/include/asm-ppc/floppy.h
index 8ccd4a2..2ba191e 100644
--- a/include/asm-ppc/floppy.h
+++ b/include/asm-ppc/floppy.h
@@ -99,10 +99,8 @@ static int fd_request_irq(void)
return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
"floppy", NULL);
else
- return request_irq(FLOPPY_IRQ, floppy_interrupt,
- SA_INTERRUPT|SA_SAMPLE_RANDOM,
- "floppy", NULL);
-
+ return request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT,
+ "floppy", NULL);
}
static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io)
diff --git a/include/asm-ppc/mmu.h b/include/asm-ppc/mmu.h
index 0a70b05..14584e5 100644
--- a/include/asm-ppc/mmu.h
+++ b/include/asm-ppc/mmu.h
@@ -23,25 +23,18 @@ extern phys_addr_t fixup_bigphys_addr(phys_addr_t, phys_addr_t);
#define PHYS_FMT "%16Lx"
#endif
-/* Default "unsigned long" context */
-typedef unsigned long mm_context_t;
+typedef struct {
+ unsigned long id;
+ unsigned long vdso_base;
+} mm_context_t;
/* Hardware Page Table Entry */
typedef struct _PTE {
-#ifdef CONFIG_PPC64BRIDGE
- unsigned long long vsid:52;
- unsigned long api:5;
- unsigned long :5;
- unsigned long h:1;
- unsigned long v:1;
- unsigned long long rpn:52;
-#else /* CONFIG_PPC64BRIDGE */
unsigned long v:1; /* Entry is valid */
unsigned long vsid:24; /* Virtual segment identifier */
unsigned long h:1; /* Hash algorithm indicator */
unsigned long api:6; /* Abbreviated page index */
unsigned long rpn:20; /* Real (physical) page number */
-#endif /* CONFIG_PPC64BRIDGE */
unsigned long :3; /* Unused */
unsigned long r:1; /* Referenced */
unsigned long c:1; /* Changed */
@@ -82,11 +75,7 @@ typedef struct _P601_BATU { /* Upper part of BAT for 601 processor */
} P601_BATU;
typedef struct _BATU { /* Upper part of BAT (all except 601) */
-#ifdef CONFIG_PPC64BRIDGE
- unsigned long long bepi:47;
-#else /* CONFIG_PPC64BRIDGE */
unsigned long bepi:15; /* Effective page index (virtual address) */
-#endif /* CONFIG_PPC64BRIDGE */
unsigned long :4; /* Unused */
unsigned long bl:11; /* Block size mask */
unsigned long vs:1; /* Supervisor valid */
@@ -101,11 +90,7 @@ typedef struct _P601_BATL { /* Lower part of BAT for 601 processor */
} P601_BATL;
typedef struct _BATL { /* Lower part of BAT (all except 601) */
-#ifdef CONFIG_PPC64BRIDGE
- unsigned long long brpn:47;
-#else /* CONFIG_PPC64BRIDGE */
unsigned long brpn:15; /* Real page index (physical address) */
-#endif /* CONFIG_PPC64BRIDGE */
unsigned long :10; /* Unused */
unsigned long w:1; /* Write-thru cache */
unsigned long i:1; /* Cache inhibit */
diff --git a/include/asm-ppc/mmu_context.h b/include/asm-ppc/mmu_context.h
index 94f2bf7..2bc8589 100644
--- a/include/asm-ppc/mmu_context.h
+++ b/include/asm-ppc/mmu_context.h
@@ -70,7 +70,7 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
#else
/* PPC 6xx, 7xx CPUs */
-#define NO_CONTEXT ((mm_context_t) -1)
+#define NO_CONTEXT ((unsigned long) -1)
#define LAST_CONTEXT 32767
#define FIRST_CONTEXT 1
#endif
@@ -85,7 +85,7 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
* can be used for debugging on all processors (if you happen to have
* an Abatron).
*/
-extern void set_context(mm_context_t context, pgd_t *pgd);
+extern void set_context(unsigned long contextid, pgd_t *pgd);
/*
* Bitmap of contexts in use.
@@ -98,7 +98,7 @@ extern unsigned long context_map[];
* Its use is an optimization only, we can't rely on this context
* number to be free, but it usually will be.
*/
-extern mm_context_t next_mmu_context;
+extern unsigned long next_mmu_context;
/*
* If we don't have sufficient contexts to give one to every task
@@ -117,9 +117,9 @@ extern void steal_context(void);
*/
static inline void get_mmu_context(struct mm_struct *mm)
{
- mm_context_t ctx;
+ unsigned long ctx;
- if (mm->context != NO_CONTEXT)
+ if (mm->context.id != NO_CONTEXT)
return;
#ifdef FEW_CONTEXTS
while (atomic_dec_if_positive(&nr_free_contexts) < 0)
@@ -132,7 +132,7 @@ static inline void get_mmu_context(struct mm_struct *mm)
ctx = 0;
}
next_mmu_context = (ctx + 1) & LAST_CONTEXT;
- mm->context = ctx;
+ mm->context.id = ctx;
#ifdef FEW_CONTEXTS
context_mm[ctx] = mm;
#endif
@@ -141,7 +141,12 @@ static inline void get_mmu_context(struct mm_struct *mm)
/*
* Set up the context for a new address space.
*/
-#define init_new_context(tsk,mm) (((mm)->context = NO_CONTEXT), 0)
+static inline int init_new_context(struct task_struct *t, struct mm_struct *mm)
+{
+ mm->context.id = NO_CONTEXT;
+ mm->context.vdso_base = 0;
+ return 0;
+}
/*
* We're finished using the context for an address space.
@@ -149,9 +154,9 @@ static inline void get_mmu_context(struct mm_struct *mm)
static inline void destroy_context(struct mm_struct *mm)
{
preempt_disable();
- if (mm->context != NO_CONTEXT) {
- clear_bit(mm->context, context_map);
- mm->context = NO_CONTEXT;
+ if (mm->context.id != NO_CONTEXT) {
+ clear_bit(mm->context.id, context_map);
+ mm->context.id = NO_CONTEXT;
#ifdef FEW_CONTEXTS
atomic_inc(&nr_free_contexts);
#endif
@@ -179,7 +184,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
/* Setup new userspace context */
get_mmu_context(next);
- set_context(next->context, next->pgd);
+ set_context(next->context.id, next->pgd);
}
#define deactivate_mm(tsk,mm) do { } while (0)
diff --git a/include/asm-ppc/mpc85xx.h b/include/asm-ppc/mpc85xx.h
index c25bdd9..9b48511 100644
--- a/include/asm-ppc/mpc85xx.h
+++ b/include/asm-ppc/mpc85xx.h
@@ -27,6 +27,9 @@
#if defined(CONFIG_MPC8555_CDS) || defined(CONFIG_MPC8548_CDS)
#include <platforms/85xx/mpc8555_cds.h>
#endif
+#ifdef CONFIG_MPC85xx_CDS
+#include <platforms/85xx/mpc85xx_cds.h>
+#endif
#ifdef CONFIG_MPC8560_ADS
#include <platforms/85xx/mpc8560_ads.h>
#endif
diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h
index 9cb8367..51fa7c6 100644
--- a/include/asm-ppc/pgtable.h
+++ b/include/asm-ppc/pgtable.h
@@ -662,7 +662,7 @@ static inline int __ptep_test_and_clear_young(unsigned int context, unsigned lon
return (old & _PAGE_ACCESSED) != 0;
}
#define ptep_test_and_clear_young(__vma, __addr, __ptep) \
- __ptep_test_and_clear_young((__vma)->vm_mm->context, __addr, __ptep)
+ __ptep_test_and_clear_young((__vma)->vm_mm->context.id, __addr, __ptep)
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma,
diff --git a/include/asm-s390/irq.h b/include/asm-s390/irq.h
index 916a1aa..bd1a721 100644
--- a/include/asm-s390/irq.h
+++ b/include/asm-s390/irq.h
@@ -21,10 +21,6 @@ enum interruption_class {
#define touch_nmi_watchdog() do { } while(0)
-struct irqaction;
-struct pt_regs;
-int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
-
#endif /* __KERNEL__ */
#endif
diff --git a/include/asm-s390/percpu.h b/include/asm-s390/percpu.h
index 436d216..d9a8cca 100644
--- a/include/asm-s390/percpu.h
+++ b/include/asm-s390/percpu.h
@@ -40,6 +40,7 @@ extern unsigned long __per_cpu_offset[NR_CPUS];
__typeof__(type) per_cpu__##name
#define __get_cpu_var(var) __reloc_hide(var,S390_lowcore.percpu_offset)
+#define __raw_get_cpu_var(var) __reloc_hide(var,S390_lowcore.percpu_offset)
#define per_cpu(var,cpu) __reloc_hide(var,__per_cpu_offset[cpu])
/* A macro to avoid #include hell... */
@@ -57,6 +58,7 @@ do { \
__typeof__(type) per_cpu__##name
#define __get_cpu_var(var) __reloc_hide(var,0)
+#define __raw_get_cpu_var(var) __reloc_hide(var,0)
#define per_cpu(var,cpu) __reloc_hide(var,0)
#endif /* SMP */
diff --git a/include/asm-sh/floppy.h b/include/asm-sh/floppy.h
index 38d7a29..307d9ce 100644
--- a/include/asm-sh/floppy.h
+++ b/include/asm-sh/floppy.h
@@ -147,11 +147,10 @@ static int fd_request_irq(void)
{
if(can_use_virtual_dma)
return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
- "floppy", NULL);
+ "floppy", NULL);
else
- return request_irq(FLOPPY_IRQ, floppy_interrupt,
- SA_INTERRUPT|SA_SAMPLE_RANDOM,
- "floppy", NULL);
+ return request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT,
+ "floppy", NULL);
}
diff --git a/include/asm-sparc/ebus.h b/include/asm-sparc/ebus.h
index 2d6a997..5465288 100644
--- a/include/asm-sparc/ebus.h
+++ b/include/asm-sparc/ebus.h
@@ -13,13 +13,14 @@
#include <linux/ioport.h>
#endif
#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
struct linux_ebus_child {
struct linux_ebus_child *next;
struct linux_ebus_device *parent;
struct linux_ebus *bus;
- int prom_node;
- char prom_name[64];
+ struct device_node *prom_node;
struct resource resource[PROMREG_MAX];
int num_addrs;
unsigned int irqs[PROMINTR_MAX];
@@ -27,27 +28,27 @@ struct linux_ebus_child {
};
struct linux_ebus_device {
+ struct of_device ofdev;
struct linux_ebus_device *next;
struct linux_ebus_child *children;
struct linux_ebus *bus;
- int prom_node;
- char prom_name[64];
+ struct device_node *prom_node;
struct resource resource[PROMREG_MAX];
int num_addrs;
unsigned int irqs[PROMINTR_MAX];
int num_irqs;
};
+#define to_ebus_device(d) container_of(d, struct linux_ebus_device, ofdev.dev)
struct linux_ebus {
+ struct of_device ofdev;
struct linux_ebus *next;
struct linux_ebus_device *devices;
struct linux_pbm_info *parent;
struct pci_dev *self;
- int prom_node;
- char prom_name[64];
- struct linux_prom_ebus_ranges ebus_ranges[PROMREG_MAX];
- int num_ebus_ranges;
+ struct device_node *prom_node;
};
+#define to_ebus(d) container_of(d, struct linux_ebus, ofdev.dev)
struct linux_ebus_dma {
unsigned int dcsr;
diff --git a/include/asm-sparc/irq.h b/include/asm-sparc/irq.h
index f2d6453..3141ddf 100644
--- a/include/asm-sparc/irq.h
+++ b/include/asm-sparc/irq.h
@@ -181,8 +181,4 @@ extern struct sun4m_intregs *sun4m_interrupts;
#define SUN4M_INT_SBUS(x) (1 << (x+7))
#define SUN4M_INT_VME(x) (1 << (x))
-struct irqaction;
-struct pt_regs;
-int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
-
#endif
diff --git a/include/asm-sparc/of_device.h b/include/asm-sparc/of_device.h
new file mode 100644
index 0000000..4816d10
--- /dev/null
+++ b/include/asm-sparc/of_device.h
@@ -0,0 +1,63 @@
+#ifndef _ASM_SPARC_OF_DEVICE_H
+#define _ASM_SPARC_OF_DEVICE_H
+#ifdef __KERNEL__
+
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <asm/prom.h>
+
+extern struct bus_type ebus_bus_type;
+extern struct bus_type sbus_bus_type;
+
+/*
+ * The of_device is a kind of "base class" that is a superset of
+ * struct device for use by devices attached to an OF node and
+ * probed using OF properties.
+ */
+struct of_device
+{
+ struct device_node *node; /* OF device node */
+ struct device dev; /* Generic device interface */
+};
+#define to_of_device(d) container_of(d, struct of_device, dev)
+
+extern const struct of_device_id *of_match_device(
+ const struct of_device_id *matches, const struct of_device *dev);
+
+extern struct of_device *of_dev_get(struct of_device *dev);
+extern void of_dev_put(struct of_device *dev);
+
+/*
+ * An of_platform_driver driver is attached to a basic of_device on
+ * the ISA, EBUS, and SBUS busses on sparc64.
+ */
+struct of_platform_driver
+{
+ char *name;
+ struct of_device_id *match_table;
+ struct module *owner;
+
+ int (*probe)(struct of_device* dev, const struct of_device_id *match);
+ int (*remove)(struct of_device* dev);
+
+ int (*suspend)(struct of_device* dev, pm_message_t state);
+ int (*resume)(struct of_device* dev);
+ int (*shutdown)(struct of_device* dev);
+
+ struct device_driver driver;
+};
+#define to_of_platform_driver(drv) container_of(drv,struct of_platform_driver, driver)
+
+extern int of_register_driver(struct of_platform_driver *drv,
+ struct bus_type *bus);
+extern void of_unregister_driver(struct of_platform_driver *drv);
+extern int of_device_register(struct of_device *ofdev);
+extern void of_device_unregister(struct of_device *ofdev);
+extern struct of_device *of_platform_device_create(struct device_node *np,
+ const char *bus_id,
+ struct device *parent,
+ struct bus_type *bus);
+extern void of_release_dev(struct device *dev);
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_SPARC_OF_DEVICE_H */
diff --git a/include/asm-sparc/pbm.h b/include/asm-sparc/pbm.h
index 0aba3a8..fedd9c6 100644
--- a/include/asm-sparc/pbm.h
+++ b/include/asm-sparc/pbm.h
@@ -22,6 +22,7 @@
#include <linux/pci.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
struct linux_pbm_info {
int prom_node;
@@ -40,7 +41,7 @@ struct linux_pbm_info {
*/
struct pcidev_cookie {
struct linux_pbm_info *pbm;
- int prom_node;
+ struct device_node *prom_node;
};
#endif /* !(__SPARC_PBM_H) */
diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h
new file mode 100644
index 0000000..c5e3d26
--- /dev/null
+++ b/include/asm-sparc/prom.h
@@ -0,0 +1,98 @@
+#ifndef _SPARC_PROM_H
+#define _SPARC_PROM_H
+#ifdef __KERNEL__
+
+
+/*
+ * Definitions for talking to the Open Firmware PROM on
+ * Power Macintosh computers.
+ *
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * Updates for PPC64 by Peter Bergner & David Engebretsen, IBM Corp.
+ * Updates for SPARC32 by David S. Miller
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <asm/atomic.h>
+
+typedef u32 phandle;
+typedef u32 ihandle;
+
+struct interrupt_info {
+ int line;
+ int sense; /* +ve/-ve logic, edge or level, etc. */
+};
+
+struct property {
+ char *name;
+ int length;
+ void *value;
+ struct property *next;
+};
+
+struct device_node {
+ char *name;
+ char *type;
+ phandle node;
+ phandle linux_phandle;
+ int n_intrs;
+ struct interrupt_info *intrs;
+ char *path_component_name;
+ char *full_name;
+
+ struct property *properties;
+ struct property *deadprops; /* removed properties */
+ struct device_node *parent;
+ struct device_node *child;
+ struct device_node *sibling;
+ struct device_node *next; /* next device of same type */
+ struct device_node *allnext; /* next in list of all nodes */
+ struct proc_dir_entry *pde; /* this node's proc directory */
+ struct kref kref;
+ unsigned long _flags;
+ void *data;
+};
+
+static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
+{
+ dn->pde = de;
+}
+
+extern struct device_node *of_find_node_by_name(struct device_node *from,
+ const char *name);
+#define for_each_node_by_name(dn, name) \
+ for (dn = of_find_node_by_name(NULL, name); dn; \
+ dn = of_find_node_by_name(dn, name))
+extern struct device_node *of_find_node_by_type(struct device_node *from,
+ const char *type);
+#define for_each_node_by_type(dn, type) \
+ for (dn = of_find_node_by_type(NULL, type); dn; \
+ dn = of_find_node_by_type(dn, type))
+extern struct device_node *of_find_compatible_node(struct device_node *from,
+ const char *type, const char *compat);
+extern struct device_node *of_find_node_by_path(const char *path);
+extern struct device_node *of_find_node_by_phandle(phandle handle);
+extern struct device_node *of_get_parent(const struct device_node *node);
+extern struct device_node *of_get_next_child(const struct device_node *node,
+ struct device_node *prev);
+extern struct property *of_find_property(struct device_node *np,
+ const char *name,
+ int *lenp);
+extern int of_device_is_compatible(struct device_node *device, const char *);
+extern void *of_get_property(struct device_node *node, const char *name,
+ int *lenp);
+extern int of_getintprop_default(struct device_node *np,
+ const char *name,
+ int def);
+
+extern void prom_build_devicetree(void);
+
+#endif /* __KERNEL__ */
+#endif /* _SPARC_PROM_H */
diff --git a/include/asm-sparc/sbus.h b/include/asm-sparc/sbus.h
index a13cddc..d036e44 100644
--- a/include/asm-sparc/sbus.h
+++ b/include/asm-sparc/sbus.h
@@ -11,7 +11,8 @@
#include <linux/ioport.h>
#include <asm/oplib.h>
-/* #include <asm/iommu.h> */ /* Unused since we use opaque iommu (|io-unit) */
+#include <asm/prom.h>
+#include <asm/of_device.h>
#include <asm/scatterlist.h>
/* We scan which devices are on the SBus using the PROM node device
@@ -42,18 +43,19 @@ struct sbus_bus;
/* Linux SBUS device tables */
struct sbus_dev {
- struct sbus_bus *bus; /* Back ptr to sbus */
- struct sbus_dev *next; /* next device on this SBus or null */
- struct sbus_dev *child; /* For ledma and espdma on sun4m */
- struct sbus_dev *parent; /* Parent device if not toplevel */
- int prom_node; /* PROM device tree node for this device */
- char prom_name[64]; /* PROM device name */
+ struct of_device ofdev;
+ struct sbus_bus *bus;
+ struct sbus_dev *next;
+ struct sbus_dev *child;
+ struct sbus_dev *parent;
+ int prom_node;
+ char prom_name[64];
int slot;
struct resource resource[PROMREG_MAX];
struct linux_prom_registers reg_addrs[PROMREG_MAX];
- int num_registers, ranges_applied;
+ int num_registers;
struct linux_prom_ranges device_ranges[PROMREG_MAX];
int num_device_ranges;
@@ -61,9 +63,11 @@ struct sbus_dev {
unsigned int irqs[4];
int num_irqs;
};
+#define to_sbus_device(d) container_of(d, struct sbus_dev, ofdev.dev)
/* This struct describes the SBus(s) found on this machine. */
struct sbus_bus {
+ struct of_device ofdev;
void *iommu; /* Opaque IOMMU cookie */
struct sbus_dev *devices; /* Link to devices on this SBus */
struct sbus_bus *next; /* next SBus, if more than one SBus */
@@ -77,6 +81,7 @@ struct sbus_bus {
int devid;
int board;
};
+#define to_sbus(d) container_of(d, struct sbus_bus, ofdev.dev)
extern struct sbus_bus *sbus_root;
@@ -102,6 +107,7 @@ sbus_is_slave(struct sbus_dev *dev)
#define sbus_can_dma_64bit(sdev) (0) /* actually, sparc_cpu_model==sun4d */
#define sbus_can_burst64(sdev) (0) /* actually, sparc_cpu_model==sun4d */
extern void sbus_set_sbus64(struct sbus_dev *, int);
+extern void sbus_fill_device_irq(struct sbus_dev *);
/* These yield IOMMU mappings in consistent mode. */
extern void *sbus_alloc_consistent(struct sbus_dev *, long, u32 *dma_addrp);
@@ -139,4 +145,10 @@ extern void sbus_dma_sync_sg_for_device(struct sbus_dev *, struct scatterlist *,
BTFIXUPDEF_CALL(unsigned int, sbint_to_irq, struct sbus_dev *sdev, unsigned int)
#define sbint_to_irq(sdev, sbint) BTFIXUP_CALL(sbint_to_irq)(sdev, sbint)
+extern void sbus_arch_bus_ranges_init(struct device_node *, struct sbus_bus *);
+extern void sbus_setup_iommu(struct sbus_bus *, struct device_node *);
+extern void sbus_setup_arch_props(struct sbus_bus *, struct device_node *);
+extern int sbus_arch_preinit(void);
+extern void sbus_arch_postinit(void);
+
#endif /* !(_SPARC_SBUS_H) */
diff --git a/include/asm-sparc64/ebus.h b/include/asm-sparc64/ebus.h
index 7a408a0..a4afe9d 100644
--- a/include/asm-sparc64/ebus.h
+++ b/include/asm-sparc64/ebus.h
@@ -10,13 +10,14 @@
#include <asm/pbm.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
struct linux_ebus_child {
struct linux_ebus_child *next;
struct linux_ebus_device *parent;
struct linux_ebus *bus;
- int prom_node;
- char prom_name[64];
+ struct device_node *prom_node;
struct resource resource[PROMREG_MAX];
int num_addrs;
unsigned int irqs[PROMINTR_MAX];
@@ -24,32 +25,29 @@ struct linux_ebus_child {
};
struct linux_ebus_device {
+ struct of_device ofdev;
struct linux_ebus_device *next;
struct linux_ebus_child *children;
struct linux_ebus *bus;
- int prom_node;
- char prom_name[64];
+ struct device_node *prom_node;
struct resource resource[PROMREG_MAX];
int num_addrs;
unsigned int irqs[PROMINTR_MAX];
int num_irqs;
};
+#define to_ebus_device(d) container_of(d, struct linux_ebus_device, ofdev.dev)
struct linux_ebus {
+ struct of_device ofdev;
struct linux_ebus *next;
struct linux_ebus_device *devices;
struct pci_pbm_info *parent;
struct pci_dev *self;
int index;
int is_rio;
- int prom_node;
- char prom_name[64];
- struct linux_prom_ebus_ranges ebus_ranges[PROMREG_MAX];
- int num_ebus_ranges;
- struct linux_prom_ebus_intmap ebus_intmap[PROMREG_MAX];
- int num_ebus_intmap;
- struct linux_prom_ebus_intmask ebus_intmask;
+ struct device_node *prom_node;
};
+#define to_ebus(d) container_of(d, struct linux_ebus, ofdev.dev)
struct ebus_dma_info {
spinlock_t lock;
diff --git a/include/asm-sparc64/fhc.h b/include/asm-sparc64/fhc.h
index f29eaa2..9e7f1b0 100644
--- a/include/asm-sparc64/fhc.h
+++ b/include/asm-sparc64/fhc.h
@@ -10,6 +10,7 @@
#include <linux/timer.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
#include <asm/upa.h>
struct linux_fhc;
@@ -34,8 +35,7 @@ struct linux_central {
unsigned long clkregs;
unsigned long clkver;
int slots;
- int prom_node;
- char prom_name[64];
+ struct device_node *prom_node;
struct linux_prom_ranges central_ranges[PROMREG_MAX];
int num_central_ranges;
@@ -112,8 +112,7 @@ struct linux_fhc {
struct fhc_regs fhc_regs;
int board;
int jtag_master;
- int prom_node;
- char prom_name[64];
+ struct device_node *prom_node;
struct linux_prom_ranges fhc_ranges[PROMREG_MAX];
int num_fhc_ranges;
diff --git a/include/asm-sparc64/floppy.h b/include/asm-sparc64/floppy.h
index 07ccd6f..f8d57bb 100644
--- a/include/asm-sparc64/floppy.h
+++ b/include/asm-sparc64/floppy.h
@@ -498,15 +498,14 @@ static int sun_pci_fd_test_drive(unsigned long port, int drive)
#ifdef CONFIG_PCI
static int __init ebus_fdthree_p(struct linux_ebus_device *edev)
{
- if (!strcmp(edev->prom_name, "fdthree"))
+ if (!strcmp(edev->prom_node->name, "fdthree"))
return 1;
- if (!strcmp(edev->prom_name, "floppy")) {
- char compat[16];
- prom_getstring(edev->prom_node,
- "compatible",
- compat, sizeof(compat));
- compat[15] = '\0';
- if (!strcmp(compat, "fdthree"))
+ if (!strcmp(edev->prom_node->name, "floppy")) {
+ char *compat;
+
+ compat = of_get_property(edev->prom_node,
+ "compatible", NULL);
+ if (compat && !strcmp(compat, "fdthree"))
return 1;
}
return 0;
@@ -524,12 +523,12 @@ static unsigned long __init isa_floppy_init(void)
for_each_isa(isa_br) {
for_each_isadev(isa_dev, isa_br) {
- if (!strcmp(isa_dev->prom_name, "dma")) {
+ if (!strcmp(isa_dev->prom_node->name, "dma")) {
struct sparc_isa_device *child =
isa_dev->child;
while (child) {
- if (!strcmp(child->prom_name,
+ if (!strcmp(child->prom_node->name,
"floppy")) {
isa_dev = child;
goto isa_done;
@@ -614,6 +613,7 @@ static unsigned long __init sun_floppy_init(void)
struct linux_ebus_device *edev = NULL;
unsigned long config = 0;
void __iomem *auxio_reg;
+ char *state_prop;
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
@@ -630,9 +630,8 @@ static unsigned long __init sun_floppy_init(void)
#endif
}
- prom_getproperty(edev->prom_node, "status",
- state, sizeof(state));
- if (!strncmp(state, "disabled", 8))
+ state_prop = of_get_property(edev->prom_node, "status", NULL);
+ if (state_prop && !strncmp(state_prop, "disabled", 8))
return 0;
FLOPPY_IRQ = edev->irqs[0];
@@ -703,7 +702,7 @@ static unsigned long __init sun_floppy_init(void)
*/
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "ecpp")) {
+ if (!strcmp(edev->prom_node->name, "ecpp")) {
config = edev->resource[1].start;
goto config_done;
}
diff --git a/include/asm-sparc64/isa.h b/include/asm-sparc64/isa.h
index 4601bbf..d9728b9 100644
--- a/include/asm-sparc64/isa.h
+++ b/include/asm-sparc64/isa.h
@@ -9,37 +9,32 @@
#include <asm/pbm.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
struct sparc_isa_bridge;
struct sparc_isa_device {
+ struct of_device ofdev;
struct sparc_isa_device *next;
struct sparc_isa_device *child;
struct sparc_isa_bridge *bus;
- int prom_node;
- char prom_name[64];
- char compatible[64];
+ struct device_node *prom_node;
struct resource resource;
unsigned int irq;
};
+#define to_isa_device(d) container_of(d, struct sparc_isa_device, ofdev.dev)
struct sparc_isa_bridge {
+ struct of_device ofdev;
struct sparc_isa_bridge *next;
struct sparc_isa_device *devices;
struct pci_pbm_info *parent;
struct pci_dev *self;
int index;
- int prom_node;
- char prom_name[64];
-#define linux_prom_isa_ranges linux_prom_ebus_ranges
- struct linux_prom_isa_ranges isa_ranges[PROMREG_MAX];
- int num_isa_ranges;
-#define linux_prom_isa_intmap linux_prom_ebus_intmap
- struct linux_prom_isa_intmap isa_intmap[PROMREG_MAX];
- int num_isa_intmap;
-#define linux_prom_isa_intmask linux_prom_ebus_intmask
- struct linux_prom_isa_intmap isa_intmask;
+ struct device_node *prom_node;
};
+#define to_isa_bridge(d) container_of(d, struct sparc_isa_bridge, ofdev.dev)
extern struct sparc_isa_bridge *isa_chain;
diff --git a/include/asm-sparc64/of_device.h b/include/asm-sparc64/of_device.h
new file mode 100644
index 0000000..024088e
--- /dev/null
+++ b/include/asm-sparc64/of_device.h
@@ -0,0 +1,64 @@
+#ifndef _ASM_SPARC64_OF_DEVICE_H
+#define _ASM_SPARC64_OF_DEVICE_H
+#ifdef __KERNEL__
+
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <asm/prom.h>
+
+extern struct bus_type isa_bus_type;
+extern struct bus_type ebus_bus_type;
+extern struct bus_type sbus_bus_type;
+
+/*
+ * The of_device is a kind of "base class" that is a superset of
+ * struct device for use by devices attached to an OF node and
+ * probed using OF properties.
+ */
+struct of_device
+{
+ struct device_node *node; /* OF device node */
+ struct device dev; /* Generic device interface */
+};
+#define to_of_device(d) container_of(d, struct of_device, dev)
+
+extern const struct of_device_id *of_match_device(
+ const struct of_device_id *matches, const struct of_device *dev);
+
+extern struct of_device *of_dev_get(struct of_device *dev);
+extern void of_dev_put(struct of_device *dev);
+
+/*
+ * An of_platform_driver driver is attached to a basic of_device on
+ * the ISA, EBUS, and SBUS busses on sparc64.
+ */
+struct of_platform_driver
+{
+ char *name;
+ struct of_device_id *match_table;
+ struct module *owner;
+
+ int (*probe)(struct of_device* dev, const struct of_device_id *match);
+ int (*remove)(struct of_device* dev);
+
+ int (*suspend)(struct of_device* dev, pm_message_t state);
+ int (*resume)(struct of_device* dev);
+ int (*shutdown)(struct of_device* dev);
+
+ struct device_driver driver;
+};
+#define to_of_platform_driver(drv) container_of(drv,struct of_platform_driver, driver)
+
+extern int of_register_driver(struct of_platform_driver *drv,
+ struct bus_type *bus);
+extern void of_unregister_driver(struct of_platform_driver *drv);
+extern int of_device_register(struct of_device *ofdev);
+extern void of_device_unregister(struct of_device *ofdev);
+extern struct of_device *of_platform_device_create(struct device_node *np,
+ const char *bus_id,
+ struct device *parent,
+ struct bus_type *bus);
+extern void of_release_dev(struct device *dev);
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_SPARC64_OF_DEVICE_H */
diff --git a/include/asm-sparc64/oplib.h b/include/asm-sparc64/oplib.h
index dea3e73..a68b0bb 100644
--- a/include/asm-sparc64/oplib.h
+++ b/include/asm-sparc64/oplib.h
@@ -323,8 +323,9 @@ extern int prom_pathtoinode(const char *path);
extern int prom_inst2pkg(int);
/* CPU probing helpers. */
-int cpu_find_by_instance(int instance, int *prom_node, int *mid);
-int cpu_find_by_mid(int mid, int *prom_node);
+struct device_node;
+int cpu_find_by_instance(int instance, struct device_node **dev_node, int *mid);
+int cpu_find_by_mid(int mid, struct device_node **prom_node);
/* Client interface level routines. */
extern void prom_set_trap_table(unsigned long tba);
diff --git a/include/asm-sparc64/parport.h b/include/asm-sparc64/parport.h
index 56b5197d..d389587 100644
--- a/include/asm-sparc64/parport.h
+++ b/include/asm-sparc64/parport.h
@@ -67,18 +67,17 @@ static __inline__ unsigned int get_dma_residue(unsigned int dmanr)
static int ebus_ecpp_p(struct linux_ebus_device *edev)
{
- if (!strcmp(edev->prom_name, "ecpp"))
+ if (!strcmp(edev->prom_node->name, "ecpp"))
return 1;
- if (!strcmp(edev->prom_name, "parallel")) {
- char compat[19];
- prom_getstring(edev->prom_node,
- "compatible",
- compat, sizeof(compat));
- compat[18] = '\0';
- if (!strcmp(compat, "ecpp"))
- return 1;
- if (!strcmp(compat, "ns87317-ecpp") &&
- !strcmp(compat + 13, "ecpp"))
+ if (!strcmp(edev->prom_node->name, "parallel")) {
+ char *compat;
+
+ compat = of_get_property(edev->prom_node,
+ "compatible", NULL);
+ if (compat &&
+ (!strcmp(compat, "ecpp") ||
+ !strcmp(compat, "ns87317-ecpp") ||
+ !strcmp(compat + 13, "ecpp")))
return 1;
}
return 0;
@@ -94,12 +93,12 @@ static int parport_isa_probe(int count)
struct sparc_isa_device *child;
unsigned long base;
- if (strcmp(isa_dev->prom_name, "dma"))
+ if (strcmp(isa_dev->prom_node->name, "dma"))
continue;
child = isa_dev->child;
while (child) {
- if (!strcmp(child->prom_name, "parallel"))
+ if (!strcmp(child->prom_node->name, "parallel"))
break;
child = child->next;
}
diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h
index 1396f11..cebe80b 100644
--- a/include/asm-sparc64/pbm.h
+++ b/include/asm-sparc64/pbm.h
@@ -15,6 +15,7 @@
#include <asm/io.h>
#include <asm/page.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
#include <asm/iommu.h>
/* The abstraction used here is that there are PCI controllers,
@@ -153,16 +154,15 @@ struct pci_pbm_info {
int chip_revision;
/* Name used for top-level resources. */
- char name[64];
+ char *name;
/* OBP specific information. */
- int prom_node;
- char prom_name[64];
- struct linux_prom_pci_ranges pbm_ranges[PROM_PCIRNG_MAX];
+ struct device_node *prom_node;
+ struct linux_prom_pci_ranges *pbm_ranges;
int num_pbm_ranges;
- struct linux_prom_pci_intmap pbm_intmap[PROM_PCIIMAP_MAX];
+ struct linux_prom_pci_intmap *pbm_intmap;
int num_pbm_intmap;
- struct linux_prom_pci_intmask pbm_intmask;
+ struct linux_prom_pci_intmask *pbm_intmask;
u64 ino_bitmap;
/* PBM I/O and Memory space resources. */
@@ -227,8 +227,7 @@ struct pci_controller_info {
*/
struct pcidev_cookie {
struct pci_pbm_info *pbm;
- char prom_name[64];
- int prom_node;
+ struct device_node *prom_node;
struct linux_prom_pci_registers prom_regs[PROMREG_MAX];
int num_prom_regs;
struct linux_prom_pci_registers prom_assignments[PROMREG_MAX];
diff --git a/include/asm-sparc64/percpu.h b/include/asm-sparc64/percpu.h
index baef13b..a6ece06 100644
--- a/include/asm-sparc64/percpu.h
+++ b/include/asm-sparc64/percpu.h
@@ -21,6 +21,7 @@ register unsigned long __local_per_cpu_offset asm("g5");
/* var is in discarded region: offset to particular copy we want */
#define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu)))
#define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __local_per_cpu_offset))
+#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __local_per_cpu_offset))
/* A macro to avoid #include hell... */
#define percpu_modcopy(pcpudst, src, size) \
@@ -37,6 +38,7 @@ do { \
#define per_cpu(var, cpu) (*((void)cpu, &per_cpu__##var))
#define __get_cpu_var(var) per_cpu__##var
+#define __raw_get_cpu_var(var) per_cpu__##var
#endif /* SMP */
diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h
index 4e21881..03f5bc9 100644
--- a/include/asm-sparc64/pgtable.h
+++ b/include/asm-sparc64/pgtable.h
@@ -756,6 +756,8 @@ extern unsigned long *sparc64_valid_addr_bitmap;
#define kern_addr_valid(addr) \
(test_bit(__pa((unsigned long)(addr))>>22, sparc64_valid_addr_bitmap))
+extern int page_in_phys_avail(unsigned long paddr);
+
extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
unsigned long pfn,
unsigned long size, pgprot_t prot);
diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h
new file mode 100644
index 0000000..6d1556c
--- /dev/null
+++ b/include/asm-sparc64/prom.h
@@ -0,0 +1,98 @@
+#ifndef _SPARC64_PROM_H
+#define _SPARC64_PROM_H
+#ifdef __KERNEL__
+
+
+/*
+ * Definitions for talking to the Open Firmware PROM on
+ * Power Macintosh computers.
+ *
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * Updates for PPC64 by Peter Bergner & David Engebretsen, IBM Corp.
+ * Updates for SPARC64 by David S. Miller
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <asm/atomic.h>
+
+typedef u32 phandle;
+typedef u32 ihandle;
+
+struct interrupt_info {
+ int line;
+ int sense; /* +ve/-ve logic, edge or level, etc. */
+};
+
+struct property {
+ char *name;
+ int length;
+ void *value;
+ struct property *next;
+};
+
+struct device_node {
+ char *name;
+ char *type;
+ phandle node;
+ phandle linux_phandle;
+ int n_intrs;
+ struct interrupt_info *intrs;
+ char *path_component_name;
+ char *full_name;
+
+ struct property *properties;
+ struct property *deadprops; /* removed properties */
+ struct device_node *parent;
+ struct device_node *child;
+ struct device_node *sibling;
+ struct device_node *next; /* next device of same type */
+ struct device_node *allnext; /* next in list of all nodes */
+ struct proc_dir_entry *pde; /* this node's proc directory */
+ struct kref kref;
+ unsigned long _flags;
+ void *data;
+};
+
+static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
+{
+ dn->pde = de;
+}
+
+extern struct device_node *of_find_node_by_name(struct device_node *from,
+ const char *name);
+#define for_each_node_by_name(dn, name) \
+ for (dn = of_find_node_by_name(NULL, name); dn; \
+ dn = of_find_node_by_name(dn, name))
+extern struct device_node *of_find_node_by_type(struct device_node *from,
+ const char *type);
+#define for_each_node_by_type(dn, type) \
+ for (dn = of_find_node_by_type(NULL, type); dn; \
+ dn = of_find_node_by_type(dn, type))
+extern struct device_node *of_find_compatible_node(struct device_node *from,
+ const char *type, const char *compat);
+extern struct device_node *of_find_node_by_path(const char *path);
+extern struct device_node *of_find_node_by_phandle(phandle handle);
+extern struct device_node *of_get_parent(const struct device_node *node);
+extern struct device_node *of_get_next_child(const struct device_node *node,
+ struct device_node *prev);
+extern struct property *of_find_property(struct device_node *np,
+ const char *name,
+ int *lenp);
+extern int of_device_is_compatible(struct device_node *device, const char *);
+extern void *of_get_property(struct device_node *node, const char *name,
+ int *lenp);
+extern int of_getintprop_default(struct device_node *np,
+ const char *name,
+ int def);
+
+extern void prom_build_devicetree(void);
+
+#endif /* __KERNEL__ */
+#endif /* _SPARC64_PROM_H */
diff --git a/include/asm-sparc64/sbus.h b/include/asm-sparc64/sbus.h
index 48279e1..56ee985 100644
--- a/include/asm-sparc64/sbus.h
+++ b/include/asm-sparc64/sbus.h
@@ -11,6 +11,8 @@
#include <linux/ioport.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
#include <asm/iommu.h>
#include <asm/scatterlist.h>
@@ -42,18 +44,19 @@ struct sbus_bus;
/* Linux SBUS device tables */
struct sbus_dev {
- struct sbus_bus *bus; /* Our toplevel parent SBUS */
- struct sbus_dev *next; /* Chain of siblings */
- struct sbus_dev *child; /* Chain of children */
- struct sbus_dev *parent;/* Parent device if not toplevel*/
- int prom_node; /* OBP node of this device */
- char prom_name[64]; /* OBP device name property */
- int slot; /* SBUS slot number */
+ struct of_device ofdev;
+ struct sbus_bus *bus;
+ struct sbus_dev *next;
+ struct sbus_dev *child;
+ struct sbus_dev *parent;
+ int prom_node;
+ char prom_name[64];
+ int slot;
struct resource resource[PROMREG_MAX];
struct linux_prom_registers reg_addrs[PROMREG_MAX];
- int num_registers, ranges_applied;
+ int num_registers;
struct linux_prom_ranges device_ranges[PROMREG_MAX];
int num_device_ranges;
@@ -61,9 +64,11 @@ struct sbus_dev {
unsigned int irqs[4];
int num_irqs;
};
+#define to_sbus_device(d) container_of(d, struct sbus_dev, ofdev.dev)
/* This struct describes the SBus(s) found on this machine. */
struct sbus_bus {
+ struct of_device ofdev;
void *iommu; /* Opaque IOMMU cookie */
struct sbus_dev *devices; /* Tree of SBUS devices */
struct sbus_bus *next; /* Next SBUS in system */
@@ -77,6 +82,7 @@ struct sbus_bus {
int portid;
void *starfire_cookie;
};
+#define to_sbus(d) container_of(d, struct sbus_bus, ofdev.dev)
extern struct sbus_bus *sbus_root;
@@ -95,6 +101,7 @@ extern struct sbus_bus *sbus_root;
#define sbus_can_dma_64bit(sdev) (1)
#define sbus_can_burst64(sdev) (1)
extern void sbus_set_sbus64(struct sbus_dev *, int);
+extern void sbus_fill_device_irq(struct sbus_dev *);
/* These yield IOMMU mappings in consistent mode. */
extern void *sbus_alloc_consistent(struct sbus_dev *, size_t, dma_addr_t *dma_addrp);
@@ -119,4 +126,10 @@ extern void sbus_dma_sync_sg_for_cpu(struct sbus_dev *, struct scatterlist *, in
#define sbus_dma_sync_sg sbus_dma_sync_sg_for_cpu
extern void sbus_dma_sync_sg_for_device(struct sbus_dev *, struct scatterlist *, int, int);
+extern void sbus_arch_bus_ranges_init(struct device_node *, struct sbus_bus *);
+extern void sbus_setup_iommu(struct sbus_bus *, struct device_node *);
+extern void sbus_setup_arch_props(struct sbus_bus *, struct device_node *);
+extern int sbus_arch_preinit(void);
+extern void sbus_arch_postinit(void);
+
#endif /* !(_SPARC64_SBUS_H) */
diff --git a/include/asm-sparc64/vdev.h b/include/asm-sparc64/vdev.h
index 996e6be..25637c5 100644
--- a/include/asm-sparc64/vdev.h
+++ b/include/asm-sparc64/vdev.h
@@ -7,10 +7,11 @@
#define _SPARC64_VDEV_H
#include <linux/types.h>
+#include <asm/prom.h>
extern u32 sun4v_vdev_devhandle;
-extern int sun4v_vdev_root;
+extern struct device_node *sun4v_vdev_root;
-extern unsigned int sun4v_vdev_device_interrupt(unsigned int);
+extern unsigned int sun4v_vdev_device_interrupt(struct device_node *dev_node);
#endif /* !(_SPARC64_VDEV_H) */
diff --git a/include/asm-sparc64/vga.h b/include/asm-sparc64/vga.h
index 9c57eb3..c69d5b2 100644
--- a/include/asm-sparc64/vga.h
+++ b/include/asm-sparc64/vga.h
@@ -28,6 +28,6 @@ static inline u16 scr_readw(const u16 *addr)
return *addr;
}
-#define VGA_MAP_MEM(x) (x)
+#define VGA_MAP_MEM(x,s) (x)
#endif
diff --git a/include/asm-v850/irq.h b/include/asm-v850/irq.h
index 4443115..1bf096d 100644
--- a/include/asm-v850/irq.h
+++ b/include/asm-v850/irq.h
@@ -62,8 +62,6 @@ extern void disable_irq (unsigned int irq);
/* Disable an irq without waiting. */
extern void disable_irq_nosync (unsigned int irq);
-extern int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
-
#endif /* !__ASSEMBLY__ */
#endif /* __V850_IRQ_H__ */
diff --git a/include/asm-x86_64/acpi.h b/include/asm-x86_64/acpi.h
index aa1c7b2..2c95a31 100644
--- a/include/asm-x86_64/acpi.h
+++ b/include/asm-x86_64/acpi.h
@@ -162,6 +162,8 @@ extern int acpi_pci_disabled;
extern u8 x86_acpiid_to_apicid[];
+#define ARCH_HAS_POWER_INIT 1
+
extern int acpi_skip_timer_override;
#endif /*__KERNEL__*/
diff --git a/include/asm-x86_64/apicdef.h b/include/asm-x86_64/apicdef.h
index 5a48e9b..1dd4006 100644
--- a/include/asm-x86_64/apicdef.h
+++ b/include/asm-x86_64/apicdef.h
@@ -137,8 +137,6 @@
*/
#define u32 unsigned int
-#define lapic ((volatile struct local_apic *)APIC_BASE)
-
struct local_apic {
/*000*/ struct { u32 __reserved[4]; } __reserved_01;
diff --git a/include/asm-x86_64/floppy.h b/include/asm-x86_64/floppy.h
index 52825ce..006291e 100644
--- a/include/asm-x86_64/floppy.h
+++ b/include/asm-x86_64/floppy.h
@@ -147,10 +147,8 @@ static int fd_request_irq(void)
return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
"floppy", NULL);
else
- return request_irq(FLOPPY_IRQ, floppy_interrupt,
- SA_INTERRUPT|SA_SAMPLE_RANDOM,
- "floppy", NULL);
-
+ return request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT,
+ "floppy", NULL);
}
static unsigned long dma_mem_alloc(unsigned long size)
diff --git a/include/asm-x86_64/mmzone.h b/include/asm-x86_64/mmzone.h
index 70bb996..c38ebdf 100644
--- a/include/asm-x86_64/mmzone.h
+++ b/include/asm-x86_64/mmzone.h
@@ -42,7 +42,6 @@ static inline __attribute__((pure)) int phys_to_nid(unsigned long addr)
#ifdef CONFIG_DISCONTIGMEM
#define pfn_to_nid(pfn) phys_to_nid((unsigned long)(pfn) << PAGE_SHIFT)
-#define kvaddr_to_nid(kaddr) phys_to_nid(__pa(kaddr))
extern int pfn_valid(unsigned long pfn);
#endif
diff --git a/include/asm-x86_64/msi.h b/include/asm-x86_64/msi.h
index 356e0e8..3ad23466 100644
--- a/include/asm-x86_64/msi.h
+++ b/include/asm-x86_64/msi.h
@@ -10,7 +10,15 @@
#include <asm/mach_apic.h>
#include <asm/smp.h>
-#define LAST_DEVICE_VECTOR 232
+#define LAST_DEVICE_VECTOR (FIRST_SYSTEM_VECTOR - 1)
#define MSI_TARGET_CPU_SHIFT 12
+extern struct msi_ops msi_apic_ops;
+
+static inline int msi_arch_init(void)
+{
+ msi_register(&msi_apic_ops);
+ return 0;
+}
+
#endif /* ASM_MSI_H */
diff --git a/include/asm-x86_64/numa.h b/include/asm-x86_64/numa.h
index 1cc92fe..933ff11 100644
--- a/include/asm-x86_64/numa.h
+++ b/include/asm-x86_64/numa.h
@@ -8,7 +8,6 @@ struct bootnode {
};
extern int compute_hash_shift(struct bootnode *nodes, int numnodes);
-extern int pxm_to_node(int nid);
#define ZONE_ALIGN (1UL << (MAX_ORDER+PAGE_SHIFT))
diff --git a/include/asm-x86_64/percpu.h b/include/asm-x86_64/percpu.h
index 7f33aaf..549eb92 100644
--- a/include/asm-x86_64/percpu.h
+++ b/include/asm-x86_64/percpu.h
@@ -21,6 +21,7 @@
/* var is in discarded region: offset to particular copy we want */
#define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu)))
#define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()))
+#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()))
/* A macro to avoid #include hell... */
#define percpu_modcopy(pcpudst, src, size) \
@@ -40,6 +41,7 @@ extern void setup_per_cpu_areas(void);
#define per_cpu(var, cpu) (*((void)(cpu), &per_cpu__##var))
#define __get_cpu_var(var) per_cpu__##var
+#define __raw_get_cpu_var(var) per_cpu__##var
#endif /* SMP */
diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h
index 0aff22b..94387c9 100644
--- a/include/asm-x86_64/unistd.h
+++ b/include/asm-x86_64/unistd.h
@@ -617,10 +617,12 @@ __SYSCALL(__NR_tee, sys_tee)
__SYSCALL(__NR_sync_file_range, sys_sync_file_range)
#define __NR_vmsplice 278
__SYSCALL(__NR_vmsplice, sys_vmsplice)
+#define __NR_move_pages 279
+__SYSCALL(__NR_move_pages, sys_move_pages)
#ifdef __KERNEL__
-#define __NR_syscall_max __NR_vmsplice
+#define __NR_syscall_max __NR_move_pages
#ifndef __NO_STUBS
diff --git a/include/asm-x86_64/vga.h b/include/asm-x86_64/vga.h
index ef0c0e5..0ecf68a 100644
--- a/include/asm-x86_64/vga.h
+++ b/include/asm-x86_64/vga.h
@@ -12,7 +12,7 @@
* access the videoram directly without any black magic.
*/
-#define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x)
+#define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x)
#define vga_readb(x) (*(x))
#define vga_writeb(x,y) (*(y) = (x))
diff --git a/include/asm-xtensa/checksum.h b/include/asm-xtensa/checksum.h
index bdc00ae..03114f8 100644
--- a/include/asm-xtensa/checksum.h
+++ b/include/asm-xtensa/checksum.h
@@ -43,8 +43,7 @@ asmlinkage unsigned int csum_partial_copy_generic( const char *src, char *dst, i
* Note: when you get a NULL pointer exception here this means someone
* passed in an incorrect kernel address to one of these functions.
*
- * If you use these functions directly please don't forget the
- * verify_area().
+ * If you use these functions directly please don't forget the access_ok().
*/
static inline
unsigned int csum_partial_copy_nocheck ( const char *src, char *dst,
diff --git a/include/asm-xtensa/rwsem.h b/include/asm-xtensa/rwsem.h
index 3c02b0e..abcd86d 100644
--- a/include/asm-xtensa/rwsem.h
+++ b/include/asm-xtensa/rwsem.h
@@ -172,4 +172,9 @@ static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
return atomic_add_return(delta, (atomic_t *)(&sem->count));
}
-#endif /* _XTENSA_RWSEM_XADD_H */
+static inline int rwsem_is_locked(struct rw_semaphore *sem)
+{
+ return (sem->count != 0);
+}
+
+#endif /* _XTENSA_RWSEM_H */
diff --git a/include/asm-xtensa/uaccess.h b/include/asm-xtensa/uaccess.h
index 06a22b8..88a64e1 100644
--- a/include/asm-xtensa/uaccess.h
+++ b/include/asm-xtensa/uaccess.h
@@ -154,35 +154,6 @@
.Laccess_ok_\@:
.endm
-/*
- * verify_area determines whether a memory access is allowed. It's
- * mostly an unnecessary wrapper for access_ok, but we provide it as a
- * duplicate of the verify_area() C inline function below. See the
- * equivalent C version below for clarity.
- *
- * On error, verify_area branches to a label indicated by parameter
- * <error>. This implies that the macro falls through to the next
- * instruction on success.
- *
- * Note that we assume success is the common case, and we optimize the
- * branch fall-through case on success.
- *
- * On Entry:
- * <aa> register containing memory address
- * <as> register containing memory size
- * <at> temp register
- * <error> label to branch to on error; implies fall-through
- * macro on success
- * On Exit:
- * <aa> preserved
- * <as> preserved
- * <at> destroyed
- */
- .macro verify_area aa, as, at, sp, error
- access_ok \at, \aa, \as, \sp, \error
- .endm
-
-
#else /* __ASSEMBLY__ not defined */
#include <linux/sched.h>
@@ -211,11 +182,6 @@
#define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
#define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
-static inline int verify_area(int type, const void * addr, unsigned long size)
-{
- return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
-
/*
* These are the main single-value transfer routines. They
* automatically use the right size if we just have the right pointer
diff --git a/include/asm-xtensa/vga.h b/include/asm-xtensa/vga.h
index 23d82f6..1fd8cab 100644
--- a/include/asm-xtensa/vga.h
+++ b/include/asm-xtensa/vga.h
@@ -11,7 +11,7 @@
#ifndef _XTENSA_VGA_H
#define _XTENSA_VGA_H
-#define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x)
+#define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x)
#define vga_readb(x) (*(x))
#define vga_writeb(x,y) (*(y) = (x))
diff --git a/include/linux/acct.h b/include/linux/acct.h
index 3d54fbc..e86bae7 100644
--- a/include/linux/acct.h
+++ b/include/linux/acct.h
@@ -121,13 +121,17 @@ struct vfsmount;
struct super_block;
extern void acct_auto_close_mnt(struct vfsmount *m);
extern void acct_auto_close(struct super_block *sb);
-extern void acct_process(long exitcode);
+extern void acct_init_pacct(struct pacct_struct *pacct);
+extern void acct_collect(long exitcode, int group_dead);
+extern void acct_process(void);
extern void acct_update_integrals(struct task_struct *tsk);
extern void acct_clear_integrals(struct task_struct *tsk);
#else
#define acct_auto_close_mnt(x) do { } while (0)
#define acct_auto_close(x) do { } while (0)
-#define acct_process(x) do { } while (0)
+#define acct_init_pacct(x) do { } while (0)
+#define acct_collect(x,y) do { } while (0)
+#define acct_process() do { } while (0)
#define acct_update_integrals(x) do { } while (0)
#define acct_clear_integrals(task) do { } while (0)
#endif
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 1cf0b91..90d6df1 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -37,6 +37,7 @@
#include <acpi/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#include <acpi/acpi_numa.h>
#include <asm/acpi.h>
@@ -407,10 +408,18 @@ void acpi_table_print_madt_entry (acpi_table_entry_header *madt);
void acpi_table_print_srat_entry (acpi_table_entry_header *srat);
/* the following four functions are architecture-dependent */
+#ifdef CONFIG_HAVE_ARCH_PARSE_SRAT
+#define NR_NODE_MEMBLKS MAX_NUMNODES
+#define acpi_numa_slit_init(slit) do {} while (0)
+#define acpi_numa_processor_affinity_init(pa) do {} while (0)
+#define acpi_numa_memory_affinity_init(ma) do {} while (0)
+#define acpi_numa_arch_fixup() do {} while (0)
+#else
void acpi_numa_slit_init (struct acpi_table_slit *slit);
void acpi_numa_processor_affinity_init (struct acpi_table_processor_affinity *pa);
void acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma);
void acpi_numa_arch_fixup(void);
+#endif
#ifdef CONFIG_ACPI_HOTPLUG_CPU
/* Arch dependent functions for cpu hotplug support */
diff --git a/include/linux/ata.h b/include/linux/ata.h
index 312a2c0..3671af8 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -97,6 +97,9 @@ enum {
ATA_DRQ = (1 << 3), /* data request i/o */
ATA_ERR = (1 << 0), /* have an error */
ATA_SRST = (1 << 2), /* software reset */
+ ATA_ICRC = (1 << 7), /* interface CRC error */
+ ATA_UNC = (1 << 6), /* uncorrectable media error */
+ ATA_IDNF = (1 << 4), /* ID not found */
ATA_ABORTED = (1 << 2), /* command aborted */
/* ATA command block registers */
@@ -130,6 +133,8 @@ enum {
ATA_CMD_WRITE = 0xCA,
ATA_CMD_WRITE_EXT = 0x35,
ATA_CMD_WRITE_FUA_EXT = 0x3D,
+ ATA_CMD_FPDMA_READ = 0x60,
+ ATA_CMD_FPDMA_WRITE = 0x61,
ATA_CMD_PIO_READ = 0x20,
ATA_CMD_PIO_READ_EXT = 0x24,
ATA_CMD_PIO_WRITE = 0x30,
@@ -148,6 +153,10 @@ enum {
ATA_CMD_INIT_DEV_PARAMS = 0x91,
ATA_CMD_READ_NATIVE_MAX = 0xF8,
ATA_CMD_READ_NATIVE_MAX_EXT = 0x27,
+ ATA_CMD_READ_LOG_EXT = 0x2f,
+
+ /* READ_LOG_EXT pages */
+ ATA_LOG_SATA_NCQ = 0x10,
/* SETFEATURES stuff */
SETFEATURES_XFER = 0x03,
@@ -172,6 +181,9 @@ enum {
XFER_PIO_0 = 0x08,
XFER_PIO_SLOW = 0x00,
+ SETFEATURES_WC_ON = 0x02, /* Enable write cache */
+ SETFEATURES_WC_OFF = 0x82, /* Disable write cache */
+
/* ATAPI stuff */
ATAPI_PKT_DMA = (1 << 0),
ATAPI_DMADIR = (1 << 2), /* ATAPI data dir:
@@ -192,6 +204,16 @@ enum {
SCR_ACTIVE = 3,
SCR_NOTIFICATION = 4,
+ /* SError bits */
+ SERR_DATA_RECOVERED = (1 << 0), /* recovered data error */
+ SERR_COMM_RECOVERED = (1 << 1), /* recovered comm failure */
+ SERR_DATA = (1 << 8), /* unrecovered data error */
+ SERR_PERSISTENT = (1 << 9), /* persistent data/comm error */
+ SERR_PROTOCOL = (1 << 10), /* protocol violation */
+ SERR_INTERNAL = (1 << 11), /* host internal error */
+ SERR_PHYRDY_CHG = (1 << 16), /* PHY RDY changed */
+ SERR_DEV_XCHG = (1 << 26), /* device exchanged */
+
/* struct ata_taskfile flags */
ATA_TFLAG_LBA48 = (1 << 0), /* enable 48-bit LBA and "HOB" */
ATA_TFLAG_ISADDR = (1 << 1), /* enable r/w to nsect/lba regs */
@@ -199,6 +221,7 @@ enum {
ATA_TFLAG_WRITE = (1 << 3), /* data dir: host->dev==1 (write) */
ATA_TFLAG_LBA = (1 << 4), /* enable LBA */
ATA_TFLAG_FUA = (1 << 5), /* enable FUA */
+ ATA_TFLAG_POLLING = (1 << 6), /* set nIEN to 1 and use polling */
};
enum ata_tf_protocols {
@@ -207,6 +230,7 @@ enum ata_tf_protocols {
ATA_PROT_NODATA, /* no data */
ATA_PROT_PIO, /* PIO single sector */
ATA_PROT_DMA, /* DMA */
+ ATA_PROT_NCQ, /* NCQ */
ATA_PROT_ATAPI, /* packet command, PIO data xfer*/
ATA_PROT_ATAPI_NODATA, /* packet command, no data */
ATA_PROT_ATAPI_DMA, /* packet command with special DMA sauce */
@@ -262,6 +286,8 @@ struct ata_taskfile {
#define ata_id_has_pm(id) ((id)[82] & (1 << 3))
#define ata_id_has_lba(id) ((id)[49] & (1 << 9))
#define ata_id_has_dma(id) ((id)[49] & (1 << 8))
+#define ata_id_has_ncq(id) ((id)[76] & (1 << 8))
+#define ata_id_queue_depth(id) (((id)[75] & 0x1f) + 1)
#define ata_id_removeable(id) ((id)[0] & (1 << 7))
#define ata_id_has_dword_io(id) ((id)[50] & (1 << 0))
#define ata_id_u32(id,n) \
@@ -272,6 +298,8 @@ struct ata_taskfile {
((u64) (id)[(n) + 1] << 16) | \
((u64) (id)[(n) + 0]) )
+#define ata_id_cdb_intr(id) (((id)[0] & 0x60) == 0x20)
+
static inline unsigned int ata_id_major_version(const u16 *id)
{
unsigned int mver;
@@ -311,6 +339,15 @@ static inline int is_atapi_taskfile(const struct ata_taskfile *tf)
(tf->protocol == ATA_PROT_ATAPI_DMA);
}
+static inline int is_multi_taskfile(struct ata_taskfile *tf)
+{
+ return (tf->command == ATA_CMD_READ_MULTI) ||
+ (tf->command == ATA_CMD_WRITE_MULTI) ||
+ (tf->command == ATA_CMD_READ_MULTI_EXT) ||
+ (tf->command == ATA_CMD_WRITE_MULTI_EXT) ||
+ (tf->command == ATA_CMD_WRITE_MULTI_FUA_EXT);
+}
+
static inline int ata_ok(u8 status)
{
return ((status & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR))
diff --git a/include/linux/bio.h b/include/linux/bio.h
index b60ffe3..76bdaea 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -47,7 +47,7 @@
#define BIO_BUG_ON
#endif
-#define BIO_MAX_PAGES (256)
+#define BIO_MAX_PAGES 256
#define BIO_MAX_SIZE (BIO_MAX_PAGES << PAGE_CACHE_SHIFT)
#define BIO_MAX_SECTORS (BIO_MAX_SIZE >> 9)
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 3457e7b..aafe827 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -151,11 +151,9 @@ struct request {
void *elevator_private;
void *completion_data;
- unsigned short ioprio;
-
int rq_status; /* should split this into a few status bits */
- struct gendisk *rq_disk;
int errors;
+ struct gendisk *rq_disk;
unsigned long start_time;
/* Number of scatter-gather DMA addr+len pairs after
@@ -170,8 +168,9 @@ struct request {
*/
unsigned short nr_hw_segments;
+ unsigned short ioprio;
+
int tag;
- char *buffer;
int ref_count;
request_queue_t *q;
@@ -179,6 +178,7 @@ struct request {
struct completion *waiting;
void *special;
+ char *buffer;
/*
* when request is used as a packet command carrier
@@ -187,20 +187,14 @@ struct request {
unsigned char cmd[BLK_MAX_CDB];
unsigned int data_len;
- void *data;
-
unsigned int sense_len;
+ void *data;
void *sense;
unsigned int timeout;
int retries;
/*
- * For Power Management requests
- */
- struct request_pm_state *pm;
-
- /*
* completion callback. end_io_data should be folded in with waiting
*/
rq_end_io_fn *end_io;
@@ -241,6 +235,7 @@ enum rq_flag_bits {
__REQ_PM_RESUME, /* resume request */
__REQ_PM_SHUTDOWN, /* shutdown request */
__REQ_ORDERED_COLOR, /* is before or after barrier */
+ __REQ_RW_SYNC, /* request is sync (O_DIRECT) */
__REQ_NR_BITS, /* stops here */
};
@@ -270,6 +265,7 @@ enum rq_flag_bits {
#define REQ_PM_RESUME (1 << __REQ_PM_RESUME)
#define REQ_PM_SHUTDOWN (1 << __REQ_PM_SHUTDOWN)
#define REQ_ORDERED_COLOR (1 << __REQ_ORDERED_COLOR)
+#define REQ_RW_SYNC (1 << __REQ_RW_SYNC)
/*
* State information carried for REQ_PM_SUSPEND and REQ_PM_RESUME
diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h
index eb1a867..a7e8cef 100644
--- a/include/linux/blktrace_api.h
+++ b/include/linux/blktrace_api.h
@@ -90,9 +90,9 @@ struct blk_io_trace {
* The remap event
*/
struct blk_io_trace_remap {
- u32 device;
+ __be32 device;
u32 __pad;
- u64 sector;
+ __be64 sector;
};
enum {
@@ -224,7 +224,7 @@ static inline void blk_add_trace_pdu_int(struct request_queue *q, u32 what,
struct bio *bio, unsigned int pdu)
{
struct blk_trace *bt = q->blk_trace;
- u64 rpdu = cpu_to_be64(pdu);
+ __be64 rpdu = cpu_to_be64(pdu);
if (likely(!bt))
return;
diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h
index da2d107..22866fa 100644
--- a/include/linux/bootmem.h
+++ b/include/linux/bootmem.h
@@ -91,8 +91,8 @@ static inline void *alloc_remap(int nid, unsigned long size)
}
#endif
-extern unsigned long __initdata nr_kernel_pages;
-extern unsigned long __initdata nr_all_pages;
+extern unsigned long nr_kernel_pages;
+extern unsigned long nr_all_pages;
extern void *__init alloc_large_system_hash(const char *tablename,
unsigned long bucketsize,
diff --git a/include/linux/cn_proc.h b/include/linux/cn_proc.h
index 1417de9..dbb7769 100644
--- a/include/linux/cn_proc.h
+++ b/include/linux/cn_proc.h
@@ -3,31 +3,22 @@
*
* Copyright (C) Matt Helsley, IBM Corp. 2005
* Based on cn_fork.h by Nguyen Anh Quynh and Guillaume Thouvenin
- * Original copyright notice follows:
* Copyright (C) 2005 Nguyen Anh Quynh <aquynh@gmail.com>
* Copyright (C) 2005 Guillaume Thouvenin <guillaume.thouvenin@bull.net>
*
- * 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 free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef CN_PROC_H
#define CN_PROC_H
#include <linux/types.h>
-#include <linux/time.h>
-#include <linux/connector.h>
/*
* Userspace sends this enum to register with the kernel that it is listening
diff --git a/include/linux/coda_linux.h b/include/linux/coda_linux.h
index b3ecf8f..7b5c5df 100644
--- a/include/linux/coda_linux.h
+++ b/include/linux/coda_linux.h
@@ -36,7 +36,7 @@ extern const struct file_operations coda_ioctl_operations;
/* operations shared over more than one file */
int coda_open(struct inode *i, struct file *f);
-int coda_flush(struct file *f);
+int coda_flush(struct file *f, fl_owner_t id);
int coda_release(struct inode *i, struct file *f);
int coda_permission(struct inode *inode, int mask, struct nameidata *nd);
int coda_revalidate_inode(struct dentry *);
diff --git a/include/linux/coda_psdev.h b/include/linux/coda_psdev.h
index d539262..98f6c52 100644
--- a/include/linux/coda_psdev.h
+++ b/include/linux/coda_psdev.h
@@ -70,7 +70,7 @@ int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
unsigned int cmd, struct PioctlData *data);
int coda_downcall(int opcode, union outputArgs *out, struct super_block *sb);
int venus_fsync(struct super_block *sb, struct CodaFid *fid);
-int venus_statfs(struct super_block *sb, struct kstatfs *sfs);
+int venus_statfs(struct dentry *dentry, struct kstatfs *sfs);
/* messages between coda filesystem in kernel and Venus */
diff --git a/include/linux/connector.h b/include/linux/connector.h
index ad1a22c..4c02119 100644
--- a/include/linux/connector.h
+++ b/include/linux/connector.h
@@ -34,8 +34,11 @@
#define CN_VAL_PROC 0x1
#define CN_IDX_CIFS 0x2
#define CN_VAL_CIFS 0x1
+#define CN_W1_IDX 0x3 /* w1 communication */
+#define CN_W1_VAL 0x1
-#define CN_NETLINK_USERS 1
+
+#define CN_NETLINK_USERS 4
/*
* Maximum connector's message size.
diff --git a/include/linux/console.h b/include/linux/console.h
index 08734e6..d0f8a80 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -87,6 +87,7 @@ void give_up_console(const struct consw *sw);
#define CON_CONSDEV (2) /* Last on the command line */
#define CON_ENABLED (4)
#define CON_BOOT (8)
+#define CON_ANYTIME (16) /* Safe to call when cpu is offline */
struct console
{
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 5aa9501..466fbe9 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -72,6 +72,8 @@ struct cpufreq_real_policy {
struct cpufreq_policy {
cpumask_t cpus; /* affected CPUs */
+ unsigned int shared_type; /* ANY or ALL affected CPUs
+ should set cpufreq */
unsigned int cpu; /* cpu nr of registered CPU */
struct cpufreq_cpuinfo cpuinfo;/* see above */
@@ -98,6 +100,8 @@ struct cpufreq_policy {
#define CPUFREQ_INCOMPATIBLE (1)
#define CPUFREQ_NOTIFY (2)
+#define CPUFREQ_SHARED_TYPE_ALL (0) /* All dependent CPUs should set freq */
+#define CPUFREQ_SHARED_TYPE_ANY (1) /* Freq can be set from any dependent CPU */
/******************** cpufreq transition notifiers *******************/
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index 9cbb781..b268a3c 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -317,7 +317,8 @@ static inline void __cpus_remap(cpumask_t *dstp, const cpumask_t *srcp,
(cpu) < NR_CPUS; \
(cpu) = next_cpu((cpu), (mask)))
#else /* NR_CPUS == 1 */
-#define for_each_cpu_mask(cpu, mask) for ((cpu) = 0; (cpu) < 1; (cpu)++)
+#define for_each_cpu_mask(cpu, mask) \
+ for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
#endif /* NR_CPUS */
/*
@@ -405,7 +406,6 @@ int __any_online_cpu(const cpumask_t *mask);
#define any_online_cpu(mask) 0
#endif
-#define for_each_cpu(cpu) for_each_cpu_mask((cpu), cpu_possible_map)
#define for_each_possible_cpu(cpu) for_each_cpu_mask((cpu), cpu_possible_map)
#define for_each_online_cpu(cpu) for_each_cpu_mask((cpu), cpu_online_map)
#define for_each_present_cpu(cpu) for_each_cpu_mask((cpu), cpu_present_map)
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 836325e..0dd1610 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -217,7 +217,6 @@ extern struct dentry * d_alloc_anon(struct inode *);
extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
extern void shrink_dcache_sb(struct super_block *);
extern void shrink_dcache_parent(struct dentry *);
-extern void shrink_dcache_anon(struct hlist_head *);
extern int d_invalidate(struct dentry *);
/* only used at mount-time */
diff --git a/include/linux/delay.h b/include/linux/delay.h
index acb7486..17ddb55 100644
--- a/include/linux/delay.h
+++ b/include/linux/delay.h
@@ -25,10 +25,7 @@ extern unsigned long loops_per_jiffy;
#define MAX_UDELAY_MS 5
#endif
-#ifdef notdef
-#define mdelay(n) (\
- {unsigned long __ms=(n); while (__ms--) udelay(1000);})
-#else
+#ifndef mdelay
#define mdelay(n) (\
(__builtin_constant_p(n) && (n)<=MAX_UDELAY_MS) ? udelay((n)*1000) : \
({unsigned long __ms=(n); while (__ms--) udelay(1000);}))
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index 2787b8a..c6a2353 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -88,20 +88,6 @@ typedef enum
#define DMX_PES_PCR DMX_PES_PCR0
-typedef enum
-{
- DMX_SCRAMBLING_EV,
- DMX_FRONTEND_EV
-} dmx_event_t;
-
-
-typedef enum
-{
- DMX_SCRAMBLING_OFF,
- DMX_SCRAMBLING_ON
-} dmx_scrambling_status_t;
-
-
typedef struct dmx_filter
{
__u8 filter[DMX_FILTER_SIZE];
@@ -132,17 +118,6 @@ struct dmx_pes_filter_params
__u32 flags;
};
-
-struct dmx_event
-{
- dmx_event_t event;
- time_t timeStamp;
- union
- {
- dmx_scrambling_status_t scrambling;
- } u;
-};
-
typedef struct dmx_caps {
__u32 caps;
int num_decoders;
@@ -171,7 +146,6 @@ struct dmx_stc {
#define DMX_SET_FILTER _IOW('o', 43, struct dmx_sct_filter_params)
#define DMX_SET_PES_FILTER _IOW('o', 44, struct dmx_pes_filter_params)
#define DMX_SET_BUFFER_SIZE _IO('o', 45)
-#define DMX_GET_EVENT _IOR('o', 46, struct dmx_event)
#define DMX_GET_PES_PIDS _IOR('o', 47, __u16[5])
#define DMX_GET_CAPS _IOR('o', 48, dmx_caps_t)
#define DMX_SET_SOURCE _IOW('o', 49, dmx_source_t)
diff --git a/include/linux/efi.h b/include/linux/efi.h
index e203613..66d621d 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -294,6 +294,7 @@ extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if pos
extern u64 efi_get_iobase (void);
extern u32 efi_mem_type (unsigned long phys_addr);
extern u64 efi_mem_attributes (unsigned long phys_addr);
+extern u64 efi_mem_attribute (unsigned long phys_addr, unsigned long size);
extern int efi_mem_attribute_range (unsigned long phys_addr, unsigned long size,
u64 attr);
extern int __init efi_uart_console_only (void);
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index cf2abec..c6310ae 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -411,6 +411,8 @@ struct ethtool_ops {
#define ETHTOOL_GPERMADDR 0x00000020 /* Get permanent hardware address */
#define ETHTOOL_GUFO 0x00000021 /* Get UFO enable (ethtool_value) */
#define ETHTOOL_SUFO 0x00000022 /* Set UFO enable (ethtool_value) */
+#define ETHTOOL_GGSO 0x00000023 /* Get GSO enable (ethtool_value) */
+#define ETHTOOL_SGSO 0x00000024 /* Set GSO enable (ethtool_value) */
/* compatibility with older code */
#define SPARC_ETH_GSET ETHTOOL_GSET
diff --git a/include/linux/eventpoll.h b/include/linux/eventpoll.h
index 1e4bdfc..84cfa8b 100644
--- a/include/linux/eventpoll.h
+++ b/include/linux/eventpoll.h
@@ -1,6 +1,6 @@
/*
* include/linux/eventpoll.h ( Efficent event polling implementation )
- * Copyright (C) 2001,...,2003 Davide Libenzi
+ * Copyright (C) 2001,...,2006 Davide Libenzi
*
* 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
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
index 757d54d..5607e64 100644
--- a/include/linux/ext3_fs.h
+++ b/include/linux/ext3_fs.h
@@ -710,6 +710,14 @@ struct dir_private_info {
__u32 next_hash;
};
+/* calculate the first block number of the group */
+static inline ext3_fsblk_t
+ext3_group_first_block_no(struct super_block *sb, unsigned long group_no)
+{
+ return group_no * (ext3_fsblk_t)EXT3_BLOCKS_PER_GROUP(sb) +
+ le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block);
+}
+
/*
* Special error return code only used by dx_probe() and its callers.
*/
@@ -730,14 +738,16 @@ struct dir_private_info {
/* balloc.c */
extern int ext3_bg_has_super(struct super_block *sb, int group);
extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group);
-extern int ext3_new_block (handle_t *, struct inode *, unsigned long, int *);
-extern int ext3_new_blocks (handle_t *, struct inode *, unsigned long,
- unsigned long *, int *);
-extern void ext3_free_blocks (handle_t *, struct inode *, unsigned long,
- unsigned long);
-extern void ext3_free_blocks_sb (handle_t *, struct super_block *,
- unsigned long, unsigned long, int *);
-extern unsigned long ext3_count_free_blocks (struct super_block *);
+extern ext3_fsblk_t ext3_new_block (handle_t *handle, struct inode *inode,
+ ext3_fsblk_t goal, int *errp);
+extern ext3_fsblk_t ext3_new_blocks (handle_t *handle, struct inode *inode,
+ ext3_fsblk_t goal, unsigned long *count, int *errp);
+extern void ext3_free_blocks (handle_t *handle, struct inode *inode,
+ ext3_fsblk_t block, unsigned long count);
+extern void ext3_free_blocks_sb (handle_t *handle, struct super_block *sb,
+ ext3_fsblk_t block, unsigned long count,
+ unsigned long *pdquot_freed_blocks);
+extern ext3_fsblk_t ext3_count_free_blocks (struct super_block *);
extern void ext3_check_blocks_bitmap (struct super_block *);
extern struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb,
unsigned int block_group,
@@ -773,7 +783,8 @@ extern unsigned long ext3_count_free (struct buffer_head *, unsigned);
/* inode.c */
-int ext3_forget(handle_t *, int, struct inode *, struct buffer_head *, int);
+int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode,
+ struct buffer_head *bh, ext3_fsblk_t blocknr);
struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *);
struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *);
int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
@@ -808,7 +819,7 @@ extern int ext3_group_add(struct super_block *sb,
struct ext3_new_group_data *input);
extern int ext3_group_extend(struct super_block *sb,
struct ext3_super_block *es,
- unsigned long n_blocks_count);
+ ext3_fsblk_t n_blocks_count);
/* super.c */
extern void ext3_error (struct super_block *, const char *, const char *, ...)
diff --git a/include/linux/ext3_fs_i.h b/include/linux/ext3_fs_i.h
index 7abf901..2f18b95 100644
--- a/include/linux/ext3_fs_i.h
+++ b/include/linux/ext3_fs_i.h
@@ -21,9 +21,17 @@
#include <linux/seqlock.h>
#include <linux/mutex.h>
+/* data type for block offset of block group */
+typedef int ext3_grpblk_t;
+
+/* data type for filesystem-wide blocks number */
+typedef unsigned long ext3_fsblk_t;
+
+#define E3FSBLK "%lu"
+
struct ext3_reserve_window {
- __u32 _rsv_start; /* First byte reserved */
- __u32 _rsv_end; /* Last byte reserved or 0 */
+ ext3_fsblk_t _rsv_start; /* First byte reserved */
+ ext3_fsblk_t _rsv_end; /* Last byte reserved or 0 */
};
struct ext3_reserve_window_node {
@@ -50,7 +58,7 @@ struct ext3_block_alloc_info {
* allocated to this file. This give us the goal (target) for the next
* allocation when we detect linearly ascending requests.
*/
- __u32 last_alloc_physical_block;
+ ext3_fsblk_t last_alloc_physical_block;
};
#define rsv_start rsv_window._rsv_start
@@ -67,7 +75,7 @@ struct ext3_inode_info {
__u8 i_frag_no;
__u8 i_frag_size;
#endif
- __u32 i_file_acl;
+ ext3_fsblk_t i_file_acl;
__u32 i_dir_acl;
__u32 i_dtime;
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 315d897..f128168 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -1,6 +1,7 @@
#ifndef _LINUX_FB_H
#define _LINUX_FB_H
+#include <linux/backlight.h>
#include <asm/types.h>
/* Definitions of frame buffers */
@@ -366,6 +367,12 @@ struct fb_cursor {
struct fb_image image; /* Cursor image */
};
+#ifdef CONFIG_FB_BACKLIGHT
+/* Settings for the generic backlight code */
+#define FB_BACKLIGHT_LEVELS 128
+#define FB_BACKLIGHT_MAX 0xFF
+#endif
+
#ifdef __KERNEL__
#include <linux/fs.h>
@@ -756,6 +763,21 @@ struct fb_info {
struct fb_cmap cmap; /* Current cmap */
struct list_head modelist; /* mode list */
struct fb_videomode *mode; /* current mode */
+
+#ifdef CONFIG_FB_BACKLIGHT
+ /* Lock ordering:
+ * bl_mutex (protects bl_dev and bl_curve)
+ * bl_dev->sem (backlight class)
+ */
+ struct mutex bl_mutex;
+
+ /* assigned backlight device */
+ struct backlight_device *bl_dev;
+
+ /* Backlight level curve */
+ u8 bl_curve[FB_BACKLIGHT_LEVELS];
+#endif
+
struct fb_ops *fbops;
struct device *device;
struct class_device *class_device; /* sysfs per device attrs */
@@ -895,6 +917,7 @@ extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev);
extern void framebuffer_release(struct fb_info *info);
extern int fb_init_class_device(struct fb_info *fb_info);
extern void fb_cleanup_class_device(struct fb_info *head);
+extern void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max);
/* drivers/video/fbmon.c */
#define FB_MAXTIMINGS 0
diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h
index c52a637..996f561 100644
--- a/include/linux/fcntl.h
+++ b/include/linux/fcntl.h
@@ -29,6 +29,7 @@
#define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */
#define AT_REMOVEDIR 0x200 /* Remove directory instead of
unlinking file. */
+#define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */
#ifdef __KERNEL__
diff --git a/include/linux/fs.h b/include/linux/fs.h
index ecc8c2c..2d8b348 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -376,7 +376,8 @@ struct address_space_operations {
struct page* (*get_xip_page)(struct address_space *, sector_t,
int);
/* migrate the contents of a page to the specified target */
- int (*migratepage) (struct page *, struct page *);
+ int (*migratepage) (struct address_space *,
+ struct page *, struct page *);
};
struct backing_dev_info;
@@ -682,6 +683,7 @@ extern spinlock_t files_lock;
#define FL_FLOCK 2
#define FL_ACCESS 8 /* not trying to lock, just looking */
#define FL_LEASE 32 /* lease held on this file */
+#define FL_CLOSE 64 /* unlock on close */
#define FL_SLEEP 128 /* A blocking lock */
/*
@@ -774,7 +776,6 @@ extern int posix_lock_file_conf(struct file *, struct file_lock *, struct file_l
extern int posix_lock_file(struct file *, struct file_lock *);
extern int posix_lock_file_wait(struct file *, struct file_lock *);
extern int posix_unblock_lock(struct file *, struct file_lock *);
-extern int posix_locks_deadlock(struct file_lock *, struct file_lock *);
extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl);
extern int __break_lease(struct inode *inode, unsigned int flags);
extern void lease_get_mtime(struct inode *, struct timespec *time);
@@ -782,7 +783,6 @@ extern int setlease(struct file *, long, struct file_lock **);
extern int lease_modify(struct file_lock **, int);
extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
-extern void steal_locks(fl_owner_t from);
struct fasync_struct {
int magic;
@@ -1025,7 +1025,7 @@ struct file_operations {
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
- int (*flush) (struct file *);
+ int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
@@ -1097,10 +1097,10 @@ struct super_operations {
int (*sync_fs)(struct super_block *sb, int wait);
void (*write_super_lockfs) (struct super_block *);
void (*unlockfs) (struct super_block *);
- int (*statfs) (struct super_block *, struct kstatfs *);
+ int (*statfs) (struct dentry *, struct kstatfs *);
int (*remount_fs) (struct super_block *, int *, char *);
void (*clear_inode) (struct inode *);
- void (*umount_begin) (struct super_block *);
+ void (*umount_begin) (struct vfsmount *, int);
int (*show_options)(struct seq_file *, struct vfsmount *);
int (*show_stats)(struct seq_file *, struct vfsmount *);
@@ -1270,23 +1270,26 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent,
struct file_system_type {
const char *name;
int fs_flags;
- struct super_block *(*get_sb) (struct file_system_type *, int,
- const char *, void *);
+ int (*get_sb) (struct file_system_type *, int,
+ const char *, void *, struct vfsmount *);
void (*kill_sb) (struct super_block *);
struct module *owner;
struct file_system_type * next;
struct list_head fs_supers;
};
-struct super_block *get_sb_bdev(struct file_system_type *fs_type,
+extern int get_sb_bdev(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data,
- int (*fill_super)(struct super_block *, void *, int));
-struct super_block *get_sb_single(struct file_system_type *fs_type,
+ int (*fill_super)(struct super_block *, void *, int),
+ struct vfsmount *mnt);
+extern int get_sb_single(struct file_system_type *fs_type,
int flags, void *data,
- int (*fill_super)(struct super_block *, void *, int));
-struct super_block *get_sb_nodev(struct file_system_type *fs_type,
+ int (*fill_super)(struct super_block *, void *, int),
+ struct vfsmount *mnt);
+extern int get_sb_nodev(struct file_system_type *fs_type,
int flags, void *data,
- int (*fill_super)(struct super_block *, void *, int));
+ int (*fill_super)(struct super_block *, void *, int),
+ struct vfsmount *mnt);
void generic_shutdown_super(struct super_block *sb);
void kill_block_super(struct super_block *sb);
void kill_anon_super(struct super_block *sb);
@@ -1297,8 +1300,10 @@ struct super_block *sget(struct file_system_type *type,
int (*test)(struct super_block *,void *),
int (*set)(struct super_block *,void *),
void *data);
-struct super_block *get_sb_pseudo(struct file_system_type *, char *,
- struct super_operations *ops, unsigned long);
+extern int get_sb_pseudo(struct file_system_type *, char *,
+ struct super_operations *ops, unsigned long,
+ struct vfsmount *mnt);
+extern int simple_set_mnt(struct vfsmount *mnt, struct super_block *sb);
int __put_super(struct super_block *sb);
int __put_super_and_need_restart(struct super_block *sb);
void unnamed_dev_init(void);
@@ -1321,7 +1326,7 @@ extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int);
extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *,
struct vfsmount *);
-extern int vfs_statfs(struct super_block *, struct kstatfs *);
+extern int vfs_statfs(struct dentry *, struct kstatfs *);
/* /sys/fs */
extern struct subsystem fs_subsys;
@@ -1742,7 +1747,7 @@ extern int dcache_dir_close(struct inode *, struct file *);
extern loff_t dcache_dir_lseek(struct file *, loff_t, int);
extern int dcache_readdir(struct file *, void *, filldir_t);
extern int simple_getattr(struct vfsmount *, struct dentry *, struct kstat *);
-extern int simple_statfs(struct super_block *, struct kstatfs *);
+extern int simple_statfs(struct dentry *, struct kstatfs *);
extern int simple_link(struct dentry *, struct inode *, struct dentry *);
extern int simple_unlink(struct inode *, struct dentry *);
extern int simple_rmdir(struct inode *, struct dentry *);
@@ -1762,13 +1767,14 @@ extern struct inode_operations simple_dir_inode_operations;
struct tree_descr { char *name; const struct file_operations *ops; int mode; };
struct dentry *d_alloc_name(struct dentry *, const char *);
extern int simple_fill_super(struct super_block *, int, struct tree_descr *);
-extern int simple_pin_fs(char *name, struct vfsmount **mount, int *count);
+extern int simple_pin_fs(struct file_system_type *, struct vfsmount **mount, int *count);
extern void simple_release_fs(struct vfsmount **mount, int *count);
extern ssize_t simple_read_from_buffer(void __user *, size_t, loff_t *, const void *, size_t);
#ifdef CONFIG_MIGRATION
-extern int buffer_migrate_page(struct page *, struct page *);
+extern int buffer_migrate_page(struct address_space *,
+ struct page *, struct page *);
#else
#define buffer_migrate_page NULL
#endif
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index 5425b60..9fc48a6 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -1,6 +1,6 @@
/*
FUSE: Filesystem in Userspace
- Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
+ Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
@@ -9,18 +9,19 @@
/* This file defines the kernel interface of FUSE */
#include <asm/types.h>
+#include <linux/major.h>
/** Version number of this interface */
#define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 6
+#define FUSE_KERNEL_MINOR_VERSION 7
/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
/** The major number of the fuse character device */
-#define FUSE_MAJOR 10
+#define FUSE_MAJOR MISC_MAJOR
/** The minor number of the fuse character device */
#define FUSE_MINOR 229
@@ -58,6 +59,13 @@ struct fuse_kstatfs {
__u32 spare[6];
};
+struct fuse_file_lock {
+ __u64 start;
+ __u64 end;
+ __u32 type;
+ __u32 pid; /* tgid */
+};
+
/**
* Bitmasks for fuse_setattr_in.valid
*/
@@ -82,6 +90,7 @@ struct fuse_kstatfs {
* INIT request/reply flags
*/
#define FUSE_ASYNC_READ (1 << 0)
+#define FUSE_POSIX_LOCKS (1 << 1)
enum fuse_opcode {
FUSE_LOOKUP = 1,
@@ -112,8 +121,12 @@ enum fuse_opcode {
FUSE_READDIR = 28,
FUSE_RELEASEDIR = 29,
FUSE_FSYNCDIR = 30,
+ FUSE_GETLK = 31,
+ FUSE_SETLK = 32,
+ FUSE_SETLKW = 33,
FUSE_ACCESS = 34,
- FUSE_CREATE = 35
+ FUSE_CREATE = 35,
+ FUSE_INTERRUPT = 36,
};
/* The read buffer is required to be at least 8k, but may be much larger */
@@ -199,6 +212,7 @@ struct fuse_flush_in {
__u64 fh;
__u32 flush_flags;
__u32 padding;
+ __u64 lock_owner;
};
struct fuse_read_in {
@@ -247,6 +261,16 @@ struct fuse_getxattr_out {
__u32 padding;
};
+struct fuse_lk_in {
+ __u64 fh;
+ __u64 owner;
+ struct fuse_file_lock lk;
+};
+
+struct fuse_lk_out {
+ struct fuse_file_lock lk;
+};
+
struct fuse_access_in {
__u32 mask;
__u32 padding;
@@ -268,6 +292,10 @@ struct fuse_init_out {
__u32 max_write;
};
+struct fuse_interrupt_in {
+ __u64 unique;
+};
+
struct fuse_in_header {
__u32 len;
__u32 opcode;
diff --git a/include/linux/genalloc.h b/include/linux/genalloc.h
index 7fd0576..690c428 100644
--- a/include/linux/genalloc.h
+++ b/include/linux/genalloc.h
@@ -4,37 +4,32 @@
* Uses for this includes on-device special memory, uncached memory
* etc.
*
- * This code is based on the buddy allocator found in the sym53c8xx_2
- * driver, adapted for general purpose use.
- *
* This source code is licensed under the GNU General Public License,
* Version 2. See the file COPYING for more details.
*/
-#include <linux/spinlock.h>
-#define ALLOC_MIN_SHIFT 5 /* 32 bytes minimum */
/*
- * Link between free memory chunks of a given size.
+ * General purpose special memory pool descriptor.
*/
-struct gen_pool_link {
- struct gen_pool_link *next;
+struct gen_pool {
+ rwlock_t lock;
+ struct list_head chunks; /* list of chunks in this pool */
+ int min_alloc_order; /* minimum allocation order */
};
/*
- * Memory pool descriptor.
+ * General purpose special memory pool chunk descriptor.
*/
-struct gen_pool {
+struct gen_pool_chunk {
spinlock_t lock;
- unsigned long (*get_new_chunk)(struct gen_pool *);
- struct gen_pool *next;
- struct gen_pool_link *h;
- unsigned long private;
- int max_chunk_shift;
+ struct list_head next_chunk; /* next chunk in pool */
+ unsigned long start_addr; /* starting address of memory chunk */
+ unsigned long end_addr; /* ending address of memory chunk */
+ unsigned long bits[0]; /* bitmap for allocating memory chunk */
};
-unsigned long gen_pool_alloc(struct gen_pool *poolp, int size);
-void gen_pool_free(struct gen_pool *mp, unsigned long ptr, int size);
-struct gen_pool *gen_pool_create(int nr_chunks, int max_chunk_shift,
- unsigned long (*fp)(struct gen_pool *),
- unsigned long data);
+extern struct gen_pool *gen_pool_create(int, int);
+extern int gen_pool_add(struct gen_pool *, unsigned long, size_t, int);
+extern unsigned long gen_pool_alloc(struct gen_pool *, size_t);
+extern void gen_pool_free(struct gen_pool *, unsigned long, size_t);
diff --git a/include/linux/hdlc.h b/include/linux/hdlc.h
index df695e9a..4513f9e 100644
--- a/include/linux/hdlc.h
+++ b/include/linux/hdlc.h
@@ -188,7 +188,7 @@ int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr);
int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
/* Must be used by hardware driver on module startup/exit */
-int register_hdlc_device(struct net_device *dev);
+#define register_hdlc_device(dev) register_netdev(dev)
void unregister_hdlc_device(struct net_device *dev);
struct net_device *alloc_hdlcdev(void *priv);
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 7d2a1b9..07d7305 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -40,7 +40,6 @@ struct hrtimer_base;
/**
* struct hrtimer - the basic hrtimer structure
- *
* @node: red black tree node for time ordered insertion
* @expires: the absolute expiry time in the hrtimers internal
* representation. The time is related to the clock on
@@ -59,7 +58,6 @@ struct hrtimer {
/**
* struct hrtimer_sleeper - simple sleeper structure
- *
* @timer: embedded timer structure
* @task: task to wake up
*
@@ -72,7 +70,6 @@ struct hrtimer_sleeper {
/**
* struct hrtimer_base - the timer base for a specific clock
- *
* @index: clock type index for per_cpu support when moving a timer
* to a base on another cpu.
* @lock: lock protecting the base and associated timers
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 4c5e610..c25a38d 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -23,6 +23,8 @@ int hugetlb_report_node_meminfo(int, char *);
unsigned long hugetlb_total_pages(void);
int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long address, int write_access);
+int hugetlb_reserve_pages(struct inode *inode, long from, long to);
+void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed);
extern unsigned long max_huge_pages;
extern const unsigned long hugetlb_zero, hugetlb_infinity;
@@ -139,8 +141,6 @@ struct hugetlbfs_sb_info {
struct hugetlbfs_inode_info {
struct shared_policy policy;
- /* Protected by the (global) hugetlb_lock */
- unsigned long prereserved_hpages;
struct inode vfs_inode;
};
@@ -157,10 +157,6 @@ static inline struct hugetlbfs_sb_info *HUGETLBFS_SB(struct super_block *sb)
extern const struct file_operations hugetlbfs_file_operations;
extern struct vm_operations_struct hugetlb_vm_ops;
struct file *hugetlb_zero_setup(size_t);
-int hugetlb_extend_reservation(struct hugetlbfs_inode_info *info,
- unsigned long atleast_hpages);
-void hugetlb_truncate_reservation(struct hugetlbfs_inode_info *info,
- unsigned long atmost_hpages);
int hugetlb_get_quota(struct address_space *mapping);
void hugetlb_put_quota(struct address_space *mapping);
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index c8b81f4..21338bb 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -112,6 +112,9 @@
#define I2C_DRIVERID_X1205 82 /* Xicor/Intersil X1205 RTC */
#define I2C_DRIVERID_PCF8563 83 /* Philips PCF8563 RTC */
#define I2C_DRIVERID_RS5C372 84 /* Ricoh RS5C372 RTC */
+#define I2C_DRIVERID_BT866 85 /* Conexant bt866 video encoder */
+#define I2C_DRIVERID_KS0127 86 /* Samsung ks0127 video decoder */
+#define I2C_DRIVERID_TLV320AIC23B 87 /* TI TLV320AIC23B audio codec */
#define I2C_DRIVERID_I2CDEV 900
#define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */
diff --git a/include/linux/i2c-ocores.h b/include/linux/i2c-ocores.h
new file mode 100644
index 0000000..8ed591b
--- /dev/null
+++ b/include/linux/i2c-ocores.h
@@ -0,0 +1,19 @@
+/*
+ * i2c-ocores.h - definitions for the i2c-ocores interface
+ *
+ * Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef _LINUX_I2C_OCORES_H
+#define _LINUX_I2C_OCORES_H
+
+struct ocores_i2c_platform_data {
+ u32 regstep; /* distance between registers */
+ u32 clock_khz; /* input clock in kHz */
+};
+
+#endif /* _LINUX_I2C_OCORES_H */
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 0510430..526ddc8 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -97,13 +97,13 @@ extern s32 i2c_smbus_write_word_data(struct i2c_client * client,
u8 command, u16 value);
extern s32 i2c_smbus_write_block_data(struct i2c_client * client,
u8 command, u8 length,
- u8 *values);
+ const u8 *values);
/* Returns the number of read bytes */
extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client,
u8 command, u8 *values);
extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client,
u8 command, u8 length,
- u8 *values);
+ const u8 *values);
/*
* A driver is capable of handling one or more physical devices present on
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 77e66d0..ef7bef2 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -630,6 +630,7 @@ typedef struct ide_drive_s {
unsigned int usage; /* current "open()" count for drive */
unsigned int failures; /* current failure count */
unsigned int max_failures; /* maximum allowed failure count */
+ u64 probed_capacity;/* initial reported media capacity (ide-cd only currently) */
u64 capacity64; /* total number of sectors */
@@ -1005,6 +1006,8 @@ extern ide_hwif_t ide_hwifs[]; /* master data repository */
extern int noautodma;
extern int ide_end_request (ide_drive_t *drive, int uptodate, int nrsecs);
+int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq,
+ int uptodate, int nr_sectors);
/*
* This is used on exit from the driver to designate the next irq handler
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 9e0fefd..70741e1 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -7,32 +7,13 @@
#include <linux/bitops.h>
#include <linux/preempt.h>
#include <linux/cpumask.h>
+#include <linux/irqreturn.h>
#include <linux/hardirq.h>
#include <linux/sched.h>
#include <asm/atomic.h>
#include <asm/ptrace.h>
#include <asm/system.h>
-/*
- * For 2.4.x compatibility, 2.4.x can use
- *
- * typedef void irqreturn_t;
- * #define IRQ_NONE
- * #define IRQ_HANDLED
- * #define IRQ_RETVAL(x)
- *
- * To mix old-style and new-style irq handler returns.
- *
- * IRQ_NONE means we didn't handle it.
- * IRQ_HANDLED means that we did have a valid interrupt and handled it.
- * IRQ_RETVAL(x) selects on the two depending on x being non-zero (for handled)
- */
-typedef int irqreturn_t;
-
-#define IRQ_NONE (0)
-#define IRQ_HANDLED (1)
-#define IRQ_RETVAL(x) ((x) != 0)
-
struct irqaction {
irqreturn_t (*handler)(int, void *, struct pt_regs *);
unsigned long flags;
diff --git a/include/linux/ioc4.h b/include/linux/ioc4.h
index 3dd18b7..de73a32 100644
--- a/include/linux/ioc4.h
+++ b/include/linux/ioc4.h
@@ -147,6 +147,10 @@ struct ioc4_misc_regs {
#define IOC4_GPCR_EDGE_6 0x40
#define IOC4_GPCR_EDGE_7 0x80
+#define IOC4_VARIANT_IO9 0x0900
+#define IOC4_VARIANT_PCI_RT 0x0901
+#define IOC4_VARIANT_IO10 0x1000
+
/* One of these per IOC4 */
struct ioc4_driver_data {
struct list_head idd_list;
@@ -156,6 +160,7 @@ struct ioc4_driver_data {
struct __iomem ioc4_misc_regs *idd_misc_regs;
unsigned long count_period;
void *idd_serial_data;
+ unsigned int idd_variant;
};
/* One per submodule */
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 42c9cd5..676e00d 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -17,6 +17,7 @@
#include <linux/cache.h>
#include <linux/spinlock.h>
#include <linux/cpumask.h>
+#include <linux/irqreturn.h>
#include <asm/irq.h>
#include <asm/ptrace.h>
@@ -164,10 +165,18 @@ static inline void set_irq_info(int irq, cpumask_t mask)
#endif // CONFIG_SMP
+#ifdef CONFIG_IRQBALANCE
+extern void set_balance_irq_affinity(unsigned int irq, cpumask_t mask);
+#else
+static inline void set_balance_irq_affinity(unsigned int irq, cpumask_t mask)
+{
+}
+#endif
+
extern int no_irq_affinity;
extern int noirqdebug_setup(char *str);
-extern fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
+extern fastcall irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
struct irqaction *action);
extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs);
extern void note_interrupt(unsigned int irq, irq_desc_t *desc,
diff --git a/include/linux/irqreturn.h b/include/linux/irqreturn.h
new file mode 100644
index 0000000..881883c
--- /dev/null
+++ b/include/linux/irqreturn.h
@@ -0,0 +1,25 @@
+/* irqreturn.h */
+#ifndef _LINUX_IRQRETURN_H
+#define _LINUX_IRQRETURN_H
+
+/*
+ * For 2.4.x compatibility, 2.4.x can use
+ *
+ * typedef void irqreturn_t;
+ * #define IRQ_NONE
+ * #define IRQ_HANDLED
+ * #define IRQ_RETVAL(x)
+ *
+ * To mix old-style and new-style irq handler returns.
+ *
+ * IRQ_NONE means we didn't handle it.
+ * IRQ_HANDLED means that we did have a valid interrupt and handled it.
+ * IRQ_RETVAL(x) selects on the two depending on x being non-zero (for handled)
+ */
+typedef int irqreturn_t;
+
+#define IRQ_NONE (0)
+#define IRQ_HANDLED (1)
+#define IRQ_RETVAL(x) ((x) != 0)
+
+#endif
diff --git a/include/linux/jbd.h b/include/linux/jbd.h
index 6a425e3..20eb344 100644
--- a/include/linux/jbd.h
+++ b/include/linux/jbd.h
@@ -501,6 +501,12 @@ struct transaction_s
struct journal_head *t_checkpoint_list;
/*
+ * Doubly-linked circular list of all buffers submitted for IO while
+ * checkpointing. [j_list_lock]
+ */
+ struct journal_head *t_checkpoint_io_list;
+
+ /*
* Doubly-linked circular list of temporary buffers currently undergoing
* IO in the log [j_list_lock]
*/
@@ -849,7 +855,7 @@ extern void journal_commit_transaction(journal_t *);
/* Checkpoint list management */
int __journal_clean_checkpoint_list(journal_t *journal);
-void __journal_remove_checkpoint(struct journal_head *);
+int __journal_remove_checkpoint(struct journal_head *);
void __journal_insert_checkpoint(struct journal_head *, transaction_t *);
/* Buffer IO */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index f4fc576..3c5e4c2 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -24,6 +24,9 @@ extern const char linux_banner[];
#define LONG_MAX ((long)(~0UL>>1))
#define LONG_MIN (-LONG_MAX - 1)
#define ULONG_MAX (~0UL)
+#define LLONG_MAX ((long long)(~0ULL>>1))
+#define LLONG_MIN (-LLONG_MAX - 1)
+#define ULLONG_MAX (~0ULL)
#define STACK_MAGIC 0xdeadbeef
@@ -75,7 +78,7 @@ extern int cond_resched(void);
# define might_sleep() do { might_resched(); } while (0)
#endif
-#define might_sleep_if(cond) do { if (unlikely(cond)) might_sleep(); } while (0)
+#define might_sleep_if(cond) do { if (cond) might_sleep(); } while (0)
#define abs(x) ({ \
int __x = (x); \
@@ -114,6 +117,8 @@ extern int scnprintf(char * buf, size_t size, const char * fmt, ...)
__attribute__ ((format (printf, 3, 4)));
extern int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
__attribute__ ((format (printf, 3, 0)));
+extern char *kasprintf(gfp_t gfp, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
extern int sscanf(const char *, const char *, ...)
__attribute__ ((format (scanf, 2, 3)));
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index cfb3410..6427949 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -106,6 +106,7 @@ extern struct page *kimage_alloc_control_pages(struct kimage *image,
extern void crash_kexec(struct pt_regs *);
int kexec_should_crash(struct task_struct *);
extern struct kimage *kexec_image;
+extern struct kimage *kexec_crash_image;
#define KEXEC_ON_CRASH 0x00000001
#define KEXEC_ARCH_MASK 0xffff0000
diff --git a/include/linux/key.h b/include/linux/key.h
index cbf464a..e81ebf9 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -205,6 +205,11 @@ struct key_type {
/* match a key against a description */
int (*match)(const struct key *key, const void *desc);
+ /* clear some of the data from a key on revokation (optional)
+ * - the key's semaphore will be write-locked by the caller
+ */
+ void (*revoke)(struct key *key);
+
/* clear the data from a key (optional) */
void (*destroy)(struct key *key);
@@ -241,8 +246,9 @@ extern void unregister_key_type(struct key_type *ktype);
extern struct key *key_alloc(struct key_type *type,
const char *desc,
- uid_t uid, gid_t gid, key_perm_t perm,
- int not_in_quota);
+ uid_t uid, gid_t gid,
+ struct task_struct *ctx,
+ key_perm_t perm, int not_in_quota);
extern int key_payload_reserve(struct key *key, size_t datalen);
extern int key_instantiate_and_link(struct key *key,
const void *data,
@@ -292,7 +298,9 @@ extern int key_unlink(struct key *keyring,
struct key *key);
extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
- int not_in_quota, struct key *dest);
+ struct task_struct *ctx,
+ int not_in_quota,
+ struct key *dest);
extern int keyring_clear(struct key *keyring);
@@ -313,7 +321,8 @@ extern void keyring_replace_payload(struct key *key, void *replacement);
* the userspace interface
*/
extern struct key root_user_keyring, root_session_keyring;
-extern int alloc_uid_keyring(struct user_struct *user);
+extern int alloc_uid_keyring(struct user_struct *user,
+ struct task_struct *ctx);
extern void switch_uid_keyring(struct user_struct *new_user);
extern int copy_keys(unsigned long clone_flags, struct task_struct *tsk);
extern int copy_thread_group_keys(struct task_struct *tsk);
@@ -342,7 +351,7 @@ extern void key_init(void);
#define make_key_ref(k) ({ NULL; })
#define key_ref_to_ptr(k) ({ NULL; })
#define is_key_possessed(k) 0
-#define alloc_uid_keyring(u) 0
+#define alloc_uid_keyring(u,c) 0
#define switch_uid_keyring(u) do { } while(0)
#define __install_session_keyring(t, k) ({ NULL; })
#define copy_keys(f,t) 0
@@ -355,6 +364,10 @@ extern void key_init(void);
#define key_fsgid_changed(t) do { } while(0)
#define key_init() do { } while(0)
+/* Initial keyrings */
+extern struct key root_user_keyring;
+extern struct key root_session_keyring;
+
#endif /* CONFIG_KEYS */
#endif /* __KERNEL__ */
#endif /* _LINUX_KEY_H */
diff --git a/include/linux/kthread.h b/include/linux/kthread.h
index ebdd41f..7cce5df 100644
--- a/include/linux/kthread.h
+++ b/include/linux/kthread.h
@@ -4,37 +4,19 @@
#include <linux/err.h>
#include <linux/sched.h>
-/**
- * kthread_create: create a kthread.
- * @threadfn: the function to run until signal_pending(current).
- * @data: data ptr for @threadfn.
- * @namefmt: printf-style name for the thread.
- *
- * Description: This helper function creates and names a kernel
- * thread. The thread will be stopped: use wake_up_process() to start
- * it. See also kthread_run(), kthread_create_on_cpu().
- *
- * When woken, the thread will run @threadfn() with @data as its
- * argument. @threadfn can either call do_exit() directly if it is a
- * standalone thread for which noone will call kthread_stop(), or
- * return when 'kthread_should_stop()' is true (which means
- * kthread_stop() has been called). The return value should be zero
- * or a negative error number: it will be passed to kthread_stop().
- *
- * Returns a task_struct or ERR_PTR(-ENOMEM).
- */
struct task_struct *kthread_create(int (*threadfn)(void *data),
void *data,
const char namefmt[], ...);
/**
- * kthread_run: create and wake a thread.
+ * kthread_run - create and wake a thread.
* @threadfn: the function to run until signal_pending(current).
* @data: data ptr for @threadfn.
* @namefmt: printf-style name for the thread.
*
* Description: Convenient wrapper for kthread_create() followed by
- * wake_up_process(). Returns the kthread, or ERR_PTR(-ENOMEM). */
+ * wake_up_process(). Returns the kthread or ERR_PTR(-ENOMEM).
+ */
#define kthread_run(threadfn, data, namefmt, ...) \
({ \
struct task_struct *__k \
@@ -44,50 +26,9 @@ struct task_struct *kthread_create(int (*threadfn)(void *data),
__k; \
})
-/**
- * kthread_bind: bind a just-created kthread to a cpu.
- * @k: thread created by kthread_create().
- * @cpu: cpu (might not be online, must be possible) for @k to run on.
- *
- * Description: This function is equivalent to set_cpus_allowed(),
- * except that @cpu doesn't need to be online, and the thread must be
- * stopped (ie. just returned from kthread_create().
- */
void kthread_bind(struct task_struct *k, unsigned int cpu);
-
-/**
- * kthread_stop: stop a thread created by kthread_create().
- * @k: thread created by kthread_create().
- *
- * Sets kthread_should_stop() for @k to return true, wakes it, and
- * waits for it to exit. Your threadfn() must not call do_exit()
- * itself if you use this function! This can also be called after
- * kthread_create() instead of calling wake_up_process(): the thread
- * will exit without calling threadfn().
- *
- * Returns the result of threadfn(), or -EINTR if wake_up_process()
- * was never called. */
int kthread_stop(struct task_struct *k);
-
-/**
- * kthread_stop_sem: stop a thread created by kthread_create().
- * @k: thread created by kthread_create().
- * @s: semaphore that @k waits on while idle.
- *
- * Does essentially the same thing as kthread_stop() above, but wakes
- * @k by calling up(@s).
- *
- * Returns the result of threadfn(), or -EINTR if wake_up_process()
- * was never called. */
int kthread_stop_sem(struct task_struct *k, struct semaphore *s);
-
-/**
- * kthread_should_stop: should this kthread return now?
- *
- * When someone calls kthread_stop on your kthread, it will be woken
- * and this will return true. You should then return, and your return
- * value will be passed through to kthread_stop().
- */
int kthread_should_stop(void);
#endif /* _LINUX_KTHREAD_H */
diff --git a/include/linux/ktime.h b/include/linux/ktime.h
index 62bc575..ed3396d 100644
--- a/include/linux/ktime.h
+++ b/include/linux/ktime.h
@@ -66,7 +66,6 @@ typedef union {
/**
* ktime_set - Set a ktime_t variable from a seconds/nanoseconds value
- *
* @secs: seconds to set
* @nsecs: nanoseconds to set
*
@@ -138,7 +137,6 @@ static inline ktime_t ktime_set(const long secs, const unsigned long nsecs)
/**
* ktime_sub - subtract two ktime_t variables
- *
* @lhs: minuend
* @rhs: subtrahend
*
@@ -157,7 +155,6 @@ static inline ktime_t ktime_sub(const ktime_t lhs, const ktime_t rhs)
/**
* ktime_add - add two ktime_t variables
- *
* @add1: addend1
* @add2: addend2
*
@@ -184,7 +181,6 @@ static inline ktime_t ktime_add(const ktime_t add1, const ktime_t add2)
/**
* ktime_add_ns - Add a scalar nanoseconds value to a ktime_t variable
- *
* @kt: addend
* @nsec: the scalar nsec value to add
*
@@ -194,7 +190,6 @@ extern ktime_t ktime_add_ns(const ktime_t kt, u64 nsec);
/**
* timespec_to_ktime - convert a timespec to ktime_t format
- *
* @ts: the timespec variable to convert
*
* Returns a ktime_t variable with the converted timespec value
@@ -207,7 +202,6 @@ static inline ktime_t timespec_to_ktime(const struct timespec ts)
/**
* timeval_to_ktime - convert a timeval to ktime_t format
- *
* @tv: the timeval variable to convert
*
* Returns a ktime_t variable with the converted timeval value
@@ -220,7 +214,6 @@ static inline ktime_t timeval_to_ktime(const struct timeval tv)
/**
* ktime_to_timespec - convert a ktime_t variable to timespec format
- *
* @kt: the ktime_t variable to convert
*
* Returns the timespec representation of the ktime value
@@ -233,7 +226,6 @@ static inline struct timespec ktime_to_timespec(const ktime_t kt)
/**
* ktime_to_timeval - convert a ktime_t variable to timeval format
- *
* @kt: the ktime_t variable to convert
*
* Returns the timeval representation of the ktime value
diff --git a/include/linux/libata.h b/include/linux/libata.h
index b80d2e7..20b1cf5 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -33,6 +33,7 @@
#include <asm/io.h>
#include <linux/ata.h>
#include <linux/workqueue.h>
+#include <scsi/scsi_host.h>
/*
* compile-time options: to be removed as soon as all the drivers are
@@ -44,7 +45,6 @@
#undef ATA_NDEBUG /* define to disable quick runtime checks */
#undef ATA_ENABLE_PATA /* define to enable PATA support in some
* low-level drivers */
-#undef ATAPI_ENABLE_DMADIR /* enables ATAPI DMADIR bridge support */
/* note: prints function name for you */
@@ -108,8 +108,11 @@ enum {
LIBATA_MAX_PRD = ATA_MAX_PRD / 2,
ATA_MAX_PORTS = 8,
ATA_DEF_QUEUE = 1,
- ATA_MAX_QUEUE = 1,
+ /* tag ATA_MAX_QUEUE - 1 is reserved for internal commands */
+ ATA_MAX_QUEUE = 32,
+ ATA_TAG_INTERNAL = ATA_MAX_QUEUE - 1,
ATA_MAX_SECTORS = 200, /* FIXME */
+ ATA_MAX_SECTORS_LBA48 = 65535,
ATA_MAX_BUS = 2,
ATA_DEF_BUSY_WAIT = 10000,
ATA_SHORT_PAUSE = (HZ >> 6) + 1,
@@ -120,9 +123,17 @@ enum {
ATA_SHT_USE_CLUSTERING = 1,
/* struct ata_device stuff */
- ATA_DFLAG_LBA48 = (1 << 0), /* device supports LBA48 */
- ATA_DFLAG_PIO = (1 << 1), /* device currently in PIO mode */
- ATA_DFLAG_LBA = (1 << 2), /* device supports LBA */
+ ATA_DFLAG_LBA = (1 << 0), /* device supports LBA */
+ ATA_DFLAG_LBA48 = (1 << 1), /* device supports LBA48 */
+ ATA_DFLAG_CDB_INTR = (1 << 2), /* device asserts INTRQ when ready for CDB */
+ ATA_DFLAG_NCQ = (1 << 3), /* device supports NCQ */
+ ATA_DFLAG_CFG_MASK = (1 << 8) - 1,
+
+ ATA_DFLAG_PIO = (1 << 8), /* device currently in PIO mode */
+ ATA_DFLAG_INIT_MASK = (1 << 16) - 1,
+
+ ATA_DFLAG_DETACH = (1 << 16),
+ ATA_DFLAG_DETACHED = (1 << 17),
ATA_DEV_UNKNOWN = 0, /* unknown device */
ATA_DEV_ATA = 1, /* ATA device */
@@ -132,43 +143,57 @@ enum {
ATA_DEV_NONE = 5, /* no device */
/* struct ata_port flags */
- ATA_FLAG_SLAVE_POSS = (1 << 1), /* host supports slave dev */
+ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */
/* (doesn't imply presence) */
- ATA_FLAG_PORT_DISABLED = (1 << 2), /* port is disabled, ignore it */
- ATA_FLAG_SATA = (1 << 3),
- ATA_FLAG_NO_LEGACY = (1 << 4), /* no legacy mode check */
- ATA_FLAG_SRST = (1 << 5), /* (obsolete) use ATA SRST, not E.D.D. */
- ATA_FLAG_MMIO = (1 << 6), /* use MMIO, not PIO */
- ATA_FLAG_SATA_RESET = (1 << 7), /* (obsolete) use COMRESET */
- ATA_FLAG_PIO_DMA = (1 << 8), /* PIO cmds via DMA */
- ATA_FLAG_NOINTR = (1 << 9), /* FIXME: Remove this once
- * proper HSM is in place. */
- ATA_FLAG_DEBUGMSG = (1 << 10),
- ATA_FLAG_NO_ATAPI = (1 << 11), /* No ATAPI support */
-
- ATA_FLAG_SUSPENDED = (1 << 12), /* port is suspended */
-
- ATA_FLAG_PIO_LBA48 = (1 << 13), /* Host DMA engine is LBA28 only */
- ATA_FLAG_IRQ_MASK = (1 << 14), /* Mask IRQ in PIO xfers */
-
- ATA_FLAG_FLUSH_PORT_TASK = (1 << 15), /* Flush port task */
- ATA_FLAG_IN_EH = (1 << 16), /* EH in progress */
-
- ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */
- ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */
- ATA_QCFLAG_SINGLE = (1 << 4), /* no s/g, just a single buffer */
+ ATA_FLAG_SATA = (1 << 1),
+ ATA_FLAG_NO_LEGACY = (1 << 2), /* no legacy mode check */
+ ATA_FLAG_MMIO = (1 << 3), /* use MMIO, not PIO */
+ ATA_FLAG_SRST = (1 << 4), /* (obsolete) use ATA SRST, not E.D.D. */
+ ATA_FLAG_SATA_RESET = (1 << 5), /* (obsolete) use COMRESET */
+ ATA_FLAG_NO_ATAPI = (1 << 6), /* No ATAPI support */
+ ATA_FLAG_PIO_DMA = (1 << 7), /* PIO cmds via DMA */
+ ATA_FLAG_PIO_LBA48 = (1 << 8), /* Host DMA engine is LBA28 only */
+ ATA_FLAG_PIO_POLLING = (1 << 9), /* use polling PIO if LLD
+ * doesn't handle PIO interrupts */
+ ATA_FLAG_NCQ = (1 << 10), /* host supports NCQ */
+ ATA_FLAG_HRST_TO_RESUME = (1 << 11), /* hardreset to resume phy */
+ ATA_FLAG_SKIP_D2H_BSY = (1 << 12), /* can't wait for the first D2H
+ * Register FIS clearing BSY */
+
+ ATA_FLAG_DEBUGMSG = (1 << 13),
+ ATA_FLAG_FLUSH_PORT_TASK = (1 << 14), /* flush port task */
+
+ ATA_FLAG_EH_PENDING = (1 << 15), /* EH pending */
+ ATA_FLAG_EH_IN_PROGRESS = (1 << 16), /* EH in progress */
+ ATA_FLAG_FROZEN = (1 << 17), /* port is frozen */
+ ATA_FLAG_RECOVERED = (1 << 18), /* recovery action performed */
+ ATA_FLAG_LOADING = (1 << 19), /* boot/loading probe */
+ ATA_FLAG_UNLOADING = (1 << 20), /* module is unloading */
+ ATA_FLAG_SCSI_HOTPLUG = (1 << 21), /* SCSI hotplug scheduled */
+
+ ATA_FLAG_DISABLED = (1 << 22), /* port is disabled, ignore it */
+ ATA_FLAG_SUSPENDED = (1 << 23), /* port is suspended (power) */
+
+ /* bits 24:31 of ap->flags are reserved for LLDD specific flags */
+
+ /* struct ata_queued_cmd flags */
+ ATA_QCFLAG_ACTIVE = (1 << 0), /* cmd not yet ack'd to scsi lyer */
+ ATA_QCFLAG_SG = (1 << 1), /* have s/g table? */
+ ATA_QCFLAG_SINGLE = (1 << 2), /* no s/g, just a single buffer */
ATA_QCFLAG_DMAMAP = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE,
- ATA_QCFLAG_EH_SCHEDULED = (1 << 5), /* EH scheduled */
+ ATA_QCFLAG_IO = (1 << 3), /* standard IO command */
+ ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */
+
+ ATA_QCFLAG_FAILED = (1 << 16), /* cmd failed and is owned by EH */
+ ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */
+ ATA_QCFLAG_EH_SCHEDULED = (1 << 18), /* EH scheduled (obsolete) */
/* host set flags */
ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host_set only */
/* various lengths of time */
- ATA_TMOUT_PIO = 30 * HZ,
ATA_TMOUT_BOOT = 30 * HZ, /* heuristic */
ATA_TMOUT_BOOT_QUICK = 7 * HZ, /* heuristic */
- ATA_TMOUT_CDB = 30 * HZ,
- ATA_TMOUT_CDB_QUICK = 5 * HZ,
ATA_TMOUT_INTERNAL = 30 * HZ,
ATA_TMOUT_INTERNAL_QUICK = 5 * HZ,
@@ -207,21 +232,56 @@ enum {
/* size of buffer to pad xfers ending on unaligned boundaries */
ATA_DMA_PAD_SZ = 4,
ATA_DMA_PAD_BUF_SZ = ATA_DMA_PAD_SZ * ATA_MAX_QUEUE,
-
- /* Masks for port functions */
+
+ /* masks for port functions */
ATA_PORT_PRIMARY = (1 << 0),
ATA_PORT_SECONDARY = (1 << 1),
+
+ /* ering size */
+ ATA_ERING_SIZE = 32,
+
+ /* desc_len for ata_eh_info and context */
+ ATA_EH_DESC_LEN = 80,
+
+ /* reset / recovery action types */
+ ATA_EH_REVALIDATE = (1 << 0),
+ ATA_EH_SOFTRESET = (1 << 1),
+ ATA_EH_HARDRESET = (1 << 2),
+
+ ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET,
+ ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE,
+
+ /* ata_eh_info->flags */
+ ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */
+
+ ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */
+
+ /* max repeat if error condition is still set after ->error_handler */
+ ATA_EH_MAX_REPEAT = 5,
+
+ /* how hard are we gonna try to probe/recover devices */
+ ATA_PROBE_MAX_TRIES = 3,
+ ATA_EH_RESET_TRIES = 3,
+ ATA_EH_DEV_TRIES = 3,
+
+ /* Drive spinup time (time from power-on to the first D2H FIS)
+ * in msecs - 8s currently. Failing to get ready in this time
+ * isn't critical. It will result in reset failure for
+ * controllers which can't wait for the first D2H FIS. libata
+ * will retry, so it just has to be long enough to spin up
+ * most devices.
+ */
+ ATA_SPINUP_WAIT = 8000,
};
enum hsm_task_states {
- HSM_ST_UNKNOWN,
- HSM_ST_IDLE,
- HSM_ST_POLL,
- HSM_ST_TMOUT,
- HSM_ST,
- HSM_ST_LAST,
- HSM_ST_LAST_POLL,
- HSM_ST_ERR,
+ HSM_ST_UNKNOWN, /* state unknown */
+ HSM_ST_IDLE, /* no command on going */
+ HSM_ST, /* (waiting the device to) transfer data */
+ HSM_ST_LAST, /* (waiting the device to) complete command */
+ HSM_ST_ERR, /* error */
+ HSM_ST_FIRST, /* (waiting the device to)
+ write CDB or first data block */
};
enum ata_completion_errors {
@@ -244,9 +304,9 @@ struct ata_queued_cmd;
/* typedefs */
typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc);
-typedef void (*ata_probeinit_fn_t)(struct ata_port *);
-typedef int (*ata_reset_fn_t)(struct ata_port *, int, unsigned int *);
-typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *);
+typedef int (*ata_prereset_fn_t)(struct ata_port *ap);
+typedef int (*ata_reset_fn_t)(struct ata_port *ap, unsigned int *classes);
+typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *classes);
struct ata_ioports {
unsigned long cmd_addr;
@@ -297,7 +357,8 @@ struct ata_host_set {
unsigned long flags;
int simplex_claimed; /* Keep seperate in case we
ever need to do this locked */
- struct ata_port * ports[0];
+ struct ata_host_set *next; /* for legacy mode */
+ struct ata_port *ports[0];
};
struct ata_queued_cmd {
@@ -336,7 +397,7 @@ struct ata_queued_cmd {
struct scatterlist *__sg;
unsigned int err_mask;
-
+ struct ata_taskfile result_tf;
ata_qc_cb_t complete_fn;
void *private_data;
@@ -348,12 +409,26 @@ struct ata_host_stats {
unsigned long rw_reqbuf;
};
+struct ata_ering_entry {
+ int is_io;
+ unsigned int err_mask;
+ u64 timestamp;
+};
+
+struct ata_ering {
+ int cursor;
+ struct ata_ering_entry ring[ATA_ERING_SIZE];
+};
+
struct ata_device {
- u64 n_sectors; /* size of device, if ATA */
+ struct ata_port *ap;
+ unsigned int devno; /* 0 or 1 */
unsigned long flags; /* ATA_DFLAG_xxx */
+ struct scsi_device *sdev; /* attached SCSI device */
+ /* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */
+ u64 n_sectors; /* size of device, if ATA */
unsigned int class; /* ATA_DEV_xxx */
- unsigned int devno; /* 0 or 1 */
- u16 *id; /* IDENTIFY xxx DEVICE data */
+ u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
u8 pio_mode;
u8 dma_mode;
u8 xfer_mode;
@@ -373,11 +448,42 @@ struct ata_device {
u16 cylinders; /* Number of cylinders */
u16 heads; /* Number of heads */
u16 sectors; /* Number of sectors per track */
+
+ /* error history */
+ struct ata_ering ering;
+};
+
+/* Offset into struct ata_device. Fields above it are maintained
+ * acress device init. Fields below are zeroed.
+ */
+#define ATA_DEVICE_CLEAR_OFFSET offsetof(struct ata_device, n_sectors)
+
+struct ata_eh_info {
+ struct ata_device *dev; /* offending device */
+ u32 serror; /* SError from LLDD */
+ unsigned int err_mask; /* port-wide err_mask */
+ unsigned int action; /* ATA_EH_* action mask */
+ unsigned int dev_action[ATA_MAX_DEVICES]; /* dev EH action */
+ unsigned int flags; /* ATA_EHI_* flags */
+
+ unsigned long hotplug_timestamp;
+ unsigned int probe_mask;
+
+ char desc[ATA_EH_DESC_LEN];
+ int desc_len;
+};
+
+struct ata_eh_context {
+ struct ata_eh_info i;
+ int tries[ATA_MAX_DEVICES];
+ unsigned int classes[ATA_MAX_DEVICES];
+ unsigned int did_probe_mask;
};
struct ata_port {
struct Scsi_Host *host; /* our co-allocated scsi host */
const struct ata_port_operations *ops;
+ spinlock_t *lock;
unsigned long flags; /* ATA_FLAG_xxx */
unsigned int id; /* unique id req'd by scsi midlyr */
unsigned int port_no; /* unique port #; from zero */
@@ -397,26 +503,40 @@ struct ata_port {
unsigned int mwdma_mask;
unsigned int udma_mask;
unsigned int cbl; /* cable type; ATA_CBL_xxx */
+ unsigned int hw_sata_spd_limit;
+ unsigned int sata_spd_limit; /* SATA PHY speed limit */
+
+ /* record runtime error info, protected by host_set lock */
+ struct ata_eh_info eh_info;
+ /* EH context owned by EH */
+ struct ata_eh_context eh_context;
struct ata_device device[ATA_MAX_DEVICES];
struct ata_queued_cmd qcmd[ATA_MAX_QUEUE];
- unsigned long qactive;
+ unsigned long qc_allocated;
+ unsigned int qc_active;
+
unsigned int active_tag;
+ u32 sactive;
struct ata_host_stats stats;
struct ata_host_set *host_set;
struct device *dev;
struct work_struct port_task;
+ struct work_struct hotplug_task;
+ struct work_struct scsi_rescan_task;
unsigned int hsm_task_state;
- unsigned long pio_task_timeout;
u32 msg_enable;
struct list_head eh_done_q;
+ wait_queue_head_t eh_wait_q;
void *private_data;
+
+ u8 sector_buf[ATA_SECT_SIZE]; /* owned by EH */
};
struct ata_port_operations {
@@ -438,7 +558,6 @@ struct ata_port_operations {
void (*phy_reset) (struct ata_port *ap); /* obsolete */
void (*set_mode) (struct ata_port *ap);
- int (*probe_reset) (struct ata_port *ap, unsigned int *classes);
void (*post_set_mode) (struct ata_port *ap);
@@ -447,10 +566,20 @@ struct ata_port_operations {
void (*bmdma_setup) (struct ata_queued_cmd *qc);
void (*bmdma_start) (struct ata_queued_cmd *qc);
+ void (*data_xfer) (struct ata_device *, unsigned char *, unsigned int, int);
+
void (*qc_prep) (struct ata_queued_cmd *qc);
unsigned int (*qc_issue) (struct ata_queued_cmd *qc);
- void (*eng_timeout) (struct ata_port *ap);
+ /* Error handlers. ->error_handler overrides ->eng_timeout and
+ * indicates that new-style EH is in place.
+ */
+ void (*eng_timeout) (struct ata_port *ap); /* obsolete */
+
+ void (*freeze) (struct ata_port *ap);
+ void (*thaw) (struct ata_port *ap);
+ void (*error_handler) (struct ata_port *ap);
+ void (*post_internal_cmd) (struct ata_queued_cmd *qc);
irqreturn_t (*irq_handler)(int, void *, struct pt_regs *);
void (*irq_clear) (struct ata_port *);
@@ -492,22 +621,22 @@ struct ata_timing {
#define FIT(v,vmin,vmax) max_t(short,min_t(short,v,vmax),vmin)
+extern const unsigned long sata_deb_timing_boot[];
+extern const unsigned long sata_deb_timing_eh[];
+extern const unsigned long sata_deb_timing_before_fsrst[];
+
extern void ata_port_probe(struct ata_port *);
extern void __sata_phy_reset(struct ata_port *ap);
extern void sata_phy_reset(struct ata_port *ap);
extern void ata_bus_reset(struct ata_port *ap);
-extern int ata_drive_probe_reset(struct ata_port *ap,
- ata_probeinit_fn_t probeinit,
- ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
- ata_postreset_fn_t postreset, unsigned int *classes);
-extern void ata_std_probeinit(struct ata_port *ap);
-extern int ata_std_softreset(struct ata_port *ap, int verbose,
- unsigned int *classes);
-extern int sata_std_hardreset(struct ata_port *ap, int verbose,
- unsigned int *class);
+extern int sata_set_spd(struct ata_port *ap);
+extern int sata_phy_debounce(struct ata_port *ap, const unsigned long *param);
+extern int sata_phy_resume(struct ata_port *ap, const unsigned long *param);
+extern int ata_std_prereset(struct ata_port *ap);
+extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes);
+extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class);
extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes);
-extern int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev,
- int post_reset);
+extern int ata_dev_revalidate(struct ata_device *dev, int post_reset);
extern void ata_port_disable(struct ata_port *);
extern void ata_std_ports(struct ata_ioports *ioaddr);
#ifdef CONFIG_PCI
@@ -519,24 +648,32 @@ extern int ata_pci_device_resume(struct pci_dev *pdev);
extern int ata_pci_clear_simplex(struct pci_dev *pdev);
#endif /* CONFIG_PCI */
extern int ata_device_add(const struct ata_probe_ent *ent);
+extern void ata_port_detach(struct ata_port *ap);
extern void ata_host_set_remove(struct ata_host_set *host_set);
extern int ata_scsi_detect(struct scsi_host_template *sht);
extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
-extern void ata_eh_qc_complete(struct ata_queued_cmd *qc);
-extern void ata_eh_qc_retry(struct ata_queued_cmd *qc);
extern int ata_scsi_release(struct Scsi_Host *host);
extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
+extern int sata_scr_valid(struct ata_port *ap);
+extern int sata_scr_read(struct ata_port *ap, int reg, u32 *val);
+extern int sata_scr_write(struct ata_port *ap, int reg, u32 val);
+extern int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val);
+extern int ata_port_online(struct ata_port *ap);
+extern int ata_port_offline(struct ata_port *ap);
extern int ata_scsi_device_resume(struct scsi_device *);
extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state);
-extern int ata_device_resume(struct ata_port *, struct ata_device *);
-extern int ata_device_suspend(struct ata_port *, struct ata_device *, pm_message_t state);
+extern int ata_device_resume(struct ata_device *);
+extern int ata_device_suspend(struct ata_device *, pm_message_t state);
extern int ata_ratelimit(void);
extern unsigned int ata_busy_sleep(struct ata_port *ap,
unsigned long timeout_pat,
unsigned long timeout);
extern void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *),
void *data, unsigned long delay);
+extern u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
+ unsigned long interval_msec,
+ unsigned long timeout_msec);
/*
* Default driver ops implementations
@@ -550,11 +687,16 @@ extern void ata_std_dev_select (struct ata_port *ap, unsigned int device);
extern u8 ata_check_status(struct ata_port *ap);
extern u8 ata_altstatus(struct ata_port *ap);
extern void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf);
-extern int ata_std_probe_reset(struct ata_port *ap, unsigned int *classes);
extern int ata_port_start (struct ata_port *ap);
extern void ata_port_stop (struct ata_port *ap);
extern void ata_host_stop (struct ata_host_set *host_set);
extern irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+extern void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
+ unsigned int buflen, int write_data);
+extern void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
+ unsigned int buflen, int write_data);
+extern void ata_pio_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
+ unsigned int buflen, int write_data);
extern void ata_qc_prep(struct ata_queued_cmd *qc);
extern void ata_noop_qc_prep(struct ata_queued_cmd *qc);
extern unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc);
@@ -572,17 +714,29 @@ extern void ata_bmdma_start (struct ata_queued_cmd *qc);
extern void ata_bmdma_stop(struct ata_queued_cmd *qc);
extern u8 ata_bmdma_status(struct ata_port *ap);
extern void ata_bmdma_irq_clear(struct ata_port *ap);
-extern void __ata_qc_complete(struct ata_queued_cmd *qc);
-extern void ata_eng_timeout(struct ata_port *ap);
-extern void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev,
- struct scsi_cmnd *cmd,
+extern void ata_bmdma_freeze(struct ata_port *ap);
+extern void ata_bmdma_thaw(struct ata_port *ap);
+extern void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
+ ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset,
+ ata_postreset_fn_t postreset);
+extern void ata_bmdma_error_handler(struct ata_port *ap);
+extern void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc);
+extern int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
+ u8 status, int in_wq);
+extern void ata_qc_complete(struct ata_queued_cmd *qc);
+extern int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active,
+ void (*finish_qc)(struct ata_queued_cmd *));
+extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *));
extern int ata_std_bios_param(struct scsi_device *sdev,
struct block_device *bdev,
sector_t capacity, int geom[]);
extern int ata_scsi_slave_config(struct scsi_device *sdev);
-extern struct ata_device *ata_dev_pair(struct ata_port *ap,
- struct ata_device *adev);
+extern void ata_scsi_slave_destroy(struct scsi_device *sdev);
+extern int ata_scsi_change_queue_depth(struct scsi_device *sdev,
+ int queue_depth);
+extern struct ata_device *ata_dev_pair(struct ata_device *adev);
/*
* Timing helpers
@@ -628,7 +782,64 @@ extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bit
extern unsigned long ata_pci_default_filter(const struct ata_port *, struct ata_device *, unsigned long);
#endif /* CONFIG_PCI */
+/*
+ * EH
+ */
+extern void ata_eng_timeout(struct ata_port *ap);
+
+extern void ata_port_schedule_eh(struct ata_port *ap);
+extern int ata_port_abort(struct ata_port *ap);
+extern int ata_port_freeze(struct ata_port *ap);
+
+extern void ata_eh_freeze_port(struct ata_port *ap);
+extern void ata_eh_thaw_port(struct ata_port *ap);
+
+extern void ata_eh_qc_complete(struct ata_queued_cmd *qc);
+extern void ata_eh_qc_retry(struct ata_queued_cmd *qc);
+
+extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
+ ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+ ata_postreset_fn_t postreset);
+
+/*
+ * printk helpers
+ */
+#define ata_port_printk(ap, lv, fmt, args...) \
+ printk(lv"ata%u: "fmt, (ap)->id , ##args)
+
+#define ata_dev_printk(dev, lv, fmt, args...) \
+ printk(lv"ata%u.%02u: "fmt, (dev)->ap->id, (dev)->devno , ##args)
+
+/*
+ * ata_eh_info helpers
+ */
+#define ata_ehi_push_desc(ehi, fmt, args...) do { \
+ (ehi)->desc_len += scnprintf((ehi)->desc + (ehi)->desc_len, \
+ ATA_EH_DESC_LEN - (ehi)->desc_len, \
+ fmt , ##args); \
+} while (0)
+
+#define ata_ehi_clear_desc(ehi) do { \
+ (ehi)->desc[0] = '\0'; \
+ (ehi)->desc_len = 0; \
+} while (0)
+
+static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi)
+{
+ if (ehi->flags & ATA_EHI_HOTPLUGGED)
+ return;
+
+ ehi->flags |= ATA_EHI_HOTPLUGGED;
+ ehi->hotplug_timestamp = jiffies;
+ ehi->err_mask |= AC_ERR_ATA_BUS;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
+}
+
+/*
+ * qc helpers
+ */
static inline int
ata_sg_is_last(struct scatterlist *sg, struct ata_queued_cmd *qc)
{
@@ -671,14 +882,39 @@ static inline unsigned int ata_tag_valid(unsigned int tag)
return (tag < ATA_MAX_QUEUE) ? 1 : 0;
}
-static inline unsigned int ata_class_present(unsigned int class)
+static inline unsigned int ata_tag_internal(unsigned int tag)
+{
+ return tag == ATA_MAX_QUEUE - 1;
+}
+
+static inline unsigned int ata_class_enabled(unsigned int class)
{
return class == ATA_DEV_ATA || class == ATA_DEV_ATAPI;
}
-static inline unsigned int ata_dev_present(const struct ata_device *dev)
+static inline unsigned int ata_class_disabled(unsigned int class)
{
- return ata_class_present(dev->class);
+ return class == ATA_DEV_ATA_UNSUP || class == ATA_DEV_ATAPI_UNSUP;
+}
+
+static inline unsigned int ata_class_absent(unsigned int class)
+{
+ return !ata_class_enabled(class) && !ata_class_disabled(class);
+}
+
+static inline unsigned int ata_dev_enabled(const struct ata_device *dev)
+{
+ return ata_class_enabled(dev->class);
+}
+
+static inline unsigned int ata_dev_disabled(const struct ata_device *dev)
+{
+ return ata_class_disabled(dev->class);
+}
+
+static inline unsigned int ata_dev_absent(const struct ata_device *dev)
+{
+ return ata_class_absent(dev->class);
}
static inline u8 ata_chk_status(struct ata_port *ap)
@@ -759,20 +995,35 @@ static inline void ata_qc_set_polling(struct ata_queued_cmd *qc)
qc->tf.ctl |= ATA_NIEN;
}
-static inline struct ata_queued_cmd *ata_qc_from_tag (struct ata_port *ap,
- unsigned int tag)
+static inline struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap,
+ unsigned int tag)
{
if (likely(ata_tag_valid(tag)))
return &ap->qcmd[tag];
return NULL;
}
-static inline void ata_tf_init(struct ata_port *ap, struct ata_taskfile *tf, unsigned int device)
+static inline struct ata_queued_cmd *ata_qc_from_tag(struct ata_port *ap,
+ unsigned int tag)
+{
+ struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
+
+ if (unlikely(!qc) || !ap->ops->error_handler)
+ return qc;
+
+ if ((qc->flags & (ATA_QCFLAG_ACTIVE |
+ ATA_QCFLAG_FAILED)) == ATA_QCFLAG_ACTIVE)
+ return qc;
+
+ return NULL;
+}
+
+static inline void ata_tf_init(struct ata_device *dev, struct ata_taskfile *tf)
{
memset(tf, 0, sizeof(*tf));
- tf->ctl = ap->ctl;
- if (device == 0)
+ tf->ctl = dev->ap->ctl;
+ if (dev->devno == 0)
tf->device = ATA_DEVICE_OBS;
else
tf->device = ATA_DEVICE_OBS | ATA_DEV1;
@@ -787,26 +1038,11 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc)
qc->nbytes = qc->curbytes = 0;
qc->err_mask = 0;
- ata_tf_init(qc->ap, &qc->tf, qc->dev->devno);
-}
-
-/**
- * ata_qc_complete - Complete an active ATA command
- * @qc: Command to complete
- * @err_mask: ATA Status register contents
- *
- * Indicate to the mid and upper layers that an ATA
- * command has completed, with either an ok or not-ok status.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-static inline void ata_qc_complete(struct ata_queued_cmd *qc)
-{
- if (unlikely(qc->flags & ATA_QCFLAG_EH_SCHEDULED))
- return;
+ ata_tf_init(qc->dev, &qc->tf);
- __ata_qc_complete(qc);
+ /* init result_tf such that it indicates normal completion */
+ qc->result_tf.command = ATA_DRDY;
+ qc->result_tf.feature = 0;
}
/**
@@ -885,28 +1121,6 @@ static inline u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq)
return status;
}
-static inline u32 scr_read(struct ata_port *ap, unsigned int reg)
-{
- return ap->ops->scr_read(ap, reg);
-}
-
-static inline void scr_write(struct ata_port *ap, unsigned int reg, u32 val)
-{
- ap->ops->scr_write(ap, reg, val);
-}
-
-static inline void scr_write_flush(struct ata_port *ap, unsigned int reg,
- u32 val)
-{
- ap->ops->scr_write(ap, reg, val);
- (void) ap->ops->scr_read(ap, reg);
-}
-
-static inline unsigned int sata_dev_present(struct ata_port *ap)
-{
- return ((scr_read(ap, SCR_STATUS) & 0xf) == 0x3) ? 1 : 0;
-}
-
static inline int ata_try_flush_cache(const struct ata_device *dev)
{
return ata_id_wcache_enabled(dev->id) ||
@@ -916,7 +1130,7 @@ static inline int ata_try_flush_cache(const struct ata_device *dev)
static inline unsigned int ac_err_mask(u8 status)
{
- if (status & ATA_BUSY)
+ if (status & (ATA_BUSY | ATA_DRQ))
return AC_ERR_HSM;
if (status & (ATA_ERR | ATA_DF))
return AC_ERR_DEV;
@@ -944,4 +1158,9 @@ static inline void ata_pad_free(struct ata_port *ap, struct device *dev)
dma_free_coherent(dev, ATA_DMA_PAD_BUF_SZ, ap->pad, ap->pad_dma);
}
+static inline struct ata_port *ata_shost_to_port(struct Scsi_Host *host)
+{
+ return (struct ata_port *) &host->hostdata[0];
+}
+
#endif /* __LINUX_LIBATA_H__ */
diff --git a/include/linux/list.h b/include/linux/list.h
index 76f0571..37ca31b 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -197,12 +197,35 @@ static inline void list_del_rcu(struct list_head *entry)
entry->prev = LIST_POISON2;
}
+/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ * Note: if 'old' was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+ struct list_head *new)
+{
+ new->next = old->next;
+ new->next->prev = new;
+ new->prev = old->prev;
+ new->prev->next = new;
+}
+
+static inline void list_replace_init(struct list_head *old,
+ struct list_head *new)
+{
+ list_replace(old, new);
+ INIT_LIST_HEAD(old);
+}
+
/*
* list_replace_rcu - replace old entry by new one
* @old : the element to be replaced
* @new : the new element to insert
*
* The old entry will be replaced with the new entry atomically.
+ * Note: 'old' should not be empty.
*/
static inline void list_replace_rcu(struct list_head *old,
struct list_head *new)
@@ -258,16 +281,17 @@ static inline int list_empty(const struct list_head *head)
}
/**
- * list_empty_careful - tests whether a list is
- * empty _and_ checks that no other CPU might be
- * in the process of still modifying either member
+ * list_empty_careful - tests whether a list is empty and not being modified
+ * @head: the list to test
+ *
+ * Description:
+ * tests whether a list is empty _and_ checks that no other CPU might be
+ * in the process of modifying either member (next or prev)
*
* NOTE: using list_empty_careful() without synchronization
* can only be safe if the only activity that can happen
* to the list entry is list_del_init(). Eg. it cannot be used
* if another CPU could re-list_add() it.
- *
- * @head: the list to test.
*/
static inline int list_empty_careful(const struct list_head *head)
{
@@ -327,7 +351,7 @@ static inline void list_splice_init(struct list_head *list,
/**
* list_for_each - iterate over a list
- * @pos: the &struct list_head to use as a loop counter.
+ * @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
@@ -336,7 +360,7 @@ static inline void list_splice_init(struct list_head *list,
/**
* __list_for_each - iterate over a list
- * @pos: the &struct list_head to use as a loop counter.
+ * @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
*
* This variant differs from list_for_each() in that it's the
@@ -349,7 +373,7 @@ static inline void list_splice_init(struct list_head *list,
/**
* list_for_each_prev - iterate over a list backwards
- * @pos: the &struct list_head to use as a loop counter.
+ * @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
*/
#define list_for_each_prev(pos, head) \
@@ -357,8 +381,8 @@ static inline void list_splice_init(struct list_head *list,
pos = pos->prev)
/**
- * list_for_each_safe - iterate over a list safe against removal of list entry
- * @pos: the &struct list_head to use as a loop counter.
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop cursor.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
@@ -368,7 +392,7 @@ static inline void list_splice_init(struct list_head *list,
/**
* list_for_each_entry - iterate over list of given type
- * @pos: the type * to use as a loop counter.
+ * @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
@@ -379,7 +403,7 @@ static inline void list_splice_init(struct list_head *list,
/**
* list_for_each_entry_reverse - iterate backwards over list of given type.
- * @pos: the type * to use as a loop counter.
+ * @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
@@ -389,21 +413,24 @@ static inline void list_splice_init(struct list_head *list,
pos = list_entry(pos->member.prev, typeof(*pos), member))
/**
- * list_prepare_entry - prepare a pos entry for use as a start point in
- * list_for_each_entry_continue
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue
* @pos: the type * to use as a start point
* @head: the head of the list
* @member: the name of the list_struct within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue.
*/
#define list_prepare_entry(pos, head, member) \
((pos) ? : list_entry(head, typeof(*pos), member))
/**
- * list_for_each_entry_continue - iterate over list of given type
- * continuing after existing point
- * @pos: the type * to use as a loop counter.
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
*/
#define list_for_each_entry_continue(pos, head, member) \
for (pos = list_entry(pos->member.next, typeof(*pos), member); \
@@ -411,11 +438,12 @@ static inline void list_splice_init(struct list_head *list,
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
- * list_for_each_entry_from - iterate over list of given type
- * continuing from existing point
- * @pos: the type * to use as a loop counter.
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
*/
#define list_for_each_entry_from(pos, head, member) \
for (; prefetch(pos->member.next), &pos->member != (head); \
@@ -423,7 +451,7 @@ static inline void list_splice_init(struct list_head *list,
/**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @pos: the type * to use as a loop counter.
+ * @pos: the type * to use as a loop cursor.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
@@ -435,12 +463,14 @@ static inline void list_splice_init(struct list_head *list,
pos = n, n = list_entry(n->member.next, typeof(*n), member))
/**
- * list_for_each_entry_safe_continue - iterate over list of given type
- * continuing after existing point safe against removal of list entry
- * @pos: the type * to use as a loop counter.
+ * list_for_each_entry_safe_continue
+ * @pos: the type * to use as a loop cursor.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
*/
#define list_for_each_entry_safe_continue(pos, n, head, member) \
for (pos = list_entry(pos->member.next, typeof(*pos), member), \
@@ -449,12 +479,14 @@ static inline void list_splice_init(struct list_head *list,
pos = n, n = list_entry(n->member.next, typeof(*n), member))
/**
- * list_for_each_entry_safe_from - iterate over list of given type
- * from existing point safe against removal of list entry
- * @pos: the type * to use as a loop counter.
+ * list_for_each_entry_safe_from
+ * @pos: the type * to use as a loop cursor.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
*/
#define list_for_each_entry_safe_from(pos, n, head, member) \
for (n = list_entry(pos->member.next, typeof(*pos), member); \
@@ -462,12 +494,14 @@ static inline void list_splice_init(struct list_head *list,
pos = n, n = list_entry(n->member.next, typeof(*n), member))
/**
- * list_for_each_entry_safe_reverse - iterate backwards over list of given type safe against
- * removal of list entry
- * @pos: the type * to use as a loop counter.
+ * list_for_each_entry_safe_reverse
+ * @pos: the type * to use as a loop cursor.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
*/
#define list_for_each_entry_safe_reverse(pos, n, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member), \
@@ -477,7 +511,7 @@ static inline void list_splice_init(struct list_head *list,
/**
* list_for_each_rcu - iterate over an rcu-protected list
- * @pos: the &struct list_head to use as a loop counter.
+ * @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
*
* This list-traversal primitive may safely run concurrently with
@@ -495,12 +529,13 @@ static inline void list_splice_init(struct list_head *list,
pos = pos->next)
/**
- * list_for_each_safe_rcu - iterate over an rcu-protected list safe
- * against removal of list entry
- * @pos: the &struct list_head to use as a loop counter.
+ * list_for_each_safe_rcu
+ * @pos: the &struct list_head to use as a loop cursor.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*
+ * Iterate over an rcu-protected list, safe against removal of list entry.
+ *
* This list-traversal primitive may safely run concurrently with
* the _rcu list-mutation primitives such as list_add_rcu()
* as long as the traversal is guarded by rcu_read_lock().
@@ -512,7 +547,7 @@ static inline void list_splice_init(struct list_head *list,
/**
* list_for_each_entry_rcu - iterate over rcu list of given type
- * @pos: the type * to use as a loop counter.
+ * @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*
@@ -528,11 +563,12 @@ static inline void list_splice_init(struct list_head *list,
/**
- * list_for_each_continue_rcu - iterate over an rcu-protected list
- * continuing after existing point.
- * @pos: the &struct list_head to use as a loop counter.
+ * list_for_each_continue_rcu
+ * @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
*
+ * Iterate over an rcu-protected list, continuing after current point.
+ *
* This list-traversal primitive may safely run concurrently with
* the _rcu list-mutation primitives such as list_add_rcu()
* as long as the traversal is guarded by rcu_read_lock().
@@ -658,11 +694,14 @@ static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
/**
- * hlist_add_head_rcu - adds the specified element to the specified hlist,
- * while permitting racing traversals.
+ * hlist_add_head_rcu
* @n: the element to add to the hash list.
* @h: the list to add to.
*
+ * Description:
+ * Adds the specified element to the specified hlist,
+ * while permitting racing traversals.
+ *
* The caller must take whatever precautions are necessary
* (such as holding appropriate locks) to avoid racing
* with another list-mutation primitive, such as hlist_add_head_rcu()
@@ -707,11 +746,14 @@ static inline void hlist_add_after(struct hlist_node *n,
}
/**
- * hlist_add_before_rcu - adds the specified element to the specified hlist
- * before the specified node while permitting racing traversals.
+ * hlist_add_before_rcu
* @n: the new element to add to the hash list.
* @next: the existing element to add the new element before.
*
+ * Description:
+ * Adds the specified element to the specified hlist
+ * before the specified node while permitting racing traversals.
+ *
* The caller must take whatever precautions are necessary
* (such as holding appropriate locks) to avoid racing
* with another list-mutation primitive, such as hlist_add_head_rcu()
@@ -732,11 +774,14 @@ static inline void hlist_add_before_rcu(struct hlist_node *n,
}
/**
- * hlist_add_after_rcu - adds the specified element to the specified hlist
- * after the specified node while permitting racing traversals.
+ * hlist_add_after_rcu
* @prev: the existing element to add the new element after.
* @n: the new element to add to the hash list.
*
+ * Description:
+ * Adds the specified element to the specified hlist
+ * after the specified node while permitting racing traversals.
+ *
* The caller must take whatever precautions are necessary
* (such as holding appropriate locks) to avoid racing
* with another list-mutation primitive, such as hlist_add_head_rcu()
@@ -769,8 +814,8 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev,
/**
* hlist_for_each_entry - iterate over list of given type
- * @tpos: the type * to use as a loop counter.
- * @pos: the &struct hlist_node to use as a loop counter.
+ * @tpos: the type * to use as a loop cursor.
+ * @pos: the &struct hlist_node to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the hlist_node within the struct.
*/
@@ -781,9 +826,9 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev,
pos = pos->next)
/**
- * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point
- * @tpos: the type * to use as a loop counter.
- * @pos: the &struct hlist_node to use as a loop counter.
+ * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
+ * @tpos: the type * to use as a loop cursor.
+ * @pos: the &struct hlist_node to use as a loop cursor.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry_continue(tpos, pos, member) \
@@ -793,9 +838,9 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev,
pos = pos->next)
/**
- * hlist_for_each_entry_from - iterate over a hlist continuing from existing point
- * @tpos: the type * to use as a loop counter.
- * @pos: the &struct hlist_node to use as a loop counter.
+ * hlist_for_each_entry_from - iterate over a hlist continuing from current point
+ * @tpos: the type * to use as a loop cursor.
+ * @pos: the &struct hlist_node to use as a loop cursor.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry_from(tpos, pos, member) \
@@ -805,8 +850,8 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev,
/**
* hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @tpos: the type * to use as a loop counter.
- * @pos: the &struct hlist_node to use as a loop counter.
+ * @tpos: the type * to use as a loop cursor.
+ * @pos: the &struct hlist_node to use as a loop cursor.
* @n: another &struct hlist_node to use as temporary storage
* @head: the head for your list.
* @member: the name of the hlist_node within the struct.
@@ -819,8 +864,8 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev,
/**
* hlist_for_each_entry_rcu - iterate over rcu list of given type
- * @tpos: the type * to use as a loop counter.
- * @pos: the &struct hlist_node to use as a loop counter.
+ * @tpos: the type * to use as a loop cursor.
+ * @pos: the &struct hlist_node to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the hlist_node within the struct.
*
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index a8876bc..aa4fe90 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -49,11 +49,12 @@ struct nlm_host {
h_killed : 1,
h_monitored : 1;
wait_queue_head_t h_gracewait; /* wait while reclaiming */
+ struct rw_semaphore h_rwsem; /* Reboot recovery lock */
u32 h_state; /* pseudo-state counter */
u32 h_nsmstate; /* true remote NSM state */
u32 h_pidcount; /* Pseudopids */
atomic_t h_count; /* reference count */
- struct semaphore h_sema; /* mutex for pmap binding */
+ struct mutex h_mutex; /* mutex for pmap binding */
unsigned long h_nextrebind; /* next portmap call */
unsigned long h_expires; /* eligible for GC */
struct list_head h_lockowners; /* Lockowners for the client */
@@ -219,6 +220,7 @@ static __inline__ int
nlm_compare_locks(const struct file_lock *fl1, const struct file_lock *fl2)
{
return fl1->fl_pid == fl2->fl_pid
+ && fl1->fl_owner == fl2->fl_owner
&& fl1->fl_start == fl2->fl_start
&& fl1->fl_end == fl2->fl_end
&&(fl1->fl_type == fl2->fl_type || fl2->fl_type == F_UNLCK);
diff --git a/include/linux/loop.h b/include/linux/loop.h
index e76c761..bf3d234 100644
--- a/include/linux/loop.h
+++ b/include/linux/loop.h
@@ -59,7 +59,7 @@ struct loop_device {
struct bio *lo_bio;
struct bio *lo_biotail;
int lo_state;
- struct completion lo_done;
+ struct task_struct *lo_thread;
struct completion lo_bh_done;
struct mutex lo_ctl_mutex;
int lo_pending;
diff --git a/include/linux/m41t00.h b/include/linux/m41t00.h
new file mode 100644
index 0000000..b423360
--- /dev/null
+++ b/include/linux/m41t00.h
@@ -0,0 +1,50 @@
+/*
+ * Definitions for the ST M41T00 family of i2c rtc chips.
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2005, 2006 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#ifndef _M41T00_H
+#define _M41T00_H
+
+#define M41T00_DRV_NAME "m41t00"
+#define M41T00_I2C_ADDR 0x68
+
+#define M41T00_TYPE_M41T00 0
+#define M41T00_TYPE_M41T81 81
+#define M41T00_TYPE_M41T85 85
+
+struct m41t00_platform_data {
+ u8 type;
+ u8 i2c_addr;
+ u8 sqw_freq;
+};
+
+/* SQW output disabled, this is default value by power on */
+#define M41T00_SQW_DISABLE (0)
+
+#define M41T00_SQW_32KHZ (1<<4) /* 32.768 KHz */
+#define M41T00_SQW_8KHZ (2<<4) /* 8.192 KHz */
+#define M41T00_SQW_4KHZ (3<<4) /* 4.096 KHz */
+#define M41T00_SQW_2KHZ (4<<4) /* 2.048 KHz */
+#define M41T00_SQW_1KHZ (5<<4) /* 1.024 KHz */
+#define M41T00_SQW_512HZ (6<<4) /* 512 Hz */
+#define M41T00_SQW_256HZ (7<<4) /* 256 Hz */
+#define M41T00_SQW_128HZ (8<<4) /* 128 Hz */
+#define M41T00_SQW_64HZ (9<<4) /* 64 Hz */
+#define M41T00_SQW_32HZ (10<<4) /* 32 Hz */
+#define M41T00_SQW_16HZ (11<<4) /* 16 Hz */
+#define M41T00_SQW_8HZ (12<<4) /* 8 Hz */
+#define M41T00_SQW_4HZ (13<<4) /* 4 Hz */
+#define M41T00_SQW_2HZ (14<<4) /* 2 Hz */
+#define M41T00_SQW_1HZ (15<<4) /* 1 Hz */
+
+extern ulong m41t00_get_rtc_time(void);
+extern int m41t00_set_rtc_time(ulong nowtime);
+
+#endif /* _M41T00_H */
diff --git a/include/linux/migrate.h b/include/linux/migrate.h
index 6789c49..48148e0 100644
--- a/include/linux/migrate.h
+++ b/include/linux/migrate.h
@@ -3,33 +3,42 @@
#include <linux/mm.h>
+typedef struct page *new_page_t(struct page *, unsigned long private, int **);
+
#ifdef CONFIG_MIGRATION
extern int isolate_lru_page(struct page *p, struct list_head *pagelist);
extern int putback_lru_pages(struct list_head *l);
-extern int migrate_page(struct page *, struct page *);
-extern void migrate_page_copy(struct page *, struct page *);
-extern int migrate_page_remove_references(struct page *, struct page *, int);
-extern int migrate_pages(struct list_head *l, struct list_head *t,
- struct list_head *moved, struct list_head *failed);
-extern int migrate_pages_to(struct list_head *pagelist,
- struct vm_area_struct *vma, int dest);
-extern int fail_migrate_page(struct page *, struct page *);
+extern int migrate_page(struct address_space *,
+ struct page *, struct page *);
+extern int migrate_pages(struct list_head *l, new_page_t x, unsigned long);
-extern int migrate_prep(void);
+extern int fail_migrate_page(struct address_space *,
+ struct page *, struct page *);
+extern int migrate_prep(void);
+extern int migrate_vmas(struct mm_struct *mm,
+ const nodemask_t *from, const nodemask_t *to,
+ unsigned long flags);
#else
static inline int isolate_lru_page(struct page *p, struct list_head *list)
{ return -ENOSYS; }
static inline int putback_lru_pages(struct list_head *l) { return 0; }
-static inline int migrate_pages(struct list_head *l, struct list_head *t,
- struct list_head *moved, struct list_head *failed) { return -ENOSYS; }
+static inline int migrate_pages(struct list_head *l, new_page_t x,
+ unsigned long private) { return -ENOSYS; }
static inline int migrate_pages_to(struct list_head *pagelist,
struct vm_area_struct *vma, int dest) { return 0; }
static inline int migrate_prep(void) { return -ENOSYS; }
+static inline int migrate_vmas(struct mm_struct *mm,
+ const nodemask_t *from, const nodemask_t *to,
+ unsigned long flags)
+{
+ return -ENOSYS;
+}
+
/* Possible settings for the migrate_page() method in address_operations */
#define migrate_page NULL
#define fail_migrate_page NULL
diff --git a/include/linux/mm.h b/include/linux/mm.h
index e2fa375..a929ea1 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -145,7 +145,6 @@ extern unsigned int kobjsize(const void *objp);
#define VM_GROWSDOWN 0x00000100 /* general info on the segment */
#define VM_GROWSUP 0x00000200
-#define VM_SHM 0x00000000 /* Means nothing: delete it later */
#define VM_PFNMAP 0x00000400 /* Page-ranges managed without "struct page", just pure PFN */
#define VM_DENYWRITE 0x00000800 /* ETXTBSY on write attempts.. */
@@ -199,10 +198,16 @@ struct vm_operations_struct {
void (*close)(struct vm_area_struct * area);
struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int *type);
int (*populate)(struct vm_area_struct * area, unsigned long address, unsigned long len, pgprot_t prot, unsigned long pgoff, int nonblock);
+
+ /* notification that a previously read-only page is about to become
+ * writable, if an error is returned it will cause a SIGBUS */
+ int (*page_mkwrite)(struct vm_area_struct *vma, struct page *page);
#ifdef CONFIG_NUMA
int (*set_policy)(struct vm_area_struct *vma, struct mempolicy *new);
struct mempolicy *(*get_policy)(struct vm_area_struct *vma,
unsigned long addr);
+ int (*migrate)(struct vm_area_struct *vma, const nodemask_t *from,
+ const nodemask_t *to, unsigned long flags);
#endif
};
@@ -465,10 +470,13 @@ static inline unsigned long page_zonenum(struct page *page)
struct zone;
extern struct zone *zone_table[];
+static inline int page_zone_id(struct page *page)
+{
+ return (page->flags >> ZONETABLE_PGSHIFT) & ZONETABLE_MASK;
+}
static inline struct zone *page_zone(struct page *page)
{
- return zone_table[(page->flags >> ZONETABLE_PGSHIFT) &
- ZONETABLE_MASK];
+ return zone_table[page_zone_id(page)];
}
static inline unsigned long page_to_nid(struct page *page)
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 9742e3c..d6120fa 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -197,7 +197,7 @@ struct zone {
/*
* wait_table -- the array holding the hash table
- * wait_table_size -- the size of the hash table array
+ * wait_table_hash_nr_entries -- the size of the hash table array
* wait_table_bits -- wait_table_size == (1 << wait_table_bits)
*
* The purpose of all these is to keep track of the people
@@ -220,7 +220,7 @@ struct zone {
* free_area_init_core() performs the initialization of them.
*/
wait_queue_head_t * wait_table;
- unsigned long wait_table_size;
+ unsigned long wait_table_hash_nr_entries;
unsigned long wait_table_bits;
/*
@@ -333,6 +333,9 @@ void wakeup_kswapd(struct zone *zone, int order);
int zone_watermark_ok(struct zone *z, int order, unsigned long mark,
int classzone_idx, int alloc_flags);
+extern int init_currently_empty_zone(struct zone *zone, unsigned long start_pfn,
+ unsigned long size);
+
#ifdef CONFIG_HAVE_MEMORY_PRESENT
void memory_present(int nid, unsigned long start, unsigned long end);
#else
@@ -506,6 +509,10 @@ struct mem_section {
* pages. However, it is stored with some other magic.
* (see sparse.c::sparse_init_one_section())
*
+ * Additionally during early boot we encode node id of
+ * the location of the section here to guide allocation.
+ * (see sparse.c::memory_present())
+ *
* Making it a UL at least makes someone do a cast
* before using it wrong.
*/
@@ -545,6 +552,7 @@ extern int __section_nr(struct mem_section* ms);
#define SECTION_HAS_MEM_MAP (1UL<<1)
#define SECTION_MAP_LAST_BIT (1UL<<2)
#define SECTION_MAP_MASK (~(SECTION_MAP_LAST_BIT-1))
+#define SECTION_NID_SHIFT 2
static inline struct page *__section_mem_map_addr(struct mem_section *section)
{
diff --git a/include/linux/module.h b/include/linux/module.h
index c2d89e0..2d36609 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -105,6 +105,8 @@ extern struct module __this_module;
* "GPL and additional rights" [GNU Public License v2 rights and more]
* "Dual BSD/GPL" [GNU Public License v2
* or BSD license choice]
+ * "Dual MIT/GPL" [GNU Public License v2
+ * or MIT license choice]
* "Dual MPL/GPL" [GNU Public License v2
* or Mozilla license choice]
*
diff --git a/include/linux/mount.h b/include/linux/mount.h
index b7472ae..403d1a9 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -17,12 +17,19 @@
#include <linux/spinlock.h>
#include <asm/atomic.h>
+struct super_block;
+struct vfsmount;
+struct dentry;
+struct namespace;
+
#define MNT_NOSUID 0x01
#define MNT_NODEV 0x02
#define MNT_NOEXEC 0x04
#define MNT_NOATIME 0x08
#define MNT_NODIRATIME 0x10
+#define MNT_SHRINKABLE 0x100
+
#define MNT_SHARED 0x1000 /* if the vfsmount is a shared mount */
#define MNT_UNBINDABLE 0x2000 /* if the vfsmount is a unbindable mount */
#define MNT_PNODE_MASK 0x3000 /* propogation flag mask */
@@ -73,12 +80,18 @@ extern struct vfsmount *alloc_vfsmnt(const char *name);
extern struct vfsmount *do_kern_mount(const char *fstype, int flags,
const char *name, void *data);
+struct file_system_type;
+extern struct vfsmount *vfs_kern_mount(struct file_system_type *type,
+ int flags, const char *name,
+ void *data);
+
struct nameidata;
extern int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd,
int mnt_flags, struct list_head *fslist);
extern void mark_mounts_for_expiry(struct list_head *mounts);
+extern void shrink_submounts(struct vfsmount *mountpoint, struct list_head *mounts);
extern spinlock_t vfsmount_lock;
extern dev_t name_to_dev_t(char *name);
diff --git a/include/linux/nbd.h b/include/linux/nbd.h
index 1d7cdd2..e712e7d 100644
--- a/include/linux/nbd.h
+++ b/include/linux/nbd.h
@@ -77,11 +77,11 @@ struct nbd_device {
* server. All data are in network byte order.
*/
struct nbd_request {
- __u32 magic;
- __u32 type; /* == READ || == WRITE */
+ __be32 magic;
+ __be32 type; /* == READ || == WRITE */
char handle[8];
- __u64 from;
- __u32 len;
+ __be64 from;
+ __be32 len;
}
#ifdef __GNUC__
__attribute__ ((packed))
@@ -93,8 +93,8 @@ struct nbd_request {
* it has completed an I/O request (or an error occurs).
*/
struct nbd_reply {
- __u32 magic;
- __u32 error; /* 0 = ok, else error */
+ __be32 magic;
+ __be32 error; /* 0 = ok, else error */
char handle[8]; /* handle you got from request */
};
#endif
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index cead6be..bc747e5 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -308,9 +308,13 @@ struct net_device
#define NETIF_F_HW_VLAN_RX 256 /* Receive VLAN hw acceleration */
#define NETIF_F_HW_VLAN_FILTER 512 /* Receive filtering on VLAN */
#define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */
-#define NETIF_F_TSO 2048 /* Can offload TCP/IP segmentation */
+#define NETIF_F_GSO 2048 /* Enable software GSO. */
#define NETIF_F_LLTX 4096 /* LockLess TX */
-#define NETIF_F_UFO 8192 /* Can offload UDP Large Send*/
+
+ /* Segmentation offload features */
+#define NETIF_F_GSO_SHIFT 16
+#define NETIF_F_TSO (SKB_GSO_TCPV4 << NETIF_F_GSO_SHIFT)
+#define NETIF_F_UFO (SKB_GSO_UDPV4 << NETIF_F_GSO_SHIFT)
#define NETIF_F_GEN_CSUM (NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)
#define NETIF_F_ALL_CSUM (NETIF_F_IP_CSUM | NETIF_F_GEN_CSUM)
@@ -402,6 +406,9 @@ struct net_device
struct list_head qdisc_list;
unsigned long tx_queue_len; /* Max frames per queue allowed */
+ /* Partially transmitted GSO packet. */
+ struct sk_buff *gso_skb;
+
/* ingress path synchronizer */
spinlock_t ingress_lock;
struct Qdisc *qdisc_ingress;
@@ -536,6 +543,7 @@ struct packet_type {
struct net_device *,
struct packet_type *,
struct net_device *);
+ struct sk_buff *(*gso_segment)(struct sk_buff *skb, int sg);
void *af_packet_priv;
struct list_head list;
};
@@ -686,7 +694,8 @@ extern int dev_change_name(struct net_device *, char *);
extern int dev_set_mtu(struct net_device *, int);
extern int dev_set_mac_address(struct net_device *,
struct sockaddr *);
-extern void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev);
+extern int dev_hard_start_xmit(struct sk_buff *skb,
+ struct net_device *dev);
extern void dev_init(void);
@@ -960,6 +969,7 @@ extern int netdev_max_backlog;
extern int weight_p;
extern int netdev_set_master(struct net_device *dev, struct net_device *master);
extern int skb_checksum_help(struct sk_buff *skb, int inward);
+extern struct sk_buff *skb_gso_segment(struct sk_buff *skb, int sg);
#ifdef CONFIG_BUG
extern void netdev_rx_csum_fault(struct net_device *dev);
#else
@@ -979,6 +989,13 @@ extern void dev_seq_stop(struct seq_file *seq, void *v);
extern void linkwatch_run_queue(void);
+static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
+{
+ int feature = skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT;
+ return skb_shinfo(skb)->gso_size &&
+ (dev->features & feature) != feature;
+}
+
#endif /* __KERNEL__ */
#endif /* _LINUX_DEV_H */
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 87b8a57..855b446 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -5,7 +5,7 @@
#include <linux/types.h>
#define NETLINK_ROUTE 0 /* Routing/device hook */
-#define NETLINK_W1 1 /* 1-wire subsystem */
+#define NETLINK_UNUSED 1 /* Unused number */
#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
#define NETLINK_FIREWALL 3 /* Firewalling hook */
#define NETLINK_INET_DIAG 4 /* INET socket monitoring */
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 1059e6d..5f681d5 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -384,6 +384,7 @@ enum {
NFSPROC4_CLNT_DELEGRETURN,
NFSPROC4_CLNT_GETACL,
NFSPROC4_CLNT_SETACL,
+ NFSPROC4_CLNT_FS_LOCATIONS,
};
#endif
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 7e079f8..0a1740b 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -9,6 +9,27 @@
#ifndef _LINUX_NFS_FS_H
#define _LINUX_NFS_FS_H
+#include <linux/config.h>
+#include <linux/in.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/rwsem.h>
+#include <linux/wait.h>
+
+#include <linux/sunrpc/debug.h>
+#include <linux/sunrpc/auth.h>
+#include <linux/sunrpc/clnt.h>
+
+#include <linux/nfs.h>
+#include <linux/nfs2.h>
+#include <linux/nfs3.h>
+#include <linux/nfs4.h>
+#include <linux/nfs_xdr.h>
+
+#include <linux/nfs_fs_sb.h>
+
+#include <linux/rwsem.h>
+#include <linux/mempool.h>
/*
* Enable debugging support for nfs client.
@@ -41,27 +62,9 @@
#define FLUSH_LOWPRI 8 /* low priority background flush */
#define FLUSH_HIGHPRI 16 /* high priority memory reclaim flush */
#define FLUSH_NOCOMMIT 32 /* Don't send the NFSv3/v4 COMMIT */
+#define FLUSH_INVALIDATE 64 /* Invalidate the page cache */
#ifdef __KERNEL__
-#include <linux/in.h>
-#include <linux/mm.h>
-#include <linux/pagemap.h>
-#include <linux/rwsem.h>
-#include <linux/wait.h>
-
-#include <linux/nfs_fs_sb.h>
-
-#include <linux/sunrpc/debug.h>
-#include <linux/sunrpc/auth.h>
-#include <linux/sunrpc/clnt.h>
-
-#include <linux/nfs.h>
-#include <linux/nfs2.h>
-#include <linux/nfs3.h>
-#include <linux/nfs4.h>
-#include <linux/nfs_xdr.h>
-#include <linux/rwsem.h>
-#include <linux/mempool.h>
/*
* NFSv3/v4 Access mode cache entry
@@ -233,8 +236,12 @@ static inline int nfs_caches_unstable(struct inode *inode)
static inline void nfs_mark_for_revalidate(struct inode *inode)
{
+ struct nfs_inode *nfsi = NFS_I(inode);
+
spin_lock(&inode->i_lock);
- NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS;
+ nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS;
+ if (S_ISDIR(inode->i_mode))
+ nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA;
spin_unlock(&inode->i_lock);
}
@@ -296,7 +303,7 @@ extern int nfs_release(struct inode *, struct file *);
extern int nfs_attribute_timeout(struct inode *inode);
extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode);
extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
-extern void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
+extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
extern int nfs_setattr(struct dentry *, struct iattr *);
extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr);
extern void nfs_begin_attr_update(struct inode *);
@@ -306,6 +313,10 @@ extern void nfs_end_data_update(struct inode *);
extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
extern void put_nfs_open_context(struct nfs_open_context *ctx);
extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, int mode);
+extern struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
+ const struct dentry *dentry,
+ struct nfs_fh *fh,
+ struct nfs_fattr *fattr);
/* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
extern u32 root_nfs_parse_addr(char *name); /*__init*/
@@ -392,6 +403,15 @@ extern void nfs_unregister_sysctl(void);
#endif
/*
+ * linux/fs/nfs/namespace.c
+ */
+extern struct list_head nfs_automount_list;
+extern struct inode_operations nfs_mountpoint_inode_operations;
+extern struct inode_operations nfs_referral_inode_operations;
+extern int nfs_mountpoint_expiry_timeout;
+extern void nfs_release_automount_timer(void);
+
+/*
* linux/fs/nfs/unlink.c
*/
extern int nfs_async_unlink(struct dentry *);
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 65dec21..6b4a13c 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -35,6 +35,7 @@ struct nfs_server {
char * hostname; /* remote hostname */
struct nfs_fh fh;
struct sockaddr_in addr;
+ struct nfs_fsid fsid;
unsigned long mount_time; /* when this fs was mounted */
#ifdef CONFIG_NFS_V4
/* Our own IP address, as a null-terminated string.
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
index 66e2ed6..1f7bd28 100644
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -13,7 +13,6 @@
#include <linux/list.h>
#include <linux/pagemap.h>
#include <linux/wait.h>
-#include <linux/nfs_fs_sb.h>
#include <linux/sunrpc/auth.h>
#include <linux/nfs_xdr.h>
@@ -63,8 +62,8 @@ extern void nfs_release_request(struct nfs_page *req);
extern int nfs_scan_lock_dirty(struct nfs_inode *nfsi, struct list_head *dst,
unsigned long idx_start, unsigned int npages);
-extern int nfs_scan_list(struct list_head *, struct list_head *,
- unsigned long, unsigned int);
+extern int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, struct list_head *dst,
+ unsigned long idx_start, unsigned int npages);
extern int nfs_coalesce_requests(struct list_head *, struct list_head *,
unsigned int);
extern int nfs_wait_on_request(struct nfs_page *);
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 7fafc4c..7c7320f 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -14,11 +14,19 @@
#define NFS_DEF_FILE_IO_SIZE (4096U)
#define NFS_MIN_FILE_IO_SIZE (1024U)
-struct nfs4_fsid {
- __u64 major;
- __u64 minor;
+struct nfs_fsid {
+ uint64_t major;
+ uint64_t minor;
};
+/*
+ * Helper for checking equality between 2 fsids.
+ */
+static inline int nfs_fsid_equal(const struct nfs_fsid *a, const struct nfs_fsid *b)
+{
+ return a->major == b->major && a->minor == b->minor;
+}
+
struct nfs_fattr {
unsigned short valid; /* which fields are valid */
__u64 pre_size; /* pre_op_attr.size */
@@ -40,10 +48,7 @@ struct nfs_fattr {
} nfs3;
} du;
dev_t rdev;
- union {
- __u64 nfs3; /* also nfs2 */
- struct nfs4_fsid nfs4;
- } fsid_u;
+ struct nfs_fsid fsid;
__u64 fileid;
struct timespec atime;
struct timespec mtime;
@@ -57,8 +62,8 @@ struct nfs_fattr {
#define NFS_ATTR_WCC 0x0001 /* pre-op WCC data */
#define NFS_ATTR_FATTR 0x0002 /* post-op attributes */
#define NFS_ATTR_FATTR_V3 0x0004 /* NFSv3 attributes */
-#define NFS_ATTR_FATTR_V4 0x0008
-#define NFS_ATTR_PRE_CHANGE 0x0010
+#define NFS_ATTR_FATTR_V4 0x0008 /* NFSv4 change attribute */
+#define NFS_ATTR_FATTR_V4_REFERRAL 0x0010 /* NFSv4 referral */
/*
* Info on the file system
@@ -675,6 +680,40 @@ struct nfs4_server_caps_res {
u32 has_symlinks;
};
+struct nfs4_string {
+ unsigned int len;
+ char *data;
+};
+
+#define NFS4_PATHNAME_MAXCOMPONENTS 512
+struct nfs4_pathname {
+ unsigned int ncomponents;
+ struct nfs4_string components[NFS4_PATHNAME_MAXCOMPONENTS];
+};
+
+#define NFS4_FS_LOCATION_MAXSERVERS 10
+struct nfs4_fs_location {
+ unsigned int nservers;
+ struct nfs4_string servers[NFS4_FS_LOCATION_MAXSERVERS];
+ struct nfs4_pathname rootpath;
+};
+
+#define NFS4_FS_LOCATIONS_MAXENTRIES 10
+struct nfs4_fs_locations {
+ struct nfs_fattr fattr;
+ const struct nfs_server *server;
+ struct nfs4_pathname fs_path;
+ int nlocations;
+ struct nfs4_fs_location locations[NFS4_FS_LOCATIONS_MAXENTRIES];
+};
+
+struct nfs4_fs_locations_arg {
+ const struct nfs_fh *dir_fh;
+ const struct qstr *name;
+ struct page *page;
+ const u32 *bitmask;
+};
+
#endif /* CONFIG_NFS_V4 */
struct nfs_page;
@@ -695,7 +734,7 @@ struct nfs_read_data {
#ifdef CONFIG_NFS_V4
unsigned long timestamp; /* For lease renewal */
#endif
- struct page *page_array[NFS_PAGEVEC_SIZE + 1];
+ struct page *page_array[NFS_PAGEVEC_SIZE];
};
struct nfs_write_data {
@@ -713,7 +752,7 @@ struct nfs_write_data {
#ifdef CONFIG_NFS_V4
unsigned long timestamp; /* For lease renewal */
#endif
- struct page *page_array[NFS_PAGEVEC_SIZE + 1];
+ struct page *page_array[NFS_PAGEVEC_SIZE];
};
struct nfs_access_entry;
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index d276a4e..0c076d5 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -7,6 +7,8 @@
#include <linux/percpu.h>
#include <linux/cache.h>
+#include <linux/types.h>
+
#include <asm/pgtable.h>
/*
@@ -88,7 +90,17 @@
#define PG_nosave_free 18 /* Free, should not be written */
#define PG_buddy 19 /* Page is free, on buddy lists */
-#define PG_uncached 20 /* Page has been mapped as uncached */
+
+#if (BITS_PER_LONG > 32)
+/*
+ * 64-bit-only flags build down from bit 31
+ *
+ * 32 bit -------------------------------| FIELDS | FLAGS |
+ * 64 bit | FIELDS | ?????? FLAGS |
+ * 63 32 0
+ */
+#define PG_uncached 31 /* Page has been mapped as uncached */
+#endif
/*
* Global page accounting. One instance per CPU. Only unsigned longs are
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 7a1af57..1245df7 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -99,6 +99,13 @@ extern struct page * read_cache_page(struct address_space *mapping,
extern int read_cache_pages(struct address_space *mapping,
struct list_head *pages, filler_t *filler, void *data);
+static inline struct page *read_mapping_page(struct address_space *mapping,
+ unsigned long index, void *data)
+{
+ filler_t *filler = (filler_t *)mapping->a_ops->readpage;
+ return read_cache_page(mapping, index, filler, data);
+}
+
int add_to_page_cache(struct page *page, struct address_space *mapping,
unsigned long index, gfp_t gfp_mask);
int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
diff --git a/include/linux/parport.h b/include/linux/parport.h
index d42737e..5bf321e 100644
--- a/include/linux/parport.h
+++ b/include/linux/parport.h
@@ -127,6 +127,10 @@ struct amiga_parport_state {
unsigned char statusdir;/* ciab.ddrb & 7 */
};
+struct ax88796_parport_state {
+ unsigned char cpr;
+};
+
struct ip32_parport_state {
unsigned int dcr;
unsigned int ecr;
@@ -138,6 +142,7 @@ struct parport_state {
/* ARC has no state. */
struct ax_parport_state ax;
struct amiga_parport_state amiga;
+ struct ax88796_parport_state ax88796;
/* Atari has not state. */
struct ip32_parport_state ip32;
void *misc;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 6c4bc77..62a8c22 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -162,6 +162,9 @@ struct pci_dev {
unsigned int is_busmaster:1; /* device is busmaster */
unsigned int no_msi:1; /* device may not use msi */
unsigned int block_ucfg_access:1; /* userspace config space access is blocked */
+ unsigned int broken_parity_status:1; /* Device generates false positive parity */
+ unsigned int msi_enabled:1;
+ unsigned int msix_enabled:1;
u32 saved_config_space[16]; /* config space saved at suspend time */
struct hlist_head saved_cap_space;
@@ -496,6 +499,7 @@ int pci_set_dma_mask(struct pci_dev *dev, u64 mask);
int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask);
void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno);
int pci_assign_resource(struct pci_dev *dev, int i);
+int pci_assign_resource_fixed(struct pci_dev *dev, int i);
void pci_restore_bars(struct pci_dev *dev);
/* ROM control related routines */
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index bcfe9d4..c2fd2d1 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -352,8 +352,11 @@
#define PCI_DEVICE_ID_ATI_RS480 0x5950
/* ATI IXP Chipset */
#define PCI_DEVICE_ID_ATI_IXP200_IDE 0x4349
+#define PCI_DEVICE_ID_ATI_IXP200_SMBUS 0x4353
+#define PCI_DEVICE_ID_ATI_IXP300_SMBUS 0x4363
#define PCI_DEVICE_ID_ATI_IXP300_IDE 0x4369
#define PCI_DEVICE_ID_ATI_IXP300_SATA 0x436e
+#define PCI_DEVICE_ID_ATI_IXP400_SMBUS 0x4372
#define PCI_DEVICE_ID_ATI_IXP400_IDE 0x4376
#define PCI_DEVICE_ID_ATI_IXP400_SATA 0x4379
#define PCI_DEVICE_ID_ATI_IXP400_SATA2 0x437a
@@ -848,7 +851,12 @@
#define PCI_VENDOR_ID_QLOGIC 0x1077
+#define PCI_DEVICE_ID_QLOGIC_ISP10160 0x1016
#define PCI_DEVICE_ID_QLOGIC_ISP1020 0x1020
+#define PCI_DEVICE_ID_QLOGIC_ISP1080 0x1080
+#define PCI_DEVICE_ID_QLOGIC_ISP12160 0x1216
+#define PCI_DEVICE_ID_QLOGIC_ISP1240 0x1240
+#define PCI_DEVICE_ID_QLOGIC_ISP1280 0x1280
#define PCI_DEVICE_ID_QLOGIC_ISP2100 0x2100
#define PCI_DEVICE_ID_QLOGIC_ISP2200 0x2200
#define PCI_DEVICE_ID_QLOGIC_ISP2300 0x2300
@@ -1018,6 +1026,7 @@
#define PCI_DEVICE_ID_NVIDIA_NVENET_8 0x0056
#define PCI_DEVICE_ID_NVIDIA_NVENET_9 0x0057
#define PCI_DEVICE_ID_NVIDIA_CK804_AUDIO 0x0059
+#define PCI_DEVICE_ID_NVIDIA_CK804_PCIE 0x005d
#define PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS 0x0064
#define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE 0x0065
#define PCI_DEVICE_ID_NVIDIA_NVENET_2 0x0066
@@ -1127,9 +1136,11 @@
#define PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL 0x0258
#define PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL 0x0259
#define PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL 0x025B
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS 0x0264
#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE 0x0265
#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA 0x0266
#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2 0x0267
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS 0x0368
#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE 0x036E
#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA 0x037E
#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2 0x037F
@@ -1185,8 +1196,12 @@
#define PCI_DEVICE_ID_NVIDIA_NVENET_15 0x0373
#define PCI_DEVICE_ID_NVIDIA_NVENET_16 0x03E5
#define PCI_DEVICE_ID_NVIDIA_NVENET_17 0x03E6
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA 0x03E7
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE 0x03EC
#define PCI_DEVICE_ID_NVIDIA_NVENET_18 0x03EE
#define PCI_DEVICE_ID_NVIDIA_NVENET_19 0x03EF
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2 0x03F6
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3 0x03F7
#define PCI_DEVICE_ID_NVIDIA_NVENET_20 0x0450
#define PCI_DEVICE_ID_NVIDIA_NVENET_21 0x0451
#define PCI_DEVICE_ID_NVIDIA_NVENET_22 0x0452
@@ -1244,6 +1259,7 @@
#define PCI_DEVICE_ID_VIA_PX8X0_0 0x0259
#define PCI_DEVICE_ID_VIA_3269_0 0x0269
#define PCI_DEVICE_ID_VIA_K8T800PRO_0 0x0282
+#define PCI_DEVICE_ID_VIA_3296_0 0x0296
#define PCI_DEVICE_ID_VIA_8363_0 0x0305
#define PCI_DEVICE_ID_VIA_P4M800CE 0x0314
#define PCI_DEVICE_ID_VIA_8371_0 0x0391
@@ -1251,6 +1267,7 @@
#define PCI_DEVICE_ID_VIA_82C561 0x0561
#define PCI_DEVICE_ID_VIA_82C586_1 0x0571
#define PCI_DEVICE_ID_VIA_82C576 0x0576
+#define PCI_DEVICE_ID_VIA_SATA_EIDE 0x0581
#define PCI_DEVICE_ID_VIA_82C586_0 0x0586
#define PCI_DEVICE_ID_VIA_82C596 0x0596
#define PCI_DEVICE_ID_VIA_82C597_0 0x0597
@@ -1291,10 +1308,11 @@
#define PCI_DEVICE_ID_VIA_8783_0 0x3208
#define PCI_DEVICE_ID_VIA_8237 0x3227
#define PCI_DEVICE_ID_VIA_8251 0x3287
-#define PCI_DEVICE_ID_VIA_3296_0 0x0296
+#define PCI_DEVICE_ID_VIA_8237A 0x3337
#define PCI_DEVICE_ID_VIA_8231 0x8231
#define PCI_DEVICE_ID_VIA_8231_4 0x8235
#define PCI_DEVICE_ID_VIA_8365_1 0x8305
+#define PCI_DEVICE_ID_VIA_CX700 0x8324
#define PCI_DEVICE_ID_VIA_8371_1 0x8391
#define PCI_DEVICE_ID_VIA_82C598_1 0x8598
#define PCI_DEVICE_ID_VIA_838X_1 0xB188
@@ -1946,6 +1964,7 @@
#define PCI_VENDOR_ID_MELLANOX 0x15b3
#define PCI_DEVICE_ID_MELLANOX_TAVOR 0x5a44
+#define PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE 0x5a46
#define PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 0x6278
#define PCI_DEVICE_ID_MELLANOX_ARBEL 0x6282
#define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c
@@ -1969,6 +1988,9 @@
#define PCI_VENDOR_ID_NETCELL 0x169c
#define PCI_DEVICE_ID_REVOLUTION 0x0044
+#define PCI_VENDOR_ID_VITESSE 0x1725
+#define PCI_DEVICE_ID_VITESSE_VSC7174 0x7174
+
#define PCI_VENDOR_ID_LINKSYS 0x1737
#define PCI_DEVICE_ID_LINKSYS_EG1064 0x1064
@@ -2148,6 +2170,7 @@
#define PCI_DEVICE_ID_INTEL_ICH8_4 0x2815
#define PCI_DEVICE_ID_INTEL_ICH8_5 0x283e
#define PCI_DEVICE_ID_INTEL_ICH8_6 0x2850
+#define PCI_DEVICE_ID_INTEL_GD31244 0x3200
#define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340
#define PCI_DEVICE_ID_INTEL_82830_HB 0x3575
#define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index d27a78b..6bce4a2 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -197,6 +197,7 @@
#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */
#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */
#define PCI_CAP_ID_HT_IRQCONF 0x08 /* HyperTransport IRQ Configuration */
+#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific capability */
#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */
#define PCI_CAP_ID_EXP 0x10 /* PCI Express */
#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */
diff --git a/include/linux/percpu_counter.h b/include/linux/percpu_counter.h
index 66b5de4..f5aa593 100644
--- a/include/linux/percpu_counter.h
+++ b/include/linux/percpu_counter.h
@@ -10,13 +10,14 @@
#include <linux/smp.h>
#include <linux/threads.h>
#include <linux/percpu.h>
+#include <linux/types.h>
#ifdef CONFIG_SMP
struct percpu_counter {
spinlock_t lock;
- long count;
- long *counters;
+ s64 count;
+ s32 *counters;
};
#if NR_CPUS >= 16
@@ -25,11 +26,11 @@ struct percpu_counter {
#define FBC_BATCH (NR_CPUS*4)
#endif
-static inline void percpu_counter_init(struct percpu_counter *fbc)
+static inline void percpu_counter_init(struct percpu_counter *fbc, s64 amount)
{
spin_lock_init(&fbc->lock);
- fbc->count = 0;
- fbc->counters = alloc_percpu(long);
+ fbc->count = amount;
+ fbc->counters = alloc_percpu(s32);
}
static inline void percpu_counter_destroy(struct percpu_counter *fbc)
@@ -37,10 +38,10 @@ static inline void percpu_counter_destroy(struct percpu_counter *fbc)
free_percpu(fbc->counters);
}
-void percpu_counter_mod(struct percpu_counter *fbc, long amount);
-long percpu_counter_sum(struct percpu_counter *fbc);
+void percpu_counter_mod(struct percpu_counter *fbc, s32 amount);
+s64 percpu_counter_sum(struct percpu_counter *fbc);
-static inline long percpu_counter_read(struct percpu_counter *fbc)
+static inline s64 percpu_counter_read(struct percpu_counter *fbc)
{
return fbc->count;
}
@@ -48,13 +49,14 @@ static inline long percpu_counter_read(struct percpu_counter *fbc)
/*
* It is possible for the percpu_counter_read() to return a small negative
* number for some counter which should never be negative.
+ *
*/
-static inline long percpu_counter_read_positive(struct percpu_counter *fbc)
+static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
{
- long ret = fbc->count;
+ s64 ret = fbc->count;
barrier(); /* Prevent reloads of fbc->count */
- if (ret > 0)
+ if (ret >= 0)
return ret;
return 1;
}
@@ -62,12 +64,12 @@ static inline long percpu_counter_read_positive(struct percpu_counter *fbc)
#else
struct percpu_counter {
- long count;
+ s64 count;
};
-static inline void percpu_counter_init(struct percpu_counter *fbc)
+static inline void percpu_counter_init(struct percpu_counter *fbc, s64 amount)
{
- fbc->count = 0;
+ fbc->count = amount;
}
static inline void percpu_counter_destroy(struct percpu_counter *fbc)
@@ -75,24 +77,24 @@ static inline void percpu_counter_destroy(struct percpu_counter *fbc)
}
static inline void
-percpu_counter_mod(struct percpu_counter *fbc, long amount)
+percpu_counter_mod(struct percpu_counter *fbc, s32 amount)
{
preempt_disable();
fbc->count += amount;
preempt_enable();
}
-static inline long percpu_counter_read(struct percpu_counter *fbc)
+static inline s64 percpu_counter_read(struct percpu_counter *fbc)
{
return fbc->count;
}
-static inline long percpu_counter_read_positive(struct percpu_counter *fbc)
+static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
{
return fbc->count;
}
-static inline long percpu_counter_sum(struct percpu_counter *fbc)
+static inline s64 percpu_counter_sum(struct percpu_counter *fbc)
{
return percpu_counter_read_positive(fbc);
}
diff --git a/include/linux/pmu.h b/include/linux/pmu.h
index ecce591..2ed807d 100644
--- a/include/linux/pmu.h
+++ b/include/linux/pmu.h
@@ -230,4 +230,8 @@ extern int pmu_battery_count;
extern struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES];
extern unsigned int pmu_power_flags;
+/* Backlight */
+extern int disable_kernel_backlight;
+extern void pmu_backlight_init(struct device_node*);
+
#endif /* __KERNEL__ */
diff --git a/include/linux/prctl.h b/include/linux/prctl.h
index bf022c43..52a9be4 100644
--- a/include/linux/prctl.h
+++ b/include/linux/prctl.h
@@ -52,4 +52,11 @@
#define PR_SET_NAME 15 /* Set process name */
#define PR_GET_NAME 16 /* Get process name */
+/* Get/set process endian */
+#define PR_GET_ENDIAN 19
+#define PR_SET_ENDIAN 20
+# define PR_ENDIAN_BIG 0
+# define PR_ENDIAN_LITTLE 1 /* True little endian mode */
+# define PR_ENDIAN_PPC_LITTLE 2 /* "PowerPC" pseudo little endian */
+
#endif /* _LINUX_PRCTL_H */
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index 0d36750..ee918bc 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -51,6 +51,10 @@
#ifdef __KERNEL__
/*
* Ptrace flags
+ *
+ * The owner ship rules for task->ptrace which holds the ptrace
+ * flags is simple. When a task is running it owns it's task->ptrace
+ * flags. When the a task is stopped the ptracer owns task->ptrace.
*/
#define PT_PTRACED 0x00000001
diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h
index dd83cca..9158a68 100644
--- a/include/linux/radix-tree.h
+++ b/include/linux/radix-tree.h
@@ -23,6 +23,9 @@
#include <linux/preempt.h>
#include <linux/types.h>
+#define RADIX_TREE_MAX_TAGS 2
+
+/* root tags are stored in gfp_mask, shifted by __GFP_BITS_SHIFT */
struct radix_tree_root {
unsigned int height;
gfp_t gfp_mask;
@@ -45,8 +48,6 @@ do { \
(root)->rnode = NULL; \
} while (0)
-#define RADIX_TREE_MAX_TAGS 2
-
int radix_tree_insert(struct radix_tree_root *, unsigned long, void *);
void *radix_tree_lookup(struct radix_tree_root *, unsigned long);
void **radix_tree_lookup_slot(struct radix_tree_root *, unsigned long);
diff --git a/include/linux/ramfs.h b/include/linux/ramfs.h
index 78ecfa2..00b340b 100644
--- a/include/linux/ramfs.h
+++ b/include/linux/ramfs.h
@@ -2,8 +2,8 @@
#define _LINUX_RAMFS_H
struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev);
-struct super_block *ramfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data);
+extern int ramfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt);
#ifndef CONFIG_MMU
extern unsigned long ramfs_nommu_get_unmapped_area(struct file *file,
diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h
index f37006f..8d5382e 100644
--- a/include/linux/rbtree.h
+++ b/include/linux/rbtree.h
@@ -132,6 +132,10 @@ static inline void rb_set_color(struct rb_node *rb, int color)
#define RB_ROOT (struct rb_root) { NULL, }
#define rb_entry(ptr, type, member) container_of(ptr, type, member)
+#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
+#define RB_EMPTY_NODE(node) (rb_parent(node) != node)
+#define RB_CLEAR_NODE(node) (rb_set_parent(node, node))
+
extern void rb_insert_color(struct rb_node *, struct rb_root *);
extern void rb_erase(struct rb_node *, struct rb_root *);
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 970284f..6312758 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -246,7 +246,7 @@ extern int rcu_needs_cpu(int cpu);
* softirq handlers will have completed, since in some kernels, these
* handlers can run in process context, and can block.
*
- * This primitive provides the guarantees made by the (deprecated)
+ * This primitive provides the guarantees made by the (now removed)
* synchronize_kernel() API. In contrast, synchronize_rcu() only
* guarantees that rcu_read_lock() sections will have completed.
* In "classic RCU", these two guarantees happen to be one and
@@ -264,7 +264,6 @@ extern void FASTCALL(call_rcu(struct rcu_head *head,
void (*func)(struct rcu_head *head)));
extern void FASTCALL(call_rcu_bh(struct rcu_head *head,
void (*func)(struct rcu_head *head)));
-extern __deprecated_for_modules void synchronize_kernel(void);
extern void synchronize_rcu(void);
void synchronize_idle(void);
extern void rcu_barrier(void);
diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index 015297f..1dd1c70 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -59,13 +59,13 @@ extern void machine_crash_shutdown(struct pt_regs *);
* Architecture independent implemenations of sys_reboot commands.
*/
-extern void kernel_restart_prepare(char *cmd);
extern void kernel_shutdown_prepare(enum system_states state);
extern void kernel_restart(char *cmd);
extern void kernel_halt(void);
extern void kernel_power_off(void);
-extern void kernel_kexec(void);
+
+void ctrl_alt_del(void);
/*
* Emergency restart, callable from an interrupt handler.
diff --git a/include/linux/resource.h b/include/linux/resource.h
index 21a86cb..ae13db7 100644
--- a/include/linux/resource.h
+++ b/include/linux/resource.h
@@ -3,6 +3,8 @@
#include <linux/time.h>
+struct task_struct;
+
/*
* Resource control/accounting header file for linux
*/
@@ -67,4 +69,6 @@ struct rlimit {
*/
#include <asm/resource.h>
+int getrusage(struct task_struct *p, int who, struct rusage __user *ru);
+
#endif
diff --git a/include/linux/resume-trace.h b/include/linux/resume-trace.h
new file mode 100644
index 0000000..a376bd4
--- /dev/null
+++ b/include/linux/resume-trace.h
@@ -0,0 +1,30 @@
+#ifndef RESUME_TRACE_H
+#define RESUME_TRACE_H
+
+#ifdef CONFIG_PM_TRACE
+
+struct device;
+extern void set_trace_device(struct device *);
+extern void generate_resume_trace(void *tracedata, unsigned int user);
+
+#define TRACE_DEVICE(dev) set_trace_device(dev)
+#define TRACE_RESUME(user) do { \
+ void *tracedata; \
+ asm volatile("movl $1f,%0\n" \
+ ".section .tracedata,\"a\"\n" \
+ "1:\t.word %c1\n" \
+ "\t.long %c2\n" \
+ ".previous" \
+ :"=r" (tracedata) \
+ : "i" (__LINE__), "i" (__FILE__)); \
+ generate_resume_trace(tracedata, user); \
+} while (0)
+
+#else
+
+#define TRACE_DEVICE(dev) do { } while (0)
+#define TRACE_RESUME(dev) do { } while (0)
+
+#endif
+
+#endif
diff --git a/include/linux/rmap.h b/include/linux/rmap.h
index 2d4c81a..bf97b09 100644
--- a/include/linux/rmap.h
+++ b/include/linux/rmap.h
@@ -91,7 +91,6 @@ static inline void page_dup_rmap(struct page *page)
*/
int page_referenced(struct page *, int is_locked);
int try_to_unmap(struct page *, int ignore_refs);
-void remove_from_swap(struct page *page);
/*
* Called from mm/filemap_xip.c to unmap empty zero page
diff --git a/include/linux/rtc-v3020.h b/include/linux/rtc-v3020.h
new file mode 100644
index 0000000..bf74e63
--- /dev/null
+++ b/include/linux/rtc-v3020.h
@@ -0,0 +1,35 @@
+/*
+ * v3020.h - Registers definition and platform data structure for the v3020 RTC.
+ *
+ * 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) 2006, 8D Technologies inc.
+ */
+#ifndef __LINUX_V3020_H
+#define __LINUX_V3020_H
+
+/* The v3020 has only one data pin but which one
+ * is used depends on the board. */
+struct v3020_platform_data {
+ int leftshift; /* (1<<(leftshift)) & readl() */
+};
+
+#define V3020_STATUS_0 0x00
+#define V3020_STATUS_1 0x01
+#define V3020_SECONDS 0x02
+#define V3020_MINUTES 0x03
+#define V3020_HOURS 0x04
+#define V3020_MONTH_DAY 0x05
+#define V3020_MONTH 0x06
+#define V3020_YEAR 0x07
+#define V3020_WEEK_DAY 0x08
+#define V3020_WEEK 0x09
+
+#define V3020_IS_COMMAND(val) ((val)>=0x0E)
+
+#define V3020_CMD_RAM2CLOCK 0x0E
+#define V3020_CMD_CLOCK2RAM 0x0F
+
+#endif /* __LINUX_V3020_H */
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index ab61cd1..36e2bf4 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -102,6 +102,7 @@ struct rtc_pll_info {
#include <linux/interrupt.h>
extern int rtc_month_days(unsigned int month, unsigned int year);
+extern int rtc_year_days(unsigned int day, unsigned int month, unsigned int year);
extern int rtc_valid_tm(struct rtc_time *tm);
extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time);
extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm);
@@ -155,6 +156,17 @@ struct rtc_device
struct rtc_task *irq_task;
spinlock_t irq_task_lock;
int irq_freq;
+ int max_user_freq;
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+ struct work_struct uie_task;
+ struct timer_list uie_timer;
+ /* Those fields are protected by rtc->irq_lock */
+ unsigned int oldsecs;
+ unsigned int irq_active:1;
+ unsigned int stop_uie_polling:1;
+ unsigned int uie_task_active:1;
+ unsigned int uie_timer_active:1;
+#endif
};
#define to_rtc_device(d) container_of(d, struct rtc_device, class_dev)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 267f152..8d11d93 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -358,6 +358,14 @@ struct sighand_struct {
spinlock_t siglock;
};
+struct pacct_struct {
+ int ac_flag;
+ long ac_exitcode;
+ unsigned long ac_mem;
+ cputime_t ac_utime, ac_stime;
+ unsigned long ac_minflt, ac_majflt;
+};
+
/*
* NOTE! "signal_struct" does not have it's own
* locking, because a shared signal_struct always
@@ -449,6 +457,9 @@ struct signal_struct {
struct key *session_keyring; /* keyring inherited over fork */
struct key *process_keyring; /* keyring private to this process */
#endif
+#ifdef CONFIG_BSD_PROCESS_ACCT
+ struct pacct_struct pacct; /* per-process accounting information */
+#endif
};
/* Context switch must be unlocked if interrupts are to be enabled */
@@ -941,12 +952,11 @@ static inline void put_task_struct(struct task_struct *t)
#define PF_KSWAPD 0x00040000 /* I am kswapd */
#define PF_SWAPOFF 0x00080000 /* I am in swapoff */
#define PF_LESS_THROTTLE 0x00100000 /* Throttle me less: I clean memory */
-#define PF_SYNCWRITE 0x00200000 /* I am doing a sync write */
-#define PF_BORROWED_MM 0x00400000 /* I am a kthread doing use_mm */
-#define PF_RANDOMIZE 0x00800000 /* randomize virtual address space */
-#define PF_SWAPWRITE 0x01000000 /* Allowed to write to swap */
-#define PF_SPREAD_PAGE 0x04000000 /* Spread page cache over cpuset */
-#define PF_SPREAD_SLAB 0x08000000 /* Spread some slab caches over cpuset */
+#define PF_BORROWED_MM 0x00200000 /* I am a kthread doing use_mm */
+#define PF_RANDOMIZE 0x00400000 /* randomize virtual address space */
+#define PF_SWAPWRITE 0x00800000 /* Allowed to write to swap */
+#define PF_SPREAD_PAGE 0x01000000 /* Spread page cache over cpuset */
+#define PF_SPREAD_SLAB 0x02000000 /* Spread some slab caches over cpuset */
#define PF_MEMPOLICY 0x10000000 /* Non-default NUMA mempolicy */
/*
@@ -1225,7 +1235,7 @@ static inline int thread_group_empty(task_t *p)
(thread_group_leader(p) && !thread_group_empty(p))
/*
- * Protects ->fs, ->files, ->mm, ->ptrace, ->group_info, ->comm, keyring
+ * Protects ->fs, ->files, ->mm, ->group_info, ->comm, keyring
* subscriptions and synchronises with wait4(). Also used in procfs. Also
* pins the final release of task.io_context. Also protects ->cpuset.
*
diff --git a/include/linux/security.h b/include/linux/security.h
index 4dfb1b8..d2c17bd 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -171,9 +171,9 @@ struct swap_info_struct;
* Deallocate and clear the sb->s_security field.
* @sb contains the super_block structure to be modified.
* @sb_statfs:
- * Check permission before obtaining filesystem statistics for the @sb
- * filesystem.
- * @sb contains the super_block structure for the filesystem.
+ * Check permission before obtaining filesystem statistics for the @mnt
+ * mountpoint.
+ * @dentry is a handle on the superblock for the filesystem.
* Return 0 if permission is granted.
* @sb_mount:
* Check permission before an object specified by @dev_name is mounted on
@@ -577,6 +577,11 @@ struct swap_info_struct;
* @p contains the task_struct of process.
* @nice contains the new nice value.
* Return 0 if permission is granted.
+ * @task_setioprio
+ * Check permission before setting the ioprio value of @p to @ioprio.
+ * @p contains the task_struct of process.
+ * @ioprio contains the new ioprio value
+ * Return 0 if permission is granted.
* @task_setrlimit:
* Check permission before setting the resource limits of the current
* process for @resource to @new_rlim. The old resource limit values can
@@ -596,6 +601,10 @@ struct swap_info_struct;
* @p.
* @p contains the task_struct for process.
* Return 0 if permission is granted.
+ * @task_movememory
+ * Check permission before moving memory owned by process @p.
+ * @p contains the task_struct for process.
+ * Return 0 if permission is granted.
* @task_kill:
* Check permission before sending signal @sig to @p. @info can be NULL,
* the constant 1, or a pointer to a siginfo structure. If @info is 1 or
@@ -1127,7 +1136,7 @@ struct security_operations {
int (*sb_copy_data)(struct file_system_type *type,
void *orig, void *copy);
int (*sb_kern_mount) (struct super_block *sb, void *data);
- int (*sb_statfs) (struct super_block * sb);
+ int (*sb_statfs) (struct dentry *dentry);
int (*sb_mount) (char *dev_name, struct nameidata * nd,
char *type, unsigned long flags, void *data);
int (*sb_check_sb) (struct vfsmount * mnt, struct nameidata * nd);
@@ -1210,10 +1219,12 @@ struct security_operations {
int (*task_getsid) (struct task_struct * p);
int (*task_setgroups) (struct group_info *group_info);
int (*task_setnice) (struct task_struct * p, int nice);
+ int (*task_setioprio) (struct task_struct * p, int ioprio);
int (*task_setrlimit) (unsigned int resource, struct rlimit * new_rlim);
int (*task_setscheduler) (struct task_struct * p, int policy,
struct sched_param * lp);
int (*task_getscheduler) (struct task_struct * p);
+ int (*task_movememory) (struct task_struct * p);
int (*task_kill) (struct task_struct * p,
struct siginfo * info, int sig);
int (*task_wait) (struct task_struct * p);
@@ -1313,7 +1324,7 @@ struct security_operations {
/* key management security hooks */
#ifdef CONFIG_KEYS
- int (*key_alloc)(struct key *key);
+ int (*key_alloc)(struct key *key, struct task_struct *tsk);
void (*key_free)(struct key *key);
int (*key_permission)(key_ref_t key_ref,
struct task_struct *context,
@@ -1450,9 +1461,9 @@ static inline int security_sb_kern_mount (struct super_block *sb, void *data)
return security_ops->sb_kern_mount (sb, data);
}
-static inline int security_sb_statfs (struct super_block *sb)
+static inline int security_sb_statfs (struct dentry *dentry)
{
- return security_ops->sb_statfs (sb);
+ return security_ops->sb_statfs (dentry);
}
static inline int security_sb_mount (char *dev_name, struct nameidata *nd,
@@ -1836,6 +1847,11 @@ static inline int security_task_setnice (struct task_struct *p, int nice)
return security_ops->task_setnice (p, nice);
}
+static inline int security_task_setioprio (struct task_struct *p, int ioprio)
+{
+ return security_ops->task_setioprio (p, ioprio);
+}
+
static inline int security_task_setrlimit (unsigned int resource,
struct rlimit *new_rlim)
{
@@ -1854,6 +1870,11 @@ static inline int security_task_getscheduler (struct task_struct *p)
return security_ops->task_getscheduler (p);
}
+static inline int security_task_movememory (struct task_struct *p)
+{
+ return security_ops->task_movememory (p);
+}
+
static inline int security_task_kill (struct task_struct *p,
struct siginfo *info, int sig)
{
@@ -2162,7 +2183,7 @@ static inline int security_sb_kern_mount (struct super_block *sb, void *data)
return 0;
}
-static inline int security_sb_statfs (struct super_block *sb)
+static inline int security_sb_statfs (struct dentry *dentry)
{
return 0;
}
@@ -2478,6 +2499,11 @@ static inline int security_task_setnice (struct task_struct *p, int nice)
return 0;
}
+static inline int security_task_setioprio (struct task_struct *p, int ioprio)
+{
+ return 0;
+}
+
static inline int security_task_setrlimit (unsigned int resource,
struct rlimit *new_rlim)
{
@@ -2496,6 +2522,11 @@ static inline int security_task_getscheduler (struct task_struct *p)
return 0;
}
+static inline int security_task_movememory (struct task_struct *p)
+{
+ return 0;
+}
+
static inline int security_task_kill (struct task_struct *p,
struct siginfo *info, int sig)
{
@@ -3008,9 +3039,10 @@ static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid
#ifdef CONFIG_KEYS
#ifdef CONFIG_SECURITY
-static inline int security_key_alloc(struct key *key)
+static inline int security_key_alloc(struct key *key,
+ struct task_struct *tsk)
{
- return security_ops->key_alloc(key);
+ return security_ops->key_alloc(key, tsk);
}
static inline void security_key_free(struct key *key)
@@ -3027,7 +3059,8 @@ static inline int security_key_permission(key_ref_t key_ref,
#else
-static inline int security_key_alloc(struct key *key)
+static inline int security_key_alloc(struct key *key,
+ struct task_struct *tsk)
{
return 0;
}
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 0ef50ba..951c4e8 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -130,6 +130,9 @@
/* SUN4V Hypervisor Console */
#define PORT_SUNHV 72
+#define PORT_S3C2412 73
+
+
#ifdef __KERNEL__
#include <linux/compiler.h>
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 66f8819..16eef03 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -134,9 +134,10 @@ struct skb_frag_struct {
struct skb_shared_info {
atomic_t dataref;
unsigned short nr_frags;
- unsigned short tso_size;
- unsigned short tso_segs;
- unsigned short ufo_size;
+ unsigned short gso_size;
+ /* Warning: this field is not always filled in (UFO)! */
+ unsigned short gso_segs;
+ unsigned short gso_type;
unsigned int ip6_frag_id;
struct sk_buff *frag_list;
skb_frag_t frags[MAX_SKB_FRAGS];
@@ -168,6 +169,11 @@ enum {
SKB_FCLONE_CLONE,
};
+enum {
+ SKB_GSO_TCPV4 = 1 << 0,
+ SKB_GSO_UDPV4 = 1 << 1,
+};
+
/**
* struct sk_buff - socket buffer
* @next: Next buffer in list
@@ -209,6 +215,8 @@ enum {
* @nf_bridge: Saved data about a bridged frame - see br_netfilter.c
* @tc_index: Traffic control index
* @tc_verd: traffic control verdict
+ * @dma_cookie: a cookie to one of several possible DMA operations
+ * done by skb DMA functions
* @secmark: security marking
*/
@@ -345,7 +353,7 @@ extern struct sk_buff *skb_realloc_headroom(struct sk_buff *skb,
extern struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
int newheadroom, int newtailroom,
gfp_t priority);
-extern struct sk_buff * skb_pad(struct sk_buff *skb, int pad);
+extern int skb_pad(struct sk_buff *skb, int pad);
#define dev_kfree_skb(a) kfree_skb(a)
extern void skb_over_panic(struct sk_buff *skb, int len,
void *here);
@@ -1122,16 +1130,15 @@ static inline int skb_cow(struct sk_buff *skb, unsigned int headroom)
*
* Pads up a buffer to ensure the trailing bytes exist and are
* blanked. If the buffer already contains sufficient data it
- * is untouched. Returns the buffer, which may be a replacement
- * for the original, or NULL for out of memory - in which case
- * the original buffer is still freed.
+ * is untouched. Otherwise it is extended. Returns zero on
+ * success. The skb is freed on error.
*/
-static inline struct sk_buff *skb_padto(struct sk_buff *skb, unsigned int len)
+static inline int skb_padto(struct sk_buff *skb, unsigned int len)
{
unsigned int size = skb->len;
if (likely(size >= len))
- return skb;
+ return 0;
return skb_pad(skb, len-size);
}
@@ -1292,6 +1299,7 @@ extern void skb_split(struct sk_buff *skb,
struct sk_buff *skb1, const u32 len);
extern void skb_release_data(struct sk_buff *skb);
+extern struct sk_buff *skb_segment(struct sk_buff *skb, int sg);
static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
int len, void *buffer)
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 9dc93163..45ad55b 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -86,6 +86,51 @@ extern void *__kmalloc_track_caller(size_t, gfp_t, void*);
__kmalloc_track_caller(size, flags, __builtin_return_address(0))
#endif
+/**
+ * kmalloc - allocate memory
+ * @size: how many bytes of memory are required.
+ * @flags: the type of memory to allocate.
+ *
+ * kmalloc is the normal method of allocating memory
+ * in the kernel.
+ *
+ * The @flags argument may be one of:
+ *
+ * %GFP_USER - Allocate memory on behalf of user. May sleep.
+ *
+ * %GFP_KERNEL - Allocate normal kernel ram. May sleep.
+ *
+ * %GFP_ATOMIC - Allocation will not sleep.
+ * For example, use this inside interrupt handlers.
+ *
+ * %GFP_HIGHUSER - Allocate pages from high memory.
+ *
+ * %GFP_NOIO - Do not do any I/O at all while trying to get memory.
+ *
+ * %GFP_NOFS - Do not make any fs calls while trying to get memory.
+ *
+ * Also it is possible to set different flags by OR'ing
+ * in one or more of the following additional @flags:
+ *
+ * %__GFP_COLD - Request cache-cold pages instead of
+ * trying to return cache-warm pages.
+ *
+ * %__GFP_DMA - Request memory from the DMA-capable zone.
+ *
+ * %__GFP_HIGH - This allocation has high priority and may use emergency pools.
+ *
+ * %__GFP_HIGHMEM - Allocated memory may be from highmem.
+ *
+ * %__GFP_NOFAIL - Indicate that this allocation is in no way allowed to fail
+ * (think twice before using).
+ *
+ * %__GFP_NORETRY - If memory is not immediately available,
+ * then give up at once.
+ *
+ * %__GFP_NOWARN - If allocation fails, don't issue any warnings.
+ *
+ * %__GFP_REPEAT - If allocation fails initially, try once more before failing.
+ */
static inline void *kmalloc(size_t size, gfp_t flags)
{
if (__builtin_constant_p(size)) {
@@ -111,6 +156,11 @@ found:
extern void *__kzalloc(size_t, gfp_t);
+/**
+ * kzalloc - allocate memory. The memory is set to zero.
+ * @size: how many bytes of memory are required.
+ * @flags: the type of memory to allocate (see kmalloc).
+ */
static inline void *kzalloc(size_t size, gfp_t flags)
{
if (__builtin_constant_p(size)) {
diff --git a/include/linux/string.h b/include/linux/string.h
index c61306d..e4c7558 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -56,6 +56,7 @@ extern char * strnchr(const char *, size_t, int);
#ifndef __HAVE_ARCH_STRRCHR
extern char * strrchr(const char *,int);
#endif
+extern char * strstrip(char *);
#ifndef __HAVE_ARCH_STRSTR
extern char * strstr(const char *,const char *);
#endif
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index 84c35d4..e6d3d34 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -194,6 +194,7 @@ extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,
extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p);
extern uint32_t *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
+extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len);
#endif /* __KERNEL__ */
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 96e31aa..e82cb10 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -71,6 +71,7 @@ struct saved_context;
void __save_processor_state(struct saved_context *ctxt);
void __restore_processor_state(struct saved_context *ctxt);
unsigned long get_safe_page(gfp_t gfp_mask);
+int swsusp_add_arch_pages(unsigned long start, unsigned long end);
/*
* XXX: We try to keep some more pages free so that I/O operations succeed
diff --git a/include/linux/swap.h b/include/linux/swap.h
index aca9bfa..dc3f3aa 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -28,7 +28,14 @@ static inline int current_is_kswapd(void)
* the type/offset into the pte as 5/27 as well.
*/
#define MAX_SWAPFILES_SHIFT 5
+#ifndef CONFIG_MIGRATION
#define MAX_SWAPFILES (1 << MAX_SWAPFILES_SHIFT)
+#else
+/* Use last two entries for page migration swap entries */
+#define MAX_SWAPFILES ((1 << MAX_SWAPFILES_SHIFT)-2)
+#define SWP_MIGRATION_READ MAX_SWAPFILES
+#define SWP_MIGRATION_WRITE (MAX_SWAPFILES + 1)
+#endif
/*
* Magic header for a swap area. The first part of the union is
@@ -48,12 +55,14 @@ union swap_header {
char magic[10]; /* SWAP-SPACE or SWAPSPACE2 */
} magic;
struct {
- char bootbits[1024]; /* Space for disklabel etc. */
- unsigned int version;
- unsigned int last_page;
- unsigned int nr_badpages;
- unsigned int padding[125];
- unsigned int badpages[1];
+ char bootbits[1024]; /* Space for disklabel etc. */
+ __u32 version;
+ __u32 last_page;
+ __u32 nr_badpages;
+ unsigned char sws_uuid[16];
+ unsigned char sws_volume[16];
+ __u32 padding[117];
+ __u32 badpages[1];
} info;
};
@@ -176,20 +185,7 @@ extern unsigned long try_to_free_pages(struct zone **, gfp_t);
extern unsigned long shrink_all_memory(unsigned long nr_pages);
extern int vm_swappiness;
extern int remove_mapping(struct address_space *mapping, struct page *page);
-
-/* possible outcome of pageout() */
-typedef enum {
- /* failed to write page out, page is locked */
- PAGE_KEEP,
- /* move page to the active list, page is locked */
- PAGE_ACTIVATE,
- /* page has been sent to the disk successfully, page is unlocked */
- PAGE_SUCCESS,
- /* page is clean and locked */
- PAGE_CLEAN,
-} pageout_t;
-
-extern pageout_t pageout(struct page *page, struct address_space *mapping);
+extern long vm_total_pages;
#ifdef CONFIG_NUMA
extern int zone_reclaim_mode;
@@ -250,7 +246,6 @@ extern int remove_exclusive_swap_page(struct page *);
struct backing_dev_info;
extern spinlock_t swap_lock;
-extern int remove_vma_swap(struct vm_area_struct *vma, struct page *page);
/* linux/mm/thrash.c */
extern struct mm_struct * swap_token_mm;
@@ -288,18 +283,60 @@ static inline void disable_swap_token(void)
#define free_pages_and_swap_cache(pages, nr) \
release_pages((pages), (nr), 0);
-#define show_swap_cache_info() /*NOTHING*/
-#define free_swap_and_cache(swp) /*NOTHING*/
-#define swap_duplicate(swp) /*NOTHING*/
-#define swap_free(swp) /*NOTHING*/
-#define read_swap_cache_async(swp,vma,addr) NULL
-#define lookup_swap_cache(swp) NULL
-#define valid_swaphandles(swp, off) 0
+static inline void show_swap_cache_info(void)
+{
+}
+
+static inline void free_swap_and_cache(swp_entry_t swp)
+{
+}
+
+static inline int swap_duplicate(swp_entry_t swp)
+{
+ return 0;
+}
+
+static inline void swap_free(swp_entry_t swp)
+{
+}
+
+static inline struct page *read_swap_cache_async(swp_entry_t swp,
+ struct vm_area_struct *vma, unsigned long addr)
+{
+ return NULL;
+}
+
+static inline struct page *lookup_swap_cache(swp_entry_t swp)
+{
+ return NULL;
+}
+
+static inline int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
+{
+ return 0;
+}
+
#define can_share_swap_page(p) (page_mapcount(p) == 1)
-#define move_to_swap_cache(p, swp) 1
-#define move_from_swap_cache(p, i, m) 1
-#define __delete_from_swap_cache(p) /*NOTHING*/
-#define delete_from_swap_cache(p) /*NOTHING*/
+
+static inline int move_to_swap_cache(struct page *page, swp_entry_t entry)
+{
+ return 1;
+}
+
+static inline int move_from_swap_cache(struct page *page, unsigned long index,
+ struct address_space *mapping)
+{
+ return 1;
+}
+
+static inline void __delete_from_swap_cache(struct page *page)
+{
+}
+
+static inline void delete_from_swap_cache(struct page *page)
+{
+}
+
#define swap_token_default_timeout 0
static inline int remove_exclusive_swap_page(struct page *p)
diff --git a/include/linux/swapops.h b/include/linux/swapops.h
index 87b9d14..ec639aa 100644
--- a/include/linux/swapops.h
+++ b/include/linux/swapops.h
@@ -67,3 +67,56 @@ static inline pte_t swp_entry_to_pte(swp_entry_t entry)
BUG_ON(pte_file(__swp_entry_to_pte(arch_entry)));
return __swp_entry_to_pte(arch_entry);
}
+
+#ifdef CONFIG_MIGRATION
+static inline swp_entry_t make_migration_entry(struct page *page, int write)
+{
+ BUG_ON(!PageLocked(page));
+ return swp_entry(write ? SWP_MIGRATION_WRITE : SWP_MIGRATION_READ,
+ page_to_pfn(page));
+}
+
+static inline int is_migration_entry(swp_entry_t entry)
+{
+ return unlikely(swp_type(entry) == SWP_MIGRATION_READ ||
+ swp_type(entry) == SWP_MIGRATION_WRITE);
+}
+
+static inline int is_write_migration_entry(swp_entry_t entry)
+{
+ return unlikely(swp_type(entry) == SWP_MIGRATION_WRITE);
+}
+
+static inline struct page *migration_entry_to_page(swp_entry_t entry)
+{
+ struct page *p = pfn_to_page(swp_offset(entry));
+ /*
+ * Any use of migration entries may only occur while the
+ * corresponding page is locked
+ */
+ BUG_ON(!PageLocked(p));
+ return p;
+}
+
+static inline void make_migration_entry_read(swp_entry_t *entry)
+{
+ *entry = swp_entry(SWP_MIGRATION_READ, swp_offset(*entry));
+}
+
+extern void migration_entry_wait(struct mm_struct *mm, pmd_t *pmd,
+ unsigned long address);
+#else
+
+#define make_migration_entry(page, write) swp_entry(0, 0)
+#define is_migration_entry(swp) 0
+#define migration_entry_to_page(swp) NULL
+static inline void make_migration_entry_read(swp_entry_t *entryp) { }
+static inline void migration_entry_wait(struct mm_struct *mm, pmd_t *pmd,
+ unsigned long address) { }
+static inline int is_write_migration_entry(swp_entry_t entry)
+{
+ return 0;
+}
+
+#endif
+
diff --git a/include/linux/synclink.h b/include/linux/synclink.h
index 2993302..0577f52 100644
--- a/include/linux/synclink.h
+++ b/include/linux/synclink.h
@@ -1,7 +1,7 @@
/*
* SyncLink Multiprotocol Serial Adapter Driver
*
- * $Id: synclink.h,v 3.11 2006/02/06 21:20:29 paulkf Exp $
+ * $Id: synclink.h,v 3.13 2006/05/23 18:25:06 paulkf Exp $
*
* Copyright (C) 1998-2000 by Microgate Corporation
*
@@ -97,6 +97,8 @@
#define HDLC_TXIDLE_ALT_MARK_SPACE 4
#define HDLC_TXIDLE_SPACE 5
#define HDLC_TXIDLE_MARK 6
+#define HDLC_TXIDLE_CUSTOM_8 0x10000000
+#define HDLC_TXIDLE_CUSTOM_16 0x20000000
#define HDLC_ENCODING_NRZ 0
#define HDLC_ENCODING_NRZB 1
@@ -170,6 +172,7 @@ typedef struct _MGSL_PARAMS
#define SYNCLINK_GT_DEVICE_ID 0x0070
#define SYNCLINK_GT4_DEVICE_ID 0x0080
#define SYNCLINK_AC_DEVICE_ID 0x0090
+#define SYNCLINK_GT2_DEVICE_ID 0x00A0
#define MGSL_MAX_SERIAL_NUMBER 30
/*
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index bd67a44..33785b7 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -516,6 +516,16 @@ asmlinkage long sys_set_mempolicy(int mode, unsigned long __user *nmask,
asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode,
const unsigned long __user *from,
const unsigned long __user *to);
+asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages,
+ const void __user * __user *pages,
+ const int __user *nodes,
+ int __user *status,
+ int flags);
+asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_page,
+ __u32 __user *pages,
+ const int __user *nodes,
+ int __user *status,
+ int flags);
asmlinkage long sys_mbind(unsigned long start, unsigned long len,
unsigned long mode,
unsigned long __user *nmask,
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index cee944d..6a60770 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -55,7 +55,7 @@ enum
CTL_KERN=1, /* General kernel info and control */
CTL_VM=2, /* VM management */
CTL_NET=3, /* Networking */
- CTL_PROC=4, /* Process info */
+ /* was CTL_PROC */
CTL_FS=5, /* Filesystems */
CTL_DEBUG=6, /* Debugging */
CTL_DEV=7, /* Devices */
@@ -186,6 +186,7 @@ enum
VM_PERCPU_PAGELIST_FRACTION=30,/* int: fraction of pages in each percpu_pagelist */
VM_ZONE_RECLAIM_MODE=31, /* reclaim local zone memory before going off node */
VM_ZONE_RECLAIM_INTERVAL=32, /* time period to wait after reclaim failure */
+ VM_PANIC_ON_OOM=33, /* panic at out-of-memory */
};
@@ -766,8 +767,6 @@ enum {
NET_BRIDGE_NF_FILTER_VLAN_TAGGED = 4,
};
-/* CTL_PROC names: */
-
/* CTL_FS names: */
enum
{
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 420a689..8ebf497 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -18,7 +18,6 @@
#define _LINUX_TCP_H
#include <linux/types.h>
-#include <linux/dmaengine.h>
#include <asm/byteorder.h>
struct tcphdr {
@@ -161,6 +160,7 @@ struct tcp_info
#ifdef __KERNEL__
#include <linux/skbuff.h>
+#include <linux/dmaengine.h>
#include <net/sock.h>
#include <net/inet_connection_sock.h>
#include <net/inet_timewait_sock.h>
diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
new file mode 100644
index 0000000..391e7ed
--- /dev/null
+++ b/include/linux/uaccess.h
@@ -0,0 +1,22 @@
+#ifndef __LINUX_UACCESS_H__
+#define __LINUX_UACCESS_H__
+
+#include <asm/uaccess.h>
+
+#ifndef ARCH_HAS_NOCACHE_UACCESS
+
+static inline unsigned long __copy_from_user_inatomic_nocache(void *to,
+ const void __user *from, unsigned long n)
+{
+ return __copy_from_user_inatomic(to, from, n);
+}
+
+static inline unsigned long __copy_from_user_nocache(void *to,
+ const void __user *from, unsigned long n)
+{
+ return __copy_from_user(to, from, n);
+}
+
+#endif /* ARCH_HAS_NOCACHE_UACCESS */
+
+#endif /* __LINUX_UACCESS_H__ */
diff --git a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h
index 86b5b42..914f911 100644
--- a/include/linux/ufs_fs.h
+++ b/include/linux/ufs_fs.h
@@ -220,6 +220,19 @@ typedef __u16 __bitwise __fs16;
*/
#define UFS_MINFREE 5
#define UFS_DEFAULTOPT UFS_OPTTIME
+
+/*
+ * Debug code
+ */
+#ifdef CONFIG_UFS_DEBUG
+# define UFSD(f, a...) { \
+ printk ("UFSD (%s, %d): %s:", \
+ __FILE__, __LINE__, __FUNCTION__); \
+ printk (f, ## a); \
+ }
+#else
+# define UFSD(f, a...) /**/
+#endif
/*
* Turn file system block numbers into disk block addresses.
@@ -339,7 +352,22 @@ struct ufs2_csum_total {
};
/*
+ * File system flags
+ */
+#define UFS_UNCLEAN 0x01 /* file system not clean at mount (unused) */
+#define UFS_DOSOFTDEP 0x02 /* file system using soft dependencies */
+#define UFS_NEEDSFSCK 0x04 /* needs sync fsck (FreeBSD compat, unused) */
+#define UFS_INDEXDIRS 0x08 /* kernel supports indexed directories */
+#define UFS_ACLS 0x10 /* file system has ACLs enabled */
+#define UFS_MULTILABEL 0x20 /* file system is MAC multi-label */
+#define UFS_FLAGS_UPDATED 0x80 /* flags have been moved to new location */
+
+#if 0
+/*
* This is the actual superblock, as it is laid out on the disk.
+ * Do NOT use this structure, because of sizeof(ufs_super_block) > 512 and
+ * it may occupy several blocks, use
+ * struct ufs_super_block_(first,second,third) instead.
*/
struct ufs_super_block {
__fs32 fs_link; /* UNUSED */
@@ -416,7 +444,7 @@ struct ufs_super_block {
__s8 fs_fmod; /* super block modified flag */
__s8 fs_clean; /* file system is clean flag */
__s8 fs_ronly; /* mounted read-only flag */
- __s8 fs_flags; /* currently unused flag */
+ __s8 fs_flags;
union {
struct {
__s8 fs_fsmnt[UFS_MAXMNTLEN];/* name mounted on */
@@ -485,6 +513,7 @@ struct ufs_super_block {
__fs32 fs_magic; /* magic number */
__u8 fs_space[1]; /* list of blocks for each rotation */
};
+#endif/*struct ufs_super_block*/
/*
* Preference for optimization.
@@ -666,7 +695,7 @@ struct ufs_buffer_head {
};
struct ufs_cg_private_info {
- struct ufs_cylinder_group ucg;
+ struct ufs_buffer_head c_ubh;
__u32 c_cgx; /* number of cylidner group */
__u16 c_ncyl; /* number of cyl's this cg */
__u16 c_niblk; /* number of inode blocks this cg */
@@ -686,6 +715,7 @@ struct ufs_cg_private_info {
struct ufs_sb_private_info {
struct ufs_buffer_head s_ubh; /* buffer containing super block */
+ struct ufs2_csum_total cs_total;
__u32 s_sblkno; /* offset of super-blocks in filesys */
__u32 s_cblkno; /* offset of cg-block in filesys */
__u32 s_iblkno; /* offset of inode-blocks in filesys */
@@ -824,16 +854,54 @@ struct ufs_super_block_first {
};
struct ufs_super_block_second {
- __s8 fs_fsmnt[212];
- __fs32 fs_cgrotor;
- __fs32 fs_csp[UFS_MAXCSBUFS];
- __fs32 fs_maxcluster;
- __fs32 fs_cpc;
- __fs16 fs_opostbl[82];
-};
+ union {
+ struct {
+ __s8 fs_fsmnt[212];
+ __fs32 fs_cgrotor;
+ __fs32 fs_csp[UFS_MAXCSBUFS];
+ __fs32 fs_maxcluster;
+ __fs32 fs_cpc;
+ __fs16 fs_opostbl[82];
+ } fs_u1;
+ struct {
+ __s8 fs_fsmnt[UFS2_MAXMNTLEN - UFS_MAXMNTLEN + 212];
+ __u8 fs_volname[UFS2_MAXVOLLEN];
+ __fs64 fs_swuid;
+ __fs32 fs_pad;
+ __fs32 fs_cgrotor;
+ __fs32 fs_ocsp[UFS2_NOCSPTRS];
+ __fs32 fs_contigdirs;
+ __fs32 fs_csp;
+ __fs32 fs_maxcluster;
+ __fs32 fs_active;
+ __fs32 fs_old_cpc;
+ __fs32 fs_maxbsize;
+ __fs64 fs_sparecon64[17];
+ __fs64 fs_sblockloc;
+ __fs64 cs_ndir;
+ __fs64 cs_nbfree;
+ } fs_u2;
+ } fs_un;
+};
struct ufs_super_block_third {
- __fs16 fs_opostbl[46];
+ union {
+ struct {
+ __fs16 fs_opostbl[46];
+ } fs_u1;
+ struct {
+ __fs64 cs_nifree; /* number of free inodes */
+ __fs64 cs_nffree; /* number of free frags */
+ __fs64 cs_numclusters; /* number of free clusters */
+ __fs64 cs_spare[3]; /* future expansion */
+ struct ufs_timeval fs_time; /* last time written */
+ __fs64 fs_size; /* number of blocks in fs */
+ __fs64 fs_dsize; /* number of data blocks in fs */
+ __fs64 fs_csaddr; /* blk addr of cyl grp summary area */
+ __fs64 fs_pendingblocks;/* blocks in process of being freed */
+ __fs32 fs_pendinginodes;/*inodes in process of being freed */
+ } fs_u2;
+ } fs_un1;
union {
struct {
__fs32 fs_sparecon[53];/* reserved for future constants */
@@ -861,7 +929,7 @@ struct ufs_super_block_third {
__fs32 fs_qfmask[2]; /* ~usb_fmask */
__fs32 fs_state; /* file system state time stamp */
} fs_44;
- } fs_u2;
+ } fs_un2;
__fs32 fs_postblformat;
__fs32 fs_nrpos;
__fs32 fs_postbloff;
@@ -875,7 +943,8 @@ struct ufs_super_block_third {
/* balloc.c */
extern void ufs_free_fragments (struct inode *, unsigned, unsigned);
extern void ufs_free_blocks (struct inode *, unsigned, unsigned);
-extern unsigned ufs_new_fragments (struct inode *, __fs32 *, unsigned, unsigned, unsigned, int *);
+extern unsigned ufs_new_fragments(struct inode *, __fs32 *, unsigned, unsigned,
+ unsigned, int *, struct page *);
/* cylinder.c */
extern struct ufs_cg_private_info * ufs_load_cylinder (struct super_block *, unsigned);
@@ -886,11 +955,12 @@ extern struct inode_operations ufs_dir_inode_operations;
extern int ufs_add_link (struct dentry *, struct inode *);
extern ino_t ufs_inode_by_name(struct inode *, struct dentry *);
extern int ufs_make_empty(struct inode *, struct inode *);
-extern struct ufs_dir_entry * ufs_find_entry (struct dentry *, struct buffer_head **);
-extern int ufs_delete_entry (struct inode *, struct ufs_dir_entry *, struct buffer_head *);
+extern struct ufs_dir_entry *ufs_find_entry(struct inode *, struct dentry *, struct page **);
+extern int ufs_delete_entry(struct inode *, struct ufs_dir_entry *, struct page *);
extern int ufs_empty_dir (struct inode *);
-extern struct ufs_dir_entry * ufs_dotdot (struct inode *, struct buffer_head **);
-extern void ufs_set_link(struct inode *, struct ufs_dir_entry *, struct buffer_head *, struct inode *);
+extern struct ufs_dir_entry *ufs_dotdot(struct inode *, struct page **);
+extern void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
+ struct page *page, struct inode *inode);
/* file.c */
extern struct inode_operations ufs_file_inode_operations;
@@ -903,13 +973,11 @@ extern void ufs_free_inode (struct inode *inode);
extern struct inode * ufs_new_inode (struct inode *, int);
/* inode.c */
-extern u64 ufs_frag_map (struct inode *, sector_t);
extern void ufs_read_inode (struct inode *);
extern void ufs_put_inode (struct inode *);
extern int ufs_write_inode (struct inode *, int);
extern int ufs_sync_inode (struct inode *);
extern void ufs_delete_inode (struct inode *);
-extern struct buffer_head * ufs_getfrag (struct inode *, unsigned, int, int *);
extern struct buffer_head * ufs_bread (struct inode *, unsigned, int, int *);
extern int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create);
diff --git a/include/linux/ufs_fs_i.h b/include/linux/ufs_fs_i.h
index 21665a9..f50ce3b 100644
--- a/include/linux/ufs_fs_i.h
+++ b/include/linux/ufs_fs_i.h
@@ -27,6 +27,7 @@ struct ufs_inode_info {
__u32 i_oeftflag;
__u16 i_osync;
__u32 i_lastfrag;
+ __u32 i_dir_start_lookup;
struct inode vfs_inode;
};
diff --git a/include/linux/videodev.h b/include/linux/videodev.h
index 9114009..41bc7e9 100644
--- a/include/linux/videodev.h
+++ b/include/linux/videodev.h
@@ -1,49 +1,21 @@
+/*
+ * Video for Linux version 1 - OBSOLETE
+ *
+ * Header file for v4l1 drivers and applications, for
+ * Linux kernels 2.2.x or 2.4.x.
+ *
+ * Provides header for legacy drivers and applications
+ *
+ * See http://linuxtv.org for more info
+ *
+ */
#ifndef __LINUX_VIDEODEV_H
#define __LINUX_VIDEODEV_H
-#include <linux/types.h>
-
#define HAVE_V4L1 1
#include <linux/videodev2.h>
-#ifdef __KERNEL__
-
-#include <linux/mm.h>
-
-extern struct video_device* video_devdata(struct file*);
-
-#define to_video_device(cd) container_of(cd, struct video_device, class_dev)
-static inline void
-video_device_create_file(struct video_device *vfd,
- struct class_device_attribute *attr)
-{
- class_device_create_file(&vfd->class_dev, attr);
-}
-static inline void
-video_device_remove_file(struct video_device *vfd,
- struct class_device_attribute *attr)
-{
- class_device_remove_file(&vfd->class_dev, attr);
-}
-
-#if OBSOLETE_OWNER /* to be removed in 2.6.15 */
-/* helper functions to access driver private data. */
-static inline void *video_get_drvdata(struct video_device *dev)
-{
- return dev->priv;
-}
-
-static inline void video_set_drvdata(struct video_device *dev, void *data)
-{
- dev->priv = data;
-}
-#endif
-
-extern int video_exclusive_open(struct inode *inode, struct file *file);
-extern int video_exclusive_release(struct inode *inode, struct file *file);
-#endif /* __KERNEL__ */
-
struct video_capability
{
char name[32];
@@ -363,6 +335,7 @@ struct video_code
#define VID_HARDWARE_SAA7114H 37
#define VID_HARDWARE_SN9C102 38
#define VID_HARDWARE_ARV 39
+
#endif /* __LINUX_VIDEODEV_H */
/*
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index ad7fa9c..4f42854 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1,35 +1,33 @@
-#ifndef __LINUX_VIDEODEV2_H
-#define __LINUX_VIDEODEV2_H
/*
* Video for Linux Two
*
- * Header file for v4l or V4L2 drivers and applications, for
- * Linux kernels 2.2.x or 2.4.x.
+ * Header file for v4l or V4L2 drivers and applications
+ * with public API.
+ * All kernel-specific stuff were moved to media/v4l2-dev.h, so
+ * no #if __KERNEL tests are allowed here
*
- * See http://bytesex.org/v4l/ for API specs and other
- * v4l2 documentation.
+ * See http://linuxtv.org for more info
*
* Author: Bill Dirks <bdirks@pacbell.net>
* Justin Schoeman
* et al.
*/
+#ifndef __LINUX_VIDEODEV2_H
+#define __LINUX_VIDEODEV2_H
#ifdef __KERNEL__
-#include <linux/time.h> /* need struct timeval */
-#include <linux/poll.h>
-#include <linux/device.h>
-#include <linux/mutex.h>
-#endif
+#include <linux/time.h> /* need struct timeval */
#include <linux/compiler.h> /* need __user */
+#else
+#define __user
+#endif
+#include <linux/types.h>
-
-#define OBSOLETE_OWNER 1 /* It will be removed for 2.6.17 */
#define HAVE_V4L2 1
/*
* Common stuff for both V4L1 and V4L2
* Moved from videodev.h
*/
-
#define VIDEO_MAX_FRAME 32
#define VID_TYPE_CAPTURE 1 /* Can capture */
@@ -47,71 +45,6 @@
#define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */
#define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */
-#ifdef __KERNEL__
-
-/* Minor device allocation */
-#define MINOR_VFL_TYPE_GRABBER_MIN 0
-#define MINOR_VFL_TYPE_GRABBER_MAX 63
-#define MINOR_VFL_TYPE_RADIO_MIN 64
-#define MINOR_VFL_TYPE_RADIO_MAX 127
-#define MINOR_VFL_TYPE_VTX_MIN 192
-#define MINOR_VFL_TYPE_VTX_MAX 223
-#define MINOR_VFL_TYPE_VBI_MIN 224
-#define MINOR_VFL_TYPE_VBI_MAX 255
-
-#define VFL_TYPE_GRABBER 0
-#define VFL_TYPE_VBI 1
-#define VFL_TYPE_RADIO 2
-#define VFL_TYPE_VTX 3
-
-struct video_device
-{
- /* device info */
- struct device *dev;
- char name[32];
- int type; /* v4l1 */
- int type2; /* v4l2 */
- int hardware;
- int minor;
-
- /* device ops + callbacks */
- const struct file_operations *fops;
- void (*release)(struct video_device *vfd);
-
-
-#if OBSOLETE_OWNER /* to be removed in 2.6.15 */
- /* obsolete -- fops->owner is used instead */
- struct module *owner;
- /* dev->driver_data will be used instead some day.
- * Use the video_{get|set}_drvdata() helper functions,
- * so the switch over will be transparent for you.
- * Or use {pci|usb}_{get|set}_drvdata() directly. */
- void *priv;
-#endif
-
- /* for videodev.c intenal usage -- please don't touch */
- int users; /* video_exclusive_{open|close} ... */
- struct mutex lock; /* ... helper function uses these */
- char devfs_name[64]; /* devfs */
- struct class_device class_dev; /* sysfs */
-};
-
-#define VIDEO_MAJOR 81
-
-extern int video_register_device(struct video_device *, int type, int nr);
-extern void video_unregister_device(struct video_device *);
-extern int video_usercopy(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg,
- int (*func)(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg));
-
-/* helper functions to alloc / release struct video_device, the
- later can be used for video_device->release() */
-struct video_device *video_device_alloc(void);
-void video_device_release(struct video_device *vfd);
-
-#endif
-
/*
* M I S C E L L A N E O U S
*/
@@ -172,6 +105,8 @@ enum v4l2_ctrl_type {
V4L2_CTRL_TYPE_BOOLEAN = 2,
V4L2_CTRL_TYPE_MENU = 3,
V4L2_CTRL_TYPE_BUTTON = 4,
+ V4L2_CTRL_TYPE_INTEGER64 = 5,
+ V4L2_CTRL_TYPE_CTRL_CLASS = 6,
};
enum v4l2_tuner_type {
@@ -270,7 +205,6 @@ struct v4l2_capability
/*
* V I D E O I M A G E F O R M A T
*/
-
struct v4l2_pix_format
{
__u32 width;
@@ -283,7 +217,7 @@ struct v4l2_pix_format
__u32 priv; /* private data, depends on pixelformat */
};
-/* Pixel format FOURCC depth Description */
+/* Pixel format FOURCC depth Description */
#define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R','G','B','1') /* 8 RGB-3-3-2 */
#define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R','G','B','O') /* 16 RGB-5-5-5 */
#define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R','G','B','P') /* 16 RGB-5-6-5 */
@@ -319,7 +253,7 @@ struct v4l2_pix_format
#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M','J','P','G') /* Motion-JPEG */
#define V4L2_PIX_FMT_JPEG v4l2_fourcc('J','P','E','G') /* JFIF JPEG */
#define V4L2_PIX_FMT_DV v4l2_fourcc('d','v','s','d') /* 1394 */
-#define V4L2_PIX_FMT_MPEG v4l2_fourcc('M','P','E','G') /* MPEG */
+#define V4L2_PIX_FMT_MPEG v4l2_fourcc('M','P','E','G') /* MPEG-1/2/4 */
/* Vendor-specific formats */
#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W','N','V','A') /* Winnov hw compress */
@@ -343,7 +277,6 @@ struct v4l2_fmtdesc
#define V4L2_FMT_FLAG_COMPRESSED 0x0001
-
/*
* T I M E C O D E
*/
@@ -373,16 +306,15 @@ struct v4l2_timecode
#define V4L2_TC_USERBITS_8BITCHARS 0x0008
/* The above is based on SMPTE timecodes */
-
+#ifdef __KERNEL__
/*
* M P E G C O M P R E S S I O N P A R A M E T E R S
*
- * ### WARNING: this is still work-in-progress right now, most likely
- * ### there will be some incompatible changes.
+ * ### WARNING: This experimental MPEG compression API is obsolete.
+ * ### It is replaced by the MPEG controls API.
+ * ### This old API will disappear in the near future!
*
*/
-
-
enum v4l2_bitrate_mode {
V4L2_BITRATE_NONE = 0, /* not specified */
V4L2_BITRATE_CBR, /* constant bitrate */
@@ -460,6 +392,7 @@ struct v4l2_mpeg_compression {
/* I don't expect the above being perfect yet ;) */
__u32 reserved_5[8];
};
+#endif
struct v4l2_jpegcompression
{
@@ -491,7 +424,6 @@ struct v4l2_jpegcompression
* allways use APP0 */
};
-
/*
* M E M O R Y - M A P P I N G B U F F E R S
*/
@@ -573,7 +505,6 @@ struct v4l2_window
void __user *bitmap;
};
-
/*
* C A P T U R E P A R A M E T E R S
*/
@@ -586,6 +517,7 @@ struct v4l2_captureparm
__u32 readbuffers; /* # of buffers for read */
__u32 reserved[4];
};
+
/* Flags for 'capability' and 'capturemode' fields */
#define V4L2_MODE_HIGHQUALITY 0x0001 /* High quality imaging mode */
#define V4L2_CAP_TIMEPERFRAME 0x1000 /* timeperframe field is supported */
@@ -603,7 +535,6 @@ struct v4l2_outputparm
/*
* I N P U T I M A G E C R O P P I N G
*/
-
struct v4l2_cropcap {
enum v4l2_buf_type type;
struct v4l2_rect bounds;
@@ -710,7 +641,6 @@ struct v4l2_standard
__u32 reserved[4];
};
-
/*
* V I D E O I N P U T S
*/
@@ -725,6 +655,7 @@ struct v4l2_input
__u32 status;
__u32 reserved[4];
};
+
/* Values for the 'type' field */
#define V4L2_INPUT_TYPE_TUNER 1
#define V4L2_INPUT_TYPE_CAMERA 2
@@ -775,6 +706,34 @@ struct v4l2_control
__s32 value;
};
+struct v4l2_ext_control
+{
+ __u32 id;
+ __u32 reserved2[2];
+ union {
+ __s32 value;
+ __s64 value64;
+ void *reserved;
+ };
+};
+
+struct v4l2_ext_controls
+{
+ __u32 ctrl_class;
+ __u32 count;
+ __u32 error_idx;
+ __u32 reserved[2];
+ struct v4l2_ext_control *controls;
+};
+
+/* Values for ctrl_class field */
+#define V4L2_CTRL_CLASS_USER 0x00980000 /* Old-style 'user' controls */
+#define V4L2_CTRL_CLASS_MPEG 0x00990000 /* MPEG-compression controls */
+
+#define V4L2_CTRL_ID_MASK (0x0fffffff)
+#define V4L2_CTRL_ID2CLASS(id) ((id) & 0x0fff0000UL)
+#define V4L2_CTRL_DRIVER_PRIV(id) (((id) & 0xffff) >= 0x1000)
+
/* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
struct v4l2_queryctrl
{
@@ -801,12 +760,21 @@ struct v4l2_querymenu
/* Control flags */
#define V4L2_CTRL_FLAG_DISABLED 0x0001
#define V4L2_CTRL_FLAG_GRABBED 0x0002
+#define V4L2_CTRL_FLAG_READ_ONLY 0x0004
+#define V4L2_CTRL_FLAG_UPDATE 0x0008
+#define V4L2_CTRL_FLAG_INACTIVE 0x0010
+#define V4L2_CTRL_FLAG_SLIDER 0x0020
+
+/* Query flag, to be ORed with the control ID */
+#define V4L2_CTRL_FLAG_NEXT_CTRL 0x80000000
-/* Control IDs defined by V4L2 */
-#define V4L2_CID_BASE 0x00980900
+/* User-class control IDs defined by V4L2 */
+#define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900)
+#define V4L2_CID_USER_BASE V4L2_CID_BASE
/* IDs reserved for driver specific controls */
#define V4L2_CID_PRIVATE_BASE 0x08000000
+#define V4L2_CID_USER_CLASS (V4L2_CTRL_CLASS_USER | 1)
#define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0)
#define V4L2_CID_CONTRAST (V4L2_CID_BASE+1)
#define V4L2_CID_SATURATION (V4L2_CID_BASE+2)
@@ -833,6 +801,183 @@ struct v4l2_querymenu
#define V4L2_CID_VCENTER (V4L2_CID_BASE+23)
#define V4L2_CID_LASTP1 (V4L2_CID_BASE+24) /* last CID + 1 */
+/* MPEG-class control IDs defined by V4L2 */
+#define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900)
+#define V4L2_CID_MPEG_CLASS (V4L2_CTRL_CLASS_MPEG | 1)
+
+/* MPEG streams */
+#define V4L2_CID_MPEG_STREAM_TYPE (V4L2_CID_MPEG_BASE+0)
+enum v4l2_mpeg_stream_type {
+ V4L2_MPEG_STREAM_TYPE_MPEG2_PS = 0, /* MPEG-2 program stream */
+ V4L2_MPEG_STREAM_TYPE_MPEG2_TS = 1, /* MPEG-2 transport stream */
+ V4L2_MPEG_STREAM_TYPE_MPEG1_SS = 2, /* MPEG-1 system stream */
+ V4L2_MPEG_STREAM_TYPE_MPEG2_DVD = 3, /* MPEG-2 DVD-compatible stream */
+ V4L2_MPEG_STREAM_TYPE_MPEG1_VCD = 4, /* MPEG-1 VCD-compatible stream */
+ V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD = 5, /* MPEG-2 SVCD-compatible stream */
+};
+#define V4L2_CID_MPEG_STREAM_PID_PMT (V4L2_CID_MPEG_BASE+1)
+#define V4L2_CID_MPEG_STREAM_PID_AUDIO (V4L2_CID_MPEG_BASE+2)
+#define V4L2_CID_MPEG_STREAM_PID_VIDEO (V4L2_CID_MPEG_BASE+3)
+#define V4L2_CID_MPEG_STREAM_PID_PCR (V4L2_CID_MPEG_BASE+4)
+#define V4L2_CID_MPEG_STREAM_PES_ID_AUDIO (V4L2_CID_MPEG_BASE+5)
+#define V4L2_CID_MPEG_STREAM_PES_ID_VIDEO (V4L2_CID_MPEG_BASE+6)
+
+/* MPEG audio */
+#define V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ (V4L2_CID_MPEG_BASE+100)
+enum v4l2_mpeg_audio_sampling_freq {
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100 = 0,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000 = 1,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000 = 2,
+};
+#define V4L2_CID_MPEG_AUDIO_ENCODING (V4L2_CID_MPEG_BASE+101)
+enum v4l2_mpeg_audio_encoding {
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_1 = 0,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2 = 1,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_3 = 2,
+};
+#define V4L2_CID_MPEG_AUDIO_L1_BITRATE (V4L2_CID_MPEG_BASE+102)
+enum v4l2_mpeg_audio_l1_bitrate {
+ V4L2_MPEG_AUDIO_L1_BITRATE_32K = 0,
+ V4L2_MPEG_AUDIO_L1_BITRATE_64K = 1,
+ V4L2_MPEG_AUDIO_L1_BITRATE_96K = 2,
+ V4L2_MPEG_AUDIO_L1_BITRATE_128K = 3,
+ V4L2_MPEG_AUDIO_L1_BITRATE_160K = 4,
+ V4L2_MPEG_AUDIO_L1_BITRATE_192K = 5,
+ V4L2_MPEG_AUDIO_L1_BITRATE_224K = 6,
+ V4L2_MPEG_AUDIO_L1_BITRATE_256K = 7,
+ V4L2_MPEG_AUDIO_L1_BITRATE_288K = 8,
+ V4L2_MPEG_AUDIO_L1_BITRATE_320K = 9,
+ V4L2_MPEG_AUDIO_L1_BITRATE_352K = 10,
+ V4L2_MPEG_AUDIO_L1_BITRATE_384K = 11,
+ V4L2_MPEG_AUDIO_L1_BITRATE_416K = 12,
+ V4L2_MPEG_AUDIO_L1_BITRATE_448K = 13,
+};
+#define V4L2_CID_MPEG_AUDIO_L2_BITRATE (V4L2_CID_MPEG_BASE+103)
+enum v4l2_mpeg_audio_l2_bitrate {
+ V4L2_MPEG_AUDIO_L2_BITRATE_32K = 0,
+ V4L2_MPEG_AUDIO_L2_BITRATE_48K = 1,
+ V4L2_MPEG_AUDIO_L2_BITRATE_56K = 2,
+ V4L2_MPEG_AUDIO_L2_BITRATE_64K = 3,
+ V4L2_MPEG_AUDIO_L2_BITRATE_80K = 4,
+ V4L2_MPEG_AUDIO_L2_BITRATE_96K = 5,
+ V4L2_MPEG_AUDIO_L2_BITRATE_112K = 6,
+ V4L2_MPEG_AUDIO_L2_BITRATE_128K = 7,
+ V4L2_MPEG_AUDIO_L2_BITRATE_160K = 8,
+ V4L2_MPEG_AUDIO_L2_BITRATE_192K = 9,
+ V4L2_MPEG_AUDIO_L2_BITRATE_224K = 10,
+ V4L2_MPEG_AUDIO_L2_BITRATE_256K = 11,
+ V4L2_MPEG_AUDIO_L2_BITRATE_320K = 12,
+ V4L2_MPEG_AUDIO_L2_BITRATE_384K = 13,
+};
+#define V4L2_CID_MPEG_AUDIO_L3_BITRATE (V4L2_CID_MPEG_BASE+104)
+enum v4l2_mpeg_audio_l3_bitrate {
+ V4L2_MPEG_AUDIO_L3_BITRATE_32K = 0,
+ V4L2_MPEG_AUDIO_L3_BITRATE_40K = 1,
+ V4L2_MPEG_AUDIO_L3_BITRATE_48K = 2,
+ V4L2_MPEG_AUDIO_L3_BITRATE_56K = 3,
+ V4L2_MPEG_AUDIO_L3_BITRATE_64K = 4,
+ V4L2_MPEG_AUDIO_L3_BITRATE_80K = 5,
+ V4L2_MPEG_AUDIO_L3_BITRATE_96K = 6,
+ V4L2_MPEG_AUDIO_L3_BITRATE_112K = 7,
+ V4L2_MPEG_AUDIO_L3_BITRATE_128K = 8,
+ V4L2_MPEG_AUDIO_L3_BITRATE_160K = 9,
+ V4L2_MPEG_AUDIO_L3_BITRATE_192K = 10,
+ V4L2_MPEG_AUDIO_L3_BITRATE_224K = 11,
+ V4L2_MPEG_AUDIO_L3_BITRATE_256K = 12,
+ V4L2_MPEG_AUDIO_L3_BITRATE_320K = 13,
+};
+#define V4L2_CID_MPEG_AUDIO_MODE (V4L2_CID_MPEG_BASE+105)
+enum v4l2_mpeg_audio_mode {
+ V4L2_MPEG_AUDIO_MODE_STEREO = 0,
+ V4L2_MPEG_AUDIO_MODE_JOINT_STEREO = 1,
+ V4L2_MPEG_AUDIO_MODE_DUAL = 2,
+ V4L2_MPEG_AUDIO_MODE_MONO = 3,
+};
+#define V4L2_CID_MPEG_AUDIO_MODE_EXTENSION (V4L2_CID_MPEG_BASE+106)
+enum v4l2_mpeg_audio_mode_extension {
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4 = 0,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8 = 1,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12 = 2,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16 = 3,
+};
+#define V4L2_CID_MPEG_AUDIO_EMPHASIS (V4L2_CID_MPEG_BASE+107)
+enum v4l2_mpeg_audio_emphasis {
+ V4L2_MPEG_AUDIO_EMPHASIS_NONE = 0,
+ V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS = 1,
+ V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17 = 2,
+};
+#define V4L2_CID_MPEG_AUDIO_CRC (V4L2_CID_MPEG_BASE+108)
+enum v4l2_mpeg_audio_crc {
+ V4L2_MPEG_AUDIO_CRC_NONE = 0,
+ V4L2_MPEG_AUDIO_CRC_CRC16 = 1,
+};
+
+/* MPEG video */
+#define V4L2_CID_MPEG_VIDEO_ENCODING (V4L2_CID_MPEG_BASE+200)
+enum v4l2_mpeg_video_encoding {
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_1 = 0,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2 = 1,
+};
+#define V4L2_CID_MPEG_VIDEO_ASPECT (V4L2_CID_MPEG_BASE+201)
+enum v4l2_mpeg_video_aspect {
+ V4L2_MPEG_VIDEO_ASPECT_1x1 = 0,
+ V4L2_MPEG_VIDEO_ASPECT_4x3 = 1,
+ V4L2_MPEG_VIDEO_ASPECT_16x9 = 2,
+ V4L2_MPEG_VIDEO_ASPECT_221x100 = 3,
+};
+#define V4L2_CID_MPEG_VIDEO_B_FRAMES (V4L2_CID_MPEG_BASE+202)
+#define V4L2_CID_MPEG_VIDEO_GOP_SIZE (V4L2_CID_MPEG_BASE+203)
+#define V4L2_CID_MPEG_VIDEO_GOP_CLOSURE (V4L2_CID_MPEG_BASE+204)
+#define V4L2_CID_MPEG_VIDEO_PULLDOWN (V4L2_CID_MPEG_BASE+205)
+#define V4L2_CID_MPEG_VIDEO_BITRATE_MODE (V4L2_CID_MPEG_BASE+206)
+enum v4l2_mpeg_video_bitrate_mode {
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR = 0,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR = 1,
+};
+#define V4L2_CID_MPEG_VIDEO_BITRATE (V4L2_CID_MPEG_BASE+207)
+#define V4L2_CID_MPEG_VIDEO_BITRATE_PEAK (V4L2_CID_MPEG_BASE+208)
+#define V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION (V4L2_CID_MPEG_BASE+209)
+
+/* MPEG-class control IDs specific to the CX2584x driver as defined by V4L2 */
+#define V4L2_CID_MPEG_CX2341X_BASE (V4L2_CTRL_CLASS_MPEG | 0x1000)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE (V4L2_CID_MPEG_CX2341X_BASE+0)
+enum v4l2_mpeg_cx2341x_video_spatial_filter_mode {
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL = 0,
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO = 1,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER (V4L2_CID_MPEG_CX2341X_BASE+1)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE (V4L2_CID_MPEG_CX2341X_BASE+2)
+enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type {
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF = 0,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR = 1,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT = 2,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE = 3,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE = 4,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE (V4L2_CID_MPEG_CX2341X_BASE+3)
+enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type {
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF = 0,
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR = 1,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE (V4L2_CID_MPEG_CX2341X_BASE+4)
+enum v4l2_mpeg_cx2341x_video_temporal_filter_mode {
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL = 0,
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO = 1,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER (V4L2_CID_MPEG_CX2341X_BASE+5)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE (V4L2_CID_MPEG_CX2341X_BASE+6)
+enum v4l2_mpeg_cx2341x_video_median_filter_type {
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF = 0,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR = 1,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT = 2,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT = 3,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG = 4,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM (V4L2_CID_MPEG_CX2341X_BASE+7)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP (V4L2_CID_MPEG_CX2341X_BASE+8)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM (V4L2_CID_MPEG_CX2341X_BASE+9)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP (V4L2_CID_MPEG_CX2341X_BASE+10)
+
/*
* T U N I N G
*/
@@ -904,6 +1049,7 @@ struct v4l2_audio
__u32 mode;
__u32 reserved[2];
};
+
/* Flags for the 'capability' field */
#define V4L2_AUDCAP_STEREO 0x00001
#define V4L2_AUDCAP_AVL 0x00002
@@ -927,7 +1073,6 @@ struct v4l2_audioout
*/
/* Raw VBI */
-
struct v4l2_vbi_format
{
__u32 sampling_rate; /* in 1 Hz */
@@ -1034,8 +1179,6 @@ struct v4l2_streamparm
} parm;
};
-
-
/*
* I O C T L C O D E S F O R V I D E O D E V I C E S
*
@@ -1045,8 +1188,10 @@ struct v4l2_streamparm
#define VIDIOC_ENUM_FMT _IOWR ('V', 2, struct v4l2_fmtdesc)
#define VIDIOC_G_FMT _IOWR ('V', 4, struct v4l2_format)
#define VIDIOC_S_FMT _IOWR ('V', 5, struct v4l2_format)
+#ifdef __KERNEL__
#define VIDIOC_G_MPEGCOMP _IOR ('V', 6, struct v4l2_mpeg_compression)
#define VIDIOC_S_MPEGCOMP _IOW ('V', 7, struct v4l2_mpeg_compression)
+#endif
#define VIDIOC_REQBUFS _IOWR ('V', 8, struct v4l2_requestbuffers)
#define VIDIOC_QUERYBUF _IOWR ('V', 9, struct v4l2_buffer)
#define VIDIOC_G_FBUF _IOR ('V', 10, struct v4l2_framebuffer)
@@ -1096,7 +1241,11 @@ struct v4l2_streamparm
#define VIDIOC_G_SLICED_VBI_CAP _IOR ('V', 69, struct v4l2_sliced_vbi_cap)
#endif
#define VIDIOC_LOG_STATUS _IO ('V', 70)
+#define VIDIOC_G_EXT_CTRLS _IOWR ('V', 71, struct v4l2_ext_controls)
+#define VIDIOC_S_EXT_CTRLS _IOWR ('V', 72, struct v4l2_ext_controls)
+#define VIDIOC_TRY_EXT_CTRLS _IOWR ('V', 73, struct v4l2_ext_controls)
+#ifdef __OLD_VIDIOC_
/* for compatibility, will go away some day */
#define VIDIOC_OVERLAY_OLD _IOWR ('V', 14, int)
#define VIDIOC_S_PARM_OLD _IOW ('V', 22, struct v4l2_streamparm)
@@ -1104,57 +1253,10 @@ struct v4l2_streamparm
#define VIDIOC_G_AUDIO_OLD _IOWR ('V', 33, struct v4l2_audio)
#define VIDIOC_G_AUDOUT_OLD _IOWR ('V', 49, struct v4l2_audioout)
#define VIDIOC_CROPCAP_OLD _IOR ('V', 58, struct v4l2_cropcap)
-
-#define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */
-
-
-#ifdef __KERNEL__
-/*
- *
- * V 4 L 2 D R I V E R H E L P E R A P I
- *
- * Some commonly needed functions for drivers (v4l2-common.o module)
- */
-#include <linux/fs.h>
-
-/* Video standard functions */
-extern unsigned int v4l2_video_std_fps(struct v4l2_standard *vs);
-extern int v4l2_video_std_construct(struct v4l2_standard *vs,
- int id, char *name);
-
-/* prority handling */
-struct v4l2_prio_state {
- atomic_t prios[4];
-};
-int v4l2_prio_init(struct v4l2_prio_state *global);
-int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local,
- enum v4l2_priority new);
-int v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local);
-int v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority *local);
-enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global);
-int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local);
-
-/* names for fancy debug output */
-extern char *v4l2_field_names[];
-extern char *v4l2_type_names[];
-
-/* Compatibility layer interface -- v4l1-compat module */
-typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg);
-
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-int v4l_compat_translate_ioctl(struct inode *inode, struct file *file,
- int cmd, void *arg, v4l2_kioctl driver_ioctl);
-#else
-#define v4l_compat_translate_ioctl(inode,file,cmd,arg,ioctl) -EINVAL
#endif
-/* 32 Bits compatibility layer for 64 bits processors */
-extern long v4l_compat_ioctl32(struct file *file, unsigned int cmd,
- unsigned long arg);
-
+#define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */
-#endif /* __KERNEL__ */
#endif /* __LINUX_VIDEODEV2_H */
/*
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 1d5577b..f6024ab 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -4,10 +4,13 @@
#include <linux/spinlock.h>
#include <asm/page.h> /* pgprot_t */
+struct vm_area_struct;
+
/* bits in vm_struct->flags */
#define VM_IOREMAP 0x00000001 /* ioremap() and friends */
#define VM_ALLOC 0x00000002 /* vmalloc() */
#define VM_MAP 0x00000004 /* vmap()ed pages */
+#define VM_USERMAP 0x00000008 /* suitable for remap_vmalloc_range */
/* bits [20..32] reserved for arch specific ioremap internals */
/*
@@ -32,9 +35,11 @@ struct vm_struct {
* Highlevel APIs for driver use
*/
extern void *vmalloc(unsigned long size);
+extern void *vmalloc_user(unsigned long size);
extern void *vmalloc_node(unsigned long size, int node);
extern void *vmalloc_exec(unsigned long size);
extern void *vmalloc_32(unsigned long size);
+extern void *vmalloc_32_user(unsigned long size);
extern void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot);
extern void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask,
pgprot_t prot);
@@ -45,6 +50,9 @@ extern void vfree(void *addr);
extern void *vmap(struct page **pages, unsigned int count,
unsigned long flags, pgprot_t prot);
extern void vunmap(void *addr);
+
+extern int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
+ unsigned long pgoff);
/*
* Lowlevel-APIs (not for driver use!)
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index 56f92fc..9e38b56 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -50,14 +50,15 @@ struct writeback_control {
* a hint that the filesystem need only write out the pages inside that
* byterange. The byte at `end' is included in the writeout request.
*/
- loff_t start;
- loff_t end;
+ loff_t range_start;
+ loff_t range_end;
unsigned nonblocking:1; /* Don't get stuck on request queues */
unsigned encountered_congestion:1; /* An output: a queue is full */
unsigned for_kupdate:1; /* A kupdate writeback */
unsigned for_reclaim:1; /* Invoked from the page allocator */
unsigned for_writepages:1; /* This is a writepages() call */
+ unsigned range_cyclic:1; /* range_start is cyclic */
};
/*
diff --git a/include/linux/zconf.h b/include/linux/zconf.h
index f1cfd66..0beb75e 100644
--- a/include/linux/zconf.h
+++ b/include/linux/zconf.h
@@ -35,6 +35,18 @@
# define MAX_WBITS 15 /* 32K LZ77 window */
#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+
+/* default memLevel */
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+
/* Type declarations */
typedef unsigned char Byte; /* 8 bits */
diff --git a/include/linux/zlib.h b/include/linux/zlib.h
index 4fa32f0..9e3192a 100644
--- a/include/linux/zlib.h
+++ b/include/linux/zlib.h
@@ -1,7 +1,6 @@
/* zlib.h -- interface of the 'zlib' general purpose compression library
- version 1.1.3, July 9th, 1998
- Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
+ Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -24,7 +23,7 @@
The data format used by the zlib library is described by RFCs (Request for
- Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+ Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
(zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
*/
@@ -33,7 +32,22 @@
#include <linux/zconf.h>
-#define ZLIB_VERSION "1.1.3"
+/* zlib deflate based on ZLIB_VERSION "1.1.3" */
+/* zlib inflate based on ZLIB_VERSION "1.2.3" */
+
+/*
+ This is a modified version of zlib for use inside the Linux kernel.
+ The main changes are to perform all memory allocation in advance.
+
+ Inflation Changes:
+ * Z_PACKET_FLUSH is added and used by ppp_deflate. Before returning
+ this checks there is no more input data available and the next data
+ is a STORED block. It also resets the mode to be read for the next
+ data, all as per PPP requirements.
+ * Addition of zlib_inflateIncomp which copies incompressible data into
+ the history window and adjusts the accoutning without calling
+ zlib_inflate itself to inflate the data.
+*/
/*
The 'zlib' compression library provides in-memory compression and
@@ -48,9 +62,18 @@
application must provide more input and/or consume the output
(providing more output space) before each call.
+ The compressed data format used by default by the in-memory functions is
+ the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+ around a deflate stream, which is itself documented in RFC 1951.
+
The library also supports reading and writing files in gzip (.gz) format
with an interface similar to that of stdio.
+ The zlib format was designed to be compact and fast for use in memory
+ and on communications channels. The gzip format was designed for single-
+ file compression on file systems, has a larger header than zlib to maintain
+ directory information, and uses a different, slower check method than zlib.
+
The library does not install any signal handler. The decoder checks
the consistency of the compressed data, so the library should never
crash even in case of corrupted input.
@@ -119,7 +142,8 @@ typedef z_stream *z_streamp;
#define Z_SYNC_FLUSH 3
#define Z_FULL_FLUSH 4
#define Z_FINISH 5
-/* Allowed flush values; see deflate() below for details */
+#define Z_BLOCK 6 /* Only for inflate at present */
+/* Allowed flush values; see deflate() and inflate() below for details */
#define Z_OK 0
#define Z_STREAM_END 1
@@ -155,13 +179,6 @@ typedef z_stream *z_streamp;
/* basic functions */
-extern const char * zlib_zlibVersion (void);
-/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
- If the first character differs, the library code actually used is
- not compatible with the zlib.h header file used by the application.
- This check is automatically made by deflateInit and inflateInit.
- */
-
extern int zlib_deflate_workspacesize (void);
/*
Returns the number of bytes that needs to be allocated for a per-
@@ -315,9 +332,9 @@ extern int zlib_inflateInit (z_streamp strm);
extern int zlib_inflate (z_streamp strm, int flush);
/*
inflate decompresses as much data as possible, and stops when the input
- buffer becomes empty or the output buffer becomes full. It may some
- introduce some output latency (reading input without producing any output)
- except when forced to flush.
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output) except when
+ forced to flush.
The detailed semantics are as follows. inflate performs one or both of the
following actions:
@@ -341,11 +358,26 @@ extern int zlib_inflate (z_streamp strm, int flush);
must be called again after making room in the output buffer because there
might be more output pending.
- If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much
- output as possible to the output buffer. The flushing behavior of inflate is
- not specified for values of the flush parameter other than Z_SYNC_FLUSH
- and Z_FINISH, but the current implementation actually flushes as much output
- as possible anyway.
+ The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH,
+ Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much
+ output as possible to the output buffer. Z_BLOCK requests that inflate() stop
+ if and when it gets to the next deflate block boundary. When decoding the
+ zlib or gzip format, this will cause inflate() to return immediately after
+ the header and before the first block. When doing a raw inflate, inflate()
+ will go ahead and process the first block, and will return when it gets to
+ the end of that block, or when it runs out of data.
+
+ The Z_BLOCK option assists in appending to or combining deflate streams.
+ Also to assist in this, on return inflate() will set strm->data_type to the
+ number of unused bits in the last byte taken from strm->next_in, plus 64
+ if inflate() is currently decoding the last block in the deflate stream,
+ plus 128 if inflate() returned immediately after decoding an end-of-block
+ code or decoding the complete header up to just before the first byte of the
+ deflate stream. The end-of-block will not be indicated until all of the
+ uncompressed data from that block has been written to strm->next_out. The
+ number of unused bits may in general be greater than seven, except when
+ bit 7 of data_type is set, in which case the number of unused bits will be
+ less than eight.
inflate() should normally be called until it returns Z_STREAM_END or an
error. However if all decompression is to be performed in a single step
@@ -355,29 +387,44 @@ extern int zlib_inflate (z_streamp strm, int flush);
uncompressed data. (The size of the uncompressed data may have been saved
by the compressor for this purpose.) The next operation on this stream must
be inflateEnd to deallocate the decompression state. The use of Z_FINISH
- is never required, but can be used to inform inflate that a faster routine
+ is never required, but can be used to inform inflate that a faster approach
may be used for the single inflate() call.
- If a preset dictionary is needed at this point (see inflateSetDictionary
- below), inflate sets strm-adler to the adler32 checksum of the
- dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise
- it sets strm->adler to the adler32 checksum of all output produced
- so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
- an error code as described below. At the end of the stream, inflate()
- checks that its computed adler32 checksum is equal to that saved by the
- compressor and returns Z_STREAM_END only if the checksum is correct.
+ In this implementation, inflate() always flushes as much output as
+ possible to the output buffer, and always uses the faster approach on the
+ first call. So the only effect of the flush parameter in this implementation
+ is on the return value of inflate(), as noted below, or when it returns early
+ because Z_BLOCK is used.
+
+ If a preset dictionary is needed after this call (see inflateSetDictionary
+ below), inflate sets strm->adler to the adler32 checksum of the dictionary
+ chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+ strm->adler to the adler32 checksum of all output produced so far (that is,
+ total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+ below. At the end of the stream, inflate() checks that its computed adler32
+ checksum is equal to that saved by the compressor and returns Z_STREAM_END
+ only if the checksum is correct.
+
+ inflate() will decompress and check either zlib-wrapped or gzip-wrapped
+ deflate data. The header type is detected automatically. Any information
+ contained in the gzip header is not retained, so applications that need that
+ information should instead use raw inflate, see inflateInit2() below, or
+ inflateBack() and perform their own processing of the gzip header and
+ trailer.
inflate() returns Z_OK if some progress has been made (more input processed
or more output produced), Z_STREAM_END if the end of the compressed data has
been reached and all uncompressed output has been produced, Z_NEED_DICT if a
preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
- corrupted (input stream not conforming to the zlib format or incorrect
- adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent
- (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not
- enough memory, Z_BUF_ERROR if no progress is possible or if there was not
- enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR
- case, the application may then call inflateSync to look for a good
- compression block.
+ corrupted (input stream not conforming to the zlib format or incorrect check
+ value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+ if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+ Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+ output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+ inflate() can be called again with more input and more output space to
+ continue decompressing. If Z_DATA_ERROR is returned, the application may then
+ call inflateSync() to look for a good compression block if a partial recovery
+ of the data is desired.
*/
@@ -547,16 +594,36 @@ extern int inflateInit2 (z_streamp strm, int windowBits);
The windowBits parameter is the base two logarithm of the maximum window
size (the size of the history buffer). It should be in the range 8..15 for
this version of the library. The default value is 15 if inflateInit is used
- instead. If a compressed stream with a larger window size is given as
- input, inflate() will return with the error code Z_DATA_ERROR instead of
- trying to allocate a larger window.
-
- inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
- memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
- memLevel). msg is set to null if there is no error message. inflateInit2
- does not perform any decompression apart from reading the zlib header if
- present: this will be done by inflate(). (So next_in and avail_in may be
- modified, but next_out and avail_out are unchanged.)
+ instead. windowBits must be greater than or equal to the windowBits value
+ provided to deflateInit2() while compressing, or it must be equal to 15 if
+ deflateInit2() was not used. If a compressed stream with a larger window
+ size is given as input, inflate() will return with the error code
+ Z_DATA_ERROR instead of trying to allocate a larger window.
+
+ windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+ determines the window size. inflate() will then process raw deflate data,
+ not looking for a zlib or gzip header, not generating a check value, and not
+ looking for any check values for comparison at the end of the stream. This
+ is for use with other formats that use the deflate compressed data format
+ such as zip. Those formats provide their own check values. If a custom
+ format is developed using the raw deflate format for compressed data, it is
+ recommended that a check value such as an adler32 or a crc32 be applied to
+ the uncompressed data as is done in the zlib, gzip, and zip formats. For
+ most applications, the zlib format should be used as is. Note that comments
+ above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+ windowBits can also be greater than 15 for optional gzip decoding. Add
+ 32 to windowBits to enable zlib and gzip decoding with automatic header
+ detection, or add 16 to decode only the gzip format (the zlib format will
+ return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is
+ a crc32 instead of an adler32.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg
+ is set to null if there is no error message. inflateInit2 does not perform
+ any decompression apart from reading the zlib header if present: this will
+ be done by inflate(). (So next_in and avail_in may be modified, but next_out
+ and avail_out are unchanged.)
*/
extern int zlib_inflateSetDictionary (z_streamp strm,
@@ -564,16 +631,19 @@ extern int zlib_inflateSetDictionary (z_streamp strm,
uInt dictLength);
/*
Initializes the decompression dictionary from the given uncompressed byte
- sequence. This function must be called immediately after a call of inflate
- if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
- can be determined from the Adler32 value returned by this call of
- inflate. The compressor and decompressor must use exactly the same
- dictionary (see deflateSetDictionary).
+ sequence. This function must be called immediately after a call of inflate,
+ if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+ can be determined from the adler32 value returned by that call of inflate.
+ The compressor and decompressor must use exactly the same dictionary (see
+ deflateSetDictionary). For raw inflate, this function can be called
+ immediately after inflateInit2() or inflateReset() and before any call of
+ inflate() to set the dictionary. The application must insure that the
+ dictionary that was used for compression is provided.
inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
parameter is invalid (such as NULL dictionary) or the stream state is
inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
- expected one (incorrect Adler32 value). inflateSetDictionary does not
+ expected one (incorrect adler32 value). inflateSetDictionary does not
perform any decompression: this will be done by subsequent calls of
inflate().
*/
@@ -614,40 +684,19 @@ extern int zlib_inflateIncomp (z_stream *strm);
containing the data at next_in (except that the data is not output).
*/
- /* various hacks, don't look :) */
-
-/* deflateInit and inflateInit are macros to allow checking the zlib version
- * and the compiler's view of z_stream:
- */
-extern int zlib_deflateInit_ (z_streamp strm, int level,
- const char *version, int stream_size);
-extern int zlib_inflateInit_ (z_streamp strm,
- const char *version, int stream_size);
-extern int zlib_deflateInit2_ (z_streamp strm, int level, int method,
- int windowBits, int memLevel,
- int strategy, const char *version,
- int stream_size);
-extern int zlib_inflateInit2_ (z_streamp strm, int windowBits,
- const char *version, int stream_size);
#define zlib_deflateInit(strm, level) \
- zlib_deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+ zlib_deflateInit2((strm), (level), Z_DEFLATED, MAX_WBITS, \
+ DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY)
#define zlib_inflateInit(strm) \
- zlib_inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
-#define zlib_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
- zlib_deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
- (strategy), ZLIB_VERSION, sizeof(z_stream))
-#define zlib_inflateInit2(strm, windowBits) \
- zlib_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+ zlib_inflateInit2((strm), DEF_WBITS)
+extern int zlib_deflateInit2(z_streamp strm, int level, int method,
+ int windowBits, int memLevel,
+ int strategy);
+extern int zlib_inflateInit2(z_streamp strm, int windowBits);
#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
struct internal_state {int dummy;}; /* hack for buggy compilers */
#endif
-extern const char * zlib_zError (int err);
-#if 0
-extern int zlib_inflateSyncPoint (z_streamp z);
-#endif
-extern const uLong * zlib_get_crc_table (void);
-
#endif /* _ZLIB_H */
diff --git a/include/linux/zorro.h b/include/linux/zorro.h
index 2f135cf..913bfc2 100644
--- a/include/linux/zorro.h
+++ b/include/linux/zorro.h
@@ -11,8 +11,6 @@
#ifndef _LINUX_ZORRO_H
#define _LINUX_ZORRO_H
-#ifndef __ASSEMBLY__
-
#include <linux/device.h>
@@ -112,45 +110,6 @@ struct ConfigDev {
__u32 cd_Unused[4]; /* for whatever the driver wants */
} __attribute__ ((packed));
-#else /* __ASSEMBLY__ */
-
-LN_Succ = 0
-LN_Pred = LN_Succ+4
-LN_Type = LN_Pred+4
-LN_Pri = LN_Type+1
-LN_Name = LN_Pri+1
-LN_sizeof = LN_Name+4
-
-ER_Type = 0
-ER_Product = ER_Type+1
-ER_Flags = ER_Product+1
-ER_Reserved03 = ER_Flags+1
-ER_Manufacturer = ER_Reserved03+1
-ER_SerialNumber = ER_Manufacturer+2
-ER_InitDiagVec = ER_SerialNumber+4
-ER_Reserved0c = ER_InitDiagVec+2
-ER_Reserved0d = ER_Reserved0c+1
-ER_Reserved0e = ER_Reserved0d+1
-ER_Reserved0f = ER_Reserved0e+1
-ER_sizeof = ER_Reserved0f+1
-
-CD_Node = 0
-CD_Flags = CD_Node+LN_sizeof
-CD_Pad = CD_Flags+1
-CD_Rom = CD_Pad+1
-CD_BoardAddr = CD_Rom+ER_sizeof
-CD_BoardSize = CD_BoardAddr+4
-CD_SlotAddr = CD_BoardSize+4
-CD_SlotSize = CD_SlotAddr+2
-CD_Driver = CD_SlotSize+2
-CD_NextCD = CD_Driver+4
-CD_Unused = CD_NextCD+4
-CD_sizeof = CD_Unused+(4*4)
-
-#endif /* __ASSEMBLY__ */
-
-#ifndef __ASSEMBLY__
-
#define ZORRO_NUM_AUTO 16
#ifdef __KERNEL__
@@ -290,7 +249,6 @@ extern DECLARE_BITMAP(zorro_unused_z2ram, 128);
#define Z2RAM_CHUNKSHIFT (16)
-#endif /* !__ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* _LINUX_ZORRO_H */
diff --git a/include/linux/zutil.h b/include/linux/zutil.h
index ee0c59c..6adfa9a 100644
--- a/include/linux/zutil.h
+++ b/include/linux/zutil.h
@@ -23,18 +23,6 @@ typedef unsigned long ulg;
/* common constants */
-#ifndef DEF_WBITS
-# define DEF_WBITS MAX_WBITS
-#endif
-/* default windowBits for decompression. MAX_WBITS is for compression only */
-
-#if MAX_MEM_LEVEL >= 8
-# define DEF_MEM_LEVEL 8
-#else
-# define DEF_MEM_LEVEL MAX_MEM_LEVEL
-#endif
-/* default memLevel */
-
#define STORED_BLOCK 0
#define STATIC_TREES 1
#define DYN_TREES 2
diff --git a/include/media/cx2341x.h b/include/media/cx2341x.h
new file mode 100644
index 0000000..51fb06b
--- /dev/null
+++ b/include/media/cx2341x.h
@@ -0,0 +1,189 @@
+/*
+ cx23415/6 header containing common defines.
+
+ 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 CX2341X_H
+#define CX2341X_H
+
+enum cx2341x_port {
+ CX2341X_PORT_MEMORY = 0,
+ CX2341X_PORT_STREAMING = 1,
+ CX2341X_PORT_SERIAL = 2
+};
+
+struct cx2341x_mpeg_params {
+ /* misc */
+ enum cx2341x_port port;
+ u16 width;
+ u16 height;
+ u16 is_50hz;
+
+ /* stream */
+ enum v4l2_mpeg_stream_type stream_type;
+
+ /* audio */
+ enum v4l2_mpeg_audio_sampling_freq audio_sampling_freq;
+ enum v4l2_mpeg_audio_encoding audio_encoding;
+ enum v4l2_mpeg_audio_l2_bitrate audio_l2_bitrate;
+ enum v4l2_mpeg_audio_mode audio_mode;
+ enum v4l2_mpeg_audio_mode_extension audio_mode_extension;
+ enum v4l2_mpeg_audio_emphasis audio_emphasis;
+ enum v4l2_mpeg_audio_crc audio_crc;
+ u8 audio_properties;
+
+ /* video */
+ enum v4l2_mpeg_video_encoding video_encoding;
+ enum v4l2_mpeg_video_aspect video_aspect;
+ u16 video_b_frames;
+ u16 video_gop_size;
+ u16 video_gop_closure;
+ u16 video_pulldown;
+ enum v4l2_mpeg_video_bitrate_mode video_bitrate_mode;
+ u32 video_bitrate;
+ u32 video_bitrate_peak;
+ u16 video_temporal_decimation;
+
+ /* encoding filters */
+ enum v4l2_mpeg_cx2341x_video_spatial_filter_mode video_spatial_filter_mode;
+ u16 video_spatial_filter;
+ enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type video_luma_spatial_filter_type;
+ enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type video_chroma_spatial_filter_type;
+ enum v4l2_mpeg_cx2341x_video_temporal_filter_mode video_temporal_filter_mode;
+ u16 video_temporal_filter;
+ enum v4l2_mpeg_cx2341x_video_median_filter_type video_median_filter_type;
+ u16 video_luma_median_filter_top;
+ u16 video_luma_median_filter_bottom;
+ u16 video_chroma_median_filter_top;
+ u16 video_chroma_median_filter_bottom;
+};
+
+#define CX2341X_MBOX_MAX_DATA 16
+
+extern const u32 cx2341x_mpeg_ctrls[];
+typedef int (*cx2341x_mbox_func)(void *priv, int cmd, int in, int out,
+ u32 data[CX2341X_MBOX_MAX_DATA]);
+int cx2341x_update(void *priv, cx2341x_mbox_func func,
+ const struct cx2341x_mpeg_params *old,
+ const struct cx2341x_mpeg_params *new);
+int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params,
+ struct v4l2_queryctrl *qctrl);
+const char **cx2341x_ctrl_get_menu(u32 id);
+int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
+ struct v4l2_ext_controls *ctrls, int cmd);
+void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p);
+void cx2341x_log_status(struct cx2341x_mpeg_params *p, int cardid);
+
+/* Firmware names */
+#define CX2341X_FIRM_ENC_FILENAME "v4l-cx2341x-enc.fw"
+/* Decoder firmware for the cx23415 only */
+#define CX2341X_FIRM_DEC_FILENAME "v4l-cx2341x-dec.fw"
+
+/* Firmware API commands */
+
+/* MPEG decoder API, specific to the cx23415 */
+#define CX2341X_DEC_PING_FW 0x00
+#define CX2341X_DEC_START_PLAYBACK 0x01
+#define CX2341X_DEC_STOP_PLAYBACK 0x02
+#define CX2341X_DEC_SET_PLAYBACK_SPEED 0x03
+#define CX2341X_DEC_STEP_VIDEO 0x05
+#define CX2341X_DEC_SET_DMA_BLOCK_SIZE 0x08
+#define CX2341X_DEC_GET_XFER_INFO 0x09
+#define CX2341X_DEC_GET_DMA_STATUS 0x0a
+#define CX2341X_DEC_SCHED_DMA_FROM_HOST 0x0b
+#define CX2341X_DEC_PAUSE_PLAYBACK 0x0d
+#define CX2341X_DEC_HALT_FW 0x0e
+#define CX2341X_DEC_SET_STANDARD 0x10
+#define CX2341X_DEC_GET_VERSION 0x11
+#define CX2341X_DEC_SET_STREAM_INPUT 0x14
+#define CX2341X_DEC_GET_TIMING_INFO 0x15
+#define CX2341X_DEC_SET_AUDIO_MODE 0x16
+#define CX2341X_DEC_SET_EVENT_NOTIFICATION 0x17
+#define CX2341X_DEC_SET_DISPLAY_BUFFERS 0x18
+#define CX2341X_DEC_EXTRACT_VBI 0x19
+#define CX2341X_DEC_SET_DECODER_SOURCE 0x1a
+#define CX2341X_DEC_SET_AUDIO_OUTPUT 0x1b
+#define CX2341X_DEC_SET_AV_DELAY 0x1c
+#define CX2341X_DEC_SET_PREBUFFERING 0x1e
+
+/* MPEG encoder API */
+#define CX2341X_ENC_PING_FW 0x80
+#define CX2341X_ENC_START_CAPTURE 0x81
+#define CX2341X_ENC_STOP_CAPTURE 0x82
+#define CX2341X_ENC_SET_AUDIO_ID 0x89
+#define CX2341X_ENC_SET_VIDEO_ID 0x8b
+#define CX2341X_ENC_SET_PCR_ID 0x8d
+#define CX2341X_ENC_SET_FRAME_RATE 0x8f
+#define CX2341X_ENC_SET_FRAME_SIZE 0x91
+#define CX2341X_ENC_SET_BIT_RATE 0x95
+#define CX2341X_ENC_SET_GOP_PROPERTIES 0x97
+#define CX2341X_ENC_SET_ASPECT_RATIO 0x99
+#define CX2341X_ENC_SET_DNR_FILTER_MODE 0x9b
+#define CX2341X_ENC_SET_DNR_FILTER_PROPS 0x9d
+#define CX2341X_ENC_SET_CORING_LEVELS 0x9f
+#define CX2341X_ENC_SET_SPATIAL_FILTER_TYPE 0xa1
+#define CX2341X_ENC_SET_3_2_PULLDOWN 0xb1
+#define CX2341X_ENC_SET_VBI_LINE 0xb7
+#define CX2341X_ENC_SET_STREAM_TYPE 0xb9
+#define CX2341X_ENC_SET_OUTPUT_PORT 0xbb
+#define CX2341X_ENC_SET_AUDIO_PROPERTIES 0xbd
+#define CX2341X_ENC_HALT_FW 0xc3
+#define CX2341X_ENC_GET_VERSION 0xc4
+#define CX2341X_ENC_SET_GOP_CLOSURE 0xc5
+#define CX2341X_ENC_GET_SEQ_END 0xc6
+#define CX2341X_ENC_SET_PGM_INDEX_INFO 0xc7
+#define CX2341X_ENC_SET_VBI_CONFIG 0xc8
+#define CX2341X_ENC_SET_DMA_BLOCK_SIZE 0xc9
+#define CX2341X_ENC_GET_PREV_DMA_INFO_MB_10 0xca
+#define CX2341X_ENC_GET_PREV_DMA_INFO_MB_9 0xcb
+#define CX2341X_ENC_SCHED_DMA_TO_HOST 0xcc
+#define CX2341X_ENC_INITIALIZE_INPUT 0xcd
+#define CX2341X_ENC_SET_FRAME_DROP_RATE 0xd0
+#define CX2341X_ENC_PAUSE_ENCODER 0xd2
+#define CX2341X_ENC_REFRESH_INPUT 0xd3
+#define CX2341X_ENC_SET_COPYRIGHT 0xd4
+#define CX2341X_ENC_SET_EVENT_NOTIFICATION 0xd5
+#define CX2341X_ENC_SET_NUM_VSYNC_LINES 0xd6
+#define CX2341X_ENC_SET_PLACEHOLDER 0xd7
+#define CX2341X_ENC_MUTE_VIDEO 0xd9
+#define CX2341X_ENC_MUTE_AUDIO 0xda
+#define CX2341X_ENC_UNKNOWN 0xdb
+#define CX2341X_ENC_MISC 0xdc
+
+/* OSD API, specific to the cx23415 */
+#define CX2341X_OSD_GET_FRAMEBUFFER 0x41
+#define CX2341X_OSD_GET_PIXEL_FORMAT 0x42
+#define CX2341X_OSD_SET_PIXEL_FORMAT 0x43
+#define CX2341X_OSD_GET_STATE 0x44
+#define CX2341X_OSD_SET_STATE 0x45
+#define CX2341X_OSD_GET_OSD_COORDS 0x46
+#define CX2341X_OSD_SET_OSD_COORDS 0x47
+#define CX2341X_OSD_GET_SCREEN_COORDS 0x48
+#define CX2341X_OSD_SET_SCREEN_COORDS 0x49
+#define CX2341X_OSD_GET_GLOBAL_ALPHA 0x4a
+#define CX2341X_OSD_SET_GLOBAL_ALPHA 0x4b
+#define CX2341X_OSD_SET_BLEND_COORDS 0x4c
+#define CX2341X_OSD_GET_FLICKER_STATE 0x4f
+#define CX2341X_OSD_SET_FLICKER_STATE 0x50
+#define CX2341X_OSD_BLT_COPY 0x52
+#define CX2341X_OSD_BLT_FILL 0x53
+#define CX2341X_OSD_BLT_TEXT 0x54
+#define CX2341X_OSD_SET_FRAMEBUFFER_WINDOW 0x56
+#define CX2341X_OSD_SET_CHROMA_KEY 0x60
+#define CX2341X_OSD_GET_ALPHA_CONTENT_INDEX 0x61
+#define CX2341X_OSD_SET_ALPHA_CONTENT_INDEX 0x62
+
+#endif /* CX2341X_H */
diff --git a/include/media/ir-common.h b/include/media/ir-common.h
index 302d5b3..7bab09b 100644
--- a/include/media/ir-common.h
+++ b/include/media/ir-common.h
@@ -73,7 +73,7 @@ extern IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_dntv_live_dvbt_pro[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_flyvideo[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_flydvb[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_cinergy[IR_KEYTAB_SIZE];
@@ -87,8 +87,9 @@ extern IR_KEYTAB_TYPE ir_codes_pctv_sedna[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pinnacle_color[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_npgtech[IR_KEYTAB_SIZE];
#endif
diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h
index 730f21e..a455f7c 100644
--- a/include/media/ir-kbd-i2c.h
+++ b/include/media/ir-kbd-i2c.h
@@ -20,5 +20,6 @@ struct IR_i2c {
int (*get_key)(struct IR_i2c*, u32*, u32*);
};
-int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
+int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
+int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
#endif
diff --git a/include/media/ovcamchip.h b/include/media/ovcamchip.h
index 8138983..0f43451 100644
--- a/include/media/ovcamchip.h
+++ b/include/media/ovcamchip.h
@@ -15,6 +15,7 @@
#define __LINUX_OVCAMCHIP_H
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/i2c.h>
/* --------------------------------- */
diff --git a/include/media/pwc-ioctl.h b/include/media/pwc-ioctl.h
new file mode 100644
index 0000000..adc1254
--- /dev/null
+++ b/include/media/pwc-ioctl.h
@@ -0,0 +1,325 @@
+#ifndef PWC_IOCTL_H
+#define PWC_IOCTL_H
+
+/* (C) 2001-2004 Nemosoft Unv.
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+ NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+ driver and thus may have bugs that are not present in the original version.
+ Please send bug reports and support requests to <luc@saillard.org>.
+ The decompression routines have been implemented by reverse-engineering the
+ Nemosoft binary pwcx module. Caveat emptor.
+
+ 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
+*/
+
+/* This is pwc-ioctl.h belonging to PWC 10.0.10
+ It contains structures and defines to communicate from user space
+ directly to the driver.
+ */
+
+/*
+ Changes
+ 2001/08/03 Alvarado Added ioctl constants to access methods for
+ changing white balance and red/blue gains
+ 2002/12/15 G. H. Fernandez-Toribio VIDIOCGREALSIZE
+ 2003/12/13 Nemosft Unv. Some modifications to make interfacing to
+ PWCX easier
+ 2006/01/01 Luc Saillard Add raw format definition
+ */
+
+/* These are private ioctl() commands, specific for the Philips webcams.
+ They contain functions not found in other webcams, and settings not
+ specified in the Video4Linux API.
+
+ The #define names are built up like follows:
+ VIDIOC VIDeo IOCtl prefix
+ PWC Philps WebCam
+ G optional: Get
+ S optional: Set
+ ... the function
+ */
+
+#include <linux/types.h>
+#include <linux/version.h>
+
+
+ /* Enumeration of image sizes */
+#define PSZ_SQCIF 0x00
+#define PSZ_QSIF 0x01
+#define PSZ_QCIF 0x02
+#define PSZ_SIF 0x03
+#define PSZ_CIF 0x04
+#define PSZ_VGA 0x05
+#define PSZ_MAX 6
+
+
+/* The frame rate is encoded in the video_window.flags parameter using
+ the upper 16 bits, since some flags are defined nowadays. The following
+ defines provide a mask and shift to filter out this value.
+ This value can also be passing using the private flag when using v4l2 and
+ VIDIOC_S_FMT ioctl.
+
+ In 'Snapshot' mode the camera freezes its automatic exposure and colour
+ balance controls.
+ */
+#define PWC_FPS_SHIFT 16
+#define PWC_FPS_MASK 0x00FF0000
+#define PWC_FPS_FRMASK 0x003F0000
+#define PWC_FPS_SNAPSHOT 0x00400000
+#define PWC_QLT_MASK 0x03000000
+#define PWC_QLT_SHIFT 24
+
+
+/* structure for transferring x & y coordinates */
+struct pwc_coord
+{
+ int x, y; /* guess what */
+ int size; /* size, or offset */
+};
+
+
+/* Used with VIDIOCPWCPROBE */
+struct pwc_probe
+{
+ char name[32];
+ int type;
+};
+
+struct pwc_serial
+{
+ char serial[30]; /* String with serial number. Contains terminating 0 */
+};
+
+/* pwc_whitebalance.mode values */
+#define PWC_WB_INDOOR 0
+#define PWC_WB_OUTDOOR 1
+#define PWC_WB_FL 2
+#define PWC_WB_MANUAL 3
+#define PWC_WB_AUTO 4
+
+/* Used with VIDIOCPWC[SG]AWB (Auto White Balance).
+ Set mode to one of the PWC_WB_* values above.
+ *red and *blue are the respective gains of these colour components inside
+ the camera; range 0..65535
+ When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read;
+ otherwise undefined.
+ 'read_red' and 'read_blue' are read-only.
+*/
+struct pwc_whitebalance
+{
+ int mode;
+ int manual_red, manual_blue; /* R/W */
+ int read_red, read_blue; /* R/O */
+};
+
+/*
+ 'control_speed' and 'control_delay' are used in automatic whitebalance mode,
+ and tell the camera how fast it should react to changes in lighting, and
+ with how much delay. Valid values are 0..65535.
+*/
+struct pwc_wb_speed
+{
+ int control_speed;
+ int control_delay;
+
+};
+
+/* Used with VIDIOCPWC[SG]LED */
+struct pwc_leds
+{
+ int led_on; /* Led on-time; range = 0..25000 */
+ int led_off; /* Led off-time; range = 0..25000 */
+};
+
+/* Image size (used with GREALSIZE) */
+struct pwc_imagesize
+{
+ int width;
+ int height;
+};
+
+/* Defines and structures for Motorized Pan & Tilt */
+#define PWC_MPT_PAN 0x01
+#define PWC_MPT_TILT 0x02
+#define PWC_MPT_TIMEOUT 0x04 /* for status */
+
+/* Set angles; when absolute != 0, the angle is absolute and the
+ driver calculates the relative offset for you. This can only
+ be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns
+ absolute angles.
+ */
+struct pwc_mpt_angles
+{
+ int absolute; /* write-only */
+ int pan; /* degrees * 100 */
+ int tilt; /* degress * 100 */
+};
+
+/* Range of angles of the camera, both horizontally and vertically.
+ */
+struct pwc_mpt_range
+{
+ int pan_min, pan_max; /* degrees * 100 */
+ int tilt_min, tilt_max;
+};
+
+struct pwc_mpt_status
+{
+ int status;
+ int time_pan;
+ int time_tilt;
+};
+
+
+/* This is used for out-of-kernel decompression. With it, you can get
+ all the necessary information to initialize and use the decompressor
+ routines in standalone applications.
+ */
+struct pwc_video_command
+{
+ int type; /* camera type (645, 675, 730, etc.) */
+ int release; /* release number */
+
+ int size; /* one of PSZ_* */
+ int alternate;
+ int command_len; /* length of USB video command */
+ unsigned char command_buf[13]; /* Actual USB video command */
+ int bandlength; /* >0 = compressed */
+ int frame_size; /* Size of one (un)compressed frame */
+};
+
+/* Flags for PWCX subroutines. Not all modules honour all flags. */
+#define PWCX_FLAG_PLANAR 0x0001
+#define PWCX_FLAG_BAYER 0x0008
+
+
+/* IOCTL definitions */
+
+ /* Restore user settings */
+#define VIDIOCPWCRUSER _IO('v', 192)
+ /* Save user settings */
+#define VIDIOCPWCSUSER _IO('v', 193)
+ /* Restore factory settings */
+#define VIDIOCPWCFACTORY _IO('v', 194)
+
+ /* You can manipulate the compression factor. A compression preference of 0
+ means use uncompressed modes when available; 1 is low compression, 2 is
+ medium and 3 is high compression preferred. Of course, the higher the
+ compression, the lower the bandwidth used but more chance of artefacts
+ in the image. The driver automatically chooses a higher compression when
+ the preferred mode is not available.
+ */
+ /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */
+#define VIDIOCPWCSCQUAL _IOW('v', 195, int)
+ /* Get preferred compression quality */
+#define VIDIOCPWCGCQUAL _IOR('v', 195, int)
+
+
+/* Retrieve serial number of camera */
+#define VIDIOCPWCGSERIAL _IOR('v', 198, struct pwc_serial)
+
+ /* This is a probe function; since so many devices are supported, it
+ becomes difficult to include all the names in programs that want to
+ check for the enhanced Philips stuff. So in stead, try this PROBE;
+ it returns a structure with the original name, and the corresponding
+ Philips type.
+ To use, fill the structure with zeroes, call PROBE and if that succeeds,
+ compare the name with that returned from VIDIOCGCAP; they should be the
+ same. If so, you can be assured it is a Philips (OEM) cam and the type
+ is valid.
+ */
+#define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe)
+
+ /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */
+#define VIDIOCPWCSAGC _IOW('v', 200, int)
+ /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */
+#define VIDIOCPWCGAGC _IOR('v', 200, int)
+ /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */
+#define VIDIOCPWCSSHUTTER _IOW('v', 201, int)
+
+ /* Color compensation (Auto White Balance) */
+#define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance)
+#define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance)
+
+ /* Auto WB speed */
+#define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed)
+#define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed)
+
+ /* LEDs on/off/blink; int range 0..65535 */
+#define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds)
+#define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds)
+
+ /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */
+#define VIDIOCPWCSCONTOUR _IOW('v', 206, int)
+#define VIDIOCPWCGCONTOUR _IOR('v', 206, int)
+
+ /* Backlight compensation; 0 = off, otherwise on */
+#define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int)
+#define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int)
+
+ /* Flickerless mode; = 0 off, otherwise on */
+#define VIDIOCPWCSFLICKER _IOW('v', 208, int)
+#define VIDIOCPWCGFLICKER _IOR('v', 208, int)
+
+ /* Dynamic noise reduction; 0 off, 3 = high noise reduction */
+#define VIDIOCPWCSDYNNOISE _IOW('v', 209, int)
+#define VIDIOCPWCGDYNNOISE _IOR('v', 209, int)
+
+ /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */
+#define VIDIOCPWCGREALSIZE _IOR('v', 210, struct pwc_imagesize)
+
+ /* Motorized pan & tilt functions */
+#define VIDIOCPWCMPTRESET _IOW('v', 211, int)
+#define VIDIOCPWCMPTGRANGE _IOR('v', 211, struct pwc_mpt_range)
+#define VIDIOCPWCMPTSANGLE _IOW('v', 212, struct pwc_mpt_angles)
+#define VIDIOCPWCMPTGANGLE _IOR('v', 212, struct pwc_mpt_angles)
+#define VIDIOCPWCMPTSTATUS _IOR('v', 213, struct pwc_mpt_status)
+
+ /* Get the USB set-video command; needed for initializing libpwcx */
+#define VIDIOCPWCGVIDCMD _IOR('v', 215, struct pwc_video_command)
+struct pwc_table_init_buffer {
+ int len;
+ char *buffer;
+
+};
+#define VIDIOCPWCGVIDTABLE _IOR('v', 216, struct pwc_table_init_buffer)
+
+/*
+ * This is private command used when communicating with v4l2.
+ * In the future all private ioctl will be remove/replace to
+ * use interface offer by v4l2.
+ */
+
+#define V4L2_CID_PRIVATE_SAVE_USER (V4L2_CID_PRIVATE_BASE + 0)
+#define V4L2_CID_PRIVATE_RESTORE_USER (V4L2_CID_PRIVATE_BASE + 1)
+#define V4L2_CID_PRIVATE_RESTORE_FACTORY (V4L2_CID_PRIVATE_BASE + 2)
+#define V4L2_CID_PRIVATE_COLOUR_MODE (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_PRIVATE_AUTOCONTOUR (V4L2_CID_PRIVATE_BASE + 4)
+#define V4L2_CID_PRIVATE_CONTOUR (V4L2_CID_PRIVATE_BASE + 5)
+#define V4L2_CID_PRIVATE_BACKLIGHT (V4L2_CID_PRIVATE_BASE + 6)
+#define V4L2_CID_PRIVATE_FLICKERLESS (V4L2_CID_PRIVATE_BASE + 7)
+#define V4L2_CID_PRIVATE_NOISE_REDUCTION (V4L2_CID_PRIVATE_BASE + 8)
+
+struct pwc_raw_frame {
+ __le16 type; /* type of the webcam */
+ __le16 vbandlength; /* Size of 4lines compressed (used by the decompressor) */
+ __u8 cmd[4]; /* the four byte of the command (in case of nala,
+ only the first 3 bytes is filled) */
+ __u8 rawframe[0]; /* frame_size = H/4*vbandlength */
+} __attribute__ ((packed));
+
+
+#endif
diff --git a/include/media/saa7115.h b/include/media/saa7115.h
index 6b4836f..9f0e228 100644
--- a/include/media/saa7115.h
+++ b/include/media/saa7115.h
@@ -1,5 +1,5 @@
/*
- saa7115.h - definition for saa7113/4/5 inputs
+ saa7115.h - definition for saa7113/4/5 inputs and frequency flags
Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
@@ -33,5 +33,14 @@
#define SAA7115_SVIDEO2 8
#define SAA7115_SVIDEO3 9
+/* SAA7115 v4l2_crystal_freq frequency values */
+#define SAA7115_FREQ_32_11_MHZ 32110000 /* 32.11 MHz crystal, SAA7114/5 only */
+#define SAA7115_FREQ_24_576_MHZ 24576000 /* 24.576 MHz crystal */
+
+/* SAA7115 v4l2_crystal_freq audio clock control flags */
+#define SAA7115_FREQ_FL_UCGC (1 << 0) /* SA 3A[7], UCGC, SAA7115 only */
+#define SAA7115_FREQ_FL_CGCDIV (1 << 1) /* SA 3A[6], CGCDIV, SAA7115 only */
+#define SAA7115_FREQ_FL_APLL (1 << 2) /* SA 3A[3], APLL, SAA7114/5 only */
+
#endif
diff --git a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h
index 4507cb6..83fe2e3 100644
--- a/include/media/saa7146_vv.h
+++ b/include/media/saa7146_vv.h
@@ -2,7 +2,7 @@
#define __SAA7146_VV__
#include <linux/videodev.h>
-
+#include <media/v4l2-common.h>
#include <media/saa7146.h>
#include <media/video-buf.h>
diff --git a/include/media/tuner.h b/include/media/tuner.h
index 017fed7..2f7b00b 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -25,6 +25,8 @@
#include <linux/videodev2.h>
#include <media/tuner-types.h>
+extern int tuner_debug;
+
#define ADDR_UNSET (255)
#define TUNER_TEMIC_PAL 0 /* 4002 FH5 (3X 7756, 9483) */
@@ -108,7 +110,7 @@
#define TUNER_TEA5767 62 /* Only FM Radio Tuner */
#define TUNER_PHILIPS_FMD1216ME_MK3 63
-#define TUNER_LG_TDVS_H062F 64 /* DViCO FusionHDTV 5 */
+#define TUNER_LG_TDVS_H06XF 64 /* TDVS H061F, H062F, H064F */
#define TUNER_YMEC_TVF66T5_B_DFF 65 /* Acorp Y878F */
#define TUNER_LG_TALN 66
#define TUNER_PHILIPS_TD1316 67
@@ -119,6 +121,8 @@
#define TUNER_XCEIVE_XC3028 71
#define TUNER_THOMSON_FE6600 72 /* DViCO FusionHDTV DVB-T Hybrid */
+#define TUNER_SAMSUNG_TCPG_6121P30A 73 /* Hauppauge PVR-500 PAL */
+#define TUNER_TDA9887 74 /* This tuner should be used only internally */
/* tv card specific */
#define TDA9887_PRESENT (1<<0)
@@ -190,6 +194,10 @@ struct tuner {
int using_v4l2;
+ /* used by tda9887 */
+ unsigned int tda9887_config;
+ unsigned char tda9887_data[4];
+
/* used by MT2032 */
unsigned int xogc;
unsigned int radio_if2;
@@ -206,6 +214,8 @@ struct tuner {
void (*set_radio_freq)(struct i2c_client *c, unsigned int freq);
int (*has_signal)(struct i2c_client *c);
int (*is_stereo)(struct i2c_client *c);
+ int (*get_afc)(struct i2c_client *c);
+ void (*tuner_status)(struct i2c_client *c);
void (*standby)(struct i2c_client *c);
};
@@ -218,6 +228,7 @@ extern int tda8290_probe(struct i2c_client *c);
extern int tea5767_tuner_init(struct i2c_client *c);
extern int default_tuner_init(struct i2c_client *c);
extern int tea5767_autodetection(struct i2c_client *c);
+extern int tda9887_tuner_init(struct i2c_client *c);
#define tuner_warn(fmt, arg...) do {\
printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
diff --git a/include/media/tvp5150.h b/include/media/tvp5150.h
new file mode 100644
index 0000000..72bd2a2
--- /dev/null
+++ b/include/media/tvp5150.h
@@ -0,0 +1,34 @@
+/*
+ tvp5150.h - definition for tvp5150 inputs
+
+ Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _TVP5150_H_
+#define _TVP5150_H_
+
+/* TVP5150 HW inputs */
+#define TVP5150_COMPOSITE0 0
+#define TVP5150_COMPOSITE1 1
+#define TVP5150_SVIDEO 2
+
+/* TVP5150 HW outputs */
+#define TVP5150_NORMAL 0
+#define TVP5150_BLACK_SCREEN 1
+
+#endif
+
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index 642520a..5564db1 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -26,8 +26,14 @@
#ifndef V4L2_COMMON_H_
#define V4L2_COMMON_H_
+#include <media/v4l2-dev.h>
+
/* v4l debugging and diagnostics */
+/* Debug bitmask flags to be used on V4L2 */
+#define V4L2_DEBUG_IOCTL 0x01
+#define V4L2_DEBUG_IOCTL_ARG 0x02
+
/* Common printk constucts for v4l-i2c drivers. These macros create a unique
prefix consisting of the driver name, the adapter number and the i2c
address. */
@@ -78,6 +84,19 @@ extern void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg);
/* ------------------------------------------------------------------------- */
+/* Control helper functions */
+
+int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
+ const char **menu_items);
+const char **v4l2_ctrl_get_menu(u32 id);
+int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def);
+int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl);
+int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu,
+ struct v4l2_queryctrl *qctrl, const char **menu_items);
+u32 v4l2_ctrl_next(const u32 * const *ctrl_classes, u32 id);
+
+/* ------------------------------------------------------------------------- */
+
/* Internal ioctls */
/* VIDIOC_INT_G_REGISTER and VIDIOC_INT_S_REGISTER */
@@ -112,6 +131,8 @@ enum v4l2_chip_ident {
V4L2_IDENT_SAA7129 = 159,
/* module cx25840: reserved range 200-249 */
+ V4L2_IDENT_CX25836 = 236,
+ V4L2_IDENT_CX25837 = 237,
V4L2_IDENT_CX25840 = 240,
V4L2_IDENT_CX25841 = 241,
V4L2_IDENT_CX25842 = 242,
@@ -211,4 +232,15 @@ struct v4l2_routing {
#define VIDIOC_INT_S_VIDEO_ROUTING _IOW ('d', 111, struct v4l2_routing)
#define VIDIOC_INT_G_VIDEO_ROUTING _IOR ('d', 112, struct v4l2_routing)
+struct v4l2_crystal_freq {
+ u32 freq; /* frequency in Hz of the crystal */
+ u32 flags; /* device specific flags */
+};
+
+/* Sets the frequency of the crystal used to generate the clocks.
+ An extra flags field allows device specific configuration regarding
+ clock frequency dividers, etc. If not used, then set flags to 0.
+ If the frequency is not supported, then -EINVAL is returned. */
+#define VIDIOC_INT_S_CRYSTAL_FREQ _IOW ('d', 113, struct v4l2_crystal_freq)
+
#endif /* V4L2_COMMON_H_ */
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
new file mode 100644
index 0000000..a1b4731
--- /dev/null
+++ b/include/media/v4l2-dev.h
@@ -0,0 +1,375 @@
+/*
+ *
+ * V 4 L 2 D R I V E R H E L P E R A P I
+ *
+ * Moved from videodev2.h
+ *
+ * Some commonly needed functions for drivers (v4l2-common.o module)
+ */
+#ifndef _V4L2_DEV_H
+#define _V4L2_DEV_H
+
+#define OBSOLETE_OWNER 1 /* to be removed soon */
+
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/compiler.h> /* need __user */
+#ifdef CONFIG_VIDEO_V4L1
+#include <linux/videodev.h>
+#else
+#include <linux/videodev2.h>
+#endif
+
+#include <linux/fs.h>
+
+#define VIDEO_MAJOR 81
+/* Minor device allocation */
+#define MINOR_VFL_TYPE_GRABBER_MIN 0
+#define MINOR_VFL_TYPE_GRABBER_MAX 63
+#define MINOR_VFL_TYPE_RADIO_MIN 64
+#define MINOR_VFL_TYPE_RADIO_MAX 127
+#define MINOR_VFL_TYPE_VTX_MIN 192
+#define MINOR_VFL_TYPE_VTX_MAX 223
+#define MINOR_VFL_TYPE_VBI_MIN 224
+#define MINOR_VFL_TYPE_VBI_MAX 255
+
+#define VFL_TYPE_GRABBER 0
+#define VFL_TYPE_VBI 1
+#define VFL_TYPE_RADIO 2
+#define VFL_TYPE_VTX 3
+
+/* Video standard functions */
+extern unsigned int v4l2_video_std_fps(struct v4l2_standard *vs);
+extern int v4l2_video_std_construct(struct v4l2_standard *vs,
+ int id, char *name);
+
+/* prority handling */
+struct v4l2_prio_state {
+ atomic_t prios[4];
+};
+int v4l2_prio_init(struct v4l2_prio_state *global);
+int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local,
+ enum v4l2_priority new);
+int v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local);
+int v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority *local);
+enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global);
+int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local);
+
+/* names for fancy debug output */
+extern char *v4l2_field_names[];
+extern char *v4l2_type_names[];
+
+/* Compatibility layer interface -- v4l1-compat module */
+typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg);
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+int v4l_compat_translate_ioctl(struct inode *inode, struct file *file,
+ int cmd, void *arg, v4l2_kioctl driver_ioctl);
+#else
+#define v4l_compat_translate_ioctl(inode,file,cmd,arg,ioctl) -EINVAL
+#endif
+
+/* 32 Bits compatibility layer for 64 bits processors */
+extern long v4l_compat_ioctl32(struct file *file, unsigned int cmd,
+ unsigned long arg);
+
+/*
+ * Newer version of video_device, handled by videodev2.c
+ * This version moves redundant code from video device code to
+ * the common handler
+ */
+struct v4l2_tvnorm {
+ char *name;
+ v4l2_std_id id;
+
+ void *priv_data;
+};
+
+struct video_device
+{
+ /* device ops */
+ const struct file_operations *fops;
+
+ /* device info */
+ struct device *dev;
+ char name[32];
+ int type; /* v4l1 */
+ int type2; /* v4l2 */
+ int hardware;
+ int minor;
+
+ int debug; /* Activates debug level*/
+
+ /* Video standard vars */
+ int tvnormsize; /* Size of tvnorm array */
+ v4l2_std_id current_norm; /* Current tvnorm */
+ struct v4l2_tvnorm *tvnorms;
+
+ /* callbacks */
+ void (*release)(struct video_device *vfd);
+
+ /* ioctl callbacks */
+
+ /* VIDIOC_QUERYCAP handler */
+ int (*vidioc_querycap)(struct file *file, void *fh, struct v4l2_capability *cap);
+
+ /* Priority handling */
+ int (*vidioc_g_priority) (struct file *file, void *fh,
+ enum v4l2_priority *p);
+ int (*vidioc_s_priority) (struct file *file, void *fh,
+ enum v4l2_priority p);
+
+ /* VIDIOC_ENUM_FMT handlers */
+ int (*vidioc_enum_fmt_cap) (struct file *file, void *fh,
+ struct v4l2_fmtdesc *f);
+ int (*vidioc_enum_fmt_overlay) (struct file *file, void *fh,
+ struct v4l2_fmtdesc *f);
+ int (*vidioc_enum_fmt_vbi) (struct file *file, void *fh,
+ struct v4l2_fmtdesc *f);
+ int (*vidioc_enum_fmt_vbi_capture) (struct file *file, void *fh,
+ struct v4l2_fmtdesc *f);
+ int (*vidioc_enum_fmt_video_output)(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f);
+ int (*vidioc_enum_fmt_vbi_output) (struct file *file, void *fh,
+ struct v4l2_fmtdesc *f);
+ int (*vidioc_enum_fmt_type_private)(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f);
+
+ /* VIDIOC_G_FMT handlers */
+ int (*vidioc_g_fmt_cap) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_g_fmt_overlay) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_g_fmt_vbi) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_g_fmt_vbi_output) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_g_fmt_vbi_capture)(struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_g_fmt_video_output)(struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_g_fmt_type_private)(struct file *file, void *fh,
+ struct v4l2_format *f);
+
+ /* VIDIOC_S_FMT handlers */
+ int (*vidioc_s_fmt_cap) (struct file *file, void *fh,
+ struct v4l2_format *f);
+
+ int (*vidioc_s_fmt_overlay) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_s_fmt_vbi) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_s_fmt_vbi_output) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_s_fmt_vbi_capture)(struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_s_fmt_video_output)(struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_s_fmt_type_private)(struct file *file, void *fh,
+ struct v4l2_format *f);
+
+ /* VIDIOC_TRY_FMT handlers */
+ int (*vidioc_try_fmt_cap) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_try_fmt_overlay) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_try_fmt_vbi) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_try_fmt_vbi_output) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_try_fmt_vbi_capture)(struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_try_fmt_video_output)(struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_try_fmt_type_private)(struct file *file, void *fh,
+ struct v4l2_format *f);
+
+ /* Buffer handlers */
+ int (*vidioc_reqbufs) (struct file *file, void *fh, struct v4l2_requestbuffers *b);
+ int (*vidioc_querybuf)(struct file *file, void *fh, struct v4l2_buffer *b);
+ int (*vidioc_qbuf) (struct file *file, void *fh, struct v4l2_buffer *b);
+ int (*vidioc_dqbuf) (struct file *file, void *fh, struct v4l2_buffer *b);
+
+
+ int (*vidioc_overlay) (struct file *file, void *fh, unsigned int i);
+#ifdef HAVE_V4L1
+ /* buffer type is struct vidio_mbuf * */
+ int (*vidiocgmbuf) (struct file *file, void *fh, struct video_mbuf *p);
+#endif
+ int (*vidioc_g_fbuf) (struct file *file, void *fh,
+ struct v4l2_framebuffer *a);
+ int (*vidioc_s_fbuf) (struct file *file, void *fh,
+ struct v4l2_framebuffer *a);
+
+ /* Stream on/off */
+ int (*vidioc_streamon) (struct file *file, void *fh, enum v4l2_buf_type i);
+ int (*vidioc_streamoff)(struct file *file, void *fh, enum v4l2_buf_type i);
+
+ /* Standard handling
+ G_STD and ENUMSTD are handled by videodev.c
+ */
+ int (*vidioc_s_std) (struct file *file, void *fh, v4l2_std_id a);
+ int (*vidioc_querystd) (struct file *file, void *fh, v4l2_std_id *a);
+
+ /* Input handling */
+ int (*vidioc_enum_input)(struct file *file, void *fh,
+ struct v4l2_input *inp);
+ int (*vidioc_g_input) (struct file *file, void *fh, unsigned int *i);
+ int (*vidioc_s_input) (struct file *file, void *fh, unsigned int i);
+
+ /* Output handling */
+ int (*vidioc_enumoutput) (struct file *file, void *fh,
+ struct v4l2_output *a);
+ int (*vidioc_g_output) (struct file *file, void *fh, unsigned int *i);
+ int (*vidioc_s_output) (struct file *file, void *fh, unsigned int i);
+
+ /* Control handling */
+ int (*vidioc_queryctrl) (struct file *file, void *fh,
+ struct v4l2_queryctrl *a);
+ int (*vidioc_g_ctrl) (struct file *file, void *fh,
+ struct v4l2_control *a);
+ int (*vidioc_s_ctrl) (struct file *file, void *fh,
+ struct v4l2_control *a);
+ int (*vidioc_g_ext_ctrls) (struct file *file, void *fh,
+ struct v4l2_ext_controls *a);
+ int (*vidioc_s_ext_ctrls) (struct file *file, void *fh,
+ struct v4l2_ext_controls *a);
+ int (*vidioc_try_ext_ctrls) (struct file *file, void *fh,
+ struct v4l2_ext_controls *a);
+ int (*vidioc_querymenu) (struct file *file, void *fh,
+ struct v4l2_querymenu *a);
+
+ /* Audio ioctls */
+ int (*vidioc_enumaudio) (struct file *file, void *fh,
+ struct v4l2_audio *a);
+ int (*vidioc_g_audio) (struct file *file, void *fh,
+ struct v4l2_audio *a);
+ int (*vidioc_s_audio) (struct file *file, void *fh,
+ struct v4l2_audio *a);
+
+ /* Audio out ioctls */
+ int (*vidioc_enumaudout) (struct file *file, void *fh,
+ struct v4l2_audioout *a);
+ int (*vidioc_g_audout) (struct file *file, void *fh,
+ struct v4l2_audioout *a);
+ int (*vidioc_s_audout) (struct file *file, void *fh,
+ struct v4l2_audioout *a);
+ int (*vidioc_g_modulator) (struct file *file, void *fh,
+ struct v4l2_modulator *a);
+ int (*vidioc_s_modulator) (struct file *file, void *fh,
+ struct v4l2_modulator *a);
+ /* Crop ioctls */
+ int (*vidioc_cropcap) (struct file *file, void *fh,
+ struct v4l2_cropcap *a);
+ int (*vidioc_g_crop) (struct file *file, void *fh,
+ struct v4l2_crop *a);
+ int (*vidioc_s_crop) (struct file *file, void *fh,
+ struct v4l2_crop *a);
+ /* Compression ioctls */
+ int (*vidioc_g_mpegcomp) (struct file *file, void *fh,
+ struct v4l2_mpeg_compression *a);
+ int (*vidioc_s_mpegcomp) (struct file *file, void *fh,
+ struct v4l2_mpeg_compression *a);
+ int (*vidioc_g_jpegcomp) (struct file *file, void *fh,
+ struct v4l2_jpegcompression *a);
+ int (*vidioc_s_jpegcomp) (struct file *file, void *fh,
+ struct v4l2_jpegcompression *a);
+
+ /* Stream type-dependent parameter ioctls */
+ int (*vidioc_g_parm) (struct file *file, void *fh,
+ struct v4l2_streamparm *a);
+ int (*vidioc_s_parm) (struct file *file, void *fh,
+ struct v4l2_streamparm *a);
+
+ /* Tuner ioctls */
+ int (*vidioc_g_tuner) (struct file *file, void *fh,
+ struct v4l2_tuner *a);
+ int (*vidioc_s_tuner) (struct file *file, void *fh,
+ struct v4l2_tuner *a);
+ int (*vidioc_g_frequency) (struct file *file, void *fh,
+ struct v4l2_frequency *a);
+ int (*vidioc_s_frequency) (struct file *file, void *fh,
+ struct v4l2_frequency *a);
+
+ /* Sliced VBI cap */
+ int (*vidioc_g_sliced_vbi_cap) (struct file *file, void *fh,
+ struct v4l2_sliced_vbi_cap *a);
+
+ /* Log status ioctl */
+ int (*vidioc_log_status) (struct file *file, void *fh);
+
+
+#ifdef OBSOLETE_OWNER /* to be removed soon */
+/* obsolete -- fops->owner is used instead */
+struct module *owner;
+/* dev->driver_data will be used instead some day.
+ * Use the video_{get|set}_drvdata() helper functions,
+ * so the switch over will be transparent for you.
+ * Or use {pci|usb}_{get|set}_drvdata() directly. */
+void *priv;
+#endif
+
+ /* for videodev.c intenal usage -- please don't touch */
+ int users; /* video_exclusive_{open|close} ... */
+ struct mutex lock; /* ... helper function uses these */
+ char devfs_name[64]; /* devfs */
+ struct class_device class_dev; /* sysfs */
+};
+
+/* Version 2 functions */
+extern int video_register_device(struct video_device *vfd, int type, int nr);
+void video_unregister_device(struct video_device *);
+extern int video_ioctl2(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg);
+
+/* helper functions to alloc / release struct video_device, the
+ later can be used for video_device->release() */
+struct video_device *video_device_alloc(void);
+void video_device_release(struct video_device *vfd);
+
+/* Include support for obsoleted stuff */
+extern int video_usercopy(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg,
+ int (*func)(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg));
+
+
+#ifdef HAVE_V4L1
+#include <linux/mm.h>
+
+extern struct video_device* video_devdata(struct file*);
+
+#define to_video_device(cd) container_of(cd, struct video_device, class_dev)
+static inline void
+video_device_create_file(struct video_device *vfd,
+ struct class_device_attribute *attr)
+{
+ class_device_create_file(&vfd->class_dev, attr);
+}
+static inline void
+video_device_remove_file(struct video_device *vfd,
+ struct class_device_attribute *attr)
+{
+ class_device_remove_file(&vfd->class_dev, attr);
+}
+
+#ifdef OBSOLETE_OWNER /* to be removed soon */
+/* helper functions to access driver private data. */
+static inline void *video_get_drvdata(struct video_device *dev)
+{
+ return dev->priv;
+}
+
+static inline void video_set_drvdata(struct video_device *dev, void *data)
+{
+ dev->priv = data;
+}
+#endif
+
+extern int video_exclusive_open(struct inode *inode, struct file *file);
+extern int video_exclusive_release(struct inode *inode, struct file *file);
+#endif /* HAVE_V4L1 */
+
+#endif /* _V4L2_DEV_H */
diff --git a/include/media/video-buf-dvb.h b/include/media/video-buf-dvb.h
index b78d90f..8233caf 100644
--- a/include/media/video-buf-dvb.h
+++ b/include/media/video-buf-dvb.h
@@ -26,7 +26,8 @@ struct videobuf_dvb {
int videobuf_dvb_register(struct videobuf_dvb *dvb,
struct module *module,
- void *adapter_priv);
+ void *adapter_priv,
+ struct device *device);
void videobuf_dvb_unregister(struct videobuf_dvb *dvb);
/*
diff --git a/include/media/video-buf.h b/include/media/video-buf.h
index fff3fd0..1115a25 100644
--- a/include/media/video-buf.h
+++ b/include/media/video-buf.h
@@ -23,6 +23,7 @@
*/
#include <linux/videodev2.h>
+#include <linux/poll.h>
#define UNSET (-1U)
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index d5147770..ecc4286 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -968,6 +968,7 @@ enum ieee80211_state {
enum {
IEEE80211_CH_PASSIVE_ONLY = (1 << 0),
+ IEEE80211_CH_80211H_RULES = (1 << 1),
IEEE80211_CH_B_ONLY = (1 << 2),
IEEE80211_CH_NO_IBSS = (1 << 3),
IEEE80211_CH_UNIFORM_SPREADING = (1 << 4),
@@ -976,10 +977,10 @@ enum {
};
struct ieee80211_channel {
- u32 freq;
+ u32 freq; /* in MHz */
u8 channel;
u8 flags;
- u8 max_power;
+ u8 max_power; /* in dBm */
};
struct ieee80211_geo {
diff --git a/include/net/protocol.h b/include/net/protocol.h
index bcaee39..3b6dc15 100644
--- a/include/net/protocol.h
+++ b/include/net/protocol.h
@@ -36,6 +36,7 @@
struct net_protocol {
int (*handler)(struct sk_buff *skb);
void (*err_handler)(struct sk_buff *skb, u32 info);
+ struct sk_buff *(*gso_segment)(struct sk_buff *skb, int sg);
int no_policy;
};
diff --git a/include/net/sock.h b/include/net/sock.h
index d10dfec..2d8d6ad 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1030,9 +1030,13 @@ static inline void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
{
__sk_dst_set(sk, dst);
sk->sk_route_caps = dst->dev->features;
+ if (sk->sk_route_caps & NETIF_F_GSO)
+ sk->sk_route_caps |= NETIF_F_TSO;
if (sk->sk_route_caps & NETIF_F_TSO) {
if (sock_flag(sk, SOCK_NO_LARGESEND) || dst->header_len)
sk->sk_route_caps &= ~NETIF_F_TSO;
+ else
+ sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM;
}
}
@@ -1265,6 +1269,7 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
* sk_eat_skb - Release a skb if it is no longer needed
* @sk: socket to eat this skb from
* @skb: socket buffer to eat
+ * @copied_early: flag indicating whether DMA operations copied this data early
*
* This routine must be called with interrupts disabled or with the socket
* locked so that the sk_buff queue operation is ok.
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 5f4eb5c..ca3d38d 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -569,13 +569,13 @@ struct tcp_skb_cb {
*/
static inline int tcp_skb_pcount(const struct sk_buff *skb)
{
- return skb_shinfo(skb)->tso_segs;
+ return skb_shinfo(skb)->gso_segs;
}
/* This is valid iff tcp_skb_pcount() > 1. */
static inline int tcp_skb_mss(const struct sk_buff *skb)
{
- return skb_shinfo(skb)->tso_size;
+ return skb_shinfo(skb)->gso_size;
}
static inline void tcp_dec_pcount_approx(__u32 *count,
@@ -1086,6 +1086,8 @@ extern struct request_sock_ops tcp_request_sock_ops;
extern int tcp_v4_destroy_sock(struct sock *sk);
+extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg);
+
#ifdef CONFIG_PROC_FS
extern int tcp4_proc_init(void);
extern void tcp4_proc_exit(void);
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index b0caabe..e46cd40 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -145,6 +145,7 @@ extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t);
extern void scsi_put_command(struct scsi_cmnd *);
extern void scsi_io_completion(struct scsi_cmnd *, unsigned int, unsigned int);
extern void scsi_finish_command(struct scsi_cmnd *cmd);
+extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd);
extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
size_t *offset, size_t *len);
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index de6ce54..a42efd6 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -472,6 +472,7 @@ struct Scsi_Host {
*/
unsigned int host_busy; /* commands actually active on low-level */
unsigned int host_failed; /* commands that failed. */
+ unsigned int host_eh_scheduled; /* EH scheduled without command */
unsigned short host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
int resetting; /* if set, it means that last_reset is a valid value */
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
index b45a737..446afc3 100644
--- a/include/sound/ac97_codec.h
+++ b/include/sound/ac97_codec.h
@@ -378,6 +378,7 @@
#define AC97_HAS_NO_MIC (1<<15) /* no MIC volume */
#define AC97_HAS_NO_TONE (1<<16) /* no Tone volume */
#define AC97_HAS_NO_STD_PCM (1<<17) /* no standard AC97 PCM volume and mute */
+#define AC97_HAS_NO_AUX (1<<18) /* no standard AC97 AUX volume and mute */
/* rates indexes */
#define AC97_RATES_FRONT_DAC 0
diff --git a/include/sound/asequencer.h b/include/sound/asequencer.h
index 6691e4a..3f2f404 100644
--- a/include/sound/asequencer.h
+++ b/include/sound/asequencer.h
@@ -605,6 +605,10 @@ struct snd_seq_remove_events {
#define SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE (1<<11) /* Sampling device (support sample download) */
#define SNDRV_SEQ_PORT_TYPE_SAMPLE (1<<12) /* Sampling device (sample can be downloaded at any time) */
/*...*/
+#define SNDRV_SEQ_PORT_TYPE_HARDWARE (1<<16) /* driver for a hardware device */
+#define SNDRV_SEQ_PORT_TYPE_SOFTWARE (1<<17) /* implemented in software */
+#define SNDRV_SEQ_PORT_TYPE_SYNTHESIZER (1<<18) /* generates sound */
+#define SNDRV_SEQ_PORT_TYPE_PORT (1<<19) /* connects to other device(s) */
#define SNDRV_SEQ_PORT_TYPE_APPLICATION (1<<20) /* application (sequencer/editor) */
/* misc. conditioning flags */
diff --git a/include/sound/asound.h b/include/sound/asound.h
index 9cc021c..41885f4 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -137,7 +137,7 @@ enum {
* *
*****************************************************************************/
-#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 7)
+#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 8)
typedef unsigned long snd_pcm_uframes_t;
typedef signed long snd_pcm_sframes_t;
diff --git a/include/sound/core.h b/include/sound/core.h
index 5135147..5d184be 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -233,9 +233,8 @@ int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size
/* init.c */
-extern unsigned int snd_cards_lock;
extern struct snd_card *snd_cards[SNDRV_CARDS];
-extern rwlock_t snd_card_rwlock;
+int snd_card_locked(int card);
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
#define SND_MIXER_OSS_NOTIFY_REGISTER 0
#define SND_MIXER_OSS_NOTIFY_DISCONNECT 1
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 186e00a..884bbf5 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -245,6 +245,7 @@
#define A_IOCFG_GPOUT0 0x0044 /* analog/digital */
#define A_IOCFG_DISABLE_ANALOG 0x0040 /* = 'enable' for Audigy2 (chiprev=4) */
#define A_IOCFG_ENABLE_DIGITAL 0x0004
+#define A_IOCFG_ENABLE_DIGITAL_AUDIGY4 0x0080
#define A_IOCFG_UNKNOWN_20 0x0020
#define A_IOCFG_DISABLE_AC97_FRONT 0x0080 /* turn off ac97 front -> front (10k2.1) */
#define A_IOCFG_GPOUT1 0x0002 /* IR? drive's internal bypass (?) */
@@ -1065,6 +1066,7 @@ struct snd_emu_chip_details {
unsigned char emu1212m; /* EMU 1212m card */
unsigned char spi_dac; /* SPI interface for DAC */
unsigned char i2c_adc; /* I2C interface for ADC */
+ unsigned char adc_1361t; /* Use Philips 1361T ADC */
const char *driver;
const char *name;
const char *id; /* for backward compatibility - can be NULL if not needed */
diff --git a/include/sound/info.h b/include/sound/info.h
index f23d838..74f69967 100644
--- a/include/sound/info.h
+++ b/include/sound/info.h
@@ -27,9 +27,9 @@
/* buffer for information */
struct snd_info_buffer {
char *buffer; /* pointer to begin of buffer */
- char *curr; /* current position in buffer */
- unsigned long size; /* current size */
- unsigned long len; /* total length of buffer */
+ unsigned int curr; /* current position in buffer */
+ unsigned int size; /* current size */
+ unsigned int len; /* total length of buffer */
int stop; /* stop flag */
int error; /* error code */
};
@@ -40,8 +40,6 @@ struct snd_info_buffer {
struct snd_info_entry;
struct snd_info_entry_text {
- unsigned long read_size;
- unsigned long write_size;
void (*read) (struct snd_info_entry *entry, struct snd_info_buffer *buffer);
void (*write) (struct snd_info_entry *entry, struct snd_info_buffer *buffer);
};
@@ -132,11 +130,9 @@ int snd_card_proc_new(struct snd_card *card, const char *name, struct snd_info_e
static inline void snd_info_set_text_ops(struct snd_info_entry *entry,
void *private_data,
- long read_size,
void (*read)(struct snd_info_entry *, struct snd_info_buffer *))
{
entry->private_data = private_data;
- entry->c.text.read_size = read_size;
entry->c.text.read = read;
}
@@ -167,7 +163,6 @@ static inline int snd_card_proc_new(struct snd_card *card, const char *name,
struct snd_info_entry **entryp) { return -EINVAL; }
static inline void snd_info_set_text_ops(struct snd_info_entry *entry __attribute__((unused)),
void *private_data,
- long read_size,
void (*read)(struct snd_info_entry *, struct snd_info_buffer *)) {}
static inline int snd_info_check_reserved_words(const char *str) { return 1; }
diff --git a/include/sound/mpu401.h b/include/sound/mpu401.h
index 8e97ace..ac50432 100644
--- a/include/sound/mpu401.h
+++ b/include/sound/mpu401.h
@@ -45,6 +45,12 @@
#define MPU401_HW_PC98II 18 /* Roland PC98II */
#define MPU401_HW_AUREAL 19 /* Aureal Vortex */
+#define MPU401_INFO_INPUT (1 << 0) /* input stream */
+#define MPU401_INFO_OUTPUT (1 << 1) /* output stream */
+#define MPU401_INFO_INTEGRATED (1 << 2) /* integrated h/w port */
+#define MPU401_INFO_MMIO (1 << 3) /* MMIO access */
+#define MPU401_INFO_TX_IRQ (1 << 4) /* independent TX irq */
+
#define MPU401_MODE_BIT_INPUT 0
#define MPU401_MODE_BIT_OUTPUT 1
#define MPU401_MODE_BIT_INPUT_TRIGGER 2
@@ -62,6 +68,7 @@ struct snd_mpu401 {
struct snd_rawmidi *rmidi;
unsigned short hardware; /* MPU401_HW_XXXX */
+ unsigned int info_flags; /* MPU401_INFO_XXX */
unsigned long port; /* base port of MPU-401 chip */
unsigned long cport; /* port + 1 (usually) */
struct resource *res; /* port resource */
@@ -99,13 +106,16 @@ struct snd_mpu401 {
*/
-irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs);
+irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id,
+ struct pt_regs *regs);
int snd_mpu401_uart_new(struct snd_card *card,
int device,
unsigned short hardware,
unsigned long port,
- int integrated,
+ unsigned int info_flags,
int irq,
int irq_flags,
struct snd_rawmidi ** rrawmidi);
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 3734258..f84d849 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -300,7 +300,6 @@ struct snd_pcm_runtime {
/* -- mmap -- */
volatile struct snd_pcm_mmap_status *status;
volatile struct snd_pcm_mmap_control *control;
- atomic_t mmap_count;
/* -- locking / scheduling -- */
wait_queue_head_t sleep;
@@ -368,7 +367,9 @@ struct snd_pcm_substream {
struct snd_pcm_group *group; /* pointer to current group */
/* -- assigned files -- */
void *file;
- struct file *ffile;
+ int ref_count;
+ atomic_t mmap_count;
+ unsigned int f_flags;
void (*pcm_release)(struct snd_pcm_substream *);
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
/* -- OSS things -- */
@@ -387,7 +388,7 @@ struct snd_pcm_substream {
unsigned int hw_opened: 1;
};
-#define SUBSTREAM_BUSY(substream) ((substream)->file != NULL)
+#define SUBSTREAM_BUSY(substream) ((substream)->ref_count > 0)
struct snd_pcm_str {
@@ -825,14 +826,6 @@ int snd_interval_ratnum(struct snd_interval *i,
void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params);
void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var);
-int snd_pcm_hw_param_near(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var,
- unsigned int val, int *dir);
-int snd_pcm_hw_param_set(struct snd_pcm_substream *pcm,
- struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var,
- unsigned int val, int dir);
int snd_pcm_hw_params_choose(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params);
int snd_pcm_hw_refine(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params);
@@ -979,13 +972,13 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne
static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area)
{
struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data;
- atomic_inc(&substream->runtime->mmap_count);
+ atomic_inc(&substream->mmap_count);
}
static inline void snd_pcm_mmap_data_close(struct vm_area_struct *area)
{
struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data;
- atomic_dec(&substream->runtime->mmap_count);
+ atomic_dec(&substream->mmap_count);
}
/* mmap for io-memory area */
diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h
index fb18aef7..85cf1cf 100644
--- a/include/sound/pcm_params.h
+++ b/include/sound/pcm_params.h
@@ -22,29 +22,21 @@
*
*/
-extern int snd_pcm_hw_param_mask(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var, const struct snd_mask *val);
-extern unsigned int snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var, int *dir);
-extern unsigned int snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var, int *dir);
-extern int _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var, unsigned int val, int dir);
-extern int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var);
-extern int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var, unsigned int val, int dir);
-
-/* To share the same code we have alsa-lib */
-#define INLINE static inline
-#define assert(a) (void)(a)
+int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm,
+ struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, int *dir);
+int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm,
+ struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, int *dir);
+int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, int *dir);
#define SNDRV_MASK_BITS 64 /* we use so far 64bits only */
#define SNDRV_MASK_SIZE (SNDRV_MASK_BITS / 32)
#define MASK_OFS(i) ((i) >> 5)
#define MASK_BIT(i) (1U << ((i) & 31))
-INLINE unsigned int ld2(u_int32_t v)
+static inline unsigned int ld2(u_int32_t v)
{
unsigned r = 0;
@@ -69,22 +61,22 @@ INLINE unsigned int ld2(u_int32_t v)
return r;
}
-INLINE size_t snd_mask_sizeof(void)
+static inline size_t snd_mask_sizeof(void)
{
return sizeof(struct snd_mask);
}
-INLINE void snd_mask_none(struct snd_mask *mask)
+static inline void snd_mask_none(struct snd_mask *mask)
{
memset(mask, 0, sizeof(*mask));
}
-INLINE void snd_mask_any(struct snd_mask *mask)
+static inline void snd_mask_any(struct snd_mask *mask)
{
memset(mask, 0xff, SNDRV_MASK_SIZE * sizeof(u_int32_t));
}
-INLINE int snd_mask_empty(const struct snd_mask *mask)
+static inline int snd_mask_empty(const struct snd_mask *mask)
{
int i;
for (i = 0; i < SNDRV_MASK_SIZE; i++)
@@ -93,10 +85,9 @@ INLINE int snd_mask_empty(const struct snd_mask *mask)
return 1;
}
-INLINE unsigned int snd_mask_min(const struct snd_mask *mask)
+static inline unsigned int snd_mask_min(const struct snd_mask *mask)
{
int i;
- assert(!snd_mask_empty(mask));
for (i = 0; i < SNDRV_MASK_SIZE; i++) {
if (mask->bits[i])
return ffs(mask->bits[i]) - 1 + (i << 5);
@@ -104,10 +95,9 @@ INLINE unsigned int snd_mask_min(const struct snd_mask *mask)
return 0;
}
-INLINE unsigned int snd_mask_max(const struct snd_mask *mask)
+static inline unsigned int snd_mask_max(const struct snd_mask *mask)
{
int i;
- assert(!snd_mask_empty(mask));
for (i = SNDRV_MASK_SIZE - 1; i >= 0; i--) {
if (mask->bits[i])
return ld2(mask->bits[i]) + (i << 5);
@@ -115,70 +105,68 @@ INLINE unsigned int snd_mask_max(const struct snd_mask *mask)
return 0;
}
-INLINE void snd_mask_set(struct snd_mask *mask, unsigned int val)
+static inline void snd_mask_set(struct snd_mask *mask, unsigned int val)
{
- assert(val <= SNDRV_MASK_BITS);
mask->bits[MASK_OFS(val)] |= MASK_BIT(val);
}
-INLINE void snd_mask_reset(struct snd_mask *mask, unsigned int val)
+static inline void snd_mask_reset(struct snd_mask *mask, unsigned int val)
{
- assert(val <= SNDRV_MASK_BITS);
mask->bits[MASK_OFS(val)] &= ~MASK_BIT(val);
}
-INLINE void snd_mask_set_range(struct snd_mask *mask, unsigned int from, unsigned int to)
+static inline void snd_mask_set_range(struct snd_mask *mask,
+ unsigned int from, unsigned int to)
{
unsigned int i;
- assert(to <= SNDRV_MASK_BITS && from <= to);
for (i = from; i <= to; i++)
mask->bits[MASK_OFS(i)] |= MASK_BIT(i);
}
-INLINE void snd_mask_reset_range(struct snd_mask *mask, unsigned int from, unsigned int to)
+static inline void snd_mask_reset_range(struct snd_mask *mask,
+ unsigned int from, unsigned int to)
{
unsigned int i;
- assert(to <= SNDRV_MASK_BITS && from <= to);
for (i = from; i <= to; i++)
mask->bits[MASK_OFS(i)] &= ~MASK_BIT(i);
}
-INLINE void snd_mask_leave(struct snd_mask *mask, unsigned int val)
+static inline void snd_mask_leave(struct snd_mask *mask, unsigned int val)
{
unsigned int v;
- assert(val <= SNDRV_MASK_BITS);
v = mask->bits[MASK_OFS(val)] & MASK_BIT(val);
snd_mask_none(mask);
mask->bits[MASK_OFS(val)] = v;
}
-INLINE void snd_mask_intersect(struct snd_mask *mask, const struct snd_mask *v)
+static inline void snd_mask_intersect(struct snd_mask *mask,
+ const struct snd_mask *v)
{
int i;
for (i = 0; i < SNDRV_MASK_SIZE; i++)
mask->bits[i] &= v->bits[i];
}
-INLINE int snd_mask_eq(const struct snd_mask *mask, const struct snd_mask *v)
+static inline int snd_mask_eq(const struct snd_mask *mask,
+ const struct snd_mask *v)
{
return ! memcmp(mask, v, SNDRV_MASK_SIZE * sizeof(u_int32_t));
}
-INLINE void snd_mask_copy(struct snd_mask *mask, const struct snd_mask *v)
+static inline void snd_mask_copy(struct snd_mask *mask,
+ const struct snd_mask *v)
{
*mask = *v;
}
-INLINE int snd_mask_test(const struct snd_mask *mask, unsigned int val)
+static inline int snd_mask_test(const struct snd_mask *mask, unsigned int val)
{
- assert(val <= SNDRV_MASK_BITS);
return mask->bits[MASK_OFS(val)] & MASK_BIT(val);
}
-INLINE int snd_mask_single(const struct snd_mask *mask)
+static inline int snd_mask_single(const struct snd_mask *mask)
{
int i, c = 0;
- assert(!snd_mask_empty(mask));
for (i = 0; i < SNDRV_MASK_SIZE; i++) {
if (! mask->bits[i])
continue;
@@ -191,10 +179,10 @@ INLINE int snd_mask_single(const struct snd_mask *mask)
return 1;
}
-INLINE int snd_mask_refine(struct snd_mask *mask, const struct snd_mask *v)
+static inline int snd_mask_refine(struct snd_mask *mask,
+ const struct snd_mask *v)
{
struct snd_mask old;
- assert(!snd_mask_empty(mask));
snd_mask_copy(&old, mask);
snd_mask_intersect(mask, v);
if (snd_mask_empty(mask))
@@ -202,27 +190,24 @@ INLINE int snd_mask_refine(struct snd_mask *mask, const struct snd_mask *v)
return !snd_mask_eq(mask, &old);
}
-INLINE int snd_mask_refine_first(struct snd_mask *mask)
+static inline int snd_mask_refine_first(struct snd_mask *mask)
{
- assert(!snd_mask_empty(mask));
if (snd_mask_single(mask))
return 0;
snd_mask_leave(mask, snd_mask_min(mask));
return 1;
}
-INLINE int snd_mask_refine_last(struct snd_mask *mask)
+static inline int snd_mask_refine_last(struct snd_mask *mask)
{
- assert(!snd_mask_empty(mask));
if (snd_mask_single(mask))
return 0;
snd_mask_leave(mask, snd_mask_max(mask));
return 1;
}
-INLINE int snd_mask_refine_min(struct snd_mask *mask, unsigned int val)
+static inline int snd_mask_refine_min(struct snd_mask *mask, unsigned int val)
{
- assert(!snd_mask_empty(mask));
if (snd_mask_min(mask) >= val)
return 0;
snd_mask_reset_range(mask, 0, val - 1);
@@ -231,9 +216,8 @@ INLINE int snd_mask_refine_min(struct snd_mask *mask, unsigned int val)
return 1;
}
-INLINE int snd_mask_refine_max(struct snd_mask *mask, unsigned int val)
+static inline int snd_mask_refine_max(struct snd_mask *mask, unsigned int val)
{
- assert(!snd_mask_empty(mask));
if (snd_mask_max(mask) <= val)
return 0;
snd_mask_reset_range(mask, val + 1, SNDRV_MASK_BITS);
@@ -242,10 +226,9 @@ INLINE int snd_mask_refine_max(struct snd_mask *mask, unsigned int val)
return 1;
}
-INLINE int snd_mask_refine_set(struct snd_mask *mask, unsigned int val)
+static inline int snd_mask_refine_set(struct snd_mask *mask, unsigned int val)
{
int changed;
- assert(!snd_mask_empty(mask));
changed = !snd_mask_single(mask);
snd_mask_leave(mask, val);
if (snd_mask_empty(mask))
@@ -253,13 +236,12 @@ INLINE int snd_mask_refine_set(struct snd_mask *mask, unsigned int val)
return changed;
}
-INLINE int snd_mask_value(const struct snd_mask *mask)
+static inline int snd_mask_value(const struct snd_mask *mask)
{
- assert(!snd_mask_empty(mask));
return snd_mask_min(mask);
}
-INLINE void snd_interval_any(struct snd_interval *i)
+static inline void snd_interval_any(struct snd_interval *i)
{
i->min = 0;
i->openmin = 0;
@@ -269,63 +251,59 @@ INLINE void snd_interval_any(struct snd_interval *i)
i->empty = 0;
}
-INLINE void snd_interval_none(struct snd_interval *i)
+static inline void snd_interval_none(struct snd_interval *i)
{
i->empty = 1;
}
-INLINE int snd_interval_checkempty(const struct snd_interval *i)
+static inline int snd_interval_checkempty(const struct snd_interval *i)
{
return (i->min > i->max ||
(i->min == i->max && (i->openmin || i->openmax)));
}
-INLINE int snd_interval_empty(const struct snd_interval *i)
+static inline int snd_interval_empty(const struct snd_interval *i)
{
return i->empty;
}
-INLINE int snd_interval_single(const struct snd_interval *i)
+static inline int snd_interval_single(const struct snd_interval *i)
{
- assert(!snd_interval_empty(i));
return (i->min == i->max ||
(i->min + 1 == i->max && i->openmax));
}
-INLINE int snd_interval_value(const struct snd_interval *i)
+static inline int snd_interval_value(const struct snd_interval *i)
{
- assert(snd_interval_single(i));
return i->min;
}
-INLINE int snd_interval_min(const struct snd_interval *i)
+static inline int snd_interval_min(const struct snd_interval *i)
{
- assert(!snd_interval_empty(i));
return i->min;
}
-INLINE int snd_interval_max(const struct snd_interval *i)
+static inline int snd_interval_max(const struct snd_interval *i)
{
unsigned int v;
- assert(!snd_interval_empty(i));
v = i->max;
if (i->openmax)
v--;
return v;
}
-INLINE int snd_interval_test(const struct snd_interval *i, unsigned int val)
+static inline int snd_interval_test(const struct snd_interval *i, unsigned int val)
{
return !((i->min > val || (i->min == val && i->openmin) ||
i->max < val || (i->max == val && i->openmax)));
}
-INLINE void snd_interval_copy(struct snd_interval *d, const struct snd_interval *s)
+static inline void snd_interval_copy(struct snd_interval *d, const struct snd_interval *s)
{
*d = *s;
}
-INLINE int snd_interval_setinteger(struct snd_interval *i)
+static inline int snd_interval_setinteger(struct snd_interval *i)
{
if (i->integer)
return 0;
@@ -335,7 +313,7 @@ INLINE int snd_interval_setinteger(struct snd_interval *i)
return 1;
}
-INLINE int snd_interval_eq(const struct snd_interval *i1, const struct snd_interval *i2)
+static inline int snd_interval_eq(const struct snd_interval *i1, const struct snd_interval *i2)
{
if (i1->empty)
return i2->empty;
@@ -359,8 +337,5 @@ static inline unsigned int sub(unsigned int a, unsigned int b)
return 0;
}
-#undef INLINE
-#undef assert
-
#endif /* __SOUND_PCM_PARAMS_H */
diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h
index 584e73d..7dbcd10 100644
--- a/include/sound/rawmidi.h
+++ b/include/sound/rawmidi.h
@@ -46,6 +46,7 @@
struct snd_rawmidi;
struct snd_rawmidi_substream;
+struct snd_seq_port_info;
struct snd_rawmidi_ops {
int (*open) (struct snd_rawmidi_substream * substream);
@@ -57,6 +58,8 @@ struct snd_rawmidi_ops {
struct snd_rawmidi_global_ops {
int (*dev_register) (struct snd_rawmidi * rmidi);
int (*dev_unregister) (struct snd_rawmidi * rmidi);
+ void (*get_port_info)(struct snd_rawmidi *rmidi, int number,
+ struct snd_seq_port_info *info);
};
struct snd_rawmidi_runtime {
diff --git a/include/sound/tea575x-tuner.h b/include/sound/tea575x-tuner.h
index a4f55452..b5067d3 100644
--- a/include/sound/tea575x-tuner.h
+++ b/include/sound/tea575x-tuner.h
@@ -20,9 +20,10 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- */
+ */
#include <linux/videodev.h>
+#include <media/v4l2-dev.h>
struct snd_tea575x;
diff --git a/include/sound/version.h b/include/sound/version.h
index 4f0e658..2ee849d 100644
--- a/include/sound/version.h
+++ b/include/sound/version.h
@@ -1,3 +1,3 @@
/* include/version.h. Generated by configure. */
-#define CONFIG_SND_VERSION "1.0.11rc4"
-#define CONFIG_SND_DATE " (Wed Mar 22 10:27:24 2006 UTC)"
+#define CONFIG_SND_VERSION "1.0.12rc1"
+#define CONFIG_SND_DATE " (Thu Jun 22 13:55:50 2006 UTC)"
diff --git a/init/Kconfig b/init/Kconfig
index df864a3..e0358f3 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -151,7 +151,8 @@ config BSD_PROCESS_ACCT_V3
at <http://www.physik3.uni-rostock.de/tim/kernel/utils/acct/>.
config SYSCTL
- bool "Sysctl support"
+ bool "Sysctl support" if EMBEDDED
+ default y
---help---
The sysctl interface provides a means of dynamically changing
certain kernel parameters and variables on the fly without requiring
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 1511714..02e6f67 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -205,11 +205,11 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
return 0;
}
-static struct super_block *mqueue_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data)
+static int mqueue_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data, struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, mqueue_fill_super);
+ return get_sb_single(fs_type, flags, data, mqueue_fill_super, mnt);
}
static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags)
@@ -359,7 +359,7 @@ static ssize_t mqueue_read_file(struct file *filp, char __user *u_data,
return count;
}
-static int mqueue_flush_file(struct file *filp)
+static int mqueue_flush_file(struct file *filp, fl_owner_t id)
{
struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode);
diff --git a/ipc/shm.c b/ipc/shm.c
index 4f133d2..fe7ae73 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -698,7 +698,6 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
int err;
unsigned long flags;
unsigned long prot;
- unsigned long o_flags;
int acc_mode;
void *user_addr;
@@ -725,11 +724,9 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
if (shmflg & SHM_RDONLY) {
prot = PROT_READ;
- o_flags = O_RDONLY;
acc_mode = S_IRUGO;
} else {
prot = PROT_READ | PROT_WRITE;
- o_flags = O_RDWR;
acc_mode = S_IRUGO | S_IWUGO;
}
if (shmflg & SHM_EXEC) {
diff --git a/kernel/acct.c b/kernel/acct.c
index b327f4d..368c4f0 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -75,7 +75,7 @@ int acct_parm[3] = {4, 2, 30};
/*
* External references and all of the globals.
*/
-static void do_acct_process(long, struct file *);
+static void do_acct_process(struct file *);
/*
* This structure is used so that all the data protected by lock
@@ -118,7 +118,7 @@ static int check_free_space(struct file *file)
spin_unlock(&acct_globals.lock);
/* May block */
- if (vfs_statfs(file->f_dentry->d_inode->i_sb, &sbuf))
+ if (vfs_statfs(file->f_dentry, &sbuf))
return res;
suspend = sbuf.f_blocks * SUSPEND;
resume = sbuf.f_blocks * RESUME;
@@ -196,7 +196,7 @@ static void acct_file_reopen(struct file *file)
if (old_acct) {
mnt_unpin(old_acct->f_vfsmnt);
spin_unlock(&acct_globals.lock);
- do_acct_process(0, old_acct);
+ do_acct_process(old_acct);
filp_close(old_acct, NULL);
spin_lock(&acct_globals.lock);
}
@@ -419,16 +419,15 @@ static u32 encode_float(u64 value)
/*
* do_acct_process does all actual work. Caller holds the reference to file.
*/
-static void do_acct_process(long exitcode, struct file *file)
+static void do_acct_process(struct file *file)
{
+ struct pacct_struct *pacct = &current->signal->pacct;
acct_t ac;
mm_segment_t fs;
- unsigned long vsize;
unsigned long flim;
u64 elapsed;
u64 run_time;
struct timespec uptime;
- unsigned long jiffies;
/*
* First check to see if there is enough free_space to continue
@@ -469,12 +468,6 @@ static void do_acct_process(long exitcode, struct file *file)
#endif
do_div(elapsed, AHZ);
ac.ac_btime = xtime.tv_sec - elapsed;
- jiffies = cputime_to_jiffies(cputime_add(current->utime,
- current->signal->utime));
- ac.ac_utime = encode_comp_t(jiffies_to_AHZ(jiffies));
- jiffies = cputime_to_jiffies(cputime_add(current->stime,
- current->signal->stime));
- ac.ac_stime = encode_comp_t(jiffies_to_AHZ(jiffies));
/* we really need to bite the bullet and change layout */
ac.ac_uid = current->uid;
ac.ac_gid = current->gid;
@@ -496,37 +489,18 @@ static void do_acct_process(long exitcode, struct file *file)
old_encode_dev(tty_devnum(current->signal->tty)) : 0;
read_unlock(&tasklist_lock);
- ac.ac_flag = 0;
- if (current->flags & PF_FORKNOEXEC)
- ac.ac_flag |= AFORK;
- if (current->flags & PF_SUPERPRIV)
- ac.ac_flag |= ASU;
- if (current->flags & PF_DUMPCORE)
- ac.ac_flag |= ACORE;
- if (current->flags & PF_SIGNALED)
- ac.ac_flag |= AXSIG;
-
- vsize = 0;
- if (current->mm) {
- struct vm_area_struct *vma;
- down_read(&current->mm->mmap_sem);
- vma = current->mm->mmap;
- while (vma) {
- vsize += vma->vm_end - vma->vm_start;
- vma = vma->vm_next;
- }
- up_read(&current->mm->mmap_sem);
- }
- vsize = vsize / 1024;
- ac.ac_mem = encode_comp_t(vsize);
+ spin_lock(&current->sighand->siglock);
+ 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)));
+ ac.ac_flag = pacct->ac_flag;
+ ac.ac_mem = encode_comp_t(pacct->ac_mem);
+ ac.ac_minflt = encode_comp_t(pacct->ac_minflt);
+ ac.ac_majflt = encode_comp_t(pacct->ac_majflt);
+ ac.ac_exitcode = pacct->ac_exitcode;
+ spin_unlock(&current->sighand->siglock);
ac.ac_io = encode_comp_t(0 /* current->io_usage */); /* %% */
ac.ac_rw = encode_comp_t(ac.ac_io / 1024);
- ac.ac_minflt = encode_comp_t(current->signal->min_flt +
- current->min_flt);
- ac.ac_majflt = encode_comp_t(current->signal->maj_flt +
- current->maj_flt);
ac.ac_swaps = encode_comp_t(0);
- ac.ac_exitcode = exitcode;
/*
* Kernel segment override to datasegment and write it
@@ -546,12 +520,63 @@ static void do_acct_process(long exitcode, struct file *file)
}
/**
+ * acct_init_pacct - initialize a new pacct_struct
+ */
+void acct_init_pacct(struct pacct_struct *pacct)
+{
+ memset(pacct, 0, sizeof(struct pacct_struct));
+ pacct->ac_utime = pacct->ac_stime = cputime_zero;
+}
+
+/**
+ * acct_collect - collect accounting information into pacct_struct
+ * @exitcode: task exit code
+ * @group_dead: not 0, if this thread is the last one in the process.
+ */
+void acct_collect(long exitcode, int group_dead)
+{
+ struct pacct_struct *pacct = &current->signal->pacct;
+ unsigned long vsize = 0;
+
+ if (group_dead && current->mm) {
+ struct vm_area_struct *vma;
+ down_read(&current->mm->mmap_sem);
+ vma = current->mm->mmap;
+ while (vma) {
+ vsize += vma->vm_end - vma->vm_start;
+ vma = vma->vm_next;
+ }
+ up_read(&current->mm->mmap_sem);
+ }
+
+ spin_lock_irq(&current->sighand->siglock);
+ if (group_dead)
+ pacct->ac_mem = vsize / 1024;
+ if (thread_group_leader(current)) {
+ pacct->ac_exitcode = exitcode;
+ if (current->flags & PF_FORKNOEXEC)
+ pacct->ac_flag |= AFORK;
+ }
+ if (current->flags & PF_SUPERPRIV)
+ pacct->ac_flag |= ASU;
+ if (current->flags & PF_DUMPCORE)
+ pacct->ac_flag |= ACORE;
+ if (current->flags & PF_SIGNALED)
+ pacct->ac_flag |= AXSIG;
+ pacct->ac_utime = cputime_add(pacct->ac_utime, current->utime);
+ pacct->ac_stime = cputime_add(pacct->ac_stime, current->stime);
+ pacct->ac_minflt += current->min_flt;
+ pacct->ac_majflt += current->maj_flt;
+ spin_unlock_irq(&current->sighand->siglock);
+}
+
+/**
* acct_process - now just a wrapper around do_acct_process
* @exitcode: task exit code
*
* handles process accounting for an exiting task
*/
-void acct_process(long exitcode)
+void acct_process()
{
struct file *file = NULL;
@@ -570,7 +595,7 @@ void acct_process(long exitcode)
get_file(file);
spin_unlock(&acct_globals.lock);
- do_acct_process(exitcode, file);
+ do_acct_process(file);
fput(file);
}
@@ -599,9 +624,7 @@ void acct_update_integrals(struct task_struct *tsk)
*/
void acct_clear_integrals(struct task_struct *tsk)
{
- if (tsk) {
- tsk->acct_stimexpd = 0;
- tsk->acct_rss_mem1 = 0;
- tsk->acct_vm_mem1 = 0;
- }
+ tsk->acct_stimexpd = 0;
+ tsk->acct_rss_mem1 = 0;
+ tsk->acct_vm_mem1 = 0;
}
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index b097ccb..9ebd96f 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1558,6 +1558,7 @@ int __audit_ipc_obj(struct kern_ipc_perm *ipcp)
* @uid: msgq user id
* @gid: msgq group id
* @mode: msgq mode (permissions)
+ * @ipcp: in-kernel IPC permissions
*
* Returns 0 for success or NULL context or < 0 on error.
*/
diff --git a/kernel/compat.c b/kernel/compat.c
index c1601a8..126dee9 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -21,6 +21,7 @@
#include <linux/unistd.h>
#include <linux/security.h>
#include <linux/timex.h>
+#include <linux/migrate.h>
#include <asm/uaccess.h>
@@ -729,17 +730,10 @@ void
sigset_from_compat (sigset_t *set, compat_sigset_t *compat)
{
switch (_NSIG_WORDS) {
-#if defined (__COMPAT_ENDIAN_SWAP__)
- case 4: set->sig[3] = compat->sig[7] | (((long)compat->sig[6]) << 32 );
- case 3: set->sig[2] = compat->sig[5] | (((long)compat->sig[4]) << 32 );
- case 2: set->sig[1] = compat->sig[3] | (((long)compat->sig[2]) << 32 );
- case 1: set->sig[0] = compat->sig[1] | (((long)compat->sig[0]) << 32 );
-#else
case 4: set->sig[3] = compat->sig[6] | (((long)compat->sig[7]) << 32 );
case 3: set->sig[2] = compat->sig[4] | (((long)compat->sig[5]) << 32 );
case 2: set->sig[1] = compat->sig[2] | (((long)compat->sig[3]) << 32 );
case 1: set->sig[0] = compat->sig[0] | (((long)compat->sig[1]) << 32 );
-#endif
}
}
@@ -934,3 +928,25 @@ asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp)
return ret;
}
+
+#ifdef CONFIG_NUMA
+asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_pages,
+ compat_uptr_t __user *pages32,
+ const int __user *nodes,
+ int __user *status,
+ int flags)
+{
+ const void __user * __user *pages;
+ int i;
+
+ pages = compat_alloc_user_space(nr_pages * sizeof(void *));
+ for (i = 0; i < nr_pages; i++) {
+ compat_uptr_t p;
+
+ if (get_user(p, pages32 + i) ||
+ put_user(compat_ptr(p), pages + i))
+ return -EFAULT;
+ }
+ return sys_move_pages(pid, nr_pages, pages, nodes, status, flags);
+}
+#endif
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index ab81fdd..b602f73 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -41,6 +41,7 @@
#include <linux/rcupdate.h>
#include <linux/sched.h>
#include <linux/seq_file.h>
+#include <linux/security.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/spinlock.h>
@@ -392,11 +393,11 @@ static int cpuset_fill_super(struct super_block *sb, void *unused_data,
return 0;
}
-static struct super_block *cpuset_get_sb(struct file_system_type *fs_type,
- int flags, const char *unused_dev_name,
- void *data)
+static int cpuset_get_sb(struct file_system_type *fs_type,
+ int flags, const char *unused_dev_name,
+ void *data, struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, cpuset_fill_super);
+ return get_sb_single(fs_type, flags, data, cpuset_fill_super, mnt);
}
static struct file_system_type cpuset_fs_type = {
@@ -1177,6 +1178,7 @@ static int attach_task(struct cpuset *cs, char *pidbuf, char **ppathbuf)
cpumask_t cpus;
nodemask_t from, to;
struct mm_struct *mm;
+ int retval;
if (sscanf(pidbuf, "%d", &pid) != 1)
return -EIO;
@@ -1205,6 +1207,12 @@ static int attach_task(struct cpuset *cs, char *pidbuf, char **ppathbuf)
get_task_struct(tsk);
}
+ retval = security_task_setscheduler(tsk, 0, NULL);
+ if (retval) {
+ put_task_struct(tsk);
+ return retval;
+ }
+
mutex_lock(&callback_mutex);
task_lock(tsk);
diff --git a/kernel/exit.c b/kernel/exit.c
index e06d0c1..e76bd02 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -36,6 +36,7 @@
#include <linux/compat.h>
#include <linux/pipe_fs_i.h>
#include <linux/audit.h> /* for audit_free() */
+#include <linux/resource.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
@@ -45,8 +46,6 @@
extern void sem_exit (void);
extern struct task_struct *child_reaper;
-int getrusage(struct task_struct *, int, struct rusage __user *);
-
static void exit_mm(struct task_struct * tsk);
static void __unhash_process(struct task_struct *p)
@@ -579,7 +578,7 @@ static void exit_mm(struct task_struct * tsk)
down_read(&mm->mmap_sem);
}
atomic_inc(&mm->mm_count);
- if (mm != tsk->active_mm) BUG();
+ BUG_ON(mm != tsk->active_mm);
/* more a memory barrier than a real lock */
task_lock(tsk);
tsk->mm = NULL;
@@ -895,11 +894,11 @@ fastcall NORET_TYPE void do_exit(long code)
if (group_dead) {
hrtimer_cancel(&tsk->signal->real_timer);
exit_itimers(tsk->signal);
- acct_process(code);
}
+ acct_collect(code, group_dead);
if (unlikely(tsk->robust_list))
exit_robust_list(tsk);
-#ifdef CONFIG_COMPAT
+#if defined(CONFIG_FUTEX) && defined(CONFIG_COMPAT)
if (unlikely(tsk->compat_robust_list))
compat_exit_robust_list(tsk);
#endif
@@ -907,6 +906,8 @@ fastcall NORET_TYPE void do_exit(long code)
audit_free(tsk);
exit_mm(tsk);
+ if (group_dead)
+ acct_process();
exit_sem(tsk);
__exit_files(tsk);
__exit_fs(tsk);
@@ -1530,8 +1531,7 @@ check_continued:
if (options & __WNOTHREAD)
break;
tsk = next_thread(tsk);
- if (tsk->signal != current->signal)
- BUG();
+ BUG_ON(tsk->signal != current->signal);
} while (tsk != current);
read_unlock(&tasklist_lock);
diff --git a/kernel/fork.c b/kernel/fork.c
index ac8100e..dfd10cb 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -368,6 +368,8 @@ void fastcall __mmdrop(struct mm_struct *mm)
*/
void mmput(struct mm_struct *mm)
{
+ might_sleep();
+
if (atomic_dec_and_test(&mm->mm_users)) {
exit_aio(mm);
exit_mmap(mm);
@@ -623,6 +625,7 @@ out:
/*
* Allocate a new files structure and copy contents from the
* passed in files structure.
+ * errorp will be valid only when the returned files_struct is NULL.
*/
static struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
{
@@ -631,6 +634,7 @@ static struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
int open_files, size, i, expand;
struct fdtable *old_fdt, *new_fdt;
+ *errorp = -ENOMEM;
newf = alloc_files();
if (!newf)
goto out;
@@ -744,7 +748,6 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk)
* break this.
*/
tsk->files = NULL;
- error = -ENOMEM;
newf = dup_fd(oldf, &error);
if (!newf)
goto out;
@@ -871,6 +874,7 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts
tsk->it_prof_expires =
secs_to_cputime(sig->rlim[RLIMIT_CPU].rlim_cur);
}
+ acct_init_pacct(&sig->pacct);
return 0;
}
diff --git a/kernel/futex.c b/kernel/futex.c
index 5699c51..e1a380c 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -1056,11 +1056,11 @@ asmlinkage long sys_futex(u32 __user *uaddr, int op, int val,
(unsigned long)uaddr2, val2, val3);
}
-static struct super_block *
-futexfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int futexfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data,
+ struct vfsmount *mnt)
{
- return get_sb_pseudo(fs_type, "futex", NULL, 0xBAD1DEA);
+ return get_sb_pseudo(fs_type, "futex", NULL, 0xBAD1DEA, mnt);
}
static struct file_system_type futex_fs_type = {
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 1832430..55601b3 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -98,7 +98,6 @@ static DEFINE_PER_CPU(struct hrtimer_base, hrtimer_bases[MAX_HRTIMER_BASES]) =
/**
* ktime_get_ts - get the monotonic clock in timespec format
- *
* @ts: pointer to timespec variable
*
* The function calculates the monotonic clock from the realtime
@@ -238,7 +237,6 @@ lock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags)
# ifndef CONFIG_KTIME_SCALAR
/**
* ktime_add_ns - Add a scalar nanoseconds value to a ktime_t variable
- *
* @kt: addend
* @nsec: the scalar nsec value to add
*
@@ -299,7 +297,6 @@ void unlock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags)
/**
* hrtimer_forward - forward the timer expiry
- *
* @timer: hrtimer to forward
* @now: forward past this time
* @interval: the interval to forward
@@ -411,7 +408,6 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_base *base)
/**
* hrtimer_start - (re)start an relative timer on the current CPU
- *
* @timer: the timer to be added
* @tim: expiry time
* @mode: expiry mode: absolute (HRTIMER_ABS) or relative (HRTIMER_REL)
@@ -460,14 +456,13 @@ EXPORT_SYMBOL_GPL(hrtimer_start);
/**
* hrtimer_try_to_cancel - try to deactivate a timer
- *
* @timer: hrtimer to stop
*
* Returns:
* 0 when the timer was not active
* 1 when the timer was active
* -1 when the timer is currently excuting the callback function and
- * can not be stopped
+ * cannot be stopped
*/
int hrtimer_try_to_cancel(struct hrtimer *timer)
{
@@ -489,7 +484,6 @@ EXPORT_SYMBOL_GPL(hrtimer_try_to_cancel);
/**
* hrtimer_cancel - cancel a timer and wait for the handler to finish.
- *
* @timer: the timer to be cancelled
*
* Returns:
@@ -510,7 +504,6 @@ EXPORT_SYMBOL_GPL(hrtimer_cancel);
/**
* hrtimer_get_remaining - get remaining time for the timer
- *
* @timer: the timer to read
*/
ktime_t hrtimer_get_remaining(const struct hrtimer *timer)
@@ -564,7 +557,6 @@ ktime_t hrtimer_get_next_event(void)
/**
* hrtimer_init - initialize a timer to the given clock
- *
* @timer: the timer to be initialized
* @clock_id: the clock to be used
* @mode: timer mode abs/rel
@@ -576,7 +568,7 @@ void hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
memset(timer, 0, sizeof(struct hrtimer));
- bases = per_cpu(hrtimer_bases, raw_smp_processor_id());
+ bases = __raw_get_cpu_var(hrtimer_bases);
if (clock_id == CLOCK_REALTIME && mode != HRTIMER_ABS)
clock_id = CLOCK_MONOTONIC;
@@ -588,7 +580,6 @@ EXPORT_SYMBOL_GPL(hrtimer_init);
/**
* hrtimer_get_res - get the timer resolution for a clock
- *
* @which_clock: which clock to query
* @tp: pointer to timespec variable to store the resolution
*
@@ -599,7 +590,7 @@ int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp)
{
struct hrtimer_base *bases;
- bases = per_cpu(hrtimer_bases, raw_smp_processor_id());
+ bases = __raw_get_cpu_var(hrtimer_bases);
*tp = ktime_to_timespec(bases[which_clock].resolution);
return 0;
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index 51df337..0f65301 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -76,10 +76,11 @@ irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs)
/*
* Have got an event to handle:
*/
-fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
+fastcall irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
struct irqaction *action)
{
- int ret, retval = 0, status = 0;
+ irqreturn_t ret, retval = IRQ_NONE;
+ unsigned int status = 0;
if (!(action->flags & SA_INTERRUPT))
local_irq_enable();
diff --git a/kernel/irq/migration.c b/kernel/irq/migration.c
index 134f9f2..a12d00e 100644
--- a/kernel/irq/migration.c
+++ b/kernel/irq/migration.c
@@ -30,7 +30,7 @@ void move_native_irq(int irq)
desc->move_irq = 0;
- if (likely(cpus_empty(pending_irq_cpumask[irq])))
+ if (unlikely(cpus_empty(pending_irq_cpumask[irq])))
return;
if (!desc->handler->set_affinity)
@@ -49,7 +49,7 @@ void move_native_irq(int irq)
* cause some ioapics to mal-function.
* Being paranoid i guess!
*/
- if (unlikely(!cpus_empty(tmp))) {
+ if (likely(!cpus_empty(tmp))) {
if (likely(!(desc->status & IRQ_DISABLED)))
desc->handler->disable(irq);
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index d03b5ee..afacd6f 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -24,6 +24,8 @@ static struct proc_dir_entry *smp_affinity_entry[NR_IRQS];
#ifdef CONFIG_GENERIC_PENDING_IRQ
void proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val)
{
+ set_balance_irq_affinity(irq, mask_val);
+
/*
* Save these away for later use. Re-progam when the
* interrupt is pending
@@ -33,6 +35,7 @@ void proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val)
#else
void proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val)
{
+ set_balance_irq_affinity(irq, mask_val);
irq_affinity[irq] = mask_val;
irq_desc[irq].handler->set_affinity(irq, mask_val);
}
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
index 7df9abd..b2fb3c1 100644
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -11,7 +11,7 @@
#include <linux/kallsyms.h>
#include <linux/interrupt.h>
-static int irqfixup;
+static int irqfixup __read_mostly;
/*
* Recovery handler for misrouted interrupts.
@@ -136,9 +136,9 @@ static void report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t actio
void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret,
struct pt_regs *regs)
{
- if (action_ret != IRQ_HANDLED) {
+ if (unlikely(action_ret != IRQ_HANDLED)) {
desc->irqs_unhandled++;
- if (action_ret != IRQ_NONE)
+ if (unlikely(action_ret != IRQ_NONE))
report_bad_irq(irq, desc, action_ret);
}
@@ -152,11 +152,11 @@ void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret,
}
desc->irq_count++;
- if (desc->irq_count < 100000)
+ if (likely(desc->irq_count < 100000))
return;
desc->irq_count = 0;
- if (desc->irqs_unhandled > 99900) {
+ if (unlikely(desc->irqs_unhandled > 99900)) {
/*
* The interrupt is stuck
*/
@@ -171,7 +171,7 @@ void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret,
desc->irqs_unhandled = 0;
}
-int noirqdebug;
+int noirqdebug __read_mostly;
int __init noirqdebug_setup(char *str)
{
diff --git a/kernel/kexec.c b/kernel/kexec.c
index bf39d28..58f0f38 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -902,14 +902,14 @@ static int kimage_load_segment(struct kimage *image,
* kexec does not sync, or unmount filesystems so if you need
* that to happen you need to do that yourself.
*/
-struct kimage *kexec_image = NULL;
-static struct kimage *kexec_crash_image = NULL;
+struct kimage *kexec_image;
+struct kimage *kexec_crash_image;
/*
* A home grown binary mutex.
* Nothing can wait so this mutex is safe to use
* in interrupt context :)
*/
-static int kexec_lock = 0;
+static int kexec_lock;
asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments,
struct kexec_segment __user *segments,
diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c
index f119e09..9e28478 100644
--- a/kernel/ksysfs.c
+++ b/kernel/ksysfs.c
@@ -14,6 +14,7 @@
#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/kexec.h>
#define KERNEL_ATTR_RO(_name) \
static struct subsys_attribute _name##_attr = __ATTR_RO(_name)
@@ -48,6 +49,20 @@ static ssize_t uevent_helper_store(struct subsystem *subsys, const char *page, s
KERNEL_ATTR_RW(uevent_helper);
#endif
+#ifdef CONFIG_KEXEC
+static ssize_t kexec_loaded_show(struct subsystem *subsys, char *page)
+{
+ return sprintf(page, "%d\n", !!kexec_image);
+}
+KERNEL_ATTR_RO(kexec_loaded);
+
+static ssize_t kexec_crash_loaded_show(struct subsystem *subsys, char *page)
+{
+ return sprintf(page, "%d\n", !!kexec_crash_image);
+}
+KERNEL_ATTR_RO(kexec_crash_loaded);
+#endif /* CONFIG_KEXEC */
+
decl_subsys(kernel, NULL, NULL);
EXPORT_SYMBOL_GPL(kernel_subsys);
@@ -56,6 +71,10 @@ static struct attribute * kernel_attrs[] = {
&uevent_seqnum_attr.attr,
&uevent_helper_attr.attr,
#endif
+#ifdef CONFIG_KEXEC
+ &kexec_loaded_attr.attr,
+ &kexec_crash_loaded_attr.attr,
+#endif
NULL
};
diff --git a/kernel/kthread.c b/kernel/kthread.c
index c5f3c66..24be714 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -45,6 +45,13 @@ struct kthread_stop_info
static DEFINE_MUTEX(kthread_stop_lock);
static struct kthread_stop_info kthread_stop_info;
+/**
+ * kthread_should_stop - should this kthread return now?
+ *
+ * When someone calls kthread_stop on your kthread, it will be woken
+ * and this will return true. You should then return, and your return
+ * value will be passed through to kthread_stop().
+ */
int kthread_should_stop(void)
{
return (kthread_stop_info.k == current);
@@ -122,6 +129,25 @@ static void keventd_create_kthread(void *_create)
complete(&create->done);
}
+/**
+ * kthread_create - create a kthread.
+ * @threadfn: the function to run until signal_pending(current).
+ * @data: data ptr for @threadfn.
+ * @namefmt: printf-style name for the thread.
+ *
+ * Description: This helper function creates and names a kernel
+ * thread. The thread will be stopped: use wake_up_process() to start
+ * it. See also kthread_run(), kthread_create_on_cpu().
+ *
+ * When woken, the thread will run @threadfn() with @data as its
+ * argument. @threadfn can either call do_exit() directly if it is a
+ * standalone thread for which noone will call kthread_stop(), or
+ * return when 'kthread_should_stop()' is true (which means
+ * kthread_stop() has been called). The return value should be zero
+ * or a negative error number; it will be passed to kthread_stop().
+ *
+ * Returns a task_struct or ERR_PTR(-ENOMEM).
+ */
struct task_struct *kthread_create(int (*threadfn)(void *data),
void *data,
const char namefmt[],
@@ -156,6 +182,15 @@ struct task_struct *kthread_create(int (*threadfn)(void *data),
}
EXPORT_SYMBOL(kthread_create);
+/**
+ * kthread_bind - bind a just-created kthread to a cpu.
+ * @k: thread created by kthread_create().
+ * @cpu: cpu (might not be online, must be possible) for @k to run on.
+ *
+ * Description: This function is equivalent to set_cpus_allowed(),
+ * except that @cpu doesn't need to be online, and the thread must be
+ * stopped (i.e., just returned from kthread_create().
+ */
void kthread_bind(struct task_struct *k, unsigned int cpu)
{
BUG_ON(k->state != TASK_INTERRUPTIBLE);
@@ -166,12 +201,36 @@ void kthread_bind(struct task_struct *k, unsigned int cpu)
}
EXPORT_SYMBOL(kthread_bind);
+/**
+ * kthread_stop - stop a thread created by kthread_create().
+ * @k: thread created by kthread_create().
+ *
+ * Sets kthread_should_stop() for @k to return true, wakes it, and
+ * waits for it to exit. Your threadfn() must not call do_exit()
+ * itself if you use this function! This can also be called after
+ * kthread_create() instead of calling wake_up_process(): the thread
+ * will exit without calling threadfn().
+ *
+ * Returns the result of threadfn(), or %-EINTR if wake_up_process()
+ * was never called.
+ */
int kthread_stop(struct task_struct *k)
{
return kthread_stop_sem(k, NULL);
}
EXPORT_SYMBOL(kthread_stop);
+/**
+ * kthread_stop_sem - stop a thread created by kthread_create().
+ * @k: thread created by kthread_create().
+ * @s: semaphore that @k waits on while idle.
+ *
+ * Does essentially the same thing as kthread_stop() above, but wakes
+ * @k by calling up(@s).
+ *
+ * Returns the result of threadfn(), or %-EINTR if wake_up_process()
+ * was never called.
+ */
int kthread_stop_sem(struct task_struct *k, struct semaphore *s)
{
int ret;
@@ -210,5 +269,5 @@ static __init int helper_init(void)
return 0;
}
-core_initcall(helper_init);
+core_initcall(helper_init);
diff --git a/kernel/module.c b/kernel/module.c
index bbe0486..d75275d 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1326,7 +1326,7 @@ int is_exported(const char *name, const struct module *mod)
if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab))
return 1;
else
- if (lookup_symbol(name, mod->syms, mod->syms + mod->num_syms))
+ if (mod && lookup_symbol(name, mod->syms, mod->syms + mod->num_syms))
return 1;
else
return 0;
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index ce0dfb8..fc311a4 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -36,6 +36,15 @@ config PM_DEBUG
code. This is helpful when debugging and reporting various PM bugs,
like suspend support.
+config PM_TRACE
+ bool "Suspend/resume event tracing"
+ depends on PM && PM_DEBUG && X86_32
+ default y
+ ---help---
+ This enables some cheesy code to save the last PM event point in the
+ RTC across reboots, so that you can debug a machine that just hangs
+ during suspend (or more commonly, during resume).
+
config SOFTWARE_SUSPEND
bool "Software Suspend"
depends on PM && SWAP && (X86 && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP)
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index 81d4d98..e13e740 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -231,7 +231,7 @@ static int software_resume(void)
late_initcall(software_resume);
-static char * pm_disk_modes[] = {
+static const char * const pm_disk_modes[] = {
[PM_DISK_FIRMWARE] = "firmware",
[PM_DISK_PLATFORM] = "platform",
[PM_DISK_SHUTDOWN] = "shutdown",
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 0a907f0..6d295c7 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -15,7 +15,7 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/pm.h>
-
+#include <linux/console.h>
#include "power.h"
@@ -145,7 +145,7 @@ static void suspend_finish(suspend_state_t state)
-static char *pm_states[PM_SUSPEND_MAX] = {
+static const char * const pm_states[PM_SUSPEND_MAX] = {
[PM_SUSPEND_STANDBY] = "standby",
[PM_SUSPEND_MEM] = "mem",
#ifdef CONFIG_SOFTWARE_SUSPEND
@@ -262,7 +262,7 @@ static ssize_t state_show(struct subsystem * subsys, char * buf)
static ssize_t state_store(struct subsystem * subsys, const char * buf, size_t n)
{
suspend_state_t state = PM_SUSPEND_STANDBY;
- char ** s;
+ const char * const *s;
char *p;
int error;
int len;
diff --git a/kernel/power/power.h b/kernel/power/power.h
index f06f12f..98c4142 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -55,7 +55,7 @@ struct snapshot_handle {
unsigned int page;
unsigned int page_offset;
unsigned int prev;
- struct pbe *pbe;
+ struct pbe *pbe, *last_pbe;
void *buffer;
unsigned int buf_offset;
};
@@ -105,6 +105,10 @@ extern struct bitmap_page *alloc_bitmap(unsigned int nr_bits);
extern unsigned long alloc_swap_page(int swap, struct bitmap_page *bitmap);
extern void free_all_swap_pages(int swap, struct bitmap_page *bitmap);
+extern unsigned int count_special_pages(void);
+extern int save_special_mem(void);
+extern int restore_special_mem(void);
+
extern int swsusp_check(void);
extern int swsusp_shrink_memory(void);
extern void swsusp_free(void);
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 3eeedbb..3d92841 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -39,8 +39,90 @@ static unsigned int nr_copy_pages;
static unsigned int nr_meta_pages;
static unsigned long *buffer;
+struct arch_saveable_page {
+ unsigned long start;
+ unsigned long end;
+ char *data;
+ struct arch_saveable_page *next;
+};
+static struct arch_saveable_page *arch_pages;
+
+int swsusp_add_arch_pages(unsigned long start, unsigned long end)
+{
+ struct arch_saveable_page *tmp;
+
+ while (start < end) {
+ tmp = kzalloc(sizeof(struct arch_saveable_page), GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+ tmp->start = start;
+ tmp->end = ((start >> PAGE_SHIFT) + 1) << PAGE_SHIFT;
+ if (tmp->end > end)
+ tmp->end = end;
+ tmp->next = arch_pages;
+ start = tmp->end;
+ arch_pages = tmp;
+ }
+ return 0;
+}
+
+static unsigned int count_arch_pages(void)
+{
+ unsigned int count = 0;
+ struct arch_saveable_page *tmp = arch_pages;
+ while (tmp) {
+ count++;
+ tmp = tmp->next;
+ }
+ return count;
+}
+
+static int save_arch_mem(void)
+{
+ char *kaddr;
+ struct arch_saveable_page *tmp = arch_pages;
+ int offset;
+
+ pr_debug("swsusp: Saving arch specific memory");
+ while (tmp) {
+ tmp->data = (char *)__get_free_page(GFP_ATOMIC);
+ if (!tmp->data)
+ return -ENOMEM;
+ offset = tmp->start - (tmp->start & PAGE_MASK);
+ /* arch pages might haven't a 'struct page' */
+ kaddr = kmap_atomic_pfn(tmp->start >> PAGE_SHIFT, KM_USER0);
+ memcpy(tmp->data + offset, kaddr + offset,
+ tmp->end - tmp->start);
+ kunmap_atomic(kaddr, KM_USER0);
+
+ tmp = tmp->next;
+ }
+ return 0;
+}
+
+static int restore_arch_mem(void)
+{
+ char *kaddr;
+ struct arch_saveable_page *tmp = arch_pages;
+ int offset;
+
+ while (tmp) {
+ if (!tmp->data)
+ continue;
+ offset = tmp->start - (tmp->start & PAGE_MASK);
+ kaddr = kmap_atomic_pfn(tmp->start >> PAGE_SHIFT, KM_USER0);
+ memcpy(kaddr + offset, tmp->data + offset,
+ tmp->end - tmp->start);
+ kunmap_atomic(kaddr, KM_USER0);
+ free_page((long)tmp->data);
+ tmp->data = NULL;
+ tmp = tmp->next;
+ }
+ return 0;
+}
+
#ifdef CONFIG_HIGHMEM
-unsigned int count_highmem_pages(void)
+static unsigned int count_highmem_pages(void)
{
struct zone *zone;
unsigned long zone_pfn;
@@ -117,7 +199,7 @@ static int save_highmem_zone(struct zone *zone)
return 0;
}
-int save_highmem(void)
+static int save_highmem(void)
{
struct zone *zone;
int res = 0;
@@ -134,7 +216,7 @@ int save_highmem(void)
return 0;
}
-int restore_highmem(void)
+static int restore_highmem(void)
{
printk("swsusp: Restoring Highmem\n");
while (highmem_copy) {
@@ -150,8 +232,35 @@ int restore_highmem(void)
}
return 0;
}
+#else
+static inline unsigned int count_highmem_pages(void) {return 0;}
+static inline int save_highmem(void) {return 0;}
+static inline int restore_highmem(void) {return 0;}
#endif
+unsigned int count_special_pages(void)
+{
+ return count_arch_pages() + count_highmem_pages();
+}
+
+int save_special_mem(void)
+{
+ int ret;
+ ret = save_arch_mem();
+ if (!ret)
+ ret = save_highmem();
+ return ret;
+}
+
+int restore_special_mem(void)
+{
+ int ret;
+ ret = restore_arch_mem();
+ if (!ret)
+ ret = restore_highmem();
+ return ret;
+}
+
static int pfn_is_nosave(unsigned long pfn)
{
unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT;
@@ -177,7 +286,6 @@ static int saveable(struct zone *zone, unsigned long *zone_pfn)
return 0;
page = pfn_to_page(pfn);
- BUG_ON(PageReserved(page) && PageNosave(page));
if (PageNosave(page))
return 0;
if (PageReserved(page) && pfn_is_nosave(pfn))
@@ -293,62 +401,29 @@ static inline void create_pbe_list(struct pbe *pblist, unsigned int nr_pages)
}
}
-/**
- * On resume it is necessary to trace and eventually free the unsafe
- * pages that have been allocated, because they are needed for I/O
- * (on x86-64 we likely will "eat" these pages once again while
- * creating the temporary page translation tables)
- */
-
-struct eaten_page {
- struct eaten_page *next;
- char padding[PAGE_SIZE - sizeof(void *)];
-};
-
-static struct eaten_page *eaten_pages = NULL;
-
-static void release_eaten_pages(void)
-{
- struct eaten_page *p, *q;
-
- p = eaten_pages;
- while (p) {
- q = p->next;
- /* We don't want swsusp_free() to free this page again */
- ClearPageNosave(virt_to_page(p));
- free_page((unsigned long)p);
- p = q;
- }
- eaten_pages = NULL;
-}
+static unsigned int unsafe_pages;
/**
* @safe_needed - on resume, for storing the PBE list and the image,
* we can only use memory pages that do not conflict with the pages
- * which had been used before suspend.
+ * used before suspend.
*
* The unsafe pages are marked with the PG_nosave_free flag
- *
- * Allocated but unusable (ie eaten) memory pages should be marked
- * so that swsusp_free() can release them
+ * and we count them using unsafe_pages
*/
static inline void *alloc_image_page(gfp_t gfp_mask, int safe_needed)
{
void *res;
+ res = (void *)get_zeroed_page(gfp_mask);
if (safe_needed)
- do {
+ while (res && PageNosaveFree(virt_to_page(res))) {
+ /* The page is unsafe, mark it for swsusp_free() */
+ SetPageNosave(virt_to_page(res));
+ unsafe_pages++;
res = (void *)get_zeroed_page(gfp_mask);
- if (res && PageNosaveFree(virt_to_page(res))) {
- /* This is for swsusp_free() */
- SetPageNosave(virt_to_page(res));
- ((struct eaten_page *)res)->next = eaten_pages;
- eaten_pages = res;
- }
- } while (res && PageNosaveFree(virt_to_page(res)));
- else
- res = (void *)get_zeroed_page(gfp_mask);
+ }
if (res) {
SetPageNosave(virt_to_page(res));
SetPageNosaveFree(virt_to_page(res));
@@ -374,7 +449,8 @@ unsigned long get_safe_page(gfp_t gfp_mask)
* On each page we set up a list of struct_pbe elements.
*/
-struct pbe *alloc_pagedir(unsigned int nr_pages, gfp_t gfp_mask, int safe_needed)
+static struct pbe *alloc_pagedir(unsigned int nr_pages, gfp_t gfp_mask,
+ int safe_needed)
{
unsigned int num;
struct pbe *pblist, *pbe;
@@ -642,6 +718,8 @@ static int mark_unsafe_pages(struct pbe *pblist)
return -EFAULT;
}
+ unsafe_pages = 0;
+
return 0;
}
@@ -719,42 +797,99 @@ static inline struct pbe *unpack_orig_addresses(unsigned long *buf,
}
/**
- * create_image - use metadata contained in the PBE list
+ * prepare_image - use metadata contained in the PBE list
* pointed to by pagedir_nosave to mark the pages that will
* be overwritten in the process of restoring the system
- * memory state from the image and allocate memory for
- * the image avoiding these pages
+ * memory state from the image ("unsafe" pages) and allocate
+ * memory for the image
+ *
+ * The idea is to allocate the PBE list first and then
+ * allocate as many pages as it's needed for the image data,
+ * but not to assign these pages to the PBEs initially.
+ * Instead, we just mark them as allocated and create a list
+ * of "safe" which will be used later
*/
-static int create_image(struct snapshot_handle *handle)
+struct safe_page {
+ struct safe_page *next;
+ char padding[PAGE_SIZE - sizeof(void *)];
+};
+
+static struct safe_page *safe_pages;
+
+static int prepare_image(struct snapshot_handle *handle)
{
int error = 0;
- struct pbe *p, *pblist;
+ unsigned int nr_pages = nr_copy_pages;
+ struct pbe *p, *pblist = NULL;
p = pagedir_nosave;
error = mark_unsafe_pages(p);
if (!error) {
- pblist = alloc_pagedir(nr_copy_pages, GFP_ATOMIC, 1);
+ pblist = alloc_pagedir(nr_pages, GFP_ATOMIC, 1);
if (pblist)
copy_page_backup_list(pblist, p);
free_pagedir(p, 0);
if (!pblist)
error = -ENOMEM;
}
- if (!error)
- error = alloc_data_pages(pblist, GFP_ATOMIC, 1);
+ safe_pages = NULL;
+ if (!error && nr_pages > unsafe_pages) {
+ nr_pages -= unsafe_pages;
+ while (nr_pages--) {
+ struct safe_page *ptr;
+
+ ptr = (struct safe_page *)get_zeroed_page(GFP_ATOMIC);
+ if (!ptr) {
+ error = -ENOMEM;
+ break;
+ }
+ if (!PageNosaveFree(virt_to_page(ptr))) {
+ /* The page is "safe", add it to the list */
+ ptr->next = safe_pages;
+ safe_pages = ptr;
+ }
+ /* Mark the page as allocated */
+ SetPageNosave(virt_to_page(ptr));
+ SetPageNosaveFree(virt_to_page(ptr));
+ }
+ }
if (!error) {
- release_eaten_pages();
pagedir_nosave = pblist;
} else {
- pagedir_nosave = NULL;
handle->pbe = NULL;
- nr_copy_pages = 0;
- nr_meta_pages = 0;
+ swsusp_free();
}
return error;
}
+static void *get_buffer(struct snapshot_handle *handle)
+{
+ struct pbe *pbe = handle->pbe, *last = handle->last_pbe;
+ struct page *page = virt_to_page(pbe->orig_address);
+
+ if (PageNosave(page) && PageNosaveFree(page)) {
+ /*
+ * We have allocated the "original" page frame and we can
+ * use it directly to store the read page
+ */
+ pbe->address = 0;
+ if (last && last->next)
+ last->next = NULL;
+ return (void *)pbe->orig_address;
+ }
+ /*
+ * The "original" page frame has not been allocated and we have to
+ * use a "safe" page frame to store the read page
+ */
+ pbe->address = (unsigned long)safe_pages;
+ safe_pages = safe_pages->next;
+ if (last)
+ last->next = pbe;
+ handle->last_pbe = pbe;
+ return (void *)pbe->address;
+}
+
/**
* snapshot_write_next - used for writing the system memory snapshot.
*
@@ -799,15 +934,16 @@ int snapshot_write_next(struct snapshot_handle *handle, size_t count)
} else if (handle->prev <= nr_meta_pages) {
handle->pbe = unpack_orig_addresses(buffer, handle->pbe);
if (!handle->pbe) {
- error = create_image(handle);
+ error = prepare_image(handle);
if (error)
return error;
handle->pbe = pagedir_nosave;
- handle->buffer = (void *)handle->pbe->address;
+ handle->last_pbe = NULL;
+ handle->buffer = get_buffer(handle);
}
} else {
handle->pbe = handle->pbe->next;
- handle->buffer = (void *)handle->pbe->address;
+ handle->buffer = get_buffer(handle);
}
handle->prev = handle->page;
}
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index c4016cb..f0ee4e7 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -62,16 +62,6 @@ unsigned long image_size = 500 * 1024 * 1024;
int in_suspend __nosavedata = 0;
-#ifdef CONFIG_HIGHMEM
-unsigned int count_highmem_pages(void);
-int save_highmem(void);
-int restore_highmem(void);
-#else
-static int save_highmem(void) { return 0; }
-static int restore_highmem(void) { return 0; }
-static unsigned int count_highmem_pages(void) { return 0; }
-#endif
-
/**
* The following functions are used for tracing the allocated
* swap pages, so that they can be freed in case of an error.
@@ -175,6 +165,12 @@ void free_all_swap_pages(int swap, struct bitmap_page *bitmap)
*/
#define SHRINK_BITE 10000
+static inline unsigned long __shrink_memory(long tmp)
+{
+ if (tmp > SHRINK_BITE)
+ tmp = SHRINK_BITE;
+ return shrink_all_memory(tmp);
+}
int swsusp_shrink_memory(void)
{
@@ -186,21 +182,23 @@ int swsusp_shrink_memory(void)
printk("Shrinking memory... ");
do {
- size = 2 * count_highmem_pages();
+ size = 2 * count_special_pages();
size += size / 50 + count_data_pages();
size += (size + PBES_PER_PAGE - 1) / PBES_PER_PAGE +
PAGES_FOR_IO;
tmp = size;
for_each_zone (zone)
- if (!is_highmem(zone))
+ if (!is_highmem(zone) && populated_zone(zone)) {
tmp -= zone->free_pages;
+ tmp += zone->lowmem_reserve[ZONE_NORMAL];
+ }
if (tmp > 0) {
- tmp = shrink_all_memory(SHRINK_BITE);
+ tmp = __shrink_memory(tmp);
if (!tmp)
return -ENOMEM;
pages += tmp;
} else if (size > image_size / PAGE_SIZE) {
- tmp = shrink_all_memory(SHRINK_BITE);
+ tmp = __shrink_memory(size - (image_size / PAGE_SIZE));
pages += tmp;
}
printk("\b%c", p[i++%4]);
@@ -228,7 +226,7 @@ int swsusp_suspend(void)
goto Enable_irqs;
}
- if ((error = save_highmem())) {
+ if ((error = save_special_mem())) {
printk(KERN_ERR "swsusp: Not enough free pages for highmem\n");
goto Restore_highmem;
}
@@ -239,7 +237,7 @@ int swsusp_suspend(void)
/* Restore control flow magically appears here */
restore_processor_state();
Restore_highmem:
- restore_highmem();
+ restore_special_mem();
device_power_up();
Enable_irqs:
local_irq_enable();
@@ -265,7 +263,7 @@ int swsusp_resume(void)
*/
swsusp_free();
restore_processor_state();
- restore_highmem();
+ restore_special_mem();
touch_softlockup_watchdog();
device_power_up();
local_irq_enable();
diff --git a/kernel/printk.c b/kernel/printk.c
index 19a9556..95b7fe1 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -24,6 +24,7 @@
#include <linux/console.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/interrupt.h> /* For in_interrupt() */
#include <linux/config.h>
#include <linux/delay.h>
@@ -327,7 +328,9 @@ static void __call_console_drivers(unsigned long start, unsigned long end)
struct console *con;
for (con = console_drivers; con; con = con->next) {
- if ((con->flags & CON_ENABLED) && con->write)
+ if ((con->flags & CON_ENABLED) && con->write &&
+ (cpu_online(smp_processor_id()) ||
+ (con->flags & CON_ANYTIME)))
con->write(con, &LOG_BUF(start), end - start);
}
}
@@ -437,6 +440,7 @@ static int printk_time = 1;
#else
static int printk_time = 0;
#endif
+module_param(printk_time, int, S_IRUGO | S_IWUSR);
static int __init printk_time_setup(char *str)
{
@@ -453,6 +457,18 @@ __attribute__((weak)) unsigned long long printk_clock(void)
return sched_clock();
}
+/* Check if we have any console registered that can be called early in boot. */
+static int have_callable_console(void)
+{
+ struct console *con;
+
+ for (con = console_drivers; con; con = con->next)
+ if (con->flags & CON_ANYTIME)
+ return 1;
+
+ return 0;
+}
+
/**
* printk - print a kernel message
* @fmt: format string
@@ -566,27 +582,29 @@ asmlinkage int vprintk(const char *fmt, va_list args)
log_level_unknown = 1;
}
- if (!cpu_online(smp_processor_id())) {
+ if (!down_trylock(&console_sem)) {
/*
- * Some console drivers may assume that per-cpu resources have
- * been allocated. So don't allow them to be called by this
- * CPU until it is officially up. We shouldn't be calling into
- * random console drivers on a CPU which doesn't exist yet..
+ * We own the drivers. We can drop the spinlock and
+ * let release_console_sem() print the text, maybe ...
*/
+ console_locked = 1;
printk_cpu = UINT_MAX;
spin_unlock_irqrestore(&logbuf_lock, flags);
- goto out;
- }
- if (!down_trylock(&console_sem)) {
- console_locked = 1;
+
/*
- * We own the drivers. We can drop the spinlock and let
- * release_console_sem() print the text
+ * Console drivers may assume that per-cpu resources have
+ * been allocated. So unless they're explicitly marked as
+ * being able to cope (CON_ANYTIME) don't call them until
+ * this CPU is officially up.
*/
- printk_cpu = UINT_MAX;
- spin_unlock_irqrestore(&logbuf_lock, flags);
- console_may_schedule = 0;
- release_console_sem();
+ if (cpu_online(smp_processor_id()) || have_callable_console()) {
+ console_may_schedule = 0;
+ release_console_sem();
+ } else {
+ /* Release by hand to avoid flushing the buffer. */
+ console_locked = 0;
+ up(&console_sem);
+ }
} else {
/*
* Someone else owns the drivers. We drop the spinlock, which
@@ -596,7 +614,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
printk_cpu = UINT_MAX;
spin_unlock_irqrestore(&logbuf_lock, flags);
}
-out:
+
preempt_enable();
return printed_len;
}
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index 2058f88..20e9710 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -612,14 +612,6 @@ void synchronize_rcu(void)
wait_for_completion(&rcu.completion);
}
-/*
- * Deprecated, use synchronize_rcu() or synchronize_sched() instead.
- */
-void synchronize_kernel(void)
-{
- synchronize_rcu();
-}
-
module_param(blimit, int, 0);
module_param(qhimark, int, 0);
module_param(qlowmark, int, 0);
@@ -627,7 +619,6 @@ module_param(qlowmark, int, 0);
module_param(rsinterval, int, 0);
#endif
EXPORT_SYMBOL_GPL(rcu_batches_completed);
-EXPORT_SYMBOL_GPL_FUTURE(call_rcu); /* WARNING: GPL-only in April 2006. */
-EXPORT_SYMBOL_GPL_FUTURE(call_rcu_bh); /* WARNING: GPL-only in April 2006. */
+EXPORT_SYMBOL_GPL(call_rcu);
+EXPORT_SYMBOL_GPL(call_rcu_bh);
EXPORT_SYMBOL_GPL(synchronize_rcu);
-EXPORT_SYMBOL_GPL_FUTURE(synchronize_kernel); /* WARNING: GPL-only in April 2006. */
diff --git a/kernel/sched.c b/kernel/sched.c
index c13f1bd..f06d059 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -3886,6 +3886,10 @@ long sched_setaffinity(pid_t pid, cpumask_t new_mask)
!capable(CAP_SYS_NICE))
goto out_unlock;
+ retval = security_task_setscheduler(p, 0, NULL);
+ if (retval)
+ goto out_unlock;
+
cpus_allowed = cpuset_cpus_allowed(p);
cpus_and(new_mask, new_mask, cpus_allowed);
retval = set_cpus_allowed(p, new_mask);
@@ -3954,7 +3958,10 @@ long sched_getaffinity(pid_t pid, cpumask_t *mask)
if (!p)
goto out_unlock;
- retval = 0;
+ retval = security_task_getscheduler(p);
+ if (retval)
+ goto out_unlock;
+
cpus_and(*mask, p->cpus_allowed, cpu_online_map);
out_unlock:
@@ -4046,6 +4053,9 @@ asmlinkage long sys_sched_yield(void)
static inline void __cond_resched(void)
{
+#ifdef CONFIG_DEBUG_SPINLOCK_SLEEP
+ __might_sleep(__FILE__, __LINE__);
+#endif
/*
* The BKS might be reacquired before we have dropped
* PREEMPT_ACTIVE, which could trigger a second
@@ -4142,7 +4152,7 @@ EXPORT_SYMBOL(yield);
*/
void __sched io_schedule(void)
{
- struct runqueue *rq = &per_cpu(runqueues, raw_smp_processor_id());
+ struct runqueue *rq = &__raw_get_cpu_var(runqueues);
atomic_inc(&rq->nr_iowait);
schedule();
@@ -4153,7 +4163,7 @@ EXPORT_SYMBOL(io_schedule);
long __sched io_schedule_timeout(long timeout)
{
- struct runqueue *rq = &per_cpu(runqueues, raw_smp_processor_id());
+ struct runqueue *rq = &__raw_get_cpu_var(runqueues);
long ret;
atomic_inc(&rq->nr_iowait);
@@ -4746,6 +4756,8 @@ static int migration_call(struct notifier_block *nfb, unsigned long action,
break;
#ifdef CONFIG_HOTPLUG_CPU
case CPU_UP_CANCELED:
+ if (!cpu_rq(cpu)->migration_thread)
+ break;
/* Unbind it from offline cpu so it can run. Fall thru. */
kthread_bind(cpu_rq(cpu)->migration_thread,
any_online_cpu(cpu_online_map));
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 336f92d..9e2f1c6 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -470,6 +470,8 @@ static int cpu_callback(struct notifier_block *nfb,
break;
#ifdef CONFIG_HOTPLUG_CPU
case CPU_UP_CANCELED:
+ if (!per_cpu(ksoftirqd, hotcpu))
+ break;
/* Unbind so it can run. Fall thru. */
kthread_bind(per_cpu(ksoftirqd, hotcpu),
any_online_cpu(cpu_online_map));
diff --git a/kernel/softlockup.c b/kernel/softlockup.c
index 14c7faf..b5c3b94 100644
--- a/kernel/softlockup.c
+++ b/kernel/softlockup.c
@@ -36,7 +36,7 @@ static struct notifier_block panic_block = {
void touch_softlockup_watchdog(void)
{
- per_cpu(touch_timestamp, raw_smp_processor_id()) = jiffies;
+ __raw_get_cpu_var(touch_timestamp) = jiffies;
}
EXPORT_SYMBOL(touch_softlockup_watchdog);
@@ -127,6 +127,8 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
break;
#ifdef CONFIG_HOTPLUG_CPU
case CPU_UP_CANCELED:
+ if (!per_cpu(watchdog_task, hotcpu))
+ break;
/* Unbind so it can run. Fall thru. */
kthread_bind(per_cpu(watchdog_task, hotcpu),
any_online_cpu(cpu_online_map));
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index dcfb5d7..2c0aacc 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -4,6 +4,7 @@
#include <linux/cpu.h>
#include <linux/err.h>
#include <linux/syscalls.h>
+#include <linux/kthread.h>
#include <asm/atomic.h>
#include <asm/semaphore.h>
#include <asm/uaccess.h>
@@ -25,13 +26,11 @@ static unsigned int stopmachine_num_threads;
static atomic_t stopmachine_thread_ack;
static DECLARE_MUTEX(stopmachine_mutex);
-static int stopmachine(void *cpu)
+static int stopmachine(void *unused)
{
int irqs_disabled = 0;
int prepared = 0;
- set_cpus_allowed(current, cpumask_of_cpu((int)(long)cpu));
-
/* Ack: we are alive */
smp_mb(); /* Theoretically the ack = 0 might not be on this CPU yet. */
atomic_inc(&stopmachine_thread_ack);
@@ -85,7 +84,8 @@ static void stopmachine_set_state(enum stopmachine_state state)
static int stop_machine(void)
{
- int i, ret = 0;
+ int ret = 0;
+ unsigned int i;
struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
/* One high-prio thread per cpu. We'll do this one. */
@@ -96,11 +96,16 @@ static int stop_machine(void)
stopmachine_state = STOPMACHINE_WAIT;
for_each_online_cpu(i) {
+ struct task_struct *tsk;
if (i == raw_smp_processor_id())
continue;
- ret = kernel_thread(stopmachine, (void *)(long)i,CLONE_KERNEL);
- if (ret < 0)
+ tsk = kthread_create(stopmachine, NULL, "stopmachine");
+ if (IS_ERR(tsk)) {
+ ret = PTR_ERR(tsk);
break;
+ }
+ kthread_bind(tsk, i);
+ wake_up_process(tsk);
stopmachine_num_threads++;
}
diff --git a/kernel/sys.c b/kernel/sys.c
index 0b6ec0e..2d5179c 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -13,7 +13,6 @@
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/prctl.h>
-#include <linux/init.h>
#include <linux/highuid.h>
#include <linux/fs.h>
#include <linux/kernel.h>
@@ -57,6 +56,12 @@
#ifndef GET_FPEXC_CTL
# define GET_FPEXC_CTL(a,b) (-EINVAL)
#endif
+#ifndef GET_ENDIAN
+# define GET_ENDIAN(a,b) (-EINVAL)
+#endif
+#ifndef SET_ENDIAN
+# define SET_ENDIAN(a,b) (-EINVAL)
+#endif
/*
* this is where the system-wide overflow UID and GID are defined, for
@@ -132,14 +137,15 @@ static int __kprobes notifier_call_chain(struct notifier_block **nl,
unsigned long val, void *v)
{
int ret = NOTIFY_DONE;
- struct notifier_block *nb;
+ struct notifier_block *nb, *next_nb;
nb = rcu_dereference(*nl);
while (nb) {
+ next_nb = rcu_dereference(nb->next);
ret = nb->notifier_call(nb, val, v);
if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)
break;
- nb = rcu_dereference(nb->next);
+ nb = next_nb;
}
return ret;
}
@@ -583,7 +589,7 @@ void emergency_restart(void)
}
EXPORT_SYMBOL_GPL(emergency_restart);
-void kernel_restart_prepare(char *cmd)
+static void kernel_restart_prepare(char *cmd)
{
blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
system_state = SYSTEM_RESTART;
@@ -617,7 +623,7 @@ EXPORT_SYMBOL_GPL(kernel_restart);
* Move into place and start executing a preloaded standalone
* executable. If nothing was preloaded return an error.
*/
-void kernel_kexec(void)
+static void kernel_kexec(void)
{
#ifdef CONFIG_KEXEC
struct kimage *image;
@@ -631,7 +637,6 @@ void kernel_kexec(void)
machine_kexec(image);
#endif
}
-EXPORT_SYMBOL_GPL(kernel_kexec);
void kernel_shutdown_prepare(enum system_states state)
{
@@ -1860,23 +1865,20 @@ out:
* fields when reaping, so a sample either gets all the additions of a
* given child after it's reaped, or none so this sample is before reaping.
*
- * tasklist_lock locking optimisation:
- * If we are current and single threaded, we do not need to take the tasklist
- * lock or the siglock. No one else can take our signal_struct away,
- * no one else can reap the children to update signal->c* counters, and
- * no one else can race with the signal-> fields.
- * If we do not take the tasklist_lock, the signal-> fields could be read
- * out of order while another thread was just exiting. So we place a
- * read memory barrier when we avoid the lock. On the writer side,
- * write memory barrier is implied in __exit_signal as __exit_signal releases
- * the siglock spinlock after updating the signal-> fields.
- *
- * We don't really need the siglock when we access the non c* fields
- * of the signal_struct (for RUSAGE_SELF) even in multithreaded
- * case, since we take the tasklist lock for read and the non c* signal->
- * fields are updated only in __exit_signal, which is called with
- * tasklist_lock taken for write, hence these two threads cannot execute
- * concurrently.
+ * Locking:
+ * We need to take the siglock for CHILDEREN, SELF and BOTH
+ * for the cases current multithreaded, non-current single threaded
+ * non-current multithreaded. Thread traversal is now safe with
+ * the siglock held.
+ * Strictly speaking, we donot need to take the siglock if we are current and
+ * single threaded, as no one else can take our signal_struct away, no one
+ * else can reap the children to update signal->c* counters, and no one else
+ * can race with the signal-> fields. If we do not take any lock, the
+ * signal-> fields could be read out of order while another thread was just
+ * exiting. So we should place a read memory barrier when we avoid the lock.
+ * On the writer side, write memory barrier is implied in __exit_signal
+ * as __exit_signal releases the siglock spinlock after updating the signal->
+ * fields. But we don't do this yet to keep things simple.
*
*/
@@ -1885,35 +1887,25 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
struct task_struct *t;
unsigned long flags;
cputime_t utime, stime;
- int need_lock = 0;
memset((char *) r, 0, sizeof *r);
utime = stime = cputime_zero;
- if (p != current || !thread_group_empty(p))
- need_lock = 1;
-
- if (need_lock) {
- read_lock(&tasklist_lock);
- if (unlikely(!p->signal)) {
- read_unlock(&tasklist_lock);
- return;
- }
- } else
- /* See locking comments above */
- smp_rmb();
+ rcu_read_lock();
+ if (!lock_task_sighand(p, &flags)) {
+ rcu_read_unlock();
+ return;
+ }
switch (who) {
case RUSAGE_BOTH:
case RUSAGE_CHILDREN:
- spin_lock_irqsave(&p->sighand->siglock, flags);
utime = p->signal->cutime;
stime = p->signal->cstime;
r->ru_nvcsw = p->signal->cnvcsw;
r->ru_nivcsw = p->signal->cnivcsw;
r->ru_minflt = p->signal->cmin_flt;
r->ru_majflt = p->signal->cmaj_flt;
- spin_unlock_irqrestore(&p->sighand->siglock, flags);
if (who == RUSAGE_CHILDREN)
break;
@@ -1941,8 +1933,9 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
BUG();
}
- if (need_lock)
- read_unlock(&tasklist_lock);
+ unlock_task_sighand(p, &flags);
+ rcu_read_unlock();
+
cputime_to_timeval(utime, &r->ru_utime);
cputime_to_timeval(stime, &r->ru_stime);
}
@@ -2057,6 +2050,13 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
return -EFAULT;
return 0;
}
+ case PR_GET_ENDIAN:
+ error = GET_ENDIAN(current, arg2);
+ break;
+ case PR_SET_ENDIAN:
+ error = SET_ENDIAN(current, arg2);
+ break;
+
default:
error = -EINVAL;
break;
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 5433195..6991bec 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -87,6 +87,7 @@ cond_syscall(sys_inotify_init);
cond_syscall(sys_inotify_add_watch);
cond_syscall(sys_inotify_rm_watch);
cond_syscall(sys_migrate_pages);
+cond_syscall(sys_move_pages);
cond_syscall(sys_chown16);
cond_syscall(sys_fchown16);
cond_syscall(sys_getegid16);
@@ -132,3 +133,4 @@ cond_syscall(sys_mincore);
cond_syscall(sys_madvise);
cond_syscall(sys_mremap);
cond_syscall(sys_remap_file_pages);
+cond_syscall(compat_sys_move_pages);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 0d656e6..2c0e658 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -59,6 +59,7 @@ extern int proc_nr_files(ctl_table *table, int write, struct file *filp,
extern int C_A_D;
extern int sysctl_overcommit_memory;
extern int sysctl_overcommit_ratio;
+extern int sysctl_panic_on_oom;
extern int max_threads;
extern int sysrq_enabled;
extern int core_uses_pid;
@@ -142,7 +143,6 @@ static struct ctl_table_header root_table_header =
static ctl_table kern_table[];
static ctl_table vm_table[];
-static ctl_table proc_table[];
static ctl_table fs_table[];
static ctl_table debug_table[];
static ctl_table dev_table[];
@@ -202,12 +202,6 @@ static ctl_table root_table[] = {
},
#endif
{
- .ctl_name = CTL_PROC,
- .procname = "proc",
- .mode = 0555,
- .child = proc_table,
- },
- {
.ctl_name = CTL_FS,
.procname = "fs",
.mode = 0555,
@@ -398,7 +392,7 @@ static ctl_table kern_table[] = {
.strategy = &sysctl_string,
},
#endif
-#ifdef CONFIG_HOTPLUG
+#if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
{
.ctl_name = KERN_HOTPLUG,
.procname = "hotplug",
@@ -702,6 +696,14 @@ static ctl_table vm_table[] = {
.proc_handler = &proc_dointvec,
},
{
+ .ctl_name = VM_PANIC_ON_OOM,
+ .procname = "panic_on_oom",
+ .data = &sysctl_panic_on_oom,
+ .maxlen = sizeof(sysctl_panic_on_oom),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
.ctl_name = VM_OVERCOMMIT_RATIO,
.procname = "overcommit_ratio",
.data = &sysctl_overcommit_ratio,
@@ -918,10 +920,6 @@ static ctl_table vm_table[] = {
{ .ctl_name = 0 }
};
-static ctl_table proc_table[] = {
- { .ctl_name = 0 }
-};
-
static ctl_table fs_table[] = {
{
.ctl_name = FS_NRINODE,
diff --git a/kernel/timer.c b/kernel/timer.c
index 9e49dee..eb97371 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -146,7 +146,7 @@ static void internal_add_timer(tvec_base_t *base, struct timer_list *timer)
void fastcall init_timer(struct timer_list *timer)
{
timer->entry.next = NULL;
- timer->base = per_cpu(tvec_bases, raw_smp_processor_id());
+ timer->base = __raw_get_cpu_var(tvec_bases);
}
EXPORT_SYMBOL(init_timer);
@@ -383,23 +383,19 @@ EXPORT_SYMBOL(del_timer_sync);
static int cascade(tvec_base_t *base, tvec_t *tv, int index)
{
/* cascade all the timers from tv up one level */
- struct list_head *head, *curr;
+ struct timer_list *timer, *tmp;
+ struct list_head tv_list;
+
+ list_replace_init(tv->vec + index, &tv_list);
- head = tv->vec + index;
- curr = head->next;
/*
- * We are removing _all_ timers from the list, so we don't have to
- * detach them individually, just clear the list afterwards.
+ * We are removing _all_ timers from the list, so we
+ * don't have to detach them individually.
*/
- while (curr != head) {
- struct timer_list *tmp;
-
- tmp = list_entry(curr, struct timer_list, entry);
- BUG_ON(tmp->base != base);
- curr = curr->next;
- internal_add_timer(base, tmp);
+ list_for_each_entry_safe(timer, tmp, &tv_list, entry) {
+ BUG_ON(timer->base != base);
+ internal_add_timer(base, timer);
}
- INIT_LIST_HEAD(head);
return index;
}
@@ -419,10 +415,10 @@ static inline void __run_timers(tvec_base_t *base)
spin_lock_irq(&base->lock);
while (time_after_eq(jiffies, base->timer_jiffies)) {
- struct list_head work_list = LIST_HEAD_INIT(work_list);
+ struct list_head work_list;
struct list_head *head = &work_list;
int index = base->timer_jiffies & TVR_MASK;
-
+
/*
* Cascade timers:
*/
@@ -431,8 +427,8 @@ static inline void __run_timers(tvec_base_t *base)
(!cascade(base, &base->tv3, INDEX(1))) &&
!cascade(base, &base->tv4, INDEX(2)))
cascade(base, &base->tv5, INDEX(3));
- ++base->timer_jiffies;
- list_splice_init(base->tv1.vec + index, &work_list);
+ ++base->timer_jiffies;
+ list_replace_init(base->tv1.vec + index, &work_list);
while (!list_empty(head)) {
void (*fn)(unsigned long);
unsigned long data;
diff --git a/kernel/user.c b/kernel/user.c
index 4b1eb74..6408c04 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -148,7 +148,7 @@ struct user_struct * alloc_uid(uid_t uid)
new->mq_bytes = 0;
new->locked_shm = 0;
- if (alloc_uid_keyring(new) < 0) {
+ if (alloc_uid_keyring(new, current) < 0) {
kmem_cache_free(uid_cachep, new);
return NULL;
}
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 880fb41..565cf7a 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -428,22 +428,34 @@ int schedule_delayed_work_on(int cpu,
return ret;
}
-int schedule_on_each_cpu(void (*func) (void *info), void *info)
+/**
+ * schedule_on_each_cpu - call a function on each online CPU from keventd
+ * @func: the function to call
+ * @info: a pointer to pass to func()
+ *
+ * Returns zero on success.
+ * Returns -ve errno on failure.
+ *
+ * Appears to be racy against CPU hotplug.
+ *
+ * schedule_on_each_cpu() is very slow.
+ */
+int schedule_on_each_cpu(void (*func)(void *info), void *info)
{
int cpu;
- struct work_struct *work;
+ struct work_struct *works;
- work = kmalloc(NR_CPUS * sizeof(struct work_struct), GFP_KERNEL);
-
- if (!work)
+ works = alloc_percpu(struct work_struct);
+ if (!works)
return -ENOMEM;
+
for_each_online_cpu(cpu) {
- INIT_WORK(work + cpu, func, info);
+ INIT_WORK(per_cpu_ptr(works, cpu), func, info);
__queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu),
- work + cpu);
+ per_cpu_ptr(works, cpu));
}
flush_workqueue(keventd_wq);
- kfree(work);
+ free_percpu(works);
return 0;
}
@@ -531,11 +543,11 @@ int current_is_keventd(void)
static void take_over_work(struct workqueue_struct *wq, unsigned int cpu)
{
struct cpu_workqueue_struct *cwq = per_cpu_ptr(wq->cpu_wq, cpu);
- LIST_HEAD(list);
+ struct list_head list;
struct work_struct *work;
spin_lock_irq(&cwq->lock);
- list_splice_init(&cwq->worklist, &list);
+ list_replace_init(&cwq->worklist, &list);
while (!list_empty(&list)) {
printk("Taking work for %s\n", wq->name);
@@ -578,6 +590,8 @@ static int workqueue_cpu_callback(struct notifier_block *nfb,
case CPU_UP_CANCELED:
list_for_each_entry(wq, &workqueues, list) {
+ if (!per_cpu_ptr(wq->cpu_wq, hotcpu)->thread)
+ continue;
/* Unbind so it can run. */
kthread_bind(per_cpu_ptr(wq->cpu_wq, hotcpu)->thread,
any_online_cpu(cpu_online_map));
diff --git a/lib/Makefile b/lib/Makefile
index b830c9a..79358ad 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_TEXTSEARCH) += textsearch.o
obj-$(CONFIG_TEXTSEARCH_KMP) += ts_kmp.o
obj-$(CONFIG_TEXTSEARCH_BM) += ts_bm.o
obj-$(CONFIG_TEXTSEARCH_FSM) += ts_fsm.o
+obj-$(CONFIG_SMP) += percpu_counter.o
obj-$(CONFIG_SWIOTLB) += swiotlb.o
diff --git a/lib/bitmap.c b/lib/bitmap.c
index ed2ae3b..d71e38c 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -317,16 +317,16 @@ EXPORT_SYMBOL(bitmap_scnprintf);
/**
* bitmap_parse - convert an ASCII hex string into a bitmap.
- * @buf: pointer to buffer in user space containing string.
- * @buflen: buffer size in bytes. If string is smaller than this
+ * @ubuf: pointer to buffer in user space containing string.
+ * @ubuflen: buffer size in bytes. If string is smaller than this
* then it must be terminated with a \0.
* @maskp: pointer to bitmap array that will contain result.
* @nmaskbits: size of bitmap, in bits.
*
* Commas group hex digits into chunks. Each chunk defines exactly 32
* bits of the resultant bitmask. No chunk may specify a value larger
- * than 32 bits (-EOVERFLOW), and if a chunk specifies a smaller value
- * then leading 0-bits are prepended. -EINVAL is returned for illegal
+ * than 32 bits (%-EOVERFLOW), and if a chunk specifies a smaller value
+ * then leading 0-bits are prepended. %-EINVAL is returned for illegal
* characters and for grouping errors such as "1,,5", ",44", "," and "".
* Leading and trailing whitespace accepted, but not embedded whitespace.
*/
@@ -452,8 +452,8 @@ EXPORT_SYMBOL(bitmap_scnlistprintf);
/**
* bitmap_parselist - convert list format ASCII string to bitmap
- * @buf: read nul-terminated user string from this buffer
- * @mask: write resulting mask here
+ * @bp: read nul-terminated user string from this buffer
+ * @maskp: write resulting mask here
* @nmaskbits: number of bits in mask to be written
*
* Input format is a comma-separated list of decimal numbers and
@@ -461,10 +461,11 @@ EXPORT_SYMBOL(bitmap_scnlistprintf);
* decimal numbers, the smallest and largest bit numbers set in
* the range.
*
- * Returns 0 on success, -errno on invalid input strings:
- * -EINVAL: second number in range smaller than first
- * -EINVAL: invalid character in string
- * -ERANGE: bit number specified too large for mask
+ * Returns 0 on success, -errno on invalid input strings.
+ * Error values:
+ * %-EINVAL: second number in range smaller than first
+ * %-EINVAL: invalid character in string
+ * %-ERANGE: bit number specified too large for mask
*/
int bitmap_parselist(const char *bp, unsigned long *maskp, int nmaskbits)
{
@@ -625,10 +626,10 @@ EXPORT_SYMBOL(bitmap_remap);
/**
* bitmap_bitremap - Apply map defined by a pair of bitmaps to a single bit
- * @oldbit - bit position to be mapped
- * @old: defines domain of map
- * @new: defines range of map
- * @bits: number of bits in each of these bitmaps
+ * @oldbit: bit position to be mapped
+ * @old: defines domain of map
+ * @new: defines range of map
+ * @bits: number of bits in each of these bitmaps
*
* Let @old and @new define a mapping of bit positions, such that
* whatever position is held by the n-th set bit in @old is mapped
@@ -790,7 +791,7 @@ EXPORT_SYMBOL(bitmap_release_region);
*
* Allocate (set bits in) a specified region of a bitmap.
*
- * Return 0 on success, or -EBUSY if specified region wasn't
+ * Return 0 on success, or %-EBUSY if specified region wasn't
* free (not all bits were zero).
*/
int bitmap_allocate_region(unsigned long *bitmap, int pos, int order)
diff --git a/lib/crc-ccitt.c b/lib/crc-ccitt.c
index 115d149..7f6dd68 100644
--- a/lib/crc-ccitt.c
+++ b/lib/crc-ccitt.c
@@ -53,9 +53,9 @@ EXPORT_SYMBOL(crc_ccitt_table);
/**
* crc_ccitt - recompute the CRC for the data buffer
- * @crc - previous CRC value
- * @buffer - data pointer
- * @len - number of bytes in the buffer
+ * @crc: previous CRC value
+ * @buffer: data pointer
+ * @len: number of bytes in the buffer
*/
u16 crc_ccitt(u16 crc, u8 const *buffer, size_t len)
{
diff --git a/lib/crc16.c b/lib/crc16.c
index 011fe57..8737b08 100644
--- a/lib/crc16.c
+++ b/lib/crc16.c
@@ -47,12 +47,12 @@ u16 const crc16_table[256] = {
EXPORT_SYMBOL(crc16_table);
/**
- * Compute the CRC-16 for the data buffer
+ * crc16 - compute the CRC-16 for the data buffer
+ * @crc: previous CRC value
+ * @buffer: data pointer
+ * @len: number of bytes in the buffer
*
- * @param crc previous CRC value
- * @param buffer data pointer
- * @param len number of bytes in the buffer
- * @return the updated CRC value
+ * Returns the updated CRC value.
*/
u16 crc16(u16 crc, u8 const *buffer, size_t len)
{
diff --git a/lib/crc32.c b/lib/crc32.c
index 065198f..285fd9b 100644
--- a/lib/crc32.c
+++ b/lib/crc32.c
@@ -42,20 +42,21 @@ MODULE_AUTHOR("Matt Domsch <Matt_Domsch@dell.com>");
MODULE_DESCRIPTION("Ethernet CRC32 calculations");
MODULE_LICENSE("GPL");
+/**
+ * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
+ * @crc: seed value for computation. ~0 for Ethernet, sometimes 0 for
+ * other uses, or the previous crc32 value if computing incrementally.
+ * @p: pointer to buffer over which CRC is run
+ * @len: length of buffer @p
+ */
+u32 __attribute_pure__ crc32_le(u32 crc, unsigned char const *p, size_t len);
+
#if CRC_LE_BITS == 1
/*
* In fact, the table-based code will work in this case, but it can be
* simplified by inlining the table in ?: form.
*/
-/**
- * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
- * @crc - seed value for computation. ~0 for Ethernet, sometimes 0 for
- * other uses, or the previous crc32 value if computing incrementally.
- * @p - pointer to buffer over which CRC is run
- * @len - length of buffer @p
- *
- */
u32 __attribute_pure__ crc32_le(u32 crc, unsigned char const *p, size_t len)
{
int i;
@@ -68,14 +69,6 @@ u32 __attribute_pure__ crc32_le(u32 crc, unsigned char const *p, size_t len)
}
#else /* Table-based approach */
-/**
- * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
- * @crc - seed value for computation. ~0 for Ethernet, sometimes 0 for
- * other uses, or the previous crc32 value if computing incrementally.
- * @p - pointer to buffer over which CRC is run
- * @len - length of buffer @p
- *
- */
u32 __attribute_pure__ crc32_le(u32 crc, unsigned char const *p, size_t len)
{
# if CRC_LE_BITS == 8
@@ -145,20 +138,21 @@ u32 __attribute_pure__ crc32_le(u32 crc, unsigned char const *p, size_t len)
}
#endif
+/**
+ * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
+ * @crc: seed value for computation. ~0 for Ethernet, sometimes 0 for
+ * other uses, or the previous crc32 value if computing incrementally.
+ * @p: pointer to buffer over which CRC is run
+ * @len: length of buffer @p
+ */
+u32 __attribute_pure__ crc32_be(u32 crc, unsigned char const *p, size_t len);
+
#if CRC_BE_BITS == 1
/*
* In fact, the table-based code will work in this case, but it can be
* simplified by inlining the table in ?: form.
*/
-/**
- * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
- * @crc - seed value for computation. ~0 for Ethernet, sometimes 0 for
- * other uses, or the previous crc32 value if computing incrementally.
- * @p - pointer to buffer over which CRC is run
- * @len - length of buffer @p
- *
- */
u32 __attribute_pure__ crc32_be(u32 crc, unsigned char const *p, size_t len)
{
int i;
@@ -173,14 +167,6 @@ u32 __attribute_pure__ crc32_be(u32 crc, unsigned char const *p, size_t len)
}
#else /* Table-based approach */
-/**
- * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
- * @crc - seed value for computation. ~0 for Ethernet, sometimes 0 for
- * other uses, or the previous crc32 value if computing incrementally.
- * @p - pointer to buffer over which CRC is run
- * @len - length of buffer @p
- *
- */
u32 __attribute_pure__ crc32_be(u32 crc, unsigned char const *p, size_t len)
{
# if CRC_BE_BITS == 8
@@ -249,6 +235,10 @@ u32 __attribute_pure__ crc32_be(u32 crc, unsigned char const *p, size_t len)
}
#endif
+/**
+ * bitreverse - reverse the order of bits in a u32 value
+ * @x: value to be bit-reversed
+ */
u32 bitreverse(u32 x)
{
x = (x >> 16) | (x << 16);
diff --git a/lib/genalloc.c b/lib/genalloc.c
index 9ce0a6a..71338b4 100644
--- a/lib/genalloc.c
+++ b/lib/genalloc.c
@@ -4,10 +4,6 @@
* Uses for this includes on-device special memory, uncached memory
* etc.
*
- * This code is based on the buddy allocator found in the sym53c8xx_2
- * driver Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr>,
- * and adapted for general purpose use.
- *
* Copyright 2005 (C) Jes Sorensen <jes@trained-monkey.org>
*
* This source code is licensed under the GNU General Public License,
@@ -15,172 +11,155 @@
*/
#include <linux/module.h>
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/spinlock.h>
#include <linux/genalloc.h>
-#include <asm/page.h>
-
-struct gen_pool *gen_pool_create(int nr_chunks, int max_chunk_shift,
- unsigned long (*fp)(struct gen_pool *),
- unsigned long data)
+/*
+ * Create a new special memory pool.
+ *
+ * @min_alloc_order: log base 2 of number of bytes each bitmap bit represents
+ * @nid: node id of the node the pool structure should be allocated on, or -1
+ */
+struct gen_pool *gen_pool_create(int min_alloc_order, int nid)
{
- struct gen_pool *poolp;
- unsigned long tmp;
- int i;
-
- /*
- * This is really an arbitrary limit, +10 is enough for
- * IA64_GRANULE_SHIFT, aka 16MB. If anyone needs a large limit
- * this can be increased without problems.
- */
- if ((max_chunk_shift > (PAGE_SHIFT + 10)) ||
- ((max_chunk_shift < ALLOC_MIN_SHIFT) && max_chunk_shift))
- return NULL;
-
- if (!max_chunk_shift)
- max_chunk_shift = PAGE_SHIFT;
-
- poolp = kmalloc(sizeof(struct gen_pool), GFP_KERNEL);
- if (!poolp)
- return NULL;
- memset(poolp, 0, sizeof(struct gen_pool));
- poolp->h = kmalloc(sizeof(struct gen_pool_link) *
- (max_chunk_shift - ALLOC_MIN_SHIFT + 1),
- GFP_KERNEL);
- if (!poolp->h) {
- printk(KERN_WARNING "gen_pool_alloc() failed to allocate\n");
- kfree(poolp);
- return NULL;
- }
- memset(poolp->h, 0, sizeof(struct gen_pool_link) *
- (max_chunk_shift - ALLOC_MIN_SHIFT + 1));
-
- spin_lock_init(&poolp->lock);
- poolp->get_new_chunk = fp;
- poolp->max_chunk_shift = max_chunk_shift;
- poolp->private = data;
-
- for (i = 0; i < nr_chunks; i++) {
- tmp = poolp->get_new_chunk(poolp);
- printk(KERN_INFO "allocated %lx\n", tmp);
- if (!tmp)
- break;
- gen_pool_free(poolp, tmp, (1 << poolp->max_chunk_shift));
- }
+ struct gen_pool *pool;
- return poolp;
+ pool = kmalloc_node(sizeof(struct gen_pool), GFP_KERNEL, nid);
+ if (pool != NULL) {
+ rwlock_init(&pool->lock);
+ INIT_LIST_HEAD(&pool->chunks);
+ pool->min_alloc_order = min_alloc_order;
+ }
+ return pool;
}
EXPORT_SYMBOL(gen_pool_create);
/*
- * Simple power of two buddy-like generic allocator.
- * Provides naturally aligned memory chunks.
+ * Add a new chunk of memory to the specified pool.
+ *
+ * @pool: pool to add new memory chunk to
+ * @addr: starting address of memory chunk to add to pool
+ * @size: size in bytes of the memory chunk to add to pool
+ * @nid: node id of the node the chunk structure and bitmap should be
+ * allocated on, or -1
*/
-unsigned long gen_pool_alloc(struct gen_pool *poolp, int size)
+int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size,
+ int nid)
{
- int j, i, s, max_chunk_size;
- unsigned long a, flags;
- struct gen_pool_link *h = poolp->h;
+ struct gen_pool_chunk *chunk;
+ int nbits = size >> pool->min_alloc_order;
+ int nbytes = sizeof(struct gen_pool_chunk) +
+ (nbits + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
- max_chunk_size = 1 << poolp->max_chunk_shift;
+ chunk = kmalloc_node(nbytes, GFP_KERNEL, nid);
+ if (unlikely(chunk == NULL))
+ return -1;
- if (size > max_chunk_size)
- return 0;
+ memset(chunk, 0, nbytes);
+ spin_lock_init(&chunk->lock);
+ chunk->start_addr = addr;
+ chunk->end_addr = addr + size;
- size = max(size, 1 << ALLOC_MIN_SHIFT);
- i = fls(size - 1);
- s = 1 << i;
- j = i -= ALLOC_MIN_SHIFT;
-
- spin_lock_irqsave(&poolp->lock, flags);
- while (!h[j].next) {
- if (s == max_chunk_size) {
- struct gen_pool_link *ptr;
- spin_unlock_irqrestore(&poolp->lock, flags);
- ptr = (struct gen_pool_link *)poolp->get_new_chunk(poolp);
- spin_lock_irqsave(&poolp->lock, flags);
- h[j].next = ptr;
- if (h[j].next)
- h[j].next->next = NULL;
- break;
- }
- j++;
- s <<= 1;
- }
- a = (unsigned long) h[j].next;
- if (a) {
- h[j].next = h[j].next->next;
- /*
- * This should be split into a seperate function doing
- * the chunk split in order to support custom
- * handling memory not physically accessible by host
- */
- while (j > i) {
- j -= 1;
- s >>= 1;
- h[j].next = (struct gen_pool_link *) (a + s);
- h[j].next->next = NULL;
- }
- }
- spin_unlock_irqrestore(&poolp->lock, flags);
- return a;
+ write_lock(&pool->lock);
+ list_add(&chunk->next_chunk, &pool->chunks);
+ write_unlock(&pool->lock);
+
+ return 0;
}
-EXPORT_SYMBOL(gen_pool_alloc);
+EXPORT_SYMBOL(gen_pool_add);
/*
- * Counter-part of the generic allocator.
+ * Allocate the requested number of bytes from the specified pool.
+ * Uses a first-fit algorithm.
+ *
+ * @pool: pool to allocate from
+ * @size: number of bytes to allocate from the pool
*/
-void gen_pool_free(struct gen_pool *poolp, unsigned long ptr, int size)
+unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size)
{
- struct gen_pool_link *q;
- struct gen_pool_link *h = poolp->h;
- unsigned long a, b, flags;
- int i, s, max_chunk_size;
-
- max_chunk_size = 1 << poolp->max_chunk_shift;
+ struct list_head *_chunk;
+ struct gen_pool_chunk *chunk;
+ unsigned long addr, flags;
+ int order = pool->min_alloc_order;
+ int nbits, bit, start_bit, end_bit;
- if (size > max_chunk_size)
- return;
-
- size = max(size, 1 << ALLOC_MIN_SHIFT);
- i = fls(size - 1);
- s = 1 << i;
- i -= ALLOC_MIN_SHIFT;
-
- a = ptr;
+ if (size == 0)
+ return 0;
- spin_lock_irqsave(&poolp->lock, flags);
- while (1) {
- if (s == max_chunk_size) {
- ((struct gen_pool_link *)a)->next = h[i].next;
- h[i].next = (struct gen_pool_link *)a;
- break;
+ nbits = (size + (1UL << order) - 1) >> order;
+
+ read_lock(&pool->lock);
+ list_for_each(_chunk, &pool->chunks) {
+ chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
+
+ end_bit = (chunk->end_addr - chunk->start_addr) >> order;
+ end_bit -= nbits + 1;
+
+ spin_lock_irqsave(&chunk->lock, flags);
+ bit = -1;
+ while (bit + 1 < end_bit) {
+ bit = find_next_zero_bit(chunk->bits, end_bit, bit + 1);
+ if (bit >= end_bit)
+ break;
+
+ start_bit = bit;
+ if (nbits > 1) {
+ bit = find_next_bit(chunk->bits, bit + nbits,
+ bit + 1);
+ if (bit - start_bit < nbits)
+ continue;
+ }
+
+ addr = chunk->start_addr +
+ ((unsigned long)start_bit << order);
+ while (nbits--)
+ __set_bit(start_bit++, &chunk->bits);
+ spin_unlock_irqrestore(&chunk->lock, flags);
+ read_unlock(&pool->lock);
+ return addr;
}
- b = a ^ s;
- q = &h[i];
+ spin_unlock_irqrestore(&chunk->lock, flags);
+ }
+ read_unlock(&pool->lock);
+ return 0;
+}
+EXPORT_SYMBOL(gen_pool_alloc);
- while (q->next && q->next != (struct gen_pool_link *)b)
- q = q->next;
- if (!q->next) {
- ((struct gen_pool_link *)a)->next = h[i].next;
- h[i].next = (struct gen_pool_link *)a;
+/*
+ * Free the specified memory back to the specified pool.
+ *
+ * @pool: pool to free to
+ * @addr: starting address of memory to free back to pool
+ * @size: size in bytes of memory to free
+ */
+void gen_pool_free(struct gen_pool *pool, unsigned long addr, size_t size)
+{
+ struct list_head *_chunk;
+ struct gen_pool_chunk *chunk;
+ unsigned long flags;
+ int order = pool->min_alloc_order;
+ int bit, nbits;
+
+ nbits = (size + (1UL << order) - 1) >> order;
+
+ read_lock(&pool->lock);
+ list_for_each(_chunk, &pool->chunks) {
+ chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
+
+ if (addr >= chunk->start_addr && addr < chunk->end_addr) {
+ BUG_ON(addr + size > chunk->end_addr);
+ spin_lock_irqsave(&chunk->lock, flags);
+ bit = (addr - chunk->start_addr) >> order;
+ while (nbits--)
+ __clear_bit(bit++, &chunk->bits);
+ spin_unlock_irqrestore(&chunk->lock, flags);
break;
}
- q->next = q->next->next;
- a = a & b;
- s <<= 1;
- i++;
}
- spin_unlock_irqrestore(&poolp->lock, flags);
+ BUG_ON(nbits > 0);
+ read_unlock(&pool->lock);
}
EXPORT_SYMBOL(gen_pool_free);
diff --git a/lib/idr.c b/lib/idr.c
index d226259..de19030 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -48,15 +48,21 @@ static struct idr_layer *alloc_layer(struct idr *idp)
return(p);
}
+/* only called when idp->lock is held */
+static void __free_layer(struct idr *idp, struct idr_layer *p)
+{
+ p->ary[0] = idp->id_free;
+ idp->id_free = p;
+ idp->id_free_cnt++;
+}
+
static void free_layer(struct idr *idp, struct idr_layer *p)
{
/*
* Depends on the return element being zeroed.
*/
spin_lock(&idp->lock);
- p->ary[0] = idp->id_free;
- idp->id_free = p;
- idp->id_free_cnt++;
+ __free_layer(idp, p);
spin_unlock(&idp->lock);
}
@@ -184,12 +190,14 @@ build_up:
* The allocation failed. If we built part of
* the structure tear it down.
*/
+ spin_lock(&idp->lock);
for (new = p; p && p != idp->top; new = p) {
p = p->ary[0];
new->ary[0] = NULL;
new->bitmap = new->count = 0;
- free_layer(idp, new);
+ __free_layer(idp, new);
}
+ spin_unlock(&idp->lock);
return -1;
}
new->ary[0] = p;
diff --git a/lib/libcrc32c.c b/lib/libcrc32c.c
index 52b6dc1..60f4680 100644
--- a/lib/libcrc32c.c
+++ b/lib/libcrc32c.c
@@ -88,7 +88,7 @@ crc32c_le(u32 crc, unsigned char const *p, size_t len)
* reflect output bytes = true
*/
-static u32 crc32c_table[256] = {
+static const u32 crc32c_table[256] = {
0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
diff --git a/lib/percpu_counter.c b/lib/percpu_counter.c
new file mode 100644
index 0000000..8504490
--- /dev/null
+++ b/lib/percpu_counter.c
@@ -0,0 +1,46 @@
+/*
+ * Fast batching percpu counters.
+ */
+
+#include <linux/percpu_counter.h>
+#include <linux/module.h>
+
+void percpu_counter_mod(struct percpu_counter *fbc, s32 amount)
+{
+ long count;
+ s32 *pcount;
+ int cpu = get_cpu();
+
+ pcount = per_cpu_ptr(fbc->counters, cpu);
+ count = *pcount + amount;
+ if (count >= FBC_BATCH || count <= -FBC_BATCH) {
+ spin_lock(&fbc->lock);
+ fbc->count += count;
+ *pcount = 0;
+ spin_unlock(&fbc->lock);
+ } else {
+ *pcount = count;
+ }
+ put_cpu();
+}
+EXPORT_SYMBOL(percpu_counter_mod);
+
+/*
+ * Add up all the per-cpu counts, return the result. This is a more accurate
+ * but much slower version of percpu_counter_read_positive()
+ */
+s64 percpu_counter_sum(struct percpu_counter *fbc)
+{
+ s64 ret;
+ int cpu;
+
+ spin_lock(&fbc->lock);
+ ret = fbc->count;
+ for_each_possible_cpu(cpu) {
+ s32 *pcount = per_cpu_ptr(fbc->counters, cpu);
+ ret += *pcount;
+ }
+ spin_unlock(&fbc->lock);
+ return ret < 0 ? 0 : ret;
+}
+EXPORT_SYMBOL(percpu_counter_sum);
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 7097bb2..637d556 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -33,7 +33,7 @@
#ifdef __KERNEL__
-#define RADIX_TREE_MAP_SHIFT 6
+#define RADIX_TREE_MAP_SHIFT (CONFIG_BASE_SMALL ? 4 : 6)
#else
#define RADIX_TREE_MAP_SHIFT 3 /* For more stressful testing */
#endif
@@ -74,6 +74,11 @@ struct radix_tree_preload {
};
DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, };
+static inline gfp_t root_gfp_mask(struct radix_tree_root *root)
+{
+ return root->gfp_mask & __GFP_BITS_MASK;
+}
+
/*
* This assumes that the caller has performed appropriate preallocation, and
* that the caller has pinned this thread of control to the current CPU.
@@ -82,9 +87,10 @@ static struct radix_tree_node *
radix_tree_node_alloc(struct radix_tree_root *root)
{
struct radix_tree_node *ret;
+ gfp_t gfp_mask = root_gfp_mask(root);
- ret = kmem_cache_alloc(radix_tree_node_cachep, root->gfp_mask);
- if (ret == NULL && !(root->gfp_mask & __GFP_WAIT)) {
+ ret = kmem_cache_alloc(radix_tree_node_cachep, gfp_mask);
+ if (ret == NULL && !(gfp_mask & __GFP_WAIT)) {
struct radix_tree_preload *rtp;
rtp = &__get_cpu_var(radix_tree_preloads);
@@ -152,6 +158,27 @@ static inline int tag_get(struct radix_tree_node *node, unsigned int tag,
return test_bit(offset, node->tags[tag]);
}
+static inline void root_tag_set(struct radix_tree_root *root, unsigned int tag)
+{
+ root->gfp_mask |= (1 << (tag + __GFP_BITS_SHIFT));
+}
+
+
+static inline void root_tag_clear(struct radix_tree_root *root, unsigned int tag)
+{
+ root->gfp_mask &= ~(1 << (tag + __GFP_BITS_SHIFT));
+}
+
+static inline void root_tag_clear_all(struct radix_tree_root *root)
+{
+ root->gfp_mask &= __GFP_BITS_MASK;
+}
+
+static inline int root_tag_get(struct radix_tree_root *root, unsigned int tag)
+{
+ return root->gfp_mask & (1 << (tag + __GFP_BITS_SHIFT));
+}
+
/*
* Returns 1 if any slot in the node has this tag set.
* Otherwise returns 0.
@@ -182,7 +209,6 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
{
struct radix_tree_node *node;
unsigned int height;
- char tags[RADIX_TREE_MAX_TAGS];
int tag;
/* Figure out what the height should be. */
@@ -195,16 +221,6 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
goto out;
}
- /*
- * Prepare the tag status of the top-level node for propagation
- * into the newly-pushed top-level node(s)
- */
- for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
- tags[tag] = 0;
- if (any_tag_set(root->rnode, tag))
- tags[tag] = 1;
- }
-
do {
if (!(node = radix_tree_node_alloc(root)))
return -ENOMEM;
@@ -214,7 +230,7 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
/* Propagate the aggregated tag info into the new root */
for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
- if (tags[tag])
+ if (root_tag_get(root, tag))
tag_set(node, tag, 0);
}
@@ -243,8 +259,7 @@ int radix_tree_insert(struct radix_tree_root *root,
int error;
/* Make sure the tree is high enough. */
- if ((!index && !root->rnode) ||
- index > radix_tree_maxindex(root->height)) {
+ if (index > radix_tree_maxindex(root->height)) {
error = radix_tree_extend(root, index);
if (error)
return error;
@@ -255,7 +270,7 @@ int radix_tree_insert(struct radix_tree_root *root,
shift = (height-1) * RADIX_TREE_MAP_SHIFT;
offset = 0; /* uninitialised var warning */
- do {
+ while (height > 0) {
if (slot == NULL) {
/* Have to add a child node. */
if (!(slot = radix_tree_node_alloc(root)))
@@ -273,16 +288,21 @@ int radix_tree_insert(struct radix_tree_root *root,
slot = node->slots[offset];
shift -= RADIX_TREE_MAP_SHIFT;
height--;
- } while (height > 0);
+ }
if (slot != NULL)
return -EEXIST;
- BUG_ON(!node);
- node->count++;
- node->slots[offset] = item;
- BUG_ON(tag_get(node, 0, offset));
- BUG_ON(tag_get(node, 1, offset));
+ if (node) {
+ node->count++;
+ node->slots[offset] = item;
+ BUG_ON(tag_get(node, 0, offset));
+ BUG_ON(tag_get(node, 1, offset));
+ } else {
+ root->rnode = item;
+ BUG_ON(root_tag_get(root, 0));
+ BUG_ON(root_tag_get(root, 1));
+ }
return 0;
}
@@ -295,9 +315,13 @@ static inline void **__lookup_slot(struct radix_tree_root *root,
struct radix_tree_node **slot;
height = root->height;
+
if (index > radix_tree_maxindex(height))
return NULL;
+ if (height == 0 && root->rnode)
+ return (void **)&root->rnode;
+
shift = (height-1) * RADIX_TREE_MAP_SHIFT;
slot = &root->rnode;
@@ -365,11 +389,10 @@ void *radix_tree_tag_set(struct radix_tree_root *root,
struct radix_tree_node *slot;
height = root->height;
- if (index > radix_tree_maxindex(height))
- return NULL;
+ BUG_ON(index > radix_tree_maxindex(height));
- shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
slot = root->rnode;
+ shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
while (height > 0) {
int offset;
@@ -383,6 +406,10 @@ void *radix_tree_tag_set(struct radix_tree_root *root,
height--;
}
+ /* set the root's tag bit */
+ if (slot && !root_tag_get(root, tag))
+ root_tag_set(root, tag);
+
return slot;
}
EXPORT_SYMBOL(radix_tree_tag_set);
@@ -405,9 +432,8 @@ void *radix_tree_tag_clear(struct radix_tree_root *root,
unsigned long index, unsigned int tag)
{
struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path;
- struct radix_tree_node *slot;
+ struct radix_tree_node *slot = NULL;
unsigned int height, shift;
- void *ret = NULL;
height = root->height;
if (index > radix_tree_maxindex(height))
@@ -432,20 +458,24 @@ void *radix_tree_tag_clear(struct radix_tree_root *root,
height--;
}
- ret = slot;
- if (ret == NULL)
+ if (slot == NULL)
goto out;
- do {
+ while (pathp->node) {
if (!tag_get(pathp->node, tag, pathp->offset))
goto out;
tag_clear(pathp->node, tag, pathp->offset);
if (any_tag_set(pathp->node, tag))
goto out;
pathp--;
- } while (pathp->node);
+ }
+
+ /* clear the root's tag bit */
+ if (root_tag_get(root, tag))
+ root_tag_clear(root, tag);
+
out:
- return ret;
+ return slot;
}
EXPORT_SYMBOL(radix_tree_tag_clear);
@@ -458,9 +488,8 @@ EXPORT_SYMBOL(radix_tree_tag_clear);
*
* Return values:
*
- * 0: tag not present
- * 1: tag present, set
- * -1: tag present, unset
+ * 0: tag not present or not set
+ * 1: tag set
*/
int radix_tree_tag_get(struct radix_tree_root *root,
unsigned long index, unsigned int tag)
@@ -473,6 +502,13 @@ int radix_tree_tag_get(struct radix_tree_root *root,
if (index > radix_tree_maxindex(height))
return 0;
+ /* check the root's tag bit */
+ if (!root_tag_get(root, tag))
+ return 0;
+
+ if (height == 0)
+ return 1;
+
shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
slot = root->rnode;
@@ -494,7 +530,7 @@ int radix_tree_tag_get(struct radix_tree_root *root,
int ret = tag_get(slot, tag, offset);
BUG_ON(ret && saw_unset_tag);
- return ret ? 1 : -1;
+ return !!ret;
}
slot = slot->slots[offset];
shift -= RADIX_TREE_MAP_SHIFT;
@@ -514,8 +550,11 @@ __lookup(struct radix_tree_root *root, void **results, unsigned long index,
unsigned long i;
height = root->height;
- if (height == 0)
+ if (height == 0) {
+ if (root->rnode && index == 0)
+ results[nr_found++] = root->rnode;
goto out;
+ }
shift = (height-1) * RADIX_TREE_MAP_SHIFT;
slot = root->rnode;
@@ -603,10 +642,16 @@ __lookup_tag(struct radix_tree_root *root, void **results, unsigned long index,
unsigned int height = root->height;
struct radix_tree_node *slot;
+ if (height == 0) {
+ if (root->rnode && index == 0)
+ results[nr_found++] = root->rnode;
+ goto out;
+ }
+
shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
slot = root->rnode;
- while (height > 0) {
+ do {
unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK;
for ( ; i < RADIX_TREE_MAP_SIZE; i++) {
@@ -637,7 +682,7 @@ __lookup_tag(struct radix_tree_root *root, void **results, unsigned long index,
}
shift -= RADIX_TREE_MAP_SHIFT;
slot = slot->slots[i];
- }
+ } while (height > 0);
out:
*next_index = index;
return nr_found;
@@ -665,6 +710,10 @@ radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results,
unsigned long cur_index = first_index;
unsigned int ret = 0;
+ /* check the root's tag bit */
+ if (!root_tag_get(root, tag))
+ return 0;
+
while (ret < max_items) {
unsigned int nr_found;
unsigned long next_index; /* Index of next search */
@@ -689,7 +738,7 @@ EXPORT_SYMBOL(radix_tree_gang_lookup_tag);
static inline void radix_tree_shrink(struct radix_tree_root *root)
{
/* try to shrink tree height */
- while (root->height > 1 &&
+ while (root->height > 0 &&
root->rnode->count == 1 &&
root->rnode->slots[0]) {
struct radix_tree_node *to_free = root->rnode;
@@ -717,12 +766,8 @@ static inline void radix_tree_shrink(struct radix_tree_root *root)
void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
{
struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path;
- struct radix_tree_path *orig_pathp;
- struct radix_tree_node *slot;
+ struct radix_tree_node *slot = NULL;
unsigned int height, shift;
- void *ret = NULL;
- char tags[RADIX_TREE_MAX_TAGS];
- int nr_cleared_tags;
int tag;
int offset;
@@ -730,11 +775,17 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
if (index > radix_tree_maxindex(height))
goto out;
+ slot = root->rnode;
+ if (height == 0 && root->rnode) {
+ root_tag_clear_all(root);
+ root->rnode = NULL;
+ goto out;
+ }
+
shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
pathp->node = NULL;
- slot = root->rnode;
- for ( ; height > 0; height--) {
+ do {
if (slot == NULL)
goto out;
@@ -744,44 +795,22 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
pathp->node = slot;
slot = slot->slots[offset];
shift -= RADIX_TREE_MAP_SHIFT;
- }
+ height--;
+ } while (height > 0);
- ret = slot;
- if (ret == NULL)
+ if (slot == NULL)
goto out;
- orig_pathp = pathp;
-
/*
* Clear all tags associated with the just-deleted item
*/
- nr_cleared_tags = 0;
for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
- tags[tag] = 1;
- if (tag_get(pathp->node, tag, pathp->offset)) {
- tag_clear(pathp->node, tag, pathp->offset);
- if (!any_tag_set(pathp->node, tag)) {
- tags[tag] = 0;
- nr_cleared_tags++;
- }
- }
- }
-
- for (pathp--; nr_cleared_tags && pathp->node; pathp--) {
- for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
- if (tags[tag])
- continue;
-
- tag_clear(pathp->node, tag, pathp->offset);
- if (any_tag_set(pathp->node, tag)) {
- tags[tag] = 1;
- nr_cleared_tags--;
- }
- }
+ if (tag_get(pathp->node, tag, pathp->offset))
+ radix_tree_tag_clear(root, index, tag);
}
/* Now free the nodes we do not need anymore */
- for (pathp = orig_pathp; pathp->node; pathp--) {
+ while (pathp->node) {
pathp->node->slots[pathp->offset] = NULL;
pathp->node->count--;
@@ -793,11 +822,15 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
/* Node with zero slots in use so free it */
radix_tree_node_free(pathp->node);
+
+ pathp--;
}
- root->rnode = NULL;
+ root_tag_clear_all(root);
root->height = 0;
+ root->rnode = NULL;
+
out:
- return ret;
+ return slot;
}
EXPORT_SYMBOL(radix_tree_delete);
@@ -808,11 +841,7 @@ EXPORT_SYMBOL(radix_tree_delete);
*/
int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag)
{
- struct radix_tree_node *rnode;
- rnode = root->rnode;
- if (!rnode)
- return 0;
- return any_tag_set(rnode, tag);
+ return root_tag_get(root, tag);
}
EXPORT_SYMBOL(radix_tree_tagged);
diff --git a/lib/reed_solomon/reed_solomon.c b/lib/reed_solomon/reed_solomon.c
index f8ac9fa..2cc11fa 100644
--- a/lib/reed_solomon/reed_solomon.c
+++ b/lib/reed_solomon/reed_solomon.c
@@ -54,7 +54,6 @@ static DEFINE_MUTEX(rslistlock);
/**
* rs_init - Initialize a Reed-Solomon codec
- *
* @symsize: symbol size, bits (1-8)
* @gfpoly: Field generator polynomial coefficients
* @fcr: first root of RS code generator polynomial, index form
@@ -62,7 +61,7 @@ static DEFINE_MUTEX(rslistlock);
* @nroots: RS code generator polynomial degree (number of roots)
*
* Allocate a control structure and the polynom arrays for faster
- * en/decoding. Fill the arrays according to the given parameters
+ * en/decoding. Fill the arrays according to the given parameters.
*/
static struct rs_control *rs_init(int symsize, int gfpoly, int fcr,
int prim, int nroots)
@@ -155,8 +154,7 @@ errrs:
/**
- * free_rs - Free the rs control structure, if its not longer used
- *
+ * free_rs - Free the rs control structure, if it is no longer used
* @rs: the control structure which is not longer used by the
* caller
*/
@@ -176,7 +174,6 @@ void free_rs(struct rs_control *rs)
/**
* init_rs - Find a matching or allocate a new rs control structure
- *
* @symsize: the symbol size (number of bits)
* @gfpoly: the extended Galois field generator polynomial coefficients,
* with the 0th coefficient in the low order bit. The polynomial
@@ -236,7 +233,6 @@ out:
#ifdef CONFIG_REED_SOLOMON_ENC8
/**
* encode_rs8 - Calculate the parity for data values (8bit data width)
- *
* @rs: the rs control structure
* @data: data field of a given type
* @len: data length
@@ -258,7 +254,6 @@ EXPORT_SYMBOL_GPL(encode_rs8);
#ifdef CONFIG_REED_SOLOMON_DEC8
/**
* decode_rs8 - Decode codeword (8bit data width)
- *
* @rs: the rs control structure
* @data: data field of a given type
* @par: received parity data field
@@ -285,7 +280,6 @@ EXPORT_SYMBOL_GPL(decode_rs8);
#ifdef CONFIG_REED_SOLOMON_ENC16
/**
* encode_rs16 - Calculate the parity for data values (16bit data width)
- *
* @rs: the rs control structure
* @data: data field of a given type
* @len: data length
@@ -305,7 +299,6 @@ EXPORT_SYMBOL_GPL(encode_rs16);
#ifdef CONFIG_REED_SOLOMON_DEC16
/**
* decode_rs16 - Decode codeword (16bit data width)
- *
* @rs: the rs control structure
* @data: data field of a given type
* @par: received parity data field
diff --git a/lib/string.c b/lib/string.c
index 064f631..6307726 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -301,6 +301,36 @@ char *strnchr(const char *s, size_t count, int c)
EXPORT_SYMBOL(strnchr);
#endif
+/**
+ * strstrip - Removes leading and trailing whitespace from @s.
+ * @s: The string to be stripped.
+ *
+ * Note that the first trailing whitespace is replaced with a %NUL-terminator
+ * in the given string @s. Returns a pointer to the first non-whitespace
+ * character in @s.
+ */
+char *strstrip(char *s)
+{
+ size_t size;
+ char *end;
+
+ size = strlen(s);
+
+ if (!size)
+ return s;
+
+ end = s + size - 1;
+ while (end != s && isspace(*end))
+ end--;
+ *(end + 1) = '\0';
+
+ while (*s && isspace(*s))
+ s++;
+
+ return s;
+}
+EXPORT_SYMBOL(strstrip);
+
#ifndef __HAVE_ARCH_STRLEN
/**
* strlen - Find the length of a string
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index b07db5c..797428a 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -187,49 +187,49 @@ static char * number(char * buf, char * end, unsigned long long num, int base, i
size -= precision;
if (!(type&(ZEROPAD+LEFT))) {
while(size-->0) {
- if (buf <= end)
+ if (buf < end)
*buf = ' ';
++buf;
}
}
if (sign) {
- if (buf <= end)
+ if (buf < end)
*buf = sign;
++buf;
}
if (type & SPECIAL) {
if (base==8) {
- if (buf <= end)
+ if (buf < end)
*buf = '0';
++buf;
} else if (base==16) {
- if (buf <= end)
+ if (buf < end)
*buf = '0';
++buf;
- if (buf <= end)
+ if (buf < end)
*buf = digits[33];
++buf;
}
}
if (!(type & LEFT)) {
while (size-- > 0) {
- if (buf <= end)
+ if (buf < end)
*buf = c;
++buf;
}
}
while (i < precision--) {
- if (buf <= end)
+ if (buf < end)
*buf = '0';
++buf;
}
while (i-- > 0) {
- if (buf <= end)
+ if (buf < end)
*buf = tmp[i];
++buf;
}
while (size-- > 0) {
- if (buf <= end)
+ if (buf < end)
*buf = ' ';
++buf;
}
@@ -272,7 +272,8 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
/* 'z' changed to 'Z' --davidm 1/25/99 */
/* 't' added for ptrdiff_t */
- /* Reject out-of-range values early */
+ /* Reject out-of-range values early. Large positive sizes are
+ used for unknown buffer sizes. */
if (unlikely((int) size < 0)) {
/* There can be only one.. */
static int warn = 1;
@@ -282,16 +283,17 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
}
str = buf;
- end = buf + size - 1;
+ end = buf + size;
- if (end < buf - 1) {
- end = ((void *) -1);
- size = end - buf + 1;
+ /* Make sure end is always >= buf */
+ if (end < buf) {
+ end = ((void *)-1);
+ size = end - buf;
}
for (; *fmt ; ++fmt) {
if (*fmt != '%') {
- if (str <= end)
+ if (str < end)
*str = *fmt;
++str;
continue;
@@ -357,17 +359,17 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
case 'c':
if (!(flags & LEFT)) {
while (--field_width > 0) {
- if (str <= end)
+ if (str < end)
*str = ' ';
++str;
}
}
c = (unsigned char) va_arg(args, int);
- if (str <= end)
+ if (str < end)
*str = c;
++str;
while (--field_width > 0) {
- if (str <= end)
+ if (str < end)
*str = ' ';
++str;
}
@@ -382,18 +384,18 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
if (!(flags & LEFT)) {
while (len < field_width--) {
- if (str <= end)
+ if (str < end)
*str = ' ';
++str;
}
}
for (i = 0; i < len; ++i) {
- if (str <= end)
+ if (str < end)
*str = *s;
++str; ++s;
}
while (len < field_width--) {
- if (str <= end)
+ if (str < end)
*str = ' ';
++str;
}
@@ -426,7 +428,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
continue;
case '%':
- if (str <= end)
+ if (str < end)
*str = '%';
++str;
continue;
@@ -449,11 +451,11 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
break;
default:
- if (str <= end)
+ if (str < end)
*str = '%';
++str;
if (*fmt) {
- if (str <= end)
+ if (str < end)
*str = *fmt;
++str;
} else {
@@ -483,14 +485,13 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
str = number(str, end, num, base,
field_width, precision, flags);
}
- if (str <= end)
- *str = '\0';
- else if (size > 0)
- /* don't write out a null byte if the buf size is zero */
- *end = '\0';
- /* the trailing null byte doesn't count towards the total
- * ++str;
- */
+ if (size > 0) {
+ if (str < end)
+ *str = '\0';
+ else
+ *end = '\0';
+ }
+ /* the trailing null byte doesn't count towards the total */
return str-buf;
}
@@ -848,3 +849,26 @@ int sscanf(const char * buf, const char * fmt, ...)
}
EXPORT_SYMBOL(sscanf);
+
+
+/* Simplified asprintf. */
+char *kasprintf(gfp_t gfp, const char *fmt, ...)
+{
+ va_list ap;
+ unsigned int len;
+ char *p;
+
+ va_start(ap, fmt);
+ len = vsnprintf(NULL, 0, fmt, ap);
+ va_end(ap);
+
+ p = kmalloc(len+1, gfp);
+ if (!p)
+ return NULL;
+ va_start(ap, fmt);
+ vsnprintf(p, len+1, fmt, ap);
+ va_end(ap);
+ return p;
+}
+
+EXPORT_SYMBOL(kasprintf);
diff --git a/lib/zlib_deflate/deflate.c b/lib/zlib_deflate/deflate.c
index 1653dd9..c3e4a2ba 100644
--- a/lib/zlib_deflate/deflate.c
+++ b/lib/zlib_deflate/deflate.c
@@ -164,34 +164,17 @@ static const config configuration_table[10] = {
memset((char *)s->head, 0, (unsigned)(s->hash_size-1)*sizeof(*s->head));
/* ========================================================================= */
-int zlib_deflateInit_(
- z_streamp strm,
- int level,
- const char *version,
- int stream_size
-)
-{
- return zlib_deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS,
- DEF_MEM_LEVEL,
- Z_DEFAULT_STRATEGY, version, stream_size);
- /* To do: ignore strm->next_in if we use it as window */
-}
-
-/* ========================================================================= */
-int zlib_deflateInit2_(
+int zlib_deflateInit2(
z_streamp strm,
int level,
int method,
int windowBits,
int memLevel,
- int strategy,
- const char *version,
- int stream_size
+ int strategy
)
{
deflate_state *s;
int noheader = 0;
- static char* my_version = ZLIB_VERSION;
deflate_workspace *mem;
ush *overlay;
@@ -199,10 +182,6 @@ int zlib_deflateInit2_(
* output size for (length,distance) codes is <= 24 bits.
*/
- if (version == NULL || version[0] != my_version[0] ||
- stream_size != sizeof(z_stream)) {
- return Z_VERSION_ERROR;
- }
if (strm == NULL) return Z_STREAM_ERROR;
strm->msg = NULL;
diff --git a/lib/zlib_deflate/deflate_syms.c b/lib/zlib_deflate/deflate_syms.c
index 767b573..ccfe25f 100644
--- a/lib/zlib_deflate/deflate_syms.c
+++ b/lib/zlib_deflate/deflate_syms.c
@@ -12,8 +12,7 @@
EXPORT_SYMBOL(zlib_deflate_workspacesize);
EXPORT_SYMBOL(zlib_deflate);
-EXPORT_SYMBOL(zlib_deflateInit_);
-EXPORT_SYMBOL(zlib_deflateInit2_);
+EXPORT_SYMBOL(zlib_deflateInit2);
EXPORT_SYMBOL(zlib_deflateEnd);
EXPORT_SYMBOL(zlib_deflateReset);
MODULE_LICENSE("GPL");
diff --git a/lib/zlib_inflate/Makefile b/lib/zlib_inflate/Makefile
index 221c139..bf06548 100644
--- a/lib/zlib_inflate/Makefile
+++ b/lib/zlib_inflate/Makefile
@@ -15,5 +15,5 @@
obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate.o
-zlib_inflate-objs := infblock.o infcodes.o inffast.o inflate.o \
- inflate_sync.o inftrees.o infutil.o inflate_syms.o
+zlib_inflate-objs := inffast.o inflate.o \
+ inftrees.o inflate_syms.o
diff --git a/lib/zlib_inflate/infblock.c b/lib/zlib_inflate/infblock.c
deleted file mode 100644
index c16cdef..0000000
--- a/lib/zlib_inflate/infblock.c
+++ /dev/null
@@ -1,365 +0,0 @@
-/* infblock.c -- interpret and process block types to last block
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h
- */
-
-#include <linux/zutil.h>
-#include "infblock.h"
-#include "inftrees.h"
-#include "infcodes.h"
-#include "infutil.h"
-
-struct inflate_codes_state;
-
-/* simplify the use of the inflate_huft type with some defines */
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-/* Table for deflate from PKZIP's appnote.txt. */
-static const uInt border[] = { /* Order of the bit length code lengths */
- 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
-
-/*
- Notes beyond the 1.93a appnote.txt:
-
- 1. Distance pointers never point before the beginning of the output
- stream.
- 2. Distance pointers can point back across blocks, up to 32k away.
- 3. There is an implied maximum of 7 bits for the bit length table and
- 15 bits for the actual data.
- 4. If only one code exists, then it is encoded using one bit. (Zero
- would be more efficient, but perhaps a little confusing.) If two
- codes exist, they are coded using one bit each (0 and 1).
- 5. There is no way of sending zero distance codes--a dummy must be
- sent if there are none. (History: a pre 2.0 version of PKZIP would
- store blocks with no distance codes, but this was discovered to be
- too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
- zero distance codes, which is sent as one code of zero bits in
- length.
- 6. There are up to 286 literal/length codes. Code 256 represents the
- end-of-block. Note however that the static length tree defines
- 288 codes just to fill out the Huffman codes. Codes 286 and 287
- cannot be used though, since there is no length base or extra bits
- defined for them. Similarily, there are up to 30 distance codes.
- However, static trees define 32 codes (all 5 bits) to fill out the
- Huffman codes, but the last two had better not show up in the data.
- 7. Unzip can check dynamic Huffman blocks for complete code sets.
- The exception is that a single code would not be complete (see #4).
- 8. The five bits following the block type is really the number of
- literal codes sent minus 257.
- 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
- (1+6+6). Therefore, to output three times the length, you output
- three codes (1+1+1), whereas to output four times the same length,
- you only need two codes (1+3). Hmm.
- 10. In the tree reconstruction algorithm, Code = Code + Increment
- only if BitLength(i) is not zero. (Pretty obvious.)
- 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
- 12. Note: length code 284 can represent 227-258, but length code 285
- really is 258. The last length deserves its own, short code
- since it gets used a lot in very redundant files. The length
- 258 is special since 258 - 3 (the min match length) is 255.
- 13. The literal/length and distance code bit lengths are read as a
- single stream of lengths. It is possible (and advantageous) for
- a repeat code (16, 17, or 18) to go across the boundary between
- the two sets of lengths.
- */
-
-
-void zlib_inflate_blocks_reset(
- inflate_blocks_statef *s,
- z_streamp z,
- uLong *c
-)
-{
- if (c != NULL)
- *c = s->check;
- if (s->mode == CODES)
- zlib_inflate_codes_free(s->sub.decode.codes, z);
- s->mode = TYPE;
- s->bitk = 0;
- s->bitb = 0;
- s->read = s->write = s->window;
- if (s->checkfn != NULL)
- z->adler = s->check = (*s->checkfn)(0L, NULL, 0);
-}
-
-inflate_blocks_statef *zlib_inflate_blocks_new(
- z_streamp z,
- check_func c,
- uInt w
-)
-{
- inflate_blocks_statef *s;
-
- s = &WS(z)->working_blocks_state;
- s->hufts = WS(z)->working_hufts;
- s->window = WS(z)->working_window;
- s->end = s->window + w;
- s->checkfn = c;
- s->mode = TYPE;
- zlib_inflate_blocks_reset(s, z, NULL);
- return s;
-}
-
-
-int zlib_inflate_blocks(
- inflate_blocks_statef *s,
- z_streamp z,
- int r
-)
-{
- uInt t; /* temporary storage */
- uLong b; /* bit buffer */
- uInt k; /* bits in bit buffer */
- Byte *p; /* input data pointer */
- uInt n; /* bytes available there */
- Byte *q; /* output window write pointer */
- uInt m; /* bytes to end of window or read pointer */
-
- /* copy input/output information to locals (UPDATE macro restores) */
- LOAD
-
- /* process input based on current state */
- while (1) switch (s->mode)
- {
- case TYPE:
- NEEDBITS(3)
- t = (uInt)b & 7;
- s->last = t & 1;
- switch (t >> 1)
- {
- case 0: /* stored */
- DUMPBITS(3)
- t = k & 7; /* go to byte boundary */
- DUMPBITS(t)
- s->mode = LENS; /* get length of stored block */
- break;
- case 1: /* fixed */
- {
- uInt bl, bd;
- inflate_huft *tl, *td;
-
- zlib_inflate_trees_fixed(&bl, &bd, &tl, &td, s->hufts, z);
- s->sub.decode.codes = zlib_inflate_codes_new(bl, bd, tl, td, z);
- if (s->sub.decode.codes == NULL)
- {
- r = Z_MEM_ERROR;
- LEAVE
- }
- }
- DUMPBITS(3)
- s->mode = CODES;
- break;
- case 2: /* dynamic */
- DUMPBITS(3)
- s->mode = TABLE;
- break;
- case 3: /* illegal */
- DUMPBITS(3)
- s->mode = B_BAD;
- z->msg = (char*)"invalid block type";
- r = Z_DATA_ERROR;
- LEAVE
- }
- break;
- case LENS:
- NEEDBITS(32)
- if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
- {
- s->mode = B_BAD;
- z->msg = (char*)"invalid stored block lengths";
- r = Z_DATA_ERROR;
- LEAVE
- }
- s->sub.left = (uInt)b & 0xffff;
- b = k = 0; /* dump bits */
- s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
- break;
- case STORED:
- if (n == 0)
- LEAVE
- NEEDOUT
- t = s->sub.left;
- if (t > n) t = n;
- if (t > m) t = m;
- memcpy(q, p, t);
- p += t; n -= t;
- q += t; m -= t;
- if ((s->sub.left -= t) != 0)
- break;
- s->mode = s->last ? DRY : TYPE;
- break;
- case TABLE:
- NEEDBITS(14)
- s->sub.trees.table = t = (uInt)b & 0x3fff;
-#ifndef PKZIP_BUG_WORKAROUND
- if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
- {
- s->mode = B_BAD;
- z->msg = (char*)"too many length or distance symbols";
- r = Z_DATA_ERROR;
- LEAVE
- }
-#endif
- {
- s->sub.trees.blens = WS(z)->working_blens;
- }
- DUMPBITS(14)
- s->sub.trees.index = 0;
- s->mode = BTREE;
- case BTREE:
- while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
- {
- NEEDBITS(3)
- s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
- DUMPBITS(3)
- }
- while (s->sub.trees.index < 19)
- s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
- s->sub.trees.bb = 7;
- t = zlib_inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
- &s->sub.trees.tb, s->hufts, z);
- if (t != Z_OK)
- {
- r = t;
- if (r == Z_DATA_ERROR)
- s->mode = B_BAD;
- LEAVE
- }
- s->sub.trees.index = 0;
- s->mode = DTREE;
- case DTREE:
- while (t = s->sub.trees.table,
- s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
- {
- inflate_huft *h;
- uInt i, j, c;
-
- t = s->sub.trees.bb;
- NEEDBITS(t)
- h = s->sub.trees.tb + ((uInt)b & zlib_inflate_mask[t]);
- t = h->bits;
- c = h->base;
- if (c < 16)
- {
- DUMPBITS(t)
- s->sub.trees.blens[s->sub.trees.index++] = c;
- }
- else /* c == 16..18 */
- {
- i = c == 18 ? 7 : c - 14;
- j = c == 18 ? 11 : 3;
- NEEDBITS(t + i)
- DUMPBITS(t)
- j += (uInt)b & zlib_inflate_mask[i];
- DUMPBITS(i)
- i = s->sub.trees.index;
- t = s->sub.trees.table;
- if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
- (c == 16 && i < 1))
- {
- s->mode = B_BAD;
- z->msg = (char*)"invalid bit length repeat";
- r = Z_DATA_ERROR;
- LEAVE
- }
- c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
- do {
- s->sub.trees.blens[i++] = c;
- } while (--j);
- s->sub.trees.index = i;
- }
- }
- s->sub.trees.tb = NULL;
- {
- uInt bl, bd;
- inflate_huft *tl, *td;
- inflate_codes_statef *c;
-
- bl = 9; /* must be <= 9 for lookahead assumptions */
- bd = 6; /* must be <= 9 for lookahead assumptions */
- t = s->sub.trees.table;
- t = zlib_inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
- s->sub.trees.blens, &bl, &bd, &tl, &td,
- s->hufts, z);
- if (t != Z_OK)
- {
- if (t == (uInt)Z_DATA_ERROR)
- s->mode = B_BAD;
- r = t;
- LEAVE
- }
- if ((c = zlib_inflate_codes_new(bl, bd, tl, td, z)) == NULL)
- {
- r = Z_MEM_ERROR;
- LEAVE
- }
- s->sub.decode.codes = c;
- }
- s->mode = CODES;
- case CODES:
- UPDATE
- if ((r = zlib_inflate_codes(s, z, r)) != Z_STREAM_END)
- return zlib_inflate_flush(s, z, r);
- r = Z_OK;
- zlib_inflate_codes_free(s->sub.decode.codes, z);
- LOAD
- if (!s->last)
- {
- s->mode = TYPE;
- break;
- }
- s->mode = DRY;
- case DRY:
- FLUSH
- if (s->read != s->write)
- LEAVE
- s->mode = B_DONE;
- case B_DONE:
- r = Z_STREAM_END;
- LEAVE
- case B_BAD:
- r = Z_DATA_ERROR;
- LEAVE
- default:
- r = Z_STREAM_ERROR;
- LEAVE
- }
-}
-
-
-int zlib_inflate_blocks_free(
- inflate_blocks_statef *s,
- z_streamp z
-)
-{
- zlib_inflate_blocks_reset(s, z, NULL);
- return Z_OK;
-}
-
-
-#if 0
-void zlib_inflate_set_dictionary(
- inflate_blocks_statef *s,
- const Byte *d,
- uInt n
-)
-{
- memcpy(s->window, d, n);
- s->read = s->write = s->window + n;
-}
-#endif /* 0 */
-
-
-/* Returns true if inflate is currently at the end of a block generated
- * by Z_SYNC_FLUSH or Z_FULL_FLUSH.
- * IN assertion: s != NULL
- */
-#if 0
-int zlib_inflate_blocks_sync_point(
- inflate_blocks_statef *s
-)
-{
- return s->mode == LENS;
-}
-#endif /* 0 */
diff --git a/lib/zlib_inflate/infblock.h b/lib/zlib_inflate/infblock.h
deleted file mode 100644
index ceee60b..0000000
--- a/lib/zlib_inflate/infblock.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* infblock.h -- header to use infblock.c
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h
- */
-
-/* WARNING: this file should *not* be used by applications. It is
- part of the implementation of the compression library and is
- subject to change. Applications should only use zlib.h.
- */
-
-#ifndef _INFBLOCK_H
-#define _INFBLOCK_H
-
-struct inflate_blocks_state;
-typedef struct inflate_blocks_state inflate_blocks_statef;
-
-extern inflate_blocks_statef * zlib_inflate_blocks_new (
- z_streamp z,
- check_func c, /* check function */
- uInt w); /* window size */
-
-extern int zlib_inflate_blocks (
- inflate_blocks_statef *,
- z_streamp ,
- int); /* initial return code */
-
-extern void zlib_inflate_blocks_reset (
- inflate_blocks_statef *,
- z_streamp ,
- uLong *); /* check value on output */
-
-extern int zlib_inflate_blocks_free (
- inflate_blocks_statef *,
- z_streamp);
-
-#if 0
-extern void zlib_inflate_set_dictionary (
- inflate_blocks_statef *s,
- const Byte *d, /* dictionary */
- uInt n); /* dictionary length */
-#endif /* 0 */
-
-#if 0
-extern int zlib_inflate_blocks_sync_point (
- inflate_blocks_statef *s);
-#endif /* 0 */
-
-#endif /* _INFBLOCK_H */
diff --git a/lib/zlib_inflate/infcodes.c b/lib/zlib_inflate/infcodes.c
deleted file mode 100644
index 07cd759..0000000
--- a/lib/zlib_inflate/infcodes.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/* infcodes.c -- process literals and length/distance pairs
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h
- */
-
-#include <linux/zutil.h>
-#include "inftrees.h"
-#include "infblock.h"
-#include "infcodes.h"
-#include "infutil.h"
-#include "inffast.h"
-
-/* simplify the use of the inflate_huft type with some defines */
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-inflate_codes_statef *zlib_inflate_codes_new(
- uInt bl,
- uInt bd,
- inflate_huft *tl,
- inflate_huft *td, /* need separate declaration for Borland C++ */
- z_streamp z
-)
-{
- inflate_codes_statef *c;
-
- c = &WS(z)->working_state;
- {
- c->mode = START;
- c->lbits = (Byte)bl;
- c->dbits = (Byte)bd;
- c->ltree = tl;
- c->dtree = td;
- }
- return c;
-}
-
-
-int zlib_inflate_codes(
- inflate_blocks_statef *s,
- z_streamp z,
- int r
-)
-{
- uInt j; /* temporary storage */
- inflate_huft *t; /* temporary pointer */
- uInt e; /* extra bits or operation */
- uLong b; /* bit buffer */
- uInt k; /* bits in bit buffer */
- Byte *p; /* input data pointer */
- uInt n; /* bytes available there */
- Byte *q; /* output window write pointer */
- uInt m; /* bytes to end of window or read pointer */
- Byte *f; /* pointer to copy strings from */
- inflate_codes_statef *c = s->sub.decode.codes; /* codes state */
-
- /* copy input/output information to locals (UPDATE macro restores) */
- LOAD
-
- /* process input and output based on current state */
- while (1) switch (c->mode)
- { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
- case START: /* x: set up for LEN */
-#ifndef SLOW
- if (m >= 258 && n >= 10)
- {
- UPDATE
- r = zlib_inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
- LOAD
- if (r != Z_OK)
- {
- c->mode = r == Z_STREAM_END ? WASH : BADCODE;
- break;
- }
- }
-#endif /* !SLOW */
- c->sub.code.need = c->lbits;
- c->sub.code.tree = c->ltree;
- c->mode = LEN;
- case LEN: /* i: get length/literal/eob next */
- j = c->sub.code.need;
- NEEDBITS(j)
- t = c->sub.code.tree + ((uInt)b & zlib_inflate_mask[j]);
- DUMPBITS(t->bits)
- e = (uInt)(t->exop);
- if (e == 0) /* literal */
- {
- c->sub.lit = t->base;
- c->mode = LIT;
- break;
- }
- if (e & 16) /* length */
- {
- c->sub.copy.get = e & 15;
- c->len = t->base;
- c->mode = LENEXT;
- break;
- }
- if ((e & 64) == 0) /* next table */
- {
- c->sub.code.need = e;
- c->sub.code.tree = t + t->base;
- break;
- }
- if (e & 32) /* end of block */
- {
- c->mode = WASH;
- break;
- }
- c->mode = BADCODE; /* invalid code */
- z->msg = (char*)"invalid literal/length code";
- r = Z_DATA_ERROR;
- LEAVE
- case LENEXT: /* i: getting length extra (have base) */
- j = c->sub.copy.get;
- NEEDBITS(j)
- c->len += (uInt)b & zlib_inflate_mask[j];
- DUMPBITS(j)
- c->sub.code.need = c->dbits;
- c->sub.code.tree = c->dtree;
- c->mode = DIST;
- case DIST: /* i: get distance next */
- j = c->sub.code.need;
- NEEDBITS(j)
- t = c->sub.code.tree + ((uInt)b & zlib_inflate_mask[j]);
- DUMPBITS(t->bits)
- e = (uInt)(t->exop);
- if (e & 16) /* distance */
- {
- c->sub.copy.get = e & 15;
- c->sub.copy.dist = t->base;
- c->mode = DISTEXT;
- break;
- }
- if ((e & 64) == 0) /* next table */
- {
- c->sub.code.need = e;
- c->sub.code.tree = t + t->base;
- break;
- }
- c->mode = BADCODE; /* invalid code */
- z->msg = (char*)"invalid distance code";
- r = Z_DATA_ERROR;
- LEAVE
- case DISTEXT: /* i: getting distance extra */
- j = c->sub.copy.get;
- NEEDBITS(j)
- c->sub.copy.dist += (uInt)b & zlib_inflate_mask[j];
- DUMPBITS(j)
- c->mode = COPY;
- case COPY: /* o: copying bytes in window, waiting for space */
- f = q - c->sub.copy.dist;
- while (f < s->window) /* modulo window size-"while" instead */
- f += s->end - s->window; /* of "if" handles invalid distances */
- while (c->len)
- {
- NEEDOUT
- OUTBYTE(*f++)
- if (f == s->end)
- f = s->window;
- c->len--;
- }
- c->mode = START;
- break;
- case LIT: /* o: got literal, waiting for output space */
- NEEDOUT
- OUTBYTE(c->sub.lit)
- c->mode = START;
- break;
- case WASH: /* o: got eob, possibly more output */
- if (k > 7) /* return unused byte, if any */
- {
- k -= 8;
- n++;
- p--; /* can always return one */
- }
- FLUSH
- if (s->read != s->write)
- LEAVE
- c->mode = END;
- case END:
- r = Z_STREAM_END;
- LEAVE
- case BADCODE: /* x: got error */
- r = Z_DATA_ERROR;
- LEAVE
- default:
- r = Z_STREAM_ERROR;
- LEAVE
- }
-#ifdef NEED_DUMMY_RETURN
- return Z_STREAM_ERROR; /* Some dumb compilers complain without this */
-#endif
-}
-
-
-void zlib_inflate_codes_free(
- inflate_codes_statef *c,
- z_streamp z
-)
-{
-}
diff --git a/lib/zlib_inflate/infcodes.h b/lib/zlib_inflate/infcodes.h
deleted file mode 100644
index 5cff417..0000000
--- a/lib/zlib_inflate/infcodes.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* infcodes.h -- header to use infcodes.c
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h
- */
-
-/* WARNING: this file should *not* be used by applications. It is
- part of the implementation of the compression library and is
- subject to change. Applications should only use zlib.h.
- */
-
-#ifndef _INFCODES_H
-#define _INFCODES_H
-
-#include "infblock.h"
-
-struct inflate_codes_state;
-typedef struct inflate_codes_state inflate_codes_statef;
-
-extern inflate_codes_statef *zlib_inflate_codes_new (
- uInt, uInt,
- inflate_huft *, inflate_huft *,
- z_streamp );
-
-extern int zlib_inflate_codes (
- inflate_blocks_statef *,
- z_streamp ,
- int);
-
-extern void zlib_inflate_codes_free (
- inflate_codes_statef *,
- z_streamp );
-
-#endif /* _INFCODES_H */
diff --git a/lib/zlib_inflate/inffast.c b/lib/zlib_inflate/inffast.c
index 0bd7623..02a16ea 100644
--- a/lib/zlib_inflate/inffast.c
+++ b/lib/zlib_inflate/inffast.c
@@ -1,176 +1,312 @@
-/* inffast.c -- process literals and length/distance pairs fast
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
*/
#include <linux/zutil.h>
#include "inftrees.h"
-#include "infblock.h"
-#include "infcodes.h"
-#include "infutil.h"
+#include "inflate.h"
#include "inffast.h"
-struct inflate_codes_state;
-
-/* simplify the use of the inflate_huft type with some defines */
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-/* macros for bit input with no checking and for returning unused bytes */
-#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
-#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}
-
-/* Called with number of bytes left to write in window at least 258
- (the maximum string length) and number of input bytes available
- at least ten. The ten bytes are six bytes for the longest length/
- distance pair plus four bytes for overloading the bit buffer. */
-
-int zlib_inflate_fast(
- uInt bl,
- uInt bd,
- inflate_huft *tl,
- inflate_huft *td, /* need separate declaration for Borland C++ */
- inflate_blocks_statef *s,
- z_streamp z
-)
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+ Based on testing to date,
+ Pre-increment preferred for:
+ - PowerPC G3 (Adler)
+ - MIPS R5000 (Randers-Pehrson)
+ Post-increment preferred for:
+ - none
+ No measurable difference:
+ - Pentium III (Anderson)
+ - M68060 (Nikl)
+ */
+#ifdef POSTINC
+# define OFF 0
+# define PUP(a) *(a)++
+#else
+# define OFF 1
+# define PUP(a) *++(a)
+#endif
+
+/*
+ Decode literal, length, and distance codes and write out the resulting
+ literal and match bytes until either not enough input or output is
+ available, an end-of-block is encountered, or a data error is encountered.
+ When large enough input and output buffers are supplied to inflate(), for
+ example, a 16K input buffer and a 64K output buffer, more than 95% of the
+ inflate execution time is spent in this routine.
+
+ Entry assumptions:
+
+ state->mode == LEN
+ strm->avail_in >= 6
+ strm->avail_out >= 258
+ start >= strm->avail_out
+ state->bits < 8
+
+ On return, state->mode is one of:
+
+ LEN -- ran out of enough output space or enough available input
+ TYPE -- reached end of block code, inflate() to interpret next block
+ BAD -- error in block data
+
+ Notes:
+
+ - The maximum input bits used by a length/distance pair is 15 bits for the
+ length code, 5 bits for the length extra, 15 bits for the distance code,
+ and 13 bits for the distance extra. This totals 48 bits, or six bytes.
+ Therefore if strm->avail_in >= 6, then there is enough input to avoid
+ checking for available input while decoding.
+
+ - The maximum bytes that a single length/distance pair can output is 258
+ bytes, which is the maximum length that can be coded. inflate_fast()
+ requires strm->avail_out >= 258 for each loop to avoid checking for
+ output space.
+ */
+void inflate_fast(strm, start)
+z_streamp strm;
+unsigned start; /* inflate()'s starting value for strm->avail_out */
{
- inflate_huft *t; /* temporary pointer */
- uInt e; /* extra bits or operation */
- uLong b; /* bit buffer */
- uInt k; /* bits in bit buffer */
- Byte *p; /* input data pointer */
- uInt n; /* bytes available there */
- Byte *q; /* output window write pointer */
- uInt m; /* bytes to end of window or read pointer */
- uInt ml; /* mask for literal/length tree */
- uInt md; /* mask for distance tree */
- uInt c; /* bytes to copy */
- uInt d; /* distance back to copy from */
- Byte *r; /* copy source pointer */
-
- /* load input, output, bit values */
- LOAD
-
- /* initialize masks */
- ml = zlib_inflate_mask[bl];
- md = zlib_inflate_mask[bd];
-
- /* do until not enough input or output space for fast loop */
- do { /* assume called with m >= 258 && n >= 10 */
- /* get literal/length code */
- GRABBITS(20) /* max bits for literal/length code */
- if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
- {
- DUMPBITS(t->bits)
- *q++ = (Byte)t->base;
- m--;
- continue;
- }
+ struct inflate_state *state;
+ unsigned char *in; /* local strm->next_in */
+ unsigned char *last; /* while in < last, enough input available */
+ unsigned char *out; /* local strm->next_out */
+ unsigned char *beg; /* inflate()'s initial strm->next_out */
+ unsigned char *end; /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+ unsigned dmax; /* maximum distance from zlib header */
+#endif
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned write; /* window write index */
+ unsigned char *window; /* allocated sliding window, if wsize != 0 */
+ unsigned long hold; /* local strm->hold */
+ unsigned bits; /* local strm->bits */
+ code const *lcode; /* local strm->lencode */
+ code const *dcode; /* local strm->distcode */
+ unsigned lmask; /* mask for first level of length codes */
+ unsigned dmask; /* mask for first level of distance codes */
+ code this; /* retrieved table entry */
+ unsigned op; /* code bits, operation, extra bits, or */
+ /* window position, window bytes to copy */
+ unsigned len; /* match length, unused bytes */
+ unsigned dist; /* match distance */
+ unsigned char *from; /* where to copy match from */
+
+ /* copy state to local variables */
+ state = (struct inflate_state *)strm->state;
+ in = strm->next_in - OFF;
+ last = in + (strm->avail_in - 5);
+ out = strm->next_out - OFF;
+ beg = out - (start - strm->avail_out);
+ end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+ dmax = state->dmax;
+#endif
+ wsize = state->wsize;
+ whave = state->whave;
+ write = state->write;
+ window = state->window;
+ hold = state->hold;
+ bits = state->bits;
+ lcode = state->lencode;
+ dcode = state->distcode;
+ lmask = (1U << state->lenbits) - 1;
+ dmask = (1U << state->distbits) - 1;
+
+ /* decode literals and length/distances until end-of-block or not enough
+ input data or output space */
do {
- DUMPBITS(t->bits)
- if (e & 16)
- {
- /* get extra bits for length */
- e &= 15;
- c = t->base + ((uInt)b & zlib_inflate_mask[e]);
- DUMPBITS(e)
-
- /* decode distance base of block to copy */
- GRABBITS(15); /* max bits for distance code */
- e = (t = td + ((uInt)b & md))->exop;
- do {
- DUMPBITS(t->bits)
- if (e & 16)
- {
- /* get extra bits to add to distance base */
- e &= 15;
- GRABBITS(e) /* get extra bits (up to 13) */
- d = t->base + ((uInt)b & zlib_inflate_mask[e]);
- DUMPBITS(e)
-
- /* do the copy */
- m -= c;
- r = q - d;
- if (r < s->window) /* wrap if needed */
- {
- do {
- r += s->end - s->window; /* force pointer in window */
- } while (r < s->window); /* covers invalid distances */
- e = s->end - r;
- if (c > e)
- {
- c -= e; /* wrapped copy */
- do {
- *q++ = *r++;
- } while (--e);
- r = s->window;
- do {
- *q++ = *r++;
- } while (--c);
- }
- else /* normal copy */
- {
- *q++ = *r++; c--;
- *q++ = *r++; c--;
- do {
- *q++ = *r++;
- } while (--c);
- }
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ this = lcode[hold & lmask];
+ dolen:
+ op = (unsigned)(this.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(this.op);
+ if (op == 0) { /* literal */
+ PUP(out) = (unsigned char)(this.val);
+ }
+ else if (op & 16) { /* length base */
+ len = (unsigned)(this.val);
+ op &= 15; /* number of extra bits */
+ if (op) {
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ len += (unsigned)hold & ((1U << op) - 1);
+ hold >>= op;
+ bits -= op;
+ }
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ this = dcode[hold & dmask];
+ dodist:
+ op = (unsigned)(this.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(this.op);
+ if (op & 16) { /* distance base */
+ dist = (unsigned)(this.val);
+ op &= 15; /* number of extra bits */
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ }
+ dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+ if (dist > dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(out - beg); /* max distance in output */
+ if (dist > op) { /* see if copy from window */
+ op = dist - op; /* distance back in window */
+ if (op > whave) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ from = window - OFF;
+ if (write == 0) { /* very common case */
+ from += wsize - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ else if (write < op) { /* wrap around window */
+ from += wsize + write - op;
+ op -= write;
+ if (op < len) { /* some from end of window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = window - OFF;
+ if (write < len) { /* some from start of window */
+ op = write;
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ }
+ else { /* contiguous in window */
+ from += write - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ while (len > 2) {
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ }
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ else {
+ from = out - dist; /* copy direct from output */
+ do { /* minimum length is three */
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ } while (len > 2);
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level distance code */
+ this = dcode[this.val + (hold & ((1U << op) - 1))];
+ goto dodist;
}
- else /* normal copy */
- {
- *q++ = *r++; c--;
- *q++ = *r++; c--;
- do {
- *q++ = *r++;
- } while (--c);
+ else {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
}
+ }
+ else if ((op & 64) == 0) { /* 2nd level length code */
+ this = lcode[this.val + (hold & ((1U << op) - 1))];
+ goto dolen;
+ }
+ else if (op & 32) { /* end-of-block */
+ state->mode = TYPE;
break;
- }
- else if ((e & 64) == 0)
- {
- t += t->base;
- e = (t += ((uInt)b & zlib_inflate_mask[e]))->exop;
- }
- else
- {
- z->msg = (char*)"invalid distance code";
- UNGRAB
- UPDATE
- return Z_DATA_ERROR;
- }
- } while (1);
- break;
- }
- if ((e & 64) == 0)
- {
- t += t->base;
- if ((e = (t += ((uInt)b & zlib_inflate_mask[e]))->exop) == 0)
- {
- DUMPBITS(t->bits)
- *q++ = (Byte)t->base;
- m--;
- break;
}
- }
- else if (e & 32)
- {
- UNGRAB
- UPDATE
- return Z_STREAM_END;
- }
- else
- {
- z->msg = (char*)"invalid literal/length code";
- UNGRAB
- UPDATE
- return Z_DATA_ERROR;
- }
- } while (1);
- } while (m >= 258 && n >= 10);
-
- /* not enough input or output--restore pointers and return */
- UNGRAB
- UPDATE
- return Z_OK;
+ else {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ } while (in < last && out < end);
+
+ /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+ len = bits >> 3;
+ in -= len;
+ bits -= len << 3;
+ hold &= (1U << bits) - 1;
+
+ /* update state and return */
+ strm->next_in = in + OFF;
+ strm->next_out = out + OFF;
+ strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+ strm->avail_out = (unsigned)(out < end ?
+ 257 + (end - out) : 257 - (out - end));
+ state->hold = hold;
+ state->bits = bits;
+ return;
}
+
+/*
+ inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+ - Using bit fields for code structure
+ - Different op definition to avoid & for extra bits (do & for table bits)
+ - Three separate decoding do-loops for direct, window, and write == 0
+ - Special case for distance > 1 copies to do overlapped load and store copy
+ - Explicit branch predictions (based on measured branch probabilities)
+ - Deferring match copy and interspersed it with decoding subsequent codes
+ - Swapping literal/length else
+ - Swapping window/direct else
+ - Larger unrolled copy loops (three is about right)
+ - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
diff --git a/lib/zlib_inflate/inffast.h b/lib/zlib_inflate/inffast.h
index fc720f0..40315d9 100644
--- a/lib/zlib_inflate/inffast.h
+++ b/lib/zlib_inflate/inffast.h
@@ -1,6 +1,6 @@
/* inffast.h -- header to use inffast.c
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
*/
/* WARNING: this file should *not* be used by applications. It is
@@ -8,10 +8,4 @@
subject to change. Applications should only use zlib.h.
*/
-extern int zlib_inflate_fast (
- uInt,
- uInt,
- inflate_huft *,
- inflate_huft *,
- inflate_blocks_statef *,
- z_streamp );
+void inflate_fast (z_streamp strm, unsigned start);
diff --git a/lib/zlib_inflate/inffixed.h b/lib/zlib_inflate/inffixed.h
new file mode 100644
index 0000000..75ed4b5
--- /dev/null
+++ b/lib/zlib_inflate/inffixed.h
@@ -0,0 +1,94 @@
+ /* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by makefixed().
+ */
+
+ /* WARNING: this file should *not* be used by applications. It
+ is part of the implementation of the compression library and
+ is subject to change. Applications should only use zlib.h.
+ */
+
+ static const code lenfix[512] = {
+ {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+ {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+ {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+ {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+ {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+ {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+ {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+ {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+ {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+ {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+ {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+ {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+ {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+ {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+ {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+ {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+ {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+ {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+ {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+ {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+ {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+ {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+ {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+ {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+ {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+ {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+ {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+ {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+ {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+ {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+ {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+ {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+ {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+ {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+ {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+ {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+ {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+ {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+ {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+ {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+ {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+ {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+ {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+ {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+ {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+ {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+ {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+ {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+ {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+ {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+ {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+ {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+ {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+ {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+ {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+ {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+ {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+ {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+ {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+ {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+ {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+ {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+ {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+ {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+ {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+ {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+ {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+ {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+ {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+ {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+ {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+ {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+ {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+ {0,9,255}
+ };
+
+ static const code distfix[32] = {
+ {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+ {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+ {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+ {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+ {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+ {22,5,193},{64,5,0}
+ };
diff --git a/lib/zlib_inflate/inflate.c b/lib/zlib_inflate/inflate.c
index 31b9e90..7f922dc 100644
--- a/lib/zlib_inflate/inflate.c
+++ b/lib/zlib_inflate/inflate.c
@@ -1,89 +1,148 @@
-/* inflate.c -- zlib interface to inflate modules
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Based on zlib 1.2.3 but modified for the Linux Kernel by
+ * Richard Purdie <richard@openedhand.com>
+ *
+ * Changes mainly for static instead of dynamic memory allocation
+ *
*/
#include <linux/zutil.h>
-#include "infblock.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
#include "infutil.h"
int zlib_inflate_workspacesize(void)
{
- return sizeof(struct inflate_workspace);
+ return sizeof(struct inflate_workspace);
}
+int zlib_inflateReset(z_streamp strm)
+{
+ struct inflate_state *state;
+
+ if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state *)strm->state;
+ strm->total_in = strm->total_out = state->total = 0;
+ strm->msg = NULL;
+ strm->adler = 1; /* to support ill-conceived Java test suite */
+ state->mode = HEAD;
+ state->last = 0;
+ state->havedict = 0;
+ state->dmax = 32768U;
+ state->hold = 0;
+ state->bits = 0;
+ state->lencode = state->distcode = state->next = state->codes;
-int zlib_inflateReset(
- z_streamp z
-)
+ /* Initialise Window */
+ state->wsize = 1U << state->wbits;
+ state->write = 0;
+ state->whave = 0;
+
+ return Z_OK;
+}
+
+#if 0
+int zlib_inflatePrime(z_streamp strm, int bits, int value)
{
- if (z == NULL || z->state == NULL || z->workspace == NULL)
- return Z_STREAM_ERROR;
- z->total_in = z->total_out = 0;
- z->msg = NULL;
- z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
- zlib_inflate_blocks_reset(z->state->blocks, z, NULL);
- return Z_OK;
+ struct inflate_state *state;
+
+ if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state *)strm->state;
+ if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+ value &= (1L << bits) - 1;
+ state->hold += value << state->bits;
+ state->bits += bits;
+ return Z_OK;
}
+#endif
+
+int zlib_inflateInit2(z_streamp strm, int windowBits)
+{
+ struct inflate_state *state;
+
+ if (strm == NULL) return Z_STREAM_ERROR;
+ strm->msg = NULL; /* in case we return an error */
+
+ state = &WS(strm)->inflate_state;
+ strm->state = (struct internal_state *)state;
+
+ if (windowBits < 0) {
+ state->wrap = 0;
+ windowBits = -windowBits;
+ }
+ else {
+ state->wrap = (windowBits >> 4) + 1;
+ }
+ if (windowBits < 8 || windowBits > 15) {
+ return Z_STREAM_ERROR;
+ }
+ state->wbits = (unsigned)windowBits;
+ state->window = &WS(strm)->working_window[0];
+ return zlib_inflateReset(strm);
+}
-int zlib_inflateEnd(
- z_streamp z
-)
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. This returns fixed tables from inffixed.h.
+ */
+static void zlib_fixedtables(struct inflate_state *state)
{
- if (z == NULL || z->state == NULL || z->workspace == NULL)
- return Z_STREAM_ERROR;
- if (z->state->blocks != NULL)
- zlib_inflate_blocks_free(z->state->blocks, z);
- z->state = NULL;
- return Z_OK;
+# include "inffixed.h"
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
}
-int zlib_inflateInit2_(
- z_streamp z,
- int w,
- const char *version,
- int stream_size
-)
+/*
+ Update the window with the last wsize (normally 32K) bytes written before
+ returning. This is only called when a window is already in use, or when
+ output has been written during this inflate call, but the end of the deflate
+ stream has not been reached yet. It is also called to window dictionary data
+ when a dictionary is loaded.
+
+ Providing output buffers larger than 32K to inflate() should provide a speed
+ advantage, since only the last 32K of output is copied to the sliding window
+ upon return from inflate(), and since all distances after the first 32K of
+ output will fall in the output data, making match copies simpler and faster.
+ The advantage may be dependent on the size of the processor's data caches.
+ */
+static void zlib_updatewindow(z_streamp strm, unsigned out)
{
- if (version == NULL || version[0] != ZLIB_VERSION[0] ||
- stream_size != sizeof(z_stream) || z->workspace == NULL)
- return Z_VERSION_ERROR;
-
- /* initialize state */
- z->msg = NULL;
- z->state = &WS(z)->internal_state;
- z->state->blocks = NULL;
-
- /* handle undocumented nowrap option (no zlib header or check) */
- z->state->nowrap = 0;
- if (w < 0)
- {
- w = - w;
- z->state->nowrap = 1;
- }
-
- /* set window size */
- if (w < 8 || w > 15)
- {
- zlib_inflateEnd(z);
- return Z_STREAM_ERROR;
- }
- z->state->wbits = (uInt)w;
-
- /* create inflate_blocks state */
- if ((z->state->blocks =
- zlib_inflate_blocks_new(z, z->state->nowrap ? NULL : zlib_adler32, (uInt)1 << w))
- == NULL)
- {
- zlib_inflateEnd(z);
- return Z_MEM_ERROR;
- }
-
- /* reset state */
- zlib_inflateReset(z);
- return Z_OK;
+ struct inflate_state *state;
+ unsigned copy, dist;
+
+ state = (struct inflate_state *)strm->state;
+
+ /* copy state->wsize or less output bytes into the circular window */
+ copy = out - strm->avail_out;
+ if (copy >= state->wsize) {
+ memcpy(state->window, strm->next_out - state->wsize, state->wsize);
+ state->write = 0;
+ state->whave = state->wsize;
+ }
+ else {
+ dist = state->wsize - state->write;
+ if (dist > copy) dist = copy;
+ memcpy(state->window + state->write, strm->next_out - copy, dist);
+ copy -= dist;
+ if (copy) {
+ memcpy(state->window, strm->next_out - copy, copy);
+ state->write = copy;
+ state->whave = state->wsize;
+ }
+ else {
+ state->write += dist;
+ if (state->write == state->wsize) state->write = 0;
+ if (state->whave < state->wsize) state->whave += dist;
+ }
+ }
}
@@ -91,157 +150,764 @@ int zlib_inflateInit2_(
* At the end of a Deflate-compressed PPP packet, we expect to have seen
* a `stored' block type value but not the (zero) length bytes.
*/
-static int zlib_inflate_packet_flush(inflate_blocks_statef *s)
+/*
+ Returns true if inflate is currently at the end of a block generated by
+ Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ implementation to provide an additional safety check. PPP uses
+ Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+ block. When decompressing, PPP checks that at the end of input packet,
+ inflate is waiting for these length bytes.
+ */
+static int zlib_inflateSyncPacket(z_streamp strm)
{
- if (s->mode != LENS)
- return Z_DATA_ERROR;
- s->mode = TYPE;
+ struct inflate_state *state;
+
+ if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state *)strm->state;
+
+ if (state->mode == STORED && state->bits == 0) {
+ state->mode = TYPE;
+ return Z_OK;
+ }
+ return Z_DATA_ERROR;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#define UPDATE(check, buf, len) zlib_adler32(check, buf, len)
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+ if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ if (have == 0) goto inf_leave; \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Reverse the bytes in a 32-bit value */
+#define REVERSE(q) \
+ ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+/*
+ inflate() uses a state machine to process as much input data and generate as
+ much output data as possible before returning. The state machine is
+ structured roughly as follows:
+
+ for (;;) switch (state) {
+ ...
+ case STATEn:
+ if (not enough input data or output space to make progress)
+ return;
+ ... make progress ...
+ state = STATEm;
+ break;
+ ...
+ }
+
+ so when inflate() is called again, the same case is attempted again, and
+ if the appropriate resources are provided, the machine proceeds to the
+ next state. The NEEDBITS() macro is usually the way the state evaluates
+ whether it can proceed or should return. NEEDBITS() does the return if
+ the requested bits are not available. The typical use of the BITS macros
+ is:
+
+ NEEDBITS(n);
+ ... do something with BITS(n) ...
+ DROPBITS(n);
+
+ where NEEDBITS(n) either returns from inflate() if there isn't enough
+ input left to load n bits into the accumulator, or it continues. BITS(n)
+ gives the low n bits in the accumulator. When done, DROPBITS(n) drops
+ the low n bits off the accumulator. INITBITS() clears the accumulator
+ and sets the number of available bits to zero. BYTEBITS() discards just
+ enough bits to put the accumulator on a byte boundary. After BYTEBITS()
+ and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+ NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+ if there is no input available. The decoding of variable length codes uses
+ PULLBYTE() directly in order to pull just enough bytes to decode the next
+ code, and no more.
+
+ Some states loop until they get enough input, making sure that enough
+ state information is maintained to continue the loop where it left off
+ if NEEDBITS() returns in the loop. For example, want, need, and keep
+ would all have to actually be part of the saved state in case NEEDBITS()
+ returns:
+
+ case STATEw:
+ while (want < need) {
+ NEEDBITS(n);
+ keep[want++] = BITS(n);
+ DROPBITS(n);
+ }
+ state = STATEx;
+ case STATEx:
+
+ As shown above, if the next state is also the next case, then the break
+ is omitted.
+
+ A state may also return if there is not enough output space available to
+ complete that state. Those states are copying stored data, writing a
+ literal byte, and copying a matching string.
+
+ When returning, a "goto inf_leave" is used to update the total counters,
+ update the check value, and determine whether any progress has been made
+ during that inflate() call in order to return the proper return code.
+ Progress is defined as a change in either strm->avail_in or strm->avail_out.
+ When there is a window, goto inf_leave will update the window with the last
+ output written. If a goto inf_leave occurs in the middle of decompression
+ and there is no window currently, goto inf_leave will create one and copy
+ output to the window for the next call of inflate().
+
+ In this implementation, the flush parameter of inflate() only affects the
+ return code (per zlib.h). inflate() always writes as much as possible to
+ strm->next_out, given the space available and the provided input--the effect
+ documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers
+ the allocation of and copying into a sliding window until necessary, which
+ provides the effect documented in zlib.h for Z_FINISH when the entire input
+ stream available. So the only thing the flush parameter actually does is:
+ when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it
+ will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int zlib_inflate(z_streamp strm, int flush)
+{
+ struct inflate_state *state;
+ unsigned char *next; /* next input */
+ unsigned char *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned in, out; /* save starting available input and output */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char *from; /* where to copy match bytes from */
+ code this; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ if (strm == NULL || strm->state == NULL || strm->next_out == NULL ||
+ (strm->next_in == NULL && strm->avail_in != 0))
+ return Z_STREAM_ERROR;
+
+ state = (struct inflate_state *)strm->state;
+
+ if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */
+ LOAD();
+ in = have;
+ out = left;
+ ret = Z_OK;
+ for (;;)
+ switch (state->mode) {
+ case HEAD:
+ if (state->wrap == 0) {
+ state->mode = TYPEDO;
+ break;
+ }
+ NEEDBITS(16);
+ if (
+ ((BITS(8) << 8) + (hold >> 8)) % 31) {
+ strm->msg = (char *)"incorrect header check";
+ state->mode = BAD;
+ break;
+ }
+ if (BITS(4) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ DROPBITS(4);
+ len = BITS(4) + 8;
+ if (len > state->wbits) {
+ strm->msg = (char *)"invalid window size";
+ state->mode = BAD;
+ break;
+ }
+ state->dmax = 1U << len;
+ strm->adler = state->check = zlib_adler32(0L, NULL, 0);
+ state->mode = hold & 0x200 ? DICTID : TYPE;
+ INITBITS();
+ break;
+ case DICTID:
+ NEEDBITS(32);
+ strm->adler = state->check = REVERSE(hold);
+ INITBITS();
+ state->mode = DICT;
+ case DICT:
+ if (state->havedict == 0) {
+ RESTORE();
+ return Z_NEED_DICT;
+ }
+ strm->adler = state->check = zlib_adler32(0L, NULL, 0);
+ state->mode = TYPE;
+ case TYPE:
+ if (flush == Z_BLOCK) goto inf_leave;
+ case TYPEDO:
+ if (state->last) {
+ BYTEBITS();
+ state->mode = CHECK;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ zlib_fixedtables(state);
+ state->mode = LEN; /* decode codes */
+ break;
+ case 2: /* dynamic block */
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+ case STORED:
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ INITBITS();
+ state->mode = COPY;
+ case COPY:
+ copy = state->length;
+ if (copy) {
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ if (copy == 0) goto inf_leave;
+ memcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ break;
+ }
+ state->mode = TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ state->have = 0;
+ state->mode = LENLENS;
+ case LENLENS:
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (code const *)(state->next);
+ state->lenbits = 7;
+ ret = zlib_inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->have = 0;
+ state->mode = CODELENS;
+ case CODELENS:
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.val < 16) {
+ NEEDBITS(this.bits);
+ DROPBITS(this.bits);
+ state->lens[state->have++] = this.val;
+ }
+ else {
+ if (this.val == 16) {
+ NEEDBITS(this.bits + 2);
+ DROPBITS(this.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = state->lens[state->have - 1];
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (this.val == 17) {
+ NEEDBITS(this.bits + 3);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(this.bits + 7);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state->mode == BAD) break;
+
+ /* build code tables */
+ state->next = state->codes;
+ state->lencode = (code const *)(state->next);
+ state->lenbits = 9;
+ ret = zlib_inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (code const *)(state->next);
+ state->distbits = 6;
+ ret = zlib_inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ state->mode = LEN;
+ case LEN:
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ inflate_fast(strm, out);
+ LOAD();
+ break;
+ }
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.op && (this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ state->length = (unsigned)this.val;
+ if ((int)(this.op) == 0) {
+ state->mode = LIT;
+ break;
+ }
+ if (this.op & 32) {
+ state->mode = TYPE;
+ break;
+ }
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ state->extra = (unsigned)(this.op) & 15;
+ state->mode = LENEXT;
+ case LENEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ state->mode = DIST;
+ case DIST:
+ for (;;) {
+ this = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)this.val;
+ state->extra = (unsigned)(this.op) & 15;
+ state->mode = DISTEXT;
+ case DISTEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+#ifdef INFLATE_STRICT
+ if (state->offset > state->dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ if (state->offset > state->whave + out - left) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ state->mode = MATCH;
+ case MATCH:
+ if (left == 0) goto inf_leave;
+ copy = out - left;
+ if (state->offset > copy) { /* copy from window */
+ copy = state->offset - copy;
+ if (copy > state->write) {
+ copy -= state->write;
+ from = state->window + (state->wsize - copy);
+ }
+ else
+ from = state->window + (state->write - copy);
+ if (copy > state->length) copy = state->length;
+ }
+ else { /* copy from output */
+ from = put - state->offset;
+ copy = state->length;
+ }
+ if (copy > left) copy = left;
+ left -= copy;
+ state->length -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ if (state->length == 0) state->mode = LEN;
+ break;
+ case LIT:
+ if (left == 0) goto inf_leave;
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ case CHECK:
+ if (state->wrap) {
+ NEEDBITS(32);
+ out -= left;
+ strm->total_out += out;
+ state->total += out;
+ if (out)
+ strm->adler = state->check =
+ UPDATE(state->check, put - out, out);
+ out = left;
+ if ((
+ REVERSE(hold)) != state->check) {
+ strm->msg = (char *)"incorrect data check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ }
+ state->mode = DONE;
+ case DONE:
+ ret = Z_STREAM_END;
+ goto inf_leave;
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+ case MEM:
+ return Z_MEM_ERROR;
+ case SYNC:
+ default:
+ return Z_STREAM_ERROR;
+ }
+
+ /*
+ Return from inflate(), updating the total counts and the check value.
+ If there was no progress during the inflate() call, return a buffer
+ error. Call zlib_updatewindow() to create and/or update the window state.
+ */
+ inf_leave:
+ RESTORE();
+ if (state->wsize || (state->mode < CHECK && out != strm->avail_out))
+ zlib_updatewindow(strm, out);
+
+ in -= strm->avail_in;
+ out -= strm->avail_out;
+ strm->total_in += in;
+ strm->total_out += out;
+ state->total += out;
+ if (state->wrap && out)
+ strm->adler = state->check =
+ UPDATE(state->check, strm->next_out - out, out);
+
+ strm->data_type = state->bits + (state->last ? 64 : 0) +
+ (state->mode == TYPE ? 128 : 0);
+ if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+ ret = Z_BUF_ERROR;
+
+ if (flush == Z_PACKET_FLUSH && ret == Z_OK &&
+ (strm->avail_out != 0 || strm->avail_in == 0))
+ return zlib_inflateSyncPacket(strm);
+ return ret;
+}
+
+int zlib_inflateEnd(z_streamp strm)
+{
+ if (strm == NULL || strm->state == NULL)
+ return Z_STREAM_ERROR;
return Z_OK;
}
+#if 0
+int zlib_inflateSetDictionary(z_streamp strm, const Byte *dictionary,
+ uInt dictLength)
+{
+ struct inflate_state *state;
+ unsigned long id;
+
+ /* check state */
+ if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state *)strm->state;
+ if (state->wrap != 0 && state->mode != DICT)
+ return Z_STREAM_ERROR;
+
+ /* check for correct dictionary id */
+ if (state->mode == DICT) {
+ id = zlib_adler32(0L, NULL, 0);
+ id = zlib_adler32(id, dictionary, dictLength);
+ if (id != state->check)
+ return Z_DATA_ERROR;
+ }
+
+ /* copy dictionary to window */
+ zlib_updatewindow(strm, strm->avail_out);
-int zlib_inflateInit_(
- z_streamp z,
- const char *version,
- int stream_size
-)
+ if (dictLength > state->wsize) {
+ memcpy(state->window, dictionary + dictLength - state->wsize,
+ state->wsize);
+ state->whave = state->wsize;
+ }
+ else {
+ memcpy(state->window + state->wsize - dictLength, dictionary,
+ dictLength);
+ state->whave = dictLength;
+ }
+ state->havedict = 1;
+ return Z_OK;
+}
+#endif
+
+#if 0
+/*
+ Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found
+ or when out of input. When called, *have is the number of pattern bytes
+ found in order so far, in 0..3. On return *have is updated to the new
+ state. If on return *have equals four, then the pattern was found and the
+ return value is how many bytes were read including the last byte of the
+ pattern. If *have is less than four, then the pattern has not been found
+ yet and the return value is len. In the latter case, zlib_syncsearch() can be
+ called again with more data and the *have state. *have is initialized to
+ zero for the first call.
+ */
+static unsigned zlib_syncsearch(unsigned *have, unsigned char *buf,
+ unsigned len)
{
- return zlib_inflateInit2_(z, DEF_WBITS, version, stream_size);
+ unsigned got;
+ unsigned next;
+
+ got = *have;
+ next = 0;
+ while (next < len && got < 4) {
+ if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+ got++;
+ else if (buf[next])
+ got = 0;
+ else
+ got = 4 - got;
+ next++;
+ }
+ *have = got;
+ return next;
}
+#endif
-#undef NEEDBYTE
-#undef NEXTBYTE
-#define NEEDBYTE {if(z->avail_in==0)goto empty;r=trv;}
-#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+#if 0
+int zlib_inflateSync(z_streamp strm)
+{
+ unsigned len; /* number of bytes to look at or looked at */
+ unsigned long in, out; /* temporary to save total_in and total_out */
+ unsigned char buf[4]; /* to restore bit buffer to byte string */
+ struct inflate_state *state;
+
+ /* check parameters */
+ if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state *)strm->state;
+ if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+ /* if first time, start search in bit buffer */
+ if (state->mode != SYNC) {
+ state->mode = SYNC;
+ state->hold <<= state->bits & 7;
+ state->bits -= state->bits & 7;
+ len = 0;
+ while (state->bits >= 8) {
+ buf[len++] = (unsigned char)(state->hold);
+ state->hold >>= 8;
+ state->bits -= 8;
+ }
+ state->have = 0;
+ zlib_syncsearch(&(state->have), buf, len);
+ }
+
+ /* search available input */
+ len = zlib_syncsearch(&(state->have), strm->next_in, strm->avail_in);
+ strm->avail_in -= len;
+ strm->next_in += len;
+ strm->total_in += len;
+
+ /* return no joy or set up to restart inflate() on a new block */
+ if (state->have != 4) return Z_DATA_ERROR;
+ in = strm->total_in; out = strm->total_out;
+ zlib_inflateReset(strm);
+ strm->total_in = in; strm->total_out = out;
+ state->mode = TYPE;
+ return Z_OK;
+}
+#endif
-int zlib_inflate(
- z_streamp z,
- int f
-)
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output. The output buffer must be "caught up";
+ * i.e. no pending output but this should always be the case. The state must
+ * be waiting on the start of a block (i.e. mode == TYPE or HEAD). On exit,
+ * the output will also be caught up, and the checksum will have been updated
+ * if need be.
+ */
+int zlib_inflateIncomp(z_stream *z)
{
- int r, trv;
- uInt b;
-
- if (z == NULL || z->state == NULL || z->next_in == NULL)
- return Z_STREAM_ERROR;
- trv = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
- r = Z_BUF_ERROR;
- while (1) switch (z->state->mode)
- {
- case METHOD:
- NEEDBYTE
- if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
- {
- z->state->mode = I_BAD;
- z->msg = (char*)"unknown compression method";
- z->state->sub.marker = 5; /* can't try inflateSync */
- break;
- }
- if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
- {
- z->state->mode = I_BAD;
- z->msg = (char*)"invalid window size";
- z->state->sub.marker = 5; /* can't try inflateSync */
- break;
- }
- z->state->mode = FLAG;
- case FLAG:
- NEEDBYTE
- b = NEXTBYTE;
- if (((z->state->sub.method << 8) + b) % 31)
- {
- z->state->mode = I_BAD;
- z->msg = (char*)"incorrect header check";
- z->state->sub.marker = 5; /* can't try inflateSync */
- break;
- }
- if (!(b & PRESET_DICT))
- {
- z->state->mode = BLOCKS;
- break;
- }
- z->state->mode = DICT4;
- case DICT4:
- NEEDBYTE
- z->state->sub.check.need = (uLong)NEXTBYTE << 24;
- z->state->mode = DICT3;
- case DICT3:
- NEEDBYTE
- z->state->sub.check.need += (uLong)NEXTBYTE << 16;
- z->state->mode = DICT2;
- case DICT2:
- NEEDBYTE
- z->state->sub.check.need += (uLong)NEXTBYTE << 8;
- z->state->mode = DICT1;
- case DICT1:
- NEEDBYTE
- z->state->sub.check.need += (uLong)NEXTBYTE;
- z->adler = z->state->sub.check.need;
- z->state->mode = DICT0;
- return Z_NEED_DICT;
- case DICT0:
- z->state->mode = I_BAD;
- z->msg = (char*)"need dictionary";
- z->state->sub.marker = 0; /* can try inflateSync */
- return Z_STREAM_ERROR;
- case BLOCKS:
- r = zlib_inflate_blocks(z->state->blocks, z, r);
- if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
- r = zlib_inflate_packet_flush(z->state->blocks);
- if (r == Z_DATA_ERROR)
- {
- z->state->mode = I_BAD;
- z->state->sub.marker = 0; /* can try inflateSync */
- break;
- }
- if (r == Z_OK)
- r = trv;
- if (r != Z_STREAM_END)
- return r;
- r = trv;
- zlib_inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
- if (z->state->nowrap)
- {
- z->state->mode = I_DONE;
- break;
- }
- z->state->mode = CHECK4;
- case CHECK4:
- NEEDBYTE
- z->state->sub.check.need = (uLong)NEXTBYTE << 24;
- z->state->mode = CHECK3;
- case CHECK3:
- NEEDBYTE
- z->state->sub.check.need += (uLong)NEXTBYTE << 16;
- z->state->mode = CHECK2;
- case CHECK2:
- NEEDBYTE
- z->state->sub.check.need += (uLong)NEXTBYTE << 8;
- z->state->mode = CHECK1;
- case CHECK1:
- NEEDBYTE
- z->state->sub.check.need += (uLong)NEXTBYTE;
-
- if (z->state->sub.check.was != z->state->sub.check.need)
- {
- z->state->mode = I_BAD;
- z->msg = (char*)"incorrect data check";
- z->state->sub.marker = 5; /* can't try inflateSync */
- break;
- }
- z->state->mode = I_DONE;
- case I_DONE:
- return Z_STREAM_END;
- case I_BAD:
- return Z_DATA_ERROR;
- default:
- return Z_STREAM_ERROR;
- }
- empty:
- if (f != Z_PACKET_FLUSH)
- return r;
- z->state->mode = I_BAD;
- z->msg = (char *)"need more for packet flush";
- z->state->sub.marker = 0; /* can try inflateSync */
- return Z_DATA_ERROR;
+ struct inflate_state *state = (struct inflate_state *)z->state;
+ Byte *saved_no = z->next_out;
+ uInt saved_ao = z->avail_out;
+
+ if (state->mode != TYPE && state->mode != HEAD)
+ return Z_DATA_ERROR;
+
+ /* Setup some variables to allow misuse of updateWindow */
+ z->avail_out = 0;
+ z->next_out = z->next_in + z->avail_in;
+
+ zlib_updatewindow(z, z->avail_in);
+
+ /* Restore saved variables */
+ z->avail_out = saved_ao;
+ z->next_out = saved_no;
+
+ z->adler = state->check =
+ UPDATE(state->check, z->next_in, z->avail_in);
+
+ z->total_out += z->avail_in;
+ z->total_in += z->avail_in;
+ z->next_in += z->avail_in;
+ state->total += z->avail_in;
+ z->avail_in = 0;
+
+ return Z_OK;
}
diff --git a/lib/zlib_inflate/inflate.h b/lib/zlib_inflate/inflate.h
new file mode 100644
index 0000000..df8a6c9
--- /dev/null
+++ b/lib/zlib_inflate/inflate.h
@@ -0,0 +1,107 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+ HEAD, /* i: waiting for magic header */
+ FLAGS, /* i: waiting for method and flags (gzip) */
+ TIME, /* i: waiting for modification time (gzip) */
+ OS, /* i: waiting for extra flags and operating system (gzip) */
+ EXLEN, /* i: waiting for extra length (gzip) */
+ EXTRA, /* i: waiting for extra bytes (gzip) */
+ NAME, /* i: waiting for end of file name (gzip) */
+ COMMENT, /* i: waiting for end of comment (gzip) */
+ HCRC, /* i: waiting for header crc (gzip) */
+ DICTID, /* i: waiting for dictionary check value */
+ DICT, /* waiting for inflateSetDictionary() call */
+ TYPE, /* i: waiting for type bits, including last-flag bit */
+ TYPEDO, /* i: same, but skip check to exit inflate on new block */
+ STORED, /* i: waiting for stored size (length and complement) */
+ COPY, /* i/o: waiting for input or output to copy stored block */
+ TABLE, /* i: waiting for dynamic block table lengths */
+ LENLENS, /* i: waiting for code length code lengths */
+ CODELENS, /* i: waiting for length/lit and distance code lengths */
+ LEN, /* i: waiting for length/lit code */
+ LENEXT, /* i: waiting for length extra bits */
+ DIST, /* i: waiting for distance code */
+ DISTEXT, /* i: waiting for distance extra bits */
+ MATCH, /* o: waiting for output space to copy string */
+ LIT, /* o: waiting for output space to write literal */
+ CHECK, /* i: waiting for 32-bit check value */
+ LENGTH, /* i: waiting for 32-bit length (gzip) */
+ DONE, /* finished check, done -- remain here until reset */
+ BAD, /* got a data error -- remain here until reset */
+ MEM, /* got an inflate() memory error -- remain here until reset */
+ SYNC /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+ State transitions between above modes -
+
+ (most modes can go to the BAD or MEM mode -- not shown for clarity)
+
+ Process header:
+ HEAD -> (gzip) or (zlib)
+ (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME
+ NAME -> COMMENT -> HCRC -> TYPE
+ (zlib) -> DICTID or TYPE
+ DICTID -> DICT -> TYPE
+ Read deflate blocks:
+ TYPE -> STORED or TABLE or LEN or CHECK
+ STORED -> COPY -> TYPE
+ TABLE -> LENLENS -> CODELENS -> LEN
+ Read deflate codes:
+ LEN -> LENEXT or LIT or TYPE
+ LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+ LIT -> LEN
+ Process trailer:
+ CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls. Approximately 7K bytes. */
+struct inflate_state {
+ inflate_mode mode; /* current inflate mode */
+ int last; /* true if processing last block */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ int havedict; /* true if dictionary provided */
+ int flags; /* gzip header method and flags (0 if zlib) */
+ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */
+ unsigned long check; /* protected copy of check value */
+ unsigned long total; /* protected copy of output count */
+ /* gz_headerp head; */ /* where to save gzip header information */
+ /* sliding window */
+ unsigned wbits; /* log base 2 of requested window size */
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned write; /* window write index */
+ unsigned char *window; /* allocated sliding window, if needed */
+ /* bit accumulator */
+ unsigned long hold; /* input bit accumulator */
+ unsigned bits; /* number of bits in "in" */
+ /* for string and stored block copying */
+ unsigned length; /* literal or length of data to copy */
+ unsigned offset; /* distance back to copy string from */
+ /* for table and code decoding */
+ unsigned extra; /* extra bits needed */
+ /* fixed and dynamic code tables */
+ code const *lencode; /* starting table for length/literal codes */
+ code const *distcode; /* starting table for distance codes */
+ unsigned lenbits; /* index bits for lencode */
+ unsigned distbits; /* index bits for distcode */
+ /* dynamic table building */
+ unsigned ncode; /* number of code length code lengths */
+ unsigned nlen; /* number of length code lengths */
+ unsigned ndist; /* number of distance code lengths */
+ unsigned have; /* number of code lengths in lens[] */
+ code *next; /* next available space in codes[] */
+ unsigned short lens[320]; /* temporary storage for code lengths */
+ unsigned short work[288]; /* work area for code table building */
+ code codes[ENOUGH]; /* space for code tables */
+};
diff --git a/lib/zlib_inflate/inflate_syms.c b/lib/zlib_inflate/inflate_syms.c
index ef49738..2061d4f 100644
--- a/lib/zlib_inflate/inflate_syms.c
+++ b/lib/zlib_inflate/inflate_syms.c
@@ -12,8 +12,7 @@
EXPORT_SYMBOL(zlib_inflate_workspacesize);
EXPORT_SYMBOL(zlib_inflate);
-EXPORT_SYMBOL(zlib_inflateInit_);
-EXPORT_SYMBOL(zlib_inflateInit2_);
+EXPORT_SYMBOL(zlib_inflateInit2);
EXPORT_SYMBOL(zlib_inflateEnd);
EXPORT_SYMBOL(zlib_inflateReset);
EXPORT_SYMBOL(zlib_inflateIncomp);
diff --git a/lib/zlib_inflate/inflate_sync.c b/lib/zlib_inflate/inflate_sync.c
deleted file mode 100644
index 61411ff..0000000
--- a/lib/zlib_inflate/inflate_sync.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/* inflate.c -- zlib interface to inflate modules
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h
- */
-
-#include <linux/zutil.h>
-#include "infblock.h"
-#include "infutil.h"
-
-#if 0
-int zlib_inflateSync(
- z_streamp z
-)
-{
- uInt n; /* number of bytes to look at */
- Byte *p; /* pointer to bytes */
- uInt m; /* number of marker bytes found in a row */
- uLong r, w; /* temporaries to save total_in and total_out */
-
- /* set up */
- if (z == NULL || z->state == NULL)
- return Z_STREAM_ERROR;
- if (z->state->mode != I_BAD)
- {
- z->state->mode = I_BAD;
- z->state->sub.marker = 0;
- }
- if ((n = z->avail_in) == 0)
- return Z_BUF_ERROR;
- p = z->next_in;
- m = z->state->sub.marker;
-
- /* search */
- while (n && m < 4)
- {
- static const Byte mark[4] = {0, 0, 0xff, 0xff};
- if (*p == mark[m])
- m++;
- else if (*p)
- m = 0;
- else
- m = 4 - m;
- p++, n--;
- }
-
- /* restore */
- z->total_in += p - z->next_in;
- z->next_in = p;
- z->avail_in = n;
- z->state->sub.marker = m;
-
- /* return no joy or set up to restart on a new block */
- if (m != 4)
- return Z_DATA_ERROR;
- r = z->total_in; w = z->total_out;
- zlib_inflateReset(z);
- z->total_in = r; z->total_out = w;
- z->state->mode = BLOCKS;
- return Z_OK;
-}
-#endif /* 0 */
-
-
-/* Returns true if inflate is currently at the end of a block generated
- * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
- * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
- * but removes the length bytes of the resulting empty stored block. When
- * decompressing, PPP checks that at the end of input packet, inflate is
- * waiting for these length bytes.
- */
-#if 0
-int zlib_inflateSyncPoint(
- z_streamp z
-)
-{
- if (z == NULL || z->state == NULL || z->state->blocks == NULL)
- return Z_STREAM_ERROR;
- return zlib_inflate_blocks_sync_point(z->state->blocks);
-}
-#endif /* 0 */
-
-/*
- * This subroutine adds the data at next_in/avail_in to the output history
- * without performing any output. The output buffer must be "caught up";
- * i.e. no pending output (hence s->read equals s->write), and the state must
- * be BLOCKS (i.e. we should be willing to see the start of a series of
- * BLOCKS). On exit, the output will also be caught up, and the checksum
- * will have been updated if need be.
- */
-static int zlib_inflate_addhistory(inflate_blocks_statef *s,
- z_stream *z)
-{
- uLong b; /* bit buffer */ /* NOT USED HERE */
- uInt k; /* bits in bit buffer */ /* NOT USED HERE */
- uInt t; /* temporary storage */
- Byte *p; /* input data pointer */
- uInt n; /* bytes available there */
- Byte *q; /* output window write pointer */
- uInt m; /* bytes to end of window or read pointer */
-
- if (s->read != s->write)
- return Z_STREAM_ERROR;
- if (s->mode != TYPE)
- return Z_DATA_ERROR;
-
- /* we're ready to rock */
- LOAD
- /* while there is input ready, copy to output buffer, moving
- * pointers as needed.
- */
- while (n) {
- t = n; /* how many to do */
- /* is there room until end of buffer? */
- if (t > m) t = m;
- /* update check information */
- if (s->checkfn != NULL)
- s->check = (*s->checkfn)(s->check, q, t);
- memcpy(q, p, t);
- q += t;
- p += t;
- n -= t;
- z->total_out += t;
- s->read = q; /* drag read pointer forward */
-/* WWRAP */ /* expand WWRAP macro by hand to handle s->read */
- if (q == s->end) {
- s->read = q = s->window;
- m = WAVAIL;
- }
- }
- UPDATE
- return Z_OK;
-}
-
-
-/*
- * This subroutine adds the data at next_in/avail_in to the output history
- * without performing any output. The output buffer must be "caught up";
- * i.e. no pending output (hence s->read equals s->write), and the state must
- * be BLOCKS (i.e. we should be willing to see the start of a series of
- * BLOCKS). On exit, the output will also be caught up, and the checksum
- * will have been updated if need be.
- */
-
-int zlib_inflateIncomp(
- z_stream *z
-
-)
-{
- if (z->state->mode != BLOCKS)
- return Z_DATA_ERROR;
- return zlib_inflate_addhistory(z->state->blocks, z);
-}
diff --git a/lib/zlib_inflate/inftrees.c b/lib/zlib_inflate/inftrees.c
index 874950e..62343c5 100644
--- a/lib/zlib_inflate/inftrees.c
+++ b/lib/zlib_inflate/inftrees.c
@@ -1,412 +1,329 @@
/* inftrees.c -- generate Huffman trees for efficient decoding
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
*/
#include <linux/zutil.h>
#include "inftrees.h"
-#include "infutil.h"
-static const char inflate_copyright[] __attribute_used__ =
- " inflate 1.1.3 Copyright 1995-1998 Mark Adler ";
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+ " inflate 1.2.3 Copyright 1995-2005 Mark Adler ";
/*
If you use the zlib library in a product, an acknowledgment is welcome
in the documentation of your product. If for some reason you cannot
include such an acknowledgment, I would appreciate that you keep this
copyright string in the executable of your product.
*/
-struct internal_state;
-
-/* simplify the use of the inflate_huft type with some defines */
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-
-static int huft_build (
- uInt *, /* code lengths in bits */
- uInt, /* number of codes */
- uInt, /* number of "simple" codes */
- const uInt *, /* list of base values for non-simple codes */
- const uInt *, /* list of extra bits for non-simple codes */
- inflate_huft **, /* result: starting table */
- uInt *, /* maximum lookup bits (returns actual) */
- inflate_huft *, /* space for trees */
- uInt *, /* hufts used in space */
- uInt * ); /* space for values */
-
-/* Tables for deflate from PKZIP's appnote.txt. */
-static const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
- 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
- /* see note #13 above about 258 */
-static const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
- 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
-static const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
- 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
- 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
- 8193, 12289, 16385, 24577};
-static const uInt cpdext[30] = { /* Extra bits for distance codes */
- 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
- 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
- 12, 12, 13, 13};
/*
- Huffman code decoding is performed using a multi-level table lookup.
- The fastest way to decode is to simply build a lookup table whose
- size is determined by the longest code. However, the time it takes
- to build this table can also be a factor if the data being decoded
- is not very long. The most common codes are necessarily the
- shortest codes, so those codes dominate the decoding time, and hence
- the speed. The idea is you can have a shorter table that decodes the
- shorter, more probable codes, and then point to subsidiary tables for
- the longer codes. The time it costs to decode the longer codes is
- then traded against the time it takes to make longer tables.
-
- This results of this trade are in the variables lbits and dbits
- below. lbits is the number of bits the first level table for literal/
- length codes can decode in one step, and dbits is the same thing for
- the distance codes. Subsequent tables are also less than or equal to
- those sizes. These values may be adjusted either when all of the
- codes are shorter than that, in which case the longest code length in
- bits is used, or when the shortest code is *longer* than the requested
- table size, in which case the length of the shortest code in bits is
- used.
-
- There are two different values for the two tables, since they code a
- different number of possibilities each. The literal/length table
- codes 286 possible values, or in a flat code, a little over eight
- bits. The distance table codes 30 possible values, or a little less
- than five bits, flat. The optimum values for speed end up being
- about one bit more than those, so lbits is 8+1 and dbits is 5+1.
- The optimum values may differ though from machine to machine, and
- possibly even between compilers. Your mileage may vary.
+ Build a set of tables to decode the provided canonical Huffman code.
+ The code lengths are lens[0..codes-1]. The result starts at *table,
+ whose indices are 0..2^bits-1. work is a writable array of at least
+ lens shorts, which is used as a work area. type is the type of code
+ to be generated, CODES, LENS, or DISTS. On return, zero is success,
+ -1 is an invalid code, and +1 means that ENOUGH isn't enough. table
+ on return points to the next available entry's address. bits is the
+ requested root table index bits, and on return it is the actual root
+ table index bits. It will differ if the request is greater than the
+ longest code or if it is less than the shortest code.
*/
-
-
-/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
-#define BMAX 15 /* maximum bit length of any code */
-
-static int huft_build(
- uInt *b, /* code lengths in bits (all assumed <= BMAX) */
- uInt n, /* number of codes (assumed <= 288) */
- uInt s, /* number of simple-valued codes (0..s-1) */
- const uInt *d, /* list of base values for non-simple codes */
- const uInt *e, /* list of extra bits for non-simple codes */
- inflate_huft **t, /* result: starting table */
- uInt *m, /* maximum lookup bits, returns actual */
- inflate_huft *hp, /* space for trees */
- uInt *hn, /* hufts used in space */
- uInt *v /* working area: values in order of bit length */
-)
-/* Given a list of code lengths and a maximum table size, make a set of
- tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
- if the given code set is incomplete (the tables are still built in this
- case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
- lengths), or Z_MEM_ERROR if not enough memory. */
+int zlib_inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short *lens;
+unsigned codes;
+code **table;
+unsigned *bits;
+unsigned short *work;
{
+ unsigned len; /* a code's length in bits */
+ unsigned sym; /* index of code symbols */
+ unsigned min, max; /* minimum and maximum code lengths */
+ unsigned root; /* number of index bits for root table */
+ unsigned curr; /* number of index bits for current table */
+ unsigned drop; /* code bits to drop for sub-table */
+ int left; /* number of prefix codes available */
+ unsigned used; /* code entries in table used */
+ unsigned huff; /* Huffman code */
+ unsigned incr; /* for incrementing code, index */
+ unsigned fill; /* index for replicating entries */
+ unsigned low; /* low bits for current root entry */
+ unsigned mask; /* mask for low root bits */
+ code this; /* table entry for duplication */
+ code *next; /* next available space in table */
+ const unsigned short *base; /* base value table to use */
+ const unsigned short *extra; /* extra bits table to use */
+ int end; /* use base and extra for symbol > end */
+ unsigned short count[MAXBITS+1]; /* number of codes of each length */
+ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
+ static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+ 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196};
+ static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577, 0, 0};
+ static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+ 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+ 28, 28, 29, 29, 64, 64};
+
+ /*
+ Process a set of code lengths to create a canonical Huffman code. The
+ code lengths are lens[0..codes-1]. Each length corresponds to the
+ symbols 0..codes-1. The Huffman code is generated by first sorting the
+ symbols by length from short to long, and retaining the symbol order
+ for codes with equal lengths. Then the code starts with all zero bits
+ for the first code of the shortest length, and the codes are integer
+ increments for the same length, and zeros are appended as the length
+ increases. For the deflate format, these bits are stored backwards
+ from their more natural integer increment ordering, and so when the
+ decoding tables are built in the large loop below, the integer codes
+ are incremented backwards.
+
+ This routine assumes, but does not check, that all of the entries in
+ lens[] are in the range 0..MAXBITS. The caller must assure this.
+ 1..MAXBITS is interpreted as that code length. zero means that that
+ symbol does not occur in this code.
+
+ The codes are sorted by computing a count of codes for each length,
+ creating from that a table of starting indices for each length in the
+ sorted table, and then entering the symbols in order in the sorted
+ table. The sorted table is work[], with that space being provided by
+ the caller.
+
+ The length counts are used for other purposes as well, i.e. finding
+ the minimum and maximum length codes, determining if there are any
+ codes at all, checking for a valid set of lengths, and looking ahead
+ at length counts to determine sub-table sizes when building the
+ decoding tables.
+ */
+
+ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+ for (len = 0; len <= MAXBITS; len++)
+ count[len] = 0;
+ for (sym = 0; sym < codes; sym++)
+ count[lens[sym]]++;
+
+ /* bound code lengths, force root to be within code lengths */
+ root = *bits;
+ for (max = MAXBITS; max >= 1; max--)
+ if (count[max] != 0) break;
+ if (root > max) root = max;
+ if (max == 0) { /* no symbols to code at all */
+ this.op = (unsigned char)64; /* invalid code marker */
+ this.bits = (unsigned char)1;
+ this.val = (unsigned short)0;
+ *(*table)++ = this; /* make a table to force an error */
+ *(*table)++ = this;
+ *bits = 1;
+ return 0; /* no symbols, but wait for decoding to report error */
+ }
+ for (min = 1; min <= MAXBITS; min++)
+ if (count[min] != 0) break;
+ if (root < min) root = min;
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1;
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1;
+ left -= count[len];
+ if (left < 0) return -1; /* over-subscribed */
+ }
+ if (left > 0 && (type == CODES || max != 1))
+ return -1; /* incomplete set */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + count[len];
+
+ /* sort symbols by length, by symbol order within each length */
+ for (sym = 0; sym < codes; sym++)
+ if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+ /*
+ Create and fill in decoding tables. In this loop, the table being
+ filled is at next and has curr index bits. The code being used is huff
+ with length len. That code is converted to an index by dropping drop
+ bits off of the bottom. For codes where len is less than drop + curr,
+ those top drop + curr - len bits are incremented through all values to
+ fill the table with replicated entries.
+
+ root is the number of index bits for the root table. When len exceeds
+ root, sub-tables are created pointed to by the root entry with an index
+ of the low root bits of huff. This is saved in low to check for when a
+ new sub-table should be started. drop is zero when the root table is
+ being filled, and drop is root when sub-tables are being filled.
+
+ When a new sub-table is needed, it is necessary to look ahead in the
+ code lengths to determine what size sub-table is needed. The length
+ counts are used for this, and so count[] is decremented as codes are
+ entered in the tables.
+
+ used keeps track of how many table entries have been allocated from the
+ provided *table space. It is checked when a LENS table is being made
+ against the space in *table, ENOUGH, minus the maximum space needed by
+ the worst case distance code, MAXD. This should never happen, but the
+ sufficiency of ENOUGH has not been proven exhaustively, hence the check.
+ This assumes that when type == LENS, bits == 9.
+
+ sym increments through all symbols, and the loop terminates when
+ all codes of length max, i.e. all codes, have been processed. This
+ routine permits incomplete codes, so another loop after this one fills
+ in the rest of the decoding tables with invalid code markers.
+ */
+
+ /* set up for code type */
+ switch (type) {
+ case CODES:
+ base = extra = work; /* dummy value--not used */
+ end = 19;
+ break;
+ case LENS:
+ base = lbase;
+ base -= 257;
+ extra = lext;
+ extra -= 257;
+ end = 256;
+ break;
+ default: /* DISTS */
+ base = dbase;
+ extra = dext;
+ end = -1;
+ }
- uInt a; /* counter for codes of length k */
- uInt c[BMAX+1]; /* bit length count table */
- uInt f; /* i repeats in table every f entries */
- int g; /* maximum code length */
- int h; /* table level */
- register uInt i; /* counter, current code */
- register uInt j; /* counter */
- register int k; /* number of bits in current code */
- int l; /* bits per table (returned in m) */
- uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */
- register uInt *p; /* pointer into c[], b[], or v[] */
- inflate_huft *q; /* points to current table */
- struct inflate_huft_s r; /* table entry for structure assignment */
- inflate_huft *u[BMAX]; /* table stack */
- register int w; /* bits before this table == (l * h) */
- uInt x[BMAX+1]; /* bit offsets, then code stack */
- uInt *xp; /* pointer into x */
- int y; /* number of dummy codes added */
- uInt z; /* number of entries in current table */
-
-
- /* Generate counts for each bit length */
- p = c;
-#define C0 *p++ = 0;
-#define C2 C0 C0 C0 C0
-#define C4 C2 C2 C2 C2
- C4 /* clear c[]--assume BMAX+1 is 16 */
- p = b; i = n;
- do {
- c[*p++]++; /* assume all entries <= BMAX */
- } while (--i);
- if (c[0] == n) /* null input--all zero length codes */
- {
- *t = NULL;
- *m = 0;
- return Z_OK;
- }
-
-
- /* Find minimum and maximum length, bound *m by those */
- l = *m;
- for (j = 1; j <= BMAX; j++)
- if (c[j])
- break;
- k = j; /* minimum code length */
- if ((uInt)l < j)
- l = j;
- for (i = BMAX; i; i--)
- if (c[i])
- break;
- g = i; /* maximum code length */
- if ((uInt)l > i)
- l = i;
- *m = l;
-
-
- /* Adjust last length count to fill out codes, if needed */
- for (y = 1 << j; j < i; j++, y <<= 1)
- if ((y -= c[j]) < 0)
- return Z_DATA_ERROR;
- if ((y -= c[i]) < 0)
- return Z_DATA_ERROR;
- c[i] += y;
-
-
- /* Generate starting offsets into the value table for each length */
- x[1] = j = 0;
- p = c + 1; xp = x + 2;
- while (--i) { /* note that i == g from above */
- *xp++ = (j += *p++);
- }
-
-
- /* Make a table of values in order of bit lengths */
- p = b; i = 0;
- do {
- if ((j = *p++) != 0)
- v[x[j]++] = i;
- } while (++i < n);
- n = x[g]; /* set n to length of v */
-
-
- /* Generate the Huffman codes and for each, make the table entries */
- x[0] = i = 0; /* first Huffman code is zero */
- p = v; /* grab values in bit order */
- h = -1; /* no tables yet--level -1 */
- w = -l; /* bits decoded == (l * h) */
- u[0] = NULL; /* just to keep compilers happy */
- q = NULL; /* ditto */
- z = 0; /* ditto */
-
- /* go through the bit lengths (k already is bits in shortest code) */
- for (; k <= g; k++)
- {
- a = c[k];
- while (a--)
- {
- /* here i is the Huffman code of length k bits for value *p */
- /* make tables up to required level */
- while (k > w + l)
- {
- h++;
- w += l; /* previous table always l bits */
-
- /* compute minimum size table less than or equal to l bits */
- z = g - w;
- z = z > (uInt)l ? l : z; /* table size upper limit */
- if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
- { /* too few codes for k-w bit table */
- f -= a + 1; /* deduct codes from patterns left */
- xp = c + k;
- if (j < z)
- while (++j < z) /* try smaller tables up to z bits */
- {
- if ((f <<= 1) <= *++xp)
- break; /* enough codes to use up j bits */
- f -= *xp; /* else deduct codes from patterns */
- }
+ /* initialize state for loop */
+ huff = 0; /* starting code */
+ sym = 0; /* starting code symbol */
+ len = min; /* starting code length */
+ next = *table; /* current table to fill in */
+ curr = root; /* current table index bits */
+ drop = 0; /* current bits to drop from code for index */
+ low = (unsigned)(-1); /* trigger new sub-table when len > root */
+ used = 1U << root; /* use root table entries */
+ mask = used - 1; /* mask for comparing low */
+
+ /* check available table space */
+ if (type == LENS && used >= ENOUGH - MAXD)
+ return 1;
+
+ /* process all codes and make table entries */
+ for (;;) {
+ /* create table entry */
+ this.bits = (unsigned char)(len - drop);
+ if ((int)(work[sym]) < end) {
+ this.op = (unsigned char)0;
+ this.val = work[sym];
}
- z = 1 << j; /* table entries for j-bit table */
-
- /* allocate new table */
- if (*hn + z > MANY) /* (note: doesn't matter for fixed) */
- return Z_DATA_ERROR; /* overflow of MANY */
- u[h] = q = hp + *hn;
- *hn += z;
-
- /* connect to last table, if there is one */
- if (h)
- {
- x[h] = i; /* save pattern for backing up */
- r.bits = (Byte)l; /* bits to dump before this table */
- r.exop = (Byte)j; /* bits in this table */
- j = i >> (w - l);
- r.base = (uInt)(q - u[h-1] - j); /* offset to this table */
- u[h-1][j] = r; /* connect to last table */
+ else if ((int)(work[sym]) > end) {
+ this.op = (unsigned char)(extra[work[sym]]);
+ this.val = base[work[sym]];
+ }
+ else {
+ this.op = (unsigned char)(32 + 64); /* end of block */
+ this.val = 0;
}
- else
- *t = q; /* first table is returned result */
- }
-
- /* set up table entry in r */
- r.bits = (Byte)(k - w);
- if (p >= v + n)
- r.exop = 128 + 64; /* out of values--invalid code */
- else if (*p < s)
- {
- r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */
- r.base = *p++; /* simple code is just the value */
- }
- else
- {
- r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
- r.base = d[*p++ - s];
- }
-
- /* fill code-like entries with r */
- f = 1 << (k - w);
- for (j = i >> w; j < z; j += f)
- q[j] = r;
-
- /* backwards increment the k-bit code i */
- for (j = 1 << (k - 1); i & j; j >>= 1)
- i ^= j;
- i ^= j;
-
- /* backup over finished tables */
- mask = (1 << w) - 1; /* needed on HP, cc -O bug */
- while ((i & mask) != x[h])
- {
- h--; /* don't need to update q */
- w -= l;
- mask = (1 << w) - 1;
- }
- }
- }
+ /* replicate for those indices with low len bits equal to huff */
+ incr = 1U << (len - drop);
+ fill = 1U << curr;
+ min = fill; /* save offset to next table */
+ do {
+ fill -= incr;
+ next[(huff >> drop) + fill] = this;
+ } while (fill != 0);
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
- /* Return Z_BUF_ERROR if we were given an incomplete table */
- return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
-}
+ /* go to next symbol, update count, len */
+ sym++;
+ if (--(count[len]) == 0) {
+ if (len == max) break;
+ len = lens[work[sym]];
+ }
+ /* create new sub-table if needed */
+ if (len > root && (huff & mask) != low) {
+ /* if first time, transition to sub-tables */
+ if (drop == 0)
+ drop = root;
+
+ /* increment past last table */
+ next += min; /* here min is 1 << curr */
+
+ /* determine length of next table */
+ curr = len - drop;
+ left = (int)(1 << curr);
+ while (curr + drop < max) {
+ left -= count[curr + drop];
+ if (left <= 0) break;
+ curr++;
+ left <<= 1;
+ }
-int zlib_inflate_trees_bits(
- uInt *c, /* 19 code lengths */
- uInt *bb, /* bits tree desired/actual depth */
- inflate_huft **tb, /* bits tree result */
- inflate_huft *hp, /* space for trees */
- z_streamp z /* for messages */
-)
-{
- int r;
- uInt hn = 0; /* hufts used in space */
- uInt *v; /* work area for huft_build */
-
- v = WS(z)->tree_work_area_1;
- r = huft_build(c, 19, 19, NULL, NULL, tb, bb, hp, &hn, v);
- if (r == Z_DATA_ERROR)
- z->msg = (char*)"oversubscribed dynamic bit lengths tree";
- else if (r == Z_BUF_ERROR || *bb == 0)
- {
- z->msg = (char*)"incomplete dynamic bit lengths tree";
- r = Z_DATA_ERROR;
- }
- return r;
-}
+ /* check for enough space */
+ used += 1U << curr;
+ if (type == LENS && used >= ENOUGH - MAXD)
+ return 1;
-int zlib_inflate_trees_dynamic(
- uInt nl, /* number of literal/length codes */
- uInt nd, /* number of distance codes */
- uInt *c, /* that many (total) code lengths */
- uInt *bl, /* literal desired/actual bit depth */
- uInt *bd, /* distance desired/actual bit depth */
- inflate_huft **tl, /* literal/length tree result */
- inflate_huft **td, /* distance tree result */
- inflate_huft *hp, /* space for trees */
- z_streamp z /* for messages */
-)
-{
- int r;
- uInt hn = 0; /* hufts used in space */
- uInt *v; /* work area for huft_build */
-
- /* allocate work area */
- v = WS(z)->tree_work_area_2;
-
- /* build literal/length tree */
- r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);
- if (r != Z_OK || *bl == 0)
- {
- if (r == Z_DATA_ERROR)
- z->msg = (char*)"oversubscribed literal/length tree";
- else if (r != Z_MEM_ERROR)
- {
- z->msg = (char*)"incomplete literal/length tree";
- r = Z_DATA_ERROR;
- }
- return r;
- }
-
- /* build distance tree */
- r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);
- if (r != Z_OK || (*bd == 0 && nl > 257))
- {
- if (r == Z_DATA_ERROR)
- z->msg = (char*)"oversubscribed distance tree";
- else if (r == Z_BUF_ERROR) {
-#ifdef PKZIP_BUG_WORKAROUND
- r = Z_OK;
- }
-#else
- z->msg = (char*)"incomplete distance tree";
- r = Z_DATA_ERROR;
- }
- else if (r != Z_MEM_ERROR)
- {
- z->msg = (char*)"empty distance tree with lengths";
- r = Z_DATA_ERROR;
+ /* point entry in root table to sub-table */
+ low = huff & mask;
+ (*table)[low].op = (unsigned char)curr;
+ (*table)[low].bits = (unsigned char)root;
+ (*table)[low].val = (unsigned short)(next - *table);
+ }
}
- return r;
-#endif
- }
- /* done */
- return Z_OK;
-}
+ /*
+ Fill in rest of table for incomplete codes. This loop is similar to the
+ loop above in incrementing huff for table indices. It is assumed that
+ len is equal to curr + drop, so there is no loop needed to increment
+ through high index bits. When the current sub-table is filled, the loop
+ drops back to the root table to fill in any remaining entries there.
+ */
+ this.op = (unsigned char)64; /* invalid code marker */
+ this.bits = (unsigned char)(len - drop);
+ this.val = (unsigned short)0;
+ while (huff != 0) {
+ /* when done with sub-table, drop back to root table */
+ if (drop != 0 && (huff & mask) != low) {
+ drop = 0;
+ len = root;
+ next = *table;
+ this.bits = (unsigned char)len;
+ }
+ /* put invalid code marker in table */
+ next[huff >> drop] = this;
-int zlib_inflate_trees_fixed(
- uInt *bl, /* literal desired/actual bit depth */
- uInt *bd, /* distance desired/actual bit depth */
- inflate_huft **tl, /* literal/length tree result */
- inflate_huft **td, /* distance tree result */
- inflate_huft *hp, /* space for trees */
- z_streamp z /* for memory allocation */
-)
-{
- int i; /* temporary variable */
- unsigned l[288]; /* length list for huft_build */
- uInt *v; /* work area for huft_build */
-
- /* set up literal table */
- for (i = 0; i < 144; i++)
- l[i] = 8;
- for (; i < 256; i++)
- l[i] = 9;
- for (; i < 280; i++)
- l[i] = 7;
- for (; i < 288; i++) /* make a complete, but wrong code set */
- l[i] = 8;
- *bl = 9;
- v = WS(z)->tree_work_area_1;
- if ((i = huft_build(l, 288, 257, cplens, cplext, tl, bl, hp, &i, v)) != 0)
- return i;
-
- /* set up distance table */
- for (i = 0; i < 30; i++) /* make an incomplete code set */
- l[i] = 5;
- *bd = 5;
- if ((i = huft_build(l, 30, 0, cpdist, cpdext, td, bd, hp, &i, v)) > 1)
- return i;
-
- return Z_OK;
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+ }
+
+ /* set return parameters */
+ *table += used;
+ *bits = root;
+ return 0;
}
diff --git a/lib/zlib_inflate/inftrees.h b/lib/zlib_inflate/inftrees.h
index e37705a..5f5219b 100644
--- a/lib/zlib_inflate/inftrees.h
+++ b/lib/zlib_inflate/inftrees.h
@@ -1,6 +1,6 @@
/* inftrees.h -- header to use inftrees.c
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
*/
/* WARNING: this file should *not* be used by applications. It is
@@ -8,57 +8,48 @@
subject to change. Applications should only use zlib.h.
*/
-/* Huffman code lookup table entry--this entry is four bytes for machines
- that have 16-bit pointers (e.g. PC's in the small or medium model). */
-
-#ifndef _INFTREES_H
-#define _INFTREES_H
-
-typedef struct inflate_huft_s inflate_huft;
-
-struct inflate_huft_s {
- union {
- struct {
- Byte Exop; /* number of extra bits or operation */
- Byte Bits; /* number of bits in this code or subcode */
- } what;
- uInt pad; /* pad structure to a power of 2 (4 bytes for */
- } word; /* 16-bit, 8 bytes for 32-bit int's) */
- uInt base; /* literal, length base, distance base,
- or table offset */
-};
+/* Structure for decoding tables. Each entry provides either the
+ information needed to do the operation requested by the code that
+ indexed that table entry, or it provides a pointer to another
+ table that indexes more bits of the code. op indicates whether
+ the entry is a pointer to another table, a literal, a length or
+ distance, an end-of-block, or an invalid code. For a table
+ pointer, the low four bits of op is the number of index bits of
+ that table. For a length or distance, the low four bits of op
+ is the number of extra bits to get after the code. bits is
+ the number of bits in this code or part of the code to drop off
+ of the bit buffer. val is the actual byte to output in the case
+ of a literal, the base length or distance, or the offset from
+ the current table to the next table. Each entry is four bytes. */
+typedef struct {
+ unsigned char op; /* operation, extra bits, table bits */
+ unsigned char bits; /* bits in this part of the code */
+ unsigned short val; /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+ 00000000 - literal
+ 0000tttt - table link, tttt != 0 is the number of table index bits
+ 0001eeee - length or distance, eeee is the number of extra bits
+ 01100000 - end of block
+ 01000000 - invalid code
+ */
/* Maximum size of dynamic tree. The maximum found in a long but non-
- exhaustive search was 1004 huft structures (850 for length/literals
- and 154 for distances, the latter actually the result of an
- exhaustive search). The actual maximum is not known, but the
- value below is more than safe. */
-#define MANY 1440
-
-extern int zlib_inflate_trees_bits (
- uInt *, /* 19 code lengths */
- uInt *, /* bits tree desired/actual depth */
- inflate_huft **, /* bits tree result */
- inflate_huft *, /* space for trees */
- z_streamp); /* for messages */
-
-extern int zlib_inflate_trees_dynamic (
- uInt, /* number of literal/length codes */
- uInt, /* number of distance codes */
- uInt *, /* that many (total) code lengths */
- uInt *, /* literal desired/actual bit depth */
- uInt *, /* distance desired/actual bit depth */
- inflate_huft **, /* literal/length tree result */
- inflate_huft **, /* distance tree result */
- inflate_huft *, /* space for trees */
- z_streamp); /* for messages */
-
-extern int zlib_inflate_trees_fixed (
- uInt *, /* literal desired/actual bit depth */
- uInt *, /* distance desired/actual bit depth */
- inflate_huft **, /* literal/length tree result */
- inflate_huft **, /* distance tree result */
- inflate_huft *, /* space for trees */
- z_streamp); /* for memory allocation */
-
-#endif /* _INFTREES_H */
+ exhaustive search was 1444 code structures (852 for length/literals
+ and 592 for distances, the latter actually the result of an
+ exhaustive search). The true maximum is not known, but the value
+ below is more than safe. */
+#define ENOUGH 2048
+#define MAXD 592
+
+/* Type of code to build for inftable() */
+typedef enum {
+ CODES,
+ LENS,
+ DISTS
+} codetype;
+
+extern int zlib_inflate_table (codetype type, unsigned short *lens,
+ unsigned codes, code **table,
+ unsigned *bits, unsigned short *work);
diff --git a/lib/zlib_inflate/infutil.c b/lib/zlib_inflate/infutil.c
deleted file mode 100644
index 00202b3..0000000
--- a/lib/zlib_inflate/infutil.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/* inflate_util.c -- data and routines common to blocks and codes
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h
- */
-
-#include <linux/zutil.h>
-#include "infblock.h"
-#include "inftrees.h"
-#include "infcodes.h"
-#include "infutil.h"
-
-struct inflate_codes_state;
-
-/* And'ing with mask[n] masks the lower n bits */
-uInt zlib_inflate_mask[17] = {
- 0x0000,
- 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
- 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
-};
-
-
-/* copy as much as possible from the sliding window to the output area */
-int zlib_inflate_flush(
- inflate_blocks_statef *s,
- z_streamp z,
- int r
-)
-{
- uInt n;
- Byte *p;
- Byte *q;
-
- /* local copies of source and destination pointers */
- p = z->next_out;
- q = s->read;
-
- /* compute number of bytes to copy as far as end of window */
- n = (uInt)((q <= s->write ? s->write : s->end) - q);
- if (n > z->avail_out) n = z->avail_out;
- if (n && r == Z_BUF_ERROR) r = Z_OK;
-
- /* update counters */
- z->avail_out -= n;
- z->total_out += n;
-
- /* update check information */
- if (s->checkfn != NULL)
- z->adler = s->check = (*s->checkfn)(s->check, q, n);
-
- /* copy as far as end of window */
- memcpy(p, q, n);
- p += n;
- q += n;
-
- /* see if more to copy at beginning of window */
- if (q == s->end)
- {
- /* wrap pointers */
- q = s->window;
- if (s->write == s->end)
- s->write = s->window;
-
- /* compute bytes to copy */
- n = (uInt)(s->write - q);
- if (n > z->avail_out) n = z->avail_out;
- if (n && r == Z_BUF_ERROR) r = Z_OK;
-
- /* update counters */
- z->avail_out -= n;
- z->total_out += n;
-
- /* update check information */
- if (s->checkfn != NULL)
- z->adler = s->check = (*s->checkfn)(s->check, q, n);
-
- /* copy */
- memcpy(p, q, n);
- p += n;
- q += n;
- }
-
- /* update pointers */
- z->next_out = p;
- s->read = q;
-
- /* done */
- return r;
-}
diff --git a/lib/zlib_inflate/infutil.h b/lib/zlib_inflate/infutil.h
index a15875f..eb1a900 100644
--- a/lib/zlib_inflate/infutil.h
+++ b/lib/zlib_inflate/infutil.h
@@ -11,184 +11,12 @@
#ifndef _INFUTIL_H
#define _INFUTIL_H
-#include <linux/zconf.h>
-#include "inftrees.h"
-#include "infcodes.h"
-
-typedef enum {
- TYPE, /* get type bits (3, including end bit) */
- LENS, /* get lengths for stored */
- STORED, /* processing stored block */
- TABLE, /* get table lengths */
- BTREE, /* get bit lengths tree for a dynamic block */
- DTREE, /* get length, distance trees for a dynamic block */
- CODES, /* processing fixed or dynamic block */
- DRY, /* output remaining window bytes */
- B_DONE, /* finished last block, done */
- B_BAD} /* got a data error--stuck here */
-inflate_block_mode;
-
-/* inflate blocks semi-private state */
-struct inflate_blocks_state {
-
- /* mode */
- inflate_block_mode mode; /* current inflate_block mode */
-
- /* mode dependent information */
- union {
- uInt left; /* if STORED, bytes left to copy */
- struct {
- uInt table; /* table lengths (14 bits) */
- uInt index; /* index into blens (or border) */
- uInt *blens; /* bit lengths of codes */
- uInt bb; /* bit length tree depth */
- inflate_huft *tb; /* bit length decoding tree */
- } trees; /* if DTREE, decoding info for trees */
- struct {
- inflate_codes_statef
- *codes;
- } decode; /* if CODES, current state */
- } sub; /* submode */
- uInt last; /* true if this block is the last block */
-
- /* mode independent information */
- uInt bitk; /* bits in bit buffer */
- uLong bitb; /* bit buffer */
- inflate_huft *hufts; /* single malloc for tree space */
- Byte *window; /* sliding window */
- Byte *end; /* one byte after sliding window */
- Byte *read; /* window read pointer */
- Byte *write; /* window write pointer */
- check_func checkfn; /* check function */
- uLong check; /* check on output */
-
-};
-
-
-/* defines for inflate input/output */
-/* update pointers and return */
-#define UPDBITS {s->bitb=b;s->bitk=k;}
-#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
-#define UPDOUT {s->write=q;}
-#define UPDATE {UPDBITS UPDIN UPDOUT}
-#define LEAVE {UPDATE return zlib_inflate_flush(s,z,r);}
-/* get bytes and bits */
-#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
-#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
-#define NEXTBYTE (n--,*p++)
-#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
-#define DUMPBITS(j) {b>>=(j);k-=(j);}
-/* output bytes */
-#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
-#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
-#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
-#define FLUSH {UPDOUT r=zlib_inflate_flush(s,z,r); LOADOUT}
-#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
-#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
-/* load local pointers */
-#define LOAD {LOADIN LOADOUT}
-
-/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
-extern uInt zlib_inflate_mask[17];
-
-/* copy as much as possible from the sliding window to the output area */
-extern int zlib_inflate_flush (
- inflate_blocks_statef *,
- z_streamp ,
- int);
-
-/* inflate private state */
-typedef enum {
- METHOD, /* waiting for method byte */
- FLAG, /* waiting for flag byte */
- DICT4, /* four dictionary check bytes to go */
- DICT3, /* three dictionary check bytes to go */
- DICT2, /* two dictionary check bytes to go */
- DICT1, /* one dictionary check byte to go */
- DICT0, /* waiting for inflateSetDictionary */
- BLOCKS, /* decompressing blocks */
- CHECK4, /* four check bytes to go */
- CHECK3, /* three check bytes to go */
- CHECK2, /* two check bytes to go */
- CHECK1, /* one check byte to go */
- I_DONE, /* finished check, done */
- I_BAD} /* got an error--stay here */
-inflate_mode;
-
-struct internal_state {
-
- /* mode */
- inflate_mode mode; /* current inflate mode */
-
- /* mode dependent information */
- union {
- uInt method; /* if FLAGS, method byte */
- struct {
- uLong was; /* computed check value */
- uLong need; /* stream check value */
- } check; /* if CHECK, check values to compare */
- uInt marker; /* if BAD, inflateSync's marker bytes count */
- } sub; /* submode */
-
- /* mode independent information */
- int nowrap; /* flag for no wrapper */
- uInt wbits; /* log2(window size) (8..15, defaults to 15) */
- inflate_blocks_statef
- *blocks; /* current inflate_blocks state */
-
-};
-
-/* inflate codes private state */
-typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
- START, /* x: set up for LEN */
- LEN, /* i: get length/literal/eob next */
- LENEXT, /* i: getting length extra (have base) */
- DIST, /* i: get distance next */
- DISTEXT, /* i: getting distance extra */
- COPY, /* o: copying bytes in window, waiting for space */
- LIT, /* o: got literal, waiting for output space */
- WASH, /* o: got eob, possibly still output waiting */
- END, /* x: got eob and all data flushed */
- BADCODE} /* x: got error */
-inflate_codes_mode;
-
-struct inflate_codes_state {
-
- /* mode */
- inflate_codes_mode mode; /* current inflate_codes mode */
-
- /* mode dependent information */
- uInt len;
- union {
- struct {
- inflate_huft *tree; /* pointer into tree */
- uInt need; /* bits needed */
- } code; /* if LEN or DIST, where in tree */
- uInt lit; /* if LIT, literal */
- struct {
- uInt get; /* bits to get for extra */
- uInt dist; /* distance back to copy from */
- } copy; /* if EXT or COPY, where and how much */
- } sub; /* submode */
-
- /* mode independent information */
- Byte lbits; /* ltree bits decoded per branch */
- Byte dbits; /* dtree bits decoder per branch */
- inflate_huft *ltree; /* literal/length/eob tree */
- inflate_huft *dtree; /* distance tree */
-
-};
+#include <linux/zlib.h>
/* memory allocation for inflation */
struct inflate_workspace {
- inflate_codes_statef working_state;
- struct inflate_blocks_state working_blocks_state;
- struct internal_state internal_state;
- unsigned int tree_work_area_1[19];
- unsigned int tree_work_area_2[288];
- unsigned working_blens[258 + 0x1f + 0x1f];
- inflate_huft working_hufts[MANY];
+ struct inflate_state inflate_state;
unsigned char working_window[1 << MAX_WBITS];
};
diff --git a/mm/Kconfig b/mm/Kconfig
index 332f5c2..66e65ab 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -138,8 +138,8 @@ config SPLIT_PTLOCK_CPUS
#
config MIGRATION
bool "Page migration"
- def_bool y if NUMA
- depends on SWAP && NUMA
+ def_bool y
+ depends on NUMA
help
Allows the migration of the physical location of pages of processes
while the virtual addresses are not changed. This is useful for
diff --git a/mm/filemap.c b/mm/filemap.c
index fd57442..9c7334b 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <linux/compiler.h>
#include <linux/fs.h>
+#include <linux/uaccess.h>
#include <linux/aio.h>
#include <linux/capability.h>
#include <linux/kernel_stat.h>
@@ -38,7 +39,6 @@
*/
#include <linux/buffer_head.h> /* for generic_osync_inode */
-#include <asm/uaccess.h>
#include <asm/mman.h>
static ssize_t
@@ -171,15 +171,17 @@ static int sync_page(void *word)
}
/**
- * filemap_fdatawrite_range - start writeback against all of a mapping's
- * dirty pages that lie within the byte offsets <start, end>
+ * __filemap_fdatawrite_range - start writeback on mapping dirty pages in range
* @mapping: address space structure to write
* @start: offset in bytes where the range starts
* @end: offset in bytes where the range ends (inclusive)
* @sync_mode: enable synchronous operation
*
+ * Start writeback against all of a mapping's dirty pages that lie
+ * within the byte offsets <start, end> inclusive.
+ *
* If sync_mode is WB_SYNC_ALL then this is a "data integrity" operation, as
- * opposed to a regular memory * cleansing writeback. The difference between
+ * opposed to a regular memory cleansing writeback. The difference between
* these two operations is that if a dirty page/buffer is encountered, it must
* be waited upon, and not just skipped over.
*/
@@ -190,8 +192,8 @@ int __filemap_fdatawrite_range(struct address_space *mapping, loff_t start,
struct writeback_control wbc = {
.sync_mode = sync_mode,
.nr_to_write = mapping->nrpages * 2,
- .start = start,
- .end = end,
+ .range_start = start,
+ .range_end = end,
};
if (!mapping_cap_writeback_dirty(mapping))
@@ -204,7 +206,7 @@ int __filemap_fdatawrite_range(struct address_space *mapping, loff_t start,
static inline int __filemap_fdatawrite(struct address_space *mapping,
int sync_mode)
{
- return __filemap_fdatawrite_range(mapping, 0, 0, sync_mode);
+ return __filemap_fdatawrite_range(mapping, 0, LLONG_MAX, sync_mode);
}
int filemap_fdatawrite(struct address_space *mapping)
@@ -219,7 +221,10 @@ static int filemap_fdatawrite_range(struct address_space *mapping, loff_t start,
return __filemap_fdatawrite_range(mapping, start, end, WB_SYNC_ALL);
}
-/*
+/**
+ * filemap_flush - mostly a non-blocking flush
+ * @mapping: target address_space
+ *
* This is a mostly non-blocking flush. Not suitable for data-integrity
* purposes - I/O may not be started against all dirty pages.
*/
@@ -229,7 +234,12 @@ int filemap_flush(struct address_space *mapping)
}
EXPORT_SYMBOL(filemap_flush);
-/*
+/**
+ * wait_on_page_writeback_range - wait for writeback to complete
+ * @mapping: target address_space
+ * @start: beginning page index
+ * @end: ending page index
+ *
* Wait for writeback to complete against pages indexed by start->end
* inclusive
*/
@@ -276,7 +286,13 @@ int wait_on_page_writeback_range(struct address_space *mapping,
return ret;
}
-/*
+/**
+ * sync_page_range - write and wait on all pages in the passed range
+ * @inode: target inode
+ * @mapping: target address_space
+ * @pos: beginning offset in pages to write
+ * @count: number of bytes to write
+ *
* Write and wait upon all the pages in the passed range. This is a "data
* integrity" operation. It waits upon in-flight writeout before starting and
* waiting upon new writeout. If there was an IO error, return it.
@@ -305,7 +321,13 @@ int sync_page_range(struct inode *inode, struct address_space *mapping,
}
EXPORT_SYMBOL(sync_page_range);
-/*
+/**
+ * sync_page_range_nolock
+ * @inode: target inode
+ * @mapping: target address_space
+ * @pos: beginning offset in pages to write
+ * @count: number of bytes to write
+ *
* Note: Holding i_mutex across sync_page_range_nolock is not a good idea
* as it forces O_SYNC writers to different parts of the same file
* to be serialised right until io completion.
@@ -329,10 +351,11 @@ int sync_page_range_nolock(struct inode *inode, struct address_space *mapping,
EXPORT_SYMBOL(sync_page_range_nolock);
/**
- * filemap_fdatawait - walk the list of under-writeback pages of the given
- * address space and wait for all of them.
- *
+ * filemap_fdatawait - wait for all under-writeback pages to complete
* @mapping: address space structure to wait for
+ *
+ * Walk the list of under-writeback pages of the given address space
+ * and wait for all of them.
*/
int filemap_fdatawait(struct address_space *mapping)
{
@@ -368,7 +391,12 @@ int filemap_write_and_wait(struct address_space *mapping)
}
EXPORT_SYMBOL(filemap_write_and_wait);
-/*
+/**
+ * filemap_write_and_wait_range - write out & wait on a file range
+ * @mapping: the address_space for the pages
+ * @lstart: offset in bytes where the range starts
+ * @lend: offset in bytes where the range ends (inclusive)
+ *
* Write out and wait upon file offsets lstart->lend, inclusive.
*
* Note that `lend' is inclusive (describes the last byte to be written) so
@@ -394,8 +422,14 @@ int filemap_write_and_wait_range(struct address_space *mapping,
return err;
}
-/*
- * This function is used to add newly allocated pagecache pages:
+/**
+ * add_to_page_cache - add newly allocated pagecache pages
+ * @page: page to add
+ * @mapping: the page's address_space
+ * @offset: page index
+ * @gfp_mask: page allocation mode
+ *
+ * This function is used to add newly allocated pagecache pages;
* the page is new, so we can just run SetPageLocked() against it.
* The other page state flags were set by rmqueue().
*
@@ -422,7 +456,6 @@ int add_to_page_cache(struct page *page, struct address_space *mapping,
}
return error;
}
-
EXPORT_SYMBOL(add_to_page_cache);
int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
@@ -489,8 +522,7 @@ void fastcall wait_on_page_bit(struct page *page, int bit_nr)
EXPORT_SYMBOL(wait_on_page_bit);
/**
- * unlock_page() - unlock a locked page
- *
+ * unlock_page - unlock a locked page
* @page: the page
*
* Unlocks the page and wakes up sleepers in ___wait_on_page_locked().
@@ -513,8 +545,9 @@ void fastcall unlock_page(struct page *page)
}
EXPORT_SYMBOL(unlock_page);
-/*
- * End writeback against a page.
+/**
+ * end_page_writeback - end writeback against a page
+ * @page: the page
*/
void end_page_writeback(struct page *page)
{
@@ -527,10 +560,11 @@ void end_page_writeback(struct page *page)
}
EXPORT_SYMBOL(end_page_writeback);
-/*
- * Get a lock on the page, assuming we need to sleep to get it.
+/**
+ * __lock_page - get a lock on the page, assuming we need to sleep to get it
+ * @page: the page to lock
*
- * Ugly: running sync_page() in state TASK_UNINTERRUPTIBLE is scary. If some
+ * Ugly. Running sync_page() in state TASK_UNINTERRUPTIBLE is scary. If some
* random driver's requestfn sets TASK_RUNNING, we could busywait. However
* chances are that on the second loop, the block layer's plug list is empty,
* so sync_page() will then return in state TASK_UNINTERRUPTIBLE.
@@ -544,8 +578,12 @@ void fastcall __lock_page(struct page *page)
}
EXPORT_SYMBOL(__lock_page);
-/*
- * a rather lightweight function, finding and getting a reference to a
+/**
+ * find_get_page - find and get a page reference
+ * @mapping: the address_space to search
+ * @offset: the page index
+ *
+ * A rather lightweight function, finding and getting a reference to a
* hashed page atomically.
*/
struct page * find_get_page(struct address_space *mapping, unsigned long offset)
@@ -559,11 +597,14 @@ struct page * find_get_page(struct address_space *mapping, unsigned long offset)
read_unlock_irq(&mapping->tree_lock);
return page;
}
-
EXPORT_SYMBOL(find_get_page);
-/*
- * Same as above, but trylock it instead of incrementing the count.
+/**
+ * find_trylock_page - find and lock a page
+ * @mapping: the address_space to search
+ * @offset: the page index
+ *
+ * Same as find_get_page(), but trylock it instead of incrementing the count.
*/
struct page *find_trylock_page(struct address_space *mapping, unsigned long offset)
{
@@ -576,12 +617,10 @@ struct page *find_trylock_page(struct address_space *mapping, unsigned long offs
read_unlock_irq(&mapping->tree_lock);
return page;
}
-
EXPORT_SYMBOL(find_trylock_page);
/**
* find_lock_page - locate, pin and lock a pagecache page
- *
* @mapping: the address_space to search
* @offset: the page index
*
@@ -617,12 +656,10 @@ repeat:
read_unlock_irq(&mapping->tree_lock);
return page;
}
-
EXPORT_SYMBOL(find_lock_page);
/**
* find_or_create_page - locate or add a pagecache page
- *
* @mapping: the page's address_space
* @index: the page's index into the mapping
* @gfp_mask: page allocation mode
@@ -663,7 +700,6 @@ repeat:
page_cache_release(cached_page);
return page;
}
-
EXPORT_SYMBOL(find_or_create_page);
/**
@@ -729,9 +765,16 @@ unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index,
return i;
}
-/*
+/**
+ * find_get_pages_tag - find and return pages that match @tag
+ * @mapping: the address_space to search
+ * @index: the starting page index
+ * @tag: the tag index
+ * @nr_pages: the maximum number of pages
+ * @pages: where the resulting pages are placed
+ *
* Like find_get_pages, except we only return pages which are tagged with
- * `tag'. We update *index to index the next page for the traversal.
+ * @tag. We update @index to index the next page for the traversal.
*/
unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index,
int tag, unsigned int nr_pages, struct page **pages)
@@ -750,7 +793,11 @@ unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index,
return ret;
}
-/*
+/**
+ * grab_cache_page_nowait - returns locked page at given index in given cache
+ * @mapping: target address_space
+ * @index: the page index
+ *
* Same as grab_cache_page, but do not wait if the page is unavailable.
* This is intended for speculative data generators, where the data can
* be regenerated if the page couldn't be grabbed. This routine should
@@ -779,19 +826,51 @@ grab_cache_page_nowait(struct address_space *mapping, unsigned long index)
}
return page;
}
-
EXPORT_SYMBOL(grab_cache_page_nowait);
/*
+ * CD/DVDs are error prone. When a medium error occurs, the driver may fail
+ * a _large_ part of the i/o request. Imagine the worst scenario:
+ *
+ * ---R__________________________________________B__________
+ * ^ reading here ^ bad block(assume 4k)
+ *
+ * read(R) => miss => readahead(R...B) => media error => frustrating retries
+ * => failing the whole request => read(R) => read(R+1) =>
+ * readahead(R+1...B+1) => bang => read(R+2) => read(R+3) =>
+ * readahead(R+3...B+2) => bang => read(R+3) => read(R+4) =>
+ * readahead(R+4...B+3) => bang => read(R+4) => read(R+5) => ......
+ *
+ * It is going insane. Fix it by quickly scaling down the readahead size.
+ */
+static void shrink_readahead_size_eio(struct file *filp,
+ struct file_ra_state *ra)
+{
+ if (!ra->ra_pages)
+ return;
+
+ ra->ra_pages /= 4;
+ printk(KERN_WARNING "Reducing readahead size to %luK\n",
+ ra->ra_pages << (PAGE_CACHE_SHIFT - 10));
+}
+
+/**
+ * do_generic_mapping_read - generic file read routine
+ * @mapping: address_space to be read
+ * @_ra: file's readahead state
+ * @filp: the file to read
+ * @ppos: current file position
+ * @desc: read_descriptor
+ * @actor: read method
+ *
* This is a generic file read routine, and uses the
- * mapping->a_ops->readpage() function for the actual low-level
- * stuff.
+ * mapping->a_ops->readpage() function for the actual low-level stuff.
*
* This is really ugly. But the goto's actually try to clarify some
* of the logic when it comes to error handling etc.
*
- * Note the struct file* is only passed for the use of readpage. It may be
- * NULL.
+ * Note the struct file* is only passed for the use of readpage.
+ * It may be NULL.
*/
void do_generic_mapping_read(struct address_space *mapping,
struct file_ra_state *_ra,
@@ -932,6 +1011,7 @@ readpage:
}
unlock_page(page);
error = -EIO;
+ shrink_readahead_size_eio(filp, &ra);
goto readpage_error;
}
unlock_page(page);
@@ -1004,7 +1084,6 @@ out:
if (filp)
file_accessed(filp);
}
-
EXPORT_SYMBOL(do_generic_mapping_read);
int file_read_actor(read_descriptor_t *desc, struct page *page,
@@ -1045,7 +1124,13 @@ success:
return size;
}
-/*
+/**
+ * __generic_file_aio_read - generic filesystem read routine
+ * @iocb: kernel I/O control block
+ * @iov: io vector request
+ * @nr_segs: number of segments in the iovec
+ * @ppos: current file position
+ *
* This is the "read()" routine for all filesystems
* that can use the page cache directly.
*/
@@ -1124,7 +1209,6 @@ __generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
out:
return retval;
}
-
EXPORT_SYMBOL(__generic_file_aio_read);
ssize_t
@@ -1135,7 +1219,6 @@ generic_file_aio_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t
BUG_ON(iocb->ki_pos != pos);
return __generic_file_aio_read(iocb, &local_iov, 1, &iocb->ki_pos);
}
-
EXPORT_SYMBOL(generic_file_aio_read);
ssize_t
@@ -1151,7 +1234,6 @@ generic_file_read(struct file *filp, char __user *buf, size_t count, loff_t *ppo
ret = wait_on_sync_kiocb(&kiocb);
return ret;
}
-
EXPORT_SYMBOL(generic_file_read);
int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
@@ -1192,7 +1274,6 @@ ssize_t generic_file_sendfile(struct file *in_file, loff_t *ppos,
return desc.written;
return desc.error;
}
-
EXPORT_SYMBOL(generic_file_sendfile);
static ssize_t
@@ -1228,11 +1309,15 @@ asmlinkage ssize_t sys_readahead(int fd, loff_t offset, size_t count)
}
#ifdef CONFIG_MMU
-/*
+static int FASTCALL(page_cache_read(struct file * file, unsigned long offset));
+/**
+ * page_cache_read - adds requested page to the page cache if not already there
+ * @file: file to read
+ * @offset: page index
+ *
* This adds the requested page to the page cache if it isn't already there,
* and schedules an I/O to read in its contents from disk.
*/
-static int FASTCALL(page_cache_read(struct file * file, unsigned long offset));
static int fastcall page_cache_read(struct file * file, unsigned long offset)
{
struct address_space *mapping = file->f_mapping;
@@ -1259,7 +1344,12 @@ static int fastcall page_cache_read(struct file * file, unsigned long offset)
#define MMAP_LOTSAMISS (100)
-/*
+/**
+ * filemap_nopage - read in file data for page fault handling
+ * @area: the applicable vm_area
+ * @address: target address to read in
+ * @type: returned with VM_FAULT_{MINOR,MAJOR} if not %NULL
+ *
* filemap_nopage() is invoked via the vma operations vector for a
* mapped memory region to read in file data during a page fault.
*
@@ -1459,10 +1549,10 @@ page_not_uptodate:
* Things didn't work out. Return zero to tell the
* mm layer so, possibly freeing the page cache page first.
*/
+ shrink_readahead_size_eio(file, ra);
page_cache_release(page);
return NULL;
}
-
EXPORT_SYMBOL(filemap_nopage);
static struct page * filemap_getpage(struct file *file, unsigned long pgoff,
@@ -1716,7 +1806,13 @@ repeat:
return page;
}
-/*
+/**
+ * read_cache_page - read into page cache, fill it if needed
+ * @mapping: the page's address_space
+ * @index: the page index
+ * @filler: function to perform the read
+ * @data: destination for read data
+ *
* Read into the page cache. If a page already exists,
* and PageUptodate() is not set, try to fill the page.
*/
@@ -1754,7 +1850,6 @@ retry:
out:
return page;
}
-
EXPORT_SYMBOL(read_cache_page);
/*
@@ -1825,7 +1920,7 @@ int remove_suid(struct dentry *dentry)
EXPORT_SYMBOL(remove_suid);
size_t
-__filemap_copy_from_user_iovec(char *vaddr,
+__filemap_copy_from_user_iovec_inatomic(char *vaddr,
const struct iovec *iov, size_t base, size_t bytes)
{
size_t copied = 0, left = 0;
@@ -1835,18 +1930,14 @@ __filemap_copy_from_user_iovec(char *vaddr,
int copy = min(bytes, iov->iov_len - base);
base = 0;
- left = __copy_from_user_inatomic(vaddr, buf, copy);
+ left = __copy_from_user_inatomic_nocache(vaddr, buf, copy);
copied += copy;
bytes -= copy;
vaddr += copy;
iov++;
- if (unlikely(left)) {
- /* zero the rest of the target like __copy_from_user */
- if (bytes)
- memset(vaddr, 0, bytes);
+ if (unlikely(left))
break;
- }
}
return copied - left;
}
@@ -1854,7 +1945,7 @@ __filemap_copy_from_user_iovec(char *vaddr,
/*
* Performs necessary checks before doing a write
*
- * Can adjust writing position aor amount of bytes to write.
+ * Can adjust writing position or amount of bytes to write.
* Returns appropriate error code that caller should return or
* zero in case that write should be allowed.
*/
diff --git a/mm/filemap.h b/mm/filemap.h
index 13793ba..536979f 100644
--- a/mm/filemap.h
+++ b/mm/filemap.h
@@ -13,18 +13,26 @@
#include <linux/highmem.h>
#include <linux/uio.h>
#include <linux/config.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
size_t
-__filemap_copy_from_user_iovec(char *vaddr,
- const struct iovec *iov,
- size_t base,
- size_t bytes);
+__filemap_copy_from_user_iovec_inatomic(char *vaddr,
+ const struct iovec *iov,
+ size_t base,
+ size_t bytes);
/*
* Copy as much as we can into the page and return the number of bytes which
* were sucessfully copied. If a fault is encountered then clear the page
* out to (offset+bytes) and return the number of bytes which were copied.
+ *
+ * NOTE: For this to work reliably we really want copy_from_user_inatomic_nocache
+ * to *NOT* zero any tail of the buffer that it failed to copy. If it does,
+ * and if the following non-atomic copy succeeds, then there is a small window
+ * where the target page contains neither the data before the write, nor the
+ * data after the write (it contains zero). A read at this time will see
+ * data that is inconsistent with any ordering of the read and the write.
+ * (This has been detected in practice).
*/
static inline size_t
filemap_copy_from_user(struct page *page, unsigned long offset,
@@ -34,13 +42,13 @@ filemap_copy_from_user(struct page *page, unsigned long offset,
int left;
kaddr = kmap_atomic(page, KM_USER0);
- left = __copy_from_user_inatomic(kaddr + offset, buf, bytes);
+ left = __copy_from_user_inatomic_nocache(kaddr + offset, buf, bytes);
kunmap_atomic(kaddr, KM_USER0);
if (left != 0) {
/* Do it the slow way */
kaddr = kmap(page);
- left = __copy_from_user(kaddr + offset, buf, bytes);
+ left = __copy_from_user_nocache(kaddr + offset, buf, bytes);
kunmap(page);
}
return bytes - left;
@@ -60,13 +68,15 @@ filemap_copy_from_user_iovec(struct page *page, unsigned long offset,
size_t copied;
kaddr = kmap_atomic(page, KM_USER0);
- copied = __filemap_copy_from_user_iovec(kaddr + offset, iov,
- base, bytes);
+ copied = __filemap_copy_from_user_iovec_inatomic(kaddr + offset, iov,
+ base, bytes);
kunmap_atomic(kaddr, KM_USER0);
if (copied != bytes) {
kaddr = kmap(page);
- copied = __filemap_copy_from_user_iovec(kaddr + offset, iov,
- base, bytes);
+ copied = __filemap_copy_from_user_iovec_inatomic(kaddr + offset, iov,
+ base, bytes);
+ if (bytes - copied)
+ memset(kaddr + offset + copied, 0, bytes - copied);
kunmap(page);
}
return copied;
diff --git a/mm/fremap.c b/mm/fremap.c
index 9f381e5..21b7d0c 100644
--- a/mm/fremap.c
+++ b/mm/fremap.c
@@ -83,6 +83,7 @@ int install_page(struct mm_struct *mm, struct vm_area_struct *vma,
page_add_file_rmap(page);
pte_val = *pte;
update_mmu_cache(vma, addr, pte_val);
+ lazy_mmu_prot_update(pte_val);
err = 0;
unlock:
pte_unmap_unlock(pte, ptl);
@@ -114,7 +115,13 @@ int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma,
set_pte_at(mm, addr, pte, pgoff_to_pte(pgoff));
pte_val = *pte;
- update_mmu_cache(vma, addr, pte_val);
+ /*
+ * We don't need to run update_mmu_cache() here because the "file pte"
+ * being installed by install_file_pte() is not a real pte - it's a
+ * non-present entry (like a swap entry), noting what file offset should
+ * be mapped there when there's a fault (in a non-linear vma where
+ * that's not obvious).
+ */
pte_unmap_unlock(pte, ptl);
err = 0;
out:
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 832f676..df49997 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -22,7 +22,7 @@
#include "internal.h"
const unsigned long hugetlb_zero = 0, hugetlb_infinity = ~0UL;
-static unsigned long nr_huge_pages, free_huge_pages, reserved_huge_pages;
+static unsigned long nr_huge_pages, free_huge_pages, resv_huge_pages;
unsigned long max_huge_pages;
static struct list_head hugepage_freelists[MAX_NUMNODES];
static unsigned int nr_huge_pages_node[MAX_NUMNODES];
@@ -123,39 +123,13 @@ static int alloc_fresh_huge_page(void)
static struct page *alloc_huge_page(struct vm_area_struct *vma,
unsigned long addr)
{
- struct inode *inode = vma->vm_file->f_dentry->d_inode;
struct page *page;
- int use_reserve = 0;
- unsigned long idx;
spin_lock(&hugetlb_lock);
-
- if (vma->vm_flags & VM_MAYSHARE) {
-
- /* idx = radix tree index, i.e. offset into file in
- * HPAGE_SIZE units */
- idx = ((addr - vma->vm_start) >> HPAGE_SHIFT)
- + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT));
-
- /* The hugetlbfs specific inode info stores the number
- * of "guaranteed available" (huge) pages. That is,
- * the first 'prereserved_hpages' pages of the inode
- * are either already instantiated, or have been
- * pre-reserved (by hugetlb_reserve_for_inode()). Here
- * we're in the process of instantiating the page, so
- * we use this to determine whether to draw from the
- * pre-reserved pool or the truly free pool. */
- if (idx < HUGETLBFS_I(inode)->prereserved_hpages)
- use_reserve = 1;
- }
-
- if (!use_reserve) {
- if (free_huge_pages <= reserved_huge_pages)
- goto fail;
- } else {
- BUG_ON(reserved_huge_pages == 0);
- reserved_huge_pages--;
- }
+ if (vma->vm_flags & VM_MAYSHARE)
+ resv_huge_pages--;
+ else if (free_huge_pages <= resv_huge_pages)
+ goto fail;
page = dequeue_huge_page(vma, addr);
if (!page)
@@ -165,96 +139,11 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma,
set_page_refcounted(page);
return page;
- fail:
- WARN_ON(use_reserve); /* reserved allocations shouldn't fail */
+fail:
spin_unlock(&hugetlb_lock);
return NULL;
}
-/* hugetlb_extend_reservation()
- *
- * Ensure that at least 'atleast' hugepages are, and will remain,
- * available to instantiate the first 'atleast' pages of the given
- * inode. If the inode doesn't already have this many pages reserved
- * or instantiated, set aside some hugepages in the reserved pool to
- * satisfy later faults (or fail now if there aren't enough, rather
- * than getting the SIGBUS later).
- */
-int hugetlb_extend_reservation(struct hugetlbfs_inode_info *info,
- unsigned long atleast)
-{
- struct inode *inode = &info->vfs_inode;
- unsigned long change_in_reserve = 0;
- int ret = 0;
-
- spin_lock(&hugetlb_lock);
- read_lock_irq(&inode->i_mapping->tree_lock);
-
- if (info->prereserved_hpages >= atleast)
- goto out;
-
- /* Because we always call this on shared mappings, none of the
- * pages beyond info->prereserved_hpages can have been
- * instantiated, so we need to reserve all of them now. */
- change_in_reserve = atleast - info->prereserved_hpages;
-
- if ((reserved_huge_pages + change_in_reserve) > free_huge_pages) {
- ret = -ENOMEM;
- goto out;
- }
-
- reserved_huge_pages += change_in_reserve;
- info->prereserved_hpages = atleast;
-
- out:
- read_unlock_irq(&inode->i_mapping->tree_lock);
- spin_unlock(&hugetlb_lock);
-
- return ret;
-}
-
-/* hugetlb_truncate_reservation()
- *
- * This returns pages reserved for the given inode to the general free
- * hugepage pool. If the inode has any pages prereserved, but not
- * instantiated, beyond offset (atmost << HPAGE_SIZE), then release
- * them.
- */
-void hugetlb_truncate_reservation(struct hugetlbfs_inode_info *info,
- unsigned long atmost)
-{
- struct inode *inode = &info->vfs_inode;
- struct address_space *mapping = inode->i_mapping;
- unsigned long idx;
- unsigned long change_in_reserve = 0;
- struct page *page;
-
- spin_lock(&hugetlb_lock);
- read_lock_irq(&inode->i_mapping->tree_lock);
-
- if (info->prereserved_hpages <= atmost)
- goto out;
-
- /* Count pages which were reserved, but not instantiated, and
- * which we can now release. */
- for (idx = atmost; idx < info->prereserved_hpages; idx++) {
- page = radix_tree_lookup(&mapping->page_tree, idx);
- if (!page)
- /* Pages which are already instantiated can't
- * be unreserved (and in fact have already
- * been removed from the reserved pool) */
- change_in_reserve++;
- }
-
- BUG_ON(reserved_huge_pages < change_in_reserve);
- reserved_huge_pages -= change_in_reserve;
- info->prereserved_hpages = atmost;
-
- out:
- read_unlock_irq(&inode->i_mapping->tree_lock);
- spin_unlock(&hugetlb_lock);
-}
-
static int __init hugetlb_init(void)
{
unsigned long i;
@@ -334,7 +223,7 @@ static unsigned long set_max_huge_pages(unsigned long count)
return nr_huge_pages;
spin_lock(&hugetlb_lock);
- count = max(count, reserved_huge_pages);
+ count = max(count, resv_huge_pages);
try_to_free_low(count);
while (count < nr_huge_pages) {
struct page *page = dequeue_huge_page(NULL, 0);
@@ -361,11 +250,11 @@ int hugetlb_report_meminfo(char *buf)
return sprintf(buf,
"HugePages_Total: %5lu\n"
"HugePages_Free: %5lu\n"
- "HugePages_Rsvd: %5lu\n"
+ "HugePages_Rsvd: %5lu\n"
"Hugepagesize: %5lu kB\n",
nr_huge_pages,
free_huge_pages,
- reserved_huge_pages,
+ resv_huge_pages,
HPAGE_SIZE/1024);
}
@@ -754,3 +643,156 @@ void hugetlb_change_protection(struct vm_area_struct *vma,
flush_tlb_range(vma, start, end);
}
+struct file_region {
+ struct list_head link;
+ long from;
+ long to;
+};
+
+static long region_add(struct list_head *head, long f, long t)
+{
+ struct file_region *rg, *nrg, *trg;
+
+ /* Locate the region we are either in or before. */
+ list_for_each_entry(rg, head, link)
+ if (f <= rg->to)
+ break;
+
+ /* Round our left edge to the current segment if it encloses us. */
+ if (f > rg->from)
+ f = rg->from;
+
+ /* Check for and consume any regions we now overlap with. */
+ nrg = rg;
+ list_for_each_entry_safe(rg, trg, rg->link.prev, link) {
+ if (&rg->link == head)
+ break;
+ if (rg->from > t)
+ break;
+
+ /* If this area reaches higher then extend our area to
+ * include it completely. If this is not the first area
+ * which we intend to reuse, free it. */
+ if (rg->to > t)
+ t = rg->to;
+ if (rg != nrg) {
+ list_del(&rg->link);
+ kfree(rg);
+ }
+ }
+ nrg->from = f;
+ nrg->to = t;
+ return 0;
+}
+
+static long region_chg(struct list_head *head, long f, long t)
+{
+ struct file_region *rg, *nrg;
+ long chg = 0;
+
+ /* Locate the region we are before or in. */
+ list_for_each_entry(rg, head, link)
+ if (f <= rg->to)
+ break;
+
+ /* If we are below the current region then a new region is required.
+ * Subtle, allocate a new region at the position but make it zero
+ * size such that we can guarentee to record the reservation. */
+ if (&rg->link == head || t < rg->from) {
+ nrg = kmalloc(sizeof(*nrg), GFP_KERNEL);
+ if (nrg == 0)
+ return -ENOMEM;
+ nrg->from = f;
+ nrg->to = f;
+ INIT_LIST_HEAD(&nrg->link);
+ list_add(&nrg->link, rg->link.prev);
+
+ return t - f;
+ }
+
+ /* Round our left edge to the current segment if it encloses us. */
+ if (f > rg->from)
+ f = rg->from;
+ chg = t - f;
+
+ /* Check for and consume any regions we now overlap with. */
+ list_for_each_entry(rg, rg->link.prev, link) {
+ if (&rg->link == head)
+ break;
+ if (rg->from > t)
+ return chg;
+
+ /* We overlap with this area, if it extends futher than
+ * us then we must extend ourselves. Account for its
+ * existing reservation. */
+ if (rg->to > t) {
+ chg += rg->to - t;
+ t = rg->to;
+ }
+ chg -= rg->to - rg->from;
+ }
+ return chg;
+}
+
+static long region_truncate(struct list_head *head, long end)
+{
+ struct file_region *rg, *trg;
+ long chg = 0;
+
+ /* Locate the region we are either in or before. */
+ list_for_each_entry(rg, head, link)
+ if (end <= rg->to)
+ break;
+ if (&rg->link == head)
+ return 0;
+
+ /* If we are in the middle of a region then adjust it. */
+ if (end > rg->from) {
+ chg = rg->to - end;
+ rg->to = end;
+ rg = list_entry(rg->link.next, typeof(*rg), link);
+ }
+
+ /* Drop any remaining regions. */
+ list_for_each_entry_safe(rg, trg, rg->link.prev, link) {
+ if (&rg->link == head)
+ break;
+ chg += rg->to - rg->from;
+ list_del(&rg->link);
+ kfree(rg);
+ }
+ return chg;
+}
+
+static int hugetlb_acct_memory(long delta)
+{
+ int ret = -ENOMEM;
+
+ spin_lock(&hugetlb_lock);
+ if ((delta + resv_huge_pages) <= free_huge_pages) {
+ resv_huge_pages += delta;
+ ret = 0;
+ }
+ spin_unlock(&hugetlb_lock);
+ return ret;
+}
+
+int hugetlb_reserve_pages(struct inode *inode, long from, long to)
+{
+ long ret, chg;
+
+ chg = region_chg(&inode->i_mapping->private_list, from, to);
+ if (chg < 0)
+ return chg;
+ ret = hugetlb_acct_memory(chg);
+ if (ret < 0)
+ return ret;
+ region_add(&inode->i_mapping->private_list, from, to);
+ return 0;
+}
+
+void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed)
+{
+ long chg = region_truncate(&inode->i_mapping->private_list, offset);
+ hugetlb_acct_memory(freed - chg);
+}
diff --git a/mm/memory.c b/mm/memory.c
index 0ec7bc6..247b5c3 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -434,7 +434,9 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
/* pte contains position in swap or file, so copy. */
if (unlikely(!pte_present(pte))) {
if (!pte_file(pte)) {
- swap_duplicate(pte_to_swp_entry(pte));
+ swp_entry_t entry = pte_to_swp_entry(pte);
+
+ swap_duplicate(entry);
/* make sure dst_mm is on swapoff's mmlist. */
if (unlikely(list_empty(&dst_mm->mmlist))) {
spin_lock(&mmlist_lock);
@@ -443,6 +445,16 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
&src_mm->mmlist);
spin_unlock(&mmlist_lock);
}
+ if (is_write_migration_entry(entry) &&
+ is_cow_mapping(vm_flags)) {
+ /*
+ * COW mappings require pages in both parent
+ * and child to be set to read.
+ */
+ make_migration_entry_read(&entry);
+ pte = swp_entry_to_pte(entry);
+ set_pte_at(src_mm, addr, src_pte, pte);
+ }
}
goto out_set_pte;
}
@@ -1445,25 +1457,60 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
{
struct page *old_page, *new_page;
pte_t entry;
- int ret = VM_FAULT_MINOR;
+ int reuse, ret = VM_FAULT_MINOR;
old_page = vm_normal_page(vma, address, orig_pte);
if (!old_page)
goto gotten;
- if (PageAnon(old_page) && !TestSetPageLocked(old_page)) {
- int reuse = can_share_swap_page(old_page);
- unlock_page(old_page);
- if (reuse) {
- flush_cache_page(vma, address, pte_pfn(orig_pte));
- entry = pte_mkyoung(orig_pte);
- entry = maybe_mkwrite(pte_mkdirty(entry), vma);
- ptep_set_access_flags(vma, address, page_table, entry, 1);
- update_mmu_cache(vma, address, entry);
- lazy_mmu_prot_update(entry);
- ret |= VM_FAULT_WRITE;
- goto unlock;
+ if (unlikely((vma->vm_flags & (VM_SHARED|VM_WRITE)) ==
+ (VM_SHARED|VM_WRITE))) {
+ if (vma->vm_ops && vma->vm_ops->page_mkwrite) {
+ /*
+ * Notify the address space that the page is about to
+ * become writable so that it can prohibit this or wait
+ * for the page to get into an appropriate state.
+ *
+ * We do this without the lock held, so that it can
+ * sleep if it needs to.
+ */
+ page_cache_get(old_page);
+ pte_unmap_unlock(page_table, ptl);
+
+ if (vma->vm_ops->page_mkwrite(vma, old_page) < 0)
+ goto unwritable_page;
+
+ page_cache_release(old_page);
+
+ /*
+ * Since we dropped the lock we need to revalidate
+ * the PTE as someone else may have changed it. If
+ * they did, we just return, as we can count on the
+ * MMU to tell us if they didn't also make it writable.
+ */
+ page_table = pte_offset_map_lock(mm, pmd, address,
+ &ptl);
+ if (!pte_same(*page_table, orig_pte))
+ goto unlock;
}
+
+ reuse = 1;
+ } else if (PageAnon(old_page) && !TestSetPageLocked(old_page)) {
+ reuse = can_share_swap_page(old_page);
+ unlock_page(old_page);
+ } else {
+ reuse = 0;
+ }
+
+ if (reuse) {
+ flush_cache_page(vma, address, pte_pfn(orig_pte));
+ entry = pte_mkyoung(orig_pte);
+ entry = maybe_mkwrite(pte_mkdirty(entry), vma);
+ ptep_set_access_flags(vma, address, page_table, entry, 1);
+ update_mmu_cache(vma, address, entry);
+ lazy_mmu_prot_update(entry);
+ ret |= VM_FAULT_WRITE;
+ goto unlock;
}
/*
@@ -1523,6 +1570,10 @@ oom:
if (old_page)
page_cache_release(old_page);
return VM_FAULT_OOM;
+
+unwritable_page:
+ page_cache_release(old_page);
+ return VM_FAULT_SIGBUS;
}
/*
@@ -1879,7 +1930,10 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
goto out;
entry = pte_to_swp_entry(orig_pte);
-again:
+ if (is_migration_entry(entry)) {
+ migration_entry_wait(mm, pmd, address);
+ goto out;
+ }
page = lookup_swap_cache(entry);
if (!page) {
swapin_readahead(entry, address, vma);
@@ -1903,12 +1957,6 @@ again:
mark_page_accessed(page);
lock_page(page);
- if (!PageSwapCache(page)) {
- /* Page migration has occured */
- unlock_page(page);
- page_cache_release(page);
- goto again;
- }
/*
* Back out if somebody else already faulted in this pte.
@@ -2074,18 +2122,31 @@ retry:
/*
* Should we do an early C-O-W break?
*/
- if (write_access && !(vma->vm_flags & VM_SHARED)) {
- struct page *page;
+ if (write_access) {
+ if (!(vma->vm_flags & VM_SHARED)) {
+ struct page *page;
- if (unlikely(anon_vma_prepare(vma)))
- goto oom;
- page = alloc_page_vma(GFP_HIGHUSER, vma, address);
- if (!page)
- goto oom;
- copy_user_highpage(page, new_page, address);
- page_cache_release(new_page);
- new_page = page;
- anon = 1;
+ if (unlikely(anon_vma_prepare(vma)))
+ goto oom;
+ page = alloc_page_vma(GFP_HIGHUSER, vma, address);
+ if (!page)
+ goto oom;
+ copy_user_highpage(page, new_page, address);
+ page_cache_release(new_page);
+ new_page = page;
+ anon = 1;
+
+ } else {
+ /* if the page will be shareable, see if the backing
+ * address space wants to know that the page is about
+ * to become writable */
+ if (vma->vm_ops->page_mkwrite &&
+ vma->vm_ops->page_mkwrite(vma, new_page) < 0
+ ) {
+ page_cache_release(new_page);
+ return VM_FAULT_SIGBUS;
+ }
+ }
}
page_table = pte_offset_map_lock(mm, pmd, address, &ptl);
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 70df5c0..841a077 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -26,7 +26,7 @@
extern void zonetable_add(struct zone *zone, int nid, int zid, unsigned long pfn,
unsigned long size);
-static void __add_zone(struct zone *zone, unsigned long phys_start_pfn)
+static int __add_zone(struct zone *zone, unsigned long phys_start_pfn)
{
struct pglist_data *pgdat = zone->zone_pgdat;
int nr_pages = PAGES_PER_SECTION;
@@ -34,8 +34,15 @@ static void __add_zone(struct zone *zone, unsigned long phys_start_pfn)
int zone_type;
zone_type = zone - pgdat->node_zones;
+ if (!populated_zone(zone)) {
+ int ret = 0;
+ ret = init_currently_empty_zone(zone, phys_start_pfn, nr_pages);
+ if (ret < 0)
+ return ret;
+ }
memmap_init_zone(nr_pages, nid, zone_type, phys_start_pfn);
zonetable_add(zone, nid, zone_type, phys_start_pfn, nr_pages);
+ return 0;
}
extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn,
@@ -50,7 +57,11 @@ static int __add_section(struct zone *zone, unsigned long phys_start_pfn)
if (ret < 0)
return ret;
- __add_zone(zone, phys_start_pfn);
+ ret = __add_zone(zone, phys_start_pfn);
+
+ if (ret < 0)
+ return ret;
+
return register_new_memory(__pfn_to_section(phys_start_pfn));
}
@@ -116,6 +127,7 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
unsigned long flags;
unsigned long onlined_pages = 0;
struct zone *zone;
+ int need_zonelists_rebuild = 0;
/*
* This doesn't need a lock to do pfn_to_page().
@@ -128,6 +140,14 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
grow_pgdat_span(zone->zone_pgdat, pfn, pfn + nr_pages);
pgdat_resize_unlock(zone->zone_pgdat, &flags);
+ /*
+ * If this zone is not populated, then it is not in zonelist.
+ * This means the page allocator ignores this zone.
+ * So, zonelist must be updated after online.
+ */
+ if (!populated_zone(zone))
+ need_zonelists_rebuild = 1;
+
for (i = 0; i < nr_pages; i++) {
struct page *page = pfn_to_page(pfn + i);
online_page(page);
@@ -138,5 +158,8 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
setup_per_zone_pages_min();
+ if (need_zonelists_rebuild)
+ build_all_zonelists();
+ vm_total_pages = nr_free_pagecache_pages();
return 0;
}
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 8778f58..73e0f23 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -87,6 +87,8 @@
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include <linux/migrate.h>
+#include <linux/rmap.h>
+#include <linux/security.h>
#include <asm/tlbflush.h>
#include <asm/uaccess.h>
@@ -587,6 +589,11 @@ static void migrate_page_add(struct page *page, struct list_head *pagelist,
isolate_lru_page(page, pagelist);
}
+static struct page *new_node_page(struct page *page, unsigned long node, int **x)
+{
+ return alloc_pages_node(node, GFP_HIGHUSER, 0);
+}
+
/*
* Migrate pages from one node to a target node.
* Returns error or the number of pages not migrated.
@@ -603,11 +610,9 @@ int migrate_to_node(struct mm_struct *mm, int source, int dest, int flags)
check_range(mm, mm->mmap->vm_start, TASK_SIZE, &nmask,
flags | MPOL_MF_DISCONTIG_OK, &pagelist);
- if (!list_empty(&pagelist)) {
- err = migrate_pages_to(&pagelist, NULL, dest);
- if (!list_empty(&pagelist))
- putback_lru_pages(&pagelist);
- }
+ if (!list_empty(&pagelist))
+ err = migrate_pages(&pagelist, new_node_page, dest);
+
return err;
}
@@ -627,6 +632,10 @@ int do_migrate_pages(struct mm_struct *mm,
down_read(&mm->mmap_sem);
+ err = migrate_vmas(mm, from_nodes, to_nodes, flags);
+ if (err)
+ goto out;
+
/*
* Find a 'source' bit set in 'tmp' whose corresponding 'dest'
* bit in 'to' is not also set in 'tmp'. Clear the found 'source'
@@ -686,7 +695,7 @@ int do_migrate_pages(struct mm_struct *mm,
if (err < 0)
break;
}
-
+out:
up_read(&mm->mmap_sem);
if (err < 0)
return err;
@@ -694,6 +703,12 @@ int do_migrate_pages(struct mm_struct *mm,
}
+static struct page *new_vma_page(struct page *page, unsigned long private, int **x)
+{
+ struct vm_area_struct *vma = (struct vm_area_struct *)private;
+
+ return alloc_page_vma(GFP_HIGHUSER, vma, page_address_in_vma(page, vma));
+}
#else
static void migrate_page_add(struct page *page, struct list_head *pagelist,
@@ -706,6 +721,11 @@ int do_migrate_pages(struct mm_struct *mm,
{
return -ENOSYS;
}
+
+static struct page *new_vma_page(struct page *page, unsigned long private)
+{
+ return NULL;
+}
#endif
long do_mbind(unsigned long start, unsigned long len,
@@ -767,15 +787,13 @@ long do_mbind(unsigned long start, unsigned long len,
err = mbind_range(vma, start, end, new);
if (!list_empty(&pagelist))
- nr_failed = migrate_pages_to(&pagelist, vma, -1);
+ nr_failed = migrate_pages(&pagelist, new_vma_page,
+ (unsigned long)vma);
if (!err && nr_failed && (flags & MPOL_MF_STRICT))
err = -EIO;
}
- if (!list_empty(&pagelist))
- putback_lru_pages(&pagelist);
-
up_write(&mm->mmap_sem);
mpol_free(new);
return err;
@@ -929,6 +947,10 @@ asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode,
goto out;
}
+ err = security_task_movememory(task);
+ if (err)
+ goto out;
+
err = do_migrate_pages(mm, &old, &new,
capable(CAP_SYS_NICE) ? MPOL_MF_MOVE_ALL : MPOL_MF_MOVE);
out:
diff --git a/mm/migrate.c b/mm/migrate.c
index 1c25040..3f1e0c2 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -15,6 +15,7 @@
#include <linux/migrate.h>
#include <linux/module.h>
#include <linux/swap.h>
+#include <linux/swapops.h>
#include <linux/pagemap.h>
#include <linux/buffer_head.h>
#include <linux/mm_inline.h>
@@ -23,13 +24,13 @@
#include <linux/topology.h>
#include <linux/cpu.h>
#include <linux/cpuset.h>
-#include <linux/swapops.h>
+#include <linux/writeback.h>
+#include <linux/mempolicy.h>
+#include <linux/vmalloc.h>
+#include <linux/security.h>
#include "internal.h"
-/* The maximum number of pages to take off the LRU for migration */
-#define MIGRATE_CHUNK_SIZE 256
-
#define lru_to_page(_head) (list_entry((_head)->prev, struct page, lru))
/*
@@ -64,16 +65,11 @@ int isolate_lru_page(struct page *page, struct list_head *pagelist)
}
/*
- * migrate_prep() needs to be called after we have compiled the list of pages
- * to be migrated using isolate_lru_page() but before we begin a series of calls
- * to migrate_pages().
+ * migrate_prep() needs to be called before we start compiling a list of pages
+ * to be migrated using isolate_lru_page().
*/
int migrate_prep(void)
{
- /* Must have swap device for migration */
- if (nr_swap_pages <= 0)
- return -ENODEV;
-
/*
* Clear the LRU lists so pages can be isolated.
* Note that pages may be moved off the LRU after we have
@@ -87,7 +83,6 @@ int migrate_prep(void)
static inline void move_to_lru(struct page *page)
{
- list_del(&page->lru);
if (PageActive(page)) {
/*
* lru_cache_add_active checks that
@@ -113,113 +108,200 @@ int putback_lru_pages(struct list_head *l)
int count = 0;
list_for_each_entry_safe(page, page2, l, lru) {
+ list_del(&page->lru);
move_to_lru(page);
count++;
}
return count;
}
-/*
- * Non migratable page
- */
-int fail_migrate_page(struct page *newpage, struct page *page)
+static inline int is_swap_pte(pte_t pte)
{
- return -EIO;
+ return !pte_none(pte) && !pte_present(pte) && !pte_file(pte);
}
-EXPORT_SYMBOL(fail_migrate_page);
/*
- * swapout a single page
- * page is locked upon entry, unlocked on exit
+ * Restore a potential migration pte to a working pte entry
*/
-static int swap_page(struct page *page)
+static void remove_migration_pte(struct vm_area_struct *vma,
+ struct page *old, struct page *new)
{
- struct address_space *mapping = page_mapping(page);
+ struct mm_struct *mm = vma->vm_mm;
+ swp_entry_t entry;
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *ptep, pte;
+ spinlock_t *ptl;
+ unsigned long addr = page_address_in_vma(new, vma);
+
+ if (addr == -EFAULT)
+ return;
+
+ pgd = pgd_offset(mm, addr);
+ if (!pgd_present(*pgd))
+ return;
+
+ pud = pud_offset(pgd, addr);
+ if (!pud_present(*pud))
+ return;
+
+ pmd = pmd_offset(pud, addr);
+ if (!pmd_present(*pmd))
+ return;
+
+ ptep = pte_offset_map(pmd, addr);
+
+ if (!is_swap_pte(*ptep)) {
+ pte_unmap(ptep);
+ return;
+ }
- if (page_mapped(page) && mapping)
- if (try_to_unmap(page, 1) != SWAP_SUCCESS)
- goto unlock_retry;
+ ptl = pte_lockptr(mm, pmd);
+ spin_lock(ptl);
+ pte = *ptep;
+ if (!is_swap_pte(pte))
+ goto out;
- if (PageDirty(page)) {
- /* Page is dirty, try to write it out here */
- switch(pageout(page, mapping)) {
- case PAGE_KEEP:
- case PAGE_ACTIVATE:
- goto unlock_retry;
+ entry = pte_to_swp_entry(pte);
- case PAGE_SUCCESS:
- goto retry;
+ if (!is_migration_entry(entry) || migration_entry_to_page(entry) != old)
+ goto out;
- case PAGE_CLEAN:
- ; /* try to free the page below */
- }
- }
+ get_page(new);
+ pte = pte_mkold(mk_pte(new, vma->vm_page_prot));
+ if (is_write_migration_entry(entry))
+ pte = pte_mkwrite(pte);
+ set_pte_at(mm, addr, ptep, pte);
- if (PagePrivate(page)) {
- if (!try_to_release_page(page, GFP_KERNEL) ||
- (!mapping && page_count(page) == 1))
- goto unlock_retry;
- }
+ if (PageAnon(new))
+ page_add_anon_rmap(new, vma, addr);
+ else
+ page_add_file_rmap(new);
- if (remove_mapping(mapping, page)) {
- /* Success */
- unlock_page(page);
- return 0;
- }
+ /* No need to invalidate - it was non-present before */
+ update_mmu_cache(vma, addr, pte);
+ lazy_mmu_prot_update(pte);
-unlock_retry:
- unlock_page(page);
+out:
+ pte_unmap_unlock(ptep, ptl);
+}
-retry:
- return -EAGAIN;
+/*
+ * Note that remove_file_migration_ptes will only work on regular mappings,
+ * Nonlinear mappings do not use migration entries.
+ */
+static void remove_file_migration_ptes(struct page *old, struct page *new)
+{
+ struct vm_area_struct *vma;
+ struct address_space *mapping = page_mapping(new);
+ struct prio_tree_iter iter;
+ pgoff_t pgoff = new->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
+
+ if (!mapping)
+ return;
+
+ spin_lock(&mapping->i_mmap_lock);
+
+ vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff)
+ remove_migration_pte(vma, old, new);
+
+ spin_unlock(&mapping->i_mmap_lock);
}
/*
- * Remove references for a page and establish the new page with the correct
- * basic settings to be able to stop accesses to the page.
+ * Must hold mmap_sem lock on at least one of the vmas containing
+ * the page so that the anon_vma cannot vanish.
*/
-int migrate_page_remove_references(struct page *newpage,
- struct page *page, int nr_refs)
+static void remove_anon_migration_ptes(struct page *old, struct page *new)
{
- struct address_space *mapping = page_mapping(page);
- struct page **radix_pointer;
+ struct anon_vma *anon_vma;
+ struct vm_area_struct *vma;
+ unsigned long mapping;
- /*
- * Avoid doing any of the following work if the page count
- * indicates that the page is in use or truncate has removed
- * the page.
- */
- if (!mapping || page_mapcount(page) + nr_refs != page_count(page))
- return -EAGAIN;
+ mapping = (unsigned long)new->mapping;
- /*
- * Establish swap ptes for anonymous pages or destroy pte
- * maps for files.
- *
- * In order to reestablish file backed mappings the fault handlers
- * will take the radix tree_lock which may then be used to stop
- * processses from accessing this page until the new page is ready.
- *
- * A process accessing via a swap pte (an anonymous page) will take a
- * page_lock on the old page which will block the process until the
- * migration attempt is complete. At that time the PageSwapCache bit
- * will be examined. If the page was migrated then the PageSwapCache
- * bit will be clear and the operation to retrieve the page will be
- * retried which will find the new page in the radix tree. Then a new
- * direct mapping may be generated based on the radix tree contents.
- *
- * If the page was not migrated then the PageSwapCache bit
- * is still set and the operation may continue.
- */
- if (try_to_unmap(page, 1) == SWAP_FAIL)
- /* A vma has VM_LOCKED set -> permanent failure */
- return -EPERM;
+ if (!mapping || (mapping & PAGE_MAPPING_ANON) == 0)
+ return;
/*
- * Give up if we were unable to remove all mappings.
+ * We hold the mmap_sem lock. So no need to call page_lock_anon_vma.
*/
- if (page_mapcount(page))
- return -EAGAIN;
+ anon_vma = (struct anon_vma *) (mapping - PAGE_MAPPING_ANON);
+ spin_lock(&anon_vma->lock);
+
+ list_for_each_entry(vma, &anon_vma->head, anon_vma_node)
+ remove_migration_pte(vma, old, new);
+
+ spin_unlock(&anon_vma->lock);
+}
+
+/*
+ * Get rid of all migration entries and replace them by
+ * references to the indicated page.
+ */
+static void remove_migration_ptes(struct page *old, struct page *new)
+{
+ if (PageAnon(new))
+ remove_anon_migration_ptes(old, new);
+ else
+ remove_file_migration_ptes(old, new);
+}
+
+/*
+ * Something used the pte of a page under migration. We need to
+ * get to the page and wait until migration is finished.
+ * When we return from this function the fault will be retried.
+ *
+ * This function is called from do_swap_page().
+ */
+void migration_entry_wait(struct mm_struct *mm, pmd_t *pmd,
+ unsigned long address)
+{
+ pte_t *ptep, pte;
+ spinlock_t *ptl;
+ swp_entry_t entry;
+ struct page *page;
+
+ ptep = pte_offset_map_lock(mm, pmd, address, &ptl);
+ pte = *ptep;
+ if (!is_swap_pte(pte))
+ goto out;
+
+ entry = pte_to_swp_entry(pte);
+ if (!is_migration_entry(entry))
+ goto out;
+
+ page = migration_entry_to_page(entry);
+
+ get_page(page);
+ pte_unmap_unlock(ptep, ptl);
+ wait_on_page_locked(page);
+ put_page(page);
+ return;
+out:
+ pte_unmap_unlock(ptep, ptl);
+}
+
+/*
+ * Replace the page in the mapping.
+ *
+ * The number of remaining references must be:
+ * 1 for anonymous pages without a mapping
+ * 2 for pages with a mapping
+ * 3 for pages with a mapping and PagePrivate set.
+ */
+static int migrate_page_move_mapping(struct address_space *mapping,
+ struct page *newpage, struct page *page)
+{
+ struct page **radix_pointer;
+
+ if (!mapping) {
+ /* Anonymous page */
+ if (page_count(page) != 1)
+ return -EAGAIN;
+ return 0;
+ }
write_lock_irq(&mapping->tree_lock);
@@ -227,7 +309,7 @@ int migrate_page_remove_references(struct page *newpage,
&mapping->page_tree,
page_index(page));
- if (!page_mapping(page) || page_count(page) != nr_refs ||
+ if (page_count(page) != 2 + !!PagePrivate(page) ||
*radix_pointer != page) {
write_unlock_irq(&mapping->tree_lock);
return -EAGAIN;
@@ -235,19 +317,14 @@ int migrate_page_remove_references(struct page *newpage,
/*
* Now we know that no one else is looking at the page.
- *
- * Certain minimal information about a page must be available
- * in order for other subsystems to properly handle the page if they
- * find it through the radix tree update before we are finished
- * copying the page.
*/
get_page(newpage);
- newpage->index = page->index;
- newpage->mapping = page->mapping;
+#ifdef CONFIG_SWAP
if (PageSwapCache(page)) {
SetPageSwapCache(newpage);
set_page_private(newpage, page_private(page));
}
+#endif
*radix_pointer = newpage;
__put_page(page);
@@ -255,12 +332,11 @@ int migrate_page_remove_references(struct page *newpage,
return 0;
}
-EXPORT_SYMBOL(migrate_page_remove_references);
/*
* Copy the page to its new location
*/
-void migrate_page_copy(struct page *newpage, struct page *page)
+static void migrate_page_copy(struct page *newpage, struct page *page)
{
copy_highpage(newpage, page);
@@ -282,7 +358,9 @@ void migrate_page_copy(struct page *newpage, struct page *page)
set_page_dirty(newpage);
}
+#ifdef CONFIG_SWAP
ClearPageSwapCache(page);
+#endif
ClearPageActive(page);
ClearPagePrivate(page);
set_page_private(page, 0);
@@ -295,7 +373,18 @@ void migrate_page_copy(struct page *newpage, struct page *page)
if (PageWriteback(newpage))
end_page_writeback(newpage);
}
-EXPORT_SYMBOL(migrate_page_copy);
+
+/************************************************************
+ * Migration functions
+ ***********************************************************/
+
+/* Always fail migration. Used for mappings that are not movable */
+int fail_migrate_page(struct address_space *mapping,
+ struct page *newpage, struct page *page)
+{
+ return -EIO;
+}
+EXPORT_SYMBOL(fail_migrate_page);
/*
* Common logic to directly migrate a single page suitable for
@@ -303,51 +392,284 @@ EXPORT_SYMBOL(migrate_page_copy);
*
* Pages are locked upon entry and exit.
*/
-int migrate_page(struct page *newpage, struct page *page)
+int migrate_page(struct address_space *mapping,
+ struct page *newpage, struct page *page)
{
int rc;
BUG_ON(PageWriteback(page)); /* Writeback must be complete */
- rc = migrate_page_remove_references(newpage, page, 2);
+ rc = migrate_page_move_mapping(mapping, newpage, page);
+
+ if (rc)
+ return rc;
+
+ migrate_page_copy(newpage, page);
+ return 0;
+}
+EXPORT_SYMBOL(migrate_page);
+
+/*
+ * Migration function for pages with buffers. This function can only be used
+ * if the underlying filesystem guarantees that no other references to "page"
+ * exist.
+ */
+int buffer_migrate_page(struct address_space *mapping,
+ struct page *newpage, struct page *page)
+{
+ struct buffer_head *bh, *head;
+ int rc;
+
+ if (!page_has_buffers(page))
+ return migrate_page(mapping, newpage, page);
+
+ head = page_buffers(page);
+
+ rc = migrate_page_move_mapping(mapping, newpage, page);
if (rc)
return rc;
+ bh = head;
+ do {
+ get_bh(bh);
+ lock_buffer(bh);
+ bh = bh->b_this_page;
+
+ } while (bh != head);
+
+ ClearPagePrivate(page);
+ set_page_private(newpage, page_private(page));
+ set_page_private(page, 0);
+ put_page(page);
+ get_page(newpage);
+
+ bh = head;
+ do {
+ set_bh_page(bh, newpage, bh_offset(bh));
+ bh = bh->b_this_page;
+
+ } while (bh != head);
+
+ SetPagePrivate(newpage);
+
migrate_page_copy(newpage, page);
+ bh = head;
+ do {
+ unlock_buffer(bh);
+ put_bh(bh);
+ bh = bh->b_this_page;
+
+ } while (bh != head);
+
+ return 0;
+}
+EXPORT_SYMBOL(buffer_migrate_page);
+
+/*
+ * Writeback a page to clean the dirty state
+ */
+static int writeout(struct address_space *mapping, struct page *page)
+{
+ struct writeback_control wbc = {
+ .sync_mode = WB_SYNC_NONE,
+ .nr_to_write = 1,
+ .range_start = 0,
+ .range_end = LLONG_MAX,
+ .nonblocking = 1,
+ .for_reclaim = 1
+ };
+ int rc;
+
+ if (!mapping->a_ops->writepage)
+ /* No write method for the address space */
+ return -EINVAL;
+
+ if (!clear_page_dirty_for_io(page))
+ /* Someone else already triggered a write */
+ return -EAGAIN;
+
/*
- * Remove auxiliary swap entries and replace
- * them with real ptes.
- *
- * Note that a real pte entry will allow processes that are not
- * waiting on the page lock to use the new page via the page tables
- * before the new page is unlocked.
+ * A dirty page may imply that the underlying filesystem has
+ * the page on some queue. So the page must be clean for
+ * migration. Writeout may mean we loose the lock and the
+ * page state is no longer what we checked for earlier.
+ * At this point we know that the migration attempt cannot
+ * be successful.
*/
- remove_from_swap(newpage);
- return 0;
+ remove_migration_ptes(page, page);
+
+ rc = mapping->a_ops->writepage(page, &wbc);
+ if (rc < 0)
+ /* I/O Error writing */
+ return -EIO;
+
+ if (rc != AOP_WRITEPAGE_ACTIVATE)
+ /* unlocked. Relock */
+ lock_page(page);
+
+ return -EAGAIN;
+}
+
+/*
+ * Default handling if a filesystem does not provide a migration function.
+ */
+static int fallback_migrate_page(struct address_space *mapping,
+ struct page *newpage, struct page *page)
+{
+ if (PageDirty(page))
+ return writeout(mapping, page);
+
+ /*
+ * Buffers may be managed in a filesystem specific way.
+ * We must have no buffers or drop them.
+ */
+ if (page_has_buffers(page) &&
+ !try_to_release_page(page, GFP_KERNEL))
+ return -EAGAIN;
+
+ return migrate_page(mapping, newpage, page);
+}
+
+/*
+ * Move a page to a newly allocated page
+ * The page is locked and all ptes have been successfully removed.
+ *
+ * The new page will have replaced the old page if this function
+ * is successful.
+ */
+static int move_to_new_page(struct page *newpage, struct page *page)
+{
+ struct address_space *mapping;
+ int rc;
+
+ /*
+ * Block others from accessing the page when we get around to
+ * establishing additional references. We are the only one
+ * holding a reference to the new page at this point.
+ */
+ if (TestSetPageLocked(newpage))
+ BUG();
+
+ /* Prepare mapping for the new page.*/
+ newpage->index = page->index;
+ newpage->mapping = page->mapping;
+
+ mapping = page_mapping(page);
+ if (!mapping)
+ rc = migrate_page(mapping, newpage, page);
+ else if (mapping->a_ops->migratepage)
+ /*
+ * Most pages have a mapping and most filesystems
+ * should provide a migration function. Anonymous
+ * pages are part of swap space which also has its
+ * own migration function. This is the most common
+ * path for page migration.
+ */
+ rc = mapping->a_ops->migratepage(mapping,
+ newpage, page);
+ else
+ rc = fallback_migrate_page(mapping, newpage, page);
+
+ if (!rc)
+ remove_migration_ptes(page, newpage);
+ else
+ newpage->mapping = NULL;
+
+ unlock_page(newpage);
+
+ return rc;
+}
+
+/*
+ * Obtain the lock on page, remove all ptes and migrate the page
+ * to the newly allocated page in newpage.
+ */
+static int unmap_and_move(new_page_t get_new_page, unsigned long private,
+ struct page *page, int force)
+{
+ int rc = 0;
+ int *result = NULL;
+ struct page *newpage = get_new_page(page, private, &result);
+
+ if (!newpage)
+ return -ENOMEM;
+
+ if (page_count(page) == 1)
+ /* page was freed from under us. So we are done. */
+ goto move_newpage;
+
+ rc = -EAGAIN;
+ if (TestSetPageLocked(page)) {
+ if (!force)
+ goto move_newpage;
+ lock_page(page);
+ }
+
+ if (PageWriteback(page)) {
+ if (!force)
+ goto unlock;
+ wait_on_page_writeback(page);
+ }
+
+ /*
+ * Establish migration ptes or remove ptes
+ */
+ try_to_unmap(page, 1);
+ if (!page_mapped(page))
+ rc = move_to_new_page(newpage, page);
+
+ if (rc)
+ remove_migration_ptes(page, page);
+
+unlock:
+ unlock_page(page);
+
+ if (rc != -EAGAIN) {
+ /*
+ * A page that has been migrated has all references
+ * removed and will be freed. A page that has not been
+ * migrated will have kepts its references and be
+ * restored.
+ */
+ list_del(&page->lru);
+ move_to_lru(page);
+ }
+
+move_newpage:
+ /*
+ * Move the new page to the LRU. If migration was not successful
+ * then this will free the page.
+ */
+ move_to_lru(newpage);
+ if (result) {
+ if (rc)
+ *result = rc;
+ else
+ *result = page_to_nid(newpage);
+ }
+ return rc;
}
-EXPORT_SYMBOL(migrate_page);
/*
* migrate_pages
*
- * Two lists are passed to this function. The first list
- * contains the pages isolated from the LRU to be migrated.
- * The second list contains new pages that the pages isolated
- * can be moved to. If the second list is NULL then all
- * pages are swapped out.
+ * The function takes one list of pages to migrate and a function
+ * that determines from the page to be migrated and the private data
+ * the target of the move and allocates the page.
*
* The function returns after 10 attempts or if no pages
* are movable anymore because to has become empty
- * or no retryable pages exist anymore.
+ * or no retryable pages exist anymore. All pages will be
+ * retruned to the LRU or freed.
*
- * Return: Number of pages not migrated when "to" ran empty.
+ * Return: Number of pages not migrated or error code.
*/
-int migrate_pages(struct list_head *from, struct list_head *to,
- struct list_head *moved, struct list_head *failed)
+int migrate_pages(struct list_head *from,
+ new_page_t get_new_page, unsigned long private)
{
- int retry;
+ int retry = 1;
int nr_failed = 0;
int pass = 0;
struct page *page;
@@ -358,305 +680,317 @@ int migrate_pages(struct list_head *from, struct list_head *to,
if (!swapwrite)
current->flags |= PF_SWAPWRITE;
-redo:
- retry = 0;
+ for(pass = 0; pass < 10 && retry; pass++) {
+ retry = 0;
+
+ list_for_each_entry_safe(page, page2, from, lru) {
+ cond_resched();
+
+ rc = unmap_and_move(get_new_page, private,
+ page, pass > 2);
+
+ switch(rc) {
+ case -ENOMEM:
+ goto out;
+ case -EAGAIN:
+ retry++;
+ break;
+ case 0:
+ break;
+ default:
+ /* Permanent failure */
+ nr_failed++;
+ break;
+ }
+ }
+ }
+ rc = 0;
+out:
+ if (!swapwrite)
+ current->flags &= ~PF_SWAPWRITE;
+
+ putback_lru_pages(from);
+
+ if (rc)
+ return rc;
- list_for_each_entry_safe(page, page2, from, lru) {
- struct page *newpage = NULL;
- struct address_space *mapping;
+ return nr_failed + retry;
+}
- cond_resched();
+#ifdef CONFIG_NUMA
+/*
+ * Move a list of individual pages
+ */
+struct page_to_node {
+ unsigned long addr;
+ struct page *page;
+ int node;
+ int status;
+};
- rc = 0;
- if (page_count(page) == 1)
- /* page was freed from under us. So we are done. */
- goto next;
+static struct page *new_page_node(struct page *p, unsigned long private,
+ int **result)
+{
+ struct page_to_node *pm = (struct page_to_node *)private;
- if (to && list_empty(to))
- break;
+ while (pm->node != MAX_NUMNODES && pm->page != p)
+ pm++;
- /*
- * Skip locked pages during the first two passes to give the
- * functions holding the lock time to release the page. Later we
- * use lock_page() to have a higher chance of acquiring the
- * lock.
- */
- rc = -EAGAIN;
- if (pass > 2)
- lock_page(page);
- else
- if (TestSetPageLocked(page))
- goto next;
+ if (pm->node == MAX_NUMNODES)
+ return NULL;
- /*
- * Only wait on writeback if we have already done a pass where
- * we we may have triggered writeouts for lots of pages.
- */
- if (pass > 0) {
- wait_on_page_writeback(page);
- } else {
- if (PageWriteback(page))
- goto unlock_page;
- }
+ *result = &pm->status;
- /*
- * Anonymous pages must have swap cache references otherwise
- * the information contained in the page maps cannot be
- * preserved.
- */
- if (PageAnon(page) && !PageSwapCache(page)) {
- if (!add_to_swap(page, GFP_KERNEL)) {
- rc = -ENOMEM;
- goto unlock_page;
- }
- }
+ return alloc_pages_node(pm->node, GFP_HIGHUSER, 0);
+}
- if (!to) {
- rc = swap_page(page);
- goto next;
- }
+/*
+ * Move a set of pages as indicated in the pm array. The addr
+ * field must be set to the virtual address of the page to be moved
+ * and the node number must contain a valid target node.
+ */
+static int do_move_pages(struct mm_struct *mm, struct page_to_node *pm,
+ int migrate_all)
+{
+ int err;
+ struct page_to_node *pp;
+ LIST_HEAD(pagelist);
+
+ down_read(&mm->mmap_sem);
- newpage = lru_to_page(to);
- lock_page(newpage);
+ /*
+ * Build a list of pages to migrate
+ */
+ migrate_prep();
+ for (pp = pm; pp->node != MAX_NUMNODES; pp++) {
+ struct vm_area_struct *vma;
+ struct page *page;
/*
- * Pages are properly locked and writeback is complete.
- * Try to migrate the page.
+ * A valid page pointer that will not match any of the
+ * pages that will be moved.
*/
- mapping = page_mapping(page);
- if (!mapping)
- goto unlock_both;
+ pp->page = ZERO_PAGE(0);
- if (mapping->a_ops->migratepage) {
- /*
- * Most pages have a mapping and most filesystems
- * should provide a migration function. Anonymous
- * pages are part of swap space which also has its
- * own migration function. This is the most common
- * path for page migration.
- */
- rc = mapping->a_ops->migratepage(newpage, page);
- goto unlock_both;
- }
-
- /* Make sure the dirty bit is up to date */
- if (try_to_unmap(page, 1) == SWAP_FAIL) {
- rc = -EPERM;
- goto unlock_both;
- }
+ err = -EFAULT;
+ vma = find_vma(mm, pp->addr);
+ if (!vma)
+ goto set_status;
- if (page_mapcount(page)) {
- rc = -EAGAIN;
- goto unlock_both;
- }
+ page = follow_page(vma, pp->addr, FOLL_GET);
+ err = -ENOENT;
+ if (!page)
+ goto set_status;
- /*
- * Default handling if a filesystem does not provide
- * a migration function. We can only migrate clean
- * pages so try to write out any dirty pages first.
- */
- if (PageDirty(page)) {
- switch (pageout(page, mapping)) {
- case PAGE_KEEP:
- case PAGE_ACTIVATE:
- goto unlock_both;
-
- case PAGE_SUCCESS:
- unlock_page(newpage);
- goto next;
-
- case PAGE_CLEAN:
- ; /* try to migrate the page below */
- }
- }
+ if (PageReserved(page)) /* Check for zero page */
+ goto put_and_set;
- /*
- * Buffers are managed in a filesystem specific way.
- * We must have no buffers or drop them.
- */
- if (!page_has_buffers(page) ||
- try_to_release_page(page, GFP_KERNEL)) {
- rc = migrate_page(newpage, page);
- goto unlock_both;
- }
+ pp->page = page;
+ err = page_to_nid(page);
- /*
- * On early passes with mapped pages simply
- * retry. There may be a lock held for some
- * buffers that may go away. Later
- * swap them out.
- */
- if (pass > 4) {
+ if (err == pp->node)
/*
- * Persistently unable to drop buffers..... As a
- * measure of last resort we fall back to
- * swap_page().
+ * Node already in the right place
*/
- unlock_page(newpage);
- newpage = NULL;
- rc = swap_page(page);
- goto next;
- }
+ goto put_and_set;
-unlock_both:
- unlock_page(newpage);
-
-unlock_page:
- unlock_page(page);
-
-next:
- if (rc == -EAGAIN) {
- retry++;
- } else if (rc) {
- /* Permanent failure */
- list_move(&page->lru, failed);
- nr_failed++;
- } else {
- if (newpage) {
- /* Successful migration. Return page to LRU */
- move_to_lru(newpage);
- }
- list_move(&page->lru, moved);
- }
+ err = -EACCES;
+ if (page_mapcount(page) > 1 &&
+ !migrate_all)
+ goto put_and_set;
+
+ err = isolate_lru_page(page, &pagelist);
+put_and_set:
+ /*
+ * Either remove the duplicate refcount from
+ * isolate_lru_page() or drop the page ref if it was
+ * not isolated.
+ */
+ put_page(page);
+set_status:
+ pp->status = err;
}
- if (retry && pass++ < 10)
- goto redo;
- if (!swapwrite)
- current->flags &= ~PF_SWAPWRITE;
+ if (!list_empty(&pagelist))
+ err = migrate_pages(&pagelist, new_page_node,
+ (unsigned long)pm);
+ else
+ err = -ENOENT;
- return nr_failed + retry;
+ up_read(&mm->mmap_sem);
+ return err;
}
/*
- * Migration function for pages with buffers. This function can only be used
- * if the underlying filesystem guarantees that no other references to "page"
- * exist.
+ * Determine the nodes of a list of pages. The addr in the pm array
+ * must have been set to the virtual address of which we want to determine
+ * the node number.
*/
-int buffer_migrate_page(struct page *newpage, struct page *page)
+static int do_pages_stat(struct mm_struct *mm, struct page_to_node *pm)
{
- struct address_space *mapping = page->mapping;
- struct buffer_head *bh, *head;
- int rc;
+ down_read(&mm->mmap_sem);
+
+ for ( ; pm->node != MAX_NUMNODES; pm++) {
+ struct vm_area_struct *vma;
+ struct page *page;
+ int err;
+
+ err = -EFAULT;
+ vma = find_vma(mm, pm->addr);
+ if (!vma)
+ goto set_status;
+
+ page = follow_page(vma, pm->addr, 0);
+ err = -ENOENT;
+ /* Use PageReserved to check for zero page */
+ if (!page || PageReserved(page))
+ goto set_status;
+
+ err = page_to_nid(page);
+set_status:
+ pm->status = err;
+ }
- if (!mapping)
- return -EAGAIN;
+ up_read(&mm->mmap_sem);
+ return 0;
+}
- if (!page_has_buffers(page))
- return migrate_page(newpage, page);
+/*
+ * Move a list of pages in the address space of the currently executing
+ * process.
+ */
+asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages,
+ const void __user * __user *pages,
+ const int __user *nodes,
+ int __user *status, int flags)
+{
+ int err = 0;
+ int i;
+ struct task_struct *task;
+ nodemask_t task_nodes;
+ struct mm_struct *mm;
+ struct page_to_node *pm = NULL;
- head = page_buffers(page);
+ /* Check flags */
+ if (flags & ~(MPOL_MF_MOVE|MPOL_MF_MOVE_ALL))
+ return -EINVAL;
- rc = migrate_page_remove_references(newpage, page, 3);
+ if ((flags & MPOL_MF_MOVE_ALL) && !capable(CAP_SYS_NICE))
+ return -EPERM;
- if (rc)
- return rc;
+ /* Find the mm_struct */
+ read_lock(&tasklist_lock);
+ task = pid ? find_task_by_pid(pid) : current;
+ if (!task) {
+ read_unlock(&tasklist_lock);
+ return -ESRCH;
+ }
+ mm = get_task_mm(task);
+ read_unlock(&tasklist_lock);
- bh = head;
- do {
- get_bh(bh);
- lock_buffer(bh);
- bh = bh->b_this_page;
+ if (!mm)
+ return -EINVAL;
- } while (bh != head);
+ /*
+ * Check if this process has the right to modify the specified
+ * process. The right exists if the process has administrative
+ * capabilities, superuser privileges or the same
+ * userid as the target process.
+ */
+ if ((current->euid != task->suid) && (current->euid != task->uid) &&
+ (current->uid != task->suid) && (current->uid != task->uid) &&
+ !capable(CAP_SYS_NICE)) {
+ err = -EPERM;
+ goto out2;
+ }
- ClearPagePrivate(page);
- set_page_private(newpage, page_private(page));
- set_page_private(page, 0);
- put_page(page);
- get_page(newpage);
+ err = security_task_movememory(task);
+ if (err)
+ goto out2;
- bh = head;
- do {
- set_bh_page(bh, newpage, bh_offset(bh));
- bh = bh->b_this_page;
- } while (bh != head);
+ task_nodes = cpuset_mems_allowed(task);
- SetPagePrivate(newpage);
+ /* Limit nr_pages so that the multiplication may not overflow */
+ if (nr_pages >= ULONG_MAX / sizeof(struct page_to_node) - 1) {
+ err = -E2BIG;
+ goto out2;
+ }
- migrate_page_copy(newpage, page);
+ pm = vmalloc((nr_pages + 1) * sizeof(struct page_to_node));
+ if (!pm) {
+ err = -ENOMEM;
+ goto out2;
+ }
- bh = head;
- do {
- unlock_buffer(bh);
- put_bh(bh);
- bh = bh->b_this_page;
+ /*
+ * Get parameters from user space and initialize the pm
+ * array. Return various errors if the user did something wrong.
+ */
+ for (i = 0; i < nr_pages; i++) {
+ const void *p;
- } while (bh != head);
+ err = -EFAULT;
+ if (get_user(p, pages + i))
+ goto out;
- return 0;
-}
-EXPORT_SYMBOL(buffer_migrate_page);
+ pm[i].addr = (unsigned long)p;
+ if (nodes) {
+ int node;
-/*
- * Migrate the list 'pagelist' of pages to a certain destination.
- *
- * Specify destination with either non-NULL vma or dest_node >= 0
- * Return the number of pages not migrated or error code
- */
-int migrate_pages_to(struct list_head *pagelist,
- struct vm_area_struct *vma, int dest)
-{
- LIST_HEAD(newlist);
- LIST_HEAD(moved);
- LIST_HEAD(failed);
- int err = 0;
- unsigned long offset = 0;
- int nr_pages;
- struct page *page;
- struct list_head *p;
+ if (get_user(node, nodes + i))
+ goto out;
-redo:
- nr_pages = 0;
- list_for_each(p, pagelist) {
- if (vma) {
- /*
- * The address passed to alloc_page_vma is used to
- * generate the proper interleave behavior. We fake
- * the address here by an increasing offset in order
- * to get the proper distribution of pages.
- *
- * No decision has been made as to which page
- * a certain old page is moved to so we cannot
- * specify the correct address.
- */
- page = alloc_page_vma(GFP_HIGHUSER, vma,
- offset + vma->vm_start);
- offset += PAGE_SIZE;
- }
- else
- page = alloc_pages_node(dest, GFP_HIGHUSER, 0);
+ err = -ENODEV;
+ if (!node_online(node))
+ goto out;
- if (!page) {
- err = -ENOMEM;
- goto out;
+ err = -EACCES;
+ if (!node_isset(node, task_nodes))
+ goto out;
+
+ pm[i].node = node;
}
- list_add_tail(&page->lru, &newlist);
- nr_pages++;
- if (nr_pages > MIGRATE_CHUNK_SIZE)
- break;
}
- err = migrate_pages(pagelist, &newlist, &moved, &failed);
+ /* End marker */
+ pm[nr_pages].node = MAX_NUMNODES;
+
+ if (nodes)
+ err = do_move_pages(mm, pm, flags & MPOL_MF_MOVE_ALL);
+ else
+ err = do_pages_stat(mm, pm);
- putback_lru_pages(&moved); /* Call release pages instead ?? */
+ if (err >= 0)
+ /* Return status information */
+ for (i = 0; i < nr_pages; i++)
+ if (put_user(pm[i].status, status + i))
+ err = -EFAULT;
- if (err >= 0 && list_empty(&newlist) && !list_empty(pagelist))
- goto redo;
out:
- /* Return leftover allocated pages */
- while (!list_empty(&newlist)) {
- page = list_entry(newlist.next, struct page, lru);
- list_del(&page->lru);
- __free_page(page);
- }
- list_splice(&failed, pagelist);
- if (err < 0)
- return err;
-
- /* Calculate number of leftover pages */
- nr_pages = 0;
- list_for_each(p, pagelist)
- nr_pages++;
- return nr_pages;
+ vfree(pm);
+out2:
+ mmput(mm);
+ return err;
+}
+#endif
+
+/*
+ * Call migration functions in the vma_ops that may prepare
+ * memory in a vm for migration. migration functions may perform
+ * the migration for vmas that do not have an underlying page struct.
+ */
+int migrate_vmas(struct mm_struct *mm, const nodemask_t *to,
+ const nodemask_t *from, unsigned long flags)
+{
+ struct vm_area_struct *vma;
+ int err = 0;
+
+ for(vma = mm->mmap; vma->vm_next && !err; vma = vma->vm_next) {
+ if (vma->vm_ops && vma->vm_ops->migrate) {
+ err = vma->vm_ops->migrate(vma, to, from, flags);
+ if (err)
+ break;
+ }
+ }
+ return err;
}
diff --git a/mm/mmap.c b/mm/mmap.c
index e6ee123..6446c61 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1065,7 +1065,8 @@ munmap_back:
vma->vm_start = addr;
vma->vm_end = addr + len;
vma->vm_flags = vm_flags;
- vma->vm_page_prot = protection_map[vm_flags & 0x0f];
+ vma->vm_page_prot = protection_map[vm_flags &
+ (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)];
vma->vm_pgoff = pgoff;
if (file) {
@@ -1089,6 +1090,12 @@ munmap_back:
goto free_vma;
}
+ /* Don't make the VMA automatically writable if it's shared, but the
+ * backer wishes to know when pages are first written to */
+ if (vma->vm_ops && vma->vm_ops->page_mkwrite)
+ vma->vm_page_prot =
+ protection_map[vm_flags & (VM_READ|VM_WRITE|VM_EXEC)];
+
/* We set VM_ACCOUNT in a shared mapping's vm_flags, to inform
* shmem_zero_setup (perhaps called through /dev/zero's ->mmap)
* that memory reservation must be checked; but that reservation
@@ -1921,7 +1928,8 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
vma->vm_end = addr + len;
vma->vm_pgoff = pgoff;
vma->vm_flags = flags;
- vma->vm_page_prot = protection_map[flags & 0x0f];
+ vma->vm_page_prot = protection_map[flags &
+ (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)];
vma_link(mm, vma, prev, rb_link, rb_parent);
out:
mm->total_vm += len >> PAGE_SHIFT;
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 4c14d42..638edab 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -19,7 +19,8 @@
#include <linux/mempolicy.h>
#include <linux/personality.h>
#include <linux/syscalls.h>
-
+#include <linux/swap.h>
+#include <linux/swapops.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/cacheflush.h>
@@ -28,12 +29,13 @@
static void change_pte_range(struct mm_struct *mm, pmd_t *pmd,
unsigned long addr, unsigned long end, pgprot_t newprot)
{
- pte_t *pte;
+ pte_t *pte, oldpte;
spinlock_t *ptl;
pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
do {
- if (pte_present(*pte)) {
+ oldpte = *pte;
+ if (pte_present(oldpte)) {
pte_t ptent;
/* Avoid an SMP race with hardware updated dirty/clean
@@ -43,7 +45,22 @@ static void change_pte_range(struct mm_struct *mm, pmd_t *pmd,
ptent = pte_modify(ptep_get_and_clear(mm, addr, pte), newprot);
set_pte_at(mm, addr, pte, ptent);
lazy_mmu_prot_update(ptent);
+#ifdef CONFIG_MIGRATION
+ } else if (!pte_file(oldpte)) {
+ swp_entry_t entry = pte_to_swp_entry(oldpte);
+
+ if (is_write_migration_entry(entry)) {
+ /*
+ * A protection check is difficult so
+ * just be safe and disable write
+ */
+ make_migration_entry_read(&entry);
+ set_pte_at(mm, addr, pte,
+ swp_entry_to_pte(entry));
+ }
+#endif
}
+
} while (pte++, addr += PAGE_SIZE, addr != end);
pte_unmap_unlock(pte - 1, ptl);
}
@@ -106,6 +123,7 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev,
unsigned long oldflags = vma->vm_flags;
long nrpages = (end - start) >> PAGE_SHIFT;
unsigned long charged = 0;
+ unsigned int mask;
pgprot_t newprot;
pgoff_t pgoff;
int error;
@@ -132,8 +150,6 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev,
}
}
- newprot = protection_map[newflags & 0xf];
-
/*
* First try to merge with previous and/or next vma.
*/
@@ -160,6 +176,14 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev,
}
success:
+ /* Don't make the VMA automatically writable if it's shared, but the
+ * backer wishes to know when pages are first written to */
+ mask = VM_READ|VM_WRITE|VM_EXEC|VM_SHARED;
+ if (vma->vm_ops && vma->vm_ops->page_mkwrite)
+ mask &= ~VM_SHARED;
+
+ newprot = protection_map[newflags & mask];
+
/*
* vm_flags and vm_page_prot are protected by the mmap_sem
* held in write mode.
@@ -205,8 +229,7 @@ sys_mprotect(unsigned long start, size_t len, unsigned long prot)
/*
* Does the application expect PROT_READ to imply PROT_EXEC:
*/
- if (unlikely((prot & PROT_READ) &&
- (current->personality & READ_IMPLIES_EXEC)))
+ if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC))
prot |= PROT_EXEC;
vm_flags = calc_vm_prot_bits(prot);
diff --git a/mm/msync.c b/mm/msync.c
index bc6c953..d083544 100644
--- a/mm/msync.c
+++ b/mm/msync.c
@@ -170,8 +170,6 @@ asmlinkage long sys_msync(unsigned long start, size_t len, int flags)
* just ignore them, but return -ENOMEM at the end.
*/
down_read(&current->mm->mmap_sem);
- if (flags & MS_SYNC)
- current->flags |= PF_SYNCWRITE;
vma = find_vma(current->mm, start);
if (!vma) {
error = -ENOMEM;
@@ -228,7 +226,6 @@ asmlinkage long sys_msync(unsigned long start, size_t len, int flags)
}
} while (vma && !done);
out_unlock:
- current->flags &= ~PF_SYNCWRITE;
up_read(&current->mm->mmap_sem);
out:
return error;
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 042e643..d46ed0f 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -22,10 +22,11 @@
#include <linux/jiffies.h>
#include <linux/cpuset.h>
+int sysctl_panic_on_oom;
/* #define DEBUG */
/**
- * oom_badness - calculate a numeric value for how bad this task has been
+ * badness - calculate a numeric value for how bad this task has been
* @p: task struct of which task we should calculate
* @uptime: current uptime in seconds
*
@@ -200,7 +201,7 @@ static struct task_struct *select_bad_process(unsigned long *ppoints)
continue;
/*
- * This is in the process of releasing memory so for wait it
+ * This is in the process of releasing memory so wait for it
* to finish before killing some other task by mistake.
*/
releasing = test_tsk_thread_flag(p, TIF_MEMDIE) ||
@@ -306,7 +307,7 @@ static int oom_kill_process(struct task_struct *p, unsigned long points,
}
/**
- * oom_kill - kill the "best" process when we run out of memory
+ * out_of_memory - kill the "best" process when we run out of memory
*
* If we run out of memory, we have the choice between either
* killing a random task (bad), letting the system crash (worse)
@@ -344,6 +345,8 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order)
break;
case CONSTRAINT_NONE:
+ if (sysctl_panic_on_oom)
+ panic("out of memory. panic_on_oom is selected\n");
retry:
/*
* Rambo mode: Shoot down a process and hope it solves whatever
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 75d7f48..8ccf6f1b 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -204,6 +204,7 @@ static void balance_dirty_pages(struct address_space *mapping)
.sync_mode = WB_SYNC_NONE,
.older_than_this = NULL,
.nr_to_write = write_chunk,
+ .range_cyclic = 1,
};
get_dirty_limits(&wbs, &background_thresh,
@@ -331,6 +332,7 @@ static void background_writeout(unsigned long _min_pages)
.older_than_this = NULL,
.nr_to_write = 0,
.nonblocking = 1,
+ .range_cyclic = 1,
};
for ( ; ; ) {
@@ -407,6 +409,7 @@ static void wb_kupdate(unsigned long arg)
.nr_to_write = 0,
.nonblocking = 1,
.for_kupdate = 1,
+ .range_cyclic = 1,
};
sync_supers();
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 253a450..6c1174f 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -37,6 +37,7 @@
#include <linux/nodemask.h>
#include <linux/vmalloc.h>
#include <linux/mempolicy.h>
+#include <linux/stop_machine.h>
#include <asm/tlbflush.h>
#include <asm/div64.h>
@@ -83,8 +84,8 @@ EXPORT_SYMBOL(zone_table);
static char *zone_names[MAX_NR_ZONES] = { "DMA", "DMA32", "Normal", "HighMem" };
int min_free_kbytes = 1024;
-unsigned long __initdata nr_kernel_pages;
-unsigned long __initdata nr_all_pages;
+unsigned long __meminitdata nr_kernel_pages;
+unsigned long __meminitdata nr_all_pages;
#ifdef CONFIG_DEBUG_VM
static int page_outside_zone_boundaries(struct zone *zone, struct page *page)
@@ -286,22 +287,27 @@ __find_combined_index(unsigned long page_idx, unsigned int order)
* we can do coalesce a page and its buddy if
* (a) the buddy is not in a hole &&
* (b) the buddy is in the buddy system &&
- * (c) a page and its buddy have the same order.
+ * (c) a page and its buddy have the same order &&
+ * (d) a page and its buddy are in the same zone.
*
* For recording whether a page is in the buddy system, we use PG_buddy.
* Setting, clearing, and testing PG_buddy is serialized by zone->lock.
*
* For recording page's order, we use page_private(page).
*/
-static inline int page_is_buddy(struct page *page, int order)
+static inline int page_is_buddy(struct page *page, struct page *buddy,
+ int order)
{
#ifdef CONFIG_HOLES_IN_ZONE
- if (!pfn_valid(page_to_pfn(page)))
+ if (!pfn_valid(page_to_pfn(buddy)))
return 0;
#endif
- if (PageBuddy(page) && page_order(page) == order) {
- BUG_ON(page_count(page) != 0);
+ if (page_zone_id(page) != page_zone_id(buddy))
+ return 0;
+
+ if (PageBuddy(buddy) && page_order(buddy) == order) {
+ BUG_ON(page_count(buddy) != 0);
return 1;
}
return 0;
@@ -352,7 +358,7 @@ static inline void __free_one_page(struct page *page,
struct page *buddy;
buddy = __page_find_buddy(page, page_idx, order);
- if (!page_is_buddy(buddy, order))
+ if (!page_is_buddy(page, buddy, order))
break; /* Move the buddy up one level. */
list_del(&buddy->lru);
@@ -951,8 +957,7 @@ restart:
goto got_pg;
do {
- if (cpuset_zone_allowed(*z, gfp_mask|__GFP_HARDWALL))
- wakeup_kswapd(*z, order);
+ wakeup_kswapd(*z, order);
} while (*(++z));
/*
@@ -1485,7 +1490,7 @@ void show_free_areas(void)
}
for_each_zone(zone) {
- unsigned long nr, flags, order, total = 0;
+ unsigned long nr[MAX_ORDER], flags, order, total = 0;
show_node(zone);
printk("%s: ", zone->name);
@@ -1496,11 +1501,12 @@ void show_free_areas(void)
spin_lock_irqsave(&zone->lock, flags);
for (order = 0; order < MAX_ORDER; order++) {
- nr = zone->free_area[order].nr_free;
- total += nr << order;
- printk("%lu*%lukB ", nr, K(1UL) << order);
+ nr[order] = zone->free_area[order].nr_free;
+ total += nr[order] << order;
}
spin_unlock_irqrestore(&zone->lock, flags);
+ for (order = 0; order < MAX_ORDER; order++)
+ printk("%lu*%lukB ", nr[order], K(1UL) << order);
printk("= %lukB\n", K(total));
}
@@ -1512,7 +1518,7 @@ void show_free_areas(void)
*
* Add all populated zones of a node to the zonelist.
*/
-static int __init build_zonelists_node(pg_data_t *pgdat,
+static int __meminit build_zonelists_node(pg_data_t *pgdat,
struct zonelist *zonelist, int nr_zones, int zone_type)
{
struct zone *zone;
@@ -1548,7 +1554,7 @@ static inline int highest_zone(int zone_bits)
#ifdef CONFIG_NUMA
#define MAX_NODE_LOAD (num_online_nodes())
-static int __initdata node_load[MAX_NUMNODES];
+static int __meminitdata node_load[MAX_NUMNODES];
/**
* find_next_best_node - find the next node that should appear in a given node's fallback list
* @node: node whose fallback list we're appending
@@ -1563,7 +1569,7 @@ static int __initdata node_load[MAX_NUMNODES];
* on them otherwise.
* It returns -1 if no node is found.
*/
-static int __init find_next_best_node(int node, nodemask_t *used_node_mask)
+static int __meminit find_next_best_node(int node, nodemask_t *used_node_mask)
{
int n, val;
int min_val = INT_MAX;
@@ -1609,7 +1615,7 @@ static int __init find_next_best_node(int node, nodemask_t *used_node_mask)
return best_node;
}
-static void __init build_zonelists(pg_data_t *pgdat)
+static void __meminit build_zonelists(pg_data_t *pgdat)
{
int i, j, k, node, local_node;
int prev_node, load;
@@ -1661,7 +1667,7 @@ static void __init build_zonelists(pg_data_t *pgdat)
#else /* CONFIG_NUMA */
-static void __init build_zonelists(pg_data_t *pgdat)
+static void __meminit build_zonelists(pg_data_t *pgdat)
{
int i, j, k, node, local_node;
@@ -1699,14 +1705,29 @@ static void __init build_zonelists(pg_data_t *pgdat)
#endif /* CONFIG_NUMA */
-void __init build_all_zonelists(void)
+/* return values int ....just for stop_machine_run() */
+static int __meminit __build_all_zonelists(void *dummy)
{
- int i;
+ int nid;
+ for_each_online_node(nid)
+ build_zonelists(NODE_DATA(nid));
+ return 0;
+}
- for_each_online_node(i)
- build_zonelists(NODE_DATA(i));
- printk("Built %i zonelists\n", num_online_nodes());
- cpuset_init_current_mems_allowed();
+void __meminit build_all_zonelists(void)
+{
+ if (system_state == SYSTEM_BOOTING) {
+ __build_all_zonelists(0);
+ cpuset_init_current_mems_allowed();
+ } else {
+ /* we have to stop all cpus to guaranntee there is no user
+ of zonelist */
+ stop_machine_run(__build_all_zonelists, NULL, NR_CPUS);
+ /* cpuset refresh routine should be here */
+ }
+ vm_total_pages = nr_free_pagecache_pages();
+ printk("Built %i zonelists. Total pages: %ld\n",
+ num_online_nodes(), vm_total_pages);
}
/*
@@ -1722,7 +1743,8 @@ void __init build_all_zonelists(void)
*/
#define PAGES_PER_WAITQUEUE 256
-static inline unsigned long wait_table_size(unsigned long pages)
+#ifndef CONFIG_MEMORY_HOTPLUG
+static inline unsigned long wait_table_hash_nr_entries(unsigned long pages)
{
unsigned long size = 1;
@@ -1740,6 +1762,29 @@ static inline unsigned long wait_table_size(unsigned long pages)
return max(size, 4UL);
}
+#else
+/*
+ * A zone's size might be changed by hot-add, so it is not possible to determine
+ * a suitable size for its wait_table. So we use the maximum size now.
+ *
+ * The max wait table size = 4096 x sizeof(wait_queue_head_t). ie:
+ *
+ * i386 (preemption config) : 4096 x 16 = 64Kbyte.
+ * ia64, x86-64 (no preemption): 4096 x 20 = 80Kbyte.
+ * ia64, x86-64 (preemption) : 4096 x 24 = 96Kbyte.
+ *
+ * The maximum entries are prepared when a zone's memory is (512K + 256) pages
+ * or more by the traditional way. (See above). It equals:
+ *
+ * i386, x86-64, powerpc(4K page size) : = ( 2G + 1M)byte.
+ * ia64(16K page size) : = ( 8G + 4M)byte.
+ * powerpc (64K page size) : = (32G +16M)byte.
+ */
+static inline unsigned long wait_table_hash_nr_entries(unsigned long pages)
+{
+ return 4096UL;
+}
+#endif
/*
* This is an integer logarithm so that shifts can be used later
@@ -2005,23 +2050,46 @@ void __init setup_per_cpu_pageset(void)
#endif
static __meminit
-void zone_wait_table_init(struct zone *zone, unsigned long zone_size_pages)
+int zone_wait_table_init(struct zone *zone, unsigned long zone_size_pages)
{
int i;
struct pglist_data *pgdat = zone->zone_pgdat;
+ size_t alloc_size;
/*
* The per-page waitqueue mechanism uses hashed waitqueues
* per zone.
*/
- zone->wait_table_size = wait_table_size(zone_size_pages);
- zone->wait_table_bits = wait_table_bits(zone->wait_table_size);
- zone->wait_table = (wait_queue_head_t *)
- alloc_bootmem_node(pgdat, zone->wait_table_size
- * sizeof(wait_queue_head_t));
+ zone->wait_table_hash_nr_entries =
+ wait_table_hash_nr_entries(zone_size_pages);
+ zone->wait_table_bits =
+ wait_table_bits(zone->wait_table_hash_nr_entries);
+ alloc_size = zone->wait_table_hash_nr_entries
+ * sizeof(wait_queue_head_t);
+
+ if (system_state == SYSTEM_BOOTING) {
+ zone->wait_table = (wait_queue_head_t *)
+ alloc_bootmem_node(pgdat, alloc_size);
+ } else {
+ /*
+ * This case means that a zone whose size was 0 gets new memory
+ * via memory hot-add.
+ * But it may be the case that a new node was hot-added. In
+ * this case vmalloc() will not be able to use this new node's
+ * memory - this wait_table must be initialized to use this new
+ * node itself as well.
+ * To use this new node's memory, further consideration will be
+ * necessary.
+ */
+ zone->wait_table = (wait_queue_head_t *)vmalloc(alloc_size);
+ }
+ if (!zone->wait_table)
+ return -ENOMEM;
- for(i = 0; i < zone->wait_table_size; ++i)
+ for(i = 0; i < zone->wait_table_hash_nr_entries; ++i)
init_waitqueue_head(zone->wait_table + i);
+
+ return 0;
}
static __meminit void zone_pcp_init(struct zone *zone)
@@ -2043,12 +2111,15 @@ static __meminit void zone_pcp_init(struct zone *zone)
zone->name, zone->present_pages, batch);
}
-static __meminit void init_currently_empty_zone(struct zone *zone,
- unsigned long zone_start_pfn, unsigned long size)
+__meminit int init_currently_empty_zone(struct zone *zone,
+ unsigned long zone_start_pfn,
+ unsigned long size)
{
struct pglist_data *pgdat = zone->zone_pgdat;
-
- zone_wait_table_init(zone, size);
+ int ret;
+ ret = zone_wait_table_init(zone, size);
+ if (ret)
+ return ret;
pgdat->nr_zones = zone_idx(zone) + 1;
zone->zone_start_pfn = zone_start_pfn;
@@ -2056,6 +2127,8 @@ static __meminit void init_currently_empty_zone(struct zone *zone,
memmap_init(size, pgdat->node_id, zone_idx(zone), zone_start_pfn);
zone_init_free_lists(pgdat, zone, zone->spanned_pages);
+
+ return 0;
}
/*
@@ -2064,12 +2137,13 @@ static __meminit void init_currently_empty_zone(struct zone *zone,
* - mark all memory queues empty
* - clear the memory bitmaps
*/
-static void __init free_area_init_core(struct pglist_data *pgdat,
+static void __meminit free_area_init_core(struct pglist_data *pgdat,
unsigned long *zones_size, unsigned long *zholes_size)
{
unsigned long j;
int nid = pgdat->node_id;
unsigned long zone_start_pfn = pgdat->node_start_pfn;
+ int ret;
pgdat_resize_init(pgdat);
pgdat->nr_zones = 0;
@@ -2111,7 +2185,8 @@ static void __init free_area_init_core(struct pglist_data *pgdat,
continue;
zonetable_add(zone, nid, j, zone_start_pfn, size);
- init_currently_empty_zone(zone, zone_start_pfn, size);
+ ret = init_currently_empty_zone(zone, zone_start_pfn, size);
+ BUG_ON(ret);
zone_start_pfn += size;
}
}
@@ -2152,7 +2227,7 @@ static void __init alloc_node_mem_map(struct pglist_data *pgdat)
#endif /* CONFIG_FLAT_NODE_MEM_MAP */
}
-void __init free_area_init_node(int nid, struct pglist_data *pgdat,
+void __meminit free_area_init_node(int nid, struct pglist_data *pgdat,
unsigned long *zones_size, unsigned long node_start_pfn,
unsigned long *zholes_size)
{
@@ -2804,42 +2879,14 @@ void *__init alloc_large_system_hash(const char *tablename,
}
#ifdef CONFIG_OUT_OF_LINE_PFN_TO_PAGE
-/*
- * pfn <-> page translation. out-of-line version.
- * (see asm-generic/memory_model.h)
- */
-#if defined(CONFIG_FLATMEM)
struct page *pfn_to_page(unsigned long pfn)
{
- return mem_map + (pfn - ARCH_PFN_OFFSET);
+ return __pfn_to_page(pfn);
}
unsigned long page_to_pfn(struct page *page)
{
- return (page - mem_map) + ARCH_PFN_OFFSET;
-}
-#elif defined(CONFIG_DISCONTIGMEM)
-struct page *pfn_to_page(unsigned long pfn)
-{
- int nid = arch_pfn_to_nid(pfn);
- return NODE_DATA(nid)->node_mem_map + arch_local_page_offset(pfn,nid);
-}
-unsigned long page_to_pfn(struct page *page)
-{
- struct pglist_data *pgdat = NODE_DATA(page_to_nid(page));
- return (page - pgdat->node_mem_map) + pgdat->node_start_pfn;
-}
-#elif defined(CONFIG_SPARSEMEM)
-struct page *pfn_to_page(unsigned long pfn)
-{
- return __section_mem_map_addr(__pfn_to_section(pfn)) + pfn;
-}
-
-unsigned long page_to_pfn(struct page *page)
-{
- long section_id = page_to_section(page);
- return page - __section_mem_map_addr(__nr_to_section(section_id));
+ return __page_to_pfn(page);
}
-#endif /* CONFIG_FLATMEM/DISCONTIGMME/SPARSEMEM */
EXPORT_SYMBOL(pfn_to_page);
EXPORT_SYMBOL(page_to_pfn);
#endif /* CONFIG_OUT_OF_LINE_PFN_TO_PAGE */
diff --git a/mm/pdflush.c b/mm/pdflush.c
index c4b6d0a..b02102f 100644
--- a/mm/pdflush.c
+++ b/mm/pdflush.c
@@ -104,21 +104,20 @@ static int __pdflush(struct pdflush_work *my_work)
list_move(&my_work->list, &pdflush_list);
my_work->when_i_went_to_sleep = jiffies;
spin_unlock_irq(&pdflush_lock);
-
schedule();
- if (try_to_freeze()) {
- spin_lock_irq(&pdflush_lock);
- continue;
- }
-
+ try_to_freeze();
spin_lock_irq(&pdflush_lock);
if (!list_empty(&my_work->list)) {
- printk("pdflush: bogus wakeup!\n");
+ /*
+ * Someone woke us up, but without removing our control
+ * structure from the global list. swsusp will do this
+ * in try_to_freeze()->refrigerator(). Handle it.
+ */
my_work->fn = NULL;
continue;
}
if (my_work->fn == NULL) {
- printk("pdflush: NULL work function\n");
+ printk("pdflush: bogus wakeup\n");
continue;
}
spin_unlock_irq(&pdflush_lock);
@@ -202,8 +201,7 @@ int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0)
unsigned long flags;
int ret = 0;
- if (fn == NULL)
- BUG(); /* Hard to diagnose if it's deferred */
+ BUG_ON(fn == NULL); /* Hard to diagnose if it's deferred */
spin_lock_irqsave(&pdflush_lock, flags);
if (list_empty(&pdflush_list)) {
diff --git a/mm/readahead.c b/mm/readahead.c
index 0f142a4..e39e416 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -118,8 +118,7 @@ static inline unsigned long get_next_ra_size(struct file_ra_state *ra)
#define list_to_page(head) (list_entry((head)->prev, struct page, lru))
/**
- * read_cache_pages - populate an address space with some pages, and
- * start reads against them.
+ * read_cache_pages - populate an address space with some pages & start reads against them
* @mapping: the address_space
* @pages: The address of a list_head which contains the target pages. These
* pages have their ->index populated and are otherwise uninitialised.
@@ -182,14 +181,11 @@ static int read_pages(struct address_space *mapping, struct file *filp,
list_del(&page->lru);
if (!add_to_page_cache(page, mapping,
page->index, GFP_KERNEL)) {
- ret = mapping->a_ops->readpage(filp, page);
- if (ret != AOP_TRUNCATED_PAGE) {
- if (!pagevec_add(&lru_pvec, page))
- __pagevec_lru_add(&lru_pvec);
- continue;
- } /* else fall through to release */
- }
- page_cache_release(page);
+ mapping->a_ops->readpage(filp, page);
+ if (!pagevec_add(&lru_pvec, page))
+ __pagevec_lru_add(&lru_pvec);
+ } else
+ page_cache_release(page);
}
pagevec_lru_add(&lru_pvec);
ret = 0;
diff --git a/mm/rmap.c b/mm/rmap.c
index 1963e26..e76909e 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -103,7 +103,7 @@ int anon_vma_prepare(struct vm_area_struct *vma)
spin_lock(&mm->page_table_lock);
if (likely(!vma->anon_vma)) {
vma->anon_vma = anon_vma;
- list_add(&vma->anon_vma_node, &anon_vma->head);
+ list_add_tail(&vma->anon_vma_node, &anon_vma->head);
allocated = NULL;
}
spin_unlock(&mm->page_table_lock);
@@ -127,7 +127,7 @@ void __anon_vma_link(struct vm_area_struct *vma)
struct anon_vma *anon_vma = vma->anon_vma;
if (anon_vma) {
- list_add(&vma->anon_vma_node, &anon_vma->head);
+ list_add_tail(&vma->anon_vma_node, &anon_vma->head);
validate_anon_vma(vma);
}
}
@@ -138,7 +138,7 @@ void anon_vma_link(struct vm_area_struct *vma)
if (anon_vma) {
spin_lock(&anon_vma->lock);
- list_add(&vma->anon_vma_node, &anon_vma->head);
+ list_add_tail(&vma->anon_vma_node, &anon_vma->head);
validate_anon_vma(vma);
spin_unlock(&anon_vma->lock);
}
@@ -205,44 +205,6 @@ out:
return anon_vma;
}
-#ifdef CONFIG_MIGRATION
-/*
- * Remove an anonymous page from swap replacing the swap pte's
- * through real pte's pointing to valid pages and then releasing
- * the page from the swap cache.
- *
- * Must hold page lock on page and mmap_sem of one vma that contains
- * the page.
- */
-void remove_from_swap(struct page *page)
-{
- struct anon_vma *anon_vma;
- struct vm_area_struct *vma;
- unsigned long mapping;
-
- if (!PageSwapCache(page))
- return;
-
- mapping = (unsigned long)page->mapping;
-
- if (!mapping || (mapping & PAGE_MAPPING_ANON) == 0)
- return;
-
- /*
- * We hold the mmap_sem lock. So no need to call page_lock_anon_vma.
- */
- anon_vma = (struct anon_vma *) (mapping - PAGE_MAPPING_ANON);
- spin_lock(&anon_vma->lock);
-
- list_for_each_entry(vma, &anon_vma->head, anon_vma_node)
- remove_vma_swap(vma, page);
-
- spin_unlock(&anon_vma->lock);
- delete_from_swap_cache(page);
-}
-EXPORT_SYMBOL(remove_from_swap);
-#endif
-
/*
* At what user virtual address is page expected in vma?
*/
@@ -578,7 +540,7 @@ void page_remove_rmap(struct page *page)
* repeatedly from either try_to_unmap_anon or try_to_unmap_file.
*/
static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
- int ignore_refs)
+ int migration)
{
struct mm_struct *mm = vma->vm_mm;
unsigned long address;
@@ -600,9 +562,8 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
* If it's recently referenced (perhaps page_referenced
* skipped over this mm) then we should reactivate it.
*/
- if ((vma->vm_flags & VM_LOCKED) ||
- (ptep_clear_flush_young(vma, address, pte)
- && !ignore_refs)) {
+ if (!migration && ((vma->vm_flags & VM_LOCKED) ||
+ (ptep_clear_flush_young(vma, address, pte)))) {
ret = SWAP_FAIL;
goto out_unmap;
}
@@ -620,24 +581,45 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
if (PageAnon(page)) {
swp_entry_t entry = { .val = page_private(page) };
- /*
- * Store the swap location in the pte.
- * See handle_pte_fault() ...
- */
- BUG_ON(!PageSwapCache(page));
- swap_duplicate(entry);
- if (list_empty(&mm->mmlist)) {
- spin_lock(&mmlist_lock);
- if (list_empty(&mm->mmlist))
- list_add(&mm->mmlist, &init_mm.mmlist);
- spin_unlock(&mmlist_lock);
+
+ if (PageSwapCache(page)) {
+ /*
+ * Store the swap location in the pte.
+ * See handle_pte_fault() ...
+ */
+ swap_duplicate(entry);
+ if (list_empty(&mm->mmlist)) {
+ spin_lock(&mmlist_lock);
+ if (list_empty(&mm->mmlist))
+ list_add(&mm->mmlist, &init_mm.mmlist);
+ spin_unlock(&mmlist_lock);
+ }
+ dec_mm_counter(mm, anon_rss);
+#ifdef CONFIG_MIGRATION
+ } else {
+ /*
+ * Store the pfn of the page in a special migration
+ * pte. do_swap_page() will wait until the migration
+ * pte is removed and then restart fault handling.
+ */
+ BUG_ON(!migration);
+ entry = make_migration_entry(page, pte_write(pteval));
+#endif
}
set_pte_at(mm, address, pte, swp_entry_to_pte(entry));
BUG_ON(pte_file(*pte));
- dec_mm_counter(mm, anon_rss);
} else
+#ifdef CONFIG_MIGRATION
+ if (migration) {
+ /* Establish migration entry for a file page */
+ swp_entry_t entry;
+ entry = make_migration_entry(page, pte_write(pteval));
+ set_pte_at(mm, address, pte, swp_entry_to_pte(entry));
+ } else
+#endif
dec_mm_counter(mm, file_rss);
+
page_remove_rmap(page);
page_cache_release(page);
@@ -736,7 +718,7 @@ static void try_to_unmap_cluster(unsigned long cursor,
pte_unmap_unlock(pte - 1, ptl);
}
-static int try_to_unmap_anon(struct page *page, int ignore_refs)
+static int try_to_unmap_anon(struct page *page, int migration)
{
struct anon_vma *anon_vma;
struct vm_area_struct *vma;
@@ -747,7 +729,7 @@ static int try_to_unmap_anon(struct page *page, int ignore_refs)
return ret;
list_for_each_entry(vma, &anon_vma->head, anon_vma_node) {
- ret = try_to_unmap_one(page, vma, ignore_refs);
+ ret = try_to_unmap_one(page, vma, migration);
if (ret == SWAP_FAIL || !page_mapped(page))
break;
}
@@ -764,7 +746,7 @@ static int try_to_unmap_anon(struct page *page, int ignore_refs)
*
* This function is only called from try_to_unmap for object-based pages.
*/
-static int try_to_unmap_file(struct page *page, int ignore_refs)
+static int try_to_unmap_file(struct page *page, int migration)
{
struct address_space *mapping = page->mapping;
pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
@@ -778,7 +760,7 @@ static int try_to_unmap_file(struct page *page, int ignore_refs)
spin_lock(&mapping->i_mmap_lock);
vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
- ret = try_to_unmap_one(page, vma, ignore_refs);
+ ret = try_to_unmap_one(page, vma, migration);
if (ret == SWAP_FAIL || !page_mapped(page))
goto out;
}
@@ -788,7 +770,7 @@ static int try_to_unmap_file(struct page *page, int ignore_refs)
list_for_each_entry(vma, &mapping->i_mmap_nonlinear,
shared.vm_set.list) {
- if (vma->vm_flags & VM_LOCKED)
+ if ((vma->vm_flags & VM_LOCKED) && !migration)
continue;
cursor = (unsigned long) vma->vm_private_data;
if (cursor > max_nl_cursor)
@@ -822,7 +804,7 @@ static int try_to_unmap_file(struct page *page, int ignore_refs)
do {
list_for_each_entry(vma, &mapping->i_mmap_nonlinear,
shared.vm_set.list) {
- if (vma->vm_flags & VM_LOCKED)
+ if ((vma->vm_flags & VM_LOCKED) && !migration)
continue;
cursor = (unsigned long) vma->vm_private_data;
while ( cursor < max_nl_cursor &&
@@ -863,16 +845,16 @@ out:
* SWAP_AGAIN - we missed a mapping, try again later
* SWAP_FAIL - the page is unswappable
*/
-int try_to_unmap(struct page *page, int ignore_refs)
+int try_to_unmap(struct page *page, int migration)
{
int ret;
BUG_ON(!PageLocked(page));
if (PageAnon(page))
- ret = try_to_unmap_anon(page, ignore_refs);
+ ret = try_to_unmap_anon(page, migration);
else
- ret = try_to_unmap_file(page, ignore_refs);
+ ret = try_to_unmap_file(page, migration);
if (!page_mapped(page))
ret = SWAP_SUCCESS;
diff --git a/mm/shmem.c b/mm/shmem.c
index 1e43c8a..38bc333 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1081,14 +1081,6 @@ repeat:
page_cache_release(swappage);
goto repeat;
}
- if (!PageSwapCache(swappage)) {
- /* Page migration has occured */
- shmem_swp_unmap(entry);
- spin_unlock(&info->lock);
- unlock_page(swappage);
- page_cache_release(swappage);
- goto repeat;
- }
if (PageWriteback(swappage)) {
shmem_swp_unmap(entry);
spin_unlock(&info->lock);
@@ -1654,9 +1646,9 @@ static ssize_t shmem_file_sendfile(struct file *in_file, loff_t *ppos,
return desc.error;
}
-static int shmem_statfs(struct super_block *sb, struct kstatfs *buf)
+static int shmem_statfs(struct dentry *dentry, struct kstatfs *buf)
{
- struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
+ struct shmem_sb_info *sbinfo = SHMEM_SB(dentry->d_sb);
buf->f_type = TMPFS_MAGIC;
buf->f_bsize = PAGE_CACHE_SIZE;
@@ -2233,10 +2225,10 @@ static struct vm_operations_struct shmem_vm_ops = {
};
-static struct super_block *shmem_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int shmem_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_nodev(fs_type, flags, data, shmem_fill_super);
+ return get_sb_nodev(fs_type, flags, data, shmem_fill_super, mnt);
}
static struct file_system_type tmpfs_fs_type = {
@@ -2263,7 +2255,7 @@ static int __init init_tmpfs(void)
#ifdef CONFIG_TMPFS
devfs_mk_dir("shm");
#endif
- shm_mnt = do_kern_mount(tmpfs_fs_type.name, MS_NOUSER,
+ shm_mnt = vfs_kern_mount(&tmpfs_fs_type, MS_NOUSER,
tmpfs_fs_type.name, NULL);
if (IS_ERR(shm_mnt)) {
error = PTR_ERR(shm_mnt);
diff --git a/mm/slab.c b/mm/slab.c
index f1b644e..98ac20b 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -331,6 +331,8 @@ static __always_inline int index_of(const size_t size)
return 0;
}
+static int slab_early_init = 1;
+
#define INDEX_AC index_of(sizeof(struct arraycache_init))
#define INDEX_L3 index_of(sizeof(struct kmem_list3))
@@ -592,6 +594,7 @@ static inline struct kmem_cache *page_get_cache(struct page *page)
{
if (unlikely(PageCompound(page)))
page = (struct page *)page_private(page);
+ BUG_ON(!PageSlab(page));
return (struct kmem_cache *)page->lru.next;
}
@@ -604,6 +607,7 @@ static inline struct slab *page_get_slab(struct page *page)
{
if (unlikely(PageCompound(page)))
page = (struct page *)page_private(page);
+ BUG_ON(!PageSlab(page));
return (struct slab *)page->lru.prev;
}
@@ -1024,6 +1028,40 @@ static void drain_alien_cache(struct kmem_cache *cachep,
}
}
}
+
+static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
+{
+ struct slab *slabp = virt_to_slab(objp);
+ int nodeid = slabp->nodeid;
+ struct kmem_list3 *l3;
+ struct array_cache *alien = NULL;
+
+ /*
+ * Make sure we are not freeing a object from another node to the array
+ * cache on this cpu.
+ */
+ if (likely(slabp->nodeid == numa_node_id()))
+ return 0;
+
+ l3 = cachep->nodelists[numa_node_id()];
+ STATS_INC_NODEFREES(cachep);
+ if (l3->alien && l3->alien[nodeid]) {
+ alien = l3->alien[nodeid];
+ spin_lock(&alien->lock);
+ if (unlikely(alien->avail == alien->limit)) {
+ STATS_INC_ACOVERFLOW(cachep);
+ __drain_alien_cache(cachep, alien, nodeid);
+ }
+ alien->entry[alien->avail++] = objp;
+ spin_unlock(&alien->lock);
+ } else {
+ spin_lock(&(cachep->nodelists[nodeid])->list_lock);
+ free_block(cachep, &objp, 1, nodeid);
+ spin_unlock(&(cachep->nodelists[nodeid])->list_lock);
+ }
+ return 1;
+}
+
#else
#define drain_alien_cache(cachep, alien) do { } while (0)
@@ -1038,6 +1076,11 @@ static inline void free_alien_cache(struct array_cache **ac_ptr)
{
}
+static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
+{
+ return 0;
+}
+
#endif
static int cpuup_callback(struct notifier_block *nfb,
@@ -1335,6 +1378,8 @@ void __init kmem_cache_init(void)
NULL, NULL);
}
+ slab_early_init = 0;
+
while (sizes->cs_size != ULONG_MAX) {
/*
* For performance, all the general caches are L1 aligned.
@@ -1450,31 +1495,29 @@ __initcall(cpucache_init);
static void *kmem_getpages(struct kmem_cache *cachep, gfp_t flags, int nodeid)
{
struct page *page;
- void *addr;
+ int nr_pages;
int i;
- flags |= cachep->gfpflags;
#ifndef CONFIG_MMU
- /* nommu uses slab's for process anonymous memory allocations, so
- * requires __GFP_COMP to properly refcount higher order allocations"
+ /*
+ * Nommu uses slab's for process anonymous memory allocations, and thus
+ * requires __GFP_COMP to properly refcount higher order allocations
*/
- page = alloc_pages_node(nodeid, (flags | __GFP_COMP), cachep->gfporder);
-#else
- page = alloc_pages_node(nodeid, flags, cachep->gfporder);
+ flags |= __GFP_COMP;
#endif
+ flags |= cachep->gfpflags;
+
+ page = alloc_pages_node(nodeid, flags, cachep->gfporder);
if (!page)
return NULL;
- addr = page_address(page);
- i = (1 << cachep->gfporder);
+ nr_pages = (1 << cachep->gfporder);
if (cachep->flags & SLAB_RECLAIM_ACCOUNT)
- atomic_add(i, &slab_reclaim_pages);
- add_page_state(nr_slab, i);
- while (i--) {
- __SetPageSlab(page);
- page++;
- }
- return addr;
+ atomic_add(nr_pages, &slab_reclaim_pages);
+ add_page_state(nr_slab, nr_pages);
+ for (i = 0; i < nr_pages; i++)
+ __SetPageSlab(page + i);
+ return page_address(page);
}
/*
@@ -1913,8 +1956,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
void (*dtor)(void*, struct kmem_cache *, unsigned long))
{
size_t left_over, slab_size, ralign;
- struct kmem_cache *cachep = NULL;
- struct list_head *p;
+ struct kmem_cache *cachep = NULL, *pc;
/*
* Sanity checks... these are all serious usage bugs.
@@ -1934,8 +1976,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
mutex_lock(&cache_chain_mutex);
- list_for_each(p, &cache_chain) {
- struct kmem_cache *pc = list_entry(p, struct kmem_cache, next);
+ list_for_each_entry(pc, &cache_chain, next) {
mm_segment_t old_fs = get_fs();
char tmp;
int res;
@@ -2069,8 +2110,12 @@ kmem_cache_create (const char *name, size_t size, size_t align,
#endif
#endif
- /* Determine if the slab management is 'on' or 'off' slab. */
- if (size >= (PAGE_SIZE >> 3))
+ /*
+ * Determine if the slab management is 'on' or 'off' slab.
+ * (bootstrapping cannot cope with offslab caches so don't do
+ * it too early on.)
+ */
+ if ((size >= (PAGE_SIZE >> 3)) && !slab_early_init)
/*
* Size is large, assume best to place the slab management obj
* off-slab (should allow better packing of objs).
@@ -2460,23 +2505,28 @@ static void slab_put_obj(struct kmem_cache *cachep, struct slab *slabp,
slabp->inuse--;
}
-static void set_slab_attr(struct kmem_cache *cachep, struct slab *slabp,
- void *objp)
+/*
+ * Map pages beginning at addr to the given cache and slab. This is required
+ * for the slab allocator to be able to lookup the cache and slab of a
+ * virtual address for kfree, ksize, kmem_ptr_validate, and slab debugging.
+ */
+static void slab_map_pages(struct kmem_cache *cache, struct slab *slab,
+ void *addr)
{
- int i;
+ int nr_pages;
struct page *page;
- /* Nasty!!!!!! I hope this is OK. */
- page = virt_to_page(objp);
+ page = virt_to_page(addr);
- i = 1;
+ nr_pages = 1;
if (likely(!PageCompound(page)))
- i <<= cachep->gfporder;
+ nr_pages <<= cache->gfporder;
+
do {
- page_set_cache(page, cachep);
- page_set_slab(page, slabp);
+ page_set_cache(page, cache);
+ page_set_slab(page, slab);
page++;
- } while (--i);
+ } while (--nr_pages);
}
/*
@@ -2548,7 +2598,7 @@ static int cache_grow(struct kmem_cache *cachep, gfp_t flags, int nodeid)
goto opps1;
slabp->nodeid = nodeid;
- set_slab_attr(cachep, slabp, objp);
+ slab_map_pages(cachep, slabp, objp);
cache_init_objs(cachep, slabp, ctor_flags);
@@ -2596,6 +2646,28 @@ static void kfree_debugcheck(const void *objp)
}
}
+static inline void verify_redzone_free(struct kmem_cache *cache, void *obj)
+{
+ unsigned long redzone1, redzone2;
+
+ redzone1 = *dbg_redzone1(cache, obj);
+ redzone2 = *dbg_redzone2(cache, obj);
+
+ /*
+ * Redzone is ok.
+ */
+ if (redzone1 == RED_ACTIVE && redzone2 == RED_ACTIVE)
+ return;
+
+ if (redzone1 == RED_INACTIVE && redzone2 == RED_INACTIVE)
+ slab_error(cache, "double free detected");
+ else
+ slab_error(cache, "memory outside object was overwritten");
+
+ printk(KERN_ERR "%p: redzone 1:0x%lx, redzone 2:0x%lx.\n",
+ obj, redzone1, redzone2);
+}
+
static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp,
void *caller)
{
@@ -2607,27 +2679,10 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp,
kfree_debugcheck(objp);
page = virt_to_page(objp);
- if (page_get_cache(page) != cachep) {
- printk(KERN_ERR "mismatch in kmem_cache_free: expected "
- "cache %p, got %p\n",
- page_get_cache(page), cachep);
- printk(KERN_ERR "%p is %s.\n", cachep, cachep->name);
- printk(KERN_ERR "%p is %s.\n", page_get_cache(page),
- page_get_cache(page)->name);
- WARN_ON(1);
- }
slabp = page_get_slab(page);
if (cachep->flags & SLAB_RED_ZONE) {
- if (*dbg_redzone1(cachep, objp) != RED_ACTIVE ||
- *dbg_redzone2(cachep, objp) != RED_ACTIVE) {
- slab_error(cachep, "double free, or memory outside"
- " object was overwritten");
- printk(KERN_ERR "%p: redzone 1:0x%lx, "
- "redzone 2:0x%lx.\n",
- objp, *dbg_redzone1(cachep, objp),
- *dbg_redzone2(cachep, objp));
- }
+ verify_redzone_free(cachep, objp);
*dbg_redzone1(cachep, objp) = RED_INACTIVE;
*dbg_redzone2(cachep, objp) = RED_INACTIVE;
}
@@ -3087,41 +3142,9 @@ static inline void __cache_free(struct kmem_cache *cachep, void *objp)
check_irq_off();
objp = cache_free_debugcheck(cachep, objp, __builtin_return_address(0));
- /* Make sure we are not freeing a object from another
- * node to the array cache on this cpu.
- */
-#ifdef CONFIG_NUMA
- {
- struct slab *slabp;
- slabp = virt_to_slab(objp);
- if (unlikely(slabp->nodeid != numa_node_id())) {
- struct array_cache *alien = NULL;
- int nodeid = slabp->nodeid;
- struct kmem_list3 *l3;
-
- l3 = cachep->nodelists[numa_node_id()];
- STATS_INC_NODEFREES(cachep);
- if (l3->alien && l3->alien[nodeid]) {
- alien = l3->alien[nodeid];
- spin_lock(&alien->lock);
- if (unlikely(alien->avail == alien->limit)) {
- STATS_INC_ACOVERFLOW(cachep);
- __drain_alien_cache(cachep,
- alien, nodeid);
- }
- alien->entry[alien->avail++] = objp;
- spin_unlock(&alien->lock);
- } else {
- spin_lock(&(cachep->nodelists[nodeid])->
- list_lock);
- free_block(cachep, &objp, 1, nodeid);
- spin_unlock(&(cachep->nodelists[nodeid])->
- list_lock);
- }
- return;
- }
- }
-#endif
+ if (cache_free_alien(cachep, objp))
+ return;
+
if (likely(ac->avail < ac->limit)) {
STATS_INC_FREEHIT(cachep);
ac->entry[ac->avail++] = objp;
@@ -3254,26 +3277,10 @@ EXPORT_SYMBOL(kmalloc_node);
#endif
/**
- * kmalloc - allocate memory
+ * __do_kmalloc - allocate memory
* @size: how many bytes of memory are required.
- * @flags: the type of memory to allocate.
+ * @flags: the type of memory to allocate (see kmalloc).
* @caller: function caller for debug tracking of the caller
- *
- * kmalloc is the normal method of allocating memory
- * in the kernel.
- *
- * The @flags argument may be one of:
- *
- * %GFP_USER - Allocate memory on behalf of user. May sleep.
- *
- * %GFP_KERNEL - Allocate normal kernel ram. May sleep.
- *
- * %GFP_ATOMIC - Allocation will not sleep. Use inside interrupt handlers.
- *
- * Additionally, the %GFP_DMA flag may be set to indicate the memory
- * must be suitable for DMA. This can mean different things on different
- * platforms. For example, on i386, it means that the memory must come
- * from the first 16MB.
*/
static __always_inline void *__do_kmalloc(size_t size, gfp_t flags,
void *caller)
@@ -3371,6 +3378,8 @@ void kmem_cache_free(struct kmem_cache *cachep, void *objp)
{
unsigned long flags;
+ BUG_ON(virt_to_cache(objp) != cachep);
+
local_irq_save(flags);
__cache_free(cachep, objp);
local_irq_restore(flags);
@@ -3680,7 +3689,7 @@ void drain_array(struct kmem_cache *cachep, struct kmem_list3 *l3,
*/
static void cache_reap(void *unused)
{
- struct list_head *walk;
+ struct kmem_cache *searchp;
struct kmem_list3 *l3;
int node = numa_node_id();
@@ -3691,13 +3700,11 @@ static void cache_reap(void *unused)
return;
}
- list_for_each(walk, &cache_chain) {
- struct kmem_cache *searchp;
+ list_for_each_entry(searchp, &cache_chain, next) {
struct list_head *p;
int tofree;
struct slab *slabp;
- searchp = list_entry(walk, struct kmem_cache, next);
check_irq_on();
/*
@@ -3825,7 +3832,6 @@ static void s_stop(struct seq_file *m, void *p)
static int s_show(struct seq_file *m, void *p)
{
struct kmem_cache *cachep = p;
- struct list_head *q;
struct slab *slabp;
unsigned long active_objs;
unsigned long num_objs;
@@ -3846,15 +3852,13 @@ static int s_show(struct seq_file *m, void *p)
check_irq_on();
spin_lock_irq(&l3->list_lock);
- list_for_each(q, &l3->slabs_full) {
- slabp = list_entry(q, struct slab, list);
+ list_for_each_entry(slabp, &l3->slabs_full, list) {
if (slabp->inuse != cachep->num && !error)
error = "slabs_full accounting error";
active_objs += cachep->num;
active_slabs++;
}
- list_for_each(q, &l3->slabs_partial) {
- slabp = list_entry(q, struct slab, list);
+ list_for_each_entry(slabp, &l3->slabs_partial, list) {
if (slabp->inuse == cachep->num && !error)
error = "slabs_partial inuse accounting error";
if (!slabp->inuse && !error)
@@ -3862,8 +3866,7 @@ static int s_show(struct seq_file *m, void *p)
active_objs += slabp->inuse;
active_slabs++;
}
- list_for_each(q, &l3->slabs_free) {
- slabp = list_entry(q, struct slab, list);
+ list_for_each_entry(slabp, &l3->slabs_free, list) {
if (slabp->inuse && !error)
error = "slabs_free/inuse accounting error";
num_slabs++;
@@ -3956,7 +3959,7 @@ ssize_t slabinfo_write(struct file *file, const char __user * buffer,
{
char kbuf[MAX_SLABINFO_WRITE + 1], *tmp;
int limit, batchcount, shared, res;
- struct list_head *p;
+ struct kmem_cache *cachep;
if (count > MAX_SLABINFO_WRITE)
return -EINVAL;
@@ -3975,10 +3978,7 @@ ssize_t slabinfo_write(struct file *file, const char __user * buffer,
/* Find the cache in the chain of caches. */
mutex_lock(&cache_chain_mutex);
res = -EINVAL;
- list_for_each(p, &cache_chain) {
- struct kmem_cache *cachep;
-
- cachep = list_entry(p, struct kmem_cache, next);
+ list_for_each_entry(cachep, &cache_chain, next) {
if (!strcmp(cachep->name, kbuf)) {
if (limit < 1 || batchcount < 1 ||
batchcount > limit || shared < 0) {
@@ -4080,7 +4080,6 @@ static void show_symbol(struct seq_file *m, unsigned long address)
static int leaks_show(struct seq_file *m, void *p)
{
struct kmem_cache *cachep = p;
- struct list_head *q;
struct slab *slabp;
struct kmem_list3 *l3;
const char *name;
@@ -4105,14 +4104,10 @@ static int leaks_show(struct seq_file *m, void *p)
check_irq_on();
spin_lock_irq(&l3->list_lock);
- list_for_each(q, &l3->slabs_full) {
- slabp = list_entry(q, struct slab, list);
+ list_for_each_entry(slabp, &l3->slabs_full, list)
handle_slab(n, cachep, slabp);
- }
- list_for_each(q, &l3->slabs_partial) {
- slabp = list_entry(q, struct slab, list);
+ list_for_each_entry(slabp, &l3->slabs_partial, list)
handle_slab(n, cachep, slabp);
- }
spin_unlock_irq(&l3->list_lock);
}
name = cachep->name;
diff --git a/mm/sparse.c b/mm/sparse.c
index 100040c..e0a3fe4 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -99,6 +99,22 @@ int __section_nr(struct mem_section* ms)
return (root_nr * SECTIONS_PER_ROOT) + (ms - root);
}
+/*
+ * During early boot, before section_mem_map is used for an actual
+ * mem_map, we use section_mem_map to store the section's NUMA
+ * node. This keeps us from having to use another data structure. The
+ * node information is cleared just before we store the real mem_map.
+ */
+static inline unsigned long sparse_encode_early_nid(int nid)
+{
+ return (nid << SECTION_NID_SHIFT);
+}
+
+static inline int sparse_early_nid(struct mem_section *section)
+{
+ return (section->section_mem_map >> SECTION_NID_SHIFT);
+}
+
/* Record a memory area against a node. */
void memory_present(int nid, unsigned long start, unsigned long end)
{
@@ -113,7 +129,8 @@ void memory_present(int nid, unsigned long start, unsigned long end)
ms = __nr_to_section(section);
if (!ms->section_mem_map)
- ms->section_mem_map = SECTION_MARKED_PRESENT;
+ ms->section_mem_map = sparse_encode_early_nid(nid) |
+ SECTION_MARKED_PRESENT;
}
}
@@ -164,6 +181,7 @@ static int sparse_init_one_section(struct mem_section *ms,
if (!valid_section(ms))
return -EINVAL;
+ ms->section_mem_map &= ~SECTION_MAP_MASK;
ms->section_mem_map |= sparse_encode_mem_map(mem_map, pnum);
return 1;
@@ -172,8 +190,8 @@ static int sparse_init_one_section(struct mem_section *ms,
static struct page *sparse_early_mem_map_alloc(unsigned long pnum)
{
struct page *map;
- int nid = early_pfn_to_nid(section_nr_to_pfn(pnum));
struct mem_section *ms = __nr_to_section(pnum);
+ int nid = sparse_early_nid(ms);
map = alloc_remap(nid, sizeof(struct page) * PAGES_PER_SECTION);
if (map)
diff --git a/mm/swap.c b/mm/swap.c
index 88895c2..03ae207 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -480,48 +480,6 @@ static int cpu_swap_callback(struct notifier_block *nfb,
#endif /* CONFIG_HOTPLUG_CPU */
#endif /* CONFIG_SMP */
-#ifdef CONFIG_SMP
-void percpu_counter_mod(struct percpu_counter *fbc, long amount)
-{
- long count;
- long *pcount;
- int cpu = get_cpu();
-
- pcount = per_cpu_ptr(fbc->counters, cpu);
- count = *pcount + amount;
- if (count >= FBC_BATCH || count <= -FBC_BATCH) {
- spin_lock(&fbc->lock);
- fbc->count += count;
- *pcount = 0;
- spin_unlock(&fbc->lock);
- } else {
- *pcount = count;
- }
- put_cpu();
-}
-EXPORT_SYMBOL(percpu_counter_mod);
-
-/*
- * Add up all the per-cpu counts, return the result. This is a more accurate
- * but much slower version of percpu_counter_read_positive()
- */
-long percpu_counter_sum(struct percpu_counter *fbc)
-{
- long ret;
- int cpu;
-
- spin_lock(&fbc->lock);
- ret = fbc->count;
- for_each_possible_cpu(cpu) {
- long *pcount = per_cpu_ptr(fbc->counters, cpu);
- ret += *pcount;
- }
- spin_unlock(&fbc->lock);
- return ret < 0 ? 0 : ret;
-}
-EXPORT_SYMBOL(percpu_counter_sum);
-#endif
-
/*
* Perform any setup for the swap system
*/
diff --git a/mm/swapfile.c b/mm/swapfile.c
index e5fd538..cc367f7 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -395,6 +395,9 @@ void free_swap_and_cache(swp_entry_t entry)
struct swap_info_struct * p;
struct page *page = NULL;
+ if (is_migration_entry(entry))
+ return;
+
p = swap_info_get(entry);
if (p) {
if (swap_entry_free(p, swp_offset(entry)) == 1) {
@@ -615,15 +618,6 @@ static int unuse_mm(struct mm_struct *mm,
return 0;
}
-#ifdef CONFIG_MIGRATION
-int remove_vma_swap(struct vm_area_struct *vma, struct page *page)
-{
- swp_entry_t entry = { .val = page_private(page) };
-
- return unuse_vma(vma, entry, page);
-}
-#endif
-
/*
* Scan swap_map from current position to next entry still in use.
* Recycle to start on reaching the end, returning 0 when empty.
@@ -716,7 +710,6 @@ static int try_to_unuse(unsigned int type)
*/
swap_map = &si->swap_map[i];
entry = swp_entry(type, i);
-again:
page = read_swap_cache_async(entry, NULL, 0);
if (!page) {
/*
@@ -751,12 +744,6 @@ again:
wait_on_page_locked(page);
wait_on_page_writeback(page);
lock_page(page);
- if (!PageSwapCache(page)) {
- /* Page migration has occured */
- unlock_page(page);
- page_cache_release(page);
- goto again;
- }
wait_on_page_writeback(page);
/*
@@ -785,10 +772,8 @@ again:
while (*swap_map > 1 && !retval &&
(p = p->next) != &start_mm->mmlist) {
mm = list_entry(p, struct mm_struct, mmlist);
- if (atomic_inc_return(&mm->mm_users) == 1) {
- atomic_dec(&mm->mm_users);
+ if (!atomic_inc_not_zero(&mm->mm_users))
continue;
- }
spin_unlock(&mmlist_lock);
mmput(prev_mm);
prev_mm = mm;
@@ -1407,19 +1392,7 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
if (!(p->flags & SWP_USED))
break;
error = -EPERM;
- /*
- * Test if adding another swap device is possible. There are
- * two limiting factors: 1) the number of bits for the swap
- * type swp_entry_t definition and 2) the number of bits for
- * the swap type in the swap ptes as defined by the different
- * architectures. To honor both limitations a swap entry
- * with swap offset 0 and swap type ~0UL is created, encoded
- * to a swap pte, decoded to a swp_entry_t again and finally
- * the swap type part is extracted. This will mask all bits
- * from the initial ~0UL that can't be encoded in either the
- * swp_entry_t or the architecture definition of a swap pte.
- */
- if (type > swp_type(pte_to_swp_entry(swp_entry_to_pte(swp_entry(~0UL,0))))) {
+ if (type >= MAX_SWAPFILES) {
spin_unlock(&swap_lock);
goto out;
}
@@ -1504,8 +1477,7 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
error = -EINVAL;
goto bad_swap;
}
- page = read_cache_page(mapping, 0,
- (filler_t *)mapping->a_ops->readpage, swap_file);
+ page = read_mapping_page(mapping, 0, swap_file);
if (IS_ERR(page)) {
error = PTR_ERR(page);
goto bad_swap;
@@ -1709,6 +1681,9 @@ int swap_duplicate(swp_entry_t entry)
unsigned long offset, type;
int result = 0;
+ if (is_migration_entry(entry))
+ return 1;
+
type = swp_type(entry);
if (type >= nr_swapfiles)
goto bad_file;
diff --git a/mm/truncate.c b/mm/truncate.c
index 6cb3fff..cf1b015 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -230,14 +230,24 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,
pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) {
for (i = 0; i < pagevec_count(&pvec); i++) {
struct page *page = pvec.pages[i];
+ pgoff_t index;
+ int lock_failed;
- if (TestSetPageLocked(page)) {
- next++;
- continue;
- }
- if (page->index > next)
- next = page->index;
+ lock_failed = TestSetPageLocked(page);
+
+ /*
+ * We really shouldn't be looking at the ->index of an
+ * unlocked page. But we're not allowed to lock these
+ * pages. So we rely upon nobody altering the ->index
+ * of this (pinned-by-us) page.
+ */
+ index = page->index;
+ if (index > next)
+ next = index;
next++;
+ if (lock_failed)
+ continue;
+
if (PageDirty(page) || PageWriteback(page))
goto unlock;
if (page_mapped(page))
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index c0504f1..35f8553 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -257,6 +257,19 @@ struct vm_struct *get_vm_area_node(unsigned long size, unsigned long flags, int
}
/* Caller must hold vmlist_lock */
+static struct vm_struct *__find_vm_area(void *addr)
+{
+ struct vm_struct *tmp;
+
+ for (tmp = vmlist; tmp != NULL; tmp = tmp->next) {
+ if (tmp->addr == addr)
+ break;
+ }
+
+ return tmp;
+}
+
+/* Caller must hold vmlist_lock */
struct vm_struct *__remove_vm_area(void *addr)
{
struct vm_struct **p, *tmp;
@@ -498,11 +511,33 @@ EXPORT_SYMBOL(__vmalloc);
*/
void *vmalloc(unsigned long size)
{
- return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL);
+ return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL);
}
EXPORT_SYMBOL(vmalloc);
/**
+ * vmalloc_user - allocate virtually contiguous memory which has
+ * been zeroed so it can be mapped to userspace without
+ * leaking data.
+ *
+ * @size: allocation size
+ */
+void *vmalloc_user(unsigned long size)
+{
+ struct vm_struct *area;
+ void *ret;
+
+ ret = __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL);
+ write_lock(&vmlist_lock);
+ area = __find_vm_area(ret);
+ area->flags |= VM_USERMAP;
+ write_unlock(&vmlist_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(vmalloc_user);
+
+/**
* vmalloc_node - allocate memory on a specific node
*
* @size: allocation size
@@ -516,7 +551,7 @@ EXPORT_SYMBOL(vmalloc);
*/
void *vmalloc_node(unsigned long size, int node)
{
- return __vmalloc_node(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL, node);
+ return __vmalloc_node(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL, node);
}
EXPORT_SYMBOL(vmalloc_node);
@@ -556,6 +591,28 @@ void *vmalloc_32(unsigned long size)
}
EXPORT_SYMBOL(vmalloc_32);
+/**
+ * vmalloc_32_user - allocate virtually contiguous memory (32bit
+ * addressable) which is zeroed so it can be
+ * mapped to userspace without leaking data.
+ *
+ * @size: allocation size
+ */
+void *vmalloc_32_user(unsigned long size)
+{
+ struct vm_struct *area;
+ void *ret;
+
+ ret = __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+ write_lock(&vmlist_lock);
+ area = __find_vm_area(ret);
+ area->flags |= VM_USERMAP;
+ write_unlock(&vmlist_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(vmalloc_32_user);
+
long vread(char *buf, char *addr, unsigned long count)
{
struct vm_struct *tmp;
@@ -630,3 +687,64 @@ finished:
read_unlock(&vmlist_lock);
return buf - buf_start;
}
+
+/**
+ * remap_vmalloc_range - map vmalloc pages to userspace
+ *
+ * @vma: vma to cover (map full range of vma)
+ * @addr: vmalloc memory
+ * @pgoff: number of pages into addr before first page to map
+ * @returns: 0 for success, -Exxx on failure
+ *
+ * This function checks that addr is a valid vmalloc'ed area, and
+ * that it is big enough to cover the vma. Will return failure if
+ * that criteria isn't met.
+ *
+ * Similar to remap_pfn_range (see mm/memory.c)
+ */
+int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
+ unsigned long pgoff)
+{
+ struct vm_struct *area;
+ unsigned long uaddr = vma->vm_start;
+ unsigned long usize = vma->vm_end - vma->vm_start;
+ int ret;
+
+ if ((PAGE_SIZE-1) & (unsigned long)addr)
+ return -EINVAL;
+
+ read_lock(&vmlist_lock);
+ area = __find_vm_area(addr);
+ if (!area)
+ goto out_einval_locked;
+
+ if (!(area->flags & VM_USERMAP))
+ goto out_einval_locked;
+
+ if (usize + (pgoff << PAGE_SHIFT) > area->size - PAGE_SIZE)
+ goto out_einval_locked;
+ read_unlock(&vmlist_lock);
+
+ addr += pgoff << PAGE_SHIFT;
+ do {
+ struct page *page = vmalloc_to_page(addr);
+ ret = vm_insert_page(vma, uaddr, page);
+ if (ret)
+ return ret;
+
+ uaddr += PAGE_SIZE;
+ addr += PAGE_SIZE;
+ usize -= PAGE_SIZE;
+ } while (usize > 0);
+
+ /* Prevent "things" like memory migration? VM_flags need a cleanup... */
+ vma->vm_flags |= VM_RESERVED;
+
+ return ret;
+
+out_einval_locked:
+ read_unlock(&vmlist_lock);
+ return -EINVAL;
+}
+EXPORT_SYMBOL(remap_vmalloc_range);
+
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 440a733..72babac 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -61,6 +61,8 @@ struct scan_control {
* In this context, it doesn't matter that we scan the
* whole list at once. */
int swap_cluster_max;
+
+ int swappiness;
};
/*
@@ -108,7 +110,7 @@ struct shrinker {
* From 0 .. 100. Higher means more swappy.
*/
int vm_swappiness = 60;
-static long total_memory;
+long vm_total_pages; /* The total number of pages which the VM controls */
static LIST_HEAD(shrinker_list);
static DECLARE_RWSEM(shrinker_rwsem);
@@ -288,11 +290,23 @@ static void handle_write_error(struct address_space *mapping,
unlock_page(page);
}
+/* possible outcome of pageout() */
+typedef enum {
+ /* failed to write page out, page is locked */
+ PAGE_KEEP,
+ /* move page to the active list, page is locked */
+ PAGE_ACTIVATE,
+ /* page has been sent to the disk successfully, page is unlocked */
+ PAGE_SUCCESS,
+ /* page is clean and locked */
+ PAGE_CLEAN,
+} pageout_t;
+
/*
* pageout is called by shrink_page_list() for each dirty page.
* Calls ->writepage().
*/
-pageout_t pageout(struct page *page, struct address_space *mapping)
+static pageout_t pageout(struct page *page, struct address_space *mapping)
{
/*
* If the page is dirty, only perform writeback if that write
@@ -337,6 +351,8 @@ pageout_t pageout(struct page *page, struct address_space *mapping)
struct writeback_control wbc = {
.sync_mode = WB_SYNC_NONE,
.nr_to_write = SWAP_CLUSTER_MAX,
+ .range_start = 0,
+ .range_end = LLONG_MAX,
.nonblocking = 1,
.for_reclaim = 1,
};
@@ -727,7 +743,7 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
* how much memory
* is mapped.
*/
- mapped_ratio = (sc->nr_mapped * 100) / total_memory;
+ mapped_ratio = (sc->nr_mapped * 100) / vm_total_pages;
/*
* Now decide how much we really want to unmap some pages. The
@@ -741,7 +757,7 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
* A 100% value of vm_swappiness overrides this algorithm
* altogether.
*/
- swap_tendency = mapped_ratio / 2 + distress + vm_swappiness;
+ swap_tendency = mapped_ratio / 2 + distress + sc->swappiness;
/*
* Now use this metric to decide whether to start moving mapped
@@ -957,6 +973,7 @@ unsigned long try_to_free_pages(struct zone **zones, gfp_t gfp_mask)
.may_writepage = !laptop_mode,
.swap_cluster_max = SWAP_CLUSTER_MAX,
.may_swap = 1,
+ .swappiness = vm_swappiness,
};
inc_page_state(allocstall);
@@ -1021,10 +1038,6 @@ out:
* For kswapd, balance_pgdat() will work across all this node's zones until
* they are all at pages_high.
*
- * If `nr_pages' is non-zero then it is the number of pages which are to be
- * reclaimed, regardless of the zone occupancies. This is a software suspend
- * special.
- *
* Returns the number of pages which were actually freed.
*
* There is special handling here for zones which are full of pinned pages.
@@ -1042,10 +1055,8 @@ out:
* the page allocator fallback scheme to ensure that aging of pages is balanced
* across the zones.
*/
-static unsigned long balance_pgdat(pg_data_t *pgdat, unsigned long nr_pages,
- int order)
+static unsigned long balance_pgdat(pg_data_t *pgdat, int order)
{
- unsigned long to_free = nr_pages;
int all_zones_ok;
int priority;
int i;
@@ -1055,7 +1066,8 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, unsigned long nr_pages,
struct scan_control sc = {
.gfp_mask = GFP_KERNEL,
.may_swap = 1,
- .swap_cluster_max = nr_pages ? nr_pages : SWAP_CLUSTER_MAX,
+ .swap_cluster_max = SWAP_CLUSTER_MAX,
+ .swappiness = vm_swappiness,
};
loop_again:
@@ -1082,31 +1094,26 @@ loop_again:
all_zones_ok = 1;
- if (nr_pages == 0) {
- /*
- * Scan in the highmem->dma direction for the highest
- * zone which needs scanning
- */
- for (i = pgdat->nr_zones - 1; i >= 0; i--) {
- struct zone *zone = pgdat->node_zones + i;
+ /*
+ * Scan in the highmem->dma direction for the highest
+ * zone which needs scanning
+ */
+ for (i = pgdat->nr_zones - 1; i >= 0; i--) {
+ struct zone *zone = pgdat->node_zones + i;
- if (!populated_zone(zone))
- continue;
+ if (!populated_zone(zone))
+ continue;
- if (zone->all_unreclaimable &&
- priority != DEF_PRIORITY)
- continue;
+ if (zone->all_unreclaimable && priority != DEF_PRIORITY)
+ continue;
- if (!zone_watermark_ok(zone, order,
- zone->pages_high, 0, 0)) {
- end_zone = i;
- goto scan;
- }
+ if (!zone_watermark_ok(zone, order, zone->pages_high,
+ 0, 0)) {
+ end_zone = i;
+ goto scan;
}
- goto out;
- } else {
- end_zone = pgdat->nr_zones - 1;
}
+ goto out;
scan:
for (i = 0; i <= end_zone; i++) {
struct zone *zone = pgdat->node_zones + i;
@@ -1133,11 +1140,9 @@ scan:
if (zone->all_unreclaimable && priority != DEF_PRIORITY)
continue;
- if (nr_pages == 0) { /* Not software suspend */
- if (!zone_watermark_ok(zone, order,
- zone->pages_high, end_zone, 0))
- all_zones_ok = 0;
- }
+ if (!zone_watermark_ok(zone, order, zone->pages_high,
+ end_zone, 0))
+ all_zones_ok = 0;
zone->temp_priority = priority;
if (zone->prev_priority > priority)
zone->prev_priority = priority;
@@ -1162,8 +1167,6 @@ scan:
total_scanned > nr_reclaimed + nr_reclaimed / 2)
sc.may_writepage = 1;
}
- if (nr_pages && to_free > nr_reclaimed)
- continue; /* swsusp: need to do more work */
if (all_zones_ok)
break; /* kswapd: all done */
/*
@@ -1179,7 +1182,7 @@ scan:
* matches the direct reclaim path behaviour in terms of impact
* on zone->*_priority.
*/
- if ((nr_reclaimed >= SWAP_CLUSTER_MAX) && !nr_pages)
+ if (nr_reclaimed >= SWAP_CLUSTER_MAX)
break;
}
out:
@@ -1261,7 +1264,7 @@ static int kswapd(void *p)
}
finish_wait(&pgdat->kswapd_wait, &wait);
- balance_pgdat(pgdat, 0, order);
+ balance_pgdat(pgdat, order);
}
return 0;
}
@@ -1290,35 +1293,154 @@ void wakeup_kswapd(struct zone *zone, int order)
#ifdef CONFIG_PM
/*
- * Try to free `nr_pages' of memory, system-wide. Returns the number of freed
- * pages.
+ * Helper function for shrink_all_memory(). Tries to reclaim 'nr_pages' pages
+ * from LRU lists system-wide, for given pass and priority, and returns the
+ * number of reclaimed pages
+ *
+ * For pass > 3 we also try to shrink the LRU lists that contain a few pages
+ */
+static unsigned long shrink_all_zones(unsigned long nr_pages, int pass,
+ int prio, struct scan_control *sc)
+{
+ struct zone *zone;
+ unsigned long nr_to_scan, ret = 0;
+
+ for_each_zone(zone) {
+
+ if (!populated_zone(zone))
+ continue;
+
+ if (zone->all_unreclaimable && prio != DEF_PRIORITY)
+ continue;
+
+ /* For pass = 0 we don't shrink the active list */
+ if (pass > 0) {
+ zone->nr_scan_active += (zone->nr_active >> prio) + 1;
+ if (zone->nr_scan_active >= nr_pages || pass > 3) {
+ zone->nr_scan_active = 0;
+ nr_to_scan = min(nr_pages, zone->nr_active);
+ shrink_active_list(nr_to_scan, zone, sc);
+ }
+ }
+
+ zone->nr_scan_inactive += (zone->nr_inactive >> prio) + 1;
+ if (zone->nr_scan_inactive >= nr_pages || pass > 3) {
+ zone->nr_scan_inactive = 0;
+ nr_to_scan = min(nr_pages, zone->nr_inactive);
+ ret += shrink_inactive_list(nr_to_scan, zone, sc);
+ if (ret >= nr_pages)
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Try to free `nr_pages' of memory, system-wide, and return the number of
+ * freed pages.
+ *
+ * Rather than trying to age LRUs the aim is to preserve the overall
+ * LRU order by reclaiming preferentially
+ * inactive > active > active referenced > active mapped
*/
unsigned long shrink_all_memory(unsigned long nr_pages)
{
- pg_data_t *pgdat;
- unsigned long nr_to_free = nr_pages;
+ unsigned long lru_pages, nr_slab;
unsigned long ret = 0;
- unsigned retry = 2;
- struct reclaim_state reclaim_state = {
- .reclaimed_slab = 0,
+ int pass;
+ struct reclaim_state reclaim_state;
+ struct zone *zone;
+ struct scan_control sc = {
+ .gfp_mask = GFP_KERNEL,
+ .may_swap = 0,
+ .swap_cluster_max = nr_pages,
+ .may_writepage = 1,
+ .swappiness = vm_swappiness,
};
current->reclaim_state = &reclaim_state;
-repeat:
- for_each_online_pgdat(pgdat) {
- unsigned long freed;
- freed = balance_pgdat(pgdat, nr_to_free, 0);
- ret += freed;
- nr_to_free -= freed;
- if ((long)nr_to_free <= 0)
+ lru_pages = 0;
+ for_each_zone(zone)
+ lru_pages += zone->nr_active + zone->nr_inactive;
+
+ nr_slab = read_page_state(nr_slab);
+ /* If slab caches are huge, it's better to hit them first */
+ while (nr_slab >= lru_pages) {
+ reclaim_state.reclaimed_slab = 0;
+ shrink_slab(nr_pages, sc.gfp_mask, lru_pages);
+ if (!reclaim_state.reclaimed_slab)
break;
+
+ ret += reclaim_state.reclaimed_slab;
+ if (ret >= nr_pages)
+ goto out;
+
+ nr_slab -= reclaim_state.reclaimed_slab;
}
- if (retry-- && ret < nr_pages) {
- blk_congestion_wait(WRITE, HZ/5);
- goto repeat;
+
+ /*
+ * We try to shrink LRUs in 5 passes:
+ * 0 = Reclaim from inactive_list only
+ * 1 = Reclaim from active list but don't reclaim mapped
+ * 2 = 2nd pass of type 1
+ * 3 = Reclaim mapped (normal reclaim)
+ * 4 = 2nd pass of type 3
+ */
+ for (pass = 0; pass < 5; pass++) {
+ int prio;
+
+ /* Needed for shrinking slab caches later on */
+ if (!lru_pages)
+ for_each_zone(zone) {
+ lru_pages += zone->nr_active;
+ lru_pages += zone->nr_inactive;
+ }
+
+ /* Force reclaiming mapped pages in the passes #3 and #4 */
+ if (pass > 2) {
+ sc.may_swap = 1;
+ sc.swappiness = 100;
+ }
+
+ for (prio = DEF_PRIORITY; prio >= 0; prio--) {
+ unsigned long nr_to_scan = nr_pages - ret;
+
+ sc.nr_mapped = read_page_state(nr_mapped);
+ sc.nr_scanned = 0;
+
+ ret += shrink_all_zones(nr_to_scan, prio, pass, &sc);
+ if (ret >= nr_pages)
+ goto out;
+
+ reclaim_state.reclaimed_slab = 0;
+ shrink_slab(sc.nr_scanned, sc.gfp_mask, lru_pages);
+ ret += reclaim_state.reclaimed_slab;
+ if (ret >= nr_pages)
+ goto out;
+
+ if (sc.nr_scanned && prio < DEF_PRIORITY - 2)
+ blk_congestion_wait(WRITE, HZ / 10);
+ }
+
+ lru_pages = 0;
}
+
+ /*
+ * If ret = 0, we could not shrink LRUs, but there may be something
+ * in slab caches
+ */
+ if (!ret)
+ do {
+ reclaim_state.reclaimed_slab = 0;
+ shrink_slab(nr_pages, sc.gfp_mask, lru_pages);
+ ret += reclaim_state.reclaimed_slab;
+ } while (ret < nr_pages && reclaim_state.reclaimed_slab > 0);
+
+out:
current->reclaim_state = NULL;
+
return ret;
}
#endif
@@ -1360,7 +1482,6 @@ static int __init kswapd_init(void)
pgdat->kswapd = find_task_by_pid(pid);
read_unlock(&tasklist_lock);
}
- total_memory = nr_free_pagecache_pages();
hotcpu_notifier(cpu_callback, 0);
return 0;
}
@@ -1416,6 +1537,7 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
.swap_cluster_max = max_t(unsigned long, nr_pages,
SWAP_CLUSTER_MAX),
.gfp_mask = gfp_mask,
+ .swappiness = vm_swappiness,
};
disable_swap_token();
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 0dca027..8be9f21 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -34,8 +34,8 @@ static inline unsigned packet_length(const struct sk_buff *skb)
int br_dev_queue_push_xmit(struct sk_buff *skb)
{
- /* drop mtu oversized packets except tso */
- if (packet_length(skb) > skb->dev->mtu && !skb_shinfo(skb)->tso_size)
+ /* drop mtu oversized packets except gso */
+ if (packet_length(skb) > skb->dev->mtu && !skb_shinfo(skb)->gso_size)
kfree_skb(skb);
else {
#ifdef CONFIG_BRIDGE_NETFILTER
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index fdec773..07956ec 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -376,15 +376,20 @@ void br_features_recompute(struct net_bridge *br)
features = br->feature_mask & ~NETIF_F_ALL_CSUM;
list_for_each_entry(p, &br->port_list, list) {
- if (checksum & NETIF_F_NO_CSUM &&
- !(p->dev->features & NETIF_F_NO_CSUM))
+ unsigned long feature = p->dev->features;
+
+ if (checksum & NETIF_F_NO_CSUM && !(feature & NETIF_F_NO_CSUM))
checksum ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM;
- if (checksum & NETIF_F_HW_CSUM &&
- !(p->dev->features & NETIF_F_HW_CSUM))
+ if (checksum & NETIF_F_HW_CSUM && !(feature & NETIF_F_HW_CSUM))
checksum ^= NETIF_F_HW_CSUM | NETIF_F_IP_CSUM;
- if (!(p->dev->features & NETIF_F_IP_CSUM))
+ if (!(feature & NETIF_F_IP_CSUM))
checksum = 0;
- features &= p->dev->features;
+
+ if (feature & NETIF_F_GSO)
+ feature |= NETIF_F_TSO;
+ feature |= NETIF_F_GSO;
+
+ features &= feature;
}
br->dev->features = features | checksum | NETIF_F_LLTX;
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 3e41f9d..8298a51 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -761,7 +761,7 @@ static int br_nf_dev_queue_xmit(struct sk_buff *skb)
{
if (skb->protocol == htons(ETH_P_IP) &&
skb->len > skb->dev->mtu &&
- !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
+ !skb_shinfo(skb)->gso_size)
return ip_fragment(skb, br_dev_queue_push_xmit);
else
return br_dev_queue_push_xmit(skb);
diff --git a/net/core/dev.c b/net/core/dev.c
index ab39fe1..ea24693 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -116,6 +116,7 @@
#include <asm/current.h>
#include <linux/audit.h>
#include <linux/dmaengine.h>
+#include <linux/err.h>
/*
* The list of packet types we will receive (as opposed to discard)
@@ -1048,7 +1049,7 @@ static inline void net_timestamp(struct sk_buff *skb)
* taps currently in use.
*/
-void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
+static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
{
struct packet_type *ptype;
@@ -1186,6 +1187,40 @@ out:
return ret;
}
+/**
+ * skb_gso_segment - Perform segmentation on skb.
+ * @skb: buffer to segment
+ * @sg: whether scatter-gather is supported on the target.
+ *
+ * This function segments the given skb and returns a list of segments.
+ */
+struct sk_buff *skb_gso_segment(struct sk_buff *skb, int sg)
+{
+ struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
+ struct packet_type *ptype;
+ int type = skb->protocol;
+
+ BUG_ON(skb_shinfo(skb)->frag_list);
+ BUG_ON(skb->ip_summed != CHECKSUM_HW);
+
+ skb->mac.raw = skb->data;
+ skb->mac_len = skb->nh.raw - skb->data;
+ __skb_pull(skb, skb->mac_len);
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) {
+ if (ptype->type == type && !ptype->dev && ptype->gso_segment) {
+ segs = ptype->gso_segment(skb, sg);
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+ return segs;
+}
+
+EXPORT_SYMBOL(skb_gso_segment);
+
/* Take action when hardware reception checksum errors are detected. */
#ifdef CONFIG_BUG
void netdev_rx_csum_fault(struct net_device *dev)
@@ -1222,6 +1257,86 @@ static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
#define illegal_highdma(dev, skb) (0)
#endif
+struct dev_gso_cb {
+ void (*destructor)(struct sk_buff *skb);
+};
+
+#define DEV_GSO_CB(skb) ((struct dev_gso_cb *)(skb)->cb)
+
+static void dev_gso_skb_destructor(struct sk_buff *skb)
+{
+ struct dev_gso_cb *cb;
+
+ do {
+ struct sk_buff *nskb = skb->next;
+
+ skb->next = nskb->next;
+ nskb->next = NULL;
+ kfree_skb(nskb);
+ } while (skb->next);
+
+ cb = DEV_GSO_CB(skb);
+ if (cb->destructor)
+ cb->destructor(skb);
+}
+
+/**
+ * dev_gso_segment - Perform emulated hardware segmentation on skb.
+ * @skb: buffer to segment
+ *
+ * This function segments the given skb and stores the list of segments
+ * in skb->next.
+ */
+static int dev_gso_segment(struct sk_buff *skb)
+{
+ struct net_device *dev = skb->dev;
+ struct sk_buff *segs;
+
+ segs = skb_gso_segment(skb, dev->features & NETIF_F_SG &&
+ !illegal_highdma(dev, skb));
+ if (unlikely(IS_ERR(segs)))
+ return PTR_ERR(segs);
+
+ skb->next = segs;
+ DEV_GSO_CB(skb)->destructor = skb->destructor;
+ skb->destructor = dev_gso_skb_destructor;
+
+ return 0;
+}
+
+int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ if (likely(!skb->next)) {
+ if (netdev_nit)
+ dev_queue_xmit_nit(skb, dev);
+
+ if (!netif_needs_gso(dev, skb))
+ return dev->hard_start_xmit(skb, dev);
+
+ if (unlikely(dev_gso_segment(skb)))
+ goto out_kfree_skb;
+ }
+
+ do {
+ struct sk_buff *nskb = skb->next;
+ int rc;
+
+ skb->next = nskb->next;
+ nskb->next = NULL;
+ rc = dev->hard_start_xmit(nskb, dev);
+ if (unlikely(rc)) {
+ skb->next = nskb;
+ return rc;
+ }
+ } while (skb->next);
+
+ skb->destructor = DEV_GSO_CB(skb)->destructor;
+
+out_kfree_skb:
+ kfree_skb(skb);
+ return 0;
+}
+
#define HARD_TX_LOCK(dev, cpu) { \
if ((dev->features & NETIF_F_LLTX) == 0) { \
netif_tx_lock(dev); \
@@ -1266,6 +1381,10 @@ int dev_queue_xmit(struct sk_buff *skb)
struct Qdisc *q;
int rc = -ENOMEM;
+ /* GSO will handle the following emulations directly. */
+ if (netif_needs_gso(dev, skb))
+ goto gso;
+
if (skb_shinfo(skb)->frag_list &&
!(dev->features & NETIF_F_FRAGLIST) &&
__skb_linearize(skb))
@@ -1290,12 +1409,13 @@ int dev_queue_xmit(struct sk_buff *skb)
if (skb_checksum_help(skb, 0))
goto out_kfree_skb;
+gso:
spin_lock_prefetch(&dev->queue_lock);
/* Disable soft irqs for various locks below. Also
* stops preemption for RCU.
*/
- local_bh_disable();
+ rcu_read_lock_bh();
/* Updates of qdisc are serialized by queue_lock.
* The struct Qdisc which is pointed to by qdisc is now a
@@ -1346,11 +1466,8 @@ int dev_queue_xmit(struct sk_buff *skb)
HARD_TX_LOCK(dev, cpu);
if (!netif_queue_stopped(dev)) {
- if (netdev_nit)
- dev_queue_xmit_nit(skb, dev);
-
rc = 0;
- if (!dev->hard_start_xmit(skb, dev)) {
+ if (!dev_hard_start_xmit(skb, dev)) {
HARD_TX_UNLOCK(dev);
goto out;
}
@@ -1369,13 +1486,13 @@ int dev_queue_xmit(struct sk_buff *skb)
}
rc = -ENETDOWN;
- local_bh_enable();
+ rcu_read_unlock_bh();
out_kfree_skb:
kfree_skb(skb);
return rc;
out:
- local_bh_enable();
+ rcu_read_unlock_bh();
return rc;
}
@@ -2980,7 +3097,7 @@ static void netdev_wait_allrefs(struct net_device *dev)
static DEFINE_MUTEX(net_todo_run_mutex);
void netdev_run_todo(void)
{
- struct list_head list = LIST_HEAD_INIT(list);
+ struct list_head list;
/* Need to guard against multiple cpu's getting out of order. */
mutex_lock(&net_todo_run_mutex);
@@ -2995,9 +3112,9 @@ void netdev_run_todo(void)
/* Snapshot list, allow later requests */
spin_lock(&net_todo_list_lock);
- list_splice_init(&net_todo_list, &list);
+ list_replace_init(&net_todo_list, &list);
spin_unlock(&net_todo_list_lock);
-
+
while (!list_empty(&list)) {
struct net_device *dev
= list_entry(list.next, struct net_device, todo_list);
@@ -3301,8 +3418,8 @@ static void net_dma_rebalance(void)
/**
* netdev_dma_event - event callback for the net_dma_client
* @client: should always be net_dma_client
- * @chan:
- * @event:
+ * @chan: DMA channel for the event
+ * @event: event type
*/
static void netdev_dma_event(struct dma_client *client, struct dma_chan *chan,
enum dma_event event)
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 33ce7ed..27ce168 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -614,6 +614,29 @@ static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr)
return dev->ethtool_ops->set_ufo(dev, edata.data);
}
+static int ethtool_get_gso(struct net_device *dev, char __user *useraddr)
+{
+ struct ethtool_value edata = { ETHTOOL_GGSO };
+
+ edata.data = dev->features & NETIF_F_GSO;
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ return 0;
+}
+
+static int ethtool_set_gso(struct net_device *dev, char __user *useraddr)
+{
+ struct ethtool_value edata;
+
+ if (copy_from_user(&edata, useraddr, sizeof(edata)))
+ return -EFAULT;
+ if (edata.data)
+ dev->features |= NETIF_F_GSO;
+ else
+ dev->features &= ~NETIF_F_GSO;
+ return 0;
+}
+
static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
{
struct ethtool_test test;
@@ -905,6 +928,12 @@ int dev_ethtool(struct ifreq *ifr)
case ETHTOOL_SUFO:
rc = ethtool_set_ufo(dev, useraddr);
break;
+ case ETHTOOL_GGSO:
+ rc = ethtool_get_gso(dev, useraddr);
+ break;
+ case ETHTOOL_SGSO:
+ rc = ethtool_set_gso(dev, useraddr);
+ break;
default:
rc = -EOPNOTSUPP;
}
diff --git a/net/core/link_watch.c b/net/core/link_watch.c
index 646937c..0f37266 100644
--- a/net/core/link_watch.c
+++ b/net/core/link_watch.c
@@ -91,11 +91,10 @@ static void rfc2863_policy(struct net_device *dev)
/* Must be called with the rtnl semaphore held */
void linkwatch_run_queue(void)
{
- LIST_HEAD(head);
- struct list_head *n, *next;
+ struct list_head head, *n, *next;
spin_lock_irq(&lweventlist_lock);
- list_splice_init(&lweventlist, &head);
+ list_replace_init(&lweventlist, &head);
spin_unlock_irq(&lweventlist_lock);
list_for_each_safe(n, next, &head) {
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index bb7210f..8e5044b 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -172,9 +172,9 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
shinfo = skb_shinfo(skb);
atomic_set(&shinfo->dataref, 1);
shinfo->nr_frags = 0;
- shinfo->tso_size = 0;
- shinfo->tso_segs = 0;
- shinfo->ufo_size = 0;
+ shinfo->gso_size = 0;
+ shinfo->gso_segs = 0;
+ shinfo->gso_type = 0;
shinfo->ip6_frag_id = 0;
shinfo->frag_list = NULL;
@@ -238,8 +238,9 @@ struct sk_buff *alloc_skb_from_cache(kmem_cache_t *cp,
atomic_set(&(skb_shinfo(skb)->dataref), 1);
skb_shinfo(skb)->nr_frags = 0;
- skb_shinfo(skb)->tso_size = 0;
- skb_shinfo(skb)->tso_segs = 0;
+ skb_shinfo(skb)->gso_size = 0;
+ skb_shinfo(skb)->gso_segs = 0;
+ skb_shinfo(skb)->gso_type = 0;
skb_shinfo(skb)->frag_list = NULL;
out:
return skb;
@@ -528,8 +529,9 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
#endif
skb_copy_secmark(new, old);
atomic_set(&new->users, 1);
- skb_shinfo(new)->tso_size = skb_shinfo(old)->tso_size;
- skb_shinfo(new)->tso_segs = skb_shinfo(old)->tso_segs;
+ skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size;
+ skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs;
+ skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type;
}
/**
@@ -781,24 +783,40 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
* filled. Used by network drivers which may DMA or transfer data
* beyond the buffer end onto the wire.
*
- * May return NULL in out of memory cases.
+ * May return error in out of memory cases. The skb is freed on error.
*/
-struct sk_buff *skb_pad(struct sk_buff *skb, int pad)
+int skb_pad(struct sk_buff *skb, int pad)
{
- struct sk_buff *nskb;
+ int err;
+ int ntail;
/* If the skbuff is non linear tailroom is always zero.. */
- if (skb_tailroom(skb) >= pad) {
+ if (!skb_cloned(skb) && skb_tailroom(skb) >= pad) {
memset(skb->data+skb->len, 0, pad);
- return skb;
+ return 0;
}
-
- nskb = skb_copy_expand(skb, skb_headroom(skb), skb_tailroom(skb) + pad, GFP_ATOMIC);
+
+ ntail = skb->data_len + pad - (skb->end - skb->tail);
+ if (likely(skb_cloned(skb) || ntail > 0)) {
+ err = pskb_expand_head(skb, 0, ntail, GFP_ATOMIC);
+ if (unlikely(err))
+ goto free_skb;
+ }
+
+ /* FIXME: The use of this function with non-linear skb's really needs
+ * to be audited.
+ */
+ err = skb_linearize(skb);
+ if (unlikely(err))
+ goto free_skb;
+
+ memset(skb->data + skb->len, 0, pad);
+ return 0;
+
+free_skb:
kfree_skb(skb);
- if (nskb)
- memset(nskb->data+nskb->len, 0, pad);
- return nskb;
+ return err;
}
/* Trims skb to length len. It can change skb pointers.
@@ -1824,6 +1842,132 @@ unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len)
EXPORT_SYMBOL_GPL(skb_pull_rcsum);
+/**
+ * skb_segment - Perform protocol segmentation on skb.
+ * @skb: buffer to segment
+ * @sg: whether scatter-gather can be used for generated segments
+ *
+ * This function performs segmentation on the given skb. It returns
+ * the segment at the given position. It returns NULL if there are
+ * no more segments to generate, or when an error is encountered.
+ */
+struct sk_buff *skb_segment(struct sk_buff *skb, int sg)
+{
+ struct sk_buff *segs = NULL;
+ struct sk_buff *tail = NULL;
+ unsigned int mss = skb_shinfo(skb)->gso_size;
+ unsigned int doffset = skb->data - skb->mac.raw;
+ unsigned int offset = doffset;
+ unsigned int headroom;
+ unsigned int len;
+ int nfrags = skb_shinfo(skb)->nr_frags;
+ int err = -ENOMEM;
+ int i = 0;
+ int pos;
+
+ __skb_push(skb, doffset);
+ headroom = skb_headroom(skb);
+ pos = skb_headlen(skb);
+
+ do {
+ struct sk_buff *nskb;
+ skb_frag_t *frag;
+ int hsize, nsize;
+ int k;
+ int size;
+
+ len = skb->len - offset;
+ if (len > mss)
+ len = mss;
+
+ hsize = skb_headlen(skb) - offset;
+ if (hsize < 0)
+ hsize = 0;
+ nsize = hsize + doffset;
+ if (nsize > len + doffset || !sg)
+ nsize = len + doffset;
+
+ nskb = alloc_skb(nsize + headroom, GFP_ATOMIC);
+ if (unlikely(!nskb))
+ goto err;
+
+ if (segs)
+ tail->next = nskb;
+ else
+ segs = nskb;
+ tail = nskb;
+
+ nskb->dev = skb->dev;
+ nskb->priority = skb->priority;
+ nskb->protocol = skb->protocol;
+ nskb->dst = dst_clone(skb->dst);
+ memcpy(nskb->cb, skb->cb, sizeof(skb->cb));
+ nskb->pkt_type = skb->pkt_type;
+ nskb->mac_len = skb->mac_len;
+
+ skb_reserve(nskb, headroom);
+ nskb->mac.raw = nskb->data;
+ nskb->nh.raw = nskb->data + skb->mac_len;
+ nskb->h.raw = nskb->nh.raw + (skb->h.raw - skb->nh.raw);
+ memcpy(skb_put(nskb, doffset), skb->data, doffset);
+
+ if (!sg) {
+ nskb->csum = skb_copy_and_csum_bits(skb, offset,
+ skb_put(nskb, len),
+ len, 0);
+ continue;
+ }
+
+ frag = skb_shinfo(nskb)->frags;
+ k = 0;
+
+ nskb->ip_summed = CHECKSUM_HW;
+ nskb->csum = skb->csum;
+ memcpy(skb_put(nskb, hsize), skb->data + offset, hsize);
+
+ while (pos < offset + len) {
+ BUG_ON(i >= nfrags);
+
+ *frag = skb_shinfo(skb)->frags[i];
+ get_page(frag->page);
+ size = frag->size;
+
+ if (pos < offset) {
+ frag->page_offset += offset - pos;
+ frag->size -= offset - pos;
+ }
+
+ k++;
+
+ if (pos + size <= offset + len) {
+ i++;
+ pos += size;
+ } else {
+ frag->size -= pos + size - (offset + len);
+ break;
+ }
+
+ frag++;
+ }
+
+ skb_shinfo(nskb)->nr_frags = k;
+ nskb->data_len = len - hsize;
+ nskb->len += nskb->data_len;
+ nskb->truesize += nskb->data_len;
+ } while ((offset += len) < skb->len);
+
+ return segs;
+
+err:
+ while ((skb = segs)) {
+ segs = skb->next;
+ kfree(skb);
+ }
+ return ERR_PTR(err);
+}
+
+EXPORT_SYMBOL_GPL(skb_segment);
+
void __init skb_init(void)
{
skbuff_head_cache = kmem_cache_create("skbuff_head_cache",
diff --git a/net/dccp/Kconfig b/net/dccp/Kconfig
index 7e096ba..859e335 100644
--- a/net/dccp/Kconfig
+++ b/net/dccp/Kconfig
@@ -26,7 +26,7 @@ config INET_DCCP_DIAG
config IP_DCCP_ACKVEC
depends on IP_DCCP
- def_bool N
+ bool
source "net/dccp/ccids/Kconfig"
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
index 22aa619..0e65ff4 100644
--- a/net/ieee80211/softmac/ieee80211softmac_wx.c
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -388,7 +388,7 @@ ieee80211softmac_wx_set_genie(struct net_device *dev,
memcpy(mac->wpa.IE, extra, wrqu->data.length);
dprintk(KERN_INFO PFX "generic IE set to ");
for (i=0;i<wrqu->data.length;i++)
- dprintk("%.2x", mac->wpa.IE[i]);
+ dprintk("%.2x", (u8)mac->wpa.IE[i]);
dprintk("\n");
mac->wpa.IElen = wrqu->data.length;
} else {
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 0a27745..461216b 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -68,6 +68,7 @@
*/
#include <linux/config.h>
+#include <linux/err.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -1096,6 +1097,54 @@ int inet_sk_rebuild_header(struct sock *sk)
EXPORT_SYMBOL(inet_sk_rebuild_header);
+static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int sg)
+{
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+ struct iphdr *iph;
+ struct net_protocol *ops;
+ int proto;
+ int ihl;
+ int id;
+
+ if (!pskb_may_pull(skb, sizeof(*iph)))
+ goto out;
+
+ iph = skb->nh.iph;
+ ihl = iph->ihl * 4;
+ if (ihl < sizeof(*iph))
+ goto out;
+
+ if (!pskb_may_pull(skb, ihl))
+ goto out;
+
+ skb->h.raw = __skb_pull(skb, ihl);
+ iph = skb->nh.iph;
+ id = ntohs(iph->id);
+ proto = iph->protocol & (MAX_INET_PROTOS - 1);
+ segs = ERR_PTR(-EPROTONOSUPPORT);
+
+ rcu_read_lock();
+ ops = rcu_dereference(inet_protos[proto]);
+ if (ops && ops->gso_segment)
+ segs = ops->gso_segment(skb, sg);
+ rcu_read_unlock();
+
+ if (IS_ERR(segs))
+ goto out;
+
+ skb = segs;
+ do {
+ iph = skb->nh.iph;
+ iph->id = htons(id++);
+ iph->tot_len = htons(skb->len - skb->mac_len);
+ iph->check = 0;
+ iph->check = ip_fast_csum(skb->nh.raw, iph->ihl);
+ } while ((skb = skb->next));
+
+out:
+ return segs;
+}
+
#ifdef CONFIG_IP_MULTICAST
static struct net_protocol igmp_protocol = {
.handler = igmp_rcv,
@@ -1105,6 +1154,7 @@ static struct net_protocol igmp_protocol = {
static struct net_protocol tcp_protocol = {
.handler = tcp_v4_rcv,
.err_handler = tcp_v4_err,
+ .gso_segment = tcp_tso_segment,
.no_policy = 1,
};
@@ -1150,6 +1200,7 @@ static int ipv4_proc_init(void);
static struct packet_type ip_packet_type = {
.type = __constant_htons(ETH_P_IP),
.func = ip_rcv,
+ .gso_segment = inet_gso_segment,
};
static int __init inet_init(void)
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 8538aac..7624fd1 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -210,8 +210,7 @@ static inline int ip_finish_output(struct sk_buff *skb)
return dst_output(skb);
}
#endif
- if (skb->len > dst_mtu(skb->dst) &&
- !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
+ if (skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size)
return ip_fragment(skb, ip_finish_output2);
else
return ip_finish_output2(skb);
@@ -362,7 +361,7 @@ packet_routed:
}
ip_select_ident_more(iph, &rt->u.dst, sk,
- (skb_shinfo(skb)->tso_segs ?: 1) - 1);
+ (skb_shinfo(skb)->gso_segs ?: 1) - 1);
/* Add an IP checksum. */
ip_send_check(iph);
@@ -744,7 +743,8 @@ static inline int ip_ufo_append_data(struct sock *sk,
(length - transhdrlen));
if (!err) {
/* specify the length of each IP datagram fragment*/
- skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen);
+ skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
+ skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4;
__skb_queue_tail(&sk->sk_write_queue, skb);
return 0;
@@ -1087,14 +1087,16 @@ ssize_t ip_append_page(struct sock *sk, struct page *page,
inet->cork.length += size;
if ((sk->sk_protocol == IPPROTO_UDP) &&
- (rt->u.dst.dev->features & NETIF_F_UFO))
- skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen);
+ (rt->u.dst.dev->features & NETIF_F_UFO)) {
+ skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
+ skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4;
+ }
while (size > 0) {
int i;
- if (skb_shinfo(skb)->ufo_size)
+ if (skb_shinfo(skb)->gso_size)
len = size;
else {
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index cee3397..706c002 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -1761,7 +1761,7 @@ translate_compat_table(const char *name,
goto free_newinfo;
/* And one copy for every other CPU */
- for_each_cpu(i)
+ for_each_possible_cpu(i)
if (newinfo->entries[i] && newinfo->entries[i] != entry1)
memcpy(newinfo->entries[i], entry1, newinfo->size);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index cc9423d..60b11ae 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -244,7 +244,7 @@ static unsigned int rt_hash_rnd;
static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat);
#define RT_CACHE_STAT_INC(field) \
- (per_cpu(rt_cache_stat, raw_smp_processor_id()).field++)
+ (__raw_get_cpu_var(rt_cache_stat).field++)
static int rt_intern_hash(unsigned hash, struct rtable *rth,
struct rtable **res);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 74998f2..0e029c4 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -258,6 +258,7 @@
#include <linux/random.h>
#include <linux/bootmem.h>
#include <linux/cache.h>
+#include <linux/err.h>
#include <net/icmp.h>
#include <net/tcp.h>
@@ -571,7 +572,7 @@ new_segment:
skb->ip_summed = CHECKSUM_HW;
tp->write_seq += copy;
TCP_SKB_CB(skb)->end_seq += copy;
- skb_shinfo(skb)->tso_segs = 0;
+ skb_shinfo(skb)->gso_segs = 0;
if (!copied)
TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH;
@@ -818,7 +819,7 @@ new_segment:
tp->write_seq += copy;
TCP_SKB_CB(skb)->end_seq += copy;
- skb_shinfo(skb)->tso_segs = 0;
+ skb_shinfo(skb)->gso_segs = 0;
from += copy;
copied += copy;
@@ -2144,6 +2145,67 @@ int compat_tcp_getsockopt(struct sock *sk, int level, int optname,
EXPORT_SYMBOL(compat_tcp_getsockopt);
#endif
+struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg)
+{
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+ struct tcphdr *th;
+ unsigned thlen;
+ unsigned int seq;
+ unsigned int delta;
+ unsigned int oldlen;
+ unsigned int len;
+
+ if (!pskb_may_pull(skb, sizeof(*th)))
+ goto out;
+
+ th = skb->h.th;
+ thlen = th->doff * 4;
+ if (thlen < sizeof(*th))
+ goto out;
+
+ if (!pskb_may_pull(skb, thlen))
+ goto out;
+
+ oldlen = ~htonl(skb->len);
+ __skb_pull(skb, thlen);
+
+ segs = skb_segment(skb, sg);
+ if (IS_ERR(segs))
+ goto out;
+
+ len = skb_shinfo(skb)->gso_size;
+ delta = csum_add(oldlen, htonl(thlen + len));
+
+ skb = segs;
+ th = skb->h.th;
+ seq = ntohl(th->seq);
+
+ do {
+ th->fin = th->psh = 0;
+
+ if (skb->ip_summed == CHECKSUM_NONE) {
+ th->check = csum_fold(csum_partial(
+ skb->h.raw, thlen, csum_add(skb->csum, delta)));
+ }
+
+ seq += len;
+ skb = skb->next;
+ th = skb->h.th;
+
+ th->seq = htonl(seq);
+ th->cwr = 0;
+ } while (skb->next);
+
+ if (skb->ip_summed == CHECKSUM_NONE) {
+ delta = csum_add(oldlen, htonl(skb->tail - skb->h.raw));
+ th->check = csum_fold(csum_partial(
+ skb->h.raw, thlen, csum_add(skb->csum, delta)));
+ }
+
+out:
+ return segs;
+}
+
extern void __skb_cb_too_small_for_tcp(int, int);
extern struct tcp_congestion_ops tcp_reno;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index e08245b..94fe5b1 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1073,7 +1073,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
else
pkt_len = (end_seq -
TCP_SKB_CB(skb)->seq);
- if (tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->tso_size))
+ if (tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->gso_size))
break;
pcount = tcp_skb_pcount(skb);
}
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 07bb5a2..bdd71db 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -515,15 +515,17 @@ static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb, unsigned
/* Avoid the costly divide in the normal
* non-TSO case.
*/
- skb_shinfo(skb)->tso_segs = 1;
- skb_shinfo(skb)->tso_size = 0;
+ skb_shinfo(skb)->gso_segs = 1;
+ skb_shinfo(skb)->gso_size = 0;
+ skb_shinfo(skb)->gso_type = 0;
} else {
unsigned int factor;
factor = skb->len + (mss_now - 1);
factor /= mss_now;
- skb_shinfo(skb)->tso_segs = factor;
- skb_shinfo(skb)->tso_size = mss_now;
+ skb_shinfo(skb)->gso_segs = factor;
+ skb_shinfo(skb)->gso_size = mss_now;
+ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
}
}
@@ -914,7 +916,7 @@ static int tcp_init_tso_segs(struct sock *sk, struct sk_buff *skb, unsigned int
if (!tso_segs ||
(tso_segs > 1 &&
- skb_shinfo(skb)->tso_size != mss_now)) {
+ tcp_skb_mss(skb) != mss_now)) {
tcp_set_skb_tso_segs(sk, skb, mss_now);
tso_segs = tcp_skb_pcount(skb);
}
@@ -1724,8 +1726,9 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) {
if (!pskb_trim(skb, 0)) {
TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1;
- skb_shinfo(skb)->tso_segs = 1;
- skb_shinfo(skb)->tso_size = 0;
+ skb_shinfo(skb)->gso_segs = 1;
+ skb_shinfo(skb)->gso_size = 0;
+ skb_shinfo(skb)->gso_type = 0;
skb->ip_summed = CHECKSUM_NONE;
skb->csum = 0;
}
@@ -1930,8 +1933,9 @@ void tcp_send_fin(struct sock *sk)
skb->csum = 0;
TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_FIN);
TCP_SKB_CB(skb)->sacked = 0;
- skb_shinfo(skb)->tso_segs = 1;
- skb_shinfo(skb)->tso_size = 0;
+ skb_shinfo(skb)->gso_segs = 1;
+ skb_shinfo(skb)->gso_size = 0;
+ skb_shinfo(skb)->gso_type = 0;
/* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */
TCP_SKB_CB(skb)->seq = tp->write_seq;
@@ -1963,8 +1967,9 @@ void tcp_send_active_reset(struct sock *sk, gfp_t priority)
skb->csum = 0;
TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_RST);
TCP_SKB_CB(skb)->sacked = 0;
- skb_shinfo(skb)->tso_segs = 1;
- skb_shinfo(skb)->tso_size = 0;
+ skb_shinfo(skb)->gso_segs = 1;
+ skb_shinfo(skb)->gso_size = 0;
+ skb_shinfo(skb)->gso_type = 0;
/* Send it off. */
TCP_SKB_CB(skb)->seq = tcp_acceptable_seq(sk, tp);
@@ -2047,8 +2052,9 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst,
TCP_SKB_CB(skb)->seq = tcp_rsk(req)->snt_isn;
TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1;
TCP_SKB_CB(skb)->sacked = 0;
- skb_shinfo(skb)->tso_segs = 1;
- skb_shinfo(skb)->tso_size = 0;
+ skb_shinfo(skb)->gso_segs = 1;
+ skb_shinfo(skb)->gso_size = 0;
+ skb_shinfo(skb)->gso_type = 0;
th->seq = htonl(TCP_SKB_CB(skb)->seq);
th->ack_seq = htonl(tcp_rsk(req)->rcv_isn + 1);
if (req->rcv_wnd == 0) { /* ignored for retransmitted syns */
@@ -2152,8 +2158,9 @@ int tcp_connect(struct sock *sk)
TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SYN;
TCP_ECN_send_syn(sk, tp, buff);
TCP_SKB_CB(buff)->sacked = 0;
- skb_shinfo(buff)->tso_segs = 1;
- skb_shinfo(buff)->tso_size = 0;
+ skb_shinfo(buff)->gso_segs = 1;
+ skb_shinfo(buff)->gso_size = 0;
+ skb_shinfo(buff)->gso_type = 0;
buff->csum = 0;
TCP_SKB_CB(buff)->seq = tp->write_seq++;
TCP_SKB_CB(buff)->end_seq = tp->write_seq;
@@ -2257,8 +2264,9 @@ void tcp_send_ack(struct sock *sk)
buff->csum = 0;
TCP_SKB_CB(buff)->flags = TCPCB_FLAG_ACK;
TCP_SKB_CB(buff)->sacked = 0;
- skb_shinfo(buff)->tso_segs = 1;
- skb_shinfo(buff)->tso_size = 0;
+ skb_shinfo(buff)->gso_segs = 1;
+ skb_shinfo(buff)->gso_size = 0;
+ skb_shinfo(buff)->gso_type = 0;
/* Send it off, this clears delayed acks for us. */
TCP_SKB_CB(buff)->seq = TCP_SKB_CB(buff)->end_seq = tcp_acceptable_seq(sk, tp);
@@ -2293,8 +2301,9 @@ static int tcp_xmit_probe_skb(struct sock *sk, int urgent)
skb->csum = 0;
TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK;
TCP_SKB_CB(skb)->sacked = urgent;
- skb_shinfo(skb)->tso_segs = 1;
- skb_shinfo(skb)->tso_size = 0;
+ skb_shinfo(skb)->gso_segs = 1;
+ skb_shinfo(skb)->gso_size = 0;
+ skb_shinfo(skb)->gso_type = 0;
/* Use a previous sequence. This should cause the other
* end to send an ack. Don't queue or clone SKB, just
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
index ac9d91d..193363e 100644
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -9,6 +9,8 @@
*/
#include <linux/compiler.h>
+#include <linux/if_ether.h>
+#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/netfilter_ipv4.h>
@@ -97,16 +99,10 @@ error_nolock:
goto out_exit;
}
-static int xfrm4_output_finish(struct sk_buff *skb)
+static int xfrm4_output_finish2(struct sk_buff *skb)
{
int err;
-#ifdef CONFIG_NETFILTER
- if (!skb->dst->xfrm) {
- IPCB(skb)->flags |= IPSKB_REROUTED;
- return dst_output(skb);
- }
-#endif
while (likely((err = xfrm4_output_one(skb)) == 0)) {
nf_reset(skb);
@@ -119,7 +115,7 @@ static int xfrm4_output_finish(struct sk_buff *skb)
return dst_output(skb);
err = nf_hook(PF_INET, NF_IP_POST_ROUTING, &skb, NULL,
- skb->dst->dev, xfrm4_output_finish);
+ skb->dst->dev, xfrm4_output_finish2);
if (unlikely(err != 1))
break;
}
@@ -127,6 +123,48 @@ static int xfrm4_output_finish(struct sk_buff *skb)
return err;
}
+static int xfrm4_output_finish(struct sk_buff *skb)
+{
+ struct sk_buff *segs;
+
+#ifdef CONFIG_NETFILTER
+ if (!skb->dst->xfrm) {
+ IPCB(skb)->flags |= IPSKB_REROUTED;
+ return dst_output(skb);
+ }
+#endif
+
+ if (!skb_shinfo(skb)->gso_size)
+ return xfrm4_output_finish2(skb);
+
+ skb->protocol = htons(ETH_P_IP);
+ segs = skb_gso_segment(skb, 0);
+ kfree_skb(skb);
+ if (unlikely(IS_ERR(segs)))
+ return PTR_ERR(segs);
+
+ do {
+ struct sk_buff *nskb = segs->next;
+ int err;
+
+ segs->next = NULL;
+ err = xfrm4_output_finish2(segs);
+
+ if (unlikely(err)) {
+ while ((segs = nskb)) {
+ nskb = segs->next;
+ segs->next = NULL;
+ kfree_skb(segs);
+ }
+ return err;
+ }
+
+ segs = nskb;
+ } while (segs);
+
+ return 0;
+}
+
int xfrm4_output(struct sk_buff *skb)
{
return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dst->dev,
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index c2c26fa..4da6645 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -862,6 +862,8 @@ static int inline ipv6_saddr_label(const struct in6_addr *addr, int type)
* 2002::/16 2
* ::/96 3
* ::ffff:0:0/96 4
+ * fc00::/7 5
+ * 2001::/32 6
*/
if (type & IPV6_ADDR_LOOPBACK)
return 0;
@@ -869,8 +871,12 @@ static int inline ipv6_saddr_label(const struct in6_addr *addr, int type)
return 3;
else if (type & IPV6_ADDR_MAPPED)
return 4;
+ else if (addr->s6_addr32[0] == htonl(0x20010000))
+ return 6;
else if (addr->s6_addr16[0] == htons(0x2002))
return 2;
+ else if ((addr->s6_addr[0] & 0xfe) == 0xfc)
+ return 5;
return 1;
}
@@ -1069,6 +1075,9 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
if (hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY)
continue;
}
+#else
+ if (hiscore.rule < 7)
+ hiscore.rule++;
#endif
/* Rule 8: Use longest matching prefix */
if (hiscore.rule < 8) {
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index d29620f..abb94de 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -148,7 +148,7 @@ static int ip6_output2(struct sk_buff *skb)
int ip6_output(struct sk_buff *skb)
{
- if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->ufo_size) ||
+ if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size) ||
dst_allfrag(skb->dst))
return ip6_fragment(skb, ip6_output2);
else
@@ -833,8 +833,9 @@ static inline int ip6_ufo_append_data(struct sock *sk,
struct frag_hdr fhdr;
/* specify the length of each IP datagram fragment*/
- skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen) -
- sizeof(struct frag_hdr);
+ skb_shinfo(skb)->gso_size = mtu - fragheaderlen -
+ sizeof(struct frag_hdr);
+ skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4;
ipv6_select_ident(skb, &fhdr);
skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
__skb_queue_tail(&sk->sk_write_queue, skb);
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 16e8425..48fccb1 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -94,7 +94,7 @@ error_nolock:
goto out_exit;
}
-static int xfrm6_output_finish(struct sk_buff *skb)
+static int xfrm6_output_finish2(struct sk_buff *skb)
{
int err;
@@ -110,7 +110,7 @@ static int xfrm6_output_finish(struct sk_buff *skb)
return dst_output(skb);
err = nf_hook(PF_INET6, NF_IP6_POST_ROUTING, &skb, NULL,
- skb->dst->dev, xfrm6_output_finish);
+ skb->dst->dev, xfrm6_output_finish2);
if (unlikely(err != 1))
break;
}
@@ -118,6 +118,41 @@ static int xfrm6_output_finish(struct sk_buff *skb)
return err;
}
+static int xfrm6_output_finish(struct sk_buff *skb)
+{
+ struct sk_buff *segs;
+
+ if (!skb_shinfo(skb)->gso_size)
+ return xfrm6_output_finish2(skb);
+
+ skb->protocol = htons(ETH_P_IP);
+ segs = skb_gso_segment(skb, 0);
+ kfree_skb(skb);
+ if (unlikely(IS_ERR(segs)))
+ return PTR_ERR(segs);
+
+ do {
+ struct sk_buff *nskb = segs->next;
+ int err;
+
+ segs->next = NULL;
+ err = xfrm6_output_finish2(segs);
+
+ if (unlikely(err)) {
+ while ((segs = nskb)) {
+ nskb = segs->next;
+ segs->next = NULL;
+ kfree_skb(segs);
+ }
+ return err;
+ }
+
+ segs = nskb;
+ } while (segs);
+
+ return 0;
+}
+
int xfrm6_output(struct sk_buff *skb)
{
return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL, skb->dst->dev,
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index d7aca8e..74d4a1d 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -96,8 +96,11 @@ static inline int qdisc_restart(struct net_device *dev)
struct sk_buff *skb;
/* Dequeue packet */
- if ((skb = q->dequeue(q)) != NULL) {
+ if (((skb = dev->gso_skb)) || ((skb = q->dequeue(q)))) {
unsigned nolock = (dev->features & NETIF_F_LLTX);
+
+ dev->gso_skb = NULL;
+
/*
* When the driver has LLTX set it does its own locking
* in start_xmit. No need to add additional overhead by
@@ -134,10 +137,8 @@ static inline int qdisc_restart(struct net_device *dev)
if (!netif_queue_stopped(dev)) {
int ret;
- if (netdev_nit)
- dev_queue_xmit_nit(skb, dev);
- ret = dev->hard_start_xmit(skb, dev);
+ ret = dev_hard_start_xmit(skb, dev);
if (ret == NETDEV_TX_OK) {
if (!nolock) {
netif_tx_unlock(dev);
@@ -171,7 +172,10 @@ static inline int qdisc_restart(struct net_device *dev)
*/
requeue:
- q->ops->requeue(skb, q);
+ if (skb->next)
+ dev->gso_skb = skb;
+ else
+ q->ops->requeue(skb, q);
netif_schedule(dev);
return 1;
}
@@ -181,9 +185,13 @@ requeue:
void __qdisc_run(struct net_device *dev)
{
+ if (unlikely(dev->qdisc == &noop_qdisc))
+ goto out;
+
while (qdisc_restart(dev) < 0 && !netif_queue_stopped(dev))
/* NOTHING */;
+out:
clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state);
}
@@ -583,10 +591,17 @@ void dev_deactivate(struct net_device *dev)
dev_watchdog_down(dev);
- while (test_bit(__LINK_STATE_SCHED, &dev->state))
+ /* Wait for outstanding dev_queue_xmit calls. */
+ synchronize_rcu();
+
+ /* Wait for outstanding qdisc_run calls. */
+ while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
yield();
- spin_unlock_wait(&dev->_xmit_lock);
+ if (dev->gso_skb) {
+ kfree_skb(dev->gso_skb);
+ dev->gso_skb = NULL;
+ }
}
void dev_init_scheduler(struct net_device *dev)
diff --git a/net/socket.c b/net/socket.c
index 02948b6..565f5e8 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -335,10 +335,11 @@ static struct super_operations sockfs_ops = {
.statfs = simple_statfs,
};
-static struct super_block *sockfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int sockfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC);
+ return get_sb_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC,
+ mnt);
}
static struct vfsmount *sock_mnt __read_mostly;
diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c
index f56767a..2eccffa 100644
--- a/net/sunrpc/auth_null.c
+++ b/net/sunrpc/auth_null.c
@@ -118,6 +118,8 @@ struct rpc_auth null_auth = {
.au_cslack = 4,
.au_rslack = 2,
.au_ops = &authnull_ops,
+ .au_flavor = RPC_AUTH_NULL,
+ .au_count = ATOMIC_INIT(0),
};
static
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
index df14b6b..74c7406 100644
--- a/net/sunrpc/auth_unix.c
+++ b/net/sunrpc/auth_unix.c
@@ -225,6 +225,7 @@ struct rpc_auth unix_auth = {
.au_cslack = UNX_WRITESLACK,
.au_rslack = 2, /* assume AUTH_NULL verf */
.au_ops = &authunix_ops,
+ .au_flavor = RPC_AUTH_UNIX,
.au_count = ATOMIC_INIT(0),
.au_credcache = &unix_cred_cache,
};
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index cc673dd..dafe793 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -439,7 +439,7 @@ struct vfsmount *rpc_get_mount(void)
{
int err;
- err = simple_pin_fs("rpc_pipefs", &rpc_mount, &rpc_mount_count);
+ err = simple_pin_fs(&rpc_pipe_fs_type, &rpc_mount, &rpc_mount_count);
if (err != 0)
return ERR_PTR(err);
return rpc_mount;
@@ -815,11 +815,11 @@ out:
return -ENOMEM;
}
-static struct super_block *
+static int
rpc_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, rpc_fill_super);
+ return get_sb_single(fs_type, flags, data, rpc_fill_super, mnt);
}
static struct file_system_type rpc_pipe_fs_type = {
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index ca4bfa5..49174f0 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -568,8 +568,7 @@ EXPORT_SYMBOL(xdr_inline_decode);
*
* Moves data beyond the current pointer position from the XDR head[] buffer
* into the page list. Any data that lies beyond current position + "len"
- * bytes is moved into the XDR tail[]. The current pointer is then
- * repositioned at the beginning of the XDR tail.
+ * bytes is moved into the XDR tail[].
*/
void xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
{
@@ -606,6 +605,31 @@ void xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
}
EXPORT_SYMBOL(xdr_read_pages);
+/**
+ * xdr_enter_page - decode data from the XDR page
+ * @xdr: pointer to xdr_stream struct
+ * @len: number of bytes of page data
+ *
+ * Moves data beyond the current pointer position from the XDR head[] buffer
+ * into the page list. Any data that lies beyond current position + "len"
+ * bytes is moved into the XDR tail[]. The current pointer is then
+ * repositioned at the beginning of the first XDR page.
+ */
+void xdr_enter_page(struct xdr_stream *xdr, unsigned int len)
+{
+ char * kaddr = page_address(xdr->buf->pages[0]);
+ xdr_read_pages(xdr, len);
+ /*
+ * Position current pointer at beginning of tail, and
+ * set remaining message length.
+ */
+ if (len > PAGE_CACHE_SIZE - xdr->buf->page_base)
+ len = PAGE_CACHE_SIZE - xdr->buf->page_base;
+ xdr->p = (uint32_t *)(kaddr + xdr->buf->page_base);
+ xdr->end = (uint32_t *)((char *)xdr->p + len);
+}
+EXPORT_SYMBOL(xdr_enter_page);
+
static struct kvec empty_iov = {.iov_base = NULL, .iov_len = 0};
void
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 4dd5b3c..02060d0 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -41,7 +41,7 @@
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
-#include <linux/random.h>
+#include <linux/net.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/metrics.h>
@@ -830,7 +830,7 @@ static inline u32 xprt_alloc_xid(struct rpc_xprt *xprt)
static inline void xprt_init_xid(struct rpc_xprt *xprt)
{
- get_random_bytes(&xprt->xid, sizeof(xprt->xid));
+ xprt->xid = net_random();
}
static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 4b4e7df..21006b1 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -930,6 +930,13 @@ static void xs_udp_timer(struct rpc_task *task)
xprt_adjust_cwnd(task, -ETIMEDOUT);
}
+static unsigned short xs_get_random_port(void)
+{
+ unsigned short range = xprt_max_resvport - xprt_min_resvport;
+ unsigned short rand = (unsigned short) net_random() % range;
+ return rand + xprt_min_resvport;
+}
+
/**
* xs_set_port - reset the port number in the remote endpoint address
* @xprt: generic transport
@@ -1275,7 +1282,7 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to)
memset(xprt->slot, 0, slot_table_size);
xprt->prot = IPPROTO_UDP;
- xprt->port = xprt_max_resvport;
+ xprt->port = xs_get_random_port();
xprt->tsh_size = 0;
xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
/* XXX: header size can vary due to auth type, IPv6, etc. */
@@ -1317,7 +1324,7 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to)
memset(xprt->slot, 0, slot_table_size);
xprt->prot = IPPROTO_TCP;
- xprt->port = xprt_max_resvport;
+ xprt->port = xs_get_random_port();
xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32);
xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
xprt->max_payload = RPC_MAX_FRAGMENT_SIZE;
diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter
index 75f21d8..ce59fc2 100755
--- a/scripts/bloat-o-meter
+++ b/scripts/bloat-o-meter
@@ -18,7 +18,8 @@ def getsizes(file):
for l in os.popen("nm --size-sort " + file).readlines():
size, type, name = l[:-1].split()
if type in "tTdDbB":
- sym[name] = int(size, 16)
+ if "." in name: name = "static." + name.split(".")[0]
+ sym[name] = sym.get(name, 0) + int(size, 16)
return sym
old = getsizes(sys.argv[1])
diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl
index dadfa20..b349246 100755
--- a/scripts/checkstack.pl
+++ b/scripts/checkstack.pl
@@ -89,11 +89,21 @@ sub bysize($) {
#
my $funcre = qr/^$x* <(.*)>:$/;
my $func;
+my $file, $lastslash;
+
while (my $line = <STDIN>) {
if ($line =~ m/$funcre/) {
$func = $1;
}
- if ($line =~ m/$re/) {
+ elsif ($line =~ m/(.*):\s*file format/) {
+ $file = $1;
+ $file =~ s/\.ko//;
+ $lastslash = rindex($file, "/");
+ if ($lastslash != -1) {
+ $file = substr($file, $lastslash + 1);
+ }
+ }
+ elsif ($line =~ m/$re/) {
my $size = $1;
$size = hex($size) if ($size =~ /^0x/);
@@ -109,7 +119,7 @@ while (my $line = <STDIN>) {
$addr =~ s/ /0/g;
$addr = "0x$addr";
- my $intro = "$addr $func:";
+ my $intro = "$addr $func [$file]:";
my $padlen = 56 - length($intro);
while ($padlen > 0) {
$intro .= ' ';
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 99fe4b7..00e2129 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -253,6 +253,7 @@ my $lineprefix="";
# 3 - scanning prototype.
# 4 - documentation block
my $state;
+my $in_doc_sect;
#declaration types: can be
# 'function', 'struct', 'union', 'enum', 'typedef'
@@ -1064,7 +1065,7 @@ sub output_struct_man(%) {
}
print "};\n.br\n";
- print ".SH Arguments\n";
+ print ".SH Members\n";
foreach $parameter (@{$args{'parameterlist'}}) {
($parameter =~ /^#/) && next;
@@ -1673,6 +1674,9 @@ sub process_state3_type($$) {
# replace <, >, and &
sub xml_escape($) {
my $text = shift;
+ if (($output_mode eq "text") || ($output_mode eq "man")) {
+ return $text;
+ }
$text =~ s/\&/\\\\\\amp;/g;
$text =~ s/\</\\\\\\lt;/g;
$text =~ s/\>/\\\\\\gt;/g;
@@ -1706,6 +1710,7 @@ sub process_file($) {
if ($state == 0) {
if (/$doc_start/o) {
$state = 1; # next line is always the function name
+ $in_doc_sect = 0;
}
} elsif ($state == 1) { # this line is the function name (always)
if (/$doc_block/o) {
@@ -1756,12 +1761,20 @@ sub process_file($) {
$newcontents = $2;
if ($contents ne "") {
+ if (!$in_doc_sect && $verbose) {
+ print STDERR "Warning(${file}:$.): contents before sections\n";
+ ++$warnings;
+ }
dump_section($section, xml_escape($contents));
$section = $section_default;
}
+ $in_doc_sect = 1;
$contents = $newcontents;
if ($contents ne "") {
+ if (substr($contents, 0, 1) eq " ") {
+ $contents = substr($contents, 1);
+ }
$contents .= "\n";
}
$section = $newsection;
@@ -1776,7 +1789,7 @@ sub process_file($) {
$prototype = "";
$state = 3;
$brcount = 0;
-# print STDERR "end of doc comment, looking for prototype\n";
+# print STDERR "end of doc comment, looking for prototype\n";
} elsif (/$doc_content/) {
# miguel-style comment kludge, look for blank lines after
# @parameter line to signify start of description
@@ -1793,7 +1806,7 @@ sub process_file($) {
print STDERR "Warning(${file}:$.): bad line: $_";
++$warnings;
}
- } elsif ($state == 3) { # scanning for function { (end of prototype)
+ } elsif ($state == 3) { # scanning for function '{' (end of prototype)
if ($decl_type eq 'function') {
process_state3_function($_, $file);
} else {
diff --git a/security/dummy.c b/security/dummy.c
index 64f6da0..c3c5493 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -191,7 +191,7 @@ static int dummy_sb_kern_mount (struct super_block *sb, void *data)
return 0;
}
-static int dummy_sb_statfs (struct super_block *sb)
+static int dummy_sb_statfs (struct dentry *dentry)
{
return 0;
}
@@ -516,6 +516,11 @@ static int dummy_task_setnice (struct task_struct *p, int nice)
return 0;
}
+static int dummy_task_setioprio (struct task_struct *p, int ioprio)
+{
+ return 0;
+}
+
static int dummy_task_setrlimit (unsigned int resource, struct rlimit *new_rlim)
{
return 0;
@@ -532,6 +537,11 @@ static int dummy_task_getscheduler (struct task_struct *p)
return 0;
}
+static int dummy_task_movememory (struct task_struct *p)
+{
+ return 0;
+}
+
static int dummy_task_wait (struct task_struct *p)
{
return 0;
@@ -860,7 +870,7 @@ static int dummy_setprocattr(struct task_struct *p, char *name, void *value, siz
}
#ifdef CONFIG_KEYS
-static inline int dummy_key_alloc(struct key *key)
+static inline int dummy_key_alloc(struct key *key, struct task_struct *ctx)
{
return 0;
}
@@ -972,9 +982,11 @@ void security_fixup_ops (struct security_operations *ops)
set_to_dummy_if_null(ops, task_getsid);
set_to_dummy_if_null(ops, task_setgroups);
set_to_dummy_if_null(ops, task_setnice);
+ set_to_dummy_if_null(ops, task_setioprio);
set_to_dummy_if_null(ops, task_setrlimit);
set_to_dummy_if_null(ops, task_setscheduler);
set_to_dummy_if_null(ops, task_getscheduler);
+ set_to_dummy_if_null(ops, task_movememory);
set_to_dummy_if_null(ops, task_wait);
set_to_dummy_if_null(ops, task_kill);
set_to_dummy_if_null(ops, task_prctl);
diff --git a/security/inode.c b/security/inode.c
index 0f77b02..98a0df5 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -135,11 +135,11 @@ static int fill_super(struct super_block *sb, void *data, int silent)
return simple_fill_super(sb, SECURITYFS_MAGIC, files);
}
-static struct super_block *get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data)
+static int get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data, struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, fill_super);
+ return get_sb_single(fs_type, flags, data, fill_super, mnt);
}
static struct file_system_type fs_type = {
@@ -224,7 +224,7 @@ struct dentry *securityfs_create_file(const char *name, mode_t mode,
pr_debug("securityfs: creating file '%s'\n",name);
- error = simple_pin_fs("securityfs", &mount, &mount_count);
+ error = simple_pin_fs(&fs_type, &mount, &mount_count);
if (error) {
dentry = ERR_PTR(error);
goto exit;
diff --git a/security/keys/key.c b/security/keys/key.c
index 3fdc49c..51f8515 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -247,8 +247,8 @@ static inline void key_alloc_serial(struct key *key)
* instantiate the key or discard it before returning
*/
struct key *key_alloc(struct key_type *type, const char *desc,
- uid_t uid, gid_t gid, key_perm_t perm,
- int not_in_quota)
+ uid_t uid, gid_t gid, struct task_struct *ctx,
+ key_perm_t perm, int not_in_quota)
{
struct key_user *user = NULL;
struct key *key;
@@ -318,7 +318,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
#endif
/* let the security module know about the key */
- ret = security_key_alloc(key);
+ ret = security_key_alloc(key, ctx);
if (ret < 0)
goto security_error;
@@ -822,7 +822,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
/* allocate a new key */
key = key_alloc(ktype, description, current->fsuid, current->fsgid,
- perm, not_in_quota);
+ current, perm, not_in_quota);
if (IS_ERR(key)) {
key_ref = ERR_PTR(PTR_ERR(key));
goto error_3;
@@ -907,6 +907,10 @@ void key_revoke(struct key *key)
* it */
down_write(&key->sem);
set_bit(KEY_FLAG_REVOKED, &key->flags);
+
+ if (key->type->revoke)
+ key->type->revoke(key);
+
up_write(&key->sem);
} /* end key_revoke() */
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index bffa924..1357207 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -240,13 +240,14 @@ static long keyring_read(const struct key *keyring,
* allocate a keyring and link into the destination keyring
*/
struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
- int not_in_quota, struct key *dest)
+ struct task_struct *ctx, int not_in_quota,
+ struct key *dest)
{
struct key *keyring;
int ret;
keyring = key_alloc(&key_type_keyring, description,
- uid, gid,
+ uid, gid, ctx,
(KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
not_in_quota);
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 217a0be..4d9825f 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -67,7 +67,8 @@ struct key root_session_keyring = {
/*
* allocate the keyrings to be associated with a UID
*/
-int alloc_uid_keyring(struct user_struct *user)
+int alloc_uid_keyring(struct user_struct *user,
+ struct task_struct *ctx)
{
struct key *uid_keyring, *session_keyring;
char buf[20];
@@ -76,7 +77,7 @@ int alloc_uid_keyring(struct user_struct *user)
/* concoct a default session keyring */
sprintf(buf, "_uid_ses.%u", user->uid);
- session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0, NULL);
+ session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx, 0, NULL);
if (IS_ERR(session_keyring)) {
ret = PTR_ERR(session_keyring);
goto error;
@@ -86,7 +87,7 @@ int alloc_uid_keyring(struct user_struct *user)
* keyring */
sprintf(buf, "_uid.%u", user->uid);
- uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0,
+ uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx, 0,
session_keyring);
if (IS_ERR(uid_keyring)) {
key_put(session_keyring);
@@ -143,7 +144,7 @@ int install_thread_keyring(struct task_struct *tsk)
sprintf(buf, "_tid.%u", tsk->pid);
- keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
+ keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error;
@@ -177,7 +178,7 @@ int install_process_keyring(struct task_struct *tsk)
if (!tsk->signal->process_keyring) {
sprintf(buf, "_pid.%u", tsk->tgid);
- keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
+ keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error;
@@ -217,7 +218,7 @@ static int install_session_keyring(struct task_struct *tsk,
if (!keyring) {
sprintf(buf, "_ses.%u", tsk->tgid);
- keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
+ keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL);
if (IS_ERR(keyring))
return PTR_ERR(keyring);
}
@@ -390,6 +391,8 @@ key_ref_t search_process_keyrings(struct key_type *type,
struct request_key_auth *rka;
key_ref_t key_ref, ret, err;
+ might_sleep();
+
/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
* searchable, but we failed to find a key or we found a negative key;
* otherwise we want to return a sample error (probably -EACCES) if
@@ -495,27 +498,35 @@ key_ref_t search_process_keyrings(struct key_type *type,
*/
if (context->request_key_auth &&
context == current &&
- type != &key_type_request_key_auth &&
- key_validate(context->request_key_auth) == 0
+ type != &key_type_request_key_auth
) {
- rka = context->request_key_auth->payload.data;
+ /* defend against the auth key being revoked */
+ down_read(&context->request_key_auth->sem);
- key_ref = search_process_keyrings(type, description, match,
- rka->context);
+ if (key_validate(context->request_key_auth) == 0) {
+ rka = context->request_key_auth->payload.data;
- if (!IS_ERR(key_ref))
- goto found;
+ key_ref = search_process_keyrings(type, description,
+ match, rka->context);
- switch (PTR_ERR(key_ref)) {
- case -EAGAIN: /* no key */
- if (ret)
+ up_read(&context->request_key_auth->sem);
+
+ if (!IS_ERR(key_ref))
+ goto found;
+
+ switch (PTR_ERR(key_ref)) {
+ case -EAGAIN: /* no key */
+ if (ret)
+ break;
+ case -ENOKEY: /* negative key */
+ ret = key_ref;
break;
- case -ENOKEY: /* negative key */
- ret = key_ref;
- break;
- default:
- err = key_ref;
- break;
+ default:
+ err = key_ref;
+ break;
+ }
+ } else {
+ up_read(&context->request_key_auth->sem);
}
}
@@ -717,7 +728,7 @@ long join_session_keyring(const char *name)
keyring = find_keyring_by_name(name, 0);
if (PTR_ERR(keyring) == -ENOKEY) {
/* not found - try and create a new one */
- keyring = keyring_alloc(name, tsk->uid, tsk->gid, 0, NULL);
+ keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk, 0, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error2;
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index f030a0c..eab66a0 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -48,7 +48,8 @@ static int call_sbin_request_key(struct key *key,
/* allocate a new session keyring */
sprintf(desc, "_req.%u", key->serial);
- keyring = keyring_alloc(desc, current->fsuid, current->fsgid, 1, NULL);
+ keyring = keyring_alloc(desc, current->fsuid, current->fsgid,
+ current, 1, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error_alloc;
@@ -137,7 +138,8 @@ static struct key *__request_key_construction(struct key_type *type,
/* create a key and add it to the queue */
key = key_alloc(type, description,
- current->fsuid, current->fsgid, KEY_POS_ALL, 0);
+ current->fsuid, current->fsgid,
+ current, KEY_POS_ALL, 0);
if (IS_ERR(key))
goto alloc_failed;
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index cce6ba6..cb9817c 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -20,6 +20,7 @@
static int request_key_auth_instantiate(struct key *, const void *, size_t);
static void request_key_auth_describe(const struct key *, struct seq_file *);
+static void request_key_auth_revoke(struct key *);
static void request_key_auth_destroy(struct key *);
static long request_key_auth_read(const struct key *, char __user *, size_t);
@@ -31,6 +32,7 @@ struct key_type key_type_request_key_auth = {
.def_datalen = sizeof(struct request_key_auth),
.instantiate = request_key_auth_instantiate,
.describe = request_key_auth_describe,
+ .revoke = request_key_auth_revoke,
.destroy = request_key_auth_destroy,
.read = request_key_auth_read,
};
@@ -93,6 +95,24 @@ static long request_key_auth_read(const struct key *key,
/*****************************************************************************/
/*
+ * handle revocation of an authorisation token key
+ * - called with the key sem write-locked
+ */
+static void request_key_auth_revoke(struct key *key)
+{
+ struct request_key_auth *rka = key->payload.data;
+
+ kenter("{%d}", key->serial);
+
+ if (rka->context) {
+ put_task_struct(rka->context);
+ rka->context = NULL;
+ }
+
+} /* end request_key_auth_revoke() */
+
+/*****************************************************************************/
+/*
* destroy an instantiation authorisation token key
*/
static void request_key_auth_destroy(struct key *key)
@@ -101,6 +121,11 @@ static void request_key_auth_destroy(struct key *key)
kenter("{%d}", key->serial);
+ if (rka->context) {
+ put_task_struct(rka->context);
+ rka->context = NULL;
+ }
+
key_put(rka->target_key);
kfree(rka);
@@ -131,14 +156,26 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info)
* another process */
if (current->request_key_auth) {
/* it is - use that instantiation context here too */
+ down_read(&current->request_key_auth->sem);
+
+ /* if the auth key has been revoked, then the key we're
+ * servicing is already instantiated */
+ if (test_bit(KEY_FLAG_REVOKED,
+ &current->request_key_auth->flags))
+ goto auth_key_revoked;
+
irka = current->request_key_auth->payload.data;
rka->context = irka->context;
rka->pid = irka->pid;
+ get_task_struct(rka->context);
+
+ up_read(&current->request_key_auth->sem);
}
else {
/* it isn't - use this process as the context */
rka->context = current;
rka->pid = current->pid;
+ get_task_struct(rka->context);
}
rka->target_key = key_get(target);
@@ -148,7 +185,7 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info)
sprintf(desc, "%x", target->serial);
authkey = key_alloc(&key_type_request_key_auth, desc,
- current->fsuid, current->fsgid,
+ current->fsuid, current->fsgid, current,
KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH |
KEY_USR_VIEW, 1);
if (IS_ERR(authkey)) {
@@ -161,9 +198,15 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info)
if (ret < 0)
goto error_inst;
- kleave(" = {%d})", authkey->serial);
+ kleave(" = {%d}", authkey->serial);
return authkey;
+auth_key_revoked:
+ up_read(&current->request_key_auth->sem);
+ kfree(rka);
+ kleave("= -EKEYREVOKED");
+ return ERR_PTR(-EKEYREVOKED);
+
error_inst:
key_revoke(authkey);
key_put(authkey);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 54adc9d..79c16e3 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1903,13 +1903,13 @@ static int selinux_sb_kern_mount(struct super_block *sb, void *data)
return superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad);
}
-static int selinux_sb_statfs(struct super_block *sb)
+static int selinux_sb_statfs(struct dentry *dentry)
{
struct avc_audit_data ad;
AVC_AUDIT_DATA_INIT(&ad,FS);
- ad.u.fs.dentry = sb->s_root;
- return superblock_has_perm(current, sb, FILESYSTEM__GETATTR, &ad);
+ ad.u.fs.dentry = dentry->d_sb->s_root;
+ return superblock_has_perm(current, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
}
static int selinux_mount(char * dev_name,
@@ -2645,6 +2645,11 @@ static int selinux_task_setnice(struct task_struct *p, int nice)
return task_has_perm(current,p, PROCESS__SETSCHED);
}
+static int selinux_task_setioprio(struct task_struct *p, int ioprio)
+{
+ return task_has_perm(current, p, PROCESS__SETSCHED);
+}
+
static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
{
struct rlimit *old_rlim = current->signal->rlim + resource;
@@ -2674,6 +2679,11 @@ static int selinux_task_getscheduler(struct task_struct *p)
return task_has_perm(current, p, PROCESS__GETSCHED);
}
+static int selinux_task_movememory(struct task_struct *p)
+{
+ return task_has_perm(current, p, PROCESS__SETSCHED);
+}
+
static int selinux_task_kill(struct task_struct *p, struct siginfo *info, int sig)
{
u32 perm;
@@ -4252,6 +4262,57 @@ static int selinux_setprocattr(struct task_struct *p,
return size;
}
+#ifdef CONFIG_KEYS
+
+static int selinux_key_alloc(struct key *k, struct task_struct *tsk)
+{
+ struct task_security_struct *tsec = tsk->security;
+ struct key_security_struct *ksec;
+
+ ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
+ if (!ksec)
+ return -ENOMEM;
+
+ ksec->obj = k;
+ ksec->sid = tsec->sid;
+ k->security = ksec;
+
+ return 0;
+}
+
+static void selinux_key_free(struct key *k)
+{
+ struct key_security_struct *ksec = k->security;
+
+ k->security = NULL;
+ kfree(ksec);
+}
+
+static int selinux_key_permission(key_ref_t key_ref,
+ struct task_struct *ctx,
+ key_perm_t perm)
+{
+ struct key *key;
+ struct task_security_struct *tsec;
+ struct key_security_struct *ksec;
+
+ key = key_ref_to_ptr(key_ref);
+
+ tsec = ctx->security;
+ ksec = key->security;
+
+ /* if no specific permissions are requested, we skip the
+ permission check. No serious, additional covert channels
+ appear to be created. */
+ if (perm == 0)
+ return 0;
+
+ return avc_has_perm(tsec->sid, ksec->sid,
+ SECCLASS_KEY, perm, NULL);
+}
+
+#endif
+
static struct security_operations selinux_ops = {
.ptrace = selinux_ptrace,
.capget = selinux_capget,
@@ -4332,9 +4393,11 @@ static struct security_operations selinux_ops = {
.task_getsid = selinux_task_getsid,
.task_setgroups = selinux_task_setgroups,
.task_setnice = selinux_task_setnice,
+ .task_setioprio = selinux_task_setioprio,
.task_setrlimit = selinux_task_setrlimit,
.task_setscheduler = selinux_task_setscheduler,
.task_getscheduler = selinux_task_getscheduler,
+ .task_movememory = selinux_task_movememory,
.task_kill = selinux_task_kill,
.task_wait = selinux_task_wait,
.task_prctl = selinux_task_prctl,
@@ -4406,6 +4469,12 @@ static struct security_operations selinux_ops = {
.xfrm_state_delete_security = selinux_xfrm_state_delete,
.xfrm_policy_lookup = selinux_xfrm_policy_lookup,
#endif
+
+#ifdef CONFIG_KEYS
+ .key_alloc = selinux_key_alloc,
+ .key_free = selinux_key_free,
+ .key_permission = selinux_key_permission,
+#endif
};
static __init int selinux_init(void)
@@ -4441,6 +4510,13 @@ static __init int selinux_init(void)
} else {
printk(KERN_INFO "SELinux: Starting in permissive mode\n");
}
+
+#ifdef CONFIG_KEYS
+ /* Add security information to initial keyrings */
+ security_key_alloc(&root_user_keyring, current);
+ security_key_alloc(&root_session_keyring, current);
+#endif
+
return 0;
}
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h
index 70ee65a..bc020bd 100644
--- a/security/selinux/include/av_perm_to_string.h
+++ b/security/selinux/include/av_perm_to_string.h
@@ -242,3 +242,9 @@
S_(SECCLASS_PACKET, PACKET__SEND, "send")
S_(SECCLASS_PACKET, PACKET__RECV, "recv")
S_(SECCLASS_PACKET, PACKET__RELABELTO, "relabelto")
+ S_(SECCLASS_KEY, KEY__VIEW, "view")
+ S_(SECCLASS_KEY, KEY__READ, "read")
+ S_(SECCLASS_KEY, KEY__WRITE, "write")
+ S_(SECCLASS_KEY, KEY__SEARCH, "search")
+ S_(SECCLASS_KEY, KEY__LINK, "link")
+ S_(SECCLASS_KEY, KEY__SETATTR, "setattr")
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h
index 1d9cf3d..1205227 100644
--- a/security/selinux/include/av_permissions.h
+++ b/security/selinux/include/av_permissions.h
@@ -959,3 +959,11 @@
#define PACKET__SEND 0x00000001UL
#define PACKET__RECV 0x00000002UL
#define PACKET__RELABELTO 0x00000004UL
+
+#define KEY__VIEW 0x00000001UL
+#define KEY__READ 0x00000002UL
+#define KEY__WRITE 0x00000004UL
+#define KEY__SEARCH 0x00000008UL
+#define KEY__LINK 0x00000010UL
+#define KEY__SETATTR 0x00000020UL
+
diff --git a/security/selinux/include/class_to_string.h b/security/selinux/include/class_to_string.h
index 3aec75f..24303b6 100644
--- a/security/selinux/include/class_to_string.h
+++ b/security/selinux/include/class_to_string.h
@@ -60,3 +60,4 @@
S_("netlink_kobject_uevent_socket")
S_("appletalk_socket")
S_("packet")
+ S_("key")
diff --git a/security/selinux/include/flask.h b/security/selinux/include/flask.h
index a0eb9e2..95887ae 100644
--- a/security/selinux/include/flask.h
+++ b/security/selinux/include/flask.h
@@ -62,6 +62,7 @@
#define SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET 55
#define SECCLASS_APPLETALK_SOCKET 56
#define SECCLASS_PACKET 57
+#define SECCLASS_KEY 58
/*
* Security identifier indices for initial entities
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 54c0307..8f5547a 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -99,6 +99,11 @@ struct sk_security_struct {
u32 peer_sid; /* SID of peer */
};
+struct key_security_struct {
+ struct key *obj; /* back pointer */
+ u32 sid; /* SID of key */
+};
+
extern unsigned int selinux_checkreqprot;
#endif /* _SELINUX_OBJSEC_H_ */
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 2e73d32..7029bbc 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -1345,10 +1345,11 @@ err:
goto out;
}
-static struct super_block *sel_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int sel_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data,
+ struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, sel_fill_super);
+ return get_sb_single(fs_type, flags, data, sel_fill_super, mnt);
}
static struct file_system_type sel_fs_type = {
diff --git a/sound/Kconfig b/sound/Kconfig
index b65ee47..e0d791a 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -58,6 +58,8 @@ source "sound/pci/Kconfig"
source "sound/ppc/Kconfig"
+source "sound/aoa/Kconfig"
+
source "sound/arm/Kconfig"
source "sound/mips/Kconfig"
diff --git a/sound/Makefile b/sound/Makefile
index f352bb2..a682ea3 100644
--- a/sound/Makefile
+++ b/sound/Makefile
@@ -4,7 +4,7 @@
obj-$(CONFIG_SOUND) += soundcore.o
obj-$(CONFIG_SOUND_PRIME) += oss/
obj-$(CONFIG_DMASOUND) += oss/
-obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/
+obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ aoa/
ifeq ($(CONFIG_SND),y)
obj-y += last.o
diff --git a/sound/aoa/Kconfig b/sound/aoa/Kconfig
new file mode 100644
index 0000000..a85194f
--- /dev/null
+++ b/sound/aoa/Kconfig
@@ -0,0 +1,17 @@
+menu "Apple Onboard Audio driver"
+ depends on SND!=n && PPC
+
+config SND_AOA
+ tristate "Apple Onboard Audio driver"
+ depends on SOUND && SND_PCM
+ ---help---
+ This option enables the new driver for the various
+ Apple Onboard Audio components.
+
+source "sound/aoa/fabrics/Kconfig"
+
+source "sound/aoa/codecs/Kconfig"
+
+source "sound/aoa/soundbus/Kconfig"
+
+endmenu
diff --git a/sound/aoa/Makefile b/sound/aoa/Makefile
new file mode 100644
index 0000000..d8de3e7
--- /dev/null
+++ b/sound/aoa/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_SND_AOA) += core/
+obj-$(CONFIG_SND_AOA) += codecs/
+obj-$(CONFIG_SND_AOA) += fabrics/
+obj-$(CONFIG_SND_AOA_SOUNDBUS) += soundbus/
diff --git a/sound/aoa/aoa-gpio.h b/sound/aoa/aoa-gpio.h
new file mode 100644
index 0000000..3a61f31
--- /dev/null
+++ b/sound/aoa/aoa-gpio.h
@@ -0,0 +1,81 @@
+/*
+ * Apple Onboard Audio GPIO definitions
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+
+#ifndef __AOA_GPIO_H
+#define __AOA_GPIO_H
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <asm/prom.h>
+
+typedef void (*notify_func_t)(void *data);
+
+enum notify_type {
+ AOA_NOTIFY_HEADPHONE,
+ AOA_NOTIFY_LINE_IN,
+ AOA_NOTIFY_LINE_OUT,
+};
+
+struct gpio_runtime;
+struct gpio_methods {
+ /* for initialisation/de-initialisation of the GPIO layer */
+ void (*init)(struct gpio_runtime *rt);
+ void (*exit)(struct gpio_runtime *rt);
+
+ /* turn off headphone, speakers, lineout */
+ void (*all_amps_off)(struct gpio_runtime *rt);
+ /* turn headphone, speakers, lineout back to previous setting */
+ void (*all_amps_restore)(struct gpio_runtime *rt);
+
+ void (*set_headphone)(struct gpio_runtime *rt, int on);
+ void (*set_speakers)(struct gpio_runtime *rt, int on);
+ void (*set_lineout)(struct gpio_runtime *rt, int on);
+
+ int (*get_headphone)(struct gpio_runtime *rt);
+ int (*get_speakers)(struct gpio_runtime *rt);
+ int (*get_lineout)(struct gpio_runtime *rt);
+
+ void (*set_hw_reset)(struct gpio_runtime *rt, int on);
+
+ /* use this to be notified of any events. The notification
+ * function is passed the data, and is called in process
+ * context by the use of schedule_work.
+ * The interface for it is that setting a function to NULL
+ * removes it, and they return 0 if the operation succeeded,
+ * and -EBUSY if the notification is already assigned by
+ * someone else. */
+ int (*set_notify)(struct gpio_runtime *rt,
+ enum notify_type type,
+ notify_func_t notify,
+ void *data);
+ /* returns 0 if not plugged in, 1 if plugged in
+ * or a negative error code */
+ int (*get_detect)(struct gpio_runtime *rt,
+ enum notify_type type);
+};
+
+struct gpio_notification {
+ notify_func_t notify;
+ void *data;
+ void *gpio_private;
+ struct work_struct work;
+ struct mutex mutex;
+};
+
+struct gpio_runtime {
+ /* to be assigned by fabric */
+ struct device_node *node;
+ /* since everyone needs this pointer anyway... */
+ struct gpio_methods *methods;
+ /* to be used by the gpio implementation */
+ int implementation_private;
+ struct gpio_notification headphone_notify;
+ struct gpio_notification line_in_notify;
+ struct gpio_notification line_out_notify;
+};
+
+#endif /* __AOA_GPIO_H */
diff --git a/sound/aoa/aoa.h b/sound/aoa/aoa.h
new file mode 100644
index 0000000..378ef1e
--- /dev/null
+++ b/sound/aoa/aoa.h
@@ -0,0 +1,131 @@
+/*
+ * Apple Onboard Audio definitions
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+
+#ifndef __AOA_H
+#define __AOA_H
+#include <asm/prom.h>
+#include <linux/module.h>
+/* So apparently there's a reason for requiring driver.h to be included first! */
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/asound.h>
+#include <sound/control.h>
+#include "aoa-gpio.h"
+#include "soundbus/soundbus.h"
+
+#define MAX_CODEC_NAME_LEN 32
+
+struct aoa_codec {
+ char name[MAX_CODEC_NAME_LEN];
+
+ struct module *owner;
+
+ /* called when the fabric wants to init this codec.
+ * Do alsa card manipulations from here. */
+ int (*init)(struct aoa_codec *codec);
+
+ /* called when the fabric is done with the codec.
+ * The alsa card will be cleaned up so don't bother. */
+ void (*exit)(struct aoa_codec *codec);
+
+ /* May be NULL, but can be used by the fabric.
+ * Refcounting is the codec driver's responsibility */
+ struct device_node *node;
+
+ /* assigned by fabric before init() is called, points
+ * to the soundbus device. Cannot be NULL. */
+ struct soundbus_dev *soundbus_dev;
+
+ /* assigned by the fabric before init() is called, points
+ * to the fabric's gpio runtime record for the relevant
+ * device. */
+ struct gpio_runtime *gpio;
+
+ /* assigned by the fabric before init() is called, contains
+ * a codec specific bitmask of what outputs and inputs are
+ * actually connected */
+ u32 connected;
+
+ /* data the fabric can associate with this structure */
+ void *fabric_data;
+
+ /* private! */
+ struct list_head list;
+ struct aoa_fabric *fabric;
+};
+
+/* return 0 on success */
+extern int
+aoa_codec_register(struct aoa_codec *codec);
+extern void
+aoa_codec_unregister(struct aoa_codec *codec);
+
+#define MAX_LAYOUT_NAME_LEN 32
+
+struct aoa_fabric {
+ char name[MAX_LAYOUT_NAME_LEN];
+
+ struct module *owner;
+
+ /* once codecs register, they are passed here after.
+ * They are of course not initialised, since the
+ * fabric is responsible for initialising some fields
+ * in the codec structure! */
+ int (*found_codec)(struct aoa_codec *codec);
+ /* called for each codec when it is removed,
+ * also in the case that aoa_fabric_unregister
+ * is called and all codecs are removed
+ * from this fabric.
+ * Also called if found_codec returned 0 but
+ * the codec couldn't initialise. */
+ void (*remove_codec)(struct aoa_codec *codec);
+ /* If found_codec returned 0, and the codec
+ * could be initialised, this is called. */
+ void (*attached_codec)(struct aoa_codec *codec);
+};
+
+/* return 0 on success, -EEXIST if another fabric is
+ * registered, -EALREADY if the same fabric is registered.
+ * Passing NULL can be used to test for the presence
+ * of another fabric, if -EALREADY is returned there is
+ * no other fabric present.
+ * In the case that the function returns -EALREADY
+ * and the fabric passed is not NULL, all codecs
+ * that are not assigned yet are passed to the fabric
+ * again for reconsideration. */
+extern int
+aoa_fabric_register(struct aoa_fabric *fabric);
+
+/* it is vital to call this when the fabric exits!
+ * When calling, the remove_codec will be called
+ * for all codecs, unless it is NULL. */
+extern void
+aoa_fabric_unregister(struct aoa_fabric *fabric);
+
+/* if for some reason you want to get rid of a codec
+ * before the fabric is removed, use this.
+ * Note that remove_codec is called for it! */
+extern void
+aoa_fabric_unlink_codec(struct aoa_codec *codec);
+
+/* alsa help methods */
+struct aoa_card {
+ struct snd_card *alsa_card;
+};
+
+extern int aoa_snd_device_new(snd_device_type_t type,
+ void * device_data, struct snd_device_ops * ops);
+extern struct snd_card *aoa_get_card(void);
+extern int aoa_snd_ctl_add(struct snd_kcontrol* control);
+
+/* GPIO stuff */
+extern struct gpio_methods *pmf_gpio_methods;
+extern struct gpio_methods *ftr_gpio_methods;
+/* extern struct gpio_methods *map_gpio_methods; */
+
+#endif /* __AOA_H */
diff --git a/sound/aoa/codecs/Kconfig b/sound/aoa/codecs/Kconfig
new file mode 100644
index 0000000..90cf58f
--- /dev/null
+++ b/sound/aoa/codecs/Kconfig
@@ -0,0 +1,32 @@
+config SND_AOA_ONYX
+ tristate "support Onyx chip"
+ depends on SND_AOA
+ ---help---
+ This option enables support for the Onyx (pcm3052)
+ codec chip found in the latest Apple machines
+ (most of those with digital audio output).
+
+#config SND_AOA_TOPAZ
+# tristate "support Topaz chips"
+# depends on SND_AOA
+# ---help---
+# This option enables support for the Topaz (CS84xx)
+# codec chips found in the latest Apple machines,
+# these chips do the digital input and output on
+# some PowerMacs.
+
+config SND_AOA_TAS
+ tristate "support TAS chips"
+ depends on SND_AOA
+ ---help---
+ This option enables support for the tas chips
+ found in a lot of Apple Machines, especially
+ iBooks and PowerBooks without digital.
+
+config SND_AOA_TOONIE
+ tristate "support Toonie chip"
+ depends on SND_AOA
+ ---help---
+ This option enables support for the toonie codec
+ found in the Mac Mini. If you have a Mac Mini and
+ want to hear sound, select this option.
diff --git a/sound/aoa/codecs/Makefile b/sound/aoa/codecs/Makefile
new file mode 100644
index 0000000..31cbe68
--- /dev/null
+++ b/sound/aoa/codecs/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SND_AOA_ONYX) += snd-aoa-codec-onyx.o
+obj-$(CONFIG_SND_AOA_TAS) += snd-aoa-codec-tas.o
+obj-$(CONFIG_SND_AOA_TOONIE) += snd-aoa-codec-toonie.o
diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.c b/sound/aoa/codecs/snd-aoa-codec-onyx.c
new file mode 100644
index 0000000..0b76507
--- /dev/null
+++ b/sound/aoa/codecs/snd-aoa-codec-onyx.c
@@ -0,0 +1,1113 @@
+/*
+ * Apple Onboard Audio driver for Onyx codec
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ *
+ *
+ * This is a driver for the pcm3052 codec chip (codenamed Onyx)
+ * that is present in newer Apple hardware (with digital output).
+ *
+ * The Onyx codec has the following connections (listed by the bit
+ * to be used in aoa_codec.connected):
+ * 0: analog output
+ * 1: digital output
+ * 2: line input
+ * 3: microphone input
+ * Note that even though I know of no machine that has for example
+ * the digital output connected but not the analog, I have handled
+ * all the different cases in the code so that this driver may serve
+ * as a good example of what to do.
+ *
+ * NOTE: This driver assumes that there's at most one chip to be
+ * used with one alsa card, in form of creating all kinds
+ * of mixer elements without regard for their existence.
+ * But snd-aoa assumes that there's at most one card, so
+ * this means you can only have one onyx on a system. This
+ * should probably be fixed by changing the assumption of
+ * having just a single card on a system, and making the
+ * 'card' pointer accessible to anyone who needs it instead
+ * of hiding it in the aoa_snd_* functions...
+ *
+ */
+#include <linux/delay.h>
+#include <linux/module.h>
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("pcm3052 (onyx) codec driver for snd-aoa");
+
+#include "snd-aoa-codec-onyx.h"
+#include "../aoa.h"
+#include "../soundbus/soundbus.h"
+
+
+#define PFX "snd-aoa-codec-onyx: "
+
+struct onyx {
+ /* cache registers 65 to 80, they are write-only! */
+ u8 cache[16];
+ struct i2c_client i2c;
+ struct aoa_codec codec;
+ u32 initialised:1,
+ spdif_locked:1,
+ analog_locked:1,
+ original_mute:2;
+ int open_count;
+ struct codec_info *codec_info;
+
+ /* mutex serializes concurrent access to the device
+ * and this structure.
+ */
+ struct mutex mutex;
+};
+#define codec_to_onyx(c) container_of(c, struct onyx, codec)
+
+/* both return 0 if all ok, else on error */
+static int onyx_read_register(struct onyx *onyx, u8 reg, u8 *value)
+{
+ s32 v;
+
+ if (reg != ONYX_REG_CONTROL) {
+ *value = onyx->cache[reg-FIRSTREGISTER];
+ return 0;
+ }
+ v = i2c_smbus_read_byte_data(&onyx->i2c, reg);
+ if (v < 0)
+ return -1;
+ *value = (u8)v;
+ onyx->cache[ONYX_REG_CONTROL-FIRSTREGISTER] = *value;
+ return 0;
+}
+
+static int onyx_write_register(struct onyx *onyx, u8 reg, u8 value)
+{
+ int result;
+
+ result = i2c_smbus_write_byte_data(&onyx->i2c, reg, value);
+ if (!result)
+ onyx->cache[reg-FIRSTREGISTER] = value;
+ return result;
+}
+
+/* alsa stuff */
+
+static int onyx_dev_register(struct snd_device *dev)
+{
+ return 0;
+}
+
+static struct snd_device_ops ops = {
+ .dev_register = onyx_dev_register,
+};
+
+/* this is necessary because most alsa mixer programs
+ * can't properly handle the negative range */
+#define VOLUME_RANGE_SHIFT 128
+
+static int onyx_snd_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = -128 + VOLUME_RANGE_SHIFT;
+ uinfo->value.integer.max = -1 + VOLUME_RANGE_SHIFT;
+ return 0;
+}
+
+static int onyx_snd_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+ s8 l, r;
+
+ mutex_lock(&onyx->mutex);
+ onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l);
+ onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r);
+ mutex_unlock(&onyx->mutex);
+
+ ucontrol->value.integer.value[0] = l + VOLUME_RANGE_SHIFT;
+ ucontrol->value.integer.value[1] = r + VOLUME_RANGE_SHIFT;
+
+ return 0;
+}
+
+static int onyx_snd_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+ s8 l, r;
+
+ mutex_lock(&onyx->mutex);
+ onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l);
+ onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r);
+
+ if (l + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[0] &&
+ r + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[1]) {
+ mutex_unlock(&onyx->mutex);
+ return 0;
+ }
+
+ onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_LEFT,
+ ucontrol->value.integer.value[0]
+ - VOLUME_RANGE_SHIFT);
+ onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT,
+ ucontrol->value.integer.value[1]
+ - VOLUME_RANGE_SHIFT);
+ mutex_unlock(&onyx->mutex);
+
+ return 1;
+}
+
+static struct snd_kcontrol_new volume_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Volume",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = onyx_snd_vol_info,
+ .get = onyx_snd_vol_get,
+ .put = onyx_snd_vol_put,
+};
+
+/* like above, this is necessary because a lot
+ * of alsa mixer programs don't handle ranges
+ * that don't start at 0 properly.
+ * even alsamixer is one of them... */
+#define INPUTGAIN_RANGE_SHIFT (-3)
+
+static int onyx_snd_inputgain_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 3 + INPUTGAIN_RANGE_SHIFT;
+ uinfo->value.integer.max = 28 + INPUTGAIN_RANGE_SHIFT;
+ return 0;
+}
+
+static int onyx_snd_inputgain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+ u8 ig;
+
+ mutex_lock(&onyx->mutex);
+ onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &ig);
+ mutex_unlock(&onyx->mutex);
+
+ ucontrol->value.integer.value[0] =
+ (ig & ONYX_ADC_PGA_GAIN_MASK) + INPUTGAIN_RANGE_SHIFT;
+
+ return 0;
+}
+
+static int onyx_snd_inputgain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+ u8 v, n;
+
+ mutex_lock(&onyx->mutex);
+ onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
+ n = v;
+ n &= ~ONYX_ADC_PGA_GAIN_MASK;
+ n |= (ucontrol->value.integer.value[0] - INPUTGAIN_RANGE_SHIFT)
+ & ONYX_ADC_PGA_GAIN_MASK;
+ onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, n);
+ mutex_unlock(&onyx->mutex);
+
+ return n != v;
+}
+
+static struct snd_kcontrol_new inputgain_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Capture Volume",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = onyx_snd_inputgain_info,
+ .get = onyx_snd_inputgain_get,
+ .put = onyx_snd_inputgain_put,
+};
+
+static int onyx_snd_capture_source_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[] = { "Line-In", "Microphone" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item > 1)
+ uinfo->value.enumerated.item = 1;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int onyx_snd_capture_source_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+ s8 v;
+
+ mutex_lock(&onyx->mutex);
+ onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
+ mutex_unlock(&onyx->mutex);
+
+ ucontrol->value.enumerated.item[0] = !!(v&ONYX_ADC_INPUT_MIC);
+
+ return 0;
+}
+
+static void onyx_set_capture_source(struct onyx *onyx, int mic)
+{
+ s8 v;
+
+ mutex_lock(&onyx->mutex);
+ onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
+ v &= ~ONYX_ADC_INPUT_MIC;
+ if (mic)
+ v |= ONYX_ADC_INPUT_MIC;
+ onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, v);
+ mutex_unlock(&onyx->mutex);
+}
+
+static int onyx_snd_capture_source_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ onyx_set_capture_source(snd_kcontrol_chip(kcontrol),
+ ucontrol->value.enumerated.item[0]);
+ return 1;
+}
+
+static struct snd_kcontrol_new capture_source_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* If we name this 'Input Source', it properly shows up in
+ * alsamixer as a selection, * but it's shown under the
+ * 'Playback' category.
+ * If I name it 'Capture Source', it shows up in strange
+ * ways (two bools of which one can be selected at a
+ * time) but at least it's shown in the 'Capture'
+ * category.
+ * I was told that this was due to backward compatibility,
+ * but I don't understand then why the mangling is *not*
+ * done when I name it "Input Source".....
+ */
+ .name = "Capture Source",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = onyx_snd_capture_source_info,
+ .get = onyx_snd_capture_source_get,
+ .put = onyx_snd_capture_source_put,
+};
+
+static int onyx_snd_mute_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int onyx_snd_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+ u8 c;
+
+ mutex_lock(&onyx->mutex);
+ onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &c);
+ mutex_unlock(&onyx->mutex);
+
+ ucontrol->value.integer.value[0] = !(c & ONYX_MUTE_LEFT);
+ ucontrol->value.integer.value[1] = !(c & ONYX_MUTE_RIGHT);
+
+ return 0;
+}
+
+static int onyx_snd_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+ u8 v = 0, c = 0;
+ int err = -EBUSY;
+
+ mutex_lock(&onyx->mutex);
+ if (onyx->analog_locked)
+ goto out_unlock;
+
+ onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
+ c = v;
+ c &= ~(ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT);
+ if (!ucontrol->value.integer.value[0])
+ c |= ONYX_MUTE_LEFT;
+ if (!ucontrol->value.integer.value[1])
+ c |= ONYX_MUTE_RIGHT;
+ err = onyx_write_register(onyx, ONYX_REG_DAC_CONTROL, c);
+
+ out_unlock:
+ mutex_unlock(&onyx->mutex);
+
+ return !err ? (v != c) : err;
+}
+
+static struct snd_kcontrol_new mute_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Switch",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = onyx_snd_mute_info,
+ .get = onyx_snd_mute_get,
+ .put = onyx_snd_mute_put,
+};
+
+
+static int onyx_snd_single_bit_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+#define FLAG_POLARITY_INVERT 1
+#define FLAG_SPDIFLOCK 2
+
+static int onyx_snd_single_bit_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+ u8 c;
+ long int pv = kcontrol->private_value;
+ u8 polarity = (pv >> 16) & FLAG_POLARITY_INVERT;
+ u8 address = (pv >> 8) & 0xff;
+ u8 mask = pv & 0xff;
+
+ mutex_lock(&onyx->mutex);
+ onyx_read_register(onyx, address, &c);
+ mutex_unlock(&onyx->mutex);
+
+ ucontrol->value.integer.value[0] = !!(c & mask) ^ polarity;
+
+ return 0;
+}
+
+static int onyx_snd_single_bit_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+ u8 v = 0, c = 0;
+ int err;
+ long int pv = kcontrol->private_value;
+ u8 polarity = (pv >> 16) & FLAG_POLARITY_INVERT;
+ u8 spdiflock = (pv >> 16) & FLAG_SPDIFLOCK;
+ u8 address = (pv >> 8) & 0xff;
+ u8 mask = pv & 0xff;
+
+ mutex_lock(&onyx->mutex);
+ if (spdiflock && onyx->spdif_locked) {
+ /* even if alsamixer doesn't care.. */
+ err = -EBUSY;
+ goto out_unlock;
+ }
+ onyx_read_register(onyx, address, &v);
+ c = v;
+ c &= ~(mask);
+ if (!!ucontrol->value.integer.value[0] ^ polarity)
+ c |= mask;
+ err = onyx_write_register(onyx, address, c);
+
+ out_unlock:
+ mutex_unlock(&onyx->mutex);
+
+ return !err ? (v != c) : err;
+}
+
+#define SINGLE_BIT(n, type, description, address, mask, flags) \
+static struct snd_kcontrol_new n##_control = { \
+ .iface = SNDRV_CTL_ELEM_IFACE_##type, \
+ .name = description, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .info = onyx_snd_single_bit_info, \
+ .get = onyx_snd_single_bit_get, \
+ .put = onyx_snd_single_bit_put, \
+ .private_value = (flags << 16) | (address << 8) | mask \
+}
+
+SINGLE_BIT(spdif,
+ MIXER,
+ SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH),
+ ONYX_REG_DIG_INFO4,
+ ONYX_SPDIF_ENABLE,
+ FLAG_SPDIFLOCK);
+SINGLE_BIT(ovr1,
+ MIXER,
+ "Oversampling Rate",
+ ONYX_REG_DAC_CONTROL,
+ ONYX_OVR1,
+ 0);
+SINGLE_BIT(flt0,
+ MIXER,
+ "Fast Digital Filter Rolloff",
+ ONYX_REG_DAC_FILTER,
+ ONYX_ROLLOFF_FAST,
+ FLAG_POLARITY_INVERT);
+SINGLE_BIT(hpf,
+ MIXER,
+ "Highpass Filter",
+ ONYX_REG_ADC_HPF_BYPASS,
+ ONYX_HPF_DISABLE,
+ FLAG_POLARITY_INVERT);
+SINGLE_BIT(dm12,
+ MIXER,
+ "Digital De-Emphasis",
+ ONYX_REG_DAC_DEEMPH,
+ ONYX_DIGDEEMPH_CTRL,
+ 0);
+
+static int onyx_spdif_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+ uinfo->count = 1;
+ return 0;
+}
+
+static int onyx_spdif_mask_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /* datasheet page 30, all others are 0 */
+ ucontrol->value.iec958.status[0] = 0x3e;
+ ucontrol->value.iec958.status[1] = 0xff;
+
+ ucontrol->value.iec958.status[3] = 0x3f;
+ ucontrol->value.iec958.status[4] = 0x0f;
+
+ return 0;
+}
+
+static struct snd_kcontrol_new onyx_spdif_mask = {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
+ .info = onyx_spdif_info,
+ .get = onyx_spdif_mask_get,
+};
+
+static int onyx_spdif_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+ u8 v;
+
+ mutex_lock(&onyx->mutex);
+ onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v);
+ ucontrol->value.iec958.status[0] = v & 0x3e;
+
+ onyx_read_register(onyx, ONYX_REG_DIG_INFO2, &v);
+ ucontrol->value.iec958.status[1] = v;
+
+ onyx_read_register(onyx, ONYX_REG_DIG_INFO3, &v);
+ ucontrol->value.iec958.status[3] = v & 0x3f;
+
+ onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
+ ucontrol->value.iec958.status[4] = v & 0x0f;
+ mutex_unlock(&onyx->mutex);
+
+ return 0;
+}
+
+static int onyx_spdif_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+ u8 v;
+
+ mutex_lock(&onyx->mutex);
+ onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v);
+ v = (v & ~0x3e) | (ucontrol->value.iec958.status[0] & 0x3e);
+ onyx_write_register(onyx, ONYX_REG_DIG_INFO1, v);
+
+ v = ucontrol->value.iec958.status[1];
+ onyx_write_register(onyx, ONYX_REG_DIG_INFO2, v);
+
+ onyx_read_register(onyx, ONYX_REG_DIG_INFO3, &v);
+ v = (v & ~0x3f) | (ucontrol->value.iec958.status[3] & 0x3f);
+ onyx_write_register(onyx, ONYX_REG_DIG_INFO3, v);
+
+ onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
+ v = (v & ~0x0f) | (ucontrol->value.iec958.status[4] & 0x0f);
+ onyx_write_register(onyx, ONYX_REG_DIG_INFO4, v);
+ mutex_unlock(&onyx->mutex);
+
+ return 1;
+}
+
+static struct snd_kcontrol_new onyx_spdif_ctrl = {
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
+ .info = onyx_spdif_info,
+ .get = onyx_spdif_get,
+ .put = onyx_spdif_put,
+};
+
+/* our registers */
+
+static u8 register_map[] = {
+ ONYX_REG_DAC_ATTEN_LEFT,
+ ONYX_REG_DAC_ATTEN_RIGHT,
+ ONYX_REG_CONTROL,
+ ONYX_REG_DAC_CONTROL,
+ ONYX_REG_DAC_DEEMPH,
+ ONYX_REG_DAC_FILTER,
+ ONYX_REG_DAC_OUTPHASE,
+ ONYX_REG_ADC_CONTROL,
+ ONYX_REG_ADC_HPF_BYPASS,
+ ONYX_REG_DIG_INFO1,
+ ONYX_REG_DIG_INFO2,
+ ONYX_REG_DIG_INFO3,
+ ONYX_REG_DIG_INFO4
+};
+
+static u8 initial_values[ARRAY_SIZE(register_map)] = {
+ 0x80, 0x80, /* muted */
+ ONYX_MRST | ONYX_SRST, /* but handled specially! */
+ ONYX_MUTE_LEFT | ONYX_MUTE_RIGHT,
+ 0, /* no deemphasis */
+ ONYX_DAC_FILTER_ALWAYS,
+ ONYX_OUTPHASE_INVERTED,
+ (-1 /*dB*/ + 8) & 0xF, /* line in selected, -1 dB gain*/
+ ONYX_ADC_HPF_ALWAYS,
+ (1<<2), /* pcm audio */
+ 2, /* category: pcm coder */
+ 0, /* sampling frequency 44.1 kHz, clock accuracy level II */
+ 1 /* 24 bit depth */
+};
+
+/* reset registers of chip, either to initial or to previous values */
+static int onyx_register_init(struct onyx *onyx)
+{
+ int i;
+ u8 val;
+ u8 regs[sizeof(initial_values)];
+
+ if (!onyx->initialised) {
+ memcpy(regs, initial_values, sizeof(initial_values));
+ if (onyx_read_register(onyx, ONYX_REG_CONTROL, &val))
+ return -1;
+ val &= ~ONYX_SILICONVERSION;
+ val |= initial_values[3];
+ regs[3] = val;
+ } else {
+ for (i=0; i<sizeof(register_map); i++)
+ regs[i] = onyx->cache[register_map[i]-FIRSTREGISTER];
+ }
+
+ for (i=0; i<sizeof(register_map); i++) {
+ if (onyx_write_register(onyx, register_map[i], regs[i]))
+ return -1;
+ }
+ onyx->initialised = 1;
+ return 0;
+}
+
+static struct transfer_info onyx_transfers[] = {
+ /* this is first so we can skip it if no input is present...
+ * No hardware exists with that, but it's here as an example
+ * of what to do :) */
+ {
+ /* analog input */
+ .formats = SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_BE |
+ SNDRV_PCM_FMTBIT_S24_BE,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .transfer_in = 1,
+ .must_be_clock_source = 0,
+ .tag = 0,
+ },
+ {
+ /* if analog and digital are currently off, anything should go,
+ * so this entry describes everything we can do... */
+ .formats = SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_BE |
+ SNDRV_PCM_FMTBIT_S24_BE
+#ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE
+ | SNDRV_PCM_FMTBIT_COMPRESSED_16BE
+#endif
+ ,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .tag = 0,
+ },
+ {
+ /* analog output */
+ .formats = SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_BE |
+ SNDRV_PCM_FMTBIT_S24_BE,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .transfer_in = 0,
+ .must_be_clock_source = 0,
+ .tag = 1,
+ },
+ {
+ /* digital pcm output, also possible for analog out */
+ .formats = SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_BE |
+ SNDRV_PCM_FMTBIT_S24_BE,
+ .rates = SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000,
+ .transfer_in = 0,
+ .must_be_clock_source = 0,
+ .tag = 2,
+ },
+#ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE
+Once alsa gets supports for this kind of thing we can add it...
+ {
+ /* digital compressed output */
+ .formats = SNDRV_PCM_FMTBIT_COMPRESSED_16BE,
+ .rates = SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000,
+ .tag = 2,
+ },
+#endif
+ {}
+};
+
+static int onyx_usable(struct codec_info_item *cii,
+ struct transfer_info *ti,
+ struct transfer_info *out)
+{
+ u8 v;
+ struct onyx *onyx = cii->codec_data;
+ int spdif_enabled, analog_enabled;
+
+ mutex_lock(&onyx->mutex);
+ onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
+ spdif_enabled = !!(v & ONYX_SPDIF_ENABLE);
+ onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
+ analog_enabled =
+ (v & (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT))
+ != (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT);
+ mutex_unlock(&onyx->mutex);
+
+ switch (ti->tag) {
+ case 0: return 1;
+ case 1: return analog_enabled;
+ case 2: return spdif_enabled;
+ }
+ return 1;
+}
+
+static int onyx_prepare(struct codec_info_item *cii,
+ struct bus_info *bi,
+ struct snd_pcm_substream *substream)
+{
+ u8 v;
+ struct onyx *onyx = cii->codec_data;
+ int err = -EBUSY;
+
+ mutex_lock(&onyx->mutex);
+
+#ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE
+ if (substream->runtime->format == SNDRV_PCM_FMTBIT_COMPRESSED_16BE) {
+ /* mute and lock analog output */
+ onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
+ if (onyx_write_register(onyx
+ ONYX_REG_DAC_CONTROL,
+ v | ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT))
+ goto out_unlock;
+ onyx->analog_locked = 1;
+ err = 0;
+ goto out_unlock;
+ }
+#endif
+ switch (substream->runtime->rate) {
+ case 32000:
+ case 44100:
+ case 48000:
+ /* these rates are ok for all outputs */
+ /* FIXME: program spdif channel control bits here so that
+ * userspace doesn't have to if it only plays pcm! */
+ err = 0;
+ goto out_unlock;
+ default:
+ /* got some rate that the digital output can't do,
+ * so disable and lock it */
+ onyx_read_register(cii->codec_data, ONYX_REG_DIG_INFO4, &v);
+ if (onyx_write_register(onyx,
+ ONYX_REG_DIG_INFO4,
+ v & ~ONYX_SPDIF_ENABLE))
+ goto out_unlock;
+ onyx->spdif_locked = 1;
+ err = 0;
+ goto out_unlock;
+ }
+
+ out_unlock:
+ mutex_unlock(&onyx->mutex);
+
+ return err;
+}
+
+static int onyx_open(struct codec_info_item *cii,
+ struct snd_pcm_substream *substream)
+{
+ struct onyx *onyx = cii->codec_data;
+
+ mutex_lock(&onyx->mutex);
+ onyx->open_count++;
+ mutex_unlock(&onyx->mutex);
+
+ return 0;
+}
+
+static int onyx_close(struct codec_info_item *cii,
+ struct snd_pcm_substream *substream)
+{
+ struct onyx *onyx = cii->codec_data;
+
+ mutex_lock(&onyx->mutex);
+ onyx->open_count--;
+ if (!onyx->open_count)
+ onyx->spdif_locked = onyx->analog_locked = 0;
+ mutex_unlock(&onyx->mutex);
+
+ return 0;
+}
+
+static int onyx_switch_clock(struct codec_info_item *cii,
+ enum clock_switch what)
+{
+ struct onyx *onyx = cii->codec_data;
+
+ mutex_lock(&onyx->mutex);
+ /* this *MUST* be more elaborate later... */
+ switch (what) {
+ case CLOCK_SWITCH_PREPARE_SLAVE:
+ onyx->codec.gpio->methods->all_amps_off(onyx->codec.gpio);
+ break;
+ case CLOCK_SWITCH_SLAVE:
+ onyx->codec.gpio->methods->all_amps_restore(onyx->codec.gpio);
+ break;
+ default: /* silence warning */
+ break;
+ }
+ mutex_unlock(&onyx->mutex);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int onyx_suspend(struct codec_info_item *cii, pm_message_t state)
+{
+ struct onyx *onyx = cii->codec_data;
+ u8 v;
+ int err = -ENXIO;
+
+ mutex_lock(&onyx->mutex);
+ if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))
+ goto out_unlock;
+ onyx_write_register(onyx, ONYX_REG_CONTROL, v | ONYX_ADPSV | ONYX_DAPSV);
+ /* Apple does a sleep here but the datasheet says to do it on resume */
+ err = 0;
+ out_unlock:
+ mutex_unlock(&onyx->mutex);
+
+ return err;
+}
+
+static int onyx_resume(struct codec_info_item *cii)
+{
+ struct onyx *onyx = cii->codec_data;
+ u8 v;
+ int err = -ENXIO;
+
+ mutex_lock(&onyx->mutex);
+ /* take codec out of suspend */
+ if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))
+ goto out_unlock;
+ onyx_write_register(onyx, ONYX_REG_CONTROL, v & ~(ONYX_ADPSV | ONYX_DAPSV));
+ /* FIXME: should divide by sample rate, but 8k is the lowest we go */
+ msleep(2205000/8000);
+ /* reset all values */
+ onyx_register_init(onyx);
+ err = 0;
+ out_unlock:
+ mutex_unlock(&onyx->mutex);
+
+ return err;
+}
+
+#endif /* CONFIG_PM */
+
+static struct codec_info onyx_codec_info = {
+ .transfers = onyx_transfers,
+ .sysclock_factor = 256,
+ .bus_factor = 64,
+ .owner = THIS_MODULE,
+ .usable = onyx_usable,
+ .prepare = onyx_prepare,
+ .open = onyx_open,
+ .close = onyx_close,
+ .switch_clock = onyx_switch_clock,
+#ifdef CONFIG_PM
+ .suspend = onyx_suspend,
+ .resume = onyx_resume,
+#endif
+};
+
+static int onyx_init_codec(struct aoa_codec *codec)
+{
+ struct onyx *onyx = codec_to_onyx(codec);
+ struct snd_kcontrol *ctl;
+ struct codec_info *ci = &onyx_codec_info;
+ u8 v;
+ int err;
+
+ if (!onyx->codec.gpio || !onyx->codec.gpio->methods) {
+ printk(KERN_ERR PFX "gpios not assigned!!\n");
+ return -EINVAL;
+ }
+
+ onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
+ msleep(1);
+ onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 1);
+ msleep(1);
+ onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
+ msleep(1);
+
+ if (onyx_register_init(onyx)) {
+ printk(KERN_ERR PFX "failed to initialise onyx registers\n");
+ return -ENODEV;
+ }
+
+ if (aoa_snd_device_new(SNDRV_DEV_LOWLEVEL, onyx, &ops)) {
+ printk(KERN_ERR PFX "failed to create onyx snd device!\n");
+ return -ENODEV;
+ }
+
+ /* nothing connected? what a joke! */
+ if ((onyx->codec.connected & 0xF) == 0)
+ return -ENOTCONN;
+
+ /* if no inputs are present... */
+ if ((onyx->codec.connected & 0xC) == 0) {
+ if (!onyx->codec_info)
+ onyx->codec_info = kmalloc(sizeof(struct codec_info), GFP_KERNEL);
+ if (!onyx->codec_info)
+ return -ENOMEM;
+ ci = onyx->codec_info;
+ *ci = onyx_codec_info;
+ ci->transfers++;
+ }
+
+ /* if no outputs are present... */
+ if ((onyx->codec.connected & 3) == 0) {
+ if (!onyx->codec_info)
+ onyx->codec_info = kmalloc(sizeof(struct codec_info), GFP_KERNEL);
+ if (!onyx->codec_info)
+ return -ENOMEM;
+ ci = onyx->codec_info;
+ /* this is fine as there have to be inputs
+ * if we end up in this part of the code */
+ *ci = onyx_codec_info;
+ ci->transfers[1].formats = 0;
+ }
+
+ if (onyx->codec.soundbus_dev->attach_codec(onyx->codec.soundbus_dev,
+ aoa_get_card(),
+ ci, onyx)) {
+ printk(KERN_ERR PFX "error creating onyx pcm\n");
+ return -ENODEV;
+ }
+#define ADDCTL(n) \
+ do { \
+ ctl = snd_ctl_new1(&n, onyx); \
+ if (ctl) { \
+ ctl->id.device = \
+ onyx->codec.soundbus_dev->pcm->device; \
+ err = aoa_snd_ctl_add(ctl); \
+ if (err) \
+ goto error; \
+ } \
+ } while (0)
+
+ if (onyx->codec.soundbus_dev->pcm) {
+ /* give the user appropriate controls
+ * depending on what inputs are connected */
+ if ((onyx->codec.connected & 0xC) == 0xC)
+ ADDCTL(capture_source_control);
+ else if (onyx->codec.connected & 4)
+ onyx_set_capture_source(onyx, 0);
+ else
+ onyx_set_capture_source(onyx, 1);
+ if (onyx->codec.connected & 0xC)
+ ADDCTL(inputgain_control);
+
+ /* depending on what output is connected,
+ * give the user appropriate controls */
+ if (onyx->codec.connected & 1) {
+ ADDCTL(volume_control);
+ ADDCTL(mute_control);
+ ADDCTL(ovr1_control);
+ ADDCTL(flt0_control);
+ ADDCTL(hpf_control);
+ ADDCTL(dm12_control);
+ /* spdif control defaults to off */
+ }
+ if (onyx->codec.connected & 2) {
+ ADDCTL(onyx_spdif_mask);
+ ADDCTL(onyx_spdif_ctrl);
+ }
+ if ((onyx->codec.connected & 3) == 3)
+ ADDCTL(spdif_control);
+ /* if only S/PDIF is connected, enable it unconditionally */
+ if ((onyx->codec.connected & 3) == 2) {
+ onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
+ v |= ONYX_SPDIF_ENABLE;
+ onyx_write_register(onyx, ONYX_REG_DIG_INFO4, v);
+ }
+ }
+#undef ADDCTL
+ printk(KERN_INFO PFX "attached to onyx codec via i2c\n");
+
+ return 0;
+ error:
+ onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx);
+ snd_device_free(aoa_get_card(), onyx);
+ return err;
+}
+
+static void onyx_exit_codec(struct aoa_codec *codec)
+{
+ struct onyx *onyx = codec_to_onyx(codec);
+
+ if (!onyx->codec.soundbus_dev) {
+ printk(KERN_ERR PFX "onyx_exit_codec called without soundbus_dev!\n");
+ return;
+ }
+ onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx);
+}
+
+static struct i2c_driver onyx_driver;
+
+static int onyx_create(struct i2c_adapter *adapter,
+ struct device_node *node,
+ int addr)
+{
+ struct onyx *onyx;
+ u8 dummy;
+
+ onyx = kzalloc(sizeof(struct onyx), GFP_KERNEL);
+
+ if (!onyx)
+ return -ENOMEM;
+
+ mutex_init(&onyx->mutex);
+ onyx->i2c.driver = &onyx_driver;
+ onyx->i2c.adapter = adapter;
+ onyx->i2c.addr = addr & 0x7f;
+ strlcpy(onyx->i2c.name, "onyx audio codec", I2C_NAME_SIZE-1);
+
+ if (i2c_attach_client(&onyx->i2c)) {
+ printk(KERN_ERR PFX "failed to attach to i2c\n");
+ goto fail;
+ }
+
+ /* we try to read from register ONYX_REG_CONTROL
+ * to check if the codec is present */
+ if (onyx_read_register(onyx, ONYX_REG_CONTROL, &dummy) != 0) {
+ i2c_detach_client(&onyx->i2c);
+ printk(KERN_ERR PFX "failed to read control register\n");
+ goto fail;
+ }
+
+ strlcpy(onyx->codec.name, "onyx", MAX_CODEC_NAME_LEN-1);
+ onyx->codec.owner = THIS_MODULE;
+ onyx->codec.init = onyx_init_codec;
+ onyx->codec.exit = onyx_exit_codec;
+ onyx->codec.node = of_node_get(node);
+
+ if (aoa_codec_register(&onyx->codec)) {
+ i2c_detach_client(&onyx->i2c);
+ goto fail;
+ }
+ printk(KERN_DEBUG PFX "created and attached onyx instance\n");
+ return 0;
+ fail:
+ kfree(onyx);
+ return -EINVAL;
+}
+
+static int onyx_i2c_attach(struct i2c_adapter *adapter)
+{
+ struct device_node *busnode, *dev = NULL;
+ struct pmac_i2c_bus *bus;
+
+ bus = pmac_i2c_adapter_to_bus(adapter);
+ if (bus == NULL)
+ return -ENODEV;
+ busnode = pmac_i2c_get_bus_node(bus);
+
+ while ((dev = of_get_next_child(busnode, dev)) != NULL) {
+ if (device_is_compatible(dev, "pcm3052")) {
+ u32 *addr;
+ printk(KERN_DEBUG PFX "found pcm3052\n");
+ addr = (u32 *) get_property(dev, "reg", NULL);
+ if (!addr)
+ return -ENODEV;
+ return onyx_create(adapter, dev, (*addr)>>1);
+ }
+ }
+
+ /* if that didn't work, try desperate mode for older
+ * machines that have stuff missing from the device tree */
+
+ if (!device_is_compatible(busnode, "k2-i2c"))
+ return -ENODEV;
+
+ printk(KERN_DEBUG PFX "found k2-i2c, checking if onyx chip is on it\n");
+ /* probe both possible addresses for the onyx chip */
+ if (onyx_create(adapter, NULL, 0x46) == 0)
+ return 0;
+ return onyx_create(adapter, NULL, 0x47);
+}
+
+static int onyx_i2c_detach(struct i2c_client *client)
+{
+ struct onyx *onyx = container_of(client, struct onyx, i2c);
+ int err;
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+ aoa_codec_unregister(&onyx->codec);
+ of_node_put(onyx->codec.node);
+ if (onyx->codec_info)
+ kfree(onyx->codec_info);
+ kfree(onyx);
+ return 0;
+}
+
+static struct i2c_driver onyx_driver = {
+ .driver = {
+ .name = "aoa_codec_onyx",
+ .owner = THIS_MODULE,
+ },
+ .attach_adapter = onyx_i2c_attach,
+ .detach_client = onyx_i2c_detach,
+};
+
+static int __init onyx_init(void)
+{
+ return i2c_add_driver(&onyx_driver);
+}
+
+static void __exit onyx_exit(void)
+{
+ i2c_del_driver(&onyx_driver);
+}
+
+module_init(onyx_init);
+module_exit(onyx_exit);
diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.h b/sound/aoa/codecs/snd-aoa-codec-onyx.h
new file mode 100644
index 0000000..aeedda7
--- /dev/null
+++ b/sound/aoa/codecs/snd-aoa-codec-onyx.h
@@ -0,0 +1,76 @@
+/*
+ * Apple Onboard Audio driver for Onyx codec (header)
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+#ifndef __SND_AOA_CODEC_ONYX_H
+#define __SND_AOA_CODEC_ONYX_H
+#include <stddef.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <asm/pmac_low_i2c.h>
+#include <asm/prom.h>
+
+/* PCM3052 register definitions */
+
+/* the attenuation registers take values from
+ * -1 (0dB) to -127 (-63.0 dB) or others (muted) */
+#define ONYX_REG_DAC_ATTEN_LEFT 65
+#define FIRSTREGISTER ONYX_REG_DAC_ATTEN_LEFT
+#define ONYX_REG_DAC_ATTEN_RIGHT 66
+
+#define ONYX_REG_CONTROL 67
+# define ONYX_MRST (1<<7)
+# define ONYX_SRST (1<<6)
+# define ONYX_ADPSV (1<<5)
+# define ONYX_DAPSV (1<<4)
+# define ONYX_SILICONVERSION (1<<0)
+/* all others reserved */
+
+#define ONYX_REG_DAC_CONTROL 68
+# define ONYX_OVR1 (1<<6)
+# define ONYX_MUTE_RIGHT (1<<1)
+# define ONYX_MUTE_LEFT (1<<0)
+
+#define ONYX_REG_DAC_DEEMPH 69
+# define ONYX_DIGDEEMPH_SHIFT 5
+# define ONYX_DIGDEEMPH_MASK (3<<ONYX_DIGDEEMPH_SHIFT)
+# define ONYX_DIGDEEMPH_CTRL (1<<4)
+
+#define ONYX_REG_DAC_FILTER 70
+# define ONYX_ROLLOFF_FAST (1<<5)
+# define ONYX_DAC_FILTER_ALWAYS (1<<2)
+
+#define ONYX_REG_DAC_OUTPHASE 71
+# define ONYX_OUTPHASE_INVERTED (1<<0)
+
+#define ONYX_REG_ADC_CONTROL 72
+# define ONYX_ADC_INPUT_MIC (1<<5)
+/* 8 + input gain in dB, valid range for input gain is -4 .. 20 dB */
+# define ONYX_ADC_PGA_GAIN_MASK 0x1f
+
+#define ONYX_REG_ADC_HPF_BYPASS 75
+# define ONYX_HPF_DISABLE (1<<3)
+# define ONYX_ADC_HPF_ALWAYS (1<<2)
+
+#define ONYX_REG_DIG_INFO1 77
+# define ONYX_MASK_DIN_TO_BPZ (1<<7)
+/* bits 1-5 control channel bits 1-5 */
+# define ONYX_DIGOUT_DISABLE (1<<0)
+
+#define ONYX_REG_DIG_INFO2 78
+/* controls channel bits 8-15 */
+
+#define ONYX_REG_DIG_INFO3 79
+/* control channel bits 24-29, high 2 bits reserved */
+
+#define ONYX_REG_DIG_INFO4 80
+# define ONYX_VALIDL (1<<7)
+# define ONYX_VALIDR (1<<6)
+# define ONYX_SPDIF_ENABLE (1<<5)
+/* lower 4 bits control bits 32-35 of channel control and word length */
+# define ONYX_WORDLEN_MASK (0xF)
+
+#endif /* __SND_AOA_CODEC_ONYX_H */
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas-gain-table.h b/sound/aoa/codecs/snd-aoa-codec-tas-gain-table.h
new file mode 100644
index 0000000..4cfa675
--- /dev/null
+++ b/sound/aoa/codecs/snd-aoa-codec-tas-gain-table.h
@@ -0,0 +1,209 @@
+/*
+ This is the program used to generate below table.
+
+#include <stdio.h>
+#include <math.h>
+int main() {
+ int dB2;
+ printf("/" "* This file is only included exactly once!\n");
+ printf(" *\n");
+ printf(" * If they'd only tell us that generating this table was\n");
+ printf(" * as easy as calculating\n");
+ printf(" * hwvalue = 1048576.0*exp(0.057564628*dB*2)\n");
+ printf(" * :) *" "/\n");
+ printf("static int tas_gaintable[] = {\n");
+ printf(" 0x000000, /" "* -infinity dB *" "/\n");
+ for (dB2=-140;dB2<=36;dB2++)
+ printf(" 0x%.6x, /" "* %-02.1f dB *" "/\n", (int)(1048576.0*exp(0.057564628*dB2)), dB2/2.0);
+ printf("};\n\n");
+}
+
+*/
+
+/* This file is only included exactly once!
+ *
+ * If they'd only tell us that generating this table was
+ * as easy as calculating
+ * hwvalue = 1048576.0*exp(0.057564628*dB*2)
+ * :) */
+static int tas_gaintable[] = {
+ 0x000000, /* -infinity dB */
+ 0x00014b, /* -70.0 dB */
+ 0x00015f, /* -69.5 dB */
+ 0x000174, /* -69.0 dB */
+ 0x00018a, /* -68.5 dB */
+ 0x0001a1, /* -68.0 dB */
+ 0x0001ba, /* -67.5 dB */
+ 0x0001d4, /* -67.0 dB */
+ 0x0001f0, /* -66.5 dB */
+ 0x00020d, /* -66.0 dB */
+ 0x00022c, /* -65.5 dB */
+ 0x00024d, /* -65.0 dB */
+ 0x000270, /* -64.5 dB */
+ 0x000295, /* -64.0 dB */
+ 0x0002bc, /* -63.5 dB */
+ 0x0002e6, /* -63.0 dB */
+ 0x000312, /* -62.5 dB */
+ 0x000340, /* -62.0 dB */
+ 0x000372, /* -61.5 dB */
+ 0x0003a6, /* -61.0 dB */
+ 0x0003dd, /* -60.5 dB */
+ 0x000418, /* -60.0 dB */
+ 0x000456, /* -59.5 dB */
+ 0x000498, /* -59.0 dB */
+ 0x0004de, /* -58.5 dB */
+ 0x000528, /* -58.0 dB */
+ 0x000576, /* -57.5 dB */
+ 0x0005c9, /* -57.0 dB */
+ 0x000620, /* -56.5 dB */
+ 0x00067d, /* -56.0 dB */
+ 0x0006e0, /* -55.5 dB */
+ 0x000748, /* -55.0 dB */
+ 0x0007b7, /* -54.5 dB */
+ 0x00082c, /* -54.0 dB */
+ 0x0008a8, /* -53.5 dB */
+ 0x00092b, /* -53.0 dB */
+ 0x0009b6, /* -52.5 dB */
+ 0x000a49, /* -52.0 dB */
+ 0x000ae5, /* -51.5 dB */
+ 0x000b8b, /* -51.0 dB */
+ 0x000c3a, /* -50.5 dB */
+ 0x000cf3, /* -50.0 dB */
+ 0x000db8, /* -49.5 dB */
+ 0x000e88, /* -49.0 dB */
+ 0x000f64, /* -48.5 dB */
+ 0x00104e, /* -48.0 dB */
+ 0x001145, /* -47.5 dB */
+ 0x00124b, /* -47.0 dB */
+ 0x001361, /* -46.5 dB */
+ 0x001487, /* -46.0 dB */
+ 0x0015be, /* -45.5 dB */
+ 0x001708, /* -45.0 dB */
+ 0x001865, /* -44.5 dB */
+ 0x0019d8, /* -44.0 dB */
+ 0x001b60, /* -43.5 dB */
+ 0x001cff, /* -43.0 dB */
+ 0x001eb7, /* -42.5 dB */
+ 0x002089, /* -42.0 dB */
+ 0x002276, /* -41.5 dB */
+ 0x002481, /* -41.0 dB */
+ 0x0026ab, /* -40.5 dB */
+ 0x0028f5, /* -40.0 dB */
+ 0x002b63, /* -39.5 dB */
+ 0x002df5, /* -39.0 dB */
+ 0x0030ae, /* -38.5 dB */
+ 0x003390, /* -38.0 dB */
+ 0x00369e, /* -37.5 dB */
+ 0x0039db, /* -37.0 dB */
+ 0x003d49, /* -36.5 dB */
+ 0x0040ea, /* -36.0 dB */
+ 0x0044c3, /* -35.5 dB */
+ 0x0048d6, /* -35.0 dB */
+ 0x004d27, /* -34.5 dB */
+ 0x0051b9, /* -34.0 dB */
+ 0x005691, /* -33.5 dB */
+ 0x005bb2, /* -33.0 dB */
+ 0x006121, /* -32.5 dB */
+ 0x0066e3, /* -32.0 dB */
+ 0x006cfb, /* -31.5 dB */
+ 0x007370, /* -31.0 dB */
+ 0x007a48, /* -30.5 dB */
+ 0x008186, /* -30.0 dB */
+ 0x008933, /* -29.5 dB */
+ 0x009154, /* -29.0 dB */
+ 0x0099f1, /* -28.5 dB */
+ 0x00a310, /* -28.0 dB */
+ 0x00acba, /* -27.5 dB */
+ 0x00b6f6, /* -27.0 dB */
+ 0x00c1cd, /* -26.5 dB */
+ 0x00cd49, /* -26.0 dB */
+ 0x00d973, /* -25.5 dB */
+ 0x00e655, /* -25.0 dB */
+ 0x00f3fb, /* -24.5 dB */
+ 0x010270, /* -24.0 dB */
+ 0x0111c0, /* -23.5 dB */
+ 0x0121f9, /* -23.0 dB */
+ 0x013328, /* -22.5 dB */
+ 0x01455b, /* -22.0 dB */
+ 0x0158a2, /* -21.5 dB */
+ 0x016d0e, /* -21.0 dB */
+ 0x0182af, /* -20.5 dB */
+ 0x019999, /* -20.0 dB */
+ 0x01b1de, /* -19.5 dB */
+ 0x01cb94, /* -19.0 dB */
+ 0x01e6cf, /* -18.5 dB */
+ 0x0203a7, /* -18.0 dB */
+ 0x022235, /* -17.5 dB */
+ 0x024293, /* -17.0 dB */
+ 0x0264db, /* -16.5 dB */
+ 0x02892c, /* -16.0 dB */
+ 0x02afa3, /* -15.5 dB */
+ 0x02d862, /* -15.0 dB */
+ 0x03038a, /* -14.5 dB */
+ 0x033142, /* -14.0 dB */
+ 0x0361af, /* -13.5 dB */
+ 0x0394fa, /* -13.0 dB */
+ 0x03cb50, /* -12.5 dB */
+ 0x0404de, /* -12.0 dB */
+ 0x0441d5, /* -11.5 dB */
+ 0x048268, /* -11.0 dB */
+ 0x04c6d0, /* -10.5 dB */
+ 0x050f44, /* -10.0 dB */
+ 0x055c04, /* -9.5 dB */
+ 0x05ad50, /* -9.0 dB */
+ 0x06036e, /* -8.5 dB */
+ 0x065ea5, /* -8.0 dB */
+ 0x06bf44, /* -7.5 dB */
+ 0x07259d, /* -7.0 dB */
+ 0x079207, /* -6.5 dB */
+ 0x0804dc, /* -6.0 dB */
+ 0x087e80, /* -5.5 dB */
+ 0x08ff59, /* -5.0 dB */
+ 0x0987d5, /* -4.5 dB */
+ 0x0a1866, /* -4.0 dB */
+ 0x0ab189, /* -3.5 dB */
+ 0x0b53be, /* -3.0 dB */
+ 0x0bff91, /* -2.5 dB */
+ 0x0cb591, /* -2.0 dB */
+ 0x0d765a, /* -1.5 dB */
+ 0x0e4290, /* -1.0 dB */
+ 0x0f1adf, /* -0.5 dB */
+ 0x100000, /* 0.0 dB */
+ 0x10f2b4, /* 0.5 dB */
+ 0x11f3c9, /* 1.0 dB */
+ 0x13041a, /* 1.5 dB */
+ 0x14248e, /* 2.0 dB */
+ 0x15561a, /* 2.5 dB */
+ 0x1699c0, /* 3.0 dB */
+ 0x17f094, /* 3.5 dB */
+ 0x195bb8, /* 4.0 dB */
+ 0x1adc61, /* 4.5 dB */
+ 0x1c73d5, /* 5.0 dB */
+ 0x1e236d, /* 5.5 dB */
+ 0x1fec98, /* 6.0 dB */
+ 0x21d0d9, /* 6.5 dB */
+ 0x23d1cd, /* 7.0 dB */
+ 0x25f125, /* 7.5 dB */
+ 0x2830af, /* 8.0 dB */
+ 0x2a9254, /* 8.5 dB */
+ 0x2d1818, /* 9.0 dB */
+ 0x2fc420, /* 9.5 dB */
+ 0x3298b0, /* 10.0 dB */
+ 0x35982f, /* 10.5 dB */
+ 0x38c528, /* 11.0 dB */
+ 0x3c224c, /* 11.5 dB */
+ 0x3fb278, /* 12.0 dB */
+ 0x4378b0, /* 12.5 dB */
+ 0x477829, /* 13.0 dB */
+ 0x4bb446, /* 13.5 dB */
+ 0x5030a1, /* 14.0 dB */
+ 0x54f106, /* 14.5 dB */
+ 0x59f980, /* 15.0 dB */
+ 0x5f4e52, /* 15.5 dB */
+ 0x64f403, /* 16.0 dB */
+ 0x6aef5e, /* 16.5 dB */
+ 0x714575, /* 17.0 dB */
+ 0x77fbaa, /* 17.5 dB */
+ 0x7f17af, /* 18.0 dB */
+};
+
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c
new file mode 100644
index 0000000..2e39ff6
--- /dev/null
+++ b/sound/aoa/codecs/snd-aoa-codec-tas.c
@@ -0,0 +1,654 @@
+/*
+ * Apple Onboard Audio driver for tas codec
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ *
+ * Open questions:
+ * - How to distinguish between 3004 and versions?
+ *
+ * FIXMEs:
+ * - This codec driver doesn't honour the 'connected'
+ * property of the aoa_codec struct, hence if
+ * it is used in machines where not everything is
+ * connected it will display wrong mixer elements.
+ * - Driver assumes that the microphone is always
+ * monaureal and connected to the right channel of
+ * the input. This should also be a codec-dependent
+ * flag, maybe the codec should have 3 different
+ * bits for the three different possibilities how
+ * it can be hooked up...
+ * But as long as I don't see any hardware hooked
+ * up that way...
+ * - As Apple notes in their code, the tas3004 seems
+ * to delay the right channel by one sample. You can
+ * see this when for example recording stereo in
+ * audacity, or recording the tas output via cable
+ * on another machine (use a sinus generator or so).
+ * I tried programming the BiQuads but couldn't
+ * make the delay work, maybe someone can read the
+ * datasheet and fix it. The relevant Apple comment
+ * is in AppleTAS3004Audio.cpp lines 1637 ff. Note
+ * that their comment describing how they program
+ * the filters sucks...
+ *
+ * Other things:
+ * - this should actually register *two* aoa_codec
+ * structs since it has two inputs. Then it must
+ * use the prepare callback to forbid running the
+ * secondary output on a different clock.
+ * Also, whatever bus knows how to do this must
+ * provide two soundbus_dev devices and the fabric
+ * must be able to link them correctly.
+ *
+ * I don't even know if Apple ever uses the second
+ * port on the tas3004 though, I don't think their
+ * i2s controllers can even do it. OTOH, they all
+ * derive the clocks from common clocks, so it
+ * might just be possible. The framework allows the
+ * codec to refine the transfer_info items in the
+ * usable callback, so we can simply remove the
+ * rates the second instance is not using when it
+ * actually is in use.
+ * Maybe we'll need to make the sound busses have
+ * a 'clock group id' value so the codec can
+ * determine if the two outputs can be driven at
+ * the same time. But that is likely overkill, up
+ * to the fabric to not link them up incorrectly,
+ * and up to the hardware designer to not wire
+ * them up in some weird unusable way.
+ */
+#include <stddef.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <asm/pmac_low_i2c.h>
+#include <asm/prom.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("tas codec driver for snd-aoa");
+
+#include "snd-aoa-codec-tas.h"
+#include "snd-aoa-codec-tas-gain-table.h"
+#include "../aoa.h"
+#include "../soundbus/soundbus.h"
+
+
+#define PFX "snd-aoa-codec-tas: "
+
+struct tas {
+ struct aoa_codec codec;
+ struct i2c_client i2c;
+ u32 muted_l:1, muted_r:1,
+ controls_created:1;
+ u8 cached_volume_l, cached_volume_r;
+ u8 mixer_l[3], mixer_r[3];
+ u8 acr;
+};
+
+static struct tas *codec_to_tas(struct aoa_codec *codec)
+{
+ return container_of(codec, struct tas, codec);
+}
+
+static inline int tas_write_reg(struct tas *tas, u8 reg, u8 len, u8 *data)
+{
+ if (len == 1)
+ return i2c_smbus_write_byte_data(&tas->i2c, reg, *data);
+ else
+ return i2c_smbus_write_i2c_block_data(&tas->i2c, reg, len, data);
+}
+
+static void tas_set_volume(struct tas *tas)
+{
+ u8 block[6];
+ int tmp;
+ u8 left, right;
+
+ left = tas->cached_volume_l;
+ right = tas->cached_volume_r;
+
+ if (left > 177) left = 177;
+ if (right > 177) right = 177;
+
+ if (tas->muted_l) left = 0;
+ if (tas->muted_r) right = 0;
+
+ /* analysing the volume and mixer tables shows
+ * that they are similar enough when we shift
+ * the mixer table down by 4 bits. The error
+ * is miniscule, in just one item the error
+ * is 1, at a value of 0x07f17b (mixer table
+ * value is 0x07f17a) */
+ tmp = tas_gaintable[left];
+ block[0] = tmp>>20;
+ block[1] = tmp>>12;
+ block[2] = tmp>>4;
+ tmp = tas_gaintable[right];
+ block[3] = tmp>>20;
+ block[4] = tmp>>12;
+ block[5] = tmp>>4;
+ tas_write_reg(tas, TAS_REG_VOL, 6, block);
+}
+
+static void tas_set_mixer(struct tas *tas)
+{
+ u8 block[9];
+ int tmp, i;
+ u8 val;
+
+ for (i=0;i<3;i++) {
+ val = tas->mixer_l[i];
+ if (val > 177) val = 177;
+ tmp = tas_gaintable[val];
+ block[3*i+0] = tmp>>16;
+ block[3*i+1] = tmp>>8;
+ block[3*i+2] = tmp;
+ }
+ tas_write_reg(tas, TAS_REG_LMIX, 9, block);
+
+ for (i=0;i<3;i++) {
+ val = tas->mixer_r[i];
+ if (val > 177) val = 177;
+ tmp = tas_gaintable[val];
+ block[3*i+0] = tmp>>16;
+ block[3*i+1] = tmp>>8;
+ block[3*i+2] = tmp;
+ }
+ tas_write_reg(tas, TAS_REG_RMIX, 9, block);
+}
+
+/* alsa stuff */
+
+static int tas_dev_register(struct snd_device *dev)
+{
+ return 0;
+}
+
+static struct snd_device_ops ops = {
+ .dev_register = tas_dev_register,
+};
+
+static int tas_snd_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 177;
+ return 0;
+}
+
+static int tas_snd_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = tas->cached_volume_l;
+ ucontrol->value.integer.value[1] = tas->cached_volume_r;
+ return 0;
+}
+
+static int tas_snd_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+ if (tas->cached_volume_l == ucontrol->value.integer.value[0]
+ && tas->cached_volume_r == ucontrol->value.integer.value[1])
+ return 0;
+
+ tas->cached_volume_l = ucontrol->value.integer.value[0];
+ tas->cached_volume_r = ucontrol->value.integer.value[1];
+ tas_set_volume(tas);
+ return 1;
+}
+
+static struct snd_kcontrol_new volume_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Volume",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = tas_snd_vol_info,
+ .get = tas_snd_vol_get,
+ .put = tas_snd_vol_put,
+};
+
+static int tas_snd_mute_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int tas_snd_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = !tas->muted_l;
+ ucontrol->value.integer.value[1] = !tas->muted_r;
+ return 0;
+}
+
+static int tas_snd_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+ if (tas->muted_l == !ucontrol->value.integer.value[0]
+ && tas->muted_r == !ucontrol->value.integer.value[1])
+ return 0;
+
+ tas->muted_l = !ucontrol->value.integer.value[0];
+ tas->muted_r = !ucontrol->value.integer.value[1];
+ tas_set_volume(tas);
+ return 1;
+}
+
+static struct snd_kcontrol_new mute_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Switch",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = tas_snd_mute_info,
+ .get = tas_snd_mute_get,
+ .put = tas_snd_mute_put,
+};
+
+static int tas_snd_mixer_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 177;
+ return 0;
+}
+
+static int tas_snd_mixer_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+ int idx = kcontrol->private_value;
+
+ ucontrol->value.integer.value[0] = tas->mixer_l[idx];
+ ucontrol->value.integer.value[1] = tas->mixer_r[idx];
+
+ return 0;
+}
+
+static int tas_snd_mixer_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+ int idx = kcontrol->private_value;
+
+ if (tas->mixer_l[idx] == ucontrol->value.integer.value[0]
+ && tas->mixer_r[idx] == ucontrol->value.integer.value[1])
+ return 0;
+
+ tas->mixer_l[idx] = ucontrol->value.integer.value[0];
+ tas->mixer_r[idx] = ucontrol->value.integer.value[1];
+
+ tas_set_mixer(tas);
+ return 1;
+}
+
+#define MIXER_CONTROL(n,descr,idx) \
+static struct snd_kcontrol_new n##_control = { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = descr " Playback Volume", \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .info = tas_snd_mixer_info, \
+ .get = tas_snd_mixer_get, \
+ .put = tas_snd_mixer_put, \
+ .private_value = idx, \
+}
+
+MIXER_CONTROL(pcm1, "PCM1", 0);
+MIXER_CONTROL(monitor, "Monitor", 2);
+
+static int tas_snd_capture_source_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[] = { "Line-In", "Microphone" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item > 1)
+ uinfo->value.enumerated.item = 1;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int tas_snd_capture_source_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = !!(tas->acr & TAS_ACR_INPUT_B);
+ return 0;
+}
+
+static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+ int oldacr = tas->acr;
+
+ tas->acr &= ~TAS_ACR_INPUT_B;
+ if (ucontrol->value.enumerated.item[0])
+ tas->acr |= TAS_ACR_INPUT_B;
+ if (oldacr == tas->acr)
+ return 0;
+ tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
+ return 1;
+}
+
+static struct snd_kcontrol_new capture_source_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* If we name this 'Input Source', it properly shows up in
+ * alsamixer as a selection, * but it's shown under the
+ * 'Playback' category.
+ * If I name it 'Capture Source', it shows up in strange
+ * ways (two bools of which one can be selected at a
+ * time) but at least it's shown in the 'Capture'
+ * category.
+ * I was told that this was due to backward compatibility,
+ * but I don't understand then why the mangling is *not*
+ * done when I name it "Input Source".....
+ */
+ .name = "Capture Source",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = tas_snd_capture_source_info,
+ .get = tas_snd_capture_source_get,
+ .put = tas_snd_capture_source_put,
+};
+
+
+static struct transfer_info tas_transfers[] = {
+ {
+ /* input */
+ .formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S16_BE |
+ SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE,
+ .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+ .transfer_in = 1,
+ },
+ {
+ /* output */
+ .formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S16_BE |
+ SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE,
+ .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+ .transfer_in = 0,
+ },
+ {}
+};
+
+static int tas_usable(struct codec_info_item *cii,
+ struct transfer_info *ti,
+ struct transfer_info *out)
+{
+ return 1;
+}
+
+static int tas_reset_init(struct tas *tas)
+{
+ u8 tmp;
+ tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 0);
+ msleep(1);
+ tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 1);
+ msleep(1);
+ tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 0);
+ msleep(1);
+
+ tas->acr &= ~TAS_ACR_ANALOG_PDOWN;
+ tas->acr |= TAS_ACR_B_MONAUREAL | TAS_ACR_B_MON_SEL_RIGHT;
+ if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr))
+ return -ENODEV;
+
+ tmp = TAS_MCS_SCLK64 | TAS_MCS_SPORT_MODE_I2S | TAS_MCS_SPORT_WL_24BIT;
+ if (tas_write_reg(tas, TAS_REG_MCS, 1, &tmp))
+ return -ENODEV;
+
+ tmp = 0;
+ if (tas_write_reg(tas, TAS_REG_MCS2, 1, &tmp))
+ return -ENODEV;
+
+ return 0;
+}
+
+/* we are controlled via i2c and assume that is always up
+ * If that wasn't the case, we'd have to suspend once
+ * our i2c device is suspended, and then take note of that! */
+static int tas_suspend(struct tas *tas)
+{
+ tas->acr |= TAS_ACR_ANALOG_PDOWN;
+ tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
+ return 0;
+}
+
+static int tas_resume(struct tas *tas)
+{
+ /* reset codec */
+ tas_reset_init(tas);
+ tas_set_volume(tas);
+ tas_set_mixer(tas);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int _tas_suspend(struct codec_info_item *cii, pm_message_t state)
+{
+ return tas_suspend(cii->codec_data);
+}
+
+static int _tas_resume(struct codec_info_item *cii)
+{
+ return tas_resume(cii->codec_data);
+}
+#endif
+
+static struct codec_info tas_codec_info = {
+ .transfers = tas_transfers,
+ /* in theory, we can drive it at 512 too...
+ * but so far the framework doesn't allow
+ * for that and I don't see much point in it. */
+ .sysclock_factor = 256,
+ /* same here, could be 32 for just one 16 bit format */
+ .bus_factor = 64,
+ .owner = THIS_MODULE,
+ .usable = tas_usable,
+#ifdef CONFIG_PM
+ .suspend = _tas_suspend,
+ .resume = _tas_resume,
+#endif
+};
+
+static int tas_init_codec(struct aoa_codec *codec)
+{
+ struct tas *tas = codec_to_tas(codec);
+ int err;
+
+ if (!tas->codec.gpio || !tas->codec.gpio->methods) {
+ printk(KERN_ERR PFX "gpios not assigned!!\n");
+ return -EINVAL;
+ }
+
+ if (tas_reset_init(tas)) {
+ printk(KERN_ERR PFX "tas failed to initialise\n");
+ return -ENXIO;
+ }
+
+ if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev,
+ aoa_get_card(),
+ &tas_codec_info, tas)) {
+ printk(KERN_ERR PFX "error attaching tas to soundbus\n");
+ return -ENODEV;
+ }
+
+ if (aoa_snd_device_new(SNDRV_DEV_LOWLEVEL, tas, &ops)) {
+ printk(KERN_ERR PFX "failed to create tas snd device!\n");
+ return -ENODEV;
+ }
+ err = aoa_snd_ctl_add(snd_ctl_new1(&volume_control, tas));
+ if (err)
+ goto error;
+
+ err = aoa_snd_ctl_add(snd_ctl_new1(&mute_control, tas));
+ if (err)
+ goto error;
+
+ err = aoa_snd_ctl_add(snd_ctl_new1(&pcm1_control, tas));
+ if (err)
+ goto error;
+
+ err = aoa_snd_ctl_add(snd_ctl_new1(&monitor_control, tas));
+ if (err)
+ goto error;
+
+ err = aoa_snd_ctl_add(snd_ctl_new1(&capture_source_control, tas));
+ if (err)
+ goto error;
+
+ return 0;
+ error:
+ tas->codec.soundbus_dev->detach_codec(tas->codec.soundbus_dev, tas);
+ snd_device_free(aoa_get_card(), tas);
+ return err;
+}
+
+static void tas_exit_codec(struct aoa_codec *codec)
+{
+ struct tas *tas = codec_to_tas(codec);
+
+ if (!tas->codec.soundbus_dev)
+ return;
+ tas->codec.soundbus_dev->detach_codec(tas->codec.soundbus_dev, tas);
+}
+
+
+static struct i2c_driver tas_driver;
+
+static int tas_create(struct i2c_adapter *adapter,
+ struct device_node *node,
+ int addr)
+{
+ struct tas *tas;
+
+ tas = kzalloc(sizeof(struct tas), GFP_KERNEL);
+
+ if (!tas)
+ return -ENOMEM;
+
+ tas->i2c.driver = &tas_driver;
+ tas->i2c.adapter = adapter;
+ tas->i2c.addr = addr;
+ strlcpy(tas->i2c.name, "tas audio codec", I2C_NAME_SIZE-1);
+
+ if (i2c_attach_client(&tas->i2c)) {
+ printk(KERN_ERR PFX "failed to attach to i2c\n");
+ goto fail;
+ }
+
+ strlcpy(tas->codec.name, "tas", MAX_CODEC_NAME_LEN-1);
+ tas->codec.owner = THIS_MODULE;
+ tas->codec.init = tas_init_codec;
+ tas->codec.exit = tas_exit_codec;
+ tas->codec.node = of_node_get(node);
+
+ if (aoa_codec_register(&tas->codec)) {
+ goto detach;
+ }
+ printk(KERN_DEBUG "snd-aoa-codec-tas: created and attached tas instance\n");
+ return 0;
+ detach:
+ i2c_detach_client(&tas->i2c);
+ fail:
+ kfree(tas);
+ return -EINVAL;
+}
+
+static int tas_i2c_attach(struct i2c_adapter *adapter)
+{
+ struct device_node *busnode, *dev = NULL;
+ struct pmac_i2c_bus *bus;
+
+ bus = pmac_i2c_adapter_to_bus(adapter);
+ if (bus == NULL)
+ return -ENODEV;
+ busnode = pmac_i2c_get_bus_node(bus);
+
+ while ((dev = of_get_next_child(busnode, dev)) != NULL) {
+ if (device_is_compatible(dev, "tas3004")) {
+ u32 *addr;
+ printk(KERN_DEBUG PFX "found tas3004\n");
+ addr = (u32 *) get_property(dev, "reg", NULL);
+ if (!addr)
+ continue;
+ return tas_create(adapter, dev, ((*addr) >> 1) & 0x7f);
+ }
+ /* older machines have no 'codec' node with a 'compatible'
+ * property that says 'tas3004', they just have a 'deq'
+ * node without any such property... */
+ if (strcmp(dev->name, "deq") == 0) {
+ u32 *_addr, addr;
+ printk(KERN_DEBUG PFX "found 'deq' node\n");
+ _addr = (u32 *) get_property(dev, "i2c-address", NULL);
+ if (!_addr)
+ continue;
+ addr = ((*_addr) >> 1) & 0x7f;
+ /* now, if the address doesn't match any of the two
+ * that a tas3004 can have, we cannot handle this.
+ * I doubt it ever happens but hey. */
+ if (addr != 0x34 && addr != 0x35)
+ continue;
+ return tas_create(adapter, dev, addr);
+ }
+ }
+ return -ENODEV;
+}
+
+static int tas_i2c_detach(struct i2c_client *client)
+{
+ struct tas *tas = container_of(client, struct tas, i2c);
+ int err;
+ u8 tmp = TAS_ACR_ANALOG_PDOWN;
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+ aoa_codec_unregister(&tas->codec);
+ of_node_put(tas->codec.node);
+
+ /* power down codec chip */
+ tas_write_reg(tas, TAS_REG_ACR, 1, &tmp);
+
+ kfree(tas);
+ return 0;
+}
+
+static struct i2c_driver tas_driver = {
+ .driver = {
+ .name = "aoa_codec_tas",
+ .owner = THIS_MODULE,
+ },
+ .attach_adapter = tas_i2c_attach,
+ .detach_client = tas_i2c_detach,
+};
+
+static int __init tas_init(void)
+{
+ return i2c_add_driver(&tas_driver);
+}
+
+static void __exit tas_exit(void)
+{
+ i2c_del_driver(&tas_driver);
+}
+
+module_init(tas_init);
+module_exit(tas_exit);
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.h b/sound/aoa/codecs/snd-aoa-codec-tas.h
new file mode 100644
index 0000000..daf81f4
--- /dev/null
+++ b/sound/aoa/codecs/snd-aoa-codec-tas.h
@@ -0,0 +1,47 @@
+/*
+ * Apple Onboard Audio driver for tas codec (header)
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+#ifndef __SND_AOA_CODECTASH
+#define __SND_AOA_CODECTASH
+
+#define TAS_REG_MCS 0x01 /* main control */
+# define TAS_MCS_FASTLOAD (1<<7)
+# define TAS_MCS_SCLK64 (1<<6)
+# define TAS_MCS_SPORT_MODE_MASK (3<<4)
+# define TAS_MCS_SPORT_MODE_I2S (2<<4)
+# define TAS_MCS_SPORT_MODE_RJ (1<<4)
+# define TAS_MCS_SPORT_MODE_LJ (0<<4)
+# define TAS_MCS_SPORT_WL_MASK (3<<0)
+# define TAS_MCS_SPORT_WL_16BIT (0<<0)
+# define TAS_MCS_SPORT_WL_18BIT (1<<0)
+# define TAS_MCS_SPORT_WL_20BIT (2<<0)
+# define TAS_MCS_SPORT_WL_24BIT (3<<0)
+
+#define TAS_REG_DRC 0x02
+#define TAS_REG_VOL 0x04
+#define TAS_REG_TREBLE 0x05
+#define TAS_REG_BASS 0x06
+#define TAS_REG_LMIX 0x07
+#define TAS_REG_RMIX 0x08
+
+#define TAS_REG_ACR 0x40 /* analog control */
+# define TAS_ACR_B_MONAUREAL (1<<7)
+# define TAS_ACR_B_MON_SEL_RIGHT (1<<6)
+# define TAS_ACR_DEEMPH_MASK (3<<2)
+# define TAS_ACR_DEEMPH_OFF (0<<2)
+# define TAS_ACR_DEEMPH_48KHz (1<<2)
+# define TAS_ACR_DEEMPH_44KHz (2<<2)
+# define TAS_ACR_INPUT_B (1<<1)
+# define TAS_ACR_ANALOG_PDOWN (1<<0)
+
+#define TAS_REG_MCS2 0x43 /* main control 2 */
+# define TAS_MCS2_ALLPASS (1<<1)
+
+#define TAS_REG_LEFT_BIQUAD6 0x10
+#define TAS_REG_RIGHT_BIQUAD6 0x19
+
+#endif /* __SND_AOA_CODECTASH */
diff --git a/sound/aoa/codecs/snd-aoa-codec-toonie.c b/sound/aoa/codecs/snd-aoa-codec-toonie.c
new file mode 100644
index 0000000..bcc5556
--- /dev/null
+++ b/sound/aoa/codecs/snd-aoa-codec-toonie.c
@@ -0,0 +1,141 @@
+/*
+ * Apple Onboard Audio driver for Toonie codec
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ *
+ *
+ * This is a driver for the toonie codec chip. This chip is present
+ * on the Mac Mini and is nothing but a DAC.
+ */
+#include <linux/delay.h>
+#include <linux/module.h>
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("toonie codec driver for snd-aoa");
+
+#include "../aoa.h"
+#include "../soundbus/soundbus.h"
+
+
+#define PFX "snd-aoa-codec-toonie: "
+
+struct toonie {
+ struct aoa_codec codec;
+};
+#define codec_to_toonie(c) container_of(c, struct toonie, codec)
+
+static int toonie_dev_register(struct snd_device *dev)
+{
+ return 0;
+}
+
+static struct snd_device_ops ops = {
+ .dev_register = toonie_dev_register,
+};
+
+static struct transfer_info toonie_transfers[] = {
+ /* This thing *only* has analog output,
+ * the rates are taken from Info.plist
+ * from Darwin. */
+ {
+ .formats = SNDRV_PCM_FMTBIT_S16_BE |
+ SNDRV_PCM_FMTBIT_S24_BE,
+ .rates = SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000,
+ },
+ {}
+};
+
+#ifdef CONFIG_PM
+static int toonie_suspend(struct codec_info_item *cii, pm_message_t state)
+{
+ /* can we turn it off somehow? */
+ return 0;
+}
+
+static int toonie_resume(struct codec_info_item *cii)
+{
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static struct codec_info toonie_codec_info = {
+ .transfers = toonie_transfers,
+ .sysclock_factor = 256,
+ .bus_factor = 64,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .suspend = toonie_suspend,
+ .resume = toonie_resume,
+#endif
+};
+
+static int toonie_init_codec(struct aoa_codec *codec)
+{
+ struct toonie *toonie = codec_to_toonie(codec);
+
+ if (aoa_snd_device_new(SNDRV_DEV_LOWLEVEL, toonie, &ops)) {
+ printk(KERN_ERR PFX "failed to create toonie snd device!\n");
+ return -ENODEV;
+ }
+
+ /* nothing connected? what a joke! */
+ if (toonie->codec.connected != 1)
+ return -ENOTCONN;
+
+ if (toonie->codec.soundbus_dev->attach_codec(toonie->codec.soundbus_dev,
+ aoa_get_card(),
+ &toonie_codec_info, toonie)) {
+ printk(KERN_ERR PFX "error creating toonie pcm\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void toonie_exit_codec(struct aoa_codec *codec)
+{
+ struct toonie *toonie = codec_to_toonie(codec);
+
+ if (!toonie->codec.soundbus_dev) {
+ printk(KERN_ERR PFX "toonie_exit_codec called without soundbus_dev!\n");
+ return;
+ }
+ toonie->codec.soundbus_dev->detach_codec(toonie->codec.soundbus_dev, toonie);
+}
+
+static struct toonie *toonie;
+
+static int __init toonie_init(void)
+{
+ toonie = kzalloc(sizeof(struct toonie), GFP_KERNEL);
+
+ if (!toonie)
+ return -ENOMEM;
+
+ strlcpy(toonie->codec.name, "toonie", sizeof(toonie->codec.name));
+ toonie->codec.owner = THIS_MODULE;
+ toonie->codec.init = toonie_init_codec;
+ toonie->codec.exit = toonie_exit_codec;
+
+ if (aoa_codec_register(&toonie->codec)) {
+ kfree(toonie);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void __exit toonie_exit(void)
+{
+ aoa_codec_unregister(&toonie->codec);
+ kfree(toonie);
+}
+
+module_init(toonie_init);
+module_exit(toonie_exit);
diff --git a/sound/aoa/core/Makefile b/sound/aoa/core/Makefile
new file mode 100644
index 0000000..62dc728
--- /dev/null
+++ b/sound/aoa/core/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_SND_AOA) += snd-aoa.o
+snd-aoa-objs := snd-aoa-core.o \
+ snd-aoa-alsa.o \
+ snd-aoa-gpio-pmf.o \
+ snd-aoa-gpio-feature.o
diff --git a/sound/aoa/core/snd-aoa-alsa.c b/sound/aoa/core/snd-aoa-alsa.c
new file mode 100644
index 0000000..b42fdea
--- /dev/null
+++ b/sound/aoa/core/snd-aoa-alsa.c
@@ -0,0 +1,98 @@
+/*
+ * Apple Onboard Audio Alsa helpers
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+#include <linux/module.h>
+#include "snd-aoa-alsa.h"
+
+static int index = -1;
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "index for AOA sound card.");
+
+static struct aoa_card *aoa_card;
+
+int aoa_alsa_init(char *name, struct module *mod)
+{
+ struct snd_card *alsa_card;
+ int err;
+
+ if (aoa_card)
+ /* cannot be EEXIST due to usage in aoa_fabric_register */
+ return -EBUSY;
+
+ alsa_card = snd_card_new(index, name, mod, sizeof(struct aoa_card));
+ if (!alsa_card)
+ return -ENOMEM;
+ aoa_card = alsa_card->private_data;
+ aoa_card->alsa_card = alsa_card;
+ strlcpy(alsa_card->driver, "AppleOnbdAudio", sizeof(alsa_card->driver));
+ strlcpy(alsa_card->shortname, name, sizeof(alsa_card->shortname));
+ strlcpy(alsa_card->longname, name, sizeof(alsa_card->longname));
+ strlcpy(alsa_card->mixername, name, sizeof(alsa_card->mixername));
+ err = snd_card_register(aoa_card->alsa_card);
+ if (err < 0) {
+ printk(KERN_ERR "snd-aoa: couldn't register alsa card\n");
+ snd_card_free(aoa_card->alsa_card);
+ aoa_card = NULL;
+ return err;
+ }
+ return 0;
+}
+
+struct snd_card *aoa_get_card(void)
+{
+ if (aoa_card)
+ return aoa_card->alsa_card;
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(aoa_get_card);
+
+void aoa_alsa_cleanup(void)
+{
+ if (aoa_card) {
+ snd_card_free(aoa_card->alsa_card);
+ aoa_card = NULL;
+ }
+}
+
+int aoa_snd_device_new(snd_device_type_t type,
+ void * device_data, struct snd_device_ops * ops)
+{
+ struct snd_card *card = aoa_get_card();
+ int err;
+
+ if (!card) return -ENOMEM;
+
+ err = snd_device_new(card, type, device_data, ops);
+ if (err) {
+ printk(KERN_ERR "snd-aoa: failed to create snd device (%d)\n", err);
+ return err;
+ }
+ err = snd_device_register(card, device_data);
+ if (err) {
+ printk(KERN_ERR "snd-aoa: failed to register "
+ "snd device (%d)\n", err);
+ printk(KERN_ERR "snd-aoa: have you forgotten the "
+ "dev_register callback?\n");
+ snd_device_free(card, device_data);
+ }
+ return err;
+}
+EXPORT_SYMBOL_GPL(aoa_snd_device_new);
+
+int aoa_snd_ctl_add(struct snd_kcontrol* control)
+{
+ int err;
+
+ if (!aoa_card) return -ENODEV;
+
+ err = snd_ctl_add(aoa_card->alsa_card, control);
+ if (err)
+ printk(KERN_ERR "snd-aoa: failed to add alsa control (%d)\n",
+ err);
+ return err;
+}
+EXPORT_SYMBOL_GPL(aoa_snd_ctl_add);
diff --git a/sound/aoa/core/snd-aoa-alsa.h b/sound/aoa/core/snd-aoa-alsa.h
new file mode 100644
index 0000000..660d2f1
--- /dev/null
+++ b/sound/aoa/core/snd-aoa-alsa.h
@@ -0,0 +1,16 @@
+/*
+ * Apple Onboard Audio Alsa private helpers
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+
+#ifndef __SND_AOA_ALSA_H
+#define __SND_AOA_ALSA_H
+#include "../aoa.h"
+
+extern int aoa_alsa_init(char *name, struct module *mod);
+extern void aoa_alsa_cleanup(void);
+
+#endif /* __SND_AOA_ALSA_H */
diff --git a/sound/aoa/core/snd-aoa-core.c b/sound/aoa/core/snd-aoa-core.c
new file mode 100644
index 0000000..ecd2d82
--- /dev/null
+++ b/sound/aoa/core/snd-aoa-core.c
@@ -0,0 +1,162 @@
+/*
+ * Apple Onboard Audio driver core
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include "../aoa.h"
+#include "snd-aoa-alsa.h"
+
+MODULE_DESCRIPTION("Apple Onboard Audio Sound Driver");
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
+MODULE_LICENSE("GPL");
+
+/* We allow only one fabric. This simplifies things,
+ * and more don't really make that much sense */
+static struct aoa_fabric *fabric;
+static LIST_HEAD(codec_list);
+
+static int attach_codec_to_fabric(struct aoa_codec *c)
+{
+ int err;
+
+ if (!try_module_get(c->owner))
+ return -EBUSY;
+ /* found_codec has to be assigned */
+ err = -ENOENT;
+ if (fabric->found_codec)
+ err = fabric->found_codec(c);
+ if (err) {
+ module_put(c->owner);
+ printk(KERN_ERR "snd-aoa: fabric didn't like codec %s\n",
+ c->name);
+ return err;
+ }
+ c->fabric = fabric;
+
+ err = 0;
+ if (c->init)
+ err = c->init(c);
+ if (err) {
+ printk(KERN_ERR "snd-aoa: codec %s didn't init\n", c->name);
+ c->fabric = NULL;
+ if (fabric->remove_codec)
+ fabric->remove_codec(c);
+ module_put(c->owner);
+ return err;
+ }
+ if (fabric->attached_codec)
+ fabric->attached_codec(c);
+ return 0;
+}
+
+int aoa_codec_register(struct aoa_codec *codec)
+{
+ int err = 0;
+
+ /* if there's a fabric already, we can tell if we
+ * will want to have this codec, so propagate error
+ * through. Otherwise, this will happen later... */
+ if (fabric)
+ err = attach_codec_to_fabric(codec);
+ if (!err)
+ list_add(&codec->list, &codec_list);
+ return err;
+}
+EXPORT_SYMBOL_GPL(aoa_codec_register);
+
+void aoa_codec_unregister(struct aoa_codec *codec)
+{
+ list_del(&codec->list);
+ if (codec->fabric && codec->exit)
+ codec->exit(codec);
+ if (fabric && fabric->remove_codec)
+ fabric->remove_codec(codec);
+ codec->fabric = NULL;
+ module_put(codec->owner);
+}
+EXPORT_SYMBOL_GPL(aoa_codec_unregister);
+
+int aoa_fabric_register(struct aoa_fabric *new_fabric)
+{
+ struct aoa_codec *c;
+ int err;
+
+ /* allow querying for presence of fabric
+ * (i.e. do this test first!) */
+ if (new_fabric == fabric) {
+ err = -EALREADY;
+ goto attach;
+ }
+ if (fabric)
+ return -EEXIST;
+ if (!new_fabric)
+ return -EINVAL;
+
+ err = aoa_alsa_init(new_fabric->name, new_fabric->owner);
+ if (err)
+ return err;
+
+ fabric = new_fabric;
+
+ attach:
+ list_for_each_entry(c, &codec_list, list) {
+ if (c->fabric != fabric)
+ attach_codec_to_fabric(c);
+ }
+ return err;
+}
+EXPORT_SYMBOL_GPL(aoa_fabric_register);
+
+void aoa_fabric_unregister(struct aoa_fabric *old_fabric)
+{
+ struct aoa_codec *c;
+
+ if (fabric != old_fabric)
+ return;
+
+ list_for_each_entry(c, &codec_list, list) {
+ if (c->fabric)
+ aoa_fabric_unlink_codec(c);
+ }
+
+ aoa_alsa_cleanup();
+
+ fabric = NULL;
+}
+EXPORT_SYMBOL_GPL(aoa_fabric_unregister);
+
+void aoa_fabric_unlink_codec(struct aoa_codec *codec)
+{
+ if (!codec->fabric) {
+ printk(KERN_ERR "snd-aoa: fabric unassigned "
+ "in aoa_fabric_unlink_codec\n");
+ dump_stack();
+ return;
+ }
+ if (codec->exit)
+ codec->exit(codec);
+ if (codec->fabric->remove_codec)
+ codec->fabric->remove_codec(codec);
+ codec->fabric = NULL;
+ module_put(codec->owner);
+}
+EXPORT_SYMBOL_GPL(aoa_fabric_unlink_codec);
+
+static int __init aoa_init(void)
+{
+ return 0;
+}
+
+static void __exit aoa_exit(void)
+{
+ aoa_alsa_cleanup();
+}
+
+module_init(aoa_init);
+module_exit(aoa_exit);
diff --git a/sound/aoa/core/snd-aoa-gpio-feature.c b/sound/aoa/core/snd-aoa-gpio-feature.c
new file mode 100644
index 0000000..2c6eb77
--- /dev/null
+++ b/sound/aoa/core/snd-aoa-gpio-feature.c
@@ -0,0 +1,399 @@
+/*
+ * Apple Onboard Audio feature call GPIO control
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ *
+ * This file contains the GPIO control routines for
+ * direct (through feature calls) access to the GPIO
+ * registers.
+ */
+
+#include <asm/pmac_feature.h>
+#include <linux/interrupt.h>
+#include "../aoa.h"
+
+/* TODO: these are 20 global variables
+ * that aren't used on most machines...
+ * Move them into a dynamically allocated
+ * structure and use that.
+ */
+
+/* these are the GPIO numbers (register addresses as offsets into
+ * the GPIO space) */
+static int headphone_mute_gpio;
+static int amp_mute_gpio;
+static int lineout_mute_gpio;
+static int hw_reset_gpio;
+static int lineout_detect_gpio;
+static int headphone_detect_gpio;
+static int linein_detect_gpio;
+
+/* see the SWITCH_GPIO macro */
+static int headphone_mute_gpio_activestate;
+static int amp_mute_gpio_activestate;
+static int lineout_mute_gpio_activestate;
+static int hw_reset_gpio_activestate;
+static int lineout_detect_gpio_activestate;
+static int headphone_detect_gpio_activestate;
+static int linein_detect_gpio_activestate;
+
+/* node pointers that we save when getting the GPIO number
+ * to get the interrupt later */
+static struct device_node *lineout_detect_node;
+static struct device_node *linein_detect_node;
+static struct device_node *headphone_detect_node;
+
+static int lineout_detect_irq;
+static int linein_detect_irq;
+static int headphone_detect_irq;
+
+static struct device_node *get_gpio(char *name,
+ char *altname,
+ int *gpioptr,
+ int *gpioactiveptr)
+{
+ struct device_node *np, *gpio;
+ u32 *reg;
+ char *audio_gpio;
+
+ *gpioptr = -1;
+
+ /* check if we can get it the easy way ... */
+ np = of_find_node_by_name(NULL, name);
+ if (!np) {
+ /* some machines have only gpioX/extint-gpioX nodes,
+ * and an audio-gpio property saying what it is ...
+ * So what we have to do is enumerate all children
+ * of the gpio node and check them all. */
+ gpio = of_find_node_by_name(NULL, "gpio");
+ if (!gpio)
+ return NULL;
+ while ((np = of_get_next_child(gpio, np))) {
+ audio_gpio = get_property(np, "audio-gpio", NULL);
+ if (!audio_gpio)
+ continue;
+ if (strcmp(audio_gpio, name) == 0)
+ break;
+ if (altname && (strcmp(audio_gpio, altname) == 0))
+ break;
+ }
+ /* still not found, assume not there */
+ if (!np)
+ return NULL;
+ }
+
+ reg = (u32 *)get_property(np, "reg", NULL);
+ if (!reg)
+ return NULL;
+
+ *gpioptr = *reg;
+
+ /* this is a hack, usually the GPIOs 'reg' property
+ * should have the offset based from the GPIO space
+ * which is at 0x50, but apparently not always... */
+ if (*gpioptr < 0x50)
+ *gpioptr += 0x50;
+
+ reg = (u32 *)get_property(np, "audio-gpio-active-state", NULL);
+ if (!reg)
+ /* Apple seems to default to 1, but
+ * that doesn't seem right at least on most
+ * machines. So until proven that the opposite
+ * is necessary, we default to 0
+ * (which, incidentally, snd-powermac also does...) */
+ *gpioactiveptr = 0;
+ else
+ *gpioactiveptr = *reg;
+
+ return np;
+}
+
+static void get_irq(struct device_node * np, int *irqptr)
+{
+ *irqptr = -1;
+ if (!np)
+ return;
+ if (np->n_intrs != 1)
+ return;
+ *irqptr = np->intrs[0].line;
+}
+
+/* 0x4 is outenable, 0x1 is out, thus 4 or 5 */
+#define SWITCH_GPIO(name, v, on) \
+ (((v)&~1) | ((on)? \
+ (name##_gpio_activestate==0?4:5): \
+ (name##_gpio_activestate==0?5:4)))
+
+#define FTR_GPIO(name, bit) \
+static void ftr_gpio_set_##name(struct gpio_runtime *rt, int on)\
+{ \
+ int v; \
+ \
+ if (unlikely(!rt)) return; \
+ \
+ if (name##_mute_gpio < 0) \
+ return; \
+ \
+ v = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, \
+ name##_mute_gpio, \
+ 0); \
+ \
+ /* muted = !on... */ \
+ v = SWITCH_GPIO(name##_mute, v, !on); \
+ \
+ pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, \
+ name##_mute_gpio, v); \
+ \
+ rt->implementation_private &= ~(1<<bit); \
+ rt->implementation_private |= (!!on << bit); \
+} \
+static int ftr_gpio_get_##name(struct gpio_runtime *rt) \
+{ \
+ if (unlikely(!rt)) return 0; \
+ return (rt->implementation_private>>bit)&1; \
+}
+
+FTR_GPIO(headphone, 0);
+FTR_GPIO(amp, 1);
+FTR_GPIO(lineout, 2);
+
+static void ftr_gpio_set_hw_reset(struct gpio_runtime *rt, int on)
+{
+ int v;
+
+ if (unlikely(!rt)) return;
+ if (hw_reset_gpio < 0)
+ return;
+
+ v = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL,
+ hw_reset_gpio, 0);
+ v = SWITCH_GPIO(hw_reset, v, on);
+ pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL,
+ hw_reset_gpio, v);
+}
+
+static void ftr_gpio_all_amps_off(struct gpio_runtime *rt)
+{
+ int saved;
+
+ if (unlikely(!rt)) return;
+ saved = rt->implementation_private;
+ ftr_gpio_set_headphone(rt, 0);
+ ftr_gpio_set_amp(rt, 0);
+ ftr_gpio_set_lineout(rt, 0);
+ rt->implementation_private = saved;
+}
+
+static void ftr_gpio_all_amps_restore(struct gpio_runtime *rt)
+{
+ int s;
+
+ if (unlikely(!rt)) return;
+ s = rt->implementation_private;
+ ftr_gpio_set_headphone(rt, (s>>0)&1);
+ ftr_gpio_set_amp(rt, (s>>1)&1);
+ ftr_gpio_set_lineout(rt, (s>>2)&1);
+}
+
+static void ftr_handle_notify(void *data)
+{
+ struct gpio_notification *notif = data;
+
+ mutex_lock(&notif->mutex);
+ if (notif->notify)
+ notif->notify(notif->data);
+ mutex_unlock(&notif->mutex);
+}
+
+static void ftr_gpio_init(struct gpio_runtime *rt)
+{
+ get_gpio("headphone-mute", NULL,
+ &headphone_mute_gpio,
+ &headphone_mute_gpio_activestate);
+ get_gpio("amp-mute", NULL,
+ &amp_mute_gpio,
+ &amp_mute_gpio_activestate);
+ get_gpio("lineout-mute", NULL,
+ &lineout_mute_gpio,
+ &lineout_mute_gpio_activestate);
+ get_gpio("hw-reset", "audio-hw-reset",
+ &hw_reset_gpio,
+ &hw_reset_gpio_activestate);
+
+ headphone_detect_node = get_gpio("headphone-detect", NULL,
+ &headphone_detect_gpio,
+ &headphone_detect_gpio_activestate);
+ /* go Apple, and thanks for giving these different names
+ * across the board... */
+ lineout_detect_node = get_gpio("lineout-detect", "line-output-detect",
+ &lineout_detect_gpio,
+ &lineout_detect_gpio_activestate);
+ linein_detect_node = get_gpio("linein-detect", "line-input-detect",
+ &linein_detect_gpio,
+ &linein_detect_gpio_activestate);
+
+ get_irq(headphone_detect_node, &headphone_detect_irq);
+ get_irq(lineout_detect_node, &lineout_detect_irq);
+ get_irq(linein_detect_node, &linein_detect_irq);
+
+ ftr_gpio_all_amps_off(rt);
+ rt->implementation_private = 0;
+ INIT_WORK(&rt->headphone_notify.work, ftr_handle_notify,
+ &rt->headphone_notify);
+ INIT_WORK(&rt->line_in_notify.work, ftr_handle_notify,
+ &rt->line_in_notify);
+ INIT_WORK(&rt->line_out_notify.work, ftr_handle_notify,
+ &rt->line_out_notify);
+ mutex_init(&rt->headphone_notify.mutex);
+ mutex_init(&rt->line_in_notify.mutex);
+ mutex_init(&rt->line_out_notify.mutex);
+}
+
+static void ftr_gpio_exit(struct gpio_runtime *rt)
+{
+ ftr_gpio_all_amps_off(rt);
+ rt->implementation_private = 0;
+ if (rt->headphone_notify.notify)
+ free_irq(headphone_detect_irq, &rt->headphone_notify);
+ if (rt->line_in_notify.gpio_private)
+ free_irq(linein_detect_irq, &rt->line_in_notify);
+ if (rt->line_out_notify.gpio_private)
+ free_irq(lineout_detect_irq, &rt->line_out_notify);
+ cancel_delayed_work(&rt->headphone_notify.work);
+ cancel_delayed_work(&rt->line_in_notify.work);
+ cancel_delayed_work(&rt->line_out_notify.work);
+ flush_scheduled_work();
+ mutex_destroy(&rt->headphone_notify.mutex);
+ mutex_destroy(&rt->line_in_notify.mutex);
+ mutex_destroy(&rt->line_out_notify.mutex);
+}
+
+static irqreturn_t ftr_handle_notify_irq(int xx,
+ void *data,
+ struct pt_regs *regs)
+{
+ struct gpio_notification *notif = data;
+
+ schedule_work(&notif->work);
+
+ return IRQ_HANDLED;
+}
+
+static int ftr_set_notify(struct gpio_runtime *rt,
+ enum notify_type type,
+ notify_func_t notify,
+ void *data)
+{
+ struct gpio_notification *notif;
+ notify_func_t old;
+ int irq;
+ char *name;
+ int err = -EBUSY;
+
+ switch (type) {
+ case AOA_NOTIFY_HEADPHONE:
+ notif = &rt->headphone_notify;
+ name = "headphone-detect";
+ irq = headphone_detect_irq;
+ break;
+ case AOA_NOTIFY_LINE_IN:
+ notif = &rt->line_in_notify;
+ name = "linein-detect";
+ irq = linein_detect_irq;
+ break;
+ case AOA_NOTIFY_LINE_OUT:
+ notif = &rt->line_out_notify;
+ name = "lineout-detect";
+ irq = lineout_detect_irq;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (irq == -1)
+ return -ENODEV;
+
+ mutex_lock(&notif->mutex);
+
+ old = notif->notify;
+
+ if (!old && !notify) {
+ err = 0;
+ goto out_unlock;
+ }
+
+ if (old && notify) {
+ if (old == notify && notif->data == data)
+ err = 0;
+ goto out_unlock;
+ }
+
+ if (old && !notify)
+ free_irq(irq, notif);
+
+ if (!old && notify) {
+ err = request_irq(irq, ftr_handle_notify_irq, 0, name, notif);
+ if (err)
+ goto out_unlock;
+ }
+
+ notif->notify = notify;
+ notif->data = data;
+
+ err = 0;
+ out_unlock:
+ mutex_unlock(&notif->mutex);
+ return err;
+}
+
+static int ftr_get_detect(struct gpio_runtime *rt,
+ enum notify_type type)
+{
+ int gpio, ret, active;
+
+ switch (type) {
+ case AOA_NOTIFY_HEADPHONE:
+ gpio = headphone_detect_gpio;
+ active = headphone_detect_gpio_activestate;
+ break;
+ case AOA_NOTIFY_LINE_IN:
+ gpio = linein_detect_gpio;
+ active = linein_detect_gpio_activestate;
+ break;
+ case AOA_NOTIFY_LINE_OUT:
+ gpio = lineout_detect_gpio;
+ active = lineout_detect_gpio_activestate;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (gpio == -1)
+ return -ENODEV;
+
+ ret = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio, 0);
+ if (ret < 0)
+ return ret;
+ return ((ret >> 1) & 1) == active;
+}
+
+static struct gpio_methods methods = {
+ .init = ftr_gpio_init,
+ .exit = ftr_gpio_exit,
+ .all_amps_off = ftr_gpio_all_amps_off,
+ .all_amps_restore = ftr_gpio_all_amps_restore,
+ .set_headphone = ftr_gpio_set_headphone,
+ .set_speakers = ftr_gpio_set_amp,
+ .set_lineout = ftr_gpio_set_lineout,
+ .set_hw_reset = ftr_gpio_set_hw_reset,
+ .get_headphone = ftr_gpio_get_headphone,
+ .get_speakers = ftr_gpio_get_amp,
+ .get_lineout = ftr_gpio_get_lineout,
+ .set_notify = ftr_set_notify,
+ .get_detect = ftr_get_detect,
+};
+
+struct gpio_methods *ftr_gpio_methods = &methods;
+EXPORT_SYMBOL_GPL(ftr_gpio_methods);
diff --git a/sound/aoa/core/snd-aoa-gpio-pmf.c b/sound/aoa/core/snd-aoa-gpio-pmf.c
new file mode 100644
index 0000000..0e9b9bb
--- /dev/null
+++ b/sound/aoa/core/snd-aoa-gpio-pmf.c
@@ -0,0 +1,246 @@
+/*
+ * Apple Onboard Audio pmf GPIOs
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+
+#include <asm/pmac_feature.h>
+#include <asm/pmac_pfunc.h>
+#include "../aoa.h"
+
+#define PMF_GPIO(name, bit) \
+static void pmf_gpio_set_##name(struct gpio_runtime *rt, int on)\
+{ \
+ struct pmf_args args = { .count = 1, .u[0].v = !on }; \
+ \
+ if (unlikely(!rt)) return; \
+ pmf_call_function(rt->node, #name "-mute", &args); \
+ rt->implementation_private &= ~(1<<bit); \
+ rt->implementation_private |= (!!on << bit); \
+} \
+static int pmf_gpio_get_##name(struct gpio_runtime *rt) \
+{ \
+ if (unlikely(!rt)) return 0; \
+ return (rt->implementation_private>>bit)&1; \
+}
+
+PMF_GPIO(headphone, 0);
+PMF_GPIO(amp, 1);
+PMF_GPIO(lineout, 2);
+
+static void pmf_gpio_set_hw_reset(struct gpio_runtime *rt, int on)
+{
+ struct pmf_args args = { .count = 1, .u[0].v = !!on };
+
+ if (unlikely(!rt)) return;
+ pmf_call_function(rt->node, "hw-reset", &args);
+}
+
+static void pmf_gpio_all_amps_off(struct gpio_runtime *rt)
+{
+ int saved;
+
+ if (unlikely(!rt)) return;
+ saved = rt->implementation_private;
+ pmf_gpio_set_headphone(rt, 0);
+ pmf_gpio_set_amp(rt, 0);
+ pmf_gpio_set_lineout(rt, 0);
+ rt->implementation_private = saved;
+}
+
+static void pmf_gpio_all_amps_restore(struct gpio_runtime *rt)
+{
+ int s;
+
+ if (unlikely(!rt)) return;
+ s = rt->implementation_private;
+ pmf_gpio_set_headphone(rt, (s>>0)&1);
+ pmf_gpio_set_amp(rt, (s>>1)&1);
+ pmf_gpio_set_lineout(rt, (s>>2)&1);
+}
+
+static void pmf_handle_notify(void *data)
+{
+ struct gpio_notification *notif = data;
+
+ mutex_lock(&notif->mutex);
+ if (notif->notify)
+ notif->notify(notif->data);
+ mutex_unlock(&notif->mutex);
+}
+
+static void pmf_gpio_init(struct gpio_runtime *rt)
+{
+ pmf_gpio_all_amps_off(rt);
+ rt->implementation_private = 0;
+ INIT_WORK(&rt->headphone_notify.work, pmf_handle_notify,
+ &rt->headphone_notify);
+ INIT_WORK(&rt->line_in_notify.work, pmf_handle_notify,
+ &rt->line_in_notify);
+ INIT_WORK(&rt->line_out_notify.work, pmf_handle_notify,
+ &rt->line_out_notify);
+ mutex_init(&rt->headphone_notify.mutex);
+ mutex_init(&rt->line_in_notify.mutex);
+ mutex_init(&rt->line_out_notify.mutex);
+}
+
+static void pmf_gpio_exit(struct gpio_runtime *rt)
+{
+ pmf_gpio_all_amps_off(rt);
+ rt->implementation_private = 0;
+
+ if (rt->headphone_notify.gpio_private)
+ pmf_unregister_irq_client(rt->headphone_notify.gpio_private);
+ if (rt->line_in_notify.gpio_private)
+ pmf_unregister_irq_client(rt->line_in_notify.gpio_private);
+ if (rt->line_out_notify.gpio_private)
+ pmf_unregister_irq_client(rt->line_out_notify.gpio_private);
+
+ /* make sure no work is pending before freeing
+ * all things */
+ cancel_delayed_work(&rt->headphone_notify.work);
+ cancel_delayed_work(&rt->line_in_notify.work);
+ cancel_delayed_work(&rt->line_out_notify.work);
+ flush_scheduled_work();
+
+ mutex_destroy(&rt->headphone_notify.mutex);
+ mutex_destroy(&rt->line_in_notify.mutex);
+ mutex_destroy(&rt->line_out_notify.mutex);
+
+ if (rt->headphone_notify.gpio_private)
+ kfree(rt->headphone_notify.gpio_private);
+ if (rt->line_in_notify.gpio_private)
+ kfree(rt->line_in_notify.gpio_private);
+ if (rt->line_out_notify.gpio_private)
+ kfree(rt->line_out_notify.gpio_private);
+}
+
+static void pmf_handle_notify_irq(void *data)
+{
+ struct gpio_notification *notif = data;
+
+ schedule_work(&notif->work);
+}
+
+static int pmf_set_notify(struct gpio_runtime *rt,
+ enum notify_type type,
+ notify_func_t notify,
+ void *data)
+{
+ struct gpio_notification *notif;
+ notify_func_t old;
+ struct pmf_irq_client *irq_client;
+ char *name;
+ int err = -EBUSY;
+
+ switch (type) {
+ case AOA_NOTIFY_HEADPHONE:
+ notif = &rt->headphone_notify;
+ name = "headphone-detect";
+ break;
+ case AOA_NOTIFY_LINE_IN:
+ notif = &rt->line_in_notify;
+ name = "linein-detect";
+ break;
+ case AOA_NOTIFY_LINE_OUT:
+ notif = &rt->line_out_notify;
+ name = "lineout-detect";
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mutex_lock(&notif->mutex);
+
+ old = notif->notify;
+
+ if (!old && !notify) {
+ err = 0;
+ goto out_unlock;
+ }
+
+ if (old && notify) {
+ if (old == notify && notif->data == data)
+ err = 0;
+ goto out_unlock;
+ }
+
+ if (old && !notify) {
+ irq_client = notif->gpio_private;
+ pmf_unregister_irq_client(irq_client);
+ kfree(irq_client);
+ notif->gpio_private = NULL;
+ }
+ if (!old && notify) {
+ irq_client = kzalloc(sizeof(struct pmf_irq_client),
+ GFP_KERNEL);
+ irq_client->data = notif;
+ irq_client->handler = pmf_handle_notify_irq;
+ irq_client->owner = THIS_MODULE;
+ err = pmf_register_irq_client(rt->node,
+ name,
+ irq_client);
+ if (err) {
+ printk(KERN_ERR "snd-aoa: gpio layer failed to"
+ " register %s irq (%d)\n", name, err);
+ kfree(irq_client);
+ goto out_unlock;
+ }
+ notif->gpio_private = irq_client;
+ }
+ notif->notify = notify;
+ notif->data = data;
+
+ err = 0;
+ out_unlock:
+ mutex_unlock(&notif->mutex);
+ return err;
+}
+
+static int pmf_get_detect(struct gpio_runtime *rt,
+ enum notify_type type)
+{
+ char *name;
+ int err = -EBUSY, ret;
+ struct pmf_args args = { .count = 1, .u[0].p = &ret };
+
+ switch (type) {
+ case AOA_NOTIFY_HEADPHONE:
+ name = "headphone-detect";
+ break;
+ case AOA_NOTIFY_LINE_IN:
+ name = "linein-detect";
+ break;
+ case AOA_NOTIFY_LINE_OUT:
+ name = "lineout-detect";
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = pmf_call_function(rt->node, name, &args);
+ if (err)
+ return err;
+ return ret;
+}
+
+static struct gpio_methods methods = {
+ .init = pmf_gpio_init,
+ .exit = pmf_gpio_exit,
+ .all_amps_off = pmf_gpio_all_amps_off,
+ .all_amps_restore = pmf_gpio_all_amps_restore,
+ .set_headphone = pmf_gpio_set_headphone,
+ .set_speakers = pmf_gpio_set_amp,
+ .set_lineout = pmf_gpio_set_lineout,
+ .set_hw_reset = pmf_gpio_set_hw_reset,
+ .get_headphone = pmf_gpio_get_headphone,
+ .get_speakers = pmf_gpio_get_amp,
+ .get_lineout = pmf_gpio_get_lineout,
+ .set_notify = pmf_set_notify,
+ .get_detect = pmf_get_detect,
+};
+
+struct gpio_methods *pmf_gpio_methods = &methods;
+EXPORT_SYMBOL_GPL(pmf_gpio_methods);
diff --git a/sound/aoa/fabrics/Kconfig b/sound/aoa/fabrics/Kconfig
new file mode 100644
index 0000000..c3bc770
--- /dev/null
+++ b/sound/aoa/fabrics/Kconfig
@@ -0,0 +1,12 @@
+config SND_AOA_FABRIC_LAYOUT
+ tristate "layout-id fabric"
+ depends SND_AOA
+ select SND_AOA_SOUNDBUS
+ select SND_AOA_SOUNDBUS_I2S
+ ---help---
+ This enables the layout-id fabric for the Apple Onboard
+ Audio driver, the module holding it all together
+ based on the device-tree's layout-id property.
+
+ If you are unsure and have a later Apple machine,
+ compile it as a module.
diff --git a/sound/aoa/fabrics/Makefile b/sound/aoa/fabrics/Makefile
new file mode 100644
index 0000000..55fc5e7
--- /dev/null
+++ b/sound/aoa/fabrics/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SND_AOA_FABRIC_LAYOUT) += snd-aoa-fabric-layout.o
diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/snd-aoa-fabric-layout.c
new file mode 100644
index 0000000..04a7238
--- /dev/null
+++ b/sound/aoa/fabrics/snd-aoa-fabric-layout.c
@@ -0,0 +1,1109 @@
+/*
+ * Apple Onboard Audio driver -- layout fabric
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ *
+ *
+ * This fabric module looks for sound codecs
+ * based on the layout-id property in the device tree.
+ *
+ */
+
+#include <asm/prom.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include "../aoa.h"
+#include "../soundbus/soundbus.h"
+
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Layout-ID fabric for snd-aoa");
+
+#define MAX_CODECS_PER_BUS 2
+
+/* These are the connections the layout fabric
+ * knows about. It doesn't really care about the
+ * input ones, but I thought I'd separate them
+ * to give them proper names. The thing is that
+ * Apple usually will distinguish the active output
+ * by GPIOs, while the active input is set directly
+ * on the codec. Hence we here tell the codec what
+ * we think is connected. This information is hard-
+ * coded below ... */
+#define CC_SPEAKERS (1<<0)
+#define CC_HEADPHONE (1<<1)
+#define CC_LINEOUT (1<<2)
+#define CC_DIGITALOUT (1<<3)
+#define CC_LINEIN (1<<4)
+#define CC_MICROPHONE (1<<5)
+#define CC_DIGITALIN (1<<6)
+/* pretty bogus but users complain...
+ * This is a flag saying that the LINEOUT
+ * should be renamed to HEADPHONE.
+ * be careful with input detection! */
+#define CC_LINEOUT_LABELLED_HEADPHONE (1<<7)
+
+struct codec_connection {
+ /* CC_ flags from above */
+ int connected;
+ /* codec dependent bit to be set in the aoa_codec.connected field.
+ * This intentionally doesn't have any generic flags because the
+ * fabric has to know the codec anyway and all codecs might have
+ * different connectors */
+ int codec_bit;
+};
+
+struct codec_connect_info {
+ char *name;
+ struct codec_connection *connections;
+};
+
+#define LAYOUT_FLAG_COMBO_LINEOUT_SPDIF (1<<0)
+
+struct layout {
+ unsigned int layout_id;
+ struct codec_connect_info codecs[MAX_CODECS_PER_BUS];
+ int flags;
+
+ /* if busname is not assigned, we use 'Master' below,
+ * so that our layout table doesn't need to be filled
+ * too much.
+ * We only assign these two if we expect to find more
+ * than one soundbus, i.e. on those machines with
+ * multiple layout-ids */
+ char *busname;
+ int pcmid;
+};
+
+MODULE_ALIAS("sound-layout-41");
+MODULE_ALIAS("sound-layout-45");
+MODULE_ALIAS("sound-layout-51");
+MODULE_ALIAS("sound-layout-58");
+MODULE_ALIAS("sound-layout-60");
+MODULE_ALIAS("sound-layout-61");
+MODULE_ALIAS("sound-layout-64");
+MODULE_ALIAS("sound-layout-65");
+MODULE_ALIAS("sound-layout-68");
+MODULE_ALIAS("sound-layout-69");
+MODULE_ALIAS("sound-layout-70");
+MODULE_ALIAS("sound-layout-72");
+MODULE_ALIAS("sound-layout-80");
+MODULE_ALIAS("sound-layout-82");
+MODULE_ALIAS("sound-layout-84");
+MODULE_ALIAS("sound-layout-86");
+MODULE_ALIAS("sound-layout-92");
+
+/* onyx with all but microphone connected */
+static struct codec_connection onyx_connections_nomic[] = {
+ {
+ .connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT,
+ .codec_bit = 0,
+ },
+ {
+ .connected = CC_DIGITALOUT,
+ .codec_bit = 1,
+ },
+ {
+ .connected = CC_LINEIN,
+ .codec_bit = 2,
+ },
+ {} /* terminate array by .connected == 0 */
+};
+
+/* onyx on machines without headphone */
+static struct codec_connection onyx_connections_noheadphones[] = {
+ {
+ .connected = CC_SPEAKERS | CC_LINEOUT |
+ CC_LINEOUT_LABELLED_HEADPHONE,
+ .codec_bit = 0,
+ },
+ {
+ .connected = CC_DIGITALOUT,
+ .codec_bit = 1,
+ },
+ /* FIXME: are these correct? probably not for all the machines
+ * below ... If not this will need separating. */
+ {
+ .connected = CC_LINEIN,
+ .codec_bit = 2,
+ },
+ {
+ .connected = CC_MICROPHONE,
+ .codec_bit = 3,
+ },
+ {} /* terminate array by .connected == 0 */
+};
+
+/* onyx on machines with real line-out */
+static struct codec_connection onyx_connections_reallineout[] = {
+ {
+ .connected = CC_SPEAKERS | CC_LINEOUT | CC_HEADPHONE,
+ .codec_bit = 0,
+ },
+ {
+ .connected = CC_DIGITALOUT,
+ .codec_bit = 1,
+ },
+ {
+ .connected = CC_LINEIN,
+ .codec_bit = 2,
+ },
+ {} /* terminate array by .connected == 0 */
+};
+
+/* tas on machines without line out */
+static struct codec_connection tas_connections_nolineout[] = {
+ {
+ .connected = CC_SPEAKERS | CC_HEADPHONE,
+ .codec_bit = 0,
+ },
+ {
+ .connected = CC_LINEIN,
+ .codec_bit = 2,
+ },
+ {
+ .connected = CC_MICROPHONE,
+ .codec_bit = 3,
+ },
+ {} /* terminate array by .connected == 0 */
+};
+
+/* tas on machines with neither line out nor line in */
+static struct codec_connection tas_connections_noline[] = {
+ {
+ .connected = CC_SPEAKERS | CC_HEADPHONE,
+ .codec_bit = 0,
+ },
+ {
+ .connected = CC_MICROPHONE,
+ .codec_bit = 3,
+ },
+ {} /* terminate array by .connected == 0 */
+};
+
+/* tas on machines without microphone */
+static struct codec_connection tas_connections_nomic[] = {
+ {
+ .connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT,
+ .codec_bit = 0,
+ },
+ {
+ .connected = CC_LINEIN,
+ .codec_bit = 2,
+ },
+ {} /* terminate array by .connected == 0 */
+};
+
+/* tas on machines with everything connected */
+static struct codec_connection tas_connections_all[] = {
+ {
+ .connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT,
+ .codec_bit = 0,
+ },
+ {
+ .connected = CC_LINEIN,
+ .codec_bit = 2,
+ },
+ {
+ .connected = CC_MICROPHONE,
+ .codec_bit = 3,
+ },
+ {} /* terminate array by .connected == 0 */
+};
+
+static struct codec_connection toonie_connections[] = {
+ {
+ .connected = CC_SPEAKERS | CC_HEADPHONE,
+ .codec_bit = 0,
+ },
+ {} /* terminate array by .connected == 0 */
+};
+
+static struct codec_connection topaz_input[] = {
+ {
+ .connected = CC_DIGITALIN,
+ .codec_bit = 0,
+ },
+ {} /* terminate array by .connected == 0 */
+};
+
+static struct codec_connection topaz_output[] = {
+ {
+ .connected = CC_DIGITALOUT,
+ .codec_bit = 1,
+ },
+ {} /* terminate array by .connected == 0 */
+};
+
+static struct codec_connection topaz_inout[] = {
+ {
+ .connected = CC_DIGITALIN,
+ .codec_bit = 0,
+ },
+ {
+ .connected = CC_DIGITALOUT,
+ .codec_bit = 1,
+ },
+ {} /* terminate array by .connected == 0 */
+};
+
+static struct layout layouts[] = {
+ /* last PowerBooks (15" Oct 2005) */
+ { .layout_id = 82,
+ .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF,
+ .codecs[0] = {
+ .name = "onyx",
+ .connections = onyx_connections_noheadphones,
+ },
+ .codecs[1] = {
+ .name = "topaz",
+ .connections = topaz_input,
+ },
+ },
+ /* PowerMac9,1 */
+ { .layout_id = 60,
+ .codecs[0] = {
+ .name = "onyx",
+ .connections = onyx_connections_reallineout,
+ },
+ },
+ /* PowerMac9,1 */
+ { .layout_id = 61,
+ .codecs[0] = {
+ .name = "topaz",
+ .connections = topaz_input,
+ },
+ },
+ /* PowerBook5,7 */
+ { .layout_id = 64,
+ .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF,
+ .codecs[0] = {
+ .name = "onyx",
+ .connections = onyx_connections_noheadphones,
+ },
+ },
+ /* PowerBook5,7 */
+ { .layout_id = 65,
+ .codecs[0] = {
+ .name = "topaz",
+ .connections = topaz_input,
+ },
+ },
+ /* PowerBook5,9 [17" Oct 2005] */
+ { .layout_id = 84,
+ .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF,
+ .codecs[0] = {
+ .name = "onyx",
+ .connections = onyx_connections_noheadphones,
+ },
+ .codecs[1] = {
+ .name = "topaz",
+ .connections = topaz_input,
+ },
+ },
+ /* PowerMac8,1 */
+ { .layout_id = 45,
+ .codecs[0] = {
+ .name = "onyx",
+ .connections = onyx_connections_noheadphones,
+ },
+ .codecs[1] = {
+ .name = "topaz",
+ .connections = topaz_input,
+ },
+ },
+ /* Quad PowerMac (analog in, analog/digital out) */
+ { .layout_id = 68,
+ .codecs[0] = {
+ .name = "onyx",
+ .connections = onyx_connections_nomic,
+ },
+ },
+ /* Quad PowerMac (digital in) */
+ { .layout_id = 69,
+ .codecs[0] = {
+ .name = "topaz",
+ .connections = topaz_input,
+ },
+ .busname = "digital in", .pcmid = 1 },
+ /* Early 2005 PowerBook (PowerBook 5,6) */
+ { .layout_id = 70,
+ .codecs[0] = {
+ .name = "tas",
+ .connections = tas_connections_nolineout,
+ },
+ },
+ /* PowerBook 5,4 */
+ { .layout_id = 51,
+ .codecs[0] = {
+ .name = "tas",
+ .connections = tas_connections_nolineout,
+ },
+ },
+ /* PowerBook6,7 */
+ { .layout_id = 80,
+ .codecs[0] = {
+ .name = "tas",
+ .connections = tas_connections_noline,
+ },
+ },
+ /* PowerBook6,8 */
+ { .layout_id = 72,
+ .codecs[0] = {
+ .name = "tas",
+ .connections = tas_connections_nolineout,
+ },
+ },
+ /* PowerMac8,2 */
+ { .layout_id = 86,
+ .codecs[0] = {
+ .name = "onyx",
+ .connections = onyx_connections_nomic,
+ },
+ .codecs[1] = {
+ .name = "topaz",
+ .connections = topaz_input,
+ },
+ },
+ /* PowerBook6,7 */
+ { .layout_id = 92,
+ .codecs[0] = {
+ .name = "tas",
+ .connections = tas_connections_nolineout,
+ },
+ },
+ /* PowerMac10,1 (Mac Mini) */
+ { .layout_id = 58,
+ .codecs[0] = {
+ .name = "toonie",
+ .connections = toonie_connections,
+ },
+ },
+ /* unknown, untested, but this comes from Apple */
+ { .layout_id = 41,
+ .codecs[0] = {
+ .name = "tas",
+ .connections = tas_connections_all,
+ },
+ },
+ { .layout_id = 36,
+ .codecs[0] = {
+ .name = "tas",
+ .connections = tas_connections_nomic,
+ },
+ .codecs[1] = {
+ .name = "topaz",
+ .connections = topaz_inout,
+ },
+ },
+ { .layout_id = 47,
+ .codecs[0] = {
+ .name = "onyx",
+ .connections = onyx_connections_noheadphones,
+ },
+ },
+ { .layout_id = 48,
+ .codecs[0] = {
+ .name = "topaz",
+ .connections = topaz_input,
+ },
+ },
+ { .layout_id = 49,
+ .codecs[0] = {
+ .name = "onyx",
+ .connections = onyx_connections_nomic,
+ },
+ },
+ { .layout_id = 50,
+ .codecs[0] = {
+ .name = "topaz",
+ .connections = topaz_input,
+ },
+ },
+ { .layout_id = 56,
+ .codecs[0] = {
+ .name = "onyx",
+ .connections = onyx_connections_noheadphones,
+ },
+ },
+ { .layout_id = 57,
+ .codecs[0] = {
+ .name = "topaz",
+ .connections = topaz_input,
+ },
+ },
+ { .layout_id = 62,
+ .codecs[0] = {
+ .name = "onyx",
+ .connections = onyx_connections_noheadphones,
+ },
+ .codecs[1] = {
+ .name = "topaz",
+ .connections = topaz_output,
+ },
+ },
+ { .layout_id = 66,
+ .codecs[0] = {
+ .name = "onyx",
+ .connections = onyx_connections_noheadphones,
+ },
+ },
+ { .layout_id = 67,
+ .codecs[0] = {
+ .name = "topaz",
+ .connections = topaz_input,
+ },
+ },
+ { .layout_id = 76,
+ .codecs[0] = {
+ .name = "tas",
+ .connections = tas_connections_nomic,
+ },
+ .codecs[1] = {
+ .name = "topaz",
+ .connections = topaz_inout,
+ },
+ },
+ { .layout_id = 90,
+ .codecs[0] = {
+ .name = "tas",
+ .connections = tas_connections_noline,
+ },
+ },
+ { .layout_id = 94,
+ .codecs[0] = {
+ .name = "onyx",
+ /* but it has an external mic?? how to select? */
+ .connections = onyx_connections_noheadphones,
+ },
+ },
+ { .layout_id = 96,
+ .codecs[0] = {
+ .name = "onyx",
+ .connections = onyx_connections_noheadphones,
+ },
+ },
+ { .layout_id = 98,
+ .codecs[0] = {
+ .name = "toonie",
+ .connections = toonie_connections,
+ },
+ },
+ { .layout_id = 100,
+ .codecs[0] = {
+ .name = "topaz",
+ .connections = topaz_input,
+ },
+ .codecs[1] = {
+ .name = "onyx",
+ .connections = onyx_connections_noheadphones,
+ },
+ },
+ {}
+};
+
+static struct layout *find_layout_by_id(unsigned int id)
+{
+ struct layout *l;
+
+ l = layouts;
+ while (l->layout_id) {
+ if (l->layout_id == id)
+ return l;
+ l++;
+ }
+ return NULL;
+}
+
+static void use_layout(struct layout *l)
+{
+ int i;
+
+ for (i=0; i<MAX_CODECS_PER_BUS; i++) {
+ if (l->codecs[i].name) {
+ request_module("snd-aoa-codec-%s", l->codecs[i].name);
+ }
+ }
+ /* now we wait for the codecs to call us back */
+}
+
+struct layout_dev;
+
+struct layout_dev_ptr {
+ struct layout_dev *ptr;
+};
+
+struct layout_dev {
+ struct list_head list;
+ struct soundbus_dev *sdev;
+ struct device_node *sound;
+ struct aoa_codec *codecs[MAX_CODECS_PER_BUS];
+ struct layout *layout;
+ struct gpio_runtime gpio;
+
+ /* we need these for headphone/lineout detection */
+ struct snd_kcontrol *headphone_ctrl;
+ struct snd_kcontrol *lineout_ctrl;
+ struct snd_kcontrol *speaker_ctrl;
+ struct snd_kcontrol *headphone_detected_ctrl;
+ struct snd_kcontrol *lineout_detected_ctrl;
+
+ struct layout_dev_ptr selfptr_headphone;
+ struct layout_dev_ptr selfptr_lineout;
+
+ u32 have_lineout_detect:1,
+ have_headphone_detect:1,
+ switch_on_headphone:1,
+ switch_on_lineout:1;
+};
+
+static LIST_HEAD(layouts_list);
+static int layouts_list_items;
+/* this can go away but only if we allow multiple cards,
+ * make the fabric handle all the card stuff, etc... */
+static struct layout_dev *layout_device;
+
+static int control_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+#define AMP_CONTROL(n, description) \
+static int n##_control_get(struct snd_kcontrol *kcontrol, \
+ struct snd_ctl_elem_value *ucontrol) \
+{ \
+ struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol); \
+ if (gpio->methods && gpio->methods->get_##n) \
+ ucontrol->value.integer.value[0] = \
+ gpio->methods->get_##n(gpio); \
+ return 0; \
+} \
+static int n##_control_put(struct snd_kcontrol *kcontrol, \
+ struct snd_ctl_elem_value *ucontrol) \
+{ \
+ struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol); \
+ if (gpio->methods && gpio->methods->get_##n) \
+ gpio->methods->set_##n(gpio, \
+ ucontrol->value.integer.value[0]); \
+ return 1; \
+} \
+static struct snd_kcontrol_new n##_ctl = { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = description, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .info = control_info, \
+ .get = n##_control_get, \
+ .put = n##_control_put, \
+}
+
+AMP_CONTROL(headphone, "Headphone Switch");
+AMP_CONTROL(speakers, "Speakers Switch");
+AMP_CONTROL(lineout, "Line-Out Switch");
+
+static int detect_choice_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct layout_dev *ldev = snd_kcontrol_chip(kcontrol);
+
+ switch (kcontrol->private_value) {
+ case 0:
+ ucontrol->value.integer.value[0] = ldev->switch_on_headphone;
+ break;
+ case 1:
+ ucontrol->value.integer.value[0] = ldev->switch_on_lineout;
+ break;
+ default:
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int detect_choice_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct layout_dev *ldev = snd_kcontrol_chip(kcontrol);
+
+ switch (kcontrol->private_value) {
+ case 0:
+ ldev->switch_on_headphone = !!ucontrol->value.integer.value[0];
+ break;
+ case 1:
+ ldev->switch_on_lineout = !!ucontrol->value.integer.value[0];
+ break;
+ default:
+ return -ENODEV;
+ }
+ return 1;
+}
+
+static struct snd_kcontrol_new headphone_detect_choice = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Headphone Detect Autoswitch",
+ .info = control_info,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .get = detect_choice_get,
+ .put = detect_choice_put,
+ .private_value = 0,
+};
+
+static struct snd_kcontrol_new lineout_detect_choice = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Line-Out Detect Autoswitch",
+ .info = control_info,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .get = detect_choice_get,
+ .put = detect_choice_put,
+ .private_value = 1,
+};
+
+static int detected_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct layout_dev *ldev = snd_kcontrol_chip(kcontrol);
+ int v;
+
+ switch (kcontrol->private_value) {
+ case 0:
+ v = ldev->gpio.methods->get_detect(&ldev->gpio,
+ AOA_NOTIFY_HEADPHONE);
+ break;
+ case 1:
+ v = ldev->gpio.methods->get_detect(&ldev->gpio,
+ AOA_NOTIFY_LINE_OUT);
+ break;
+ default:
+ return -ENODEV;
+ }
+ ucontrol->value.integer.value[0] = v;
+ return 0;
+}
+
+static struct snd_kcontrol_new headphone_detected = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Headphone Detected",
+ .info = control_info,
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .get = detected_get,
+ .private_value = 0,
+};
+
+static struct snd_kcontrol_new lineout_detected = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Line-Out Detected",
+ .info = control_info,
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .get = detected_get,
+ .private_value = 1,
+};
+
+static int check_codec(struct aoa_codec *codec,
+ struct layout_dev *ldev,
+ struct codec_connect_info *cci)
+{
+ u32 *ref;
+ char propname[32];
+ struct codec_connection *cc;
+
+ /* if the codec has a 'codec' node, we require a reference */
+ if (codec->node && (strcmp(codec->node->name, "codec") == 0)) {
+ snprintf(propname, sizeof(propname),
+ "platform-%s-codec-ref", codec->name);
+ ref = (u32*)get_property(ldev->sound, propname, NULL);
+ if (!ref) {
+ printk(KERN_INFO "snd-aoa-fabric-layout: "
+ "required property %s not present\n", propname);
+ return -ENODEV;
+ }
+ if (*ref != codec->node->linux_phandle) {
+ printk(KERN_INFO "snd-aoa-fabric-layout: "
+ "%s doesn't match!\n", propname);
+ return -ENODEV;
+ }
+ } else {
+ if (layouts_list_items != 1) {
+ printk(KERN_INFO "snd-aoa-fabric-layout: "
+ "more than one soundbus, but no references.\n");
+ return -ENODEV;
+ }
+ }
+ codec->soundbus_dev = ldev->sdev;
+ codec->gpio = &ldev->gpio;
+
+ cc = cci->connections;
+ if (!cc)
+ return -EINVAL;
+
+ printk(KERN_INFO "snd-aoa-fabric-layout: can use this codec\n");
+
+ codec->connected = 0;
+ codec->fabric_data = cc;
+
+ while (cc->connected) {
+ codec->connected |= 1<<cc->codec_bit;
+ cc++;
+ }
+
+ return 0;
+}
+
+static int layout_found_codec(struct aoa_codec *codec)
+{
+ struct layout_dev *ldev;
+ int i;
+
+ list_for_each_entry(ldev, &layouts_list, list) {
+ for (i=0; i<MAX_CODECS_PER_BUS; i++) {
+ if (!ldev->layout->codecs[i].name)
+ continue;
+ if (strcmp(ldev->layout->codecs[i].name, codec->name) == 0) {
+ if (check_codec(codec,
+ ldev,
+ &ldev->layout->codecs[i]) == 0)
+ return 0;
+ }
+ }
+ }
+ return -ENODEV;
+}
+
+static void layout_remove_codec(struct aoa_codec *codec)
+{
+ int i;
+ /* here remove the codec from the layout dev's
+ * codec reference */
+
+ codec->soundbus_dev = NULL;
+ codec->gpio = NULL;
+ for (i=0; i<MAX_CODECS_PER_BUS; i++) {
+ }
+}
+
+static void layout_notify(void *data)
+{
+ struct layout_dev_ptr *dptr = data;
+ struct layout_dev *ldev;
+ int v, update;
+ struct snd_kcontrol *detected, *c;
+ struct snd_card *card = aoa_get_card();
+
+ ldev = dptr->ptr;
+ if (data == &ldev->selfptr_headphone) {
+ v = ldev->gpio.methods->get_detect(&ldev->gpio, AOA_NOTIFY_HEADPHONE);
+ detected = ldev->headphone_detected_ctrl;
+ update = ldev->switch_on_headphone;
+ if (update) {
+ ldev->gpio.methods->set_speakers(&ldev->gpio, !v);
+ ldev->gpio.methods->set_headphone(&ldev->gpio, v);
+ ldev->gpio.methods->set_lineout(&ldev->gpio, 0);
+ }
+ } else if (data == &ldev->selfptr_lineout) {
+ v = ldev->gpio.methods->get_detect(&ldev->gpio, AOA_NOTIFY_LINE_OUT);
+ detected = ldev->lineout_detected_ctrl;
+ update = ldev->switch_on_lineout;
+ if (update) {
+ ldev->gpio.methods->set_speakers(&ldev->gpio, !v);
+ ldev->gpio.methods->set_headphone(&ldev->gpio, 0);
+ ldev->gpio.methods->set_lineout(&ldev->gpio, v);
+ }
+ } else
+ return;
+
+ if (detected)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &detected->id);
+ if (update) {
+ c = ldev->headphone_ctrl;
+ if (c)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id);
+ c = ldev->speaker_ctrl;
+ if (c)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id);
+ c = ldev->lineout_ctrl;
+ if (c)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id);
+ }
+}
+
+static void layout_attached_codec(struct aoa_codec *codec)
+{
+ struct codec_connection *cc;
+ struct snd_kcontrol *ctl;
+ int headphones, lineout;
+ struct layout_dev *ldev = layout_device;
+
+ /* need to add this codec to our codec array! */
+
+ cc = codec->fabric_data;
+
+ headphones = codec->gpio->methods->get_detect(codec->gpio,
+ AOA_NOTIFY_HEADPHONE);
+ lineout = codec->gpio->methods->get_detect(codec->gpio,
+ AOA_NOTIFY_LINE_OUT);
+
+ while (cc->connected) {
+ if (cc->connected & CC_SPEAKERS) {
+ if (headphones <= 0 && lineout <= 0)
+ ldev->gpio.methods->set_speakers(codec->gpio, 1);
+ ctl = snd_ctl_new1(&speakers_ctl, codec->gpio);
+ ldev->speaker_ctrl = ctl;
+ aoa_snd_ctl_add(ctl);
+ }
+ if (cc->connected & CC_HEADPHONE) {
+ if (headphones == 1)
+ ldev->gpio.methods->set_headphone(codec->gpio, 1);
+ ctl = snd_ctl_new1(&headphone_ctl, codec->gpio);
+ ldev->headphone_ctrl = ctl;
+ aoa_snd_ctl_add(ctl);
+ ldev->have_headphone_detect =
+ !ldev->gpio.methods
+ ->set_notify(&ldev->gpio,
+ AOA_NOTIFY_HEADPHONE,
+ layout_notify,
+ &ldev->selfptr_headphone);
+ if (ldev->have_headphone_detect) {
+ ctl = snd_ctl_new1(&headphone_detect_choice,
+ ldev);
+ aoa_snd_ctl_add(ctl);
+ ctl = snd_ctl_new1(&headphone_detected,
+ ldev);
+ ldev->headphone_detected_ctrl = ctl;
+ aoa_snd_ctl_add(ctl);
+ }
+ }
+ if (cc->connected & CC_LINEOUT) {
+ if (lineout == 1)
+ ldev->gpio.methods->set_lineout(codec->gpio, 1);
+ ctl = snd_ctl_new1(&lineout_ctl, codec->gpio);
+ if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
+ strlcpy(ctl->id.name,
+ "Headphone Switch", sizeof(ctl->id.name));
+ ldev->lineout_ctrl = ctl;
+ aoa_snd_ctl_add(ctl);
+ ldev->have_lineout_detect =
+ !ldev->gpio.methods
+ ->set_notify(&ldev->gpio,
+ AOA_NOTIFY_LINE_OUT,
+ layout_notify,
+ &ldev->selfptr_lineout);
+ if (ldev->have_lineout_detect) {
+ ctl = snd_ctl_new1(&lineout_detect_choice,
+ ldev);
+ if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
+ strlcpy(ctl->id.name,
+ "Headphone Detect Autoswitch",
+ sizeof(ctl->id.name));
+ aoa_snd_ctl_add(ctl);
+ ctl = snd_ctl_new1(&lineout_detected,
+ ldev);
+ if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
+ strlcpy(ctl->id.name,
+ "Headphone Detected",
+ sizeof(ctl->id.name));
+ ldev->lineout_detected_ctrl = ctl;
+ aoa_snd_ctl_add(ctl);
+ }
+ }
+ cc++;
+ }
+ /* now update initial state */
+ if (ldev->have_headphone_detect)
+ layout_notify(&ldev->selfptr_headphone);
+ if (ldev->have_lineout_detect)
+ layout_notify(&ldev->selfptr_lineout);
+}
+
+static struct aoa_fabric layout_fabric = {
+ .name = "SoundByLayout",
+ .owner = THIS_MODULE,
+ .found_codec = layout_found_codec,
+ .remove_codec = layout_remove_codec,
+ .attached_codec = layout_attached_codec,
+};
+
+static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
+{
+ struct device_node *sound = NULL;
+ unsigned int *layout_id;
+ struct layout *layout;
+ struct layout_dev *ldev = NULL;
+ int err;
+
+ /* hm, currently we can only have one ... */
+ if (layout_device)
+ return -ENODEV;
+
+ /* by breaking out we keep a reference */
+ while ((sound = of_get_next_child(sdev->ofdev.node, sound))) {
+ if (sound->type && strcasecmp(sound->type, "soundchip") == 0)
+ break;
+ }
+ if (!sound) return -ENODEV;
+
+ layout_id = (unsigned int *) get_property(sound, "layout-id", NULL);
+ if (!layout_id)
+ goto outnodev;
+ printk(KERN_INFO "snd-aoa-fabric-layout: found bus with layout %d ", *layout_id);
+
+ layout = find_layout_by_id(*layout_id);
+ if (!layout) {
+ printk("(no idea how to handle)\n");
+ goto outnodev;
+ }
+
+ ldev = kzalloc(sizeof(struct layout_dev), GFP_KERNEL);
+ if (!ldev)
+ goto outnodev;
+
+ layout_device = ldev;
+ ldev->sdev = sdev;
+ ldev->sound = sound;
+ ldev->layout = layout;
+ ldev->gpio.node = sound->parent;
+ switch (layout->layout_id) {
+ case 41: /* that unknown machine no one seems to have */
+ case 51: /* PowerBook5,4 */
+ case 58: /* Mac Mini */
+ ldev->gpio.methods = ftr_gpio_methods;
+ break;
+ default:
+ ldev->gpio.methods = pmf_gpio_methods;
+ }
+ ldev->selfptr_headphone.ptr = ldev;
+ ldev->selfptr_lineout.ptr = ldev;
+ sdev->ofdev.dev.driver_data = ldev;
+
+ printk("(using)\n");
+ list_add(&ldev->list, &layouts_list);
+ layouts_list_items++;
+
+ /* assign these before registering ourselves, so
+ * callbacks that are done during registration
+ * already have the values */
+ sdev->pcmid = ldev->layout->pcmid;
+ if (ldev->layout->busname) {
+ sdev->pcmname = ldev->layout->busname;
+ } else {
+ sdev->pcmname = "Master";
+ }
+
+ ldev->gpio.methods->init(&ldev->gpio);
+
+ err = aoa_fabric_register(&layout_fabric);
+ if (err && err != -EALREADY) {
+ printk(KERN_INFO "snd-aoa-fabric-layout: can't use,"
+ " another fabric is active!\n");
+ goto outlistdel;
+ }
+
+ use_layout(layout);
+ ldev->switch_on_headphone = 1;
+ ldev->switch_on_lineout = 1;
+ return 0;
+ outlistdel:
+ /* we won't be using these then... */
+ ldev->gpio.methods->exit(&ldev->gpio);
+ /* reset if we didn't use it */
+ sdev->pcmname = NULL;
+ sdev->pcmid = -1;
+ list_del(&ldev->list);
+ layouts_list_items--;
+ outnodev:
+ if (sound) of_node_put(sound);
+ layout_device = NULL;
+ if (ldev) kfree(ldev);
+ return -ENODEV;
+}
+
+static int aoa_fabric_layout_remove(struct soundbus_dev *sdev)
+{
+ struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
+ int i;
+
+ for (i=0; i<MAX_CODECS_PER_BUS; i++) {
+ if (ldev->codecs[i]) {
+ aoa_fabric_unlink_codec(ldev->codecs[i]);
+ }
+ ldev->codecs[i] = NULL;
+ }
+ list_del(&ldev->list);
+ layouts_list_items--;
+ of_node_put(ldev->sound);
+
+ ldev->gpio.methods->set_notify(&ldev->gpio,
+ AOA_NOTIFY_HEADPHONE,
+ NULL,
+ NULL);
+ ldev->gpio.methods->set_notify(&ldev->gpio,
+ AOA_NOTIFY_LINE_OUT,
+ NULL,
+ NULL);
+
+ ldev->gpio.methods->exit(&ldev->gpio);
+ layout_device = NULL;
+ kfree(ldev);
+ sdev->pcmid = -1;
+ sdev->pcmname = NULL;
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int aoa_fabric_layout_suspend(struct soundbus_dev *sdev, pm_message_t state)
+{
+ struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
+
+ printk("aoa_fabric_layout_suspend()\n");
+
+ if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
+ ldev->gpio.methods->all_amps_off(&ldev->gpio);
+
+ return 0;
+}
+
+static int aoa_fabric_layout_resume(struct soundbus_dev *sdev)
+{
+ struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
+
+ printk("aoa_fabric_layout_resume()\n");
+
+ if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
+ ldev->gpio.methods->all_amps_restore(&ldev->gpio);
+
+ return 0;
+}
+#endif
+
+static struct soundbus_driver aoa_soundbus_driver = {
+ .name = "snd_aoa_soundbus_drv",
+ .owner = THIS_MODULE,
+ .probe = aoa_fabric_layout_probe,
+ .remove = aoa_fabric_layout_remove,
+#ifdef CONFIG_PM
+ .suspend = aoa_fabric_layout_suspend,
+ .resume = aoa_fabric_layout_resume,
+#endif
+};
+
+static int __init aoa_fabric_layout_init(void)
+{
+ int err;
+
+ err = soundbus_register_driver(&aoa_soundbus_driver);
+ if (err)
+ return err;
+ return 0;
+}
+
+static void __exit aoa_fabric_layout_exit(void)
+{
+ soundbus_unregister_driver(&aoa_soundbus_driver);
+ aoa_fabric_unregister(&layout_fabric);
+}
+
+module_init(aoa_fabric_layout_init);
+module_exit(aoa_fabric_layout_exit);
diff --git a/sound/aoa/soundbus/Kconfig b/sound/aoa/soundbus/Kconfig
new file mode 100644
index 0000000..d532d27
--- /dev/null
+++ b/sound/aoa/soundbus/Kconfig
@@ -0,0 +1,14 @@
+config SND_AOA_SOUNDBUS
+ tristate "Apple Soundbus support"
+ depends on SOUND && SND_PCM && EXPERIMENTAL
+ ---help---
+ This option enables the generic driver for the soundbus
+ support on Apple machines.
+
+ It is required for the sound bus implementations.
+
+config SND_AOA_SOUNDBUS_I2S
+ tristate "I2S bus support"
+ depends on SND_AOA_SOUNDBUS && PCI
+ ---help---
+ This option enables support for Apple I2S busses.
diff --git a/sound/aoa/soundbus/Makefile b/sound/aoa/soundbus/Makefile
new file mode 100644
index 0000000..0e61f5a
--- /dev/null
+++ b/sound/aoa/soundbus/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SND_AOA_SOUNDBUS) += snd-aoa-soundbus.o
+snd-aoa-soundbus-objs := core.o sysfs.o
+obj-$(CONFIG_SND_AOA_SOUNDBUS_I2S) += i2sbus/
diff --git a/sound/aoa/soundbus/core.c b/sound/aoa/soundbus/core.c
new file mode 100644
index 0000000..abe84a7
--- /dev/null
+++ b/sound/aoa/soundbus/core.c
@@ -0,0 +1,250 @@
+/*
+ * soundbus
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+
+#include <linux/module.h>
+#include "soundbus.h"
+
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Apple Soundbus");
+
+struct soundbus_dev *soundbus_dev_get(struct soundbus_dev *dev)
+{
+ struct device *tmp;
+
+ if (!dev)
+ return NULL;
+ tmp = get_device(&dev->ofdev.dev);
+ if (tmp)
+ return to_soundbus_device(tmp);
+ else
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(soundbus_dev_get);
+
+void soundbus_dev_put(struct soundbus_dev *dev)
+{
+ if (dev)
+ put_device(&dev->ofdev.dev);
+}
+EXPORT_SYMBOL_GPL(soundbus_dev_put);
+
+static int soundbus_probe(struct device *dev)
+{
+ int error = -ENODEV;
+ struct soundbus_driver *drv;
+ struct soundbus_dev *soundbus_dev;
+
+ drv = to_soundbus_driver(dev->driver);
+ soundbus_dev = to_soundbus_device(dev);
+
+ if (!drv->probe)
+ return error;
+
+ soundbus_dev_get(soundbus_dev);
+
+ error = drv->probe(soundbus_dev);
+ if (error)
+ soundbus_dev_put(soundbus_dev);
+
+ return error;
+}
+
+
+static int soundbus_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
+ struct soundbus_dev * soundbus_dev;
+ struct of_device * of;
+ char *scratch, *compat, *compat2;
+ int i = 0;
+ int length, cplen, cplen2, seen = 0;
+
+ if (!dev)
+ return -ENODEV;
+
+ soundbus_dev = to_soundbus_device(dev);
+ if (!soundbus_dev)
+ return -ENODEV;
+
+ of = &soundbus_dev->ofdev;
+
+ /* stuff we want to pass to /sbin/hotplug */
+ envp[i++] = scratch = buffer;
+ length = scnprintf (scratch, buffer_size, "OF_NAME=%s", of->node->name);
+ ++length;
+ buffer_size -= length;
+ if ((buffer_size <= 0) || (i >= num_envp))
+ return -ENOMEM;
+ scratch += length;
+
+ envp[i++] = scratch;
+ length = scnprintf (scratch, buffer_size, "OF_TYPE=%s", of->node->type);
+ ++length;
+ buffer_size -= length;
+ if ((buffer_size <= 0) || (i >= num_envp))
+ return -ENOMEM;
+ scratch += length;
+
+ /* Since the compatible field can contain pretty much anything
+ * it's not really legal to split it out with commas. We split it
+ * up using a number of environment variables instead. */
+
+ compat = (char *) get_property(of->node, "compatible", &cplen);
+ compat2 = compat;
+ cplen2= cplen;
+ while (compat && cplen > 0) {
+ envp[i++] = scratch;
+ length = scnprintf (scratch, buffer_size,
+ "OF_COMPATIBLE_%d=%s", seen, compat);
+ ++length;
+ buffer_size -= length;
+ if ((buffer_size <= 0) || (i >= num_envp))
+ return -ENOMEM;
+ scratch += length;
+ length = strlen (compat) + 1;
+ compat += length;
+ cplen -= length;
+ seen++;
+ }
+
+ envp[i++] = scratch;
+ length = scnprintf (scratch, buffer_size, "OF_COMPATIBLE_N=%d", seen);
+ ++length;
+ buffer_size -= length;
+ if ((buffer_size <= 0) || (i >= num_envp))
+ return -ENOMEM;
+ scratch += length;
+
+ envp[i++] = scratch;
+ length = scnprintf (scratch, buffer_size, "MODALIAS=%s",
+ soundbus_dev->modalias);
+
+ buffer_size -= length;
+ if ((buffer_size <= 0) || (i >= num_envp))
+ return -ENOMEM;
+
+ envp[i] = NULL;
+
+ return 0;
+}
+
+static int soundbus_device_remove(struct device *dev)
+{
+ struct soundbus_dev * soundbus_dev = to_soundbus_device(dev);
+ struct soundbus_driver * drv = to_soundbus_driver(dev->driver);
+
+ if (dev->driver && drv->remove)
+ drv->remove(soundbus_dev);
+ soundbus_dev_put(soundbus_dev);
+
+ return 0;
+}
+
+static void soundbus_device_shutdown(struct device *dev)
+{
+ struct soundbus_dev * soundbus_dev = to_soundbus_device(dev);
+ struct soundbus_driver * drv = to_soundbus_driver(dev->driver);
+
+ if (dev->driver && drv->shutdown)
+ drv->shutdown(soundbus_dev);
+}
+
+#ifdef CONFIG_PM
+
+static int soundbus_device_suspend(struct device *dev, pm_message_t state)
+{
+ struct soundbus_dev * soundbus_dev = to_soundbus_device(dev);
+ struct soundbus_driver * drv = to_soundbus_driver(dev->driver);
+
+ if (dev->driver && drv->suspend)
+ return drv->suspend(soundbus_dev, state);
+ return 0;
+}
+
+static int soundbus_device_resume(struct device * dev)
+{
+ struct soundbus_dev * soundbus_dev = to_soundbus_device(dev);
+ struct soundbus_driver * drv = to_soundbus_driver(dev->driver);
+
+ if (dev->driver && drv->resume)
+ return drv->resume(soundbus_dev);
+ return 0;
+}
+
+#endif /* CONFIG_PM */
+
+extern struct device_attribute soundbus_dev_attrs[];
+
+static struct bus_type soundbus_bus_type = {
+ .name = "aoa-soundbus",
+ .probe = soundbus_probe,
+ .uevent = soundbus_uevent,
+ .remove = soundbus_device_remove,
+ .shutdown = soundbus_device_shutdown,
+#ifdef CONFIG_PM
+ .suspend = soundbus_device_suspend,
+ .resume = soundbus_device_resume,
+#endif
+ .dev_attrs = soundbus_dev_attrs,
+};
+
+static int __init soundbus_init(void)
+{
+ return bus_register(&soundbus_bus_type);
+}
+
+static void __exit soundbus_exit(void)
+{
+ bus_unregister(&soundbus_bus_type);
+}
+
+int soundbus_add_one(struct soundbus_dev *dev)
+{
+ static int devcount;
+
+ /* sanity checks */
+ if (!dev->attach_codec ||
+ !dev->ofdev.node ||
+ dev->pcmname ||
+ dev->pcmid != -1) {
+ printk(KERN_ERR "soundbus: adding device failed sanity check!\n");
+ return -EINVAL;
+ }
+
+ snprintf(dev->ofdev.dev.bus_id, BUS_ID_SIZE, "soundbus:%x", ++devcount);
+ dev->ofdev.dev.bus = &soundbus_bus_type;
+ return of_device_register(&dev->ofdev);
+}
+EXPORT_SYMBOL_GPL(soundbus_add_one);
+
+void soundbus_remove_one(struct soundbus_dev *dev)
+{
+ of_device_unregister(&dev->ofdev);
+}
+EXPORT_SYMBOL_GPL(soundbus_remove_one);
+
+int soundbus_register_driver(struct soundbus_driver *drv)
+{
+ /* initialize common driver fields */
+ drv->driver.name = drv->name;
+ drv->driver.bus = &soundbus_bus_type;
+
+ /* register with core */
+ return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(soundbus_register_driver);
+
+void soundbus_unregister_driver(struct soundbus_driver *drv)
+{
+ driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(soundbus_unregister_driver);
+
+module_init(soundbus_init);
+module_exit(soundbus_exit);
diff --git a/sound/aoa/soundbus/i2sbus/Makefile b/sound/aoa/soundbus/i2sbus/Makefile
new file mode 100644
index 0000000..e57a5cf
--- /dev/null
+++ b/sound/aoa/soundbus/i2sbus/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_SND_AOA_SOUNDBUS_I2S) += snd-aoa-i2sbus.o
+snd-aoa-i2sbus-objs := i2sbus-core.o i2sbus-pcm.o i2sbus-control.o
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-control.c b/sound/aoa/soundbus/i2sbus/i2sbus-control.c
new file mode 100644
index 0000000..f504079
--- /dev/null
+++ b/sound/aoa/soundbus/i2sbus/i2sbus-control.c
@@ -0,0 +1,192 @@
+/*
+ * i2sbus driver -- bus control routines
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <asm/prom.h>
+#include <asm/macio.h>
+#include <asm/pmac_feature.h>
+#include <asm/pmac_pfunc.h>
+#include "i2sbus.h"
+
+int i2sbus_control_init(struct macio_dev* dev, struct i2sbus_control **c)
+{
+ *c = kzalloc(sizeof(struct i2sbus_control), GFP_KERNEL);
+ if (!*c)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&(*c)->list);
+
+ if (of_address_to_resource(dev->ofdev.node, 0, &(*c)->rsrc))
+ goto err;
+ /* we really should be using feature calls instead of mapping
+ * these registers. It's safe for now since no one else is
+ * touching them... */
+ (*c)->controlregs = ioremap((*c)->rsrc.start,
+ sizeof(struct i2s_control_regs));
+ if (!(*c)->controlregs)
+ goto err;
+
+ return 0;
+ err:
+ kfree(*c);
+ *c = NULL;
+ return -ENODEV;
+}
+
+void i2sbus_control_destroy(struct i2sbus_control *c)
+{
+ iounmap(c->controlregs);
+ kfree(c);
+}
+
+/* this is serialised externally */
+int i2sbus_control_add_dev(struct i2sbus_control *c,
+ struct i2sbus_dev *i2sdev)
+{
+ struct device_node *np;
+
+ np = i2sdev->sound.ofdev.node;
+ i2sdev->enable = pmf_find_function(np, "enable");
+ i2sdev->cell_enable = pmf_find_function(np, "cell-enable");
+ i2sdev->clock_enable = pmf_find_function(np, "clock-enable");
+ i2sdev->cell_disable = pmf_find_function(np, "cell-disable");
+ i2sdev->clock_disable = pmf_find_function(np, "clock-disable");
+
+ /* if the bus number is not 0 or 1 we absolutely need to use
+ * the platform functions -- there's nothing in Darwin that
+ * would allow seeing a system behind what the FCRs are then,
+ * and I don't want to go parsing a bunch of platform functions
+ * by hand to try finding a system... */
+ if (i2sdev->bus_number != 0 && i2sdev->bus_number != 1 &&
+ (!i2sdev->enable ||
+ !i2sdev->cell_enable || !i2sdev->clock_enable ||
+ !i2sdev->cell_disable || !i2sdev->clock_disable)) {
+ pmf_put_function(i2sdev->enable);
+ pmf_put_function(i2sdev->cell_enable);
+ pmf_put_function(i2sdev->clock_enable);
+ pmf_put_function(i2sdev->cell_disable);
+ pmf_put_function(i2sdev->clock_disable);
+ return -ENODEV;
+ }
+
+ list_add(&i2sdev->item, &c->list);
+
+ return 0;
+}
+
+void i2sbus_control_remove_dev(struct i2sbus_control *c,
+ struct i2sbus_dev *i2sdev)
+{
+ /* this is serialised externally */
+ list_del(&i2sdev->item);
+ if (list_empty(&c->list))
+ i2sbus_control_destroy(c);
+}
+
+int i2sbus_control_enable(struct i2sbus_control *c,
+ struct i2sbus_dev *i2sdev)
+{
+ struct pmf_args args = { .count = 0 };
+ int cc;
+
+ if (i2sdev->enable)
+ return pmf_call_one(i2sdev->enable, &args);
+
+ switch (i2sdev->bus_number) {
+ case 0:
+ cc = in_le32(&c->controlregs->cell_control);
+ out_le32(&c->controlregs->cell_control, cc | CTRL_CLOCK_INTF_0_ENABLE);
+ break;
+ case 1:
+ cc = in_le32(&c->controlregs->cell_control);
+ out_le32(&c->controlregs->cell_control, cc | CTRL_CLOCK_INTF_1_ENABLE);
+ break;
+ default:
+ return -ENODEV;
+ }
+ return 0;
+}
+
+int i2sbus_control_cell(struct i2sbus_control *c,
+ struct i2sbus_dev *i2sdev,
+ int enable)
+{
+ struct pmf_args args = { .count = 0 };
+ int cc;
+
+ switch (enable) {
+ case 0:
+ if (i2sdev->cell_disable)
+ return pmf_call_one(i2sdev->cell_disable, &args);
+ break;
+ case 1:
+ if (i2sdev->cell_enable)
+ return pmf_call_one(i2sdev->cell_enable, &args);
+ break;
+ default:
+ printk(KERN_ERR "i2sbus: INVALID CELL ENABLE VALUE\n");
+ return -ENODEV;
+ }
+ switch (i2sdev->bus_number) {
+ case 0:
+ cc = in_le32(&c->controlregs->cell_control);
+ cc &= ~CTRL_CLOCK_CELL_0_ENABLE;
+ cc |= enable * CTRL_CLOCK_CELL_0_ENABLE;
+ out_le32(&c->controlregs->cell_control, cc);
+ break;
+ case 1:
+ cc = in_le32(&c->controlregs->cell_control);
+ cc &= ~CTRL_CLOCK_CELL_1_ENABLE;
+ cc |= enable * CTRL_CLOCK_CELL_1_ENABLE;
+ out_le32(&c->controlregs->cell_control, cc);
+ break;
+ default:
+ return -ENODEV;
+ }
+ return 0;
+}
+
+int i2sbus_control_clock(struct i2sbus_control *c,
+ struct i2sbus_dev *i2sdev,
+ int enable)
+{
+ struct pmf_args args = { .count = 0 };
+ int cc;
+
+ switch (enable) {
+ case 0:
+ if (i2sdev->clock_disable)
+ return pmf_call_one(i2sdev->clock_disable, &args);
+ break;
+ case 1:
+ if (i2sdev->clock_enable)
+ return pmf_call_one(i2sdev->clock_enable, &args);
+ break;
+ default:
+ printk(KERN_ERR "i2sbus: INVALID CLOCK ENABLE VALUE\n");
+ return -ENODEV;
+ }
+ switch (i2sdev->bus_number) {
+ case 0:
+ cc = in_le32(&c->controlregs->cell_control);
+ cc &= ~CTRL_CLOCK_CLOCK_0_ENABLE;
+ cc |= enable * CTRL_CLOCK_CLOCK_0_ENABLE;
+ out_le32(&c->controlregs->cell_control, cc);
+ break;
+ case 1:
+ cc = in_le32(&c->controlregs->cell_control);
+ cc &= ~CTRL_CLOCK_CLOCK_1_ENABLE;
+ cc |= enable * CTRL_CLOCK_CLOCK_1_ENABLE;
+ out_le32(&c->controlregs->cell_control, cc);
+ break;
+ default:
+ return -ENODEV;
+ }
+ return 0;
+}
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-control.h b/sound/aoa/soundbus/i2sbus/i2sbus-control.h
new file mode 100644
index 0000000..bb05550
--- /dev/null
+++ b/sound/aoa/soundbus/i2sbus/i2sbus-control.h
@@ -0,0 +1,37 @@
+/*
+ * i2sbus driver -- bus register definitions
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+#ifndef __I2SBUS_CONTROLREGS_H
+#define __I2SBUS_CONTROLREGS_H
+
+/* i2s control registers, at least what we know about them */
+
+#define __PAD(m,n) u8 __pad##m[n]
+#define _PAD(line, n) __PAD(line, n)
+#define PAD(n) _PAD(__LINE__, (n))
+struct i2s_control_regs {
+ PAD(0x38);
+ __le32 fcr0; /* 0x38 (unknown) */
+ __le32 cell_control; /* 0x3c (fcr1) */
+ __le32 fcr2; /* 0x40 (unknown) */
+ __le32 fcr3; /* 0x44 (fcr3) */
+ __le32 clock_control; /* 0x48 (unknown) */
+ PAD(4);
+ /* total size: 0x50 bytes */
+} __attribute__((__packed__));
+
+#define CTRL_CLOCK_CELL_0_ENABLE (1<<10)
+#define CTRL_CLOCK_CLOCK_0_ENABLE (1<<12)
+#define CTRL_CLOCK_SWRESET_0 (1<<11)
+#define CTRL_CLOCK_INTF_0_ENABLE (1<<13)
+
+#define CTRL_CLOCK_CELL_1_ENABLE (1<<17)
+#define CTRL_CLOCK_CLOCK_1_ENABLE (1<<18)
+#define CTRL_CLOCK_SWRESET_1 (1<<19)
+#define CTRL_CLOCK_INTF_1_ENABLE (1<<20)
+
+#endif /* __I2SBUS_CONTROLREGS_H */
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c
new file mode 100644
index 0000000..f268dac
--- /dev/null
+++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c
@@ -0,0 +1,387 @@
+/*
+ * i2sbus driver
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+
+#include <linux/module.h>
+#include <asm/macio.h>
+#include <asm/dbdma.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <linux/dma-mapping.h>
+#include "../soundbus.h"
+#include "i2sbus.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
+MODULE_DESCRIPTION("Apple Soundbus: I2S support");
+/* for auto-loading, declare that we handle this weird
+ * string that macio puts into the relevant device */
+MODULE_ALIAS("of:Ni2sTi2sC");
+
+static struct of_device_id i2sbus_match[] = {
+ { .name = "i2s" },
+ { }
+};
+
+static int alloc_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev,
+ struct dbdma_command_mem *r,
+ int numcmds)
+{
+ /* one more for rounding */
+ r->size = (numcmds+1) * sizeof(struct dbdma_cmd);
+ /* We use the PCI APIs for now until the generic one gets fixed
+ * enough or until we get some macio-specific versions
+ */
+ r->space = dma_alloc_coherent(
+ &macio_get_pci_dev(i2sdev->macio)->dev,
+ r->size,
+ &r->bus_addr,
+ GFP_KERNEL);
+
+ if (!r->space) return -ENOMEM;
+
+ memset(r->space, 0, r->size);
+ r->cmds = (void*)DBDMA_ALIGN(r->space);
+ r->bus_cmd_start = r->bus_addr +
+ (dma_addr_t)((char*)r->cmds - (char*)r->space);
+
+ return 0;
+}
+
+static void free_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev,
+ struct dbdma_command_mem *r)
+{
+ if (!r->space) return;
+
+ dma_free_coherent(&macio_get_pci_dev(i2sdev->macio)->dev,
+ r->size, r->space, r->bus_addr);
+}
+
+static void i2sbus_release_dev(struct device *dev)
+{
+ struct i2sbus_dev *i2sdev;
+ int i;
+
+ i2sdev = container_of(dev, struct i2sbus_dev, sound.ofdev.dev);
+
+ if (i2sdev->intfregs) iounmap(i2sdev->intfregs);
+ if (i2sdev->out.dbdma) iounmap(i2sdev->out.dbdma);
+ if (i2sdev->in.dbdma) iounmap(i2sdev->in.dbdma);
+ for (i=0;i<3;i++)
+ if (i2sdev->allocated_resource[i])
+ release_and_free_resource(i2sdev->allocated_resource[i]);
+ free_dbdma_descriptor_ring(i2sdev, &i2sdev->out.dbdma_ring);
+ free_dbdma_descriptor_ring(i2sdev, &i2sdev->in.dbdma_ring);
+ for (i=0;i<3;i++)
+ free_irq(i2sdev->interrupts[i], i2sdev);
+ i2sbus_control_remove_dev(i2sdev->control, i2sdev);
+ mutex_destroy(&i2sdev->lock);
+ kfree(i2sdev);
+}
+
+static irqreturn_t i2sbus_bus_intr(int irq, void *devid, struct pt_regs *regs)
+{
+ struct i2sbus_dev *dev = devid;
+ u32 intreg;
+
+ spin_lock(&dev->low_lock);
+ intreg = in_le32(&dev->intfregs->intr_ctl);
+
+ /* acknowledge interrupt reasons */
+ out_le32(&dev->intfregs->intr_ctl, intreg);
+
+ spin_unlock(&dev->low_lock);
+
+ return IRQ_HANDLED;
+}
+
+static int force;
+module_param(force, int, 0444);
+MODULE_PARM_DESC(force, "Force loading i2sbus even when"
+ " no layout-id property is present");
+
+/* FIXME: look at device node refcounting */
+static int i2sbus_add_dev(struct macio_dev *macio,
+ struct i2sbus_control *control,
+ struct device_node *np)
+{
+ struct i2sbus_dev *dev;
+ struct device_node *child = NULL, *sound = NULL;
+ int i;
+ static const char *rnames[] = { "i2sbus: %s (control)",
+ "i2sbus: %s (tx)",
+ "i2sbus: %s (rx)" };
+ static irqreturn_t (*ints[])(int irq, void *devid,
+ struct pt_regs *regs) = {
+ i2sbus_bus_intr,
+ i2sbus_tx_intr,
+ i2sbus_rx_intr
+ };
+
+ if (strlen(np->name) != 5)
+ return 0;
+ if (strncmp(np->name, "i2s-", 4))
+ return 0;
+
+ if (np->n_intrs != 3)
+ return 0;
+
+ dev = kzalloc(sizeof(struct i2sbus_dev), GFP_KERNEL);
+ if (!dev)
+ return 0;
+
+ i = 0;
+ while ((child = of_get_next_child(np, child))) {
+ if (strcmp(child->name, "sound") == 0) {
+ i++;
+ sound = child;
+ }
+ }
+ if (i == 1) {
+ u32 *layout_id;
+ layout_id = (u32*) get_property(sound, "layout-id", NULL);
+ if (layout_id) {
+ snprintf(dev->sound.modalias, 32,
+ "sound-layout-%d", *layout_id);
+ force = 1;
+ }
+ }
+ /* for the time being, until we can handle non-layout-id
+ * things in some fabric, refuse to attach if there is no
+ * layout-id property or we haven't been forced to attach.
+ * When there are two i2s busses and only one has a layout-id,
+ * then this depends on the order, but that isn't important
+ * either as the second one in that case is just a modem. */
+ if (!force) {
+ kfree(dev);
+ return -ENODEV;
+ }
+
+ mutex_init(&dev->lock);
+ spin_lock_init(&dev->low_lock);
+ dev->sound.ofdev.node = np;
+ dev->sound.ofdev.dma_mask = macio->ofdev.dma_mask;
+ dev->sound.ofdev.dev.dma_mask = &dev->sound.ofdev.dma_mask;
+ dev->sound.ofdev.dev.parent = &macio->ofdev.dev;
+ dev->sound.ofdev.dev.release = i2sbus_release_dev;
+ dev->sound.attach_codec = i2sbus_attach_codec;
+ dev->sound.detach_codec = i2sbus_detach_codec;
+ dev->sound.pcmid = -1;
+ dev->macio = macio;
+ dev->control = control;
+ dev->bus_number = np->name[4] - 'a';
+ INIT_LIST_HEAD(&dev->sound.codec_list);
+
+ for (i=0;i<3;i++) {
+ dev->interrupts[i] = -1;
+ snprintf(dev->rnames[i], sizeof(dev->rnames[i]), rnames[i], np->name);
+ }
+ for (i=0;i<3;i++) {
+ if (request_irq(np->intrs[i].line, ints[i], 0, dev->rnames[i], dev))
+ goto err;
+ dev->interrupts[i] = np->intrs[i].line;
+ }
+
+ for (i=0;i<3;i++) {
+ if (of_address_to_resource(np, i, &dev->resources[i]))
+ goto err;
+ /* if only we could use our resource dev->resources[i]...
+ * but request_resource doesn't know about parents and
+ * contained resources... */
+ dev->allocated_resource[i] =
+ request_mem_region(dev->resources[i].start,
+ dev->resources[i].end -
+ dev->resources[i].start + 1,
+ dev->rnames[i]);
+ if (!dev->allocated_resource[i]) {
+ printk(KERN_ERR "i2sbus: failed to claim resource %d!\n", i);
+ goto err;
+ }
+ }
+ /* should do sanity checking here about length of them */
+ dev->intfregs = ioremap(dev->resources[0].start,
+ dev->resources[0].end-dev->resources[0].start+1);
+ dev->out.dbdma = ioremap(dev->resources[1].start,
+ dev->resources[1].end-dev->resources[1].start+1);
+ dev->in.dbdma = ioremap(dev->resources[2].start,
+ dev->resources[2].end-dev->resources[2].start+1);
+ if (!dev->intfregs || !dev->out.dbdma || !dev->in.dbdma)
+ goto err;
+
+ if (alloc_dbdma_descriptor_ring(dev, &dev->out.dbdma_ring,
+ MAX_DBDMA_COMMANDS))
+ goto err;
+ if (alloc_dbdma_descriptor_ring(dev, &dev->in.dbdma_ring,
+ MAX_DBDMA_COMMANDS))
+ goto err;
+
+ if (i2sbus_control_add_dev(dev->control, dev)) {
+ printk(KERN_ERR "i2sbus: control layer didn't like bus\n");
+ goto err;
+ }
+
+ if (soundbus_add_one(&dev->sound)) {
+ printk(KERN_DEBUG "i2sbus: device registration error!\n");
+ goto err;
+ }
+
+ /* enable this cell */
+ i2sbus_control_cell(dev->control, dev, 1);
+ i2sbus_control_enable(dev->control, dev);
+ i2sbus_control_clock(dev->control, dev, 1);
+
+ return 1;
+ err:
+ for (i=0;i<3;i++)
+ if (dev->interrupts[i] != -1)
+ free_irq(dev->interrupts[i], dev);
+ free_dbdma_descriptor_ring(dev, &dev->out.dbdma_ring);
+ free_dbdma_descriptor_ring(dev, &dev->in.dbdma_ring);
+ if (dev->intfregs) iounmap(dev->intfregs);
+ if (dev->out.dbdma) iounmap(dev->out.dbdma);
+ if (dev->in.dbdma) iounmap(dev->in.dbdma);
+ for (i=0;i<3;i++)
+ if (dev->allocated_resource[i])
+ release_and_free_resource(dev->allocated_resource[i]);
+ mutex_destroy(&dev->lock);
+ kfree(dev);
+ return 0;
+}
+
+static int i2sbus_probe(struct macio_dev* dev, const struct of_device_id *match)
+{
+ struct device_node *np = NULL;
+ int got = 0, err;
+ struct i2sbus_control *control = NULL;
+
+ err = i2sbus_control_init(dev, &control);
+ if (err)
+ return err;
+ if (!control) {
+ printk(KERN_ERR "i2sbus_control_init API breakage\n");
+ return -ENODEV;
+ }
+
+ while ((np = of_get_next_child(dev->ofdev.node, np))) {
+ if (device_is_compatible(np, "i2sbus") ||
+ device_is_compatible(np, "i2s-modem")) {
+ got += i2sbus_add_dev(dev, control, np);
+ }
+ }
+
+ if (!got) {
+ /* found none, clean up */
+ i2sbus_control_destroy(control);
+ return -ENODEV;
+ }
+
+ dev->ofdev.dev.driver_data = control;
+
+ return 0;
+}
+
+static int i2sbus_remove(struct macio_dev* dev)
+{
+ struct i2sbus_control *control = dev->ofdev.dev.driver_data;
+ struct i2sbus_dev *i2sdev, *tmp;
+
+ list_for_each_entry_safe(i2sdev, tmp, &control->list, item)
+ soundbus_remove_one(&i2sdev->sound);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state)
+{
+ struct i2sbus_control *control = dev->ofdev.dev.driver_data;
+ struct codec_info_item *cii;
+ struct i2sbus_dev* i2sdev;
+ int err, ret = 0;
+
+ list_for_each_entry(i2sdev, &control->list, item) {
+ /* Notify Alsa */
+ if (i2sdev->sound.pcm) {
+ /* Suspend PCM streams */
+ snd_pcm_suspend_all(i2sdev->sound.pcm);
+ /* Probably useless as we handle
+ * power transitions ourselves */
+ snd_power_change_state(i2sdev->sound.pcm->card,
+ SNDRV_CTL_POWER_D3hot);
+ }
+ /* Notify codecs */
+ list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
+ err = 0;
+ if (cii->codec->suspend)
+ err = cii->codec->suspend(cii, state);
+ if (err)
+ ret = err;
+ }
+ }
+ return ret;
+}
+
+static int i2sbus_resume(struct macio_dev* dev)
+{
+ struct i2sbus_control *control = dev->ofdev.dev.driver_data;
+ struct codec_info_item *cii;
+ struct i2sbus_dev* i2sdev;
+ int err, ret = 0;
+
+ list_for_each_entry(i2sdev, &control->list, item) {
+ /* Notify codecs so they can re-initialize */
+ list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
+ err = 0;
+ if (cii->codec->resume)
+ err = cii->codec->resume(cii);
+ if (err)
+ ret = err;
+ }
+ /* Notify Alsa */
+ if (i2sdev->sound.pcm) {
+ /* Same comment as above, probably useless */
+ snd_power_change_state(i2sdev->sound.pcm->card,
+ SNDRV_CTL_POWER_D0);
+ }
+ }
+
+ return ret;
+}
+#endif /* CONFIG_PM */
+
+static int i2sbus_shutdown(struct macio_dev* dev)
+{
+ return 0;
+}
+
+static struct macio_driver i2sbus_drv = {
+ .name = "soundbus-i2s",
+ .owner = THIS_MODULE,
+ .match_table = i2sbus_match,
+ .probe = i2sbus_probe,
+ .remove = i2sbus_remove,
+#ifdef CONFIG_PM
+ .suspend = i2sbus_suspend,
+ .resume = i2sbus_resume,
+#endif
+ .shutdown = i2sbus_shutdown,
+};
+
+static int __init soundbus_i2sbus_init(void)
+{
+ return macio_register_driver(&i2sbus_drv);
+}
+
+static void __exit soundbus_i2sbus_exit(void)
+{
+ macio_unregister_driver(&i2sbus_drv);
+}
+
+module_init(soundbus_i2sbus_init);
+module_exit(soundbus_i2sbus_exit);
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-interface.h b/sound/aoa/soundbus/i2sbus/i2sbus-interface.h
new file mode 100644
index 0000000..c6b5f54
--- /dev/null
+++ b/sound/aoa/soundbus/i2sbus/i2sbus-interface.h
@@ -0,0 +1,187 @@
+/*
+ * i2sbus driver -- interface register definitions
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+#ifndef __I2SBUS_INTERFACE_H
+#define __I2SBUS_INTERFACE_H
+
+/* i2s bus control registers, at least what we know about them */
+
+#define __PAD(m,n) u8 __pad##m[n]
+#define _PAD(line, n) __PAD(line, n)
+#define PAD(n) _PAD(__LINE__, (n))
+struct i2s_interface_regs {
+ __le32 intr_ctl; /* 0x00 */
+ PAD(12);
+ __le32 serial_format; /* 0x10 */
+ PAD(12);
+ __le32 codec_msg_out; /* 0x20 */
+ PAD(12);
+ __le32 codec_msg_in; /* 0x30 */
+ PAD(12);
+ __le32 frame_count; /* 0x40 */
+ PAD(12);
+ __le32 frame_match; /* 0x50 */
+ PAD(12);
+ __le32 data_word_sizes; /* 0x60 */
+ PAD(12);
+ __le32 peak_level_sel; /* 0x70 */
+ PAD(12);
+ __le32 peak_level_in0; /* 0x80 */
+ PAD(12);
+ __le32 peak_level_in1; /* 0x90 */
+ PAD(12);
+ /* total size: 0x100 bytes */
+} __attribute__((__packed__));
+
+/* interrupt register is just a bitfield with
+ * interrupt enable and pending bits */
+#define I2S_REG_INTR_CTL 0x00
+# define I2S_INT_FRAME_COUNT (1<<31)
+# define I2S_PENDING_FRAME_COUNT (1<<30)
+# define I2S_INT_MESSAGE_FLAG (1<<29)
+# define I2S_PENDING_MESSAGE_FLAG (1<<28)
+# define I2S_INT_NEW_PEAK (1<<27)
+# define I2S_PENDING_NEW_PEAK (1<<26)
+# define I2S_INT_CLOCKS_STOPPED (1<<25)
+# define I2S_PENDING_CLOCKS_STOPPED (1<<24)
+# define I2S_INT_EXTERNAL_SYNC_ERROR (1<<23)
+# define I2S_PENDING_EXTERNAL_SYNC_ERROR (1<<22)
+# define I2S_INT_EXTERNAL_SYNC_OK (1<<21)
+# define I2S_PENDING_EXTERNAL_SYNC_OK (1<<20)
+# define I2S_INT_NEW_SAMPLE_RATE (1<<19)
+# define I2S_PENDING_NEW_SAMPLE_RATE (1<<18)
+# define I2S_INT_STATUS_FLAG (1<<17)
+# define I2S_PENDING_STATUS_FLAG (1<<16)
+
+/* serial format register is more interesting :)
+ * It contains:
+ * - clock source
+ * - MClk divisor
+ * - SClk divisor
+ * - SClk master flag
+ * - serial format (sony, i2s 64x, i2s 32x, dav, silabs)
+ * - external sample frequency interrupt (don't understand)
+ * - external sample frequency
+ */
+#define I2S_REG_SERIAL_FORMAT 0x10
+/* clock source. You get either 18.432, 45.1584 or 49.1520 MHz */
+# define I2S_SF_CLOCK_SOURCE_SHIFT 30
+# define I2S_SF_CLOCK_SOURCE_MASK (3<<I2S_SF_CLOCK_SOURCE_SHIFT)
+# define I2S_SF_CLOCK_SOURCE_18MHz (0<<I2S_SF_CLOCK_SOURCE_SHIFT)
+# define I2S_SF_CLOCK_SOURCE_45MHz (1<<I2S_SF_CLOCK_SOURCE_SHIFT)
+# define I2S_SF_CLOCK_SOURCE_49MHz (2<<I2S_SF_CLOCK_SOURCE_SHIFT)
+/* also, let's define the exact clock speeds here, in Hz */
+#define I2S_CLOCK_SPEED_18MHz 18432000
+#define I2S_CLOCK_SPEED_45MHz 45158400
+#define I2S_CLOCK_SPEED_49MHz 49152000
+/* MClk is the clock that drives the codec, usually called its 'system clock'.
+ * It is derived by taking only every 'divisor' tick of the clock.
+ */
+# define I2S_SF_MCLKDIV_SHIFT 24
+# define I2S_SF_MCLKDIV_MASK (0x1F<<I2S_SF_MCLKDIV_SHIFT)
+# define I2S_SF_MCLKDIV_1 (0x14<<I2S_SF_MCLKDIV_SHIFT)
+# define I2S_SF_MCLKDIV_3 (0x13<<I2S_SF_MCLKDIV_SHIFT)
+# define I2S_SF_MCLKDIV_5 (0x12<<I2S_SF_MCLKDIV_SHIFT)
+# define I2S_SF_MCLKDIV_14 (0x0E<<I2S_SF_MCLKDIV_SHIFT)
+# define I2S_SF_MCLKDIV_OTHER(div) (((div/2-1)<<I2S_SF_MCLKDIV_SHIFT)&I2S_SF_MCLKDIV_MASK)
+static inline int i2s_sf_mclkdiv(int div, int *out)
+{
+ int d;
+
+ switch(div) {
+ case 1: *out |= I2S_SF_MCLKDIV_1; return 0;
+ case 3: *out |= I2S_SF_MCLKDIV_3; return 0;
+ case 5: *out |= I2S_SF_MCLKDIV_5; return 0;
+ case 14: *out |= I2S_SF_MCLKDIV_14; return 0;
+ default:
+ if (div%2) return -1;
+ d = div/2-1;
+ if (d == 0x14 || d == 0x13 || d == 0x12 || d == 0x0E)
+ return -1;
+ *out |= I2S_SF_MCLKDIV_OTHER(div);
+ return 0;
+ }
+}
+/* SClk is the clock that drives the i2s wire bus. Note that it is
+ * derived from the MClk above by taking only every 'divisor' tick
+ * of MClk.
+ */
+# define I2S_SF_SCLKDIV_SHIFT 20
+# define I2S_SF_SCLKDIV_MASK (0xF<<I2S_SF_SCLKDIV_SHIFT)
+# define I2S_SF_SCLKDIV_1 (8<<I2S_SF_SCLKDIV_SHIFT)
+# define I2S_SF_SCLKDIV_3 (9<<I2S_SF_SCLKDIV_SHIFT)
+# define I2S_SF_SCLKDIV_OTHER(div) (((div/2-1)<<I2S_SF_SCLKDIV_SHIFT)&I2S_SF_SCLKDIV_MASK)
+static inline int i2s_sf_sclkdiv(int div, int *out)
+{
+ int d;
+
+ switch(div) {
+ case 1: *out |= I2S_SF_SCLKDIV_1; return 0;
+ case 3: *out |= I2S_SF_SCLKDIV_3; return 0;
+ default:
+ if (div%2) return -1;
+ d = div/2-1;
+ if (d == 8 || d == 9) return -1;
+ *out |= I2S_SF_SCLKDIV_OTHER(div);
+ return 0;
+ }
+}
+# define I2S_SF_SCLK_MASTER (1<<19)
+/* serial format is the way the data is put to the i2s wire bus */
+# define I2S_SF_SERIAL_FORMAT_SHIFT 16
+# define I2S_SF_SERIAL_FORMAT_MASK (7<<I2S_SF_SERIAL_FORMAT_SHIFT)
+# define I2S_SF_SERIAL_FORMAT_SONY (0<<I2S_SF_SERIAL_FORMAT_SHIFT)
+# define I2S_SF_SERIAL_FORMAT_I2S_64X (1<<I2S_SF_SERIAL_FORMAT_SHIFT)
+# define I2S_SF_SERIAL_FORMAT_I2S_32X (2<<I2S_SF_SERIAL_FORMAT_SHIFT)
+# define I2S_SF_SERIAL_FORMAT_I2S_DAV (4<<I2S_SF_SERIAL_FORMAT_SHIFT)
+# define I2S_SF_SERIAL_FORMAT_I2S_SILABS (5<<I2S_SF_SERIAL_FORMAT_SHIFT)
+/* unknown */
+# define I2S_SF_EXT_SAMPLE_FREQ_INT_SHIFT 12
+# define I2S_SF_EXT_SAMPLE_FREQ_INT_MASK (0xF<<I2S_SF_SAMPLE_FREQ_INT_SHIFT)
+/* probably gives external frequency? */
+# define I2S_SF_EXT_SAMPLE_FREQ_MASK 0xFFF
+
+/* used to send codec messages, but how isn't clear */
+#define I2S_REG_CODEC_MSG_OUT 0x20
+
+/* used to receive codec messages, but how isn't clear */
+#define I2S_REG_CODEC_MSG_IN 0x30
+
+/* frame count reg isn't clear to me yet, but probably useful */
+#define I2S_REG_FRAME_COUNT 0x40
+
+/* program to some value, and get interrupt if frame count reaches it */
+#define I2S_REG_FRAME_MATCH 0x50
+
+/* this register describes how the bus transfers data */
+#define I2S_REG_DATA_WORD_SIZES 0x60
+/* number of interleaved input channels */
+# define I2S_DWS_NUM_CHANNELS_IN_SHIFT 24
+# define I2S_DWS_NUM_CHANNELS_IN_MASK (0x1F<<I2S_DWS_NUM_CHANNELS_IN_SHIFT)
+/* word size of input data */
+# define I2S_DWS_DATA_IN_SIZE_SHIFT 16
+# define I2S_DWS_DATA_IN_16BIT (0<<I2S_DWS_DATA_IN_SIZE_SHIFT)
+# define I2S_DWS_DATA_IN_24BIT (3<<I2S_DWS_DATA_IN_SIZE_SHIFT)
+/* number of interleaved output channels */
+# define I2S_DWS_NUM_CHANNELS_OUT_SHIFT 8
+# define I2S_DWS_NUM_CHANNELS_OUT_MASK (0x1F<<I2S_DWS_NUM_CHANNELS_OUT_SHIFT)
+/* word size of output data */
+# define I2S_DWS_DATA_OUT_SIZE_SHIFT 0
+# define I2S_DWS_DATA_OUT_16BIT (0<<I2S_DWS_DATA_OUT_SIZE_SHIFT)
+# define I2S_DWS_DATA_OUT_24BIT (3<<I2S_DWS_DATA_OUT_SIZE_SHIFT)
+
+
+/* unknown */
+#define I2S_REG_PEAK_LEVEL_SEL 0x70
+
+/* unknown */
+#define I2S_REG_PEAK_LEVEL_IN0 0x80
+
+/* unknown */
+#define I2S_REG_PEAK_LEVEL_IN1 0x90
+
+#endif /* __I2SBUS_INTERFACE_H */
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
new file mode 100644
index 0000000..3049015
--- /dev/null
+++ b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
@@ -0,0 +1,1021 @@
+/*
+ * i2sbus driver -- pcm routines
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+
+#include <asm/io.h>
+#include <linux/delay.h>
+/* So apparently there's a reason for requiring driver.h
+ * to be included first, even if I don't know it... */
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <asm/macio.h>
+#include <linux/pci.h>
+#include "../soundbus.h"
+#include "i2sbus.h"
+
+static inline void get_pcm_info(struct i2sbus_dev *i2sdev, int in,
+ struct pcm_info **pi, struct pcm_info **other)
+{
+ if (in) {
+ if (pi)
+ *pi = &i2sdev->in;
+ if (other)
+ *other = &i2sdev->out;
+ } else {
+ if (pi)
+ *pi = &i2sdev->out;
+ if (other)
+ *other = &i2sdev->in;
+ }
+}
+
+static int clock_and_divisors(int mclk, int sclk, int rate, int *out)
+{
+ /* sclk must be derived from mclk! */
+ if (mclk % sclk)
+ return -1;
+ /* derive sclk register value */
+ if (i2s_sf_sclkdiv(mclk / sclk, out))
+ return -1;
+
+ if (I2S_CLOCK_SPEED_18MHz % (rate * mclk) == 0) {
+ if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_18MHz / (rate * mclk), out)) {
+ *out |= I2S_SF_CLOCK_SOURCE_18MHz;
+ return 0;
+ }
+ }
+ if (I2S_CLOCK_SPEED_45MHz % (rate * mclk) == 0) {
+ if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_45MHz / (rate * mclk), out)) {
+ *out |= I2S_SF_CLOCK_SOURCE_45MHz;
+ return 0;
+ }
+ }
+ if (I2S_CLOCK_SPEED_49MHz % (rate * mclk) == 0) {
+ if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_49MHz / (rate * mclk), out)) {
+ *out |= I2S_SF_CLOCK_SOURCE_49MHz;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+#define CHECK_RATE(rate) \
+ do { if (rates & SNDRV_PCM_RATE_ ##rate) { \
+ int dummy; \
+ if (clock_and_divisors(sysclock_factor, \
+ bus_factor, rate, &dummy)) \
+ rates &= ~SNDRV_PCM_RATE_ ##rate; \
+ } } while (0)
+
+static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
+{
+ struct pcm_info *pi, *other;
+ struct soundbus_dev *sdev;
+ int masks_inited = 0, err;
+ struct codec_info_item *cii, *rev;
+ struct snd_pcm_hardware *hw;
+ u64 formats = 0;
+ unsigned int rates = 0;
+ struct transfer_info v;
+ int result = 0;
+ int bus_factor = 0, sysclock_factor = 0;
+ int found_this;
+
+ mutex_lock(&i2sdev->lock);
+
+ get_pcm_info(i2sdev, in, &pi, &other);
+
+ hw = &pi->substream->runtime->hw;
+ sdev = &i2sdev->sound;
+
+ if (pi->active) {
+ /* alsa messed up */
+ result = -EBUSY;
+ goto out_unlock;
+ }
+
+ /* we now need to assign the hw */
+ list_for_each_entry(cii, &sdev->codec_list, list) {
+ struct transfer_info *ti = cii->codec->transfers;
+ bus_factor = cii->codec->bus_factor;
+ sysclock_factor = cii->codec->sysclock_factor;
+ while (ti->formats && ti->rates) {
+ v = *ti;
+ if (ti->transfer_in == in
+ && cii->codec->usable(cii, ti, &v)) {
+ if (masks_inited) {
+ formats &= v.formats;
+ rates &= v.rates;
+ } else {
+ formats = v.formats;
+ rates = v.rates;
+ masks_inited = 1;
+ }
+ }
+ ti++;
+ }
+ }
+ if (!masks_inited || !bus_factor || !sysclock_factor) {
+ result = -ENODEV;
+ goto out_unlock;
+ }
+ /* bus dependent stuff */
+ hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME;
+
+ CHECK_RATE(5512);
+ CHECK_RATE(8000);
+ CHECK_RATE(11025);
+ CHECK_RATE(16000);
+ CHECK_RATE(22050);
+ CHECK_RATE(32000);
+ CHECK_RATE(44100);
+ CHECK_RATE(48000);
+ CHECK_RATE(64000);
+ CHECK_RATE(88200);
+ CHECK_RATE(96000);
+ CHECK_RATE(176400);
+ CHECK_RATE(192000);
+ hw->rates = rates;
+
+ /* well. the codec might want 24 bits only, and we'll
+ * ever only transfer 24 bits, but they are top-aligned!
+ * So for alsa, we claim that we're doing full 32 bit
+ * while in reality we'll ignore the lower 8 bits of
+ * that when doing playback (they're transferred as 0
+ * as far as I know, no codecs we have are 32-bit capable
+ * so I can't really test) and when doing recording we'll
+ * always have those lower 8 bits recorded as 0 */
+ if (formats & SNDRV_PCM_FMTBIT_S24_BE)
+ formats |= SNDRV_PCM_FMTBIT_S32_BE;
+ if (formats & SNDRV_PCM_FMTBIT_U24_BE)
+ formats |= SNDRV_PCM_FMTBIT_U32_BE;
+ /* now mask off what we can support. I suppose we could
+ * also support S24_3LE and some similar formats, but I
+ * doubt there's a codec that would be able to use that,
+ * so we don't support it here. */
+ hw->formats = formats & (SNDRV_PCM_FMTBIT_S16_BE |
+ SNDRV_PCM_FMTBIT_U16_BE |
+ SNDRV_PCM_FMTBIT_S32_BE |
+ SNDRV_PCM_FMTBIT_U32_BE);
+
+ /* we need to set the highest and lowest rate possible.
+ * These are the highest and lowest rates alsa can
+ * support properly in its bitfield.
+ * Below, we'll use that to restrict to the rate
+ * currently in use (if any). */
+ hw->rate_min = 5512;
+ hw->rate_max = 192000;
+ /* if the other stream is active, then we can only
+ * support what it is currently using.
+ * FIXME: I lied. This comment is wrong. We can support
+ * anything that works with the same serial format, ie.
+ * when recording 24 bit sound we can well play 16 bit
+ * sound at the same time iff using the same transfer mode.
+ */
+ if (other->active) {
+ /* FIXME: is this guaranteed by the alsa api? */
+ hw->formats &= (1ULL << i2sdev->format);
+ /* see above, restrict rates to the one we already have */
+ hw->rate_min = i2sdev->rate;
+ hw->rate_max = i2sdev->rate;
+ }
+
+ hw->channels_min = 2;
+ hw->channels_max = 2;
+ /* these are somewhat arbitrary */
+ hw->buffer_bytes_max = 131072;
+ hw->period_bytes_min = 256;
+ hw->period_bytes_max = 16384;
+ hw->periods_min = 3;
+ hw->periods_max = MAX_DBDMA_COMMANDS;
+ list_for_each_entry(cii, &sdev->codec_list, list) {
+ if (cii->codec->open) {
+ err = cii->codec->open(cii, pi->substream);
+ if (err) {
+ result = err;
+ /* unwind */
+ found_this = 0;
+ list_for_each_entry_reverse(rev,
+ &sdev->codec_list, list) {
+ if (found_this && rev->codec->close) {
+ rev->codec->close(rev,
+ pi->substream);
+ }
+ if (rev == cii)
+ found_this = 1;
+ }
+ goto out_unlock;
+ }
+ }
+ }
+
+ out_unlock:
+ mutex_unlock(&i2sdev->lock);
+ return result;
+}
+
+#undef CHECK_RATE
+
+static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in)
+{
+ struct codec_info_item *cii;
+ struct pcm_info *pi;
+ int err = 0, tmp;
+
+ mutex_lock(&i2sdev->lock);
+
+ get_pcm_info(i2sdev, in, &pi, NULL);
+
+ list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
+ if (cii->codec->close) {
+ tmp = cii->codec->close(cii, pi->substream);
+ if (tmp)
+ err = tmp;
+ }
+ }
+
+ pi->substream = NULL;
+ pi->active = 0;
+ mutex_unlock(&i2sdev->lock);
+ return err;
+}
+
+static int i2sbus_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+}
+
+static int i2sbus_hw_free(struct snd_pcm_substream *substream)
+{
+ snd_pcm_lib_free_pages(substream);
+ return 0;
+}
+
+static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
+{
+ /* whee. Hard work now. The user has selected a bitrate
+ * and bit format, so now we have to program our
+ * I2S controller appropriately. */
+ struct snd_pcm_runtime *runtime;
+ struct dbdma_cmd *command;
+ int i, periodsize;
+ dma_addr_t offset;
+ struct bus_info bi;
+ struct codec_info_item *cii;
+ int sfr = 0; /* serial format register */
+ int dws = 0; /* data word sizes reg */
+ int input_16bit;
+ struct pcm_info *pi, *other;
+ int cnt;
+ int result = 0;
+
+ mutex_lock(&i2sdev->lock);
+
+ get_pcm_info(i2sdev, in, &pi, &other);
+
+ if (pi->dbdma_ring.running) {
+ result = -EBUSY;
+ goto out_unlock;
+ }
+
+ runtime = pi->substream->runtime;
+ pi->active = 1;
+ if (other->active &&
+ ((i2sdev->format != runtime->format)
+ || (i2sdev->rate != runtime->rate))) {
+ result = -EINVAL;
+ goto out_unlock;
+ }
+
+ i2sdev->format = runtime->format;
+ i2sdev->rate = runtime->rate;
+
+ periodsize = snd_pcm_lib_period_bytes(pi->substream);
+ pi->current_period = 0;
+
+ /* generate dbdma command ring first */
+ command = pi->dbdma_ring.cmds;
+ offset = runtime->dma_addr;
+ for (i = 0; i < pi->substream->runtime->periods;
+ i++, command++, offset += periodsize) {
+ memset(command, 0, sizeof(struct dbdma_cmd));
+ command->command =
+ cpu_to_le16((in ? INPUT_MORE : OUTPUT_MORE) | INTR_ALWAYS);
+ command->phy_addr = cpu_to_le32(offset);
+ command->req_count = cpu_to_le16(periodsize);
+ command->xfer_status = cpu_to_le16(0);
+ }
+ /* last one branches back to first */
+ command--;
+ command->command |= cpu_to_le16(BR_ALWAYS);
+ command->cmd_dep = cpu_to_le32(pi->dbdma_ring.bus_cmd_start);
+
+ /* ok, let's set the serial format and stuff */
+ switch (runtime->format) {
+ /* 16 bit formats */
+ case SNDRV_PCM_FORMAT_S16_BE:
+ case SNDRV_PCM_FORMAT_U16_BE:
+ /* FIXME: if we add different bus factors we need to
+ * do more here!! */
+ bi.bus_factor = 0;
+ list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
+ bi.bus_factor = cii->codec->bus_factor;
+ break;
+ }
+ if (!bi.bus_factor) {
+ result = -ENODEV;
+ goto out_unlock;
+ }
+ input_16bit = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S32_BE:
+ case SNDRV_PCM_FORMAT_U32_BE:
+ /* force 64x bus speed, otherwise the data cannot be
+ * transferred quickly enough! */
+ bi.bus_factor = 64;
+ input_16bit = 0;
+ break;
+ default:
+ result = -EINVAL;
+ goto out_unlock;
+ }
+ /* we assume all sysclocks are the same! */
+ list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
+ bi.sysclock_factor = cii->codec->sysclock_factor;
+ break;
+ }
+
+ if (clock_and_divisors(bi.sysclock_factor,
+ bi.bus_factor,
+ runtime->rate,
+ &sfr) < 0) {
+ result = -EINVAL;
+ goto out_unlock;
+ }
+ switch (bi.bus_factor) {
+ case 32:
+ sfr |= I2S_SF_SERIAL_FORMAT_I2S_32X;
+ break;
+ case 64:
+ sfr |= I2S_SF_SERIAL_FORMAT_I2S_64X;
+ break;
+ }
+ /* FIXME: THIS ASSUMES MASTER ALL THE TIME */
+ sfr |= I2S_SF_SCLK_MASTER;
+
+ list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
+ int err = 0;
+ if (cii->codec->prepare)
+ err = cii->codec->prepare(cii, &bi, pi->substream);
+ if (err) {
+ result = err;
+ goto out_unlock;
+ }
+ }
+ /* codecs are fine with it, so set our clocks */
+ if (input_16bit)
+ dws = (2 << I2S_DWS_NUM_CHANNELS_IN_SHIFT) |
+ (2 << I2S_DWS_NUM_CHANNELS_OUT_SHIFT) |
+ I2S_DWS_DATA_IN_16BIT | I2S_DWS_DATA_OUT_16BIT;
+ else
+ dws = (2 << I2S_DWS_NUM_CHANNELS_IN_SHIFT) |
+ (2 << I2S_DWS_NUM_CHANNELS_OUT_SHIFT) |
+ I2S_DWS_DATA_IN_24BIT | I2S_DWS_DATA_OUT_24BIT;
+
+ /* early exit if already programmed correctly */
+ /* not locking these is fine since we touch them only in this function */
+ if (in_le32(&i2sdev->intfregs->serial_format) == sfr
+ && in_le32(&i2sdev->intfregs->data_word_sizes) == dws)
+ goto out_unlock;
+
+ /* let's notify the codecs about clocks going away.
+ * For now we only do mastering on the i2s cell... */
+ list_for_each_entry(cii, &i2sdev->sound.codec_list, list)
+ if (cii->codec->switch_clock)
+ cii->codec->switch_clock(cii, CLOCK_SWITCH_PREPARE_SLAVE);
+
+ i2sbus_control_enable(i2sdev->control, i2sdev);
+ i2sbus_control_cell(i2sdev->control, i2sdev, 1);
+
+ out_le32(&i2sdev->intfregs->intr_ctl, I2S_PENDING_CLOCKS_STOPPED);
+
+ i2sbus_control_clock(i2sdev->control, i2sdev, 0);
+
+ msleep(1);
+
+ /* wait for clock stopped. This can apparently take a while... */
+ cnt = 100;
+ while (cnt-- &&
+ !(in_le32(&i2sdev->intfregs->intr_ctl) & I2S_PENDING_CLOCKS_STOPPED)) {
+ msleep(5);
+ }
+ out_le32(&i2sdev->intfregs->intr_ctl, I2S_PENDING_CLOCKS_STOPPED);
+
+ /* not locking these is fine since we touch them only in this function */
+ out_le32(&i2sdev->intfregs->serial_format, sfr);
+ out_le32(&i2sdev->intfregs->data_word_sizes, dws);
+
+ i2sbus_control_enable(i2sdev->control, i2sdev);
+ i2sbus_control_cell(i2sdev->control, i2sdev, 1);
+ i2sbus_control_clock(i2sdev->control, i2sdev, 1);
+ msleep(1);
+
+ list_for_each_entry(cii, &i2sdev->sound.codec_list, list)
+ if (cii->codec->switch_clock)
+ cii->codec->switch_clock(cii, CLOCK_SWITCH_SLAVE);
+
+ out_unlock:
+ mutex_unlock(&i2sdev->lock);
+ return result;
+}
+
+static struct dbdma_cmd STOP_CMD = {
+ .command = __constant_cpu_to_le16(DBDMA_STOP),
+};
+
+static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd)
+{
+ struct codec_info_item *cii;
+ struct pcm_info *pi;
+ int timeout;
+ struct dbdma_cmd tmp;
+ int result = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&i2sdev->low_lock, flags);
+
+ get_pcm_info(i2sdev, in, &pi, NULL);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ if (pi->dbdma_ring.running) {
+ result = -EALREADY;
+ goto out_unlock;
+ }
+ list_for_each_entry(cii, &i2sdev->sound.codec_list, list)
+ if (cii->codec->start)
+ cii->codec->start(cii, pi->substream);
+ pi->dbdma_ring.running = 1;
+
+ /* reset dma engine */
+ out_le32(&pi->dbdma->control,
+ 0 | (RUN | PAUSE | FLUSH | WAKE) << 16);
+ timeout = 100;
+ while (in_le32(&pi->dbdma->status) & RUN && timeout--)
+ udelay(1);
+ if (timeout <= 0) {
+ printk(KERN_ERR
+ "i2sbus: error waiting for dma reset\n");
+ result = -ENXIO;
+ goto out_unlock;
+ }
+
+ /* write dma command buffer address to the dbdma chip */
+ out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start);
+ /* post PCI write */
+ mb();
+ (void)in_le32(&pi->dbdma->status);
+
+ /* change first command to STOP */
+ tmp = *pi->dbdma_ring.cmds;
+ *pi->dbdma_ring.cmds = STOP_CMD;
+
+ /* set running state, remember that the first command is STOP */
+ out_le32(&pi->dbdma->control, RUN | (RUN << 16));
+ timeout = 100;
+ /* wait for STOP to be executed */
+ while (in_le32(&pi->dbdma->status) & ACTIVE && timeout--)
+ udelay(1);
+ if (timeout <= 0) {
+ printk(KERN_ERR "i2sbus: error waiting for dma stop\n");
+ result = -ENXIO;
+ goto out_unlock;
+ }
+ /* again, write dma command buffer address to the dbdma chip,
+ * this time of the first real command */
+ *pi->dbdma_ring.cmds = tmp;
+ out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start);
+ /* post write */
+ mb();
+ (void)in_le32(&pi->dbdma->status);
+
+ /* reset dma engine again */
+ out_le32(&pi->dbdma->control,
+ 0 | (RUN | PAUSE | FLUSH | WAKE) << 16);
+ timeout = 100;
+ while (in_le32(&pi->dbdma->status) & RUN && timeout--)
+ udelay(1);
+ if (timeout <= 0) {
+ printk(KERN_ERR
+ "i2sbus: error waiting for dma reset\n");
+ result = -ENXIO;
+ goto out_unlock;
+ }
+
+ /* wake up the chip with the next descriptor */
+ out_le32(&pi->dbdma->control,
+ (RUN | WAKE) | ((RUN | WAKE) << 16));
+ /* get the frame count */
+ pi->frame_count = in_le32(&i2sdev->intfregs->frame_count);
+
+ /* off you go! */
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ if (!pi->dbdma_ring.running) {
+ result = -EALREADY;
+ goto out_unlock;
+ }
+
+ /* turn off all relevant bits */
+ out_le32(&pi->dbdma->control,
+ (RUN | WAKE | FLUSH | PAUSE) << 16);
+ {
+ /* FIXME: move to own function */
+ int timeout = 5000;
+ while ((in_le32(&pi->dbdma->status) & RUN)
+ && --timeout > 0)
+ udelay(1);
+ if (!timeout)
+ printk(KERN_ERR
+ "i2sbus: timed out turning "
+ "off dbdma engine!\n");
+ }
+
+ pi->dbdma_ring.running = 0;
+ list_for_each_entry(cii, &i2sdev->sound.codec_list, list)
+ if (cii->codec->stop)
+ cii->codec->stop(cii, pi->substream);
+ break;
+ default:
+ result = -EINVAL;
+ goto out_unlock;
+ }
+
+ out_unlock:
+ spin_unlock_irqrestore(&i2sdev->low_lock, flags);
+ return result;
+}
+
+static snd_pcm_uframes_t i2sbus_pcm_pointer(struct i2sbus_dev *i2sdev, int in)
+{
+ struct pcm_info *pi;
+ u32 fc;
+
+ get_pcm_info(i2sdev, in, &pi, NULL);
+
+ fc = in_le32(&i2sdev->intfregs->frame_count);
+ fc = fc - pi->frame_count;
+
+ return (bytes_to_frames(pi->substream->runtime,
+ pi->current_period *
+ snd_pcm_lib_period_bytes(pi->substream))
+ + fc) % pi->substream->runtime->buffer_size;
+}
+
+static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in)
+{
+ struct pcm_info *pi;
+ u32 fc;
+ u32 delta;
+
+ spin_lock(&i2sdev->low_lock);
+ get_pcm_info(i2sdev, in, &pi, NULL);
+
+ if (!pi->dbdma_ring.running) {
+ /* there was still an interrupt pending
+ * while we stopped. or maybe another
+ * processor (not the one that was stopping
+ * the DMA engine) was spinning above
+ * waiting for the lock. */
+ goto out_unlock;
+ }
+
+ fc = in_le32(&i2sdev->intfregs->frame_count);
+ /* a counter overflow does not change the calculation. */
+ delta = fc - pi->frame_count;
+
+ /* update current_period */
+ while (delta >= pi->substream->runtime->period_size) {
+ pi->current_period++;
+ delta = delta - pi->substream->runtime->period_size;
+ }
+
+ if (unlikely(delta)) {
+ /* Some interrupt came late, so check the dbdma.
+ * This special case exists to syncronize the frame_count with
+ * the dbdma transfer, but is hit every once in a while. */
+ int period;
+
+ period = (in_le32(&pi->dbdma->cmdptr)
+ - pi->dbdma_ring.bus_cmd_start)
+ / sizeof(struct dbdma_cmd);
+ pi->current_period = pi->current_period
+ % pi->substream->runtime->periods;
+
+ while (pi->current_period != period) {
+ pi->current_period++;
+ pi->current_period %= pi->substream->runtime->periods;
+ /* Set delta to zero, as the frame_count value is too
+ * high (otherwise the code path will not be executed).
+ * This corrects the fact that the frame_count is too
+ * low at the beginning due to buffering. */
+ delta = 0;
+ }
+ }
+
+ pi->frame_count = fc - delta;
+ pi->current_period %= pi->substream->runtime->periods;
+
+ spin_unlock(&i2sdev->low_lock);
+ /* may call _trigger again, hence needs to be unlocked */
+ snd_pcm_period_elapsed(pi->substream);
+ return;
+ out_unlock:
+ spin_unlock(&i2sdev->low_lock);
+}
+
+irqreturn_t i2sbus_tx_intr(int irq, void *devid, struct pt_regs *regs)
+{
+ handle_interrupt((struct i2sbus_dev *)devid, 0);
+ return IRQ_HANDLED;
+}
+
+irqreturn_t i2sbus_rx_intr(int irq, void *devid, struct pt_regs * regs)
+{
+ handle_interrupt((struct i2sbus_dev *)devid, 1);
+ return IRQ_HANDLED;
+}
+
+static int i2sbus_playback_open(struct snd_pcm_substream *substream)
+{
+ struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+
+ if (!i2sdev)
+ return -EINVAL;
+ i2sdev->out.substream = substream;
+ return i2sbus_pcm_open(i2sdev, 0);
+}
+
+static int i2sbus_playback_close(struct snd_pcm_substream *substream)
+{
+ struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+ int err;
+
+ if (!i2sdev)
+ return -EINVAL;
+ if (i2sdev->out.substream != substream)
+ return -EINVAL;
+ err = i2sbus_pcm_close(i2sdev, 0);
+ if (!err)
+ i2sdev->out.substream = NULL;
+ return err;
+}
+
+static int i2sbus_playback_prepare(struct snd_pcm_substream *substream)
+{
+ struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+
+ if (!i2sdev)
+ return -EINVAL;
+ if (i2sdev->out.substream != substream)
+ return -EINVAL;
+ return i2sbus_pcm_prepare(i2sdev, 0);
+}
+
+static int i2sbus_playback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+
+ if (!i2sdev)
+ return -EINVAL;
+ if (i2sdev->out.substream != substream)
+ return -EINVAL;
+ return i2sbus_pcm_trigger(i2sdev, 0, cmd);
+}
+
+static snd_pcm_uframes_t i2sbus_playback_pointer(struct snd_pcm_substream
+ *substream)
+{
+ struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+
+ if (!i2sdev)
+ return -EINVAL;
+ if (i2sdev->out.substream != substream)
+ return 0;
+ return i2sbus_pcm_pointer(i2sdev, 0);
+}
+
+static struct snd_pcm_ops i2sbus_playback_ops = {
+ .open = i2sbus_playback_open,
+ .close = i2sbus_playback_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = i2sbus_hw_params,
+ .hw_free = i2sbus_hw_free,
+ .prepare = i2sbus_playback_prepare,
+ .trigger = i2sbus_playback_trigger,
+ .pointer = i2sbus_playback_pointer,
+};
+
+static int i2sbus_record_open(struct snd_pcm_substream *substream)
+{
+ struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+
+ if (!i2sdev)
+ return -EINVAL;
+ i2sdev->in.substream = substream;
+ return i2sbus_pcm_open(i2sdev, 1);
+}
+
+static int i2sbus_record_close(struct snd_pcm_substream *substream)
+{
+ struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+ int err;
+
+ if (!i2sdev)
+ return -EINVAL;
+ if (i2sdev->in.substream != substream)
+ return -EINVAL;
+ err = i2sbus_pcm_close(i2sdev, 1);
+ if (!err)
+ i2sdev->in.substream = NULL;
+ return err;
+}
+
+static int i2sbus_record_prepare(struct snd_pcm_substream *substream)
+{
+ struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+
+ if (!i2sdev)
+ return -EINVAL;
+ if (i2sdev->in.substream != substream)
+ return -EINVAL;
+ return i2sbus_pcm_prepare(i2sdev, 1);
+}
+
+static int i2sbus_record_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+
+ if (!i2sdev)
+ return -EINVAL;
+ if (i2sdev->in.substream != substream)
+ return -EINVAL;
+ return i2sbus_pcm_trigger(i2sdev, 1, cmd);
+}
+
+static snd_pcm_uframes_t i2sbus_record_pointer(struct snd_pcm_substream
+ *substream)
+{
+ struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+
+ if (!i2sdev)
+ return -EINVAL;
+ if (i2sdev->in.substream != substream)
+ return 0;
+ return i2sbus_pcm_pointer(i2sdev, 1);
+}
+
+static struct snd_pcm_ops i2sbus_record_ops = {
+ .open = i2sbus_record_open,
+ .close = i2sbus_record_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = i2sbus_hw_params,
+ .hw_free = i2sbus_hw_free,
+ .prepare = i2sbus_record_prepare,
+ .trigger = i2sbus_record_trigger,
+ .pointer = i2sbus_record_pointer,
+};
+
+static void i2sbus_private_free(struct snd_pcm *pcm)
+{
+ struct i2sbus_dev *i2sdev = snd_pcm_chip(pcm);
+ struct codec_info_item *p, *tmp;
+
+ i2sdev->sound.pcm = NULL;
+ i2sdev->out.created = 0;
+ i2sdev->in.created = 0;
+ list_for_each_entry_safe(p, tmp, &i2sdev->sound.codec_list, list) {
+ printk(KERN_ERR "i2sbus: a codec didn't unregister!\n");
+ list_del(&p->list);
+ module_put(p->codec->owner);
+ kfree(p);
+ }
+ soundbus_dev_put(&i2sdev->sound);
+ module_put(THIS_MODULE);
+}
+
+/* FIXME: this function needs an error handling strategy with labels */
+int
+i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
+ struct codec_info *ci, void *data)
+{
+ int err, in = 0, out = 0;
+ struct transfer_info *tmp;
+ struct i2sbus_dev *i2sdev = soundbus_dev_to_i2sbus_dev(dev);
+ struct codec_info_item *cii;
+
+ if (!dev->pcmname || dev->pcmid == -1) {
+ printk(KERN_ERR "i2sbus: pcm name and id must be set!\n");
+ return -EINVAL;
+ }
+
+ list_for_each_entry(cii, &dev->codec_list, list) {
+ if (cii->codec_data == data)
+ return -EALREADY;
+ }
+
+ if (!ci->transfers || !ci->transfers->formats
+ || !ci->transfers->rates || !ci->usable)
+ return -EINVAL;
+
+ /* we currently code the i2s transfer on the clock, and support only
+ * 32 and 64 */
+ if (ci->bus_factor != 32 && ci->bus_factor != 64)
+ return -EINVAL;
+
+ /* If you want to fix this, you need to keep track of what transport infos
+ * are to be used, which codecs they belong to, and then fix all the
+ * sysclock/busclock stuff above to depend on which is usable */
+ list_for_each_entry(cii, &dev->codec_list, list) {
+ if (cii->codec->sysclock_factor != ci->sysclock_factor) {
+ printk(KERN_DEBUG
+ "cannot yet handle multiple different sysclocks!\n");
+ return -EINVAL;
+ }
+ if (cii->codec->bus_factor != ci->bus_factor) {
+ printk(KERN_DEBUG
+ "cannot yet handle multiple different bus clocks!\n");
+ return -EINVAL;
+ }
+ }
+
+ tmp = ci->transfers;
+ while (tmp->formats && tmp->rates) {
+ if (tmp->transfer_in)
+ in = 1;
+ else
+ out = 1;
+ tmp++;
+ }
+
+ cii = kzalloc(sizeof(struct codec_info_item), GFP_KERNEL);
+ if (!cii) {
+ printk(KERN_DEBUG "i2sbus: failed to allocate cii\n");
+ return -ENOMEM;
+ }
+
+ /* use the private data to point to the codec info */
+ cii->sdev = soundbus_dev_get(dev);
+ cii->codec = ci;
+ cii->codec_data = data;
+
+ if (!cii->sdev) {
+ printk(KERN_DEBUG
+ "i2sbus: failed to get soundbus dev reference\n");
+ kfree(cii);
+ return -ENODEV;
+ }
+
+ if (!try_module_get(THIS_MODULE)) {
+ printk(KERN_DEBUG "i2sbus: failed to get module reference!\n");
+ soundbus_dev_put(dev);
+ kfree(cii);
+ return -EBUSY;
+ }
+
+ if (!try_module_get(ci->owner)) {
+ printk(KERN_DEBUG
+ "i2sbus: failed to get module reference to codec owner!\n");
+ module_put(THIS_MODULE);
+ soundbus_dev_put(dev);
+ kfree(cii);
+ return -EBUSY;
+ }
+
+ if (!dev->pcm) {
+ err = snd_pcm_new(card,
+ dev->pcmname,
+ dev->pcmid,
+ 0,
+ 0,
+ &dev->pcm);
+ if (err) {
+ printk(KERN_DEBUG "i2sbus: failed to create pcm\n");
+ kfree(cii);
+ module_put(ci->owner);
+ soundbus_dev_put(dev);
+ module_put(THIS_MODULE);
+ return err;
+ }
+ }
+
+ /* ALSA yet again sucks.
+ * If it is ever fixed, remove this line. See below. */
+ out = in = 1;
+
+ if (!i2sdev->out.created && out) {
+ if (dev->pcm->card != card) {
+ /* eh? */
+ printk(KERN_ERR
+ "Can't attach same bus to different cards!\n");
+ module_put(ci->owner);
+ kfree(cii);
+ soundbus_dev_put(dev);
+ module_put(THIS_MODULE);
+ return -EINVAL;
+ }
+ if ((err =
+ snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1))) {
+ module_put(ci->owner);
+ kfree(cii);
+ soundbus_dev_put(dev);
+ module_put(THIS_MODULE);
+ return err;
+ }
+ snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &i2sbus_playback_ops);
+ i2sdev->out.created = 1;
+ }
+
+ if (!i2sdev->in.created && in) {
+ if (dev->pcm->card != card) {
+ printk(KERN_ERR
+ "Can't attach same bus to different cards!\n");
+ module_put(ci->owner);
+ kfree(cii);
+ soundbus_dev_put(dev);
+ module_put(THIS_MODULE);
+ return -EINVAL;
+ }
+ if ((err =
+ snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1))) {
+ module_put(ci->owner);
+ kfree(cii);
+ soundbus_dev_put(dev);
+ module_put(THIS_MODULE);
+ return err;
+ }
+ snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE,
+ &i2sbus_record_ops);
+ i2sdev->in.created = 1;
+ }
+
+ /* so we have to register the pcm after adding any substream
+ * to it because alsa doesn't create the devices for the
+ * substreams when we add them later.
+ * Therefore, force in and out on both busses (above) and
+ * register the pcm now instead of just after creating it.
+ */
+ err = snd_device_register(card, dev->pcm);
+ if (err) {
+ printk(KERN_ERR "i2sbus: error registering new pcm\n");
+ module_put(ci->owner);
+ kfree(cii);
+ soundbus_dev_put(dev);
+ module_put(THIS_MODULE);
+ return err;
+ }
+ /* no errors any more, so let's add this to our list */
+ list_add(&cii->list, &dev->codec_list);
+
+ dev->pcm->private_data = i2sdev;
+ dev->pcm->private_free = i2sbus_private_free;
+
+ /* well, we really should support scatter/gather DMA */
+ snd_pcm_lib_preallocate_pages_for_all(
+ dev->pcm, SNDRV_DMA_TYPE_DEV,
+ snd_dma_pci_data(macio_get_pci_dev(i2sdev->macio)),
+ 64 * 1024, 64 * 1024);
+
+ return 0;
+}
+
+void i2sbus_detach_codec(struct soundbus_dev *dev, void *data)
+{
+ struct codec_info_item *cii = NULL, *i;
+
+ list_for_each_entry(i, &dev->codec_list, list) {
+ if (i->codec_data == data) {
+ cii = i;
+ break;
+ }
+ }
+ if (cii) {
+ list_del(&cii->list);
+ module_put(cii->codec->owner);
+ kfree(cii);
+ }
+ /* no more codecs, but still a pcm? */
+ if (list_empty(&dev->codec_list) && dev->pcm) {
+ /* the actual cleanup is done by the callback above! */
+ snd_device_free(dev->pcm->card, dev->pcm);
+ }
+}
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus.h b/sound/aoa/soundbus/i2sbus/i2sbus.h
new file mode 100644
index 0000000..cfa5162
--- /dev/null
+++ b/sound/aoa/soundbus/i2sbus/i2sbus.h
@@ -0,0 +1,112 @@
+/*
+ * i2sbus driver -- private definitions
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+#ifndef __I2SBUS_H
+#define __I2SBUS_H
+#include <asm/dbdma.h>
+#include <linux/interrupt.h>
+#include <sound/pcm.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <asm/prom.h>
+#include "i2sbus-interface.h"
+#include "i2sbus-control.h"
+#include "../soundbus.h"
+
+struct i2sbus_control {
+ volatile struct i2s_control_regs __iomem *controlregs;
+ struct resource rsrc;
+ struct list_head list;
+};
+
+#define MAX_DBDMA_COMMANDS 32
+
+struct dbdma_command_mem {
+ dma_addr_t bus_addr;
+ dma_addr_t bus_cmd_start;
+ struct dbdma_cmd *cmds;
+ void *space;
+ int size;
+ u32 running:1;
+};
+
+struct pcm_info {
+ u32 created:1, /* has this direction been created with alsa? */
+ active:1; /* is this stream active? */
+ /* runtime information */
+ struct snd_pcm_substream *substream;
+ int current_period;
+ u32 frame_count;
+ struct dbdma_command_mem dbdma_ring;
+ volatile struct dbdma_regs __iomem *dbdma;
+};
+
+struct i2sbus_dev {
+ struct soundbus_dev sound;
+ struct macio_dev *macio;
+ struct i2sbus_control *control;
+ volatile struct i2s_interface_regs __iomem *intfregs;
+
+ struct resource resources[3];
+ struct resource *allocated_resource[3];
+ int interrupts[3];
+ char rnames[3][32];
+
+ /* info about currently active substreams */
+ struct pcm_info out, in;
+ snd_pcm_format_t format;
+ unsigned int rate;
+
+ /* list for a single controller */
+ struct list_head item;
+ /* number of bus on controller */
+ int bus_number;
+ /* for use by control layer */
+ struct pmf_function *enable,
+ *cell_enable,
+ *cell_disable,
+ *clock_enable,
+ *clock_disable;
+
+ /* locks */
+ /* spinlock for low-level interrupt locking */
+ spinlock_t low_lock;
+ /* mutex for high-level consistency */
+ struct mutex lock;
+};
+
+#define soundbus_dev_to_i2sbus_dev(sdev) \
+ container_of(sdev, struct i2sbus_dev, sound)
+
+/* pcm specific functions */
+extern int
+i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
+ struct codec_info *ci, void *data);
+extern void
+i2sbus_detach_codec(struct soundbus_dev *dev, void *data);
+extern irqreturn_t
+i2sbus_tx_intr(int irq, void *devid, struct pt_regs *regs);
+extern irqreturn_t
+i2sbus_rx_intr(int irq, void *devid, struct pt_regs *regs);
+
+/* control specific functions */
+extern int i2sbus_control_init(struct macio_dev* dev,
+ struct i2sbus_control **c);
+extern void i2sbus_control_destroy(struct i2sbus_control *c);
+extern int i2sbus_control_add_dev(struct i2sbus_control *c,
+ struct i2sbus_dev *i2sdev);
+extern void i2sbus_control_remove_dev(struct i2sbus_control *c,
+ struct i2sbus_dev *i2sdev);
+extern int i2sbus_control_enable(struct i2sbus_control *c,
+ struct i2sbus_dev *i2sdev);
+extern int i2sbus_control_cell(struct i2sbus_control *c,
+ struct i2sbus_dev *i2sdev,
+ int enable);
+extern int i2sbus_control_clock(struct i2sbus_control *c,
+ struct i2sbus_dev *i2sdev,
+ int enable);
+#endif /* __I2SBUS_H */
diff --git a/sound/aoa/soundbus/soundbus.h b/sound/aoa/soundbus/soundbus.h
new file mode 100644
index 0000000..5c27297
--- /dev/null
+++ b/sound/aoa/soundbus/soundbus.h
@@ -0,0 +1,202 @@
+/*
+ * soundbus generic definitions
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+#ifndef __SOUNDBUS_H
+#define __SOUNDBUS_H
+
+#include <asm/of_device.h>
+#include <sound/pcm.h>
+#include <linux/list.h>
+
+
+/* When switching from master to slave or the other way around,
+ * you don't want to have the codec chip acting as clock source
+ * while the bus still is.
+ * More importantly, while switch from slave to master, you need
+ * to turn off the chip's master function first, but then there's
+ * no clock for a while and other chips might reset, so we notify
+ * their drivers after having switched.
+ * The constants here are codec-point of view, so when we switch
+ * the soundbus to master we tell the codec we're going to switch
+ * and give it CLOCK_SWITCH_PREPARE_SLAVE!
+ */
+enum clock_switch {
+ CLOCK_SWITCH_PREPARE_SLAVE,
+ CLOCK_SWITCH_PREPARE_MASTER,
+ CLOCK_SWITCH_SLAVE,
+ CLOCK_SWITCH_MASTER,
+ CLOCK_SWITCH_NOTIFY,
+};
+
+/* information on a transfer the codec can take */
+struct transfer_info {
+ u64 formats; /* SNDRV_PCM_FMTBIT_* */
+ unsigned int rates; /* SNDRV_PCM_RATE_* */
+ /* flags */
+ u32 transfer_in:1, /* input = 1, output = 0 */
+ must_be_clock_source:1;
+ /* for codecs to distinguish among their TIs */
+ int tag;
+};
+
+struct codec_info_item {
+ struct codec_info *codec;
+ void *codec_data;
+ struct soundbus_dev *sdev;
+ /* internal, to be used by the soundbus provider */
+ struct list_head list;
+};
+
+/* for prepare, where the codecs need to know
+ * what we're going to drive the bus with */
+struct bus_info {
+ /* see below */
+ int sysclock_factor;
+ int bus_factor;
+};
+
+/* information on the codec itself, plus function pointers */
+struct codec_info {
+ /* the module this lives in */
+ struct module *owner;
+
+ /* supported transfer possibilities, array terminated by
+ * formats or rates being 0. */
+ struct transfer_info *transfers;
+
+ /* Master clock speed factor
+ * to be used (master clock speed = sysclock_factor * sampling freq)
+ * Unused if the soundbus provider has no such notion.
+ */
+ int sysclock_factor;
+
+ /* Bus factor, bus clock speed = bus_factor * sampling freq)
+ * Unused if the soundbus provider has no such notion.
+ */
+ int bus_factor;
+
+ /* operations */
+ /* clock switching, see above */
+ int (*switch_clock)(struct codec_info_item *cii,
+ enum clock_switch clock);
+
+ /* called for each transfer_info when the user
+ * opens the pcm device to determine what the
+ * hardware can support at this point in time.
+ * That can depend on other user-switchable controls.
+ * Return 1 if usable, 0 if not.
+ * out points to another instance of a transfer_info
+ * which is initialised to the values in *ti, and
+ * it's format and rate values can be modified by
+ * the callback if it is necessary to further restrict
+ * the formats that can be used at the moment, for
+ * example when one codec has multiple logical codec
+ * info structs for multiple inputs.
+ */
+ int (*usable)(struct codec_info_item *cii,
+ struct transfer_info *ti,
+ struct transfer_info *out);
+
+ /* called when pcm stream is opened, probably not implemented
+ * most of the time since it isn't too useful */
+ int (*open)(struct codec_info_item *cii,
+ struct snd_pcm_substream *substream);
+
+ /* called when the pcm stream is closed, at this point
+ * the user choices can all be unlocked (see below) */
+ int (*close)(struct codec_info_item *cii,
+ struct snd_pcm_substream *substream);
+
+ /* if the codec must forbid some user choices because
+ * they are not valid with the substream/transfer info,
+ * it must do so here. Example: no digital output for
+ * incompatible framerate, say 8KHz, on Onyx.
+ * If the selected stuff in the substream is NOT
+ * compatible, you have to reject this call! */
+ int (*prepare)(struct codec_info_item *cii,
+ struct bus_info *bi,
+ struct snd_pcm_substream *substream);
+
+ /* start() is called before data is pushed to the codec.
+ * Note that start() must be atomic! */
+ int (*start)(struct codec_info_item *cii,
+ struct snd_pcm_substream *substream);
+
+ /* stop() is called after data is no longer pushed to the codec.
+ * Note that stop() must be atomic! */
+ int (*stop)(struct codec_info_item *cii,
+ struct snd_pcm_substream *substream);
+
+ int (*suspend)(struct codec_info_item *cii, pm_message_t state);
+ int (*resume)(struct codec_info_item *cii);
+};
+
+/* information on a soundbus device */
+struct soundbus_dev {
+ /* the bus it belongs to */
+ struct list_head onbuslist;
+
+ /* the of device it represents */
+ struct of_device ofdev;
+
+ /* what modules go by */
+ char modalias[32];
+
+ /* These fields must be before attach_codec can be called.
+ * They should be set by the owner of the alsa card object
+ * that is needed, and whoever sets them must make sure
+ * that they are unique within that alsa card object. */
+ char *pcmname;
+ int pcmid;
+
+ /* this is assigned by the soundbus provider in attach_codec */
+ struct snd_pcm *pcm;
+
+ /* operations */
+ /* attach a codec to this soundbus, give the alsa
+ * card object the PCMs for this soundbus should be in.
+ * The 'data' pointer must be unique, it is used as the
+ * key for detach_codec(). */
+ int (*attach_codec)(struct soundbus_dev *dev, struct snd_card *card,
+ struct codec_info *ci, void *data);
+ void (*detach_codec)(struct soundbus_dev *dev, void *data);
+ /* TODO: suspend/resume */
+
+ /* private for the soundbus provider */
+ struct list_head codec_list;
+ u32 have_out:1, have_in:1;
+};
+#define to_soundbus_device(d) container_of(d, struct soundbus_dev, ofdev.dev)
+#define of_to_soundbus_device(d) container_of(d, struct soundbus_dev, ofdev)
+
+extern int soundbus_add_one(struct soundbus_dev *dev);
+extern void soundbus_remove_one(struct soundbus_dev *dev);
+
+extern struct soundbus_dev *soundbus_dev_get(struct soundbus_dev *dev);
+extern void soundbus_dev_put(struct soundbus_dev *dev);
+
+struct soundbus_driver {
+ char *name;
+ struct module *owner;
+
+ /* we don't implement any matching at all */
+
+ int (*probe)(struct soundbus_dev* dev);
+ int (*remove)(struct soundbus_dev* dev);
+
+ int (*suspend)(struct soundbus_dev* dev, pm_message_t state);
+ int (*resume)(struct soundbus_dev* dev);
+ int (*shutdown)(struct soundbus_dev* dev);
+
+ struct device_driver driver;
+};
+#define to_soundbus_driver(drv) container_of(drv,struct soundbus_driver, driver)
+
+extern int soundbus_register_driver(struct soundbus_driver *drv);
+extern void soundbus_unregister_driver(struct soundbus_driver *drv);
+
+#endif /* __SOUNDBUS_H */
diff --git a/sound/aoa/soundbus/sysfs.c b/sound/aoa/soundbus/sysfs.c
new file mode 100644
index 0000000..d31f814
--- /dev/null
+++ b/sound/aoa/soundbus/sysfs.c
@@ -0,0 +1,43 @@
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+/* FIX UP */
+#include "soundbus.h"
+
+#define soundbus_config_of_attr(field, format_string) \
+static ssize_t \
+field##_show (struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct soundbus_dev *mdev = to_soundbus_device (dev); \
+ return sprintf (buf, format_string, mdev->ofdev.node->field); \
+}
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct soundbus_dev *sdev = to_soundbus_device(dev);
+ struct of_device *of = &sdev->ofdev;
+ int length;
+
+ if (*sdev->modalias) {
+ strlcpy(buf, sdev->modalias, sizeof(sdev->modalias) + 1);
+ strcat(buf, "\n");
+ length = strlen(buf);
+ } else {
+ length = sprintf(buf, "of:N%sT%s\n",
+ of->node->name, of->node->type);
+ }
+
+ return length;
+}
+
+soundbus_config_of_attr (name, "%s\n");
+soundbus_config_of_attr (type, "%s\n");
+
+struct device_attribute soundbus_dev_attrs[] = {
+ __ATTR_RO(name),
+ __ATTR_RO(type),
+ __ATTR_RO(modalias),
+ __ATTR_NULL
+};
diff --git a/sound/arm/sa11xx-uda1341.c b/sound/arm/sa11xx-uda1341.c
index 13057d9..b88fb0c 100644
--- a/sound/arm/sa11xx-uda1341.c
+++ b/sound/arm/sa11xx-uda1341.c
@@ -112,7 +112,7 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SA1100/SA1111 + UDA1341TS driver for ALSA");
MODULE_SUPPORTED_DEVICE("{{UDA1341,iPAQ H3600 UDA1341TS}}");
-static char *id = NULL; /* ID for this card */
+static char *id; /* ID for this card */
module_param(id, charp, 0444);
MODULE_PARM_DESC(id, "ID string for SA1100/SA1111 + UDA1341TS soundcard.");
@@ -984,11 +984,15 @@ static int __init sa11xx_uda1341_init(void)
if ((err = platform_driver_register(&sa11xx_uda1341_driver)) < 0)
return err;
device = platform_device_register_simple(SA11XX_UDA1341_DRIVER, -1, NULL, 0);
- if (IS_ERR(device)) {
- platform_driver_unregister(&sa11xx_uda1341_driver);
- return PTR_ERR(device);
- }
- return 0;
+ if (!IS_ERR(device)) {
+ if (platform_get_drvdata(device))
+ return 0;
+ platform_device_unregister(device);
+ err = -ENODEV
+ } else
+ err = PTR_ERR(device);
+ platform_driver_unregister(&sa11xx_uda1341_driver);
+ return err;
}
static void __exit sa11xx_uda1341_exit(void)
diff --git a/sound/core/control.c b/sound/core/control.c
index 22565c9b..bb397ea 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -176,6 +176,8 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
read_unlock(&card->ctl_files_rwlock);
}
+EXPORT_SYMBOL(snd_ctl_notify);
+
/**
* snd_ctl_new - create a control instance from the template
* @control: the control template
@@ -204,6 +206,8 @@ struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, unsigned int acce
return kctl;
}
+EXPORT_SYMBOL(snd_ctl_new);
+
/**
* snd_ctl_new1 - create a control instance from the template
* @ncontrol: the initialization record
@@ -242,6 +246,8 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
return snd_ctl_new(&kctl, access);
}
+EXPORT_SYMBOL(snd_ctl_new1);
+
/**
* snd_ctl_free_one - release the control instance
* @kcontrol: the control instance
@@ -259,6 +265,8 @@ void snd_ctl_free_one(struct snd_kcontrol *kcontrol)
}
}
+EXPORT_SYMBOL(snd_ctl_free_one);
+
static unsigned int snd_ctl_hole_check(struct snd_card *card,
unsigned int count)
{
@@ -347,6 +355,8 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
return err;
}
+EXPORT_SYMBOL(snd_ctl_add);
+
/**
* snd_ctl_remove - remove the control from the card and release it
* @card: the card instance
@@ -373,6 +383,8 @@ int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol)
return 0;
}
+EXPORT_SYMBOL(snd_ctl_remove);
+
/**
* snd_ctl_remove_id - remove the control of the given id and release it
* @card: the card instance
@@ -399,6 +411,8 @@ int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id)
return ret;
}
+EXPORT_SYMBOL(snd_ctl_remove_id);
+
/**
* snd_ctl_remove_unlocked_id - remove the unlocked control of the given id and release it
* @file: active control handle
@@ -461,6 +475,8 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
return 0;
}
+EXPORT_SYMBOL(snd_ctl_rename_id);
+
/**
* snd_ctl_find_numid - find the control instance with the given number-id
* @card: the card instance
@@ -487,6 +503,8 @@ struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numi
return NULL;
}
+EXPORT_SYMBOL(snd_ctl_find_numid);
+
/**
* snd_ctl_find_id - find the control instance with the given id
* @card: the card instance
@@ -527,6 +545,8 @@ struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
return NULL;
}
+EXPORT_SYMBOL(snd_ctl_find_id);
+
static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
unsigned int cmd, void __user *arg)
{
@@ -704,6 +724,8 @@ int snd_ctl_elem_read(struct snd_card *card, struct snd_ctl_elem_value *control)
return result;
}
+EXPORT_SYMBOL(snd_ctl_elem_read);
+
static int snd_ctl_elem_read_user(struct snd_card *card,
struct snd_ctl_elem_value __user *_control)
{
@@ -767,6 +789,8 @@ int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
return result;
}
+EXPORT_SYMBOL(snd_ctl_elem_write);
+
static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
struct snd_ctl_elem_value __user *_control)
{
@@ -1199,11 +1223,15 @@ int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn)
return _snd_ctl_register_ioctl(fcn, &snd_control_ioctls);
}
+EXPORT_SYMBOL(snd_ctl_register_ioctl);
+
#ifdef CONFIG_COMPAT
int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn)
{
return _snd_ctl_register_ioctl(fcn, &snd_control_compat_ioctls);
}
+
+EXPORT_SYMBOL(snd_ctl_register_ioctl_compat);
#endif
/*
@@ -1236,12 +1264,15 @@ int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn)
return _snd_ctl_unregister_ioctl(fcn, &snd_control_ioctls);
}
+EXPORT_SYMBOL(snd_ctl_unregister_ioctl);
+
#ifdef CONFIG_COMPAT
int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn)
{
return _snd_ctl_unregister_ioctl(fcn, &snd_control_compat_ioctls);
}
+EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat);
#endif
static int snd_ctl_fasync(int fd, struct file * file, int on)
diff --git a/sound/core/device.c b/sound/core/device.c
index b1cf6ec..6ce4da4a 100644
--- a/sound/core/device.c
+++ b/sound/core/device.c
@@ -63,6 +63,8 @@ int snd_device_new(struct snd_card *card, snd_device_type_t type,
return 0;
}
+EXPORT_SYMBOL(snd_device_new);
+
/**
* snd_device_free - release the device from the card
* @card: the card instance
@@ -107,6 +109,8 @@ int snd_device_free(struct snd_card *card, void *device_data)
return -ENXIO;
}
+EXPORT_SYMBOL(snd_device_free);
+
/**
* snd_device_disconnect - disconnect the device
* @card: the card instance
@@ -182,6 +186,8 @@ int snd_device_register(struct snd_card *card, void *device_data)
return -ENXIO;
}
+EXPORT_SYMBOL(snd_device_register);
+
/*
* register all the devices on the card.
* called from init.c
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 2524e66..8bd0dcc 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -486,7 +486,6 @@ static void __init snd_hwdep_proc_init(void)
struct snd_info_entry *entry;
if ((entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL)) != NULL) {
- entry->c.text.read_size = PAGE_SIZE;
entry->c.text.read = snd_hwdep_proc_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
diff --git a/sound/core/info.c b/sound/core/info.c
index 2582b74..10c1772 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -21,7 +21,6 @@
#include <sound/driver.h>
#include <linux/init.h>
-#include <linux/vmalloc.h>
#include <linux/time.h>
#include <linux/smp_lock.h>
#include <linux/string.h>
@@ -82,6 +81,24 @@ static int snd_info_version_init(void);
static int snd_info_version_done(void);
+/* resize the proc r/w buffer */
+static int resize_info_buffer(struct snd_info_buffer *buffer,
+ unsigned int nsize)
+{
+ char *nbuf;
+
+ nsize = PAGE_ALIGN(nsize);
+ nbuf = kmalloc(nsize, GFP_KERNEL);
+ if (! nbuf)
+ return -ENOMEM;
+
+ memcpy(nbuf, buffer->buffer, buffer->len);
+ kfree(buffer->buffer);
+ buffer->buffer = nbuf;
+ buffer->len = nsize;
+ return 0;
+}
+
/**
* snd_iprintf - printf on the procfs buffer
* @buffer: the procfs buffer
@@ -95,30 +112,43 @@ int snd_iprintf(struct snd_info_buffer *buffer, char *fmt,...)
{
va_list args;
int len, res;
+ int err = 0;
+ might_sleep();
if (buffer->stop || buffer->error)
return 0;
len = buffer->len - buffer->size;
va_start(args, fmt);
- res = vsnprintf(buffer->curr, len, fmt, args);
- va_end(args);
- if (res >= len) {
- buffer->stop = 1;
- return 0;
+ for (;;) {
+ res = vsnprintf(buffer->buffer + buffer->curr, len, fmt, args);
+ if (res < len)
+ break;
+ err = resize_info_buffer(buffer, buffer->len + PAGE_SIZE);
+ if (err < 0)
+ break;
+ len = buffer->len - buffer->size;
}
+ va_end(args);
+
+ if (err < 0)
+ return err;
buffer->curr += res;
buffer->size += res;
return res;
}
+EXPORT_SYMBOL(snd_iprintf);
+
/*
*/
-static struct proc_dir_entry *snd_proc_root = NULL;
-struct snd_info_entry *snd_seq_root = NULL;
+static struct proc_dir_entry *snd_proc_root;
+struct snd_info_entry *snd_seq_root;
+EXPORT_SYMBOL(snd_seq_root);
+
#ifdef CONFIG_SND_OSSEMUL
-struct snd_info_entry *snd_oss_root = NULL;
+struct snd_info_entry *snd_oss_root;
#endif
static inline void snd_info_entry_prepare(struct proc_dir_entry *de)
@@ -221,7 +251,7 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer
struct snd_info_private_data *data;
struct snd_info_entry *entry;
struct snd_info_buffer *buf;
- size_t size = 0;
+ ssize_t size = 0;
loff_t pos;
data = file->private_data;
@@ -237,14 +267,20 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer
buf = data->wbuffer;
if (buf == NULL)
return -EIO;
- if (pos >= buf->len)
- return -ENOMEM;
- size = buf->len - pos;
- size = min(count, size);
- if (copy_from_user(buf->buffer + pos, buffer, size))
+ mutex_lock(&entry->access);
+ if (pos + count >= buf->len) {
+ if (resize_info_buffer(buf, pos + count)) {
+ mutex_unlock(&entry->access);
+ return -ENOMEM;
+ }
+ }
+ if (copy_from_user(buf->buffer + pos, buffer, count)) {
+ mutex_unlock(&entry->access);
return -EFAULT;
- if ((long)buf->size < pos + size)
- buf->size = pos + size;
+ }
+ buf->size = pos + count;
+ mutex_unlock(&entry->access);
+ size = count;
break;
case SNDRV_INFO_CONTENT_DATA:
if (entry->c.ops->write)
@@ -279,18 +315,14 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
}
mode = file->f_flags & O_ACCMODE;
if (mode == O_RDONLY || mode == O_RDWR) {
- if ((entry->content == SNDRV_INFO_CONTENT_TEXT &&
- !entry->c.text.read_size) ||
- (entry->content == SNDRV_INFO_CONTENT_DATA &&
+ if ((entry->content == SNDRV_INFO_CONTENT_DATA &&
entry->c.ops->read == NULL)) {
err = -ENODEV;
goto __error;
}
}
if (mode == O_WRONLY || mode == O_RDWR) {
- if ((entry->content == SNDRV_INFO_CONTENT_TEXT &&
- !entry->c.text.write_size) ||
- (entry->content == SNDRV_INFO_CONTENT_DATA &&
+ if ((entry->content == SNDRV_INFO_CONTENT_DATA &&
entry->c.ops->write == NULL)) {
err = -ENODEV;
goto __error;
@@ -306,49 +338,23 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
case SNDRV_INFO_CONTENT_TEXT:
if (mode == O_RDONLY || mode == O_RDWR) {
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
- if (buffer == NULL) {
- kfree(data);
- err = -ENOMEM;
- goto __error;
- }
- buffer->len = (entry->c.text.read_size +
- (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
- buffer->buffer = vmalloc(buffer->len);
- if (buffer->buffer == NULL) {
- kfree(buffer);
- kfree(data);
- err = -ENOMEM;
- goto __error;
- }
- buffer->curr = buffer->buffer;
+ if (buffer == NULL)
+ goto __nomem;
data->rbuffer = buffer;
+ buffer->len = PAGE_SIZE;
+ buffer->buffer = kmalloc(buffer->len, GFP_KERNEL);
+ if (buffer->buffer == NULL)
+ goto __nomem;
}
if (mode == O_WRONLY || mode == O_RDWR) {
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
- if (buffer == NULL) {
- if (mode == O_RDWR) {
- vfree(data->rbuffer->buffer);
- kfree(data->rbuffer);
- }
- kfree(data);
- err = -ENOMEM;
- goto __error;
- }
- buffer->len = (entry->c.text.write_size +
- (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
- buffer->buffer = vmalloc(buffer->len);
- if (buffer->buffer == NULL) {
- if (mode == O_RDWR) {
- vfree(data->rbuffer->buffer);
- kfree(data->rbuffer);
- }
- kfree(buffer);
- kfree(data);
- err = -ENOMEM;
- goto __error;
- }
- buffer->curr = buffer->buffer;
+ if (buffer == NULL)
+ goto __nomem;
data->wbuffer = buffer;
+ buffer->len = PAGE_SIZE;
+ buffer->buffer = kmalloc(buffer->len, GFP_KERNEL);
+ if (buffer->buffer == NULL)
+ goto __nomem;
}
break;
case SNDRV_INFO_CONTENT_DATA: /* data */
@@ -373,6 +379,17 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
}
return 0;
+ __nomem:
+ if (data->rbuffer) {
+ kfree(data->rbuffer->buffer);
+ kfree(data->rbuffer);
+ }
+ if (data->wbuffer) {
+ kfree(data->wbuffer->buffer);
+ kfree(data->wbuffer);
+ }
+ kfree(data);
+ err = -ENOMEM;
__error:
module_put(entry->module);
__error1:
@@ -391,11 +408,11 @@ static int snd_info_entry_release(struct inode *inode, struct file *file)
entry = data->entry;
switch (entry->content) {
case SNDRV_INFO_CONTENT_TEXT:
- if (mode == O_RDONLY || mode == O_RDWR) {
- vfree(data->rbuffer->buffer);
+ if (data->rbuffer) {
+ kfree(data->rbuffer->buffer);
kfree(data->rbuffer);
}
- if (mode == O_WRONLY || mode == O_RDWR) {
+ if (data->wbuffer) {
if (entry->c.text.write) {
entry->c.text.write(entry, data->wbuffer);
if (data->wbuffer->error) {
@@ -404,7 +421,7 @@ static int snd_info_entry_release(struct inode *inode, struct file *file)
data->wbuffer->error);
}
}
- vfree(data->wbuffer->buffer);
+ kfree(data->wbuffer->buffer);
kfree(data->wbuffer);
}
break;
@@ -664,29 +681,29 @@ int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len)
if (len <= 0 || buffer->stop || buffer->error)
return 1;
while (--len > 0) {
- c = *buffer->curr++;
+ c = buffer->buffer[buffer->curr++];
if (c == '\n') {
- if ((buffer->curr - buffer->buffer) >= (long)buffer->size) {
+ if (buffer->curr >= buffer->size)
buffer->stop = 1;
- }
break;
}
*line++ = c;
- if ((buffer->curr - buffer->buffer) >= (long)buffer->size) {
+ if (buffer->curr >= buffer->size) {
buffer->stop = 1;
break;
}
}
while (c != '\n' && !buffer->stop) {
- c = *buffer->curr++;
- if ((buffer->curr - buffer->buffer) >= (long)buffer->size) {
+ c = buffer->buffer[buffer->curr++];
+ if (buffer->curr >= buffer->size)
buffer->stop = 1;
- }
}
*line = '\0';
return 0;
}
+EXPORT_SYMBOL(snd_info_get_line);
+
/**
* snd_info_get_str - parse a string token
* @dest: the buffer to store the string token
@@ -723,6 +740,8 @@ char *snd_info_get_str(char *dest, char *src, int len)
return src;
}
+EXPORT_SYMBOL(snd_info_get_str);
+
/**
* snd_info_create_entry - create an info entry
* @name: the proc file name
@@ -774,6 +793,8 @@ struct snd_info_entry *snd_info_create_module_entry(struct module * module,
return entry;
}
+EXPORT_SYMBOL(snd_info_create_module_entry);
+
/**
* snd_info_create_card_entry - create an info entry for the given card
* @card: the card instance
@@ -797,6 +818,8 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card,
return entry;
}
+EXPORT_SYMBOL(snd_info_create_card_entry);
+
static int snd_info_dev_free_entry(struct snd_device *device)
{
struct snd_info_entry *entry = device->device_data;
@@ -867,6 +890,8 @@ int snd_card_proc_new(struct snd_card *card, const char *name,
return 0;
}
+EXPORT_SYMBOL(snd_card_proc_new);
+
/**
* snd_info_free_entry - release the info entry
* @entry: the info entry
@@ -883,6 +908,8 @@ void snd_info_free_entry(struct snd_info_entry * entry)
kfree(entry);
}
+EXPORT_SYMBOL(snd_info_free_entry);
+
/**
* snd_info_register - register the info entry
* @entry: the info entry
@@ -913,6 +940,8 @@ int snd_info_register(struct snd_info_entry * entry)
return 0;
}
+EXPORT_SYMBOL(snd_info_register);
+
/**
* snd_info_unregister - de-register the info entry
* @entry: the info entry
@@ -937,11 +966,13 @@ int snd_info_unregister(struct snd_info_entry * entry)
return 0;
}
+EXPORT_SYMBOL(snd_info_unregister);
+
/*
*/
-static struct snd_info_entry *snd_info_version_entry = NULL;
+static struct snd_info_entry *snd_info_version_entry;
static void snd_info_version_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
{
@@ -958,7 +989,6 @@ static int __init snd_info_version_init(void)
entry = snd_info_create_module_entry(THIS_MODULE, "version", NULL);
if (entry == NULL)
return -ENOMEM;
- entry->c.text.read_size = 256;
entry->c.text.read = snd_info_version_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c
index f9ce854..bb2c40d 100644
--- a/sound/core/info_oss.c
+++ b/sound/core/info_oss.c
@@ -64,6 +64,8 @@ int snd_oss_info_register(int dev, int num, char *string)
return 0;
}
+EXPORT_SYMBOL(snd_oss_info_register);
+
extern void snd_card_info_read_oss(struct snd_info_buffer *buffer);
static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int dev)
@@ -117,7 +119,6 @@ int snd_info_minor_register(void)
memset(snd_sndstat_strings, 0, sizeof(snd_sndstat_strings));
if ((entry = snd_info_create_module_entry(THIS_MODULE, "sndstat", snd_oss_root)) != NULL) {
- entry->c.text.read_size = 2048;
entry->c.text.read = snd_sndstat_proc_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
diff --git a/sound/core/init.c b/sound/core/init.c
index 39ed2e5..4d92588 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -38,12 +38,15 @@ struct snd_shutdown_f_ops {
struct snd_shutdown_f_ops *next;
};
-unsigned int snd_cards_lock = 0; /* locked for registering/using */
-struct snd_card *snd_cards[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = NULL};
-DEFINE_RWLOCK(snd_card_rwlock);
+static unsigned int snd_cards_lock; /* locked for registering/using */
+struct snd_card *snd_cards[SNDRV_CARDS];
+EXPORT_SYMBOL(snd_cards);
+
+static DEFINE_MUTEX(snd_card_mutex);
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int free_flag);
+EXPORT_SYMBOL(snd_mixer_oss_notify_callback);
#endif
#ifdef CONFIG_PROC_FS
@@ -66,7 +69,6 @@ static inline int init_info_for_card(struct snd_card *card)
snd_printd("unable to create card entry\n");
return err;
}
- entry->c.text.read_size = PAGE_SIZE;
entry->c.text.read = snd_card_id_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
@@ -110,7 +112,7 @@ struct snd_card *snd_card_new(int idx, const char *xid,
strlcpy(card->id, xid, sizeof(card->id));
}
err = 0;
- write_lock(&snd_card_rwlock);
+ mutex_lock(&snd_card_mutex);
if (idx < 0) {
int idx2;
for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
@@ -128,12 +130,12 @@ struct snd_card *snd_card_new(int idx, const char *xid,
else
err = -ENODEV;
if (idx < 0 || err < 0) {
- write_unlock(&snd_card_rwlock);
+ mutex_unlock(&snd_card_mutex);
snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i)\n", idx, snd_ecards_limit - 1);
goto __error;
}
snd_cards_lock |= 1 << idx; /* lock it */
- write_unlock(&snd_card_rwlock);
+ mutex_unlock(&snd_card_mutex);
card->number = idx;
card->module = module;
INIT_LIST_HEAD(&card->devices);
@@ -169,6 +171,19 @@ struct snd_card *snd_card_new(int idx, const char *xid,
return NULL;
}
+EXPORT_SYMBOL(snd_card_new);
+
+/* return non-zero if a card is already locked */
+int snd_card_locked(int card)
+{
+ int locked;
+
+ mutex_lock(&snd_card_mutex);
+ locked = snd_cards_lock & (1 << card);
+ mutex_unlock(&snd_card_mutex);
+ return locked;
+}
+
static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig)
{
return -ENODEV;
@@ -236,9 +251,9 @@ int snd_card_disconnect(struct snd_card *card)
spin_unlock(&card->files_lock);
/* phase 1: disable fops (user space) operations for ALSA API */
- write_lock(&snd_card_rwlock);
+ mutex_lock(&snd_card_mutex);
snd_cards[card->number] = NULL;
- write_unlock(&snd_card_rwlock);
+ mutex_unlock(&snd_card_mutex);
/* phase 2: replace file->f_op with special dummy operations */
@@ -298,6 +313,8 @@ int snd_card_disconnect(struct snd_card *card)
return 0;
}
+EXPORT_SYMBOL(snd_card_disconnect);
+
/**
* snd_card_free - frees given soundcard structure
* @card: soundcard structure
@@ -315,9 +332,9 @@ int snd_card_free(struct snd_card *card)
if (card == NULL)
return -EINVAL;
- write_lock(&snd_card_rwlock);
+ mutex_lock(&snd_card_mutex);
snd_cards[card->number] = NULL;
- write_unlock(&snd_card_rwlock);
+ mutex_unlock(&snd_card_mutex);
#ifdef CONFIG_PM
wake_up(&card->power_sleep);
@@ -353,13 +370,15 @@ int snd_card_free(struct snd_card *card)
card->s_f_ops = s_f_ops->next;
kfree(s_f_ops);
}
- write_lock(&snd_card_rwlock);
+ mutex_lock(&snd_card_mutex);
snd_cards_lock &= ~(1 << card->number);
- write_unlock(&snd_card_rwlock);
+ mutex_unlock(&snd_card_mutex);
kfree(card);
return 0;
}
+EXPORT_SYMBOL(snd_card_free);
+
static void snd_card_free_thread(void * __card)
{
struct snd_card *card = __card;
@@ -405,6 +424,8 @@ int snd_card_free_in_thread(struct snd_card *card)
return -EFAULT;
}
+EXPORT_SYMBOL(snd_card_free_in_thread);
+
static void choose_default_id(struct snd_card *card)
{
int i, len, idx_flag = 0, loops = SNDRV_CARDS;
@@ -487,16 +508,16 @@ int snd_card_register(struct snd_card *card)
snd_assert(card != NULL, return -EINVAL);
if ((err = snd_device_register_all(card)) < 0)
return err;
- write_lock(&snd_card_rwlock);
+ mutex_lock(&snd_card_mutex);
if (snd_cards[card->number]) {
/* already registered */
- write_unlock(&snd_card_rwlock);
+ mutex_unlock(&snd_card_mutex);
return 0;
}
if (card->id[0] == '\0')
choose_default_id(card);
snd_cards[card->number] = card;
- write_unlock(&snd_card_rwlock);
+ mutex_unlock(&snd_card_mutex);
init_info_for_card(card);
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
if (snd_mixer_oss_notify_callback)
@@ -505,8 +526,10 @@ int snd_card_register(struct snd_card *card)
return 0;
}
+EXPORT_SYMBOL(snd_card_register);
+
#ifdef CONFIG_PROC_FS
-static struct snd_info_entry *snd_card_info_entry = NULL;
+static struct snd_info_entry *snd_card_info_entry;
static void snd_card_info_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
@@ -515,7 +538,7 @@ static void snd_card_info_read(struct snd_info_entry *entry,
struct snd_card *card;
for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
- read_lock(&snd_card_rwlock);
+ mutex_lock(&snd_card_mutex);
if ((card = snd_cards[idx]) != NULL) {
count++;
snd_iprintf(buffer, "%2i [%-15s]: %s - %s\n",
@@ -526,7 +549,7 @@ static void snd_card_info_read(struct snd_info_entry *entry,
snd_iprintf(buffer, " %s\n",
card->longname);
}
- read_unlock(&snd_card_rwlock);
+ mutex_unlock(&snd_card_mutex);
}
if (!count)
snd_iprintf(buffer, "--- no soundcards ---\n");
@@ -540,12 +563,12 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer)
struct snd_card *card;
for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
- read_lock(&snd_card_rwlock);
+ mutex_lock(&snd_card_mutex);
if ((card = snd_cards[idx]) != NULL) {
count++;
snd_iprintf(buffer, "%s\n", card->longname);
}
- read_unlock(&snd_card_rwlock);
+ mutex_unlock(&snd_card_mutex);
}
if (!count) {
snd_iprintf(buffer, "--- no soundcards ---\n");
@@ -563,11 +586,11 @@ static void snd_card_module_info_read(struct snd_info_entry *entry,
struct snd_card *card;
for (idx = 0; idx < SNDRV_CARDS; idx++) {
- read_lock(&snd_card_rwlock);
+ mutex_lock(&snd_card_mutex);
if ((card = snd_cards[idx]) != NULL)
snd_iprintf(buffer, "%2i %s\n",
idx, card->module->name);
- read_unlock(&snd_card_rwlock);
+ mutex_unlock(&snd_card_mutex);
}
}
#endif
@@ -579,7 +602,6 @@ int __init snd_card_info_init(void)
entry = snd_info_create_module_entry(THIS_MODULE, "cards", NULL);
if (! entry)
return -ENOMEM;
- entry->c.text.read_size = PAGE_SIZE;
entry->c.text.read = snd_card_info_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
@@ -590,7 +612,6 @@ int __init snd_card_info_init(void)
#ifdef MODULE
entry = snd_info_create_module_entry(THIS_MODULE, "modules", NULL);
if (entry) {
- entry->c.text.read_size = PAGE_SIZE;
entry->c.text.read = snd_card_module_info_read;
if (snd_info_register(entry) < 0)
snd_info_free_entry(entry);
@@ -644,6 +665,8 @@ int snd_component_add(struct snd_card *card, const char *component)
return 0;
}
+EXPORT_SYMBOL(snd_component_add);
+
/**
* snd_card_file_add - add the file to the file list of the card
* @card: soundcard structure
@@ -676,6 +699,8 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
return 0;
}
+EXPORT_SYMBOL(snd_card_file_add);
+
/**
* snd_card_file_remove - remove the file from the file list
* @card: soundcard structure
@@ -717,6 +742,8 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
return 0;
}
+EXPORT_SYMBOL(snd_card_file_remove);
+
#ifdef CONFIG_PM
/**
* snd_power_wait - wait until the power-state is changed.
@@ -753,4 +780,5 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state)
return result;
}
+EXPORT_SYMBOL(snd_power_wait);
#endif /* CONFIG_PM */
diff --git a/sound/core/isadma.c b/sound/core/isadma.c
index 1a37895..d523987 100644
--- a/sound/core/isadma.c
+++ b/sound/core/isadma.c
@@ -56,6 +56,8 @@ void snd_dma_program(unsigned long dma,
release_dma_lock(flags);
}
+EXPORT_SYMBOL(snd_dma_program);
+
/**
* snd_dma_disable - stop the ISA DMA transfer
* @dma: the dma number
@@ -72,6 +74,8 @@ void snd_dma_disable(unsigned long dma)
release_dma_lock(flags);
}
+EXPORT_SYMBOL(snd_dma_disable);
+
/**
* snd_dma_pointer - return the current pointer to DMA transfer buffer in bytes
* @dma: the dma number
@@ -101,3 +105,5 @@ unsigned int snd_dma_pointer(unsigned long dma, unsigned int size)
else
return size - result;
}
+
+EXPORT_SYMBOL(snd_dma_pointer);
diff --git a/sound/core/memory.c b/sound/core/memory.c
index 862d62d..fe59850 100644
--- a/sound/core/memory.c
+++ b/sound/core/memory.c
@@ -21,6 +21,7 @@
*/
#include <linux/config.h>
+#include <linux/module.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -55,6 +56,8 @@ int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size
#endif
}
+EXPORT_SYMBOL(copy_to_user_fromio);
+
/**
* copy_from_user_toio - copy data from user-space to mmio-space
* @dst: the destination pointer on mmio-space
@@ -85,3 +88,5 @@ int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size
return 0;
#endif
}
+
+EXPORT_SYMBOL(copy_from_user_toio);
diff --git a/sound/core/misc.c b/sound/core/misc.c
index b53e563..03fc711 100644
--- a/sound/core/misc.c
+++ b/sound/core/misc.c
@@ -34,6 +34,8 @@ void release_and_free_resource(struct resource *res)
}
}
+EXPORT_SYMBOL(release_and_free_resource);
+
#ifdef CONFIG_SND_VERBOSE_PRINTK
void snd_verbose_printk(const char *file, int line, const char *format, ...)
{
@@ -51,6 +53,8 @@ void snd_verbose_printk(const char *file, int line, const char *format, ...)
vprintk(format, args);
va_end(args);
}
+
+EXPORT_SYMBOL(snd_verbose_printk);
#endif
#if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK)
@@ -71,4 +75,6 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...)
va_end(args);
}
+
+EXPORT_SYMBOL(snd_verbose_printd);
#endif
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 9c68bc3..71b5080 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -1182,9 +1182,7 @@ static void snd_mixer_oss_proc_init(struct snd_mixer_oss *mixer)
return;
entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
- entry->c.text.read_size = 8192;
entry->c.text.read = snd_mixer_oss_proc_read;
- entry->c.text.write_size = 8192;
entry->c.text.write = snd_mixer_oss_proc_write;
entry->private_data = mixer;
if (snd_info_register(entry) < 0) {
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index ac990bf..f5ff4f4 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -45,7 +45,7 @@
#define OSS_ALSAEMULVER _SIOR ('M', 249, int)
-static int dsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 0};
+static int dsp_map[SNDRV_CARDS];
static int adsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
static int nonblock_open = 1;
@@ -78,6 +78,487 @@ static inline void snd_leave_user(mm_segment_t fs)
set_fs(fs);
}
+/*
+ * helper functions to process hw_params
+ */
+static int snd_interval_refine_min(struct snd_interval *i, unsigned int min, int openmin)
+{
+ int changed = 0;
+ if (i->min < min) {
+ i->min = min;
+ i->openmin = openmin;
+ changed = 1;
+ } else if (i->min == min && !i->openmin && openmin) {
+ i->openmin = 1;
+ changed = 1;
+ }
+ if (i->integer) {
+ if (i->openmin) {
+ i->min++;
+ i->openmin = 0;
+ }
+ }
+ if (snd_interval_checkempty(i)) {
+ snd_interval_none(i);
+ return -EINVAL;
+ }
+ return changed;
+}
+
+static int snd_interval_refine_max(struct snd_interval *i, unsigned int max, int openmax)
+{
+ int changed = 0;
+ if (i->max > max) {
+ i->max = max;
+ i->openmax = openmax;
+ changed = 1;
+ } else if (i->max == max && !i->openmax && openmax) {
+ i->openmax = 1;
+ changed = 1;
+ }
+ if (i->integer) {
+ if (i->openmax) {
+ i->max--;
+ i->openmax = 0;
+ }
+ }
+ if (snd_interval_checkempty(i)) {
+ snd_interval_none(i);
+ return -EINVAL;
+ }
+ return changed;
+}
+
+static int snd_interval_refine_set(struct snd_interval *i, unsigned int val)
+{
+ struct snd_interval t;
+ t.empty = 0;
+ t.min = t.max = val;
+ t.openmin = t.openmax = 0;
+ t.integer = 1;
+ return snd_interval_refine(i, &t);
+}
+
+/**
+ * snd_pcm_hw_param_value_min
+ * @params: the hw_params instance
+ * @var: parameter to retrieve
+ * @dir: pointer to the direction (-1,0,1) or NULL
+ *
+ * Return the minimum value for field PAR.
+ */
+static unsigned int
+snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, int *dir)
+{
+ if (hw_is_mask(var)) {
+ if (dir)
+ *dir = 0;
+ return snd_mask_min(hw_param_mask_c(params, var));
+ }
+ if (hw_is_interval(var)) {
+ const struct snd_interval *i = hw_param_interval_c(params, var);
+ if (dir)
+ *dir = i->openmin;
+ return snd_interval_min(i);
+ }
+ return -EINVAL;
+}
+
+/**
+ * snd_pcm_hw_param_value_max
+ * @params: the hw_params instance
+ * @var: parameter to retrieve
+ * @dir: pointer to the direction (-1,0,1) or NULL
+ *
+ * Return the maximum value for field PAR.
+ */
+static unsigned int
+snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, int *dir)
+{
+ if (hw_is_mask(var)) {
+ if (dir)
+ *dir = 0;
+ return snd_mask_max(hw_param_mask_c(params, var));
+ }
+ if (hw_is_interval(var)) {
+ const struct snd_interval *i = hw_param_interval_c(params, var);
+ if (dir)
+ *dir = - (int) i->openmax;
+ return snd_interval_max(i);
+ }
+ return -EINVAL;
+}
+
+static int _snd_pcm_hw_param_mask(struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var,
+ const struct snd_mask *val)
+{
+ int changed;
+ changed = snd_mask_refine(hw_param_mask(params, var), val);
+ if (changed) {
+ params->cmask |= 1 << var;
+ params->rmask |= 1 << var;
+ }
+ return changed;
+}
+
+static int snd_pcm_hw_param_mask(struct snd_pcm_substream *pcm,
+ struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var,
+ const struct snd_mask *val)
+{
+ int changed = _snd_pcm_hw_param_mask(params, var, val);
+ if (changed < 0)
+ return changed;
+ if (params->rmask) {
+ int err = snd_pcm_hw_refine(pcm, params);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+static int _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, unsigned int val,
+ int dir)
+{
+ int changed;
+ int open = 0;
+ if (dir) {
+ if (dir > 0) {
+ open = 1;
+ } else if (dir < 0) {
+ if (val > 0) {
+ open = 1;
+ val--;
+ }
+ }
+ }
+ if (hw_is_mask(var))
+ changed = snd_mask_refine_min(hw_param_mask(params, var),
+ val + !!open);
+ else if (hw_is_interval(var))
+ changed = snd_interval_refine_min(hw_param_interval(params, var),
+ val, open);
+ else
+ return -EINVAL;
+ if (changed) {
+ params->cmask |= 1 << var;
+ params->rmask |= 1 << var;
+ }
+ return changed;
+}
+
+/**
+ * snd_pcm_hw_param_min
+ * @pcm: PCM instance
+ * @params: the hw_params instance
+ * @var: parameter to retrieve
+ * @val: minimal value
+ * @dir: pointer to the direction (-1,0,1) or NULL
+ *
+ * Inside configuration space defined by PARAMS remove from PAR all
+ * values < VAL. Reduce configuration space accordingly.
+ * Return new minimum or -EINVAL if the configuration space is empty
+ */
+static int snd_pcm_hw_param_min(struct snd_pcm_substream *pcm,
+ struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, unsigned int val,
+ int *dir)
+{
+ int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0);
+ if (changed < 0)
+ return changed;
+ if (params->rmask) {
+ int err = snd_pcm_hw_refine(pcm, params);
+ if (err < 0)
+ return err;
+ }
+ return snd_pcm_hw_param_value_min(params, var, dir);
+}
+
+static int _snd_pcm_hw_param_max(struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, unsigned int val,
+ int dir)
+{
+ int changed;
+ int open = 0;
+ if (dir) {
+ if (dir < 0) {
+ open = 1;
+ } else if (dir > 0) {
+ open = 1;
+ val++;
+ }
+ }
+ if (hw_is_mask(var)) {
+ if (val == 0 && open) {
+ snd_mask_none(hw_param_mask(params, var));
+ changed = -EINVAL;
+ } else
+ changed = snd_mask_refine_max(hw_param_mask(params, var),
+ val - !!open);
+ } else if (hw_is_interval(var))
+ changed = snd_interval_refine_max(hw_param_interval(params, var),
+ val, open);
+ else
+ return -EINVAL;
+ if (changed) {
+ params->cmask |= 1 << var;
+ params->rmask |= 1 << var;
+ }
+ return changed;
+}
+
+/**
+ * snd_pcm_hw_param_max
+ * @pcm: PCM instance
+ * @params: the hw_params instance
+ * @var: parameter to retrieve
+ * @val: maximal value
+ * @dir: pointer to the direction (-1,0,1) or NULL
+ *
+ * Inside configuration space defined by PARAMS remove from PAR all
+ * values >= VAL + 1. Reduce configuration space accordingly.
+ * Return new maximum or -EINVAL if the configuration space is empty
+ */
+static int snd_pcm_hw_param_max(struct snd_pcm_substream *pcm,
+ struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, unsigned int val,
+ int *dir)
+{
+ int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0);
+ if (changed < 0)
+ return changed;
+ if (params->rmask) {
+ int err = snd_pcm_hw_refine(pcm, params);
+ if (err < 0)
+ return err;
+ }
+ return snd_pcm_hw_param_value_max(params, var, dir);
+}
+
+static int boundary_sub(int a, int adir,
+ int b, int bdir,
+ int *c, int *cdir)
+{
+ adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0);
+ bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0);
+ *c = a - b;
+ *cdir = adir - bdir;
+ if (*cdir == -2) {
+ (*c)--;
+ } else if (*cdir == 2) {
+ (*c)++;
+ }
+ return 0;
+}
+
+static int boundary_lt(unsigned int a, int adir,
+ unsigned int b, int bdir)
+{
+ if (adir < 0) {
+ a--;
+ adir = 1;
+ } else if (adir > 0)
+ adir = 1;
+ if (bdir < 0) {
+ b--;
+ bdir = 1;
+ } else if (bdir > 0)
+ bdir = 1;
+ return a < b || (a == b && adir < bdir);
+}
+
+/* Return 1 if min is nearer to best than max */
+static int boundary_nearer(int min, int mindir,
+ int best, int bestdir,
+ int max, int maxdir)
+{
+ int dmin, dmindir;
+ int dmax, dmaxdir;
+ boundary_sub(best, bestdir, min, mindir, &dmin, &dmindir);
+ boundary_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir);
+ return boundary_lt(dmin, dmindir, dmax, dmaxdir);
+}
+
+/**
+ * snd_pcm_hw_param_near
+ * @pcm: PCM instance
+ * @params: the hw_params instance
+ * @var: parameter to retrieve
+ * @best: value to set
+ * @dir: pointer to the direction (-1,0,1) or NULL
+ *
+ * Inside configuration space defined by PARAMS set PAR to the available value
+ * nearest to VAL. Reduce configuration space accordingly.
+ * This function cannot be called for SNDRV_PCM_HW_PARAM_ACCESS,
+ * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT.
+ * Return the value found.
+ */
+static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
+ struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, unsigned int best,
+ int *dir)
+{
+ struct snd_pcm_hw_params *save = NULL;
+ int v;
+ unsigned int saved_min;
+ int last = 0;
+ int min, max;
+ int mindir, maxdir;
+ int valdir = dir ? *dir : 0;
+ /* FIXME */
+ if (best > INT_MAX)
+ best = INT_MAX;
+ min = max = best;
+ mindir = maxdir = valdir;
+ if (maxdir > 0)
+ maxdir = 0;
+ else if (maxdir == 0)
+ maxdir = -1;
+ else {
+ maxdir = 1;
+ max--;
+ }
+ save = kmalloc(sizeof(*save), GFP_KERNEL);
+ if (save == NULL)
+ return -ENOMEM;
+ *save = *params;
+ saved_min = min;
+ min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir);
+ if (min >= 0) {
+ struct snd_pcm_hw_params *params1;
+ if (max < 0)
+ goto _end;
+ if ((unsigned int)min == saved_min && mindir == valdir)
+ goto _end;
+ params1 = kmalloc(sizeof(*params1), GFP_KERNEL);
+ if (params1 == NULL) {
+ kfree(save);
+ return -ENOMEM;
+ }
+ *params1 = *save;
+ max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir);
+ if (max < 0) {
+ kfree(params1);
+ goto _end;
+ }
+ if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
+ *params = *params1;
+ last = 1;
+ }
+ kfree(params1);
+ } else {
+ *params = *save;
+ max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
+ snd_assert(max >= 0, return -EINVAL);
+ last = 1;
+ }
+ _end:
+ kfree(save);
+ if (last)
+ v = snd_pcm_hw_param_last(pcm, params, var, dir);
+ else
+ v = snd_pcm_hw_param_first(pcm, params, var, dir);
+ snd_assert(v >= 0, return -EINVAL);
+ return v;
+}
+
+static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, unsigned int val,
+ int dir)
+{
+ int changed;
+ if (hw_is_mask(var)) {
+ struct snd_mask *m = hw_param_mask(params, var);
+ if (val == 0 && dir < 0) {
+ changed = -EINVAL;
+ snd_mask_none(m);
+ } else {
+ if (dir > 0)
+ val++;
+ else if (dir < 0)
+ val--;
+ changed = snd_mask_refine_set(hw_param_mask(params, var), val);
+ }
+ } else if (hw_is_interval(var)) {
+ struct snd_interval *i = hw_param_interval(params, var);
+ if (val == 0 && dir < 0) {
+ changed = -EINVAL;
+ snd_interval_none(i);
+ } else if (dir == 0)
+ changed = snd_interval_refine_set(i, val);
+ else {
+ struct snd_interval t;
+ t.openmin = 1;
+ t.openmax = 1;
+ t.empty = 0;
+ t.integer = 0;
+ if (dir < 0) {
+ t.min = val - 1;
+ t.max = val;
+ } else {
+ t.min = val;
+ t.max = val+1;
+ }
+ changed = snd_interval_refine(i, &t);
+ }
+ } else
+ return -EINVAL;
+ if (changed) {
+ params->cmask |= 1 << var;
+ params->rmask |= 1 << var;
+ }
+ return changed;
+}
+
+/**
+ * snd_pcm_hw_param_set
+ * @pcm: PCM instance
+ * @params: the hw_params instance
+ * @var: parameter to retrieve
+ * @val: value to set
+ * @dir: pointer to the direction (-1,0,1) or NULL
+ *
+ * Inside configuration space defined by PARAMS remove from PAR all
+ * values != VAL. Reduce configuration space accordingly.
+ * Return VAL or -EINVAL if the configuration space is empty
+ */
+static int snd_pcm_hw_param_set(struct snd_pcm_substream *pcm,
+ struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, unsigned int val,
+ int dir)
+{
+ int changed = _snd_pcm_hw_param_set(params, var, val, dir);
+ if (changed < 0)
+ return changed;
+ if (params->rmask) {
+ int err = snd_pcm_hw_refine(pcm, params);
+ if (err < 0)
+ return err;
+ }
+ return snd_pcm_hw_param_value(params, var, NULL);
+}
+
+static int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var)
+{
+ int changed;
+ changed = snd_interval_setinteger(hw_param_interval(params, var));
+ if (changed) {
+ params->cmask |= 1 << var;
+ params->rmask |= 1 << var;
+ }
+ return changed;
+}
+
+/*
+ * plugin
+ */
+
#ifdef CONFIG_SND_PCM_OSS_PLUGINS
static int snd_pcm_oss_plugin_clear(struct snd_pcm_substream *substream)
{
@@ -203,7 +684,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
oss_buffer_size = snd_pcm_plug_client_size(substream,
snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size;
oss_buffer_size = 1 << ld2(oss_buffer_size);
- if (atomic_read(&runtime->mmap_count)) {
+ if (atomic_read(&substream->mmap_count)) {
if (oss_buffer_size > runtime->oss.mmap_bytes)
oss_buffer_size = runtime->oss.mmap_bytes;
}
@@ -338,7 +819,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
goto failure;
}
- if (atomic_read(&runtime->mmap_count))
+ if (atomic_read(&substream->mmap_count))
direct = 1;
else
direct = substream->oss.setup.direct;
@@ -347,7 +828,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
_snd_pcm_hw_param_setinteger(sparams, SNDRV_PCM_HW_PARAM_PERIODS);
_snd_pcm_hw_param_min(sparams, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0);
snd_mask_none(&mask);
- if (atomic_read(&runtime->mmap_count))
+ if (atomic_read(&substream->mmap_count))
snd_mask_set(&mask, SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
else {
snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_INTERLEAVED);
@@ -466,7 +947,8 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
} else {
sw_params->start_threshold = runtime->boundary;
}
- if (atomic_read(&runtime->mmap_count) || substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ if (atomic_read(&substream->mmap_count) ||
+ substream->stream == SNDRV_PCM_STREAM_CAPTURE)
sw_params->stop_threshold = runtime->boundary;
else
sw_params->stop_threshold = runtime->buffer_size;
@@ -476,7 +958,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
sw_params->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
1 : runtime->period_size;
sw_params->xfer_align = 1;
- if (atomic_read(&runtime->mmap_count) ||
+ if (atomic_read(&substream->mmap_count) ||
substream->oss.setup.nosilence) {
sw_params->silence_threshold = 0;
sw_params->silence_size = 0;
@@ -820,7 +1302,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
ssize_t tmp;
struct snd_pcm_runtime *runtime = substream->runtime;
- if (atomic_read(&runtime->mmap_count))
+ if (atomic_read(&substream->mmap_count))
return -ENXIO;
if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
@@ -850,7 +1332,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
if (runtime->oss.period_ptr == 0 ||
runtime->oss.period_ptr == runtime->oss.buffer_used)
runtime->oss.buffer_used = 0;
- else if ((substream->ffile->f_flags & O_NONBLOCK) != 0)
+ else if ((substream->f_flags & O_NONBLOCK) != 0)
return xfer > 0 ? xfer : -EAGAIN;
}
} else {
@@ -863,7 +1345,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
buf += tmp;
bytes -= tmp;
xfer += tmp;
- if ((substream->ffile->f_flags & O_NONBLOCK) != 0 &&
+ if ((substream->f_flags & O_NONBLOCK) != 0 &&
tmp != runtime->oss.period_bytes)
break;
}
@@ -910,7 +1392,7 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use
ssize_t tmp;
struct snd_pcm_runtime *runtime = substream->runtime;
- if (atomic_read(&runtime->mmap_count))
+ if (atomic_read(&substream->mmap_count))
return -ENXIO;
if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
@@ -1040,7 +1522,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
if (substream != NULL) {
runtime = substream->runtime;
- if (atomic_read(&runtime->mmap_count))
+ if (atomic_read(&substream->mmap_count))
goto __direct;
if ((err = snd_pcm_oss_make_ready(substream)) < 0)
return err;
@@ -1101,10 +1583,10 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
* finish sync: drain the buffer
*/
__direct:
- saved_f_flags = substream->ffile->f_flags;
- substream->ffile->f_flags &= ~O_NONBLOCK;
+ saved_f_flags = substream->f_flags;
+ substream->f_flags &= ~O_NONBLOCK;
err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
- substream->ffile->f_flags = saved_f_flags;
+ substream->f_flags = saved_f_flags;
if (err < 0)
return err;
runtime->oss.prepare = 1;
@@ -1209,7 +1691,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
return err;
- if (atomic_read(&substream->runtime->mmap_count))
+ if (atomic_read(&substream->mmap_count))
direct = 1;
else
direct = substream->oss.setup.direct;
@@ -1419,7 +1901,7 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
if (trigger & PCM_ENABLE_OUTPUT) {
if (runtime->oss.trigger)
goto _skip1;
- if (atomic_read(&psubstream->runtime->mmap_count))
+ if (atomic_read(&psubstream->mmap_count))
snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt);
runtime->oss.trigger = 1;
runtime->start_threshold = 1;
@@ -1537,7 +2019,7 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream
if (err < 0)
return err;
info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size);
- if (atomic_read(&runtime->mmap_count)) {
+ if (atomic_read(&substream->mmap_count)) {
snd_pcm_sframes_t n;
n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt;
if (n < 0)
@@ -1683,9 +2165,9 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
substream->oss.oss = 1;
substream->oss.setup = *setup;
if (setup->nonblock)
- substream->ffile->f_flags |= O_NONBLOCK;
+ substream->f_flags |= O_NONBLOCK;
else if (setup->block)
- substream->ffile->f_flags &= ~O_NONBLOCK;
+ substream->f_flags &= ~O_NONBLOCK;
runtime = substream->runtime;
runtime->oss.params = 1;
runtime->oss.trigger = 1;
@@ -1742,6 +2224,7 @@ static int snd_pcm_oss_open_file(struct file *file,
(pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX))
f_mode = FMODE_WRITE;
+ file->f_flags &= ~O_APPEND;
for (idx = 0; idx < 2; idx++) {
if (setup[idx].disable)
continue;
@@ -2059,6 +2542,7 @@ static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t coun
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
if (substream == NULL)
return -ENXIO;
+ substream->f_flags = file->f_flags & O_NONBLOCK;
#ifndef OSS_DEBUG
return snd_pcm_oss_read1(substream, buf, count);
#else
@@ -2080,6 +2564,7 @@ static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
if (substream == NULL)
return -ENXIO;
+ substream->f_flags = file->f_flags & O_NONBLOCK;
result = snd_pcm_oss_write1(substream, buf, count);
#ifdef OSS_DEBUG
printk("pcm_oss: write %li bytes (wrote %li bytes)\n", (long)count, (long)result);
@@ -2090,7 +2575,7 @@ static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size
static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- if (atomic_read(&runtime->mmap_count))
+ if (atomic_read(&substream->mmap_count))
return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
else
return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames;
@@ -2099,7 +2584,7 @@ static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream)
static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- if (atomic_read(&runtime->mmap_count))
+ if (atomic_read(&substream->mmap_count))
return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
else
return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames;
@@ -2342,9 +2827,7 @@ static void snd_pcm_oss_proc_init(struct snd_pcm *pcm)
if ((entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root)) != NULL) {
entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
- entry->c.text.read_size = 8192;
entry->c.text.read = snd_pcm_oss_proc_read;
- entry->c.text.write_size = 8192;
entry->c.text.write = snd_pcm_oss_proc_write;
entry->private_data = pstr;
if (snd_info_register(entry) < 0) {
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 84b0003..7581edd 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -351,10 +351,8 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "closed\n");
return;
}
- snd_pcm_stream_lock_irq(substream);
if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
snd_iprintf(buffer, "no setup\n");
- snd_pcm_stream_unlock_irq(substream);
return;
}
snd_iprintf(buffer, "access: %s\n", snd_pcm_access_name(runtime->access));
@@ -375,7 +373,6 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames);
}
#endif
- snd_pcm_stream_unlock_irq(substream);
}
static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
@@ -387,10 +384,8 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "closed\n");
return;
}
- snd_pcm_stream_lock_irq(substream);
if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
snd_iprintf(buffer, "no setup\n");
- snd_pcm_stream_unlock_irq(substream);
return;
}
snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode));
@@ -403,7 +398,6 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold);
snd_iprintf(buffer, "silence_size: %lu\n", runtime->silence_size);
snd_iprintf(buffer, "boundary: %lu\n", runtime->boundary);
- snd_pcm_stream_unlock_irq(substream);
}
static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
@@ -472,7 +466,7 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr)
pstr->proc_root = entry;
if ((entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root)) != NULL) {
- snd_info_set_text_ops(entry, pstr, 256, snd_pcm_stream_proc_info_read);
+ snd_info_set_text_ops(entry, pstr, snd_pcm_stream_proc_info_read);
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
entry = NULL;
@@ -483,9 +477,7 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr)
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
if ((entry = snd_info_create_card_entry(pcm->card, "xrun_debug",
pstr->proc_root)) != NULL) {
- entry->c.text.read_size = 64;
entry->c.text.read = snd_pcm_xrun_debug_read;
- entry->c.text.write_size = 64;
entry->c.text.write = snd_pcm_xrun_debug_write;
entry->mode |= S_IWUSR;
entry->private_data = pstr;
@@ -537,7 +529,8 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
substream->proc_root = entry;
if ((entry = snd_info_create_card_entry(card, "info", substream->proc_root)) != NULL) {
- snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_info_read);
+ snd_info_set_text_ops(entry, substream,
+ snd_pcm_substream_proc_info_read);
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
entry = NULL;
@@ -546,7 +539,8 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
substream->proc_info_entry = entry;
if ((entry = snd_info_create_card_entry(card, "hw_params", substream->proc_root)) != NULL) {
- snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_hw_params_read);
+ snd_info_set_text_ops(entry, substream,
+ snd_pcm_substream_proc_hw_params_read);
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
entry = NULL;
@@ -555,7 +549,8 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
substream->proc_hw_params_entry = entry;
if ((entry = snd_info_create_card_entry(card, "sw_params", substream->proc_root)) != NULL) {
- snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_sw_params_read);
+ snd_info_set_text_ops(entry, substream,
+ snd_pcm_substream_proc_sw_params_read);
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
entry = NULL;
@@ -564,7 +559,8 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
substream->proc_sw_params_entry = entry;
if ((entry = snd_info_create_card_entry(card, "status", substream->proc_root)) != NULL) {
- snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_status_read);
+ snd_info_set_text_ops(entry, substream,
+ snd_pcm_substream_proc_status_read);
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
entry = NULL;
@@ -666,11 +662,14 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
INIT_LIST_HEAD(&substream->self_group.substreams);
list_add_tail(&substream->link_list, &substream->self_group.substreams);
spin_lock_init(&substream->timer_lock);
+ atomic_set(&substream->mmap_count, 0);
prev = substream;
}
return 0;
}
+EXPORT_SYMBOL(snd_pcm_new_stream);
+
/**
* snd_pcm_new - create a new PCM instance
* @card: the card instance
@@ -730,6 +729,8 @@ int snd_pcm_new(struct snd_card *card, char *id, int device,
return 0;
}
+EXPORT_SYMBOL(snd_pcm_new);
+
static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
{
struct snd_pcm_substream *substream, *substream_next;
@@ -829,6 +830,26 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
return -EINVAL;
}
+ if (file->f_flags & O_APPEND) {
+ if (prefer_subdevice < 0) {
+ if (pstr->substream_count > 1)
+ return -EINVAL; /* must be unique */
+ substream = pstr->substream;
+ } else {
+ for (substream = pstr->substream; substream;
+ substream = substream->next)
+ if (substream->number == prefer_subdevice)
+ break;
+ }
+ if (! substream)
+ return -ENODEV;
+ if (! SUBSTREAM_BUSY(substream))
+ return -EBADFD;
+ substream->ref_count++;
+ *rsubstream = substream;
+ return 0;
+ }
+
if (prefer_subdevice >= 0) {
for (substream = pstr->substream; substream; substream = substream->next)
if (!SUBSTREAM_BUSY(substream) && substream->number == prefer_subdevice)
@@ -864,7 +885,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
memset((void*)runtime->control, 0, size);
init_waitqueue_head(&runtime->sleep);
- atomic_set(&runtime->mmap_count, 0);
init_timer(&runtime->tick_timer);
runtime->tick_timer.function = snd_pcm_tick_timer_func;
runtime->tick_timer.data = (unsigned long) substream;
@@ -873,7 +893,8 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
substream->runtime = runtime;
substream->private_data = pcm->private_data;
- substream->ffile = file;
+ substream->ref_count = 1;
+ substream->f_flags = file->f_flags;
pstr->substream_opened++;
*rsubstream = substream;
return 0;
@@ -882,7 +903,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime;
- substream->file = NULL;
+
runtime = substream->runtime;
snd_assert(runtime != NULL, return);
if (runtime->private_free != NULL)
@@ -1022,6 +1043,8 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
return 0;
}
+EXPORT_SYMBOL(snd_pcm_notify);
+
#ifdef CONFIG_PROC_FS
/*
* Info interface
@@ -1049,15 +1072,14 @@ static void snd_pcm_proc_read(struct snd_info_entry *entry,
mutex_unlock(&register_mutex);
}
-static struct snd_info_entry *snd_pcm_proc_entry = NULL;
+static struct snd_info_entry *snd_pcm_proc_entry;
static void snd_pcm_proc_init(void)
{
struct snd_info_entry *entry;
if ((entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL)) != NULL) {
- snd_info_set_text_ops(entry, NULL, SNDRV_CARDS * SNDRV_PCM_DEVICES * 128,
- snd_pcm_proc_read);
+ snd_info_set_text_ops(entry, NULL, snd_pcm_proc_read);
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
entry = NULL;
@@ -1099,33 +1121,3 @@ static void __exit alsa_pcm_exit(void)
module_init(alsa_pcm_init)
module_exit(alsa_pcm_exit)
-
-EXPORT_SYMBOL(snd_pcm_new);
-EXPORT_SYMBOL(snd_pcm_new_stream);
-EXPORT_SYMBOL(snd_pcm_notify);
-EXPORT_SYMBOL(snd_pcm_open_substream);
-EXPORT_SYMBOL(snd_pcm_release_substream);
- /* pcm_native.c */
-EXPORT_SYMBOL(snd_pcm_link_rwlock);
-#ifdef CONFIG_PM
-EXPORT_SYMBOL(snd_pcm_suspend);
-EXPORT_SYMBOL(snd_pcm_suspend_all);
-#endif
-EXPORT_SYMBOL(snd_pcm_kernel_ioctl);
-EXPORT_SYMBOL(snd_pcm_mmap_data);
-#if SNDRV_PCM_INFO_MMAP_IOMEM
-EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);
-#endif
- /* pcm_misc.c */
-EXPORT_SYMBOL(snd_pcm_format_signed);
-EXPORT_SYMBOL(snd_pcm_format_unsigned);
-EXPORT_SYMBOL(snd_pcm_format_linear);
-EXPORT_SYMBOL(snd_pcm_format_little_endian);
-EXPORT_SYMBOL(snd_pcm_format_big_endian);
-EXPORT_SYMBOL(snd_pcm_format_width);
-EXPORT_SYMBOL(snd_pcm_format_physical_width);
-EXPORT_SYMBOL(snd_pcm_format_size);
-EXPORT_SYMBOL(snd_pcm_format_silence_64);
-EXPORT_SYMBOL(snd_pcm_format_set_silence);
-EXPORT_SYMBOL(snd_pcm_build_linear_format);
-EXPORT_SYMBOL(snd_pcm_limit_hw_rates);
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
index e513303..2b8aab6 100644
--- a/sound/core/pcm_compat.c
+++ b/sound/core/pcm_compat.c
@@ -497,9 +497,9 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
case SNDRV_PCM_IOCTL_LINK:
case SNDRV_PCM_IOCTL_UNLINK:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- return snd_pcm_playback_ioctl1(substream, cmd, argp);
+ return snd_pcm_playback_ioctl1(file, substream, cmd, argp);
else
- return snd_pcm_capture_ioctl1(substream, cmd, argp);
+ return snd_pcm_capture_ioctl1(file, substream, cmd, argp);
case SNDRV_PCM_IOCTL_HW_REFINE32:
return snd_pcm_ioctl_hw_params_compat(substream, 1, argp);
case SNDRV_PCM_IOCTL_HW_PARAMS32:
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index eedc6cb..0bb142a 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -289,6 +289,7 @@ void snd_pcm_set_ops(struct snd_pcm *pcm, int direction, struct snd_pcm_ops *ops
substream->ops = ops;
}
+EXPORT_SYMBOL(snd_pcm_set_ops);
/**
* snd_pcm_sync - set the PCM sync id
@@ -306,13 +307,12 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream)
runtime->sync.id32[3] = -1;
}
+EXPORT_SYMBOL(snd_pcm_set_sync);
+
/*
* Standard ioctl routine
*/
-/* Code taken from alsa-lib */
-#define assert(a) snd_assert((a), return -EINVAL)
-
static inline unsigned int div32(unsigned int a, unsigned int b,
unsigned int *r)
{
@@ -369,56 +369,6 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b,
return n;
}
-static int snd_interval_refine_min(struct snd_interval *i, unsigned int min, int openmin)
-{
- int changed = 0;
- assert(!snd_interval_empty(i));
- if (i->min < min) {
- i->min = min;
- i->openmin = openmin;
- changed = 1;
- } else if (i->min == min && !i->openmin && openmin) {
- i->openmin = 1;
- changed = 1;
- }
- if (i->integer) {
- if (i->openmin) {
- i->min++;
- i->openmin = 0;
- }
- }
- if (snd_interval_checkempty(i)) {
- snd_interval_none(i);
- return -EINVAL;
- }
- return changed;
-}
-
-static int snd_interval_refine_max(struct snd_interval *i, unsigned int max, int openmax)
-{
- int changed = 0;
- assert(!snd_interval_empty(i));
- if (i->max > max) {
- i->max = max;
- i->openmax = openmax;
- changed = 1;
- } else if (i->max == max && !i->openmax && openmax) {
- i->openmax = 1;
- changed = 1;
- }
- if (i->integer) {
- if (i->openmax) {
- i->max--;
- i->openmax = 0;
- }
- }
- if (snd_interval_checkempty(i)) {
- snd_interval_none(i);
- return -EINVAL;
- }
- return changed;
-}
-
/**
* snd_interval_refine - refine the interval value of configurator
* @i: the interval value to refine
@@ -433,7 +383,7 @@ static int snd_interval_refine_max(struct snd_interval *i, unsigned int max, int
int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v)
{
int changed = 0;
- assert(!snd_interval_empty(i));
+ snd_assert(!snd_interval_empty(i), return -EINVAL);
if (i->min < v->min) {
i->min = v->min;
i->openmin = v->openmin;
@@ -472,9 +422,11 @@ int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v)
return changed;
}
+EXPORT_SYMBOL(snd_interval_refine);
+
static int snd_interval_refine_first(struct snd_interval *i)
{
- assert(!snd_interval_empty(i));
+ snd_assert(!snd_interval_empty(i), return -EINVAL);
if (snd_interval_single(i))
return 0;
i->max = i->min;
@@ -486,7 +438,7 @@ static int snd_interval_refine_first(struct snd_interval *i)
static int snd_interval_refine_last(struct snd_interval *i)
{
- assert(!snd_interval_empty(i));
+ snd_assert(!snd_interval_empty(i), return -EINVAL);
if (snd_interval_single(i))
return 0;
i->min = i->max;
@@ -496,16 +448,6 @@ static int snd_interval_refine_last(struct snd_interval *i)
return 1;
}
-static int snd_interval_refine_set(struct snd_interval *i, unsigned int val)
-{
- struct snd_interval t;
- t.empty = 0;
- t.min = t.max = val;
- t.openmin = t.openmax = 0;
- t.integer = 1;
- return snd_interval_refine(i, &t);
-}
-
void snd_interval_mul(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c)
{
if (a->empty || b->empty) {
@@ -621,7 +563,6 @@ void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k,
c->integer = 0;
}
-#undef assert
/* ---- */
@@ -727,6 +668,8 @@ int snd_interval_ratnum(struct snd_interval *i,
return err;
}
+EXPORT_SYMBOL(snd_interval_ratnum);
+
/**
* snd_interval_ratden - refine the interval value
* @i: interval to refine
@@ -877,6 +820,8 @@ int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int *
return changed;
}
+EXPORT_SYMBOL(snd_interval_list);
+
static int snd_interval_step(struct snd_interval *i, unsigned int min, unsigned int step)
{
unsigned int n;
@@ -953,6 +898,8 @@ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond,
return 0;
}
+EXPORT_SYMBOL(snd_pcm_hw_rule_add);
+
/**
* snd_pcm_hw_constraint_mask
* @runtime: PCM runtime instance
@@ -1007,6 +954,8 @@ int snd_pcm_hw_constraint_integer(struct snd_pcm_runtime *runtime, snd_pcm_hw_pa
return snd_interval_setinteger(constrs_interval(constrs, var));
}
+EXPORT_SYMBOL(snd_pcm_hw_constraint_integer);
+
/**
* snd_pcm_hw_constraint_minmax
* @runtime: PCM runtime instance
@@ -1028,6 +977,8 @@ int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_par
return snd_interval_refine(constrs_interval(constrs, var), &t);
}
+EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax);
+
static int snd_pcm_hw_rule_list(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
@@ -1055,6 +1006,8 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime,
var, -1);
}
+EXPORT_SYMBOL(snd_pcm_hw_constraint_list);
+
static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
@@ -1087,6 +1040,8 @@ int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime,
var, -1);
}
+EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums);
+
static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
@@ -1118,6 +1073,8 @@ int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime,
var, -1);
}
+EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens);
+
static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
@@ -1149,6 +1106,8 @@ int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime,
SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
}
+EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits);
+
static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
@@ -1173,6 +1132,8 @@ int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime,
var, -1);
}
+EXPORT_SYMBOL(snd_pcm_hw_constraint_step);
+
static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
{
static int pow2_sizes[] = {
@@ -1200,11 +1161,7 @@ int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime,
var, -1);
}
-/* To use the same code we have in alsa-lib */
-#define assert(i) snd_assert((i), return -EINVAL)
-#ifndef INT_MIN
-#define INT_MIN ((int)((unsigned int)INT_MAX+1))
-#endif
+EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2);
static void _snd_pcm_hw_param_any(struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var)
@@ -1224,18 +1181,6 @@ static void _snd_pcm_hw_param_any(struct snd_pcm_hw_params *params,
snd_BUG();
}
-#if 0
-/*
- * snd_pcm_hw_param_any
- */
-int snd_pcm_hw_param_any(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var)
-{
- _snd_pcm_hw_param_any(params, var);
- return snd_pcm_hw_refine(pcm, params);
-}
-#endif /* 0 */
-
void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params)
{
unsigned int k;
@@ -1247,18 +1192,7 @@ void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params)
params->info = ~0U;
}
-#if 0
-/*
- * snd_pcm_hw_params_any
- *
- * Fill PARAMS with full configuration space boundaries
- */
-int snd_pcm_hw_params_any(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params)
-{
- _snd_pcm_hw_params_any(params);
- return snd_pcm_hw_refine(pcm, params);
-}
-#endif /* 0 */
+EXPORT_SYMBOL(_snd_pcm_hw_params_any);
/**
* snd_pcm_hw_param_value
@@ -1269,8 +1203,8 @@ int snd_pcm_hw_params_any(struct snd_pcm_substream *pcm, struct snd_pcm_hw_param
* Return the value for field PAR if it's fixed in configuration space
* defined by PARAMS. Return -EINVAL otherwise
*/
-static int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var, int *dir)
+int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, int *dir)
{
if (hw_is_mask(var)) {
const struct snd_mask *mask = hw_param_mask_c(params, var);
@@ -1288,61 +1222,10 @@ static int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,
*dir = i->openmin;
return snd_interval_value(i);
}
- assert(0);
- return -EINVAL;
-}
-
-/**
- * snd_pcm_hw_param_value_min
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Return the minimum value for field PAR.
- */
-unsigned int snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var, int *dir)
-{
- if (hw_is_mask(var)) {
- if (dir)
- *dir = 0;
- return snd_mask_min(hw_param_mask_c(params, var));
- }
- if (hw_is_interval(var)) {
- const struct snd_interval *i = hw_param_interval_c(params, var);
- if (dir)
- *dir = i->openmin;
- return snd_interval_min(i);
- }
- assert(0);
return -EINVAL;
}
-/**
- * snd_pcm_hw_param_value_max
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Return the maximum value for field PAR.
- */
-unsigned int snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var, int *dir)
-{
- if (hw_is_mask(var)) {
- if (dir)
- *dir = 0;
- return snd_mask_max(hw_param_mask_c(params, var));
- }
- if (hw_is_interval(var)) {
- const struct snd_interval *i = hw_param_interval_c(params, var);
- if (dir)
- *dir = - (int) i->openmax;
- return snd_interval_max(i);
- }
- assert(0);
- return -EINVAL;
-}
+EXPORT_SYMBOL(snd_pcm_hw_param_value);
void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var)
@@ -1360,42 +1243,7 @@ void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params,
}
}
-int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var)
-{
- int changed;
- assert(hw_is_interval(var));
- changed = snd_interval_setinteger(hw_param_interval(params, var));
- if (changed) {
- params->cmask |= 1 << var;
- params->rmask |= 1 << var;
- }
- return changed;
-}
-
-#if 0
-/*
- * snd_pcm_hw_param_setinteger
- *
- * Inside configuration space defined by PARAMS remove from PAR all
- * non integer values. Reduce configuration space accordingly.
- * Return -EINVAL if the configuration space is empty
- */
-int snd_pcm_hw_param_setinteger(struct snd_pcm_substream *pcm,
- struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var)
-{
- int changed = _snd_pcm_hw_param_setinteger(params, var);
- if (changed < 0)
- return changed;
- if (params->rmask) {
- int err = snd_pcm_hw_refine(pcm, params);
- if (err < 0)
- return err;
- }
- return 0;
-}
-#endif /* 0 */
+EXPORT_SYMBOL(_snd_pcm_hw_param_setempty);
static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var)
@@ -1405,10 +1253,8 @@ static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params,
changed = snd_mask_refine_first(hw_param_mask(params, var));
else if (hw_is_interval(var))
changed = snd_interval_refine_first(hw_param_interval(params, var));
- else {
- assert(0);
+ else
return -EINVAL;
- }
if (changed) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
@@ -1428,20 +1274,22 @@ static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params,
* values > minimum. Reduce configuration space accordingly.
* Return the minimum.
*/
-static int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm,
- struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var, int *dir)
+int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm,
+ struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, int *dir)
{
int changed = _snd_pcm_hw_param_first(params, var);
if (changed < 0)
return changed;
if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params);
- assert(err >= 0);
+ snd_assert(err >= 0, return err);
}
return snd_pcm_hw_param_value(params, var, dir);
}
+EXPORT_SYMBOL(snd_pcm_hw_param_first);
+
static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var)
{
@@ -1450,10 +1298,8 @@ static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params,
changed = snd_mask_refine_last(hw_param_mask(params, var));
else if (hw_is_interval(var))
changed = snd_interval_refine_last(hw_param_interval(params, var));
- else {
- assert(0);
+ else
return -EINVAL;
- }
if (changed) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
@@ -1473,381 +1319,21 @@ static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params,
* values < maximum. Reduce configuration space accordingly.
* Return the maximum.
*/
-static int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm,
- struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var, int *dir)
+int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm,
+ struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, int *dir)
{
int changed = _snd_pcm_hw_param_last(params, var);
if (changed < 0)
return changed;
if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params);
- assert(err >= 0);
+ snd_assert(err >= 0, return err);
}
return snd_pcm_hw_param_value(params, var, dir);
}
-int _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var, unsigned int val, int dir)
-{
- int changed;
- int open = 0;
- if (dir) {
- if (dir > 0) {
- open = 1;
- } else if (dir < 0) {
- if (val > 0) {
- open = 1;
- val--;
- }
- }
- }
- if (hw_is_mask(var))
- changed = snd_mask_refine_min(hw_param_mask(params, var), val + !!open);
- else if (hw_is_interval(var))
- changed = snd_interval_refine_min(hw_param_interval(params, var), val, open);
- else {
- assert(0);
- return -EINVAL;
- }
- if (changed) {
- params->cmask |= 1 << var;
- params->rmask |= 1 << var;
- }
- return changed;
-}
-
-/**
- * snd_pcm_hw_param_min
- * @pcm: PCM instance
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @val: minimal value
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Inside configuration space defined by PARAMS remove from PAR all
- * values < VAL. Reduce configuration space accordingly.
- * Return new minimum or -EINVAL if the configuration space is empty
- */
-static int snd_pcm_hw_param_min(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var, unsigned int val,
- int *dir)
-{
- int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0);
- if (changed < 0)
- return changed;
- if (params->rmask) {
- int err = snd_pcm_hw_refine(pcm, params);
- if (err < 0)
- return err;
- }
- return snd_pcm_hw_param_value_min(params, var, dir);
-}
-
-static int _snd_pcm_hw_param_max(struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var, unsigned int val,
- int dir)
-{
- int changed;
- int open = 0;
- if (dir) {
- if (dir < 0) {
- open = 1;
- } else if (dir > 0) {
- open = 1;
- val++;
- }
- }
- if (hw_is_mask(var)) {
- if (val == 0 && open) {
- snd_mask_none(hw_param_mask(params, var));
- changed = -EINVAL;
- } else
- changed = snd_mask_refine_max(hw_param_mask(params, var), val - !!open);
- } else if (hw_is_interval(var))
- changed = snd_interval_refine_max(hw_param_interval(params, var), val, open);
- else {
- assert(0);
- return -EINVAL;
- }
- if (changed) {
- params->cmask |= 1 << var;
- params->rmask |= 1 << var;
- }
- return changed;
-}
-
-/**
- * snd_pcm_hw_param_max
- * @pcm: PCM instance
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @val: maximal value
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Inside configuration space defined by PARAMS remove from PAR all
- * values >= VAL + 1. Reduce configuration space accordingly.
- * Return new maximum or -EINVAL if the configuration space is empty
- */
-static int snd_pcm_hw_param_max(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var, unsigned int val,
- int *dir)
-{
- int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0);
- if (changed < 0)
- return changed;
- if (params->rmask) {
- int err = snd_pcm_hw_refine(pcm, params);
- if (err < 0)
- return err;
- }
- return snd_pcm_hw_param_value_max(params, var, dir);
-}
-
-int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var, unsigned int val, int dir)
-{
- int changed;
- if (hw_is_mask(var)) {
- struct snd_mask *m = hw_param_mask(params, var);
- if (val == 0 && dir < 0) {
- changed = -EINVAL;
- snd_mask_none(m);
- } else {
- if (dir > 0)
- val++;
- else if (dir < 0)
- val--;
- changed = snd_mask_refine_set(hw_param_mask(params, var), val);
- }
- } else if (hw_is_interval(var)) {
- struct snd_interval *i = hw_param_interval(params, var);
- if (val == 0 && dir < 0) {
- changed = -EINVAL;
- snd_interval_none(i);
- } else if (dir == 0)
- changed = snd_interval_refine_set(i, val);
- else {
- struct snd_interval t;
- t.openmin = 1;
- t.openmax = 1;
- t.empty = 0;
- t.integer = 0;
- if (dir < 0) {
- t.min = val - 1;
- t.max = val;
- } else {
- t.min = val;
- t.max = val+1;
- }
- changed = snd_interval_refine(i, &t);
- }
- } else {
- assert(0);
- return -EINVAL;
- }
- if (changed) {
- params->cmask |= 1 << var;
- params->rmask |= 1 << var;
- }
- return changed;
-}
-
-/**
- * snd_pcm_hw_param_set
- * @pcm: PCM instance
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @val: value to set
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Inside configuration space defined by PARAMS remove from PAR all
- * values != VAL. Reduce configuration space accordingly.
- * Return VAL or -EINVAL if the configuration space is empty
- */
-int snd_pcm_hw_param_set(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var, unsigned int val, int dir)
-{
- int changed = _snd_pcm_hw_param_set(params, var, val, dir);
- if (changed < 0)
- return changed;
- if (params->rmask) {
- int err = snd_pcm_hw_refine(pcm, params);
- if (err < 0)
- return err;
- }
- return snd_pcm_hw_param_value(params, var, NULL);
-}
-
-static int _snd_pcm_hw_param_mask(struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var, const struct snd_mask *val)
-{
- int changed;
- assert(hw_is_mask(var));
- changed = snd_mask_refine(hw_param_mask(params, var), val);
- if (changed) {
- params->cmask |= 1 << var;
- params->rmask |= 1 << var;
- }
- return changed;
-}
-
-/**
- * snd_pcm_hw_param_mask
- * @pcm: PCM instance
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @val: mask to apply
- *
- * Inside configuration space defined by PARAMS remove from PAR all values
- * not contained in MASK. Reduce configuration space accordingly.
- * This function can be called only for SNDRV_PCM_HW_PARAM_ACCESS,
- * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT.
- * Return 0 on success or -EINVAL
- * if the configuration space is empty
- */
-int snd_pcm_hw_param_mask(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var, const struct snd_mask *val)
-{
- int changed = _snd_pcm_hw_param_mask(params, var, val);
- if (changed < 0)
- return changed;
- if (params->rmask) {
- int err = snd_pcm_hw_refine(pcm, params);
- if (err < 0)
- return err;
- }
- return 0;
-}
-
-static int boundary_sub(int a, int adir,
- int b, int bdir,
- int *c, int *cdir)
-{
- adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0);
- bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0);
- *c = a - b;
- *cdir = adir - bdir;
- if (*cdir == -2) {
- assert(*c > INT_MIN);
- (*c)--;
- } else if (*cdir == 2) {
- assert(*c < INT_MAX);
- (*c)++;
- }
- return 0;
-}
-
-static int boundary_lt(unsigned int a, int adir,
- unsigned int b, int bdir)
-{
- assert(a > 0 || adir >= 0);
- assert(b > 0 || bdir >= 0);
- if (adir < 0) {
- a--;
- adir = 1;
- } else if (adir > 0)
- adir = 1;
- if (bdir < 0) {
- b--;
- bdir = 1;
- } else if (bdir > 0)
- bdir = 1;
- return a < b || (a == b && adir < bdir);
-}
-
-/* Return 1 if min is nearer to best than max */
-static int boundary_nearer(int min, int mindir,
- int best, int bestdir,
- int max, int maxdir)
-{
- int dmin, dmindir;
- int dmax, dmaxdir;
- boundary_sub(best, bestdir, min, mindir, &dmin, &dmindir);
- boundary_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir);
- return boundary_lt(dmin, dmindir, dmax, dmaxdir);
-}
-
-/**
- * snd_pcm_hw_param_near
- * @pcm: PCM instance
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @best: value to set
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Inside configuration space defined by PARAMS set PAR to the available value
- * nearest to VAL. Reduce configuration space accordingly.
- * This function cannot be called for SNDRV_PCM_HW_PARAM_ACCESS,
- * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT.
- * Return the value found.
- */
-int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var, unsigned int best, int *dir)
-{
- struct snd_pcm_hw_params *save = NULL;
- int v;
- unsigned int saved_min;
- int last = 0;
- int min, max;
- int mindir, maxdir;
- int valdir = dir ? *dir : 0;
- /* FIXME */
- if (best > INT_MAX)
- best = INT_MAX;
- min = max = best;
- mindir = maxdir = valdir;
- if (maxdir > 0)
- maxdir = 0;
- else if (maxdir == 0)
- maxdir = -1;
- else {
- maxdir = 1;
- max--;
- }
- save = kmalloc(sizeof(*save), GFP_KERNEL);
- if (save == NULL)
- return -ENOMEM;
- *save = *params;
- saved_min = min;
- min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir);
- if (min >= 0) {
- struct snd_pcm_hw_params *params1;
- if (max < 0)
- goto _end;
- if ((unsigned int)min == saved_min && mindir == valdir)
- goto _end;
- params1 = kmalloc(sizeof(*params1), GFP_KERNEL);
- if (params1 == NULL) {
- kfree(save);
- return -ENOMEM;
- }
- *params1 = *save;
- max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir);
- if (max < 0) {
- kfree(params1);
- goto _end;
- }
- if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
- *params = *params1;
- last = 1;
- }
- kfree(params1);
- } else {
- *params = *save;
- max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
- assert(max >= 0);
- last = 1;
- }
- _end:
- kfree(save);
- if (last)
- v = snd_pcm_hw_param_last(pcm, params, var, dir);
- else
- v = snd_pcm_hw_param_first(pcm, params, var, dir);
- assert(v >= 0);
- return v;
-}
+EXPORT_SYMBOL(snd_pcm_hw_param_last);
/**
* snd_pcm_hw_param_choose
@@ -1859,39 +1345,32 @@ int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm, struct snd_pcm_hw_param
* first access, first format, first subformat, min channels,
* min rate, min period time, max buffer size, min tick time
*/
-int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params)
-{
- int err;
-
- err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_ACCESS, NULL);
- assert(err >= 0);
-
- err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_FORMAT, NULL);
- assert(err >= 0);
-
- err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_SUBFORMAT, NULL);
- assert(err >= 0);
-
- err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_CHANNELS, NULL);
- assert(err >= 0);
-
- err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_RATE, NULL);
- assert(err >= 0);
-
- err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_PERIOD_TIME, NULL);
- assert(err >= 0);
-
- err = snd_pcm_hw_param_last(pcm, params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL);
- assert(err >= 0);
-
- err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_TICK_TIME, NULL);
- assert(err >= 0);
+int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
+ struct snd_pcm_hw_params *params)
+{
+ static int vars[] = {
+ SNDRV_PCM_HW_PARAM_ACCESS,
+ SNDRV_PCM_HW_PARAM_FORMAT,
+ SNDRV_PCM_HW_PARAM_SUBFORMAT,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ SNDRV_PCM_HW_PARAM_RATE,
+ SNDRV_PCM_HW_PARAM_PERIOD_TIME,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+ SNDRV_PCM_HW_PARAM_TICK_TIME,
+ -1
+ };
+ int err, *v;
+ for (v = vars; *v != -1; v++) {
+ if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE)
+ err = snd_pcm_hw_param_first(pcm, params, *v, NULL);
+ else
+ err = snd_pcm_hw_param_last(pcm, params, *v, NULL);
+ snd_assert(err >= 0, return err);
+ }
return 0;
}
-#undef assert
-
static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
void *arg)
{
@@ -1967,6 +1446,8 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
return -ENXIO;
}
+EXPORT_SYMBOL(snd_pcm_lib_ioctl);
+
/*
* Conditions
*/
@@ -2101,6 +1582,8 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
kill_fasync(&runtime->fasync, SIGIO, POLL_IN);
}
+EXPORT_SYMBOL(snd_pcm_period_elapsed);
+
static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream,
unsigned int hwoff,
unsigned long data, unsigned int off,
@@ -2299,7 +1782,7 @@ snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const v
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
- nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
+ nonblock = !!(substream->f_flags & O_NONBLOCK);
if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
runtime->channels > 1)
@@ -2308,6 +1791,8 @@ snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const v
snd_pcm_lib_write_transfer);
}
+EXPORT_SYMBOL(snd_pcm_lib_write);
+
static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream,
unsigned int hwoff,
unsigned long data, unsigned int off,
@@ -2362,7 +1847,7 @@ snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream,
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
- nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
+ nonblock = !!(substream->f_flags & O_NONBLOCK);
if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
return -EINVAL;
@@ -2370,6 +1855,8 @@ snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream,
nonblock, snd_pcm_lib_writev_transfer);
}
+EXPORT_SYMBOL(snd_pcm_lib_writev);
+
static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream,
unsigned int hwoff,
unsigned long data, unsigned int off,
@@ -2572,12 +2059,14 @@ snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __u
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
- nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
+ nonblock = !!(substream->f_flags & O_NONBLOCK);
if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED)
return -EINVAL;
return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer);
}
+EXPORT_SYMBOL(snd_pcm_lib_read);
+
static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream,
unsigned int hwoff,
unsigned long data, unsigned int off,
@@ -2629,58 +2118,10 @@ snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream,
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
- nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
+ nonblock = !!(substream->f_flags & O_NONBLOCK);
if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
return -EINVAL;
return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_readv_transfer);
}
-/*
- * Exported symbols
- */
-
-EXPORT_SYMBOL(snd_interval_refine);
-EXPORT_SYMBOL(snd_interval_list);
-EXPORT_SYMBOL(snd_interval_ratnum);
-EXPORT_SYMBOL(_snd_pcm_hw_params_any);
-EXPORT_SYMBOL(_snd_pcm_hw_param_min);
-EXPORT_SYMBOL(_snd_pcm_hw_param_set);
-EXPORT_SYMBOL(_snd_pcm_hw_param_setempty);
-EXPORT_SYMBOL(_snd_pcm_hw_param_setinteger);
-EXPORT_SYMBOL(snd_pcm_hw_param_value_min);
-EXPORT_SYMBOL(snd_pcm_hw_param_value_max);
-EXPORT_SYMBOL(snd_pcm_hw_param_mask);
-EXPORT_SYMBOL(snd_pcm_hw_param_first);
-EXPORT_SYMBOL(snd_pcm_hw_param_last);
-EXPORT_SYMBOL(snd_pcm_hw_param_near);
-EXPORT_SYMBOL(snd_pcm_hw_param_set);
-EXPORT_SYMBOL(snd_pcm_hw_refine);
-EXPORT_SYMBOL(snd_pcm_hw_constraints_init);
-EXPORT_SYMBOL(snd_pcm_hw_constraints_complete);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_list);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_step);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_integer);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2);
-EXPORT_SYMBOL(snd_pcm_hw_rule_add);
-EXPORT_SYMBOL(snd_pcm_set_ops);
-EXPORT_SYMBOL(snd_pcm_set_sync);
-EXPORT_SYMBOL(snd_pcm_lib_ioctl);
-EXPORT_SYMBOL(snd_pcm_stop);
-EXPORT_SYMBOL(snd_pcm_period_elapsed);
-EXPORT_SYMBOL(snd_pcm_lib_write);
-EXPORT_SYMBOL(snd_pcm_lib_read);
-EXPORT_SYMBOL(snd_pcm_lib_writev);
EXPORT_SYMBOL(snd_pcm_lib_readv);
-EXPORT_SYMBOL(snd_pcm_lib_buffer_bytes);
-EXPORT_SYMBOL(snd_pcm_lib_period_bytes);
-/* pcm_memory.c */
-EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all);
-EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages);
-EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all);
-EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
-EXPORT_SYMBOL(snd_pcm_lib_malloc_pages);
-EXPORT_SYMBOL(snd_pcm_lib_free_pages);
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
index 428f8c1..067d205 100644
--- a/sound/core/pcm_memory.c
+++ b/sound/core/pcm_memory.c
@@ -126,6 +126,8 @@ int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm)
return 0;
}
+EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all);
+
#ifdef CONFIG_SND_VERBOSE_PROCFS
/*
* read callback for prealloc proc file
@@ -191,9 +193,7 @@ static inline void preallocate_info_init(struct snd_pcm_substream *substream)
struct snd_info_entry *entry;
if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc", substream->proc_root)) != NULL) {
- entry->c.text.read_size = 64;
entry->c.text.read = snd_pcm_lib_preallocate_proc_read;
- entry->c.text.write_size = 64;
entry->c.text.write = snd_pcm_lib_preallocate_proc_write;
entry->mode |= S_IWUSR;
entry->private_data = substream;
@@ -253,6 +253,8 @@ int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream,
return snd_pcm_lib_preallocate_pages1(substream, size, max);
}
+EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages);
+
/**
* snd_pcm_lib_preallocate_pages_for_all - pre-allocation for continous memory type (all substreams)
* @pcm: the pcm instance
@@ -280,6 +282,8 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
return 0;
}
+EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all);
+
/**
* snd_pcm_sgbuf_ops_page - get the page struct at the given offset
* @substream: the pcm substream instance
@@ -298,6 +302,8 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne
return sgbuf->page_table[idx];
}
+EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
+
/**
* snd_pcm_lib_malloc_pages - allocate the DMA buffer
* @substream: the substream to allocate the DMA buffer to
@@ -349,6 +355,8 @@ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size)
return 1; /* area was changed */
}
+EXPORT_SYMBOL(snd_pcm_lib_malloc_pages);
+
/**
* snd_pcm_lib_free_pages - release the allocated DMA buffer.
* @substream: the substream to release the DMA buffer
@@ -374,3 +382,5 @@ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream)
snd_pcm_set_runtime_buffer(substream, NULL);
return 0;
}
+
+EXPORT_SYMBOL(snd_pcm_lib_free_pages);
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c
index 593c77f..0019c59 100644
--- a/sound/core/pcm_misc.c
+++ b/sound/core/pcm_misc.c
@@ -207,6 +207,8 @@ int snd_pcm_format_signed(snd_pcm_format_t format)
return val;
}
+EXPORT_SYMBOL(snd_pcm_format_signed);
+
/**
* snd_pcm_format_unsigned - Check the PCM format is unsigned linear
* @format: the format to check
@@ -224,6 +226,8 @@ int snd_pcm_format_unsigned(snd_pcm_format_t format)
return !val;
}
+EXPORT_SYMBOL(snd_pcm_format_unsigned);
+
/**
* snd_pcm_format_linear - Check the PCM format is linear
* @format: the format to check
@@ -235,6 +239,8 @@ int snd_pcm_format_linear(snd_pcm_format_t format)
return snd_pcm_format_signed(format) >= 0;
}
+EXPORT_SYMBOL(snd_pcm_format_linear);
+
/**
* snd_pcm_format_little_endian - Check the PCM format is little-endian
* @format: the format to check
@@ -252,6 +258,8 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format)
return val;
}
+EXPORT_SYMBOL(snd_pcm_format_little_endian);
+
/**
* snd_pcm_format_big_endian - Check the PCM format is big-endian
* @format: the format to check
@@ -269,6 +277,8 @@ int snd_pcm_format_big_endian(snd_pcm_format_t format)
return !val;
}
+EXPORT_SYMBOL(snd_pcm_format_big_endian);
+
/**
* snd_pcm_format_width - return the bit-width of the format
* @format: the format to check
@@ -286,6 +296,8 @@ int snd_pcm_format_width(snd_pcm_format_t format)
return val;
}
+EXPORT_SYMBOL(snd_pcm_format_width);
+
/**
* snd_pcm_format_physical_width - return the physical bit-width of the format
* @format: the format to check
@@ -303,6 +315,8 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format)
return val;
}
+EXPORT_SYMBOL(snd_pcm_format_physical_width);
+
/**
* snd_pcm_format_size - return the byte size of samples on the given format
* @format: the format to check
@@ -318,6 +332,8 @@ ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
return samples * phys_width / 8;
}
+EXPORT_SYMBOL(snd_pcm_format_size);
+
/**
* snd_pcm_format_silence_64 - return the silent data in 8 bytes array
* @format: the format to check
@@ -333,6 +349,8 @@ const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format)
return pcm_formats[format].silence;
}
+EXPORT_SYMBOL(snd_pcm_format_silence_64);
+
/**
* snd_pcm_format_set_silence - set the silence data on the buffer
* @format: the PCM format
@@ -402,6 +420,8 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int
return 0;
}
+EXPORT_SYMBOL(snd_pcm_format_set_silence);
+
/* [width][unsigned][bigendian] */
static int linear_formats[4][2][2] = {
{{ SNDRV_PCM_FORMAT_S8, SNDRV_PCM_FORMAT_S8},
@@ -432,6 +452,8 @@ snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_end
return linear_formats[width][!!unsignd][!!big_endian];
}
+EXPORT_SYMBOL(snd_pcm_build_linear_format);
+
/**
* snd_pcm_limit_hw_rates - determine rate_min/rate_max fields
* @runtime: the runtime instance
@@ -463,3 +485,5 @@ int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime)
}
return 0;
}
+
+EXPORT_SYMBOL(snd_pcm_limit_hw_rates);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 0860c5a..439f047 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -71,8 +71,9 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream);
*/
DEFINE_RWLOCK(snd_pcm_link_rwlock);
-static DECLARE_RWSEM(snd_pcm_link_rwsem);
+EXPORT_SYMBOL(snd_pcm_link_rwlock);
+static DECLARE_RWSEM(snd_pcm_link_rwsem);
static inline mm_segment_t snd_enter_user(void)
{
@@ -319,6 +320,8 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
return 0;
}
+EXPORT_SYMBOL(snd_pcm_hw_refine);
+
static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params __user * _params)
{
@@ -369,7 +372,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
if (!substream->oss.oss)
#endif
- if (atomic_read(&runtime->mmap_count))
+ if (atomic_read(&substream->mmap_count))
return -EBADFD;
params->rmask = ~0U;
@@ -482,7 +485,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
return -EBADFD;
}
snd_pcm_stream_unlock_irq(substream);
- if (atomic_read(&runtime->mmap_count))
+ if (atomic_read(&substream->mmap_count))
return -EBADFD;
if (substream->ops->hw_free)
result = substream->ops->hw_free(substream);
@@ -936,6 +939,8 @@ int snd_pcm_stop(struct snd_pcm_substream *substream, int state)
return snd_pcm_action(&snd_pcm_action_stop, substream, state);
}
+EXPORT_SYMBOL(snd_pcm_stop);
+
/**
* snd_pcm_drain_done
* @substream: the PCM substream
@@ -1085,6 +1090,8 @@ int snd_pcm_suspend(struct snd_pcm_substream *substream)
return err;
}
+EXPORT_SYMBOL(snd_pcm_suspend);
+
/**
* snd_pcm_suspend_all
* @pcm: the PCM instance
@@ -1114,6 +1121,8 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm)
return 0;
}
+EXPORT_SYMBOL(snd_pcm_suspend_all);
+
/* resume */
static int snd_pcm_pre_resume(struct snd_pcm_substream *substream, int state)
@@ -1275,13 +1284,16 @@ static int snd_pcm_reset(struct snd_pcm_substream *substream)
/*
* prepare ioctl
*/
-static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream, int state)
+/* we use the second argument for updating f_flags */
+static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream,
+ int f_flags)
{
struct snd_pcm_runtime *runtime = substream->runtime;
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
if (snd_pcm_running(substream))
return -EBUSY;
+ substream->f_flags = f_flags;
return 0;
}
@@ -1310,17 +1322,26 @@ static struct action_ops snd_pcm_action_prepare = {
/**
* snd_pcm_prepare
* @substream: the PCM substream instance
+ * @file: file to refer f_flags
*
* Prepare the PCM substream to be triggerable.
*/
-static int snd_pcm_prepare(struct snd_pcm_substream *substream)
+static int snd_pcm_prepare(struct snd_pcm_substream *substream,
+ struct file *file)
{
int res;
struct snd_card *card = substream->pcm->card;
+ int f_flags;
+
+ if (file)
+ f_flags = file->f_flags;
+ else
+ f_flags = substream->f_flags;
snd_power_lock(card);
if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0)
- res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, substream, 0);
+ res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare,
+ substream, f_flags);
snd_power_unlock(card);
return res;
}
@@ -1331,7 +1352,7 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream)
static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state)
{
- if (substream->ffile->f_flags & O_NONBLOCK)
+ if (substream->f_flags & O_NONBLOCK)
return -EAGAIN;
substream->runtime->trigger_master = substream;
return 0;
@@ -1448,8 +1469,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream)
}
}
up_read(&snd_pcm_link_rwsem);
- if (! num_drecs)
- goto _error;
snd_pcm_stream_lock_irq(substream);
/* resume pause */
@@ -2006,6 +2025,10 @@ static void pcm_release_private(struct snd_pcm_substream *substream)
void snd_pcm_release_substream(struct snd_pcm_substream *substream)
{
+ substream->ref_count--;
+ if (substream->ref_count > 0)
+ return;
+
snd_pcm_drop(substream);
if (substream->hw_opened) {
if (substream->ops->hw_free != NULL)
@@ -2020,6 +2043,8 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream)
snd_pcm_detach_substream(substream);
}
+EXPORT_SYMBOL(snd_pcm_release_substream);
+
int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
struct file *file,
struct snd_pcm_substream **rsubstream)
@@ -2030,6 +2055,11 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
err = snd_pcm_attach_substream(pcm, stream, file, &substream);
if (err < 0)
return err;
+ if (substream->ref_count > 1) {
+ *rsubstream = substream;
+ return 0;
+ }
+
substream->no_mmap_ctrl = 0;
err = snd_pcm_hw_constraints_init(substream);
if (err < 0) {
@@ -2056,6 +2086,8 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
return err;
}
+EXPORT_SYMBOL(snd_pcm_open_substream);
+
static int snd_pcm_open_file(struct file *file,
struct snd_pcm *pcm,
int stream,
@@ -2073,17 +2105,20 @@ static int snd_pcm_open_file(struct file *file,
if (err < 0)
return err;
- pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
- if (pcm_file == NULL) {
- snd_pcm_release_substream(substream);
- return -ENOMEM;
+ if (substream->ref_count > 1)
+ pcm_file = substream->file;
+ else {
+ pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
+ if (pcm_file == NULL) {
+ snd_pcm_release_substream(substream);
+ return -ENOMEM;
+ }
+ str = substream->pstr;
+ substream->file = pcm_file;
+ substream->pcm_release = pcm_release_private;
+ pcm_file->substream = substream;
+ snd_pcm_add_file(str, pcm_file);
}
- str = substream->pstr;
- substream->file = pcm_file;
- substream->pcm_release = pcm_release_private;
- pcm_file->substream = substream;
- snd_pcm_add_file(str, pcm_file);
-
file->private_data = pcm_file;
*rpcm_file = pcm_file;
return 0;
@@ -2170,7 +2205,6 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
pcm_file = file->private_data;
substream = pcm_file->substream;
snd_assert(substream != NULL, return -ENXIO);
- snd_assert(!atomic_read(&substream->runtime->mmap_count), );
pcm = substream->pcm;
fasync_helper(-1, file, 0, &substream->runtime->fasync);
mutex_lock(&pcm->open_mutex);
@@ -2493,7 +2527,8 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
return 0;
}
-static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream,
+static int snd_pcm_common_ioctl1(struct file *file,
+ struct snd_pcm_substream *substream,
unsigned int cmd, void __user *arg)
{
snd_assert(substream != NULL, return -ENXIO);
@@ -2518,7 +2553,7 @@ static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream,
case SNDRV_PCM_IOCTL_CHANNEL_INFO:
return snd_pcm_channel_info_user(substream, arg);
case SNDRV_PCM_IOCTL_PREPARE:
- return snd_pcm_prepare(substream);
+ return snd_pcm_prepare(substream, file);
case SNDRV_PCM_IOCTL_RESET:
return snd_pcm_reset(substream);
case SNDRV_PCM_IOCTL_START:
@@ -2560,7 +2595,8 @@ static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream,
return -ENOTTY;
}
-static int snd_pcm_playback_ioctl1(struct snd_pcm_substream *substream,
+static int snd_pcm_playback_ioctl1(struct file *file,
+ struct snd_pcm_substream *substream,
unsigned int cmd, void __user *arg)
{
snd_assert(substream != NULL, return -ENXIO);
@@ -2636,10 +2672,11 @@ static int snd_pcm_playback_ioctl1(struct snd_pcm_substream *substream,
return result < 0 ? result : 0;
}
}
- return snd_pcm_common_ioctl1(substream, cmd, arg);
+ return snd_pcm_common_ioctl1(file, substream, cmd, arg);
}
-static int snd_pcm_capture_ioctl1(struct snd_pcm_substream *substream,
+static int snd_pcm_capture_ioctl1(struct file *file,
+ struct snd_pcm_substream *substream,
unsigned int cmd, void __user *arg)
{
snd_assert(substream != NULL, return -ENXIO);
@@ -2715,7 +2752,7 @@ static int snd_pcm_capture_ioctl1(struct snd_pcm_substream *substream,
return result < 0 ? result : 0;
}
}
- return snd_pcm_common_ioctl1(substream, cmd, arg);
+ return snd_pcm_common_ioctl1(file, substream, cmd, arg);
}
static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd,
@@ -2728,7 +2765,8 @@ static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd,
if (((cmd >> 8) & 0xff) != 'A')
return -ENOTTY;
- return snd_pcm_playback_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
+ return snd_pcm_playback_ioctl1(file, pcm_file->substream, cmd,
+ (void __user *)arg);
}
static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd,
@@ -2741,7 +2779,8 @@ static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd,
if (((cmd >> 8) & 0xff) != 'A')
return -ENOTTY;
- return snd_pcm_capture_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
+ return snd_pcm_capture_ioctl1(file, pcm_file->substream, cmd,
+ (void __user *)arg);
}
int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
@@ -2753,12 +2792,12 @@ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
fs = snd_enter_user();
switch (substream->stream) {
case SNDRV_PCM_STREAM_PLAYBACK:
- result = snd_pcm_playback_ioctl1(substream,
- cmd, (void __user *)arg);
+ result = snd_pcm_playback_ioctl1(NULL, substream, cmd,
+ (void __user *)arg);
break;
case SNDRV_PCM_STREAM_CAPTURE:
- result = snd_pcm_capture_ioctl1(substream,
- cmd, (void __user *)arg);
+ result = snd_pcm_capture_ioctl1(NULL, substream, cmd,
+ (void __user *)arg);
break;
default:
result = -EINVAL;
@@ -2768,6 +2807,8 @@ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
return result;
}
+EXPORT_SYMBOL(snd_pcm_kernel_ioctl);
+
static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count,
loff_t * offset)
{
@@ -3134,7 +3175,7 @@ static int snd_pcm_default_mmap(struct snd_pcm_substream *substream,
area->vm_ops = &snd_pcm_vm_ops_data;
area->vm_private_data = substream;
area->vm_flags |= VM_RESERVED;
- atomic_inc(&substream->runtime->mmap_count);
+ atomic_inc(&substream->mmap_count);
return 0;
}
@@ -3166,9 +3207,11 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
(substream->runtime->dma_addr + offset) >> PAGE_SHIFT,
size, area->vm_page_prot))
return -EAGAIN;
- atomic_inc(&substream->runtime->mmap_count);
+ atomic_inc(&substream->mmap_count);
return 0;
}
+
+EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);
#endif /* SNDRV_PCM_INFO_MMAP */
/*
@@ -3212,6 +3255,8 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file,
return snd_pcm_default_mmap(substream, area);
}
+EXPORT_SYMBOL(snd_pcm_mmap_data);
+
static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
{
struct snd_pcm_file * pcm_file;
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 87b47c9..8c15c66 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -43,7 +43,7 @@ MODULE_DESCRIPTION("Midlevel RawMidi code for ALSA.");
MODULE_LICENSE("GPL");
#ifdef CONFIG_SND_OSSEMUL
-static int midi_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 0};
+static int midi_map[SNDRV_CARDS];
static int amidi_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
module_param_array(midi_map, int, NULL, 0444);
MODULE_PARM_DESC(midi_map, "Raw MIDI device number assigned to 1st OSS device.");
@@ -1561,7 +1561,6 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
entry = snd_info_create_card_entry(rmidi->card, name, rmidi->card->proc_root);
if (entry) {
entry->private_data = rmidi;
- entry->c.text.read_size = 1024;
entry->c.text.read = snd_rawmidi_proc_info_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
index b991978..e723413 100644
--- a/sound/core/seq/oss/seq_oss.c
+++ b/sound/core/seq/oss/seq_oss.c
@@ -291,7 +291,6 @@ register_proc(void)
entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->private_data = NULL;
- entry->c.text.read_size = 1024;
entry->c.text.read = info_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c
index 20f954b..2f0d877 100644
--- a/sound/core/seq/seq.c
+++ b/sound/core/seq/seq.c
@@ -129,25 +129,3 @@ static void __exit alsa_seq_exit(void)
module_init(alsa_seq_init)
module_exit(alsa_seq_exit)
-
- /* seq_clientmgr.c */
-EXPORT_SYMBOL(snd_seq_create_kernel_client);
-EXPORT_SYMBOL(snd_seq_delete_kernel_client);
-EXPORT_SYMBOL(snd_seq_kernel_client_enqueue);
-EXPORT_SYMBOL(snd_seq_kernel_client_enqueue_blocking);
-EXPORT_SYMBOL(snd_seq_kernel_client_dispatch);
-EXPORT_SYMBOL(snd_seq_kernel_client_ctl);
-EXPORT_SYMBOL(snd_seq_kernel_client_write_poll);
-EXPORT_SYMBOL(snd_seq_set_queue_tempo);
- /* seq_memory.c */
-EXPORT_SYMBOL(snd_seq_expand_var_event);
-EXPORT_SYMBOL(snd_seq_dump_var_event);
- /* seq_ports.c */
-EXPORT_SYMBOL(snd_seq_event_port_attach);
-EXPORT_SYMBOL(snd_seq_event_port_detach);
- /* seq_lock.c */
-#if defined(CONFIG_SMP) || defined(CONFIG_SND_DEBUG)
-/*EXPORT_SYMBOL(snd_seq_sleep_in_lock);*/
-/*EXPORT_SYMBOL(snd_seq_sleep_timeout_in_lock);*/
-EXPORT_SYMBOL(snd_use_lock_sync_helper);
-#endif
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index bb15d9e..532a660 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1714,6 +1714,8 @@ int snd_seq_set_queue_tempo(int client, struct snd_seq_queue_tempo *tempo)
return snd_seq_queue_timer_set_tempo(tempo->queue, client, tempo);
}
+EXPORT_SYMBOL(snd_seq_set_queue_tempo);
+
static int snd_seq_ioctl_set_queue_tempo(struct snd_seq_client *client,
void __user *arg)
{
@@ -2264,6 +2266,8 @@ int snd_seq_create_kernel_client(struct snd_card *card, int client_index,
return client->number;
}
+EXPORT_SYMBOL(snd_seq_create_kernel_client);
+
/* exported to kernel modules */
int snd_seq_delete_kernel_client(int client)
{
@@ -2280,6 +2284,7 @@ int snd_seq_delete_kernel_client(int client)
return 0;
}
+EXPORT_SYMBOL(snd_seq_delete_kernel_client);
/* skeleton to enqueue event, called from snd_seq_kernel_client_enqueue
* and snd_seq_kernel_client_enqueue_blocking
@@ -2328,6 +2333,8 @@ int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event * ev,
return kernel_client_enqueue(client, ev, NULL, 0, atomic, hop);
}
+EXPORT_SYMBOL(snd_seq_kernel_client_enqueue);
+
/*
* exported, called by kernel clients to enqueue events (with blocking)
*
@@ -2340,6 +2347,7 @@ int snd_seq_kernel_client_enqueue_blocking(int client, struct snd_seq_event * ev
return kernel_client_enqueue(client, ev, file, 1, atomic, hop);
}
+EXPORT_SYMBOL(snd_seq_kernel_client_enqueue_blocking);
/*
* exported, called by kernel clients to dispatch events directly to other
@@ -2376,6 +2384,7 @@ int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event * ev,
return result;
}
+EXPORT_SYMBOL(snd_seq_kernel_client_dispatch);
/*
* exported, called by kernel clients to perform same functions as with
@@ -2396,6 +2405,7 @@ int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg)
return result;
}
+EXPORT_SYMBOL(snd_seq_kernel_client_ctl);
/* exported (for OSS emulator) */
int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table *wait)
@@ -2413,6 +2423,8 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table
return 0;
}
+EXPORT_SYMBOL(snd_seq_kernel_client_write_poll);
+
/*---------------------------------------------------------------------------*/
#ifdef CONFIG_PROC_FS
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
index d9a3e5a..d812dc8 100644
--- a/sound/core/seq/seq_device.c
+++ b/sound/core/seq/seq_device.c
@@ -80,7 +80,7 @@ static LIST_HEAD(opslist);
static int num_ops;
static DEFINE_MUTEX(ops_mutex);
#ifdef CONFIG_PROC_FS
-static struct snd_info_entry *info_entry = NULL;
+static struct snd_info_entry *info_entry;
#endif
/*
@@ -555,7 +555,6 @@ static int __init alsa_seq_device_init(void)
if (info_entry == NULL)
return -ENOMEM;
info_entry->content = SNDRV_INFO_CONTENT_TEXT;
- info_entry->c.text.read_size = 2048;
info_entry->c.text.read = snd_seq_device_info;
if (snd_info_register(info_entry) < 0) {
snd_info_free_entry(info_entry);
diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c
index 2a283a5..e55488d 100644
--- a/sound/core/seq/seq_dummy.c
+++ b/sound/core/seq/seq_dummy.c
@@ -66,7 +66,7 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS("snd-seq-client-" __stringify(SNDRV_SEQ_CLIENT_DUMMY));
static int ports = 1;
-static int duplex = 0;
+static int duplex;
module_param(ports, int, 0444);
MODULE_PARM_DESC(ports, "number of ports to be created");
@@ -171,7 +171,9 @@ create_port(int idx, int type)
pinfo.capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
if (duplex)
pinfo.capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
- pinfo.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
+ pinfo.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
+ | SNDRV_SEQ_PORT_TYPE_SOFTWARE
+ | SNDRV_SEQ_PORT_TYPE_PORT;
memset(&pcb, 0, sizeof(pcb));
pcb.owner = THIS_MODULE;
pcb.unuse = dummy_unuse;
diff --git a/sound/core/seq/seq_info.c b/sound/core/seq/seq_info.c
index acce21a..142e9e6 100644
--- a/sound/core/seq/seq_info.c
+++ b/sound/core/seq/seq_info.c
@@ -34,8 +34,8 @@ static struct snd_info_entry *timer_entry;
static struct snd_info_entry * __init
-create_info_entry(char *name, int size, void (*read)(struct snd_info_entry *,
- struct snd_info_buffer *))
+create_info_entry(char *name, void (*read)(struct snd_info_entry *,
+ struct snd_info_buffer *))
{
struct snd_info_entry *entry;
@@ -43,7 +43,6 @@ create_info_entry(char *name, int size, void (*read)(struct snd_info_entry *,
if (entry == NULL)
return NULL;
entry->content = SNDRV_INFO_CONTENT_TEXT;
- entry->c.text.read_size = size;
entry->c.text.read = read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
@@ -55,11 +54,11 @@ create_info_entry(char *name, int size, void (*read)(struct snd_info_entry *,
/* create all our /proc entries */
int __init snd_seq_info_init(void)
{
- queues_entry = create_info_entry("queues", 512 + (256 * SNDRV_SEQ_MAX_QUEUES),
+ queues_entry = create_info_entry("queues",
snd_seq_info_queues_read);
- clients_entry = create_info_entry("clients", 512 + (256 * SNDRV_SEQ_MAX_CLIENTS),
+ clients_entry = create_info_entry("clients",
snd_seq_info_clients_read);
- timer_entry = create_info_entry("timer", 1024, snd_seq_info_timer_read);
+ timer_entry = create_info_entry("timer", snd_seq_info_timer_read);
return 0;
}
diff --git a/sound/core/seq/seq_lock.c b/sound/core/seq/seq_lock.c
index a837a94..1a34941 100644
--- a/sound/core/seq/seq_lock.c
+++ b/sound/core/seq/seq_lock.c
@@ -44,4 +44,6 @@ void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line)
}
}
+EXPORT_SYMBOL(snd_use_lock_sync_helper);
+
#endif
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index 40b4f67..4bffe50 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -118,6 +118,8 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event,
return 0;
}
+EXPORT_SYMBOL(snd_seq_dump_var_event);
+
/*
* exported:
@@ -167,6 +169,7 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char
return err < 0 ? err : newlen;
}
+EXPORT_SYMBOL(snd_seq_expand_var_event);
/*
* release this cell, free extended data if available
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c
index 9caa137..1daa5b0 100644
--- a/sound/core/seq/seq_midi.c
+++ b/sound/core/seq/seq_midi.c
@@ -278,6 +278,7 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev)
struct seq_midisynth *msynth, *ms;
struct snd_seq_port_info *port;
struct snd_rawmidi_info *info;
+ struct snd_rawmidi *rmidi = dev->private_data;
int newclient = 0;
unsigned int p, ports;
struct snd_seq_port_callback pcallbacks;
@@ -320,8 +321,8 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev)
}
client->seq_client =
snd_seq_create_kernel_client(
- card, 0, "%s", info->name[0] ?
- (const char *)info->name : "External MIDI");
+ card, 0, "%s", card->shortname[0] ?
+ (const char *)card->shortname : "External MIDI");
if (client->seq_client < 0) {
kfree(client);
mutex_unlock(&register_mutex);
@@ -376,7 +377,9 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev)
if ((port->capability & (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ)) == (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ) &&
info->flags & SNDRV_RAWMIDI_INFO_DUPLEX)
port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
- port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
+ port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
+ | SNDRV_SEQ_PORT_TYPE_HARDWARE
+ | SNDRV_SEQ_PORT_TYPE_PORT;
port->midi_channels = 16;
memset(&pcallbacks, 0, sizeof(pcallbacks));
pcallbacks.owner = THIS_MODULE;
@@ -387,6 +390,8 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev)
pcallbacks.unuse = midisynth_unuse;
pcallbacks.event_input = event_process_midi;
port->kernel = &pcallbacks;
+ if (rmidi->ops && rmidi->ops->get_port_info)
+ rmidi->ops->get_port_info(rmidi, p, port);
if (snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_CREATE_PORT, port)<0)
goto __nomem;
ms->seq_client = client->seq_client;
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index 41e078c..334579a9 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -221,7 +221,6 @@ static void clear_subscriber_list(struct snd_seq_client *client,
{
struct list_head *p, *n;
- down_write(&grp->list_mutex);
list_for_each_safe(p, n, &grp->list_head) {
struct snd_seq_subscribers *subs;
struct snd_seq_client *c;
@@ -259,7 +258,6 @@ static void clear_subscriber_list(struct snd_seq_client *client,
snd_seq_client_unlock(c);
}
}
- up_write(&grp->list_mutex);
}
/* delete port data */
@@ -677,6 +675,7 @@ int snd_seq_event_port_attach(int client,
return ret;
}
+EXPORT_SYMBOL(snd_seq_event_port_attach);
/*
* Detach the driver from a port.
@@ -696,3 +695,5 @@ int snd_seq_event_port_detach(int client, int port)
return err;
}
+
+EXPORT_SYMBOL(snd_seq_event_port_detach);
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
index f4edec6..0cfa06c 100644
--- a/sound/core/seq/seq_virmidi.c
+++ b/sound/core/seq/seq_virmidi.c
@@ -390,7 +390,9 @@ static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev)
pinfo->capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
pinfo->capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
pinfo->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
- pinfo->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
+ pinfo->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
+ | SNDRV_SEQ_PORT_TYPE_SOFTWARE
+ | SNDRV_SEQ_PORT_TYPE_PORT;
pinfo->midi_channels = 16;
memset(&pcallbacks, 0, sizeof(pcallbacks));
pcallbacks.owner = THIS_MODULE;
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 108e430..cd86272 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -39,6 +39,8 @@
static int major = CONFIG_SND_MAJOR;
int snd_major;
+EXPORT_SYMBOL(snd_major);
+
static int cards_limit = 1;
static int device_mode = S_IFCHR | S_IRUGO | S_IWUGO;
@@ -60,6 +62,7 @@ MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR);
* modules are loaded manually, this limit number increases, too.
*/
int snd_ecards_limit;
+EXPORT_SYMBOL(snd_ecards_limit);
static struct snd_minor *snd_minors[SNDRV_OS_MINORS];
static DEFINE_MUTEX(sound_mutex);
@@ -78,20 +81,17 @@ extern struct class *sound_class;
*/
void snd_request_card(int card)
{
- int locked;
-
if (! current->fs->root)
return;
- read_lock(&snd_card_rwlock);
- locked = snd_cards_lock & (1 << card);
- read_unlock(&snd_card_rwlock);
- if (locked)
+ if (snd_card_locked(card))
return;
if (card < 0 || card >= cards_limit)
return;
request_module("snd-card-%i", card);
}
+EXPORT_SYMBOL(snd_request_card);
+
static void snd_request_other(int minor)
{
char *str;
@@ -133,6 +133,8 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
return private_data;
}
+EXPORT_SYMBOL(snd_lookup_minor_data);
+
static int snd_open(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
@@ -281,6 +283,8 @@ int snd_register_device(int type, struct snd_card *card, int dev,
return 0;
}
+EXPORT_SYMBOL(snd_register_device);
+
/**
* snd_unregister_device - unregister the device on the given card
* @type: the device type, SNDRV_DEVICE_TYPE_XXX
@@ -321,12 +325,14 @@ int snd_unregister_device(int type, struct snd_card *card, int dev)
return 0;
}
+EXPORT_SYMBOL(snd_unregister_device);
+
#ifdef CONFIG_PROC_FS
/*
* INFO PART
*/
-static struct snd_info_entry *snd_minor_info_entry = NULL;
+static struct snd_info_entry *snd_minor_info_entry;
static const char *snd_device_type_name(int type)
{
@@ -381,7 +387,6 @@ int __init snd_minor_info_init(void)
entry = snd_info_create_module_entry(THIS_MODULE, "devices", NULL);
if (entry) {
- entry->c.text.read_size = PAGE_SIZE;
entry->c.text.read = snd_minor_info_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
@@ -446,91 +451,3 @@ static void __exit alsa_sound_exit(void)
module_init(alsa_sound_init)
module_exit(alsa_sound_exit)
-
- /* sound.c */
-EXPORT_SYMBOL(snd_major);
-EXPORT_SYMBOL(snd_ecards_limit);
-#if defined(CONFIG_KMOD)
-EXPORT_SYMBOL(snd_request_card);
-#endif
-EXPORT_SYMBOL(snd_register_device);
-EXPORT_SYMBOL(snd_unregister_device);
-EXPORT_SYMBOL(snd_lookup_minor_data);
-#if defined(CONFIG_SND_OSSEMUL)
-EXPORT_SYMBOL(snd_register_oss_device);
-EXPORT_SYMBOL(snd_unregister_oss_device);
-EXPORT_SYMBOL(snd_lookup_oss_minor_data);
-#endif
- /* memory.c */
-EXPORT_SYMBOL(copy_to_user_fromio);
-EXPORT_SYMBOL(copy_from_user_toio);
- /* init.c */
-EXPORT_SYMBOL(snd_cards);
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
-EXPORT_SYMBOL(snd_mixer_oss_notify_callback);
-#endif
-EXPORT_SYMBOL(snd_card_new);
-EXPORT_SYMBOL(snd_card_disconnect);
-EXPORT_SYMBOL(snd_card_free);
-EXPORT_SYMBOL(snd_card_free_in_thread);
-EXPORT_SYMBOL(snd_card_register);
-EXPORT_SYMBOL(snd_component_add);
-EXPORT_SYMBOL(snd_card_file_add);
-EXPORT_SYMBOL(snd_card_file_remove);
-#ifdef CONFIG_PM
-EXPORT_SYMBOL(snd_power_wait);
-#endif
- /* device.c */
-EXPORT_SYMBOL(snd_device_new);
-EXPORT_SYMBOL(snd_device_register);
-EXPORT_SYMBOL(snd_device_free);
- /* isadma.c */
-#ifdef CONFIG_ISA_DMA_API
-EXPORT_SYMBOL(snd_dma_program);
-EXPORT_SYMBOL(snd_dma_disable);
-EXPORT_SYMBOL(snd_dma_pointer);
-#endif
- /* info.c */
-#ifdef CONFIG_PROC_FS
-EXPORT_SYMBOL(snd_seq_root);
-EXPORT_SYMBOL(snd_iprintf);
-EXPORT_SYMBOL(snd_info_get_line);
-EXPORT_SYMBOL(snd_info_get_str);
-EXPORT_SYMBOL(snd_info_create_module_entry);
-EXPORT_SYMBOL(snd_info_create_card_entry);
-EXPORT_SYMBOL(snd_info_free_entry);
-EXPORT_SYMBOL(snd_info_register);
-EXPORT_SYMBOL(snd_info_unregister);
-EXPORT_SYMBOL(snd_card_proc_new);
-#endif
- /* info_oss.c */
-#if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
-EXPORT_SYMBOL(snd_oss_info_register);
-#endif
- /* control.c */
-EXPORT_SYMBOL(snd_ctl_new);
-EXPORT_SYMBOL(snd_ctl_new1);
-EXPORT_SYMBOL(snd_ctl_free_one);
-EXPORT_SYMBOL(snd_ctl_add);
-EXPORT_SYMBOL(snd_ctl_remove);
-EXPORT_SYMBOL(snd_ctl_remove_id);
-EXPORT_SYMBOL(snd_ctl_rename_id);
-EXPORT_SYMBOL(snd_ctl_find_numid);
-EXPORT_SYMBOL(snd_ctl_find_id);
-EXPORT_SYMBOL(snd_ctl_notify);
-EXPORT_SYMBOL(snd_ctl_register_ioctl);
-EXPORT_SYMBOL(snd_ctl_unregister_ioctl);
-#ifdef CONFIG_COMPAT
-EXPORT_SYMBOL(snd_ctl_register_ioctl_compat);
-EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat);
-#endif
-EXPORT_SYMBOL(snd_ctl_elem_read);
-EXPORT_SYMBOL(snd_ctl_elem_write);
- /* misc.c */
-EXPORT_SYMBOL(release_and_free_resource);
-#ifdef CONFIG_SND_VERBOSE_PRINTK
-EXPORT_SYMBOL(snd_verbose_printk);
-#endif
-#if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK)
-EXPORT_SYMBOL(snd_verbose_printd);
-#endif
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c
index 9055c6d..74f0fe5 100644
--- a/sound/core/sound_oss.c
+++ b/sound/core/sound_oss.c
@@ -58,6 +58,8 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type)
return private_data;
}
+EXPORT_SYMBOL(snd_lookup_oss_minor_data);
+
static int snd_oss_kernel_minor(int type, struct snd_card *card, int dev)
{
int minor;
@@ -158,6 +160,8 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,
return -EBUSY;
}
+EXPORT_SYMBOL(snd_register_oss_device);
+
int snd_unregister_oss_device(int type, struct snd_card *card, int dev)
{
int minor = snd_oss_kernel_minor(type, card, dev);
@@ -197,13 +201,15 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev)
return 0;
}
+EXPORT_SYMBOL(snd_unregister_oss_device);
+
/*
* INFO PART
*/
#ifdef CONFIG_PROC_FS
-static struct snd_info_entry *snd_minor_info_oss_entry = NULL;
+static struct snd_info_entry *snd_minor_info_oss_entry;
static const char *snd_oss_device_type_name(int type)
{
@@ -252,7 +258,6 @@ int __init snd_minor_info_oss_init(void)
entry = snd_info_create_module_entry(THIS_MODULE, "devices", snd_oss_root);
if (entry) {
- entry->c.text.read_size = PAGE_SIZE;
entry->c.text.read = snd_minor_info_oss_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
diff --git a/sound/core/timer.c b/sound/core/timer.c
index cdeeb63..78199f5 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -1061,7 +1061,6 @@ static int snd_timer_register_system(void)
static void snd_timer_proc_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
- unsigned long flags;
struct snd_timer *timer;
struct snd_timer_instance *ti;
struct list_head *p, *q;
@@ -1095,7 +1094,6 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
snd_iprintf(buffer, " SLAVE");
snd_iprintf(buffer, "\n");
- spin_lock_irqsave(&timer->lock, flags);
list_for_each(q, &timer->open_list_head) {
ti = list_entry(q, struct snd_timer_instance, open_list);
snd_iprintf(buffer, " Client %s : %s\n",
@@ -1104,12 +1102,11 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
SNDRV_TIMER_IFLG_RUNNING)
? "running" : "stopped");
}
- spin_unlock_irqrestore(&timer->lock, flags);
}
mutex_unlock(&register_mutex);
}
-static struct snd_info_entry *snd_timer_proc_entry = NULL;
+static struct snd_info_entry *snd_timer_proc_entry;
static void __init snd_timer_proc_init(void)
{
@@ -1117,7 +1114,6 @@ static void __init snd_timer_proc_init(void)
entry = snd_info_create_module_entry(THIS_MODULE, "timers", NULL);
if (entry != NULL) {
- entry->c.text.read_size = SNDRV_TIMER_DEVICES * 128;
entry->c.text.read = snd_timer_proc_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index ae0df54..ffeafaf 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -677,6 +677,10 @@ static int __init alsa_card_dummy_init(void)
i, NULL, 0);
if (IS_ERR(device))
continue;
+ if (!platform_get_drvdata(device)) {
+ platform_device_unregister(device);
+ continue;
+ }
devices[i] = device;
cards++;
}
diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c
index 77b0600..d3cbbb0 100644
--- a/sound/drivers/mpu401/mpu401.c
+++ b/sound/drivers/mpu401/mpu401.c
@@ -253,6 +253,10 @@ static int __init alsa_card_mpu401_init(void)
i, NULL, 0);
if (IS_ERR(device))
continue;
+ if (!platform_get_drvdata(device)) {
+ platform_device_unregister(device);
+ continue;
+ }
platform_devices[i] = device;
snd_mpu401_devices++;
}
diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c
index b49a45c..4bf07ca 100644
--- a/sound/drivers/mpu401/mpu401_uart.c
+++ b/sound/drivers/mpu401/mpu401_uart.c
@@ -58,22 +58,26 @@ static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu);
#define MPU401_ACK 0xfe
/* Build in lowlevel io */
-static void mpu401_write_port(struct snd_mpu401 *mpu, unsigned char data, unsigned long addr)
+static void mpu401_write_port(struct snd_mpu401 *mpu, unsigned char data,
+ unsigned long addr)
{
outb(data, addr);
}
-static unsigned char mpu401_read_port(struct snd_mpu401 *mpu, unsigned long addr)
+static unsigned char mpu401_read_port(struct snd_mpu401 *mpu,
+ unsigned long addr)
{
return inb(addr);
}
-static void mpu401_write_mmio(struct snd_mpu401 *mpu, unsigned char data, unsigned long addr)
+static void mpu401_write_mmio(struct snd_mpu401 *mpu, unsigned char data,
+ unsigned long addr)
{
writeb(data, (void __iomem *)addr);
}
-static unsigned char mpu401_read_mmio(struct snd_mpu401 *mpu, unsigned long addr)
+static unsigned char mpu401_read_mmio(struct snd_mpu401 *mpu,
+ unsigned long addr)
{
return readb((void __iomem *)addr);
}
@@ -86,20 +90,13 @@ static void snd_mpu401_uart_clear_rx(struct snd_mpu401 *mpu)
mpu->read(mpu, MPU401D(mpu));
#ifdef CONFIG_SND_DEBUG
if (timeout <= 0)
- snd_printk("cmd: clear rx timeout (status = 0x%x)\n", mpu->read(mpu, MPU401C(mpu)));
+ snd_printk(KERN_ERR "cmd: clear rx timeout (status = 0x%x)\n",
+ mpu->read(mpu, MPU401C(mpu)));
#endif
}
-static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu)
+static void uart_interrupt_tx(struct snd_mpu401 *mpu)
{
- spin_lock(&mpu->input_lock);
- if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) {
- snd_mpu401_uart_input_read(mpu);
- } else {
- snd_mpu401_uart_clear_rx(mpu);
- }
- spin_unlock(&mpu->input_lock);
- /* ok. for better Tx performance try do some output when input is done */
if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode) &&
test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode)) {
spin_lock(&mpu->output_lock);
@@ -108,6 +105,22 @@ static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu)
}
}
+static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu)
+{
+ if (mpu->info_flags & MPU401_INFO_INPUT) {
+ spin_lock(&mpu->input_lock);
+ if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode))
+ snd_mpu401_uart_input_read(mpu);
+ else
+ snd_mpu401_uart_clear_rx(mpu);
+ spin_unlock(&mpu->input_lock);
+ }
+ if (! (mpu->info_flags & MPU401_INFO_TX_IRQ))
+ /* ok. for better Tx performance try do some output
+ when input is done */
+ uart_interrupt_tx(mpu);
+}
+
/**
* snd_mpu401_uart_interrupt - generic MPU401-UART interrupt handler
* @irq: the irq number
@@ -116,7 +129,8 @@ static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu)
*
* Processes the interrupt for MPU401-UART i/o.
*/
-irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
{
struct snd_mpu401 *mpu = dev_id;
@@ -126,6 +140,29 @@ irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, struct pt_regs *reg
return IRQ_HANDLED;
}
+EXPORT_SYMBOL(snd_mpu401_uart_interrupt);
+
+/**
+ * snd_mpu401_uart_interrupt_tx - generic MPU401-UART transmit irq handler
+ * @irq: the irq number
+ * @dev_id: mpu401 instance
+ * @regs: the reigster
+ *
+ * Processes the interrupt for MPU401-UART output.
+ */
+irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ struct snd_mpu401 *mpu = dev_id;
+
+ if (mpu == NULL)
+ return IRQ_NONE;
+ uart_interrupt_tx(mpu);
+ return IRQ_HANDLED;
+}
+
+EXPORT_SYMBOL(snd_mpu401_uart_interrupt_tx);
+
/*
* timer callback
* reprogram the timer and call the interrupt job
@@ -159,7 +196,8 @@ static void snd_mpu401_uart_add_timer (struct snd_mpu401 *mpu, int input)
mpu->timer.expires = 1 + jiffies;
add_timer(&mpu->timer);
}
- mpu->timer_invoked |= input ? MPU401_MODE_INPUT_TIMER : MPU401_MODE_OUTPUT_TIMER;
+ mpu->timer_invoked |= input ? MPU401_MODE_INPUT_TIMER :
+ MPU401_MODE_OUTPUT_TIMER;
spin_unlock_irqrestore (&mpu->timer_lock, flags);
}
@@ -172,7 +210,8 @@ static void snd_mpu401_uart_remove_timer (struct snd_mpu401 *mpu, int input)
spin_lock_irqsave (&mpu->timer_lock, flags);
if (mpu->timer_invoked) {
- mpu->timer_invoked &= input ? ~MPU401_MODE_INPUT_TIMER : ~MPU401_MODE_OUTPUT_TIMER;
+ mpu->timer_invoked &= input ? ~MPU401_MODE_INPUT_TIMER :
+ ~MPU401_MODE_OUTPUT_TIMER;
if (! mpu->timer_invoked)
del_timer(&mpu->timer);
}
@@ -180,11 +219,12 @@ static void snd_mpu401_uart_remove_timer (struct snd_mpu401 *mpu, int input)
}
/*
-
+ * send a UART command
+ * return zero if successful, non-zero for some errors
*/
static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd,
- int ack)
+ int ack)
{
unsigned long flags;
int timeout, ok;
@@ -196,11 +236,13 @@ static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd,
}
/* ok. standard MPU-401 initialization */
if (mpu->hardware != MPU401_HW_SB) {
- for (timeout = 1000; timeout > 0 && !snd_mpu401_output_ready(mpu); timeout--)
+ for (timeout = 1000; timeout > 0 &&
+ !snd_mpu401_output_ready(mpu); timeout--)
udelay(10);
#ifdef CONFIG_SND_DEBUG
if (!timeout)
- snd_printk("cmd: tx timeout (status = 0x%x)\n", mpu->read(mpu, MPU401C(mpu)));
+ snd_printk(KERN_ERR "cmd: tx timeout (status = 0x%x)\n",
+ mpu->read(mpu, MPU401C(mpu)));
#endif
}
mpu->write(mpu, cmd, MPU401C(mpu));
@@ -215,12 +257,14 @@ static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd,
}
if (!ok && mpu->read(mpu, MPU401D(mpu)) == MPU401_ACK)
ok = 1;
- } else {
+ } else
ok = 1;
- }
spin_unlock_irqrestore(&mpu->input_lock, flags);
if (!ok) {
- snd_printk("cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)\n", cmd, mpu->port, mpu->read(mpu, MPU401C(mpu)), mpu->read(mpu, MPU401D(mpu)));
+ snd_printk(KERN_ERR "cmd: 0x%x failed at 0x%lx "
+ "(status = 0x%x, data = 0x%x)\n", cmd, mpu->port,
+ mpu->read(mpu, MPU401C(mpu)),
+ mpu->read(mpu, MPU401D(mpu)));
return 1;
}
return 0;
@@ -314,7 +358,8 @@ static int snd_mpu401_uart_output_close(struct snd_rawmidi_substream *substream)
/*
* trigger input callback
*/
-static void snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substream, int up)
+static void
+snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substream, int up)
{
unsigned long flags;
struct snd_mpu401 *mpu;
@@ -322,7 +367,8 @@ static void snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substrea
mpu = substream->rmidi->private_data;
if (up) {
- if (! test_and_set_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) {
+ if (! test_and_set_bit(MPU401_MODE_BIT_INPUT_TRIGGER,
+ &mpu->mode)) {
/* first time - flush FIFO */
while (max-- > 0)
mpu->read(mpu, MPU401D(mpu));
@@ -352,13 +398,11 @@ static void snd_mpu401_uart_input_read(struct snd_mpu401 * mpu)
unsigned char byte;
while (max-- > 0) {
- if (snd_mpu401_input_avail(mpu)) {
- byte = mpu->read(mpu, MPU401D(mpu));
- if (test_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode))
- snd_rawmidi_receive(mpu->substream_input, &byte, 1);
- } else {
+ if (! snd_mpu401_input_avail(mpu))
break; /* input not available */
- }
+ byte = mpu->read(mpu, MPU401D(mpu));
+ if (test_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode))
+ snd_rawmidi_receive(mpu->substream_input, &byte, 1);
}
}
@@ -380,16 +424,16 @@ static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu)
int max = 256, timeout;
do {
- if (snd_rawmidi_transmit_peek(mpu->substream_output, &byte, 1) == 1) {
+ if (snd_rawmidi_transmit_peek(mpu->substream_output,
+ &byte, 1) == 1) {
for (timeout = 100; timeout > 0; timeout--) {
- if (snd_mpu401_output_ready(mpu)) {
- mpu->write(mpu, byte, MPU401D(mpu));
- snd_rawmidi_transmit_ack(mpu->substream_output, 1);
+ if (snd_mpu401_output_ready(mpu))
break;
- }
}
if (timeout == 0)
break; /* Tx FIFO full - try again later */
+ mpu->write(mpu, byte, MPU401D(mpu));
+ snd_rawmidi_transmit_ack(mpu->substream_output, 1);
} else {
snd_mpu401_uart_remove_timer (mpu, 0);
break; /* no other data - leave the tx loop */
@@ -400,7 +444,8 @@ static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu)
/*
* output trigger callback
*/
-static void snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up)
+static void
+snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up)
{
unsigned long flags;
struct snd_mpu401 *mpu;
@@ -413,14 +458,16 @@ static void snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substre
* since the output timer might have been removed in
* snd_mpu401_uart_output_write().
*/
- snd_mpu401_uart_add_timer(mpu, 0);
+ if (! (mpu->info_flags & MPU401_INFO_TX_IRQ))
+ snd_mpu401_uart_add_timer(mpu, 0);
/* output pending data */
spin_lock_irqsave(&mpu->output_lock, flags);
snd_mpu401_uart_output_write(mpu);
spin_unlock_irqrestore(&mpu->output_lock, flags);
} else {
- snd_mpu401_uart_remove_timer(mpu, 0);
+ if (! (mpu->info_flags & MPU401_INFO_TX_IRQ))
+ snd_mpu401_uart_remove_timer(mpu, 0);
clear_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode);
}
}
@@ -458,7 +505,7 @@ static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi)
* @device: the device index, zero-based
* @hardware: the hardware type, MPU401_HW_XXXX
* @port: the base address of MPU401 port
- * @integrated: non-zero if the port was already reserved by the chip
+ * @info_flags: bitflags MPU401_INFO_XXX
* @irq: the irq number, -1 if no interrupt for mpu
* @irq_flags: the irq request flags (SA_XXX), 0 if irq was already reserved.
* @rrawmidi: the pointer to store the new rawmidi instance
@@ -473,17 +520,24 @@ static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi)
*/
int snd_mpu401_uart_new(struct snd_card *card, int device,
unsigned short hardware,
- unsigned long port, int integrated,
+ unsigned long port,
+ unsigned int info_flags,
int irq, int irq_flags,
struct snd_rawmidi ** rrawmidi)
{
struct snd_mpu401 *mpu;
struct snd_rawmidi *rmidi;
+ int in_enable, out_enable;
int err;
if (rrawmidi)
*rrawmidi = NULL;
- if ((err = snd_rawmidi_new(card, "MPU-401U", device, 1, 1, &rmidi)) < 0)
+ if (! (info_flags & (MPU401_INFO_INPUT | MPU401_INFO_OUTPUT)))
+ info_flags |= MPU401_INFO_INPUT | MPU401_INFO_OUTPUT;
+ in_enable = (info_flags & MPU401_INFO_INPUT) ? 1 : 0;
+ out_enable = (info_flags & MPU401_INFO_OUTPUT) ? 1 : 0;
+ if ((err = snd_rawmidi_new(card, "MPU-401U", device,
+ out_enable, in_enable, &rmidi)) < 0)
return err;
mpu = kzalloc(sizeof(*mpu), GFP_KERNEL);
if (mpu == NULL) {
@@ -497,23 +551,23 @@ int snd_mpu401_uart_new(struct snd_card *card, int device,
spin_lock_init(&mpu->output_lock);
spin_lock_init(&mpu->timer_lock);
mpu->hardware = hardware;
- if (!integrated) {
+ if (! (info_flags & MPU401_INFO_INTEGRATED)) {
int res_size = hardware == MPU401_HW_PC98II ? 4 : 2;
- if ((mpu->res = request_region(port, res_size, "MPU401 UART")) == NULL) {
- snd_printk(KERN_ERR "mpu401_uart: unable to grab port 0x%lx size %d\n", port, res_size);
+ mpu->res = request_region(port, res_size, "MPU401 UART");
+ if (mpu->res == NULL) {
+ snd_printk(KERN_ERR "mpu401_uart: "
+ "unable to grab port 0x%lx size %d\n",
+ port, res_size);
snd_device_free(card, rmidi);
return -EBUSY;
}
}
- switch (hardware) {
- case MPU401_HW_AUREAL:
+ if (info_flags & MPU401_INFO_MMIO) {
mpu->write = mpu401_write_mmio;
mpu->read = mpu401_read_mmio;
- break;
- default:
+ } else {
mpu->write = mpu401_write_port;
mpu->read = mpu401_read_port;
- break;
}
mpu->port = port;
if (hardware == MPU401_HW_PC98II)
@@ -521,30 +575,40 @@ int snd_mpu401_uart_new(struct snd_card *card, int device,
else
mpu->cport = port + 1;
if (irq >= 0 && irq_flags) {
- if (request_irq(irq, snd_mpu401_uart_interrupt, irq_flags, "MPU401 UART", (void *) mpu)) {
- snd_printk(KERN_ERR "mpu401_uart: unable to grab IRQ %d\n", irq);
+ if (request_irq(irq, snd_mpu401_uart_interrupt, irq_flags,
+ "MPU401 UART", (void *) mpu)) {
+ snd_printk(KERN_ERR "mpu401_uart: "
+ "unable to grab IRQ %d\n", irq);
snd_device_free(card, rmidi);
return -EBUSY;
}
}
+ mpu->info_flags = info_flags;
mpu->irq = irq;
mpu->irq_flags = irq_flags;
if (card->shortname[0])
- snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI", card->shortname);
+ snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI",
+ card->shortname);
else
- sprintf(rmidi->name, "MPU-401 MIDI %d-%d", card->number, device);
- snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_mpu401_uart_output);
- snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_mpu401_uart_input);
- rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
- SNDRV_RAWMIDI_INFO_INPUT |
- SNDRV_RAWMIDI_INFO_DUPLEX;
+ sprintf(rmidi->name, "MPU-401 MIDI %d-%d",card->number, device);
+ if (out_enable) {
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+ &snd_mpu401_uart_output);
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
+ }
+ if (in_enable) {
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+ &snd_mpu401_uart_input);
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
+ if (out_enable)
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
+ }
mpu->rmidi = rmidi;
if (rrawmidi)
*rrawmidi = rmidi;
return 0;
}
-EXPORT_SYMBOL(snd_mpu401_uart_interrupt);
EXPORT_SYMBOL(snd_mpu401_uart_new);
/*
diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c
index b7a0b42..474eed0 100644
--- a/sound/drivers/mtpav.c
+++ b/sound/drivers/mtpav.c
@@ -770,11 +770,15 @@ static int __init alsa_card_mtpav_init(void)
return err;
device = platform_device_register_simple(SND_MTPAV_DRIVER, -1, NULL, 0);
- if (IS_ERR(device)) {
- platform_driver_unregister(&snd_mtpav_driver);
- return PTR_ERR(device);
- }
- return 0;
+ if (!IS_ERR(device)) {
+ if (platform_get_drvdata(device))
+ return 0;
+ platform_device_unregister(device);
+ err = -ENODEV;
+ } else
+ err = PTR_ERR(device);
+ platform_driver_unregister(&snd_mtpav_driver);
+ return err;
}
static void __exit alsa_card_mtpav_exit(void)
diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c
index 4f85569..87fe376 100644
--- a/sound/drivers/opl3/opl3_lib.c
+++ b/sound/drivers/opl3/opl3_lib.c
@@ -316,6 +316,8 @@ void snd_opl3_interrupt(struct snd_hwdep * hw)
}
}
+EXPORT_SYMBOL(snd_opl3_interrupt);
+
/*
*/
@@ -369,6 +371,8 @@ int snd_opl3_new(struct snd_card *card,
return 0;
}
+EXPORT_SYMBOL(snd_opl3_new);
+
int snd_opl3_init(struct snd_opl3 *opl3)
{
if (! opl3->command) {
@@ -393,6 +397,8 @@ int snd_opl3_init(struct snd_opl3 *opl3)
return 0;
}
+EXPORT_SYMBOL(snd_opl3_init);
+
int snd_opl3_create(struct snd_card *card,
unsigned long l_port,
unsigned long r_port,
@@ -451,6 +457,8 @@ int snd_opl3_create(struct snd_card *card,
return 0;
}
+EXPORT_SYMBOL(snd_opl3_create);
+
int snd_opl3_timer_new(struct snd_opl3 * opl3, int timer1_dev, int timer2_dev)
{
int err;
@@ -468,6 +476,8 @@ int snd_opl3_timer_new(struct snd_opl3 * opl3, int timer1_dev, int timer2_dev)
return 0;
}
+EXPORT_SYMBOL(snd_opl3_timer_new);
+
int snd_opl3_hwdep_new(struct snd_opl3 * opl3,
int device, int seq_device,
struct snd_hwdep ** rhwdep)
@@ -526,17 +536,8 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3,
return 0;
}
-EXPORT_SYMBOL(snd_opl3_interrupt);
-EXPORT_SYMBOL(snd_opl3_new);
-EXPORT_SYMBOL(snd_opl3_init);
-EXPORT_SYMBOL(snd_opl3_create);
-EXPORT_SYMBOL(snd_opl3_timer_new);
EXPORT_SYMBOL(snd_opl3_hwdep_new);
-/* opl3_synth.c */
-EXPORT_SYMBOL(snd_opl3_regmap);
-EXPORT_SYMBOL(snd_opl3_reset);
-
/*
* INIT part
*/
diff --git a/sound/drivers/opl3/opl3_oss.c b/sound/drivers/opl3/opl3_oss.c
index fccf019..5fd3a4c 100644
--- a/sound/drivers/opl3/opl3_oss.c
+++ b/sound/drivers/opl3/opl3_oss.c
@@ -100,7 +100,8 @@ static int snd_opl3_oss_create_port(struct snd_opl3 * opl3)
SNDRV_SEQ_PORT_CAP_WRITE,
SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
SNDRV_SEQ_PORT_TYPE_MIDI_GM |
- SNDRV_SEQ_PORT_TYPE_SYNTH,
+ SNDRV_SEQ_PORT_TYPE_HARDWARE |
+ SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
voices, voices,
name);
if (opl3->oss_chset->port < 0) {
diff --git a/sound/drivers/opl3/opl3_seq.c b/sound/drivers/opl3/opl3_seq.c
index 57becf3..96762c9 100644
--- a/sound/drivers/opl3/opl3_seq.c
+++ b/sound/drivers/opl3/opl3_seq.c
@@ -203,7 +203,9 @@ static int snd_opl3_synth_create_port(struct snd_opl3 * opl3)
SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
SNDRV_SEQ_PORT_TYPE_MIDI_GM |
- SNDRV_SEQ_PORT_TYPE_SYNTH,
+ SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE |
+ SNDRV_SEQ_PORT_TYPE_HARDWARE |
+ SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
16, voices,
name);
if (opl3->chset->port < 0) {
diff --git a/sound/drivers/opl3/opl3_synth.c b/sound/drivers/opl3/opl3_synth.c
index 6db503f..a4b3543 100644
--- a/sound/drivers/opl3/opl3_synth.c
+++ b/sound/drivers/opl3/opl3_synth.c
@@ -58,6 +58,8 @@ char snd_opl3_regmap[MAX_OPL2_VOICES][4] =
{ 0x12, 0x15, 0x00, 0x00 } /* is selected (only left reg block) */
};
+EXPORT_SYMBOL(snd_opl3_regmap);
+
/*
* prototypes
*/
@@ -228,6 +230,7 @@ void snd_opl3_reset(struct snd_opl3 * opl3)
opl3->rhythm = 0;
}
+EXPORT_SYMBOL(snd_opl3_reset);
static int snd_opl3_play_note(struct snd_opl3 * opl3, struct snd_dm_fm_note * note)
{
@@ -445,3 +448,4 @@ static int snd_opl3_set_connection(struct snd_opl3 * opl3, int connection)
return 0;
}
+
diff --git a/sound/drivers/opl4/opl4_lib.c b/sound/drivers/opl4/opl4_lib.c
index 4bc860a..01997f2 100644
--- a/sound/drivers/opl4/opl4_lib.c
+++ b/sound/drivers/opl4/opl4_lib.c
@@ -43,6 +43,8 @@ void snd_opl4_write(struct snd_opl4 *opl4, u8 reg, u8 value)
outb(value, opl4->pcm_port + 1);
}
+EXPORT_SYMBOL(snd_opl4_write);
+
u8 snd_opl4_read(struct snd_opl4 *opl4, u8 reg)
{
snd_opl4_wait(opl4);
@@ -52,6 +54,8 @@ u8 snd_opl4_read(struct snd_opl4 *opl4, u8 reg)
return inb(opl4->pcm_port + 1);
}
+EXPORT_SYMBOL(snd_opl4_read);
+
void snd_opl4_read_memory(struct snd_opl4 *opl4, char *buf, int offset, int size)
{
unsigned long flags;
@@ -76,6 +80,8 @@ void snd_opl4_read_memory(struct snd_opl4 *opl4, char *buf, int offset, int size
spin_unlock_irqrestore(&opl4->reg_lock, flags);
}
+EXPORT_SYMBOL(snd_opl4_read_memory);
+
void snd_opl4_write_memory(struct snd_opl4 *opl4, const char *buf, int offset, int size)
{
unsigned long flags;
@@ -100,6 +106,8 @@ void snd_opl4_write_memory(struct snd_opl4 *opl4, const char *buf, int offset, i
spin_unlock_irqrestore(&opl4->reg_lock, flags);
}
+EXPORT_SYMBOL(snd_opl4_write_memory);
+
static void snd_opl4_enable_opl4(struct snd_opl4 *opl4)
{
outb(OPL3_REG_MODE, opl4->fm_port + 2);
@@ -256,10 +264,6 @@ int snd_opl4_create(struct snd_card *card,
return 0;
}
-EXPORT_SYMBOL(snd_opl4_write);
-EXPORT_SYMBOL(snd_opl4_read);
-EXPORT_SYMBOL(snd_opl4_write_memory);
-EXPORT_SYMBOL(snd_opl4_read_memory);
EXPORT_SYMBOL(snd_opl4_create);
static int __init alsa_opl4_init(void)
diff --git a/sound/drivers/opl4/opl4_seq.c b/sound/drivers/opl4/opl4_seq.c
index dc0dcdc..43d8a2b 100644
--- a/sound/drivers/opl4/opl4_seq.c
+++ b/sound/drivers/opl4/opl4_seq.c
@@ -164,7 +164,9 @@ static int snd_opl4_seq_new_device(struct snd_seq_device *dev)
SNDRV_SEQ_PORT_CAP_WRITE |
SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
- SNDRV_SEQ_PORT_TYPE_MIDI_GM,
+ SNDRV_SEQ_PORT_TYPE_MIDI_GM |
+ SNDRV_SEQ_PORT_TYPE_HARDWARE |
+ SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
16, 24,
"OPL4 Wavetable Port");
if (opl4->chset->port < 0) {
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
index c01b4c5..2330fec 100644
--- a/sound/drivers/serial-u16550.c
+++ b/sound/drivers/serial-u16550.c
@@ -998,6 +998,10 @@ static int __init alsa_card_serial_init(void)
i, NULL, 0);
if (IS_ERR(device))
continue;
+ if (!platform_get_drvdata(device)) {
+ platform_device_unregister(device);
+ continue;
+ }
devices[i] = device;
cards++;
}
diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c
index 26eb249..59171f8 100644
--- a/sound/drivers/virmidi.c
+++ b/sound/drivers/virmidi.c
@@ -171,6 +171,10 @@ static int __init alsa_card_virmidi_init(void)
i, NULL, 0);
if (IS_ERR(device))
continue;
+ if (!platform_get_drvdata(device)) {
+ platform_device_unregister(device);
+ continue;
+ }
devices[i] = device;
cards++;
}
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
index fa4a2b5..a601682 100644
--- a/sound/drivers/vx/vx_core.c
+++ b/sound/drivers/vx/vx_core.c
@@ -70,6 +70,8 @@ int snd_vx_check_reg_bit(struct vx_core *chip, int reg, int mask, int bit, int t
return -EIO;
}
+EXPORT_SYMBOL(snd_vx_check_reg_bit);
+
/*
* vx_send_irq_dsp - set command irq bit
* @num: the requested IRQ type, IRQ_XXX
@@ -465,6 +467,8 @@ int snd_vx_load_boot_image(struct vx_core *chip, const struct firmware *boot)
return 0;
}
+EXPORT_SYMBOL(snd_vx_load_boot_image);
+
/*
* vx_test_irq_src - query the source of interrupts
*
@@ -545,6 +549,7 @@ irqreturn_t snd_vx_irq_handler(int irq, void *dev, struct pt_regs *regs)
return IRQ_HANDLED;
}
+EXPORT_SYMBOL(snd_vx_irq_handler);
/*
*/
@@ -635,7 +640,7 @@ static void vx_proc_init(struct vx_core *chip)
struct snd_info_entry *entry;
if (! snd_card_proc_new(chip->card, "vx-status", &entry))
- snd_info_set_text_ops(entry, chip, 1024, vx_proc_read);
+ snd_info_set_text_ops(entry, chip, vx_proc_read);
}
@@ -657,6 +662,8 @@ int snd_vx_dsp_boot(struct vx_core *chip, const struct firmware *boot)
return 0;
}
+EXPORT_SYMBOL(snd_vx_dsp_boot);
+
/**
* snd_vx_dsp_load - load the DSP image
*/
@@ -705,6 +712,8 @@ int snd_vx_dsp_load(struct vx_core *chip, const struct firmware *dsp)
return 0;
}
+EXPORT_SYMBOL(snd_vx_dsp_load);
+
#ifdef CONFIG_PM
/*
* suspend
@@ -721,6 +730,8 @@ int snd_vx_suspend(struct vx_core *chip, pm_message_t state)
return 0;
}
+EXPORT_SYMBOL(snd_vx_suspend);
+
/*
* resume
*/
@@ -747,6 +758,7 @@ int snd_vx_resume(struct vx_core *chip)
return 0;
}
+EXPORT_SYMBOL(snd_vx_resume);
#endif
/**
@@ -790,6 +802,8 @@ struct vx_core *snd_vx_create(struct snd_card *card, struct snd_vx_hardware *hw,
return chip;
}
+EXPORT_SYMBOL(snd_vx_create);
+
/*
* module entries
*/
@@ -804,19 +818,3 @@ static void __exit alsa_vx_core_exit(void)
module_init(alsa_vx_core_init)
module_exit(alsa_vx_core_exit)
-
-/*
- * exports
- */
-EXPORT_SYMBOL(snd_vx_check_reg_bit);
-EXPORT_SYMBOL(snd_vx_create);
-EXPORT_SYMBOL(snd_vx_setup_firmware);
-EXPORT_SYMBOL(snd_vx_free_firmware);
-EXPORT_SYMBOL(snd_vx_irq_handler);
-EXPORT_SYMBOL(snd_vx_dsp_boot);
-EXPORT_SYMBOL(snd_vx_dsp_load);
-EXPORT_SYMBOL(snd_vx_load_boot_image);
-#ifdef CONFIG_PM
-EXPORT_SYMBOL(snd_vx_suspend);
-EXPORT_SYMBOL(snd_vx_resume);
-#endif
diff --git a/sound/drivers/vx/vx_hwdep.c b/sound/drivers/vx/vx_hwdep.c
index d837783..e1920af 100644
--- a/sound/drivers/vx/vx_hwdep.c
+++ b/sound/drivers/vx/vx_hwdep.c
@@ -250,3 +250,6 @@ void snd_vx_free_firmware(struct vx_core *chip)
}
#endif /* SND_VX_FW_LOADER */
+
+EXPORT_SYMBOL(snd_vx_setup_firmware);
+EXPORT_SYMBOL(snd_vx_free_firmware);
diff --git a/sound/i2c/i2c.c b/sound/i2c/i2c.c
index edfe76f..b60fb18 100644
--- a/sound/i2c/i2c.c
+++ b/sound/i2c/i2c.c
@@ -106,6 +106,8 @@ int snd_i2c_bus_create(struct snd_card *card, const char *name,
return 0;
}
+EXPORT_SYMBOL(snd_i2c_bus_create);
+
int snd_i2c_device_create(struct snd_i2c_bus *bus, const char *name,
unsigned char addr, struct snd_i2c_device **rdevice)
{
@@ -124,6 +126,8 @@ int snd_i2c_device_create(struct snd_i2c_bus *bus, const char *name,
return 0;
}
+EXPORT_SYMBOL(snd_i2c_device_create);
+
int snd_i2c_device_free(struct snd_i2c_device *device)
{
if (device->bus)
@@ -134,22 +138,29 @@ int snd_i2c_device_free(struct snd_i2c_device *device)
return 0;
}
+EXPORT_SYMBOL(snd_i2c_device_free);
+
int snd_i2c_sendbytes(struct snd_i2c_device *device, unsigned char *bytes, int count)
{
return device->bus->ops->sendbytes(device, bytes, count);
}
+EXPORT_SYMBOL(snd_i2c_sendbytes);
int snd_i2c_readbytes(struct snd_i2c_device *device, unsigned char *bytes, int count)
{
return device->bus->ops->readbytes(device, bytes, count);
}
+EXPORT_SYMBOL(snd_i2c_readbytes);
+
int snd_i2c_probeaddr(struct snd_i2c_bus *bus, unsigned short addr)
{
return bus->ops->probeaddr(bus, addr);
}
+EXPORT_SYMBOL(snd_i2c_probeaddr);
+
/*
* bit-operations
*/
@@ -320,12 +331,6 @@ static int snd_i2c_bit_probeaddr(struct snd_i2c_bus *bus, unsigned short addr)
return err;
}
-EXPORT_SYMBOL(snd_i2c_bus_create);
-EXPORT_SYMBOL(snd_i2c_device_create);
-EXPORT_SYMBOL(snd_i2c_device_free);
-EXPORT_SYMBOL(snd_i2c_sendbytes);
-EXPORT_SYMBOL(snd_i2c_readbytes);
-EXPORT_SYMBOL(snd_i2c_probeaddr);
static int __init alsa_i2c_init(void)
{
diff --git a/sound/i2c/l3/uda1341.c b/sound/i2c/l3/uda1341.c
index 746500e..b074fdd 100644
--- a/sound/i2c/l3/uda1341.c
+++ b/sound/i2c/l3/uda1341.c
@@ -517,9 +517,9 @@ static void __devinit snd_uda1341_proc_init(struct snd_card *card, struct l3_cli
struct snd_info_entry *entry;
if (! snd_card_proc_new(card, "uda1341", &entry))
- snd_info_set_text_ops(entry, clnt, 1024, snd_uda1341_proc_read);
+ snd_info_set_text_ops(entry, clnt, snd_uda1341_proc_read);
if (! snd_card_proc_new(card, "uda1341-regs", &entry))
- snd_info_set_text_ops(entry, clnt, 1024, snd_uda1341_proc_regs_read);
+ snd_info_set_text_ops(entry, clnt, snd_uda1341_proc_regs_read);
}
/* }}} */
diff --git a/sound/isa/gus/gus_irq.c b/sound/isa/gus/gus_irq.c
index c19ba29..42db375 100644
--- a/sound/isa/gus/gus_irq.c
+++ b/sound/isa/gus/gus_irq.c
@@ -136,7 +136,7 @@ void snd_gus_irq_profile_init(struct snd_gus_card *gus)
struct snd_info_entry *entry;
if (! snd_card_proc_new(gus->card, "gusirq", &entry))
- snd_info_set_text_ops(entry, gus, 1024, snd_gus_irq_info_read);
+ snd_info_set_text_ops(entry, gus, snd_gus_irq_info_read);
}
#endif
diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c
index 3c0d27a..f50c276 100644
--- a/sound/isa/gus/gus_mem.c
+++ b/sound/isa/gus/gus_mem.c
@@ -264,10 +264,8 @@ int snd_gf1_mem_init(struct snd_gus_card * gus)
if (snd_gf1_mem_xalloc(alloc, &block) == NULL)
return -ENOMEM;
#ifdef CONFIG_SND_DEBUG
- if (! snd_card_proc_new(gus->card, "gusmem", &entry)) {
- snd_info_set_text_ops(entry, gus, 1024, snd_gf1_mem_info_read);
- entry->c.text.read_size = 256 * 1024;
- }
+ if (! snd_card_proc_new(gus->card, "gusmem", &entry))
+ snd_info_set_text_ops(entry, gus, snd_gf1_mem_info_read);
#endif
return 0;
}
diff --git a/sound/isa/gus/gus_synth.c b/sound/isa/gus/gus_synth.c
index 2767cc1..3e4d4d6 100644
--- a/sound/isa/gus/gus_synth.c
+++ b/sound/isa/gus/gus_synth.c
@@ -194,7 +194,9 @@ static int snd_gus_synth_create_port(struct snd_gus_card * gus, int idx)
&callbacks,
SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE |
- SNDRV_SEQ_PORT_TYPE_SYNTH,
+ SNDRV_SEQ_PORT_TYPE_SYNTH |
+ SNDRV_SEQ_PORT_TYPE_HARDWARE |
+ SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
16, 0,
name);
if (p->chset->port < 0) {
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
index 4298d33..866300f 100644
--- a/sound/isa/gus/interwave.c
+++ b/sound/isa/gus/interwave.c
@@ -70,9 +70,9 @@ static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */
static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */
static int joystick_dac[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 29};
/* 0 to 31, (0.59V-4.52V or 0.389V-2.98V) */
-static int midi[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int midi[SNDRV_CARDS];
static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
-static int effect[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int effect[SNDRV_CARDS];
#ifdef SNDRV_STB
#define PFX "interwave-stb: "
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index 6d88905..647a996 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -59,7 +59,7 @@ static long midi_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;/* 0x330,0x300 */
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 0,1,3,5,9,11,12,15 */
static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 1,3,5,6,7 */
static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 1,3,5,6,7 */
-static int opl3sa3_ymode[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 }; /* 0,1,2,3 */ /*SL Added*/
+static int opl3sa3_ymode[SNDRV_CARDS]; /* 0,1,2,3 */ /*SL Added*/
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for OPL3-SA soundcard.");
@@ -221,7 +221,7 @@ static void snd_opl3sa2_write(struct snd_opl3sa2 *chip, unsigned char reg, unsig
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
-static int __init snd_opl3sa2_detect(struct snd_opl3sa2 *chip)
+static int __devinit snd_opl3sa2_detect(struct snd_opl3sa2 *chip)
{
struct snd_card *card;
unsigned long port;
@@ -489,7 +489,7 @@ static void snd_opl3sa2_master_free(struct snd_kcontrol *kcontrol)
chip->master_volume = NULL;
}
-static int __init snd_opl3sa2_mixer(struct snd_opl3sa2 *chip)
+static int __devinit snd_opl3sa2_mixer(struct snd_opl3sa2 *chip)
{
struct snd_card *card = chip->card;
struct snd_ctl_elem_id id1, id2;
@@ -583,8 +583,8 @@ static int snd_opl3sa2_resume(struct snd_card *card)
#endif /* CONFIG_PM */
#ifdef CONFIG_PNP
-static int __init snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip,
- struct pnp_dev *pdev)
+static int __devinit snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip,
+ struct pnp_dev *pdev)
{
struct pnp_resource_table * cfg;
int err;
@@ -862,7 +862,7 @@ static struct pnp_card_driver opl3sa2_pnpc_driver = {
};
#endif /* CONFIG_PNP */
-static int __init snd_opl3sa2_nonpnp_probe(struct platform_device *pdev)
+static int __devinit snd_opl3sa2_nonpnp_probe(struct platform_device *pdev)
{
struct snd_card *card;
int err;
diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c
index e6bfcf7..283817f 100644
--- a/sound/isa/opti9xx/miro.c
+++ b/sound/isa/opti9xx/miro.c
@@ -967,7 +967,7 @@ static void __init snd_miro_proc_init(struct snd_miro * miro)
struct snd_info_entry *entry;
if (! snd_card_proc_new(miro->card, "miro", &entry))
- snd_info_set_text_ops(entry, miro, 1024, snd_miro_proc_read);
+ snd_info_set_text_ops(entry, miro, snd_miro_proc_read);
}
/*
diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c
index c0b8d61..658179e 100644
--- a/sound/isa/sb/emu8000.c
+++ b/sound/isa/sb/emu8000.c
@@ -131,7 +131,7 @@ snd_emu8000_dma_chan(struct snd_emu8000 *emu, int ch, int mode)
/*
*/
-static void __init
+static void __devinit
snd_emu8000_read_wait(struct snd_emu8000 *emu)
{
while ((EMU8000_SMALR_READ(emu) & 0x80000000) != 0) {
@@ -143,7 +143,7 @@ snd_emu8000_read_wait(struct snd_emu8000 *emu)
/*
*/
-static void __init
+static void __devinit
snd_emu8000_write_wait(struct snd_emu8000 *emu)
{
while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) {
@@ -156,7 +156,7 @@ snd_emu8000_write_wait(struct snd_emu8000 *emu)
/*
* detect a card at the given port
*/
-static int __init
+static int __devinit
snd_emu8000_detect(struct snd_emu8000 *emu)
{
/* Initialise */
@@ -182,7 +182,7 @@ snd_emu8000_detect(struct snd_emu8000 *emu)
/*
* intiailize audio channels
*/
-static void __init
+static void __devinit
init_audio(struct snd_emu8000 *emu)
{
int ch;
@@ -223,7 +223,7 @@ init_audio(struct snd_emu8000 *emu)
/*
* initialize DMA address
*/
-static void __init
+static void __devinit
init_dma(struct snd_emu8000 *emu)
{
EMU8000_SMALR_WRITE(emu, 0);
@@ -327,7 +327,7 @@ static unsigned short init4[128] /*__devinitdata*/ = {
* Taken from the oss driver, not obvious from the doc how this
* is meant to work
*/
-static void __init
+static void __devinit
send_array(struct snd_emu8000 *emu, unsigned short *data, int size)
{
int i;
@@ -349,7 +349,7 @@ send_array(struct snd_emu8000 *emu, unsigned short *data, int size)
* Send initialization arrays to start up, this just follows the
* initialisation sequence in the adip.
*/
-static void __init
+static void __devinit
init_arrays(struct snd_emu8000 *emu)
{
send_array(emu, init1, ARRAY_SIZE(init1)/4);
@@ -375,7 +375,7 @@ init_arrays(struct snd_emu8000 *emu)
* seems that the only way to do this is to use the one channel and keep
* reallocating between read and write.
*/
-static void __init
+static void __devinit
size_dram(struct snd_emu8000 *emu)
{
int i, size;
@@ -500,7 +500,7 @@ snd_emu8000_init_fm(struct snd_emu8000 *emu)
/*
* The main initialization routine.
*/
-static void __init
+static void __devinit
snd_emu8000_init_hw(struct snd_emu8000 *emu)
{
int i;
@@ -1019,7 +1019,7 @@ static struct snd_kcontrol_new *mixer_defs[EMU8000_NUM_CONTROLS] = {
/*
* create and attach mixer elements for WaveTable treble/bass controls
*/
-static int __init
+static int __devinit
snd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu)
{
int i, err = 0;
@@ -1069,7 +1069,7 @@ static int snd_emu8000_dev_free(struct snd_device *device)
/*
* initialize and register emu8000 synth device.
*/
-int __init
+int __devinit
snd_emu8000_new(struct snd_card *card, int index, long port, int seq_ports,
struct snd_seq_device **awe_ret)
{
diff --git a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c
index 80b1cf8..1be16c9 100644
--- a/sound/isa/sb/emu8000_patch.c
+++ b/sound/isa/sb/emu8000_patch.c
@@ -23,7 +23,7 @@
#include <asm/uaccess.h>
#include <linux/moduleparam.h>
-static int emu8000_reset_addr = 0;
+static int emu8000_reset_addr;
module_param(emu8000_reset_addr, int, 0444);
MODULE_PARM_DESC(emu8000_reset_addr, "reset write address at each time (makes slowdown)");
diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c
index 6333f90..7f7f05f 100644
--- a/sound/isa/sb/sb16.c
+++ b/sound/isa/sb/sb16.c
@@ -85,7 +85,7 @@ static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */
static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 5,6,7 */
static int mic_agc[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
#ifdef CONFIG_SND_SB16_CSP
-static int csp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int csp[SNDRV_CARDS];
#endif
#ifdef SNDRV_SBAWE_EMU8000
static int seq_ports[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4};
diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c
index 9703c68..fcd6380 100644
--- a/sound/isa/sb/sb16_csp.c
+++ b/sound/isa/sb/sb16_csp.c
@@ -1101,7 +1101,7 @@ static int init_proc_entry(struct snd_sb_csp * p, int device)
struct snd_info_entry *entry;
sprintf(name, "cspD%d", device);
if (! snd_card_proc_new(p->chip->card, name, &entry))
- snd_info_set_text_ops(entry, p, 1024, info_read);
+ snd_info_set_text_ops(entry, p, info_read);
return 0;
}
diff --git a/sound/isa/sb/sb8_midi.c b/sound/isa/sb/sb8_midi.c
index c549ace..0b67edd 100644
--- a/sound/isa/sb/sb8_midi.c
+++ b/sound/isa/sb/sb8_midi.c
@@ -32,20 +32,22 @@
#include <sound/core.h>
#include <sound/sb.h>
-/*
-
- */
-irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb * chip)
+irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb *chip)
{
struct snd_rawmidi *rmidi;
int max = 64;
char byte;
- if (chip == NULL || (rmidi = chip->rmidi) == NULL) {
+ if (!chip)
+ return IRQ_NONE;
+
+ rmidi = chip->rmidi;
+ if (!rmidi) {
inb(SBP(chip, DATA_AVAIL)); /* ack interrupt */
return IRQ_NONE;
}
+
spin_lock(&chip->midi_input_lock);
while (max-- > 0) {
if (inb(SBP(chip, DATA_AVAIL)) & 0x80) {
@@ -59,10 +61,6 @@ irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb * chip)
return IRQ_HANDLED;
}
-/*
-
- */
-
static int snd_sb8dsp_midi_input_open(struct snd_rawmidi_substream *substream)
{
unsigned long flags;
@@ -252,10 +250,6 @@ static void snd_sb8dsp_midi_output_trigger(struct snd_rawmidi_substream *substre
snd_sb8dsp_midi_output_write(substream);
}
-/*
-
- */
-
static struct snd_rawmidi_ops snd_sb8dsp_midi_output =
{
.open = snd_sb8dsp_midi_output_open,
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c
index d2a856f..27271c9 100644
--- a/sound/isa/sscape.c
+++ b/sound/isa/sscape.c
@@ -897,10 +897,9 @@ static int __devinit create_mpu401(struct snd_card *card, int devnum, unsigned l
struct snd_rawmidi *rawmidi;
int err;
-#define MPU401_SHARE_HARDWARE 1
if ((err = snd_mpu401_uart_new(card, devnum,
MPU401_HW_MPU401,
- port, MPU401_SHARE_HARDWARE,
+ port, MPU401_INFO_INTEGRATED,
irq, SA_INTERRUPT,
&rawmidi)) == 0) {
struct snd_mpu401 *mpu = (struct snd_mpu401 *) rawmidi->private_data;
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c
index 7ae86f8..9eb2708 100644
--- a/sound/isa/wavefront/wavefront.c
+++ b/sound/isa/wavefront/wavefront.c
@@ -50,7 +50,7 @@ static int ics2115_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 2,9,11,12,15 */
static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */
static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */
-static int use_cs4232_midi[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int use_cs4232_midi[SNDRV_CARDS];
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for WaveFront soundcard.");
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index 080ab03..95754e2 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -114,8 +114,9 @@ config SOUND_VRC5477
with the AC97 codec.
config SOUND_AU1550_AC97
- tristate "Au1550 AC97 Sound"
- depends on SOUND_PRIME && SOC_AU1550
+ tristate "Au1550/Au1200 AC97 Sound"
+ select SND_AC97_CODEC
+ depends on SOUND_PRIME && (SOC_AU1550 || SOC_AU1200)
config SOUND_TRIDENT
tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core"
diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c
index c1168fa..4cdb862 100644
--- a/sound/oss/au1550_ac97.c
+++ b/sound/oss/au1550_ac97.c
@@ -57,9 +57,9 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/hardirq.h>
-#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1xxx_psc.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
+#include <asm/mach-au1x00/au1xxx.h>
#undef OSS_DOCUMENTED_MIXER_SEMANTICS
@@ -213,7 +213,8 @@ rdcodec(struct ac97_codec *codec, u8 addr)
}
if (i == POLL_COUNT) {
err("rdcodec: read poll expired!");
- return 0;
+ data = 0;
+ goto out;
}
/* wait for command done?
@@ -226,7 +227,8 @@ rdcodec(struct ac97_codec *codec, u8 addr)
}
if (i == POLL_COUNT) {
err("rdcodec: read cmdwait expired!");
- return 0;
+ data = 0;
+ goto out;
}
data = au_readl(PSC_AC97CDC) & 0xffff;
@@ -237,6 +239,7 @@ rdcodec(struct ac97_codec *codec, u8 addr)
au_writel(PSC_AC97EVNT_CD, PSC_AC97EVNT);
au_sync();
+ out:
spin_unlock_irqrestore(&s->lock, flags);
return data;
@@ -1892,6 +1895,8 @@ static /*const */ struct file_operations au1550_audio_fops = {
MODULE_AUTHOR("Advanced Micro Devices (AMD), dan@embeddededge.com");
MODULE_DESCRIPTION("Au1550 AC97 Audio Driver");
+MODULE_LICENSE("GPL");
+
static int __devinit
au1550_probe(void)
diff --git a/sound/oss/cs46xx.c b/sound/oss/cs46xx.c
index 53881bc..994c71e 100644
--- a/sound/oss/cs46xx.c
+++ b/sound/oss/cs46xx.c
@@ -147,7 +147,7 @@
* that should be printed on any released driver.
*/
#if CSDEBUG
-#define CS_DBGOUT(mask,level,x) if((cs_debuglevel >= (level)) && ((mask) & cs_debugmask)) {x;}
+#define CS_DBGOUT(mask,level,x) if ((cs_debuglevel >= (level)) && ((mask) & cs_debugmask)) {x;}
#else
#define CS_DBGOUT(mask,level,x)
#endif
@@ -175,19 +175,19 @@
#define CS_IOCTL_CMD_RESUME 0x2 // resume
#if CSDEBUG
-static unsigned long cs_debuglevel=1; /* levels range from 1-9 */
+static unsigned long cs_debuglevel = 1; /* levels range from 1-9 */
module_param(cs_debuglevel, ulong, 0644);
-static unsigned long cs_debugmask=CS_INIT | CS_ERROR; /* use CS_DBGOUT with various mask values */
+static unsigned long cs_debugmask = CS_INIT | CS_ERROR; /* use CS_DBGOUT with various mask values */
module_param(cs_debugmask, ulong, 0644);
#endif
static unsigned long hercules_egpio_disable; /* if non-zero set all EGPIO to 0 */
module_param(hercules_egpio_disable, ulong, 0);
-static unsigned long initdelay=700; /* PM delay in millisecs */
+static unsigned long initdelay = 700; /* PM delay in millisecs */
module_param(initdelay, ulong, 0);
-static unsigned long powerdown=-1; /* turn on/off powerdown processing in driver */
+static unsigned long powerdown = -1; /* turn on/off powerdown processing in driver */
module_param(powerdown, ulong, 0);
#define DMABUF_DEFAULTORDER 3
-static unsigned long defaultorder=DMABUF_DEFAULTORDER;
+static unsigned long defaultorder = DMABUF_DEFAULTORDER;
module_param(defaultorder, ulong, 0);
static int external_amp;
@@ -200,8 +200,8 @@ module_param(thinkpad, bool, 0);
* powerdown. also set thinkpad to 1 to disable powerdown,
* but also to enable the clkrun functionality.
*/
-static unsigned cs_powerdown=1;
-static unsigned cs_laptop_wait=1;
+static unsigned cs_powerdown = 1;
+static unsigned cs_laptop_wait = 1;
/* An instance of the 4610 channel */
struct cs_channel
@@ -319,7 +319,7 @@ struct cs_card {
atomic_t mixer_use_cnt;
/* PCI device stuff */
- struct pci_dev * pci_dev;
+ struct pci_dev *pci_dev;
struct list_head list;
unsigned int pctl, cctl; /* Hardware DMA flag sets */
@@ -384,7 +384,7 @@ struct cs_card {
static int cs_open_mixdev(struct inode *inode, struct file *file);
static int cs_release_mixdev(struct inode *inode, struct file *file);
static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg);
+ unsigned long arg);
static int cs_hardware_init(struct cs_card *card);
static int cs46xx_powerup(struct cs_card *card, unsigned int type);
static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspendflag);
@@ -423,8 +423,7 @@ static void printioctl(unsigned int x)
[SOUND_MIXER_VOLUME] = 9 /* Master Volume */
};
- switch(x)
- {
+ switch (x) {
case SOUND_MIXER_CS_GETDBGMASK:
CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_GETDBGMASK: ") );
break;
@@ -521,7 +520,6 @@ static void printioctl(unsigned int x)
case SOUND_PCM_READ_FILTER:
CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_FILTER: ") );
break;
-
case SOUND_MIXER_PRIVATE1:
CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE1: ") );
break;
@@ -543,10 +541,8 @@ static void printioctl(unsigned int x)
case SOUND_OLD_MIXER_INFO:
CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_OLD_MIXER_INFO: ") );
break;
-
default:
- switch (_IOC_NR(x))
- {
+ switch (_IOC_NR(x)) {
case SOUND_MIXER_VOLUME:
CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_VOLUME: ") );
break;
@@ -579,14 +575,11 @@ static void printioctl(unsigned int x)
break;
default:
i = _IOC_NR(x);
- if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))
- {
+ if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i])) {
CS_DBGOUT(CS_IOCTL, 4, printk("UNKNOWN IOCTL: 0x%.8x NR=%d ",x,i) );
- }
- else
- {
+ } else {
CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_IOCTL AC9x: 0x%.8x NR=%d ",
- x,i) );
+ x,i));
}
break;
}
@@ -601,22 +594,22 @@ static void printioctl(unsigned int x)
static void cs461x_poke(struct cs_card *codec, unsigned long reg, unsigned int val)
{
- writel(val, codec->ba1.idx[(reg >> 16) & 3]+(reg&0xffff));
+ writel(val, codec->ba1.idx[(reg >> 16) & 3] + (reg & 0xffff));
}
static unsigned int cs461x_peek(struct cs_card *codec, unsigned long reg)
{
- return readl(codec->ba1.idx[(reg >> 16) & 3]+(reg&0xffff));
+ return readl(codec->ba1.idx[(reg >> 16) & 3] + (reg & 0xffff));
}
static void cs461x_pokeBA0(struct cs_card *codec, unsigned long reg, unsigned int val)
{
- writel(val, codec->ba0+reg);
+ writel(val, codec->ba0 + reg);
}
static unsigned int cs461x_peekBA0(struct cs_card *codec, unsigned long reg)
{
- return readl(codec->ba0+reg);
+ return readl(codec->ba0 + reg);
}
@@ -625,26 +618,26 @@ static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
static struct cs_channel *cs_alloc_pcm_channel(struct cs_card *card)
{
- if(card->channel[1].used==1)
+ if (card->channel[1].used == 1)
return NULL;
- card->channel[1].used=1;
- card->channel[1].num=1;
+ card->channel[1].used = 1;
+ card->channel[1].num = 1;
return &card->channel[1];
}
static struct cs_channel *cs_alloc_rec_pcm_channel(struct cs_card *card)
{
- if(card->channel[0].used==1)
+ if (card->channel[0].used == 1)
return NULL;
- card->channel[0].used=1;
- card->channel[0].num=0;
+ card->channel[0].used = 1;
+ card->channel[0].num = 0;
return &card->channel[0];
}
static void cs_free_pcm_channel(struct cs_card *card, int channel)
{
card->channel[channel].state = NULL;
- card->channel[channel].used=0;
+ card->channel[channel].used = 0;
}
/*
@@ -655,15 +648,15 @@ static void cs_free_pcm_channel(struct cs_card *card, int channel)
*/
static void cs_set_divisor(struct dmabuf *dmabuf)
{
- if(dmabuf->type == CS_TYPE_DAC)
+ if (dmabuf->type == CS_TYPE_DAC)
dmabuf->divisor = 1;
- else if( !(dmabuf->fmt & CS_FMT_STEREO) &&
+ else if (!(dmabuf->fmt & CS_FMT_STEREO) &&
(dmabuf->fmt & CS_FMT_16BIT))
dmabuf->divisor = 2;
- else if( (dmabuf->fmt & CS_FMT_STEREO) &&
+ else if ((dmabuf->fmt & CS_FMT_STEREO) &&
!(dmabuf->fmt & CS_FMT_16BIT))
dmabuf->divisor = 2;
- else if( !(dmabuf->fmt & CS_FMT_STEREO) &&
+ else if (!(dmabuf->fmt & CS_FMT_STEREO) &&
!(dmabuf->fmt & CS_FMT_16BIT))
dmabuf->divisor = 4;
else
@@ -680,13 +673,12 @@ static void cs_set_divisor(struct dmabuf *dmabuf)
*/
static void cs_mute(struct cs_card *card, int state)
{
- struct ac97_codec *dev=card->ac97_codec[0];
+ struct ac97_codec *dev = card->ac97_codec[0];
CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: cs_mute()+ %s\n",
- (state == CS_TRUE) ? "Muting" : "UnMuting") );
+ (state == CS_TRUE) ? "Muting" : "UnMuting"));
- if(state == CS_TRUE)
- {
+ if (state == CS_TRUE) {
/*
* fix pops when powering up on thinkpads
*/
@@ -703,9 +695,7 @@ static void cs_mute(struct cs_card *card, int state)
cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, 0x8000);
cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, 0x8000);
cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, 0x8000);
- }
- else
- {
+ } else {
cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, card->pm.u32AC97_master_volume);
cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, card->pm.u32AC97_headphone_volume);
cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, card->pm.u32AC97_master_volume_mono);
@@ -757,7 +747,6 @@ static unsigned int cs_set_dac_rate(struct cs_state * state, unsigned int rate)
/*
* Fill in the SampleRateConverter control block.
*/
-
spin_lock_irqsave(&state->card->lock, flags);
cs461x_poke(state->card, BA1_PSRC,
((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));
@@ -770,7 +759,7 @@ static unsigned int cs_set_dac_rate(struct cs_state * state, unsigned int rate)
}
/* set recording sample rate */
-static unsigned int cs_set_adc_rate(struct cs_state * state, unsigned int rate)
+static unsigned int cs_set_adc_rate(struct cs_state *state, unsigned int rate)
{
struct dmabuf *dmabuf = &state->dmabuf;
struct cs_card *card = state->card;
@@ -815,7 +804,6 @@ static unsigned int cs_set_adc_rate(struct cs_state * state, unsigned int rate)
* dividend:remainder(ulOther / GOF_PER_SEC)
* initialDelay = dividend(((24 * Fs,in) + Fs,out - 1) / Fs,out)
*/
-
tmp1 = rate << 16;
coeffIncr = tmp1 / 48000;
tmp1 -= coeffIncr * 48000;
@@ -891,7 +879,7 @@ static void cs_play_setup(struct cs_state *state)
CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_play_setup()+\n") );
cs461x_poke(card, BA1_PVOL, 0x80008000);
- if(!dmabuf->SGok)
+ if (!dmabuf->SGok)
cs461x_poke(card, BA1_PBA, virt_to_bus(dmabuf->pbuf));
Count = 4;
@@ -899,16 +887,14 @@ static void cs_play_setup(struct cs_state *state)
if ((dmabuf->fmt & CS_FMT_STEREO)) {
playFormat &= ~DMA_RQ_C2_AC_MONO_TO_STEREO;
Count *= 2;
- }
- else
+ } else
playFormat |= DMA_RQ_C2_AC_MONO_TO_STEREO;
if ((dmabuf->fmt & CS_FMT_16BIT)) {
playFormat &= ~(DMA_RQ_C2_AC_8_TO_16_BIT
| DMA_RQ_C2_AC_SIGNED_CONVERT);
Count *= 2;
- }
- else
+ } else
playFormat |= (DMA_RQ_C2_AC_8_TO_16_BIT
| DMA_RQ_C2_AC_SIGNED_CONVERT);
@@ -919,7 +905,6 @@ static void cs_play_setup(struct cs_state *state)
cs461x_poke(card, BA1_PDTC, tmp | --Count);
CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_play_setup()-\n") );
-
}
static struct InitStruct
@@ -944,8 +929,7 @@ static void SetCaptureSPValues(struct cs_card *card)
{
unsigned i, offset;
CS_DBGOUT(CS_FUNCTION, 8, printk("cs46xx: SetCaptureSPValues()+\n") );
- for(i=0; i<sizeof(InitArray)/sizeof(struct InitStruct); i++)
- {
+ for (i = 0; i < sizeof(InitArray) / sizeof(struct InitStruct); i++) {
offset = InitArray[i].off*4; /* 8bit to 32bit offset value */
cs461x_poke(card, offset, InitArray[i].val );
}
@@ -957,8 +941,8 @@ static void cs_rec_setup(struct cs_state *state)
{
struct cs_card *card = state->card;
struct dmabuf *dmabuf = &state->dmabuf;
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_rec_setup()+\n") );
+ CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_rec_setup()+\n"));
SetCaptureSPValues(card);
/*
@@ -994,14 +978,11 @@ static inline unsigned cs_get_dma_addr(struct cs_state *state)
/*
* granularity is byte boundary, good part.
*/
- if(dmabuf->enable & DAC_RUNNING)
- {
+ if (dmabuf->enable & DAC_RUNNING)
offset = cs461x_peek(state->card, BA1_PBA);
- }
else /* ADC_RUNNING must be set */
- {
offset = cs461x_peek(state->card, BA1_CBA);
- }
+
CS_DBGOUT(CS_PARMS | CS_FUNCTION, 9,
printk("cs46xx: cs_get_dma_addr() %d\n",offset) );
offset = (u32)bus_to_virt((unsigned long)offset) - (u32)dmabuf->rawbuf;
@@ -1015,8 +996,7 @@ static void resync_dma_ptrs(struct cs_state *state)
struct dmabuf *dmabuf;
CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: resync_dma_ptrs()+ \n") );
- if(state)
- {
+ if (state) {
dmabuf = &state->dmabuf;
dmabuf->hwptr=dmabuf->swptr = 0;
dmabuf->pringbuf = 0;
@@ -1149,13 +1129,13 @@ static int alloc_dmabuf(struct cs_state *state)
/*
* check for order within limits, but do not overwrite value.
*/
- if((defaultorder > 1) && (defaultorder < 12))
+ if ((defaultorder > 1) && (defaultorder < 12))
df = defaultorder;
else
df = 2;
for (order = df; order >= DMABUF_MINORDER; order--)
- if ( (rawbuf = (void *) pci_alloc_consistent(
+ if ((rawbuf = (void *)pci_alloc_consistent(
card->pci_dev, PAGE_SIZE << order, &dmabuf->dmaaddr)))
break;
if (!rawbuf) {
@@ -1181,8 +1161,7 @@ static int alloc_dmabuf(struct cs_state *state)
/*
* only allocate the conversion buffer for the ADC
*/
- if(dmabuf->type == CS_TYPE_DAC)
- {
+ if (dmabuf->type == CS_TYPE_DAC) {
dmabuf->tmpbuff = NULL;
dmabuf->buforder_tmpbuff = 0;
return 0;
@@ -1258,8 +1237,7 @@ static int __prog_dmabuf(struct cs_state *state)
/*
* check for CAPTURE and use only non-sg for initial release
*/
- if(dmabuf->type == CS_TYPE_ADC)
- {
+ if (dmabuf->type == CS_TYPE_ADC) {
CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf() ADC\n"));
/*
* add in non-sg support for capture.
@@ -1313,9 +1291,7 @@ static int __prog_dmabuf(struct cs_state *state)
CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf()- 0 \n"));
return 0;
- }
- else if (dmabuf->type == CS_TYPE_DAC)
- {
+ } else if (dmabuf->type == CS_TYPE_DAC) {
/*
* Must be DAC
*/
@@ -1337,8 +1313,7 @@ static int __prog_dmabuf(struct cs_state *state)
allocated_pages = 1 << dmabuf->buforder;
allocated_bytes = allocated_pages*PAGE_SIZE;
- if(allocated_pages < 2)
- {
+ if (allocated_pages < 2) {
CS_DBGOUT(CS_FUNCTION, 4, printk(
"cs46xx: prog_dmabuf() Error: allocated_pages too small (%d)\n",
(unsigned)allocated_pages));
@@ -1353,14 +1328,14 @@ static int __prog_dmabuf(struct cs_state *state)
/* Set up S/G variables. */
*ptmp = virt_to_bus(dmabuf->rawbuf);
- *(ptmp+1) = 0x00000008;
- for(tmp1= 1; tmp1 < nSGpages; tmp1++) {
- *(ptmp+2*tmp1) = virt_to_bus( (dmabuf->rawbuf)+4096*tmp1);
- if( tmp1 == nSGpages-1)
+ *(ptmp + 1) = 0x00000008;
+ for (tmp1 = 1; tmp1 < nSGpages; tmp1++) {
+ *(ptmp + 2 * tmp1) = virt_to_bus((dmabuf->rawbuf) + 4096 * tmp1);
+ if (tmp1 == nSGpages - 1)
tmp2 = 0xbfff0000;
else
- tmp2 = 0x80000000+8*(tmp1+1);
- *(ptmp+2*tmp1+1) = tmp2;
+ tmp2 = 0x80000000 + 8 * (tmp1 + 1);
+ *(ptmp + 2 * tmp1 + 1) = tmp2;
}
SGarray[0] = 0x82c0200d;
SGarray[1] = 0xffff0000;
@@ -1368,18 +1343,17 @@ static int __prog_dmabuf(struct cs_state *state)
SGarray[3] = 0x00010600;
SGarray[4] = *(ptmp+2);
SGarray[5] = 0x80000010;
- SGarray[6] = *ptmp;
- SGarray[7] = *(ptmp+2);
- SGarray[8] = (virt_to_bus(dmabuf->pbuf) & 0xffff000) | 0x10;
-
- if (dmabuf->SGok) {
- dmabuf->numfrag = nSGpages;
- dmabuf->fragsize = 4096;
- dmabuf->fragsamples = 4096 >> sample_shift[dmabuf->fmt];
- dmabuf->fragshift = 12;
- dmabuf->dmasize = dmabuf->numfrag*4096;
- }
- else {
+ SGarray[6] = *ptmp;
+ SGarray[7] = *(ptmp+2);
+ SGarray[8] = (virt_to_bus(dmabuf->pbuf) & 0xffff000) | 0x10;
+
+ if (dmabuf->SGok) {
+ dmabuf->numfrag = nSGpages;
+ dmabuf->fragsize = 4096;
+ dmabuf->fragsamples = 4096 >> sample_shift[dmabuf->fmt];
+ dmabuf->fragshift = 12;
+ dmabuf->dmasize = dmabuf->numfrag * 4096;
+ } else {
SGarray[0] = 0xf2c0000f;
SGarray[1] = 0x00000200;
SGarray[2] = 0;
@@ -1391,8 +1365,8 @@ static int __prog_dmabuf(struct cs_state *state)
dmabuf->dmasize = 4096;
dmabuf->fragshift = 11;
}
- for(tmp1 = 0; tmp1 < sizeof(SGarray)/4; tmp1++)
- cs461x_poke( state->card, BA1_PDTC+tmp1*4, SGarray[tmp1]);
+ for (tmp1 = 0; tmp1 < sizeof(SGarray) / 4; tmp1++)
+ cs461x_poke(state->card, BA1_PDTC+tmp1 * 4, SGarray[tmp1]);
memset(dmabuf->rawbuf, (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80,
dmabuf->dmasize);
@@ -1416,9 +1390,7 @@ static int __prog_dmabuf(struct cs_state *state)
CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf()- \n"));
return 0;
- }
- else
- {
+ } else {
CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf()- Invalid Type %d\n",
dmabuf->type));
}
@@ -1489,8 +1461,7 @@ static int drain_dac(struct cs_state *state, int nonblock)
}
remove_wait_queue(&dmabuf->wait, &wait);
current->state = TASK_RUNNING;
- if (signal_pending(current))
- {
+ if (signal_pending(current)) {
CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()- -ERESTARTSYS\n"));
/*
* set to silence and let that clear the fifos.
@@ -1514,8 +1485,7 @@ static void cs_update_ptr(struct cs_card *card, int wake)
/* error handling and process wake up for ADC */
state = card->states[0];
- if(state)
- {
+ if (state) {
dmabuf = &state->dmabuf;
if (dmabuf->enable & ADC_RUNNING) {
/* update hardware pointer */
@@ -1531,12 +1501,10 @@ static void cs_update_ptr(struct cs_card *card, int wake)
if (dmabuf->count > dmabuf->dmasize)
dmabuf->count = dmabuf->dmasize;
- if(dmabuf->mapped)
- {
+ if (dmabuf->mapped) {
if (wake && dmabuf->count >= (signed)dmabuf->fragsize)
wake_up(&dmabuf->wait);
- } else
- {
+ } else {
if (wake && dmabuf->count > 0)
wake_up(&dmabuf->wait);
}
@@ -1547,8 +1515,7 @@ static void cs_update_ptr(struct cs_card *card, int wake)
* Now the DAC
*/
state = card->states[1];
- if(state)
- {
+ if (state) {
dmabuf = &state->dmabuf;
/* error handling and process wake up for DAC */
if (dmabuf->enable & DAC_RUNNING) {
@@ -1570,7 +1537,7 @@ static void cs_update_ptr(struct cs_card *card, int wake)
* in that, since dmasize is the buffer asked for
* via mmap.
*/
- if( dmabuf->count > dmabuf->dmasize)
+ if (dmabuf->count > dmabuf->dmasize)
dmabuf->count &= dmabuf->dmasize-1;
} else {
dmabuf->count -= diff;
@@ -1578,13 +1545,10 @@ static void cs_update_ptr(struct cs_card *card, int wake)
* backfill with silence and clear out the last
* "diff" number of bytes.
*/
- if(hwptr >= diff)
- {
+ if (hwptr >= diff) {
memset(dmabuf->rawbuf + hwptr - diff,
(dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80, diff);
- }
- else
- {
+ } else {
memset(dmabuf->rawbuf,
(dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80,
(unsigned)hwptr);
@@ -1602,12 +1566,12 @@ static void cs_update_ptr(struct cs_card *card, int wake)
* buffer underrun or buffer overrun, reset the
* count of bytes written back to 0.
*/
- if(dmabuf->count < 0)
- dmabuf->underrun=1;
+ if (dmabuf->count < 0)
+ dmabuf->underrun = 1;
dmabuf->count = 0;
dmabuf->error++;
}
- if (wake && dmabuf->count < (signed)dmabuf->dmasize/2)
+ if (wake && dmabuf->count < (signed)dmabuf->dmasize / 2)
wake_up(&dmabuf->wait);
}
}
@@ -1661,8 +1625,7 @@ static irqreturn_t cs_interrupt(int irq, void *dev_id, struct pt_regs *regs)
status = cs461x_peekBA0(card, BA0_HISR);
- if ((status & 0x7fffffff) == 0)
- {
+ if ((status & 0x7fffffff) == 0) {
cs461x_pokeBA0(card, BA0_HICR, HICR_CHGM|HICR_IEV);
spin_unlock(&card->lock);
return IRQ_HANDLED; /* Might be IRQ_NONE.. */
@@ -1671,15 +1634,14 @@ static irqreturn_t cs_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/*
* check for playback or capture interrupt only
*/
- if( ((status & HISR_VC0) && playstate && playstate->dmabuf.ready) ||
- (((status & HISR_VC1) && recstate && recstate->dmabuf.ready)) )
- {
+ if (((status & HISR_VC0) && playstate && playstate->dmabuf.ready) ||
+ (((status & HISR_VC1) && recstate && recstate->dmabuf.ready))) {
CS_DBGOUT(CS_INTERRUPT, 8, printk(
"cs46xx: cs_interrupt() interrupt bit(s) set (0x%x)\n",status));
cs_update_ptr(card, CS_TRUE);
}
- if( status & HISR_MIDI )
+ if (status & HISR_MIDI)
cs_handle_midi(card);
/* clear 'em */
@@ -1694,7 +1656,7 @@ static irqreturn_t cs_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static ssize_t cs_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
- struct cs_card *card = (struct cs_card *)file->private_data;
+ struct cs_card *card = file->private_data;
ssize_t ret;
unsigned long flags;
unsigned ptr;
@@ -1737,7 +1699,7 @@ static ssize_t cs_midi_read(struct file *file, char __user *buffer, size_t count
static ssize_t cs_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
- struct cs_card *card = (struct cs_card *)file->private_data;
+ struct cs_card *card = file->private_data;
ssize_t ret;
unsigned long flags;
unsigned ptr;
@@ -1785,7 +1747,7 @@ static ssize_t cs_midi_write(struct file *file, const char __user *buffer, size_
static unsigned int cs_midi_poll(struct file *file, struct poll_table_struct *wait)
{
- struct cs_card *card = (struct cs_card *)file->private_data;
+ struct cs_card *card = file->private_data;
unsigned long flags;
unsigned int mask = 0;
@@ -1810,12 +1772,11 @@ static unsigned int cs_midi_poll(struct file *file, struct poll_table_struct *wa
static int cs_midi_open(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
- struct cs_card *card=NULL;
+ struct cs_card *card = NULL;
unsigned long flags;
struct list_head *entry;
- list_for_each(entry, &cs46xx_devs)
- {
+ list_for_each(entry, &cs46xx_devs) {
card = list_entry(entry, struct cs_card, list);
if (card->dev_midi == minor)
break;
@@ -1823,8 +1784,7 @@ static int cs_midi_open(struct inode *inode, struct file *file)
if (entry == &cs46xx_devs)
return -ENODEV;
- if (!card)
- {
+ if (!card) {
CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
"cs46xx: cs46xx_midi_open(): Error - unable to find card struct\n"));
return -ENODEV;
@@ -1852,12 +1812,10 @@ static int cs_midi_open(struct inode *inode, struct file *file)
cs461x_pokeBA0(card, BA0_MIDCR, 0x0000000f); /* Enable xmit, rcv. */
cs461x_pokeBA0(card, BA0_HICR, HICR_IEV | HICR_CHGM); /* Enable interrupts */
}
- if (file->f_mode & FMODE_READ) {
+ if (file->f_mode & FMODE_READ)
card->midi.ird = card->midi.iwr = card->midi.icnt = 0;
- }
- if (file->f_mode & FMODE_WRITE) {
+ if (file->f_mode & FMODE_WRITE)
card->midi.ord = card->midi.owr = card->midi.ocnt = 0;
- }
spin_unlock_irqrestore(&card->midi.lock, flags);
card->midi.open_mode |= (file->f_mode & (FMODE_READ | FMODE_WRITE));
mutex_unlock(&card->midi.open_mutex);
@@ -1867,7 +1825,7 @@ static int cs_midi_open(struct inode *inode, struct file *file)
static int cs_midi_release(struct inode *inode, struct file *file)
{
- struct cs_card *card = (struct cs_card *)file->private_data;
+ struct cs_card *card = file->private_data;
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
unsigned count, tmo;
@@ -1933,11 +1891,10 @@ static /*const*/ struct file_operations cs_midi_fops = {
static void CopySamples(char *dst, char *src, int count, unsigned fmt,
struct dmabuf *dmabuf)
{
-
s32 s32AudioSample;
- s16 *psSrc=(s16 *)src;
- s16 *psDst=(s16 *)dst;
- u8 *pucDst=(u8 *)dst;
+ s16 *psSrc = (s16 *)src;
+ s16 *psDst = (s16 *)dst;
+ u8 *pucDst = (u8 *)dst;
CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: CopySamples()+ ") );
CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
@@ -1947,34 +1904,29 @@ static void CopySamples(char *dst, char *src, int count, unsigned fmt,
/*
* See if the data should be output as 8-bit unsigned stereo.
*/
- if((fmt & CS_FMT_STEREO) && !(fmt & CS_FMT_16BIT))
- {
+ if ((fmt & CS_FMT_STEREO) && !(fmt & CS_FMT_16BIT)) {
/*
* Convert each 16-bit signed stereo sample to 8-bit unsigned
* stereo using rounding.
*/
psSrc = (s16 *)src;
- count = count/2;
- while(count--)
- {
+ count = count / 2;
+ while (count--)
*(pucDst++) = (u8)(((s16)(*psSrc++) + (s16)0x8000) >> 8);
- }
}
/*
* See if the data should be output at 8-bit unsigned mono.
*/
- else if(!(fmt & CS_FMT_STEREO) && !(fmt & CS_FMT_16BIT))
- {
+ else if (!(fmt & CS_FMT_STEREO) && !(fmt & CS_FMT_16BIT)) {
/*
* Convert each 16-bit signed stereo sample to 8-bit unsigned
* mono using averaging and rounding.
*/
psSrc = (s16 *)src;
- count = count/2;
- while(count--)
- {
- s32AudioSample = ((*psSrc)+(*(psSrc + 1)))/2 + (s32)0x80;
- if(s32AudioSample > 0x7fff)
+ count = count / 2;
+ while (count--) {
+ s32AudioSample = ((*psSrc) + (*(psSrc + 1))) / 2 + (s32)0x80;
+ if (s32AudioSample > 0x7fff)
s32AudioSample = 0x7fff;
*(pucDst++) = (u8)(((s16)s32AudioSample + (s16)0x8000) >> 8);
psSrc += 2;
@@ -1983,17 +1935,15 @@ static void CopySamples(char *dst, char *src, int count, unsigned fmt,
/*
* See if the data should be output at 16-bit signed mono.
*/
- else if(!(fmt & CS_FMT_STEREO) && (fmt & CS_FMT_16BIT))
- {
+ else if (!(fmt & CS_FMT_STEREO) && (fmt & CS_FMT_16BIT)) {
/*
* Convert each 16-bit signed stereo sample to 16-bit signed
* mono using averaging.
*/
psSrc = (s16 *)src;
- count = count/2;
- while(count--)
- {
- *(psDst++) = (s16)((*psSrc)+(*(psSrc + 1)))/2;
+ count = count / 2;
+ while (count--) {
+ *(psDst++) = (s16)((*psSrc) + (*(psSrc + 1))) / 2;
psSrc += 2;
}
}
@@ -2020,20 +1970,15 @@ static unsigned cs_copy_to_user(
"cs_copy_to_user()+ fmt=0x%x cnt=%d dest=%p\n",
dmabuf->fmt,(unsigned)cnt,dest) );
- if(cnt > dmabuf->dmasize)
- {
+ if (cnt > dmabuf->dmasize)
cnt = dmabuf->dmasize;
- }
- if(!cnt)
- {
+ if (!cnt) {
*copied = 0;
return 0;
}
- if(dmabuf->divisor != 1)
- {
- if(!dmabuf->tmpbuff)
- {
- *copied = cnt/dmabuf->divisor;
+ if (dmabuf->divisor != 1) {
+ if (!dmabuf->tmpbuff) {
+ *copied = cnt / dmabuf->divisor;
return 0;
}
@@ -2042,17 +1987,16 @@ static unsigned cs_copy_to_user(
src = dmabuf->tmpbuff;
cnt = cnt/dmabuf->divisor;
}
- if (copy_to_user(dest, src, cnt))
- {
+ if (copy_to_user(dest, src, cnt)) {
CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR
"cs46xx: cs_copy_to_user()- fault dest=%p src=%p cnt=%d\n",
- dest,src,cnt) );
+ dest,src,cnt));
*copied = 0;
return -EFAULT;
}
*copied = cnt;
CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO
- "cs46xx: cs_copy_to_user()- copied bytes is %d \n",cnt) );
+ "cs46xx: cs_copy_to_user()- copied bytes is %d \n",cnt));
return 0;
}
@@ -2060,7 +2004,7 @@ static unsigned cs_copy_to_user(
the user's buffer. it is filled by the dma machine and drained by this loop. */
static ssize_t cs_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
- struct cs_card *card = (struct cs_card *) file->private_data;
+ struct cs_card *card = file->private_data;
struct cs_state *state;
DECLARE_WAITQUEUE(wait, current);
struct dmabuf *dmabuf;
@@ -2068,12 +2012,12 @@ static ssize_t cs_read(struct file *file, char __user *buffer, size_t count, lof
unsigned long flags;
unsigned swptr;
int cnt;
- unsigned copied=0;
+ unsigned copied = 0;
CS_DBGOUT(CS_WAVE_READ | CS_FUNCTION, 4,
printk("cs46xx: cs_read()+ %zd\n",count) );
- state = (struct cs_state *)card->states[0];
- if(!state)
+ state = card->states[0];
+ if (!state)
return -ENODEV;
dmabuf = &state->dmabuf;
@@ -2088,11 +2032,11 @@ static ssize_t cs_read(struct file *file, char __user *buffer, size_t count, lof
add_wait_queue(&state->dmabuf.wait, &wait);
while (count > 0) {
- while(!(card->pm.flags & CS46XX_PM_IDLE))
- {
+ while (!(card->pm.flags & CS46XX_PM_IDLE)) {
schedule();
if (signal_pending(current)) {
- if(!ret) ret = -ERESTARTSYS;
+ if (!ret)
+ ret = -ERESTARTSYS;
goto out;
}
}
@@ -2112,19 +2056,20 @@ static ssize_t cs_read(struct file *file, char __user *buffer, size_t count, lof
recorded */
start_adc(state);
if (file->f_flags & O_NONBLOCK) {
- if (!ret) ret = -EAGAIN;
+ if (!ret)
+ ret = -EAGAIN;
goto out;
}
mutex_unlock(&state->sem);
schedule();
if (signal_pending(current)) {
- if(!ret) ret = -ERESTARTSYS;
+ if (!ret)
+ ret = -ERESTARTSYS;
goto out;
}
mutex_lock(&state->sem);
- if (dmabuf->mapped)
- {
- if(!ret)
+ if (dmabuf->mapped) {
+ if (!ret)
ret = -ENXIO;
goto out;
}
@@ -2135,12 +2080,12 @@ static ssize_t cs_read(struct file *file, char __user *buffer, size_t count, lof
"_read() copy_to cnt=%d count=%zd ", cnt,count) );
CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
" .dmasize=%d .count=%d buffer=%p ret=%zd\n",
- dmabuf->dmasize,dmabuf->count,buffer,ret) );
+ dmabuf->dmasize,dmabuf->count,buffer,ret));
if (cs_copy_to_user(state, buffer,
- (char *)dmabuf->rawbuf + swptr, cnt, &copied))
- {
- if (!ret) ret = -EFAULT;
+ (char *)dmabuf->rawbuf + swptr, cnt, &copied)) {
+ if (!ret)
+ ret = -EFAULT;
goto out;
}
swptr = (swptr + cnt) % dmabuf->dmasize;
@@ -2167,7 +2112,7 @@ out2:
the soundcard. it is drained by the dma machine and filled by this loop. */
static ssize_t cs_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
- struct cs_card *card = (struct cs_card *) file->private_data;
+ struct cs_card *card = file->private_data;
struct cs_state *state;
DECLARE_WAITQUEUE(wait, current);
struct dmabuf *dmabuf;
@@ -2178,16 +2123,15 @@ static ssize_t cs_write(struct file *file, const char __user *buffer, size_t cou
CS_DBGOUT(CS_WAVE_WRITE | CS_FUNCTION, 4,
printk("cs46xx: cs_write called, count = %zd\n", count) );
- state = (struct cs_state *)card->states[1];
- if(!state)
+ state = card->states[1];
+ if (!state)
return -ENODEV;
if (!access_ok(VERIFY_READ, buffer, count))
return -EFAULT;
dmabuf = &state->dmabuf;
mutex_lock(&state->sem);
- if (dmabuf->mapped)
- {
+ if (dmabuf->mapped) {
ret = -ENXIO;
goto out;
}
@@ -2201,11 +2145,11 @@ static ssize_t cs_write(struct file *file, const char __user *buffer, size_t cou
* check for PM events and underrun/overrun in the loop.
*/
while (count > 0) {
- while(!(card->pm.flags & CS46XX_PM_IDLE))
- {
+ while (!(card->pm.flags & CS46XX_PM_IDLE)) {
schedule();
if (signal_pending(current)) {
- if(!ret) ret = -ERESTARTSYS;
+ if (!ret)
+ ret = -ERESTARTSYS;
goto out;
}
}
@@ -2216,8 +2160,7 @@ static ssize_t cs_write(struct file *file, const char __user *buffer, size_t cou
dmabuf->count = 0;
dmabuf->swptr = dmabuf->hwptr;
}
- if (dmabuf->underrun)
- {
+ if (dmabuf->underrun) {
dmabuf->underrun = 0;
dmabuf->hwptr = cs_get_dma_addr(state);
dmabuf->swptr = dmabuf->hwptr;
@@ -2238,34 +2181,35 @@ static ssize_t cs_write(struct file *file, const char __user *buffer, size_t cou
played */
start_dac(state);
if (file->f_flags & O_NONBLOCK) {
- if (!ret) ret = -EAGAIN;
+ if (!ret)
+ ret = -EAGAIN;
goto out;
}
mutex_unlock(&state->sem);
schedule();
if (signal_pending(current)) {
- if(!ret) ret = -ERESTARTSYS;
+ if (!ret)
+ ret = -ERESTARTSYS;
goto out;
}
mutex_lock(&state->sem);
- if (dmabuf->mapped)
- {
- if(!ret)
+ if (dmabuf->mapped) {
+ if (!ret)
ret = -ENXIO;
goto out;
}
continue;
}
if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
- if (!ret) ret = -EFAULT;
+ if (!ret)
+ ret = -EFAULT;
goto out;
}
spin_lock_irqsave(&state->card->lock, flags);
swptr = (swptr + cnt) % dmabuf->dmasize;
dmabuf->swptr = swptr;
dmabuf->count += cnt;
- if(dmabuf->count > dmabuf->dmasize)
- {
+ if (dmabuf->count > dmabuf->dmasize) {
CS_DBGOUT(CS_WAVE_WRITE | CS_ERROR, 2, printk(
"cs46xx: cs_write() d->count > dmasize - resetting\n"));
dmabuf->count = dmabuf->dmasize;
@@ -2284,38 +2228,32 @@ out:
set_current_state(TASK_RUNNING);
CS_DBGOUT(CS_WAVE_WRITE | CS_FUNCTION, 2,
- printk("cs46xx: cs_write()- ret=%zd\n", ret) );
+ printk("cs46xx: cs_write()- ret=%zd\n", ret));
return ret;
}
static unsigned int cs_poll(struct file *file, struct poll_table_struct *wait)
{
- struct cs_card *card = (struct cs_card *)file->private_data;
+ struct cs_card *card = file->private_data;
struct dmabuf *dmabuf;
struct cs_state *state;
-
unsigned long flags;
unsigned int mask = 0;
CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_poll()+ \n"));
- if (!(file->f_mode & (FMODE_WRITE | FMODE_READ)))
- {
+ if (!(file->f_mode & (FMODE_WRITE | FMODE_READ))) {
return -EINVAL;
}
- if (file->f_mode & FMODE_WRITE)
- {
+ if (file->f_mode & FMODE_WRITE) {
state = card->states[1];
- if(state)
- {
+ if (state) {
dmabuf = &state->dmabuf;
poll_wait(file, &dmabuf->wait, wait);
}
}
- if (file->f_mode & FMODE_READ)
- {
+ if (file->f_mode & FMODE_READ) {
state = card->states[0];
- if(state)
- {
+ if (state) {
dmabuf = &state->dmabuf;
poll_wait(file, &dmabuf->wait, wait);
}
@@ -2325,8 +2263,7 @@ static unsigned int cs_poll(struct file *file, struct poll_table_struct *wait)
cs_update_ptr(card, CS_FALSE);
if (file->f_mode & FMODE_READ) {
state = card->states[0];
- if(state)
- {
+ if (state) {
dmabuf = &state->dmabuf;
if (dmabuf->count >= (signed)dmabuf->fragsize)
mask |= POLLIN | POLLRDNORM;
@@ -2334,8 +2271,7 @@ static unsigned int cs_poll(struct file *file, struct poll_table_struct *wait)
}
if (file->f_mode & FMODE_WRITE) {
state = card->states[1];
- if(state)
- {
+ if (state) {
dmabuf = &state->dmabuf;
if (dmabuf->mapped) {
if (dmabuf->count >= (signed)dmabuf->fragsize)
@@ -2364,7 +2300,7 @@ static unsigned int cs_poll(struct file *file, struct poll_table_struct *wait)
static int cs_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct cs_card *card = (struct cs_card *)file->private_data;
+ struct cs_card *card = file->private_data;
struct cs_state *state;
struct dmabuf *dmabuf;
int ret = 0;
@@ -2376,8 +2312,7 @@ static int cs_mmap(struct file *file, struct vm_area_struct *vma)
if (vma->vm_flags & VM_WRITE) {
state = card->states[1];
- if(state)
- {
+ if (state) {
CS_DBGOUT(CS_OPEN, 2, printk(
"cs46xx: cs_mmap() VM_WRITE - state TRUE prog_dmabuf DAC\n") );
if ((ret = prog_dmabuf(state)) != 0)
@@ -2385,8 +2320,7 @@ static int cs_mmap(struct file *file, struct vm_area_struct *vma)
}
} else if (vma->vm_flags & VM_READ) {
state = card->states[0];
- if(state)
- {
+ if (state) {
CS_DBGOUT(CS_OPEN, 2, printk(
"cs46xx: cs_mmap() VM_READ - state TRUE prog_dmabuf ADC\n") );
if ((ret = prog_dmabuf(state)) != 0)
@@ -2414,8 +2348,7 @@ static int cs_mmap(struct file *file, struct vm_area_struct *vma)
mutex_lock(&state->sem);
dmabuf = &state->dmabuf;
- if (cs4x_pgoff(vma) != 0)
- {
+ if (cs4x_pgoff(vma) != 0) {
ret = -EINVAL;
goto out;
}
@@ -2423,15 +2356,13 @@ static int cs_mmap(struct file *file, struct vm_area_struct *vma)
CS_DBGOUT(CS_PARMS, 2, printk("cs46xx: cs_mmap(): size=%d\n",(unsigned)size) );
- if (size > (PAGE_SIZE << dmabuf->buforder))
- {
+ if (size > (PAGE_SIZE << dmabuf->buforder)) {
ret = -EINVAL;
goto out;
}
if (remap_pfn_range(vma, vma->vm_start,
virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- {
+ size, vma->vm_page_prot)) {
ret = -EAGAIN;
goto out;
}
@@ -2445,25 +2376,24 @@ out:
static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
- struct cs_card *card = (struct cs_card *)file->private_data;
+ struct cs_card *card = file->private_data;
struct cs_state *state;
- struct dmabuf *dmabuf=NULL;
+ struct dmabuf *dmabuf = NULL;
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
- int val, valsave, mapped, ret;
+ int val, valsave, ret;
+ int mapped = 0;
void __user *argp = (void __user *)arg;
int __user *p = argp;
- state = (struct cs_state *)card->states[0];
- if(state)
- {
+ state = card->states[0];
+ if (state) {
dmabuf = &state->dmabuf;
mapped = (file->f_mode & FMODE_READ) && dmabuf->mapped;
}
- state = (struct cs_state *)card->states[1];
- if(state)
- {
+ state = card->states[1];
+ if (state) {
dmabuf = &state->dmabuf;
mapped |= (file->f_mode & FMODE_WRITE) && dmabuf->mapped;
}
@@ -2472,17 +2402,14 @@ static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
printioctl(cmd);
#endif
- switch (cmd)
- {
+ switch (cmd) {
case OSS_GETVERSION:
return put_user(SOUND_VERSION, p);
-
case SNDCTL_DSP_RESET:
/* FIXME: spin_lock ? */
if (file->f_mode & FMODE_WRITE) {
- state = (struct cs_state *)card->states[1];
- if(state)
- {
+ state = card->states[1];
+ if (state) {
dmabuf = &state->dmabuf;
stop_dac(state);
synchronize_irq(card->irq);
@@ -2495,9 +2422,8 @@ static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
}
}
if (file->f_mode & FMODE_READ) {
- state = (struct cs_state *)card->states[0];
- if(state)
- {
+ state = card->states[0];
+ if (state) {
dmabuf = &state->dmabuf;
stop_adc(state);
synchronize_irq(card->irq);
@@ -2511,20 +2437,17 @@ static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
}
CS_DBGOUT(CS_IOCTL, 2, printk("cs46xx: DSP_RESET()-\n") );
return 0;
-
case SNDCTL_DSP_SYNC:
if (file->f_mode & FMODE_WRITE)
return drain_dac(state, file->f_flags & O_NONBLOCK);
return 0;
-
case SNDCTL_DSP_SPEED: /* set sample rate */
if (get_user(val, p))
return -EFAULT;
if (val >= 0) {
if (file->f_mode & FMODE_READ) {
- state = (struct cs_state *)card->states[0];
- if(state)
- {
+ state = card->states[0];
+ if (state) {
dmabuf = &state->dmabuf;
stop_adc(state);
dmabuf->ready = 0;
@@ -2534,9 +2457,8 @@ static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
}
}
if (file->f_mode & FMODE_WRITE) {
- state = (struct cs_state *)card->states[1];
- if(state)
- {
+ state = card->states[1];
+ if (state) {
dmabuf = &state->dmabuf;
stop_dac(state);
dmabuf->ready = 0;
@@ -2553,19 +2475,17 @@ static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
return put_user(dmabuf->rate, p);
}
return put_user(0, p);
-
case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
if (get_user(val, p))
return -EFAULT;
if (file->f_mode & FMODE_WRITE) {
- state = (struct cs_state *)card->states[1];
- if(state)
- {
+ state = card->states[1];
+ if (state) {
dmabuf = &state->dmabuf;
stop_dac(state);
dmabuf->ready = 0;
dmabuf->SGok = 0;
- if(val)
+ if (val)
dmabuf->fmt |= CS_FMT_STEREO;
else
dmabuf->fmt &= ~CS_FMT_STEREO;
@@ -2577,14 +2497,13 @@ static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
}
}
if (file->f_mode & FMODE_READ) {
- state = (struct cs_state *)card->states[0];
- if(state)
- {
+ state = card->states[0];
+ if (state) {
dmabuf = &state->dmabuf;
stop_adc(state);
dmabuf->ready = 0;
dmabuf->SGok = 0;
- if(val)
+ if (val)
dmabuf->fmt |= CS_FMT_STEREO;
else
dmabuf->fmt &= ~CS_FMT_STEREO;
@@ -2596,12 +2515,10 @@ static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
}
}
return 0;
-
case SNDCTL_DSP_GETBLKSIZE:
if (file->f_mode & FMODE_WRITE) {
- state = (struct cs_state *)card->states[1];
- if(state)
- {
+ state = card->states[1];
+ if (state) {
dmabuf = &state->dmabuf;
if ((val = prog_dmabuf(state)))
return val;
@@ -2609,9 +2526,8 @@ static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
}
}
if (file->f_mode & FMODE_READ) {
- state = (struct cs_state *)card->states[0];
- if(state)
- {
+ state = card->states[0];
+ if (state) {
dmabuf = &state->dmabuf;
if ((val = prog_dmabuf(state)))
return val;
@@ -2620,10 +2536,8 @@ static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
}
}
return put_user(0, p);
-
case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
return put_user(AFMT_S16_LE | AFMT_U8, p);
-
case SNDCTL_DSP_SETFMT: /* Select sample format */
if (get_user(val, p))
return -EFAULT;
@@ -2635,88 +2549,75 @@ static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
val == AFMT_U8 ? "8Bit Unsigned" : "") );
valsave = val;
if (val != AFMT_QUERY) {
- if(val==AFMT_S16_LE || val==AFMT_U8)
- {
+ if (val==AFMT_S16_LE || val==AFMT_U8) {
if (file->f_mode & FMODE_WRITE) {
- state = (struct cs_state *)card->states[1];
- if(state)
- {
+ state = card->states[1];
+ if (state) {
dmabuf = &state->dmabuf;
stop_dac(state);
dmabuf->ready = 0;
dmabuf->SGok = 0;
- if(val==AFMT_S16_LE)
+ if (val == AFMT_S16_LE)
dmabuf->fmt |= CS_FMT_16BIT;
else
dmabuf->fmt &= ~CS_FMT_16BIT;
cs_set_divisor(dmabuf);
- if((ret = prog_dmabuf(state)))
+ if ((ret = prog_dmabuf(state)))
return ret;
}
}
if (file->f_mode & FMODE_READ) {
val = valsave;
- state = (struct cs_state *)card->states[0];
- if(state)
- {
+ state = card->states[0];
+ if (state) {
dmabuf = &state->dmabuf;
stop_adc(state);
dmabuf->ready = 0;
dmabuf->SGok = 0;
- if(val==AFMT_S16_LE)
+ if (val == AFMT_S16_LE)
dmabuf->fmt |= CS_FMT_16BIT;
else
dmabuf->fmt &= ~CS_FMT_16BIT;
cs_set_divisor(dmabuf);
- if((ret = prog_dmabuf(state)))
+ if ((ret = prog_dmabuf(state)))
return ret;
}
}
- }
- else
- {
+ } else {
CS_DBGOUT(CS_IOCTL | CS_ERROR, 2, printk(
"cs46xx: DSP_SETFMT() Unsupported format (0x%x)\n",
valsave) );
}
- }
- else
- {
- if(file->f_mode & FMODE_WRITE)
- {
- state = (struct cs_state *)card->states[1];
- if(state)
+ } else {
+ if (file->f_mode & FMODE_WRITE) {
+ state = card->states[1];
+ if (state)
dmabuf = &state->dmabuf;
- }
- else if(file->f_mode & FMODE_READ)
- {
- state = (struct cs_state *)card->states[0];
- if(state)
+ } else if (file->f_mode & FMODE_READ) {
+ state = card->states[0];
+ if (state)
dmabuf = &state->dmabuf;
}
}
- if(dmabuf)
- {
- if(dmabuf->fmt & CS_FMT_16BIT)
+ if (dmabuf) {
+ if (dmabuf->fmt & CS_FMT_16BIT)
return put_user(AFMT_S16_LE, p);
else
return put_user(AFMT_U8, p);
}
return put_user(0, p);
-
case SNDCTL_DSP_CHANNELS:
if (get_user(val, p))
return -EFAULT;
if (val != 0) {
if (file->f_mode & FMODE_WRITE) {
- state = (struct cs_state *)card->states[1];
- if(state)
- {
+ state = card->states[1];
+ if (state) {
dmabuf = &state->dmabuf;
stop_dac(state);
dmabuf->ready = 0;
dmabuf->SGok = 0;
- if(val>1)
+ if (val > 1)
dmabuf->fmt |= CS_FMT_STEREO;
else
dmabuf->fmt &= ~CS_FMT_STEREO;
@@ -2726,14 +2627,13 @@ static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
}
}
if (file->f_mode & FMODE_READ) {
- state = (struct cs_state *)card->states[0];
- if(state)
- {
+ state = card->states[0];
+ if (state) {
dmabuf = &state->dmabuf;
stop_adc(state);
dmabuf->ready = 0;
dmabuf->SGok = 0;
- if(val>1)
+ if (val > 1)
dmabuf->fmt |= CS_FMT_STEREO;
else
dmabuf->fmt &= ~CS_FMT_STEREO;
@@ -2745,19 +2645,16 @@ static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
}
return put_user((dmabuf->fmt & CS_FMT_STEREO) ? 2 : 1,
p);
-
case SNDCTL_DSP_POST:
/*
* There will be a longer than normal pause in the data.
* so... do nothing, because there is nothing that we can do.
*/
return 0;
-
case SNDCTL_DSP_SUBDIVIDE:
if (file->f_mode & FMODE_WRITE) {
- state = (struct cs_state *)card->states[1];
- if(state)
- {
+ state = card->states[1];
+ if (state) {
dmabuf = &state->dmabuf;
if (dmabuf->subdivision)
return -EINVAL;
@@ -2769,9 +2666,8 @@ static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
}
}
if (file->f_mode & FMODE_READ) {
- state = (struct cs_state *)card->states[0];
- if(state)
- {
+ state = card->states[0];
+ if (state) {
dmabuf = &state->dmabuf;
if (dmabuf->subdivision)
return -EINVAL;
@@ -2783,37 +2679,31 @@ static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
}
}
return 0;
-
case SNDCTL_DSP_SETFRAGMENT:
if (get_user(val, p))
return -EFAULT;
-
if (file->f_mode & FMODE_WRITE) {
- state = (struct cs_state *)card->states[1];
- if(state)
- {
+ state = card->states[1];
+ if (state) {
dmabuf = &state->dmabuf;
dmabuf->ossfragshift = val & 0xffff;
dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
}
}
if (file->f_mode & FMODE_READ) {
- state = (struct cs_state *)card->states[0];
- if(state)
- {
+ state = card->states[0];
+ if (state) {
dmabuf = &state->dmabuf;
dmabuf->ossfragshift = val & 0xffff;
dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
}
}
return 0;
-
case SNDCTL_DSP_GETOSPACE:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- state = (struct cs_state *)card->states[1];
- if(state)
- {
+ state = card->states[1];
+ if (state) {
dmabuf = &state->dmabuf;
spin_lock_irqsave(&state->card->lock, flags);
cs_update_ptr(card, CS_TRUE);
@@ -2832,13 +2722,11 @@ static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
}
return -ENODEV;
-
case SNDCTL_DSP_GETISPACE:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
- state = (struct cs_state *)card->states[0];
- if(state)
- {
+ state = card->states[0];
+ if (state) {
dmabuf = &state->dmabuf;
spin_lock_irqsave(&state->card->lock, flags);
cs_update_ptr(card, CS_TRUE);
@@ -2850,48 +2738,39 @@ static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
}
return -ENODEV;
-
case SNDCTL_DSP_NONBLOCK:
file->f_flags |= O_NONBLOCK;
return 0;
-
case SNDCTL_DSP_GETCAPS:
return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,
p);
-
case SNDCTL_DSP_GETTRIGGER:
val = 0;
CS_DBGOUT(CS_IOCTL, 2, printk("cs46xx: DSP_GETTRIGGER()+\n") );
- if (file->f_mode & FMODE_WRITE)
- {
- state = (struct cs_state *)card->states[1];
- if(state)
- {
+ if (file->f_mode & FMODE_WRITE) {
+ state = card->states[1];
+ if (state) {
dmabuf = &state->dmabuf;
- if(dmabuf->enable & DAC_RUNNING)
+ if (dmabuf->enable & DAC_RUNNING)
val |= PCM_ENABLE_INPUT;
}
}
- if (file->f_mode & FMODE_READ)
- {
- if(state)
- {
- state = (struct cs_state *)card->states[0];
+ if (file->f_mode & FMODE_READ) {
+ if (state) {
+ state = card->states[0];
dmabuf = &state->dmabuf;
- if(dmabuf->enable & ADC_RUNNING)
+ if (dmabuf->enable & ADC_RUNNING)
val |= PCM_ENABLE_OUTPUT;
}
}
CS_DBGOUT(CS_IOCTL, 2, printk("cs46xx: DSP_GETTRIGGER()- val=0x%x\n",val) );
return put_user(val, p);
-
case SNDCTL_DSP_SETTRIGGER:
if (get_user(val, p))
return -EFAULT;
if (file->f_mode & FMODE_READ) {
- state = (struct cs_state *)card->states[0];
- if(state)
- {
+ state = card->states[0];
+ if (state) {
dmabuf = &state->dmabuf;
if (val & PCM_ENABLE_INPUT) {
if (!dmabuf->ready && (ret = prog_dmabuf(state)))
@@ -2902,9 +2781,8 @@ static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
}
}
if (file->f_mode & FMODE_WRITE) {
- state = (struct cs_state *)card->states[1];
- if(state)
- {
+ state = card->states[1];
+ if (state) {
dmabuf = &state->dmabuf;
if (val & PCM_ENABLE_OUTPUT) {
if (!dmabuf->ready && (ret = prog_dmabuf(state)))
@@ -2915,13 +2793,11 @@ static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
}
}
return 0;
-
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
- state = (struct cs_state *)card->states[0];
- if(state)
- {
+ state = card->states[0];
+ if (state) {
dmabuf = &state->dmabuf;
spin_lock_irqsave(&state->card->lock, flags);
cs_update_ptr(card, CS_TRUE);
@@ -2934,28 +2810,23 @@ static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
return 0;
}
return -ENODEV;
-
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- state = (struct cs_state *)card->states[1];
- if(state)
- {
+ state = card->states[1];
+ if (state) {
dmabuf = &state->dmabuf;
spin_lock_irqsave(&state->card->lock, flags);
cs_update_ptr(card, CS_TRUE);
cinfo.bytes = dmabuf->total_bytes;
- if (dmabuf->mapped)
- {
+ if (dmabuf->mapped) {
cinfo.blocks = (cinfo.bytes >> dmabuf->fragshift)
- dmabuf->blocks;
CS_DBGOUT(CS_PARMS, 8,
printk("total_bytes=%d blocks=%d dmabuf->blocks=%d\n",
cinfo.bytes,cinfo.blocks,dmabuf->blocks) );
dmabuf->blocks = cinfo.bytes >> dmabuf->fragshift;
- }
- else
- {
+ } else {
cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
}
cinfo.ptr = dmabuf->hwptr;
@@ -2969,66 +2840,54 @@ static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
return 0;
}
return -ENODEV;
-
case SNDCTL_DSP_SETDUPLEX:
return 0;
-
case SNDCTL_DSP_GETODELAY:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- state = (struct cs_state *)card->states[1];
- if(state)
- {
+ state = card->states[1];
+ if (state) {
dmabuf = &state->dmabuf;
spin_lock_irqsave(&state->card->lock, flags);
cs_update_ptr(card, CS_TRUE);
val = dmabuf->count;
spin_unlock_irqrestore(&state->card->lock, flags);
- }
- else
+ } else
val = 0;
return put_user(val, p);
-
case SOUND_PCM_READ_RATE:
- if(file->f_mode & FMODE_READ)
- state = (struct cs_state *)card->states[0];
+ if (file->f_mode & FMODE_READ)
+ state = card->states[0];
else
- state = (struct cs_state *)card->states[1];
- if(state)
- {
+ state = card->states[1];
+ if (state) {
dmabuf = &state->dmabuf;
return put_user(dmabuf->rate, p);
}
return put_user(0, p);
-
-
case SOUND_PCM_READ_CHANNELS:
- if(file->f_mode & FMODE_READ)
- state = (struct cs_state *)card->states[0];
+ if (file->f_mode & FMODE_READ)
+ state = card->states[0];
else
- state = (struct cs_state *)card->states[1];
- if(state)
- {
+ state = card->states[1];
+ if (state) {
dmabuf = &state->dmabuf;
return put_user((dmabuf->fmt & CS_FMT_STEREO) ? 2 : 1,
p);
}
return put_user(0, p);
-
case SOUND_PCM_READ_BITS:
- if(file->f_mode & FMODE_READ)
- state = (struct cs_state *)card->states[0];
+ if (file->f_mode & FMODE_READ)
+ state = card->states[0];
else
- state = (struct cs_state *)card->states[1];
- if(state)
- {
+ state = card->states[1];
+ if (state) {
dmabuf = &state->dmabuf;
return put_user((dmabuf->fmt & CS_FMT_16BIT) ?
AFMT_S16_LE : AFMT_U8, p);
}
return put_user(0, p);
-
case SNDCTL_DSP_MAPINBUF:
case SNDCTL_DSP_MAPOUTBUF:
case SNDCTL_DSP_SETSYNCRO:
@@ -3057,18 +2916,15 @@ static void amp_voyetra(struct cs_card *card, int change)
/* Manage the EAPD bit on the Crystal 4297
and the Analog AD1885 */
- int old=card->amplifier;
+ int old = card->amplifier;
card->amplifier+=change;
- if(card->amplifier && !old)
- {
+ if (card->amplifier && !old) {
/* Turn the EAPD amp on */
cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL,
cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) |
0x8000);
- }
- else if(old && !card->amplifier)
- {
+ } else if(old && !card->amplifier) {
/* Turn the EAPD amp off */
cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL,
cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
@@ -3083,25 +2939,21 @@ static void amp_voyetra(struct cs_card *card, int change)
static void amp_hercules(struct cs_card *card, int change)
{
- int old=card->amplifier;
- if(!card)
- {
+ int old = card->amplifier;
+ if (!card) {
CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO
"cs46xx: amp_hercules() called before initialized.\n"));
return;
}
card->amplifier+=change;
- if( (card->amplifier && !old) && !(hercules_egpio_disable))
- {
+ if ((card->amplifier && !old) && !(hercules_egpio_disable)) {
CS_DBGOUT(CS_PARMS, 4, printk(KERN_INFO
"cs46xx: amp_hercules() external amp enabled\n"));
cs461x_pokeBA0(card, BA0_EGPIODR,
EGPIODR_GPOE2); /* enable EGPIO2 output */
cs461x_pokeBA0(card, BA0_EGPIOPTR,
EGPIOPTR_GPPT2); /* open-drain on output */
- }
- else if(old && !card->amplifier)
- {
+ } else if (old && !card->amplifier) {
CS_DBGOUT(CS_PARMS, 4, printk(KERN_INFO
"cs46xx: amp_hercules() external amp disabled\n"));
cs461x_pokeBA0(card, BA0_EGPIODR, 0); /* disable */
@@ -3124,31 +2976,28 @@ static void clkrun_hack(struct cs_card *card, int change)
u16 control;
u8 pp;
unsigned long port;
- int old=card->active;
+ int old = card->active;
card->active+=change;
acpi_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
- if(acpi_dev == NULL)
+ if (acpi_dev == NULL)
return; /* Not a thinkpad thats for sure */
/* Find the control port */
pci_read_config_byte(acpi_dev, 0x41, &pp);
- port=pp<<8;
+ port = pp << 8;
/* Read ACPI port */
- control=inw(port+0x10);
+ control = inw(port + 0x10);
/* Flip CLKRUN off while running */
- if(!card->active && old)
- {
+ if (!card->active && old) {
CS_DBGOUT(CS_PARMS , 9, printk( KERN_INFO
"cs46xx: clkrun() enable clkrun - change=%d active=%d\n",
change,card->active));
outw(control|0x2000, port+0x10);
- }
- else
- {
+ } else {
/*
* sometimes on a resume the bit is set, so always reset the bit.
*/
@@ -3162,20 +3011,19 @@ static void clkrun_hack(struct cs_card *card, int change)
static int cs_open(struct inode *inode, struct file *file)
{
- struct cs_card *card = (struct cs_card *)file->private_data;
+ struct cs_card *card = file->private_data;
struct cs_state *state = NULL;
struct dmabuf *dmabuf = NULL;
struct list_head *entry;
unsigned int minor = iminor(inode);
- int ret=0;
+ int ret = 0;
unsigned int tmp;
CS_DBGOUT(CS_OPEN | CS_FUNCTION, 2, printk("cs46xx: cs_open()+ file=%p %s %s\n",
file, file->f_mode & FMODE_WRITE ? "FMODE_WRITE" : "",
file->f_mode & FMODE_READ ? "FMODE_READ" : "") );
- list_for_each(entry, &cs46xx_devs)
- {
+ list_for_each(entry, &cs46xx_devs) {
card = list_entry(entry, struct cs_card, list);
if (!((card->dev_audio ^ minor) & ~0xf))
@@ -3192,11 +3040,10 @@ static int cs_open(struct inode *inode, struct file *file)
/*
* hardcode state[0] for capture, [1] for playback
*/
- if(file->f_mode & FMODE_READ)
- {
+ if (file->f_mode & FMODE_READ) {
CS_DBGOUT(CS_WAVE_READ, 2, printk("cs46xx: cs_open() FMODE_READ\n") );
if (card->states[0] == NULL) {
- state = card->states[0] = (struct cs_state *)
+ state = card->states[0] =
kmalloc(sizeof(struct cs_state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
@@ -3204,36 +3051,32 @@ static int cs_open(struct inode *inode, struct file *file)
mutex_init(&state->sem);
dmabuf = &state->dmabuf;
dmabuf->pbuf = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
- if(dmabuf->pbuf==NULL)
- {
+ if (dmabuf->pbuf == NULL) {
kfree(state);
- card->states[0]=NULL;
+ card->states[0] = NULL;
return -ENOMEM;
}
- }
- else
- {
+ } else {
state = card->states[0];
- if(state->open_mode & FMODE_READ)
+ if (state->open_mode & FMODE_READ)
return -EBUSY;
}
dmabuf->channel = card->alloc_rec_pcm_channel(card);
if (dmabuf->channel == NULL) {
- kfree (card->states[0]);
+ kfree(card->states[0]);
card->states[0] = NULL;
return -ENODEV;
}
/* Now turn on external AMP if needed */
state->card = card;
- state->card->active_ctrl(state->card,1);
- state->card->amplifier_ctrl(state->card,1);
+ state->card->active_ctrl(state->card, 1);
+ state->card->amplifier_ctrl(state->card, 1);
- if( (tmp = cs46xx_powerup(card, CS_POWER_ADC)) )
- {
+ if ((tmp = cs46xx_powerup(card, CS_POWER_ADC))) {
CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
- "cs46xx: cs46xx_powerup of ADC failed (0x%x)\n",tmp) );
+ "cs46xx: cs46xx_powerup of ADC failed (0x%x)\n", tmp));
return -EIO;
}
@@ -3263,11 +3106,10 @@ static int cs_open(struct inode *inode, struct file *file)
state->open_mode |= FMODE_READ;
mutex_unlock(&state->open_mutex);
}
- if(file->f_mode & FMODE_WRITE)
- {
+ if (file->f_mode & FMODE_WRITE) {
CS_DBGOUT(CS_OPEN, 2, printk("cs46xx: cs_open() FMODE_WRITE\n") );
if (card->states[1] == NULL) {
- state = card->states[1] = (struct cs_state *)
+ state = card->states[1] =
kmalloc(sizeof(struct cs_state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
@@ -3275,36 +3117,32 @@ static int cs_open(struct inode *inode, struct file *file)
mutex_init(&state->sem);
dmabuf = &state->dmabuf;
dmabuf->pbuf = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
- if(dmabuf->pbuf==NULL)
- {
+ if (dmabuf->pbuf == NULL) {
kfree(state);
- card->states[1]=NULL;
+ card->states[1] = NULL;
return -ENOMEM;
}
- }
- else
- {
+ } else {
state = card->states[1];
- if(state->open_mode & FMODE_WRITE)
+ if (state->open_mode & FMODE_WRITE)
return -EBUSY;
}
dmabuf->channel = card->alloc_pcm_channel(card);
if (dmabuf->channel == NULL) {
- kfree (card->states[1]);
+ kfree(card->states[1]);
card->states[1] = NULL;
return -ENODEV;
}
/* Now turn on external AMP if needed */
state->card = card;
- state->card->active_ctrl(state->card,1);
- state->card->amplifier_ctrl(state->card,1);
+ state->card->active_ctrl(state->card, 1);
+ state->card->amplifier_ctrl(state->card, 1);
- if( (tmp = cs46xx_powerup(card, CS_POWER_DAC)) )
- {
+ if ((tmp = cs46xx_powerup(card, CS_POWER_DAC))) {
CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
- "cs46xx: cs46xx_powerup of DAC failed (0x%x)\n",tmp) );
+ "cs46xx: cs46xx_powerup of DAC failed (0x%x)\n", tmp));
return -EIO;
}
@@ -3333,33 +3171,29 @@ static int cs_open(struct inode *inode, struct file *file)
state->open_mode |= FMODE_WRITE;
mutex_unlock(&state->open_mutex);
- if((ret = prog_dmabuf(state)))
+ if ((ret = prog_dmabuf(state)))
return ret;
}
- CS_DBGOUT(CS_OPEN | CS_FUNCTION, 2, printk("cs46xx: cs_open()- 0\n") );
+ CS_DBGOUT(CS_OPEN | CS_FUNCTION, 2, printk("cs46xx: cs_open()- 0\n"));
return nonseekable_open(inode, file);
}
static int cs_release(struct inode *inode, struct file *file)
{
- struct cs_card *card = (struct cs_card *)file->private_data;
+ struct cs_card *card = file->private_data;
struct dmabuf *dmabuf;
struct cs_state *state;
unsigned int tmp;
CS_DBGOUT(CS_RELEASE | CS_FUNCTION, 2, printk("cs46xx: cs_release()+ file=%p %s %s\n",
file, file->f_mode & FMODE_WRITE ? "FMODE_WRITE" : "",
- file->f_mode & FMODE_READ ? "FMODE_READ" : "") );
+ file->f_mode & FMODE_READ ? "FMODE_READ" : ""));
if (!(file->f_mode & (FMODE_WRITE | FMODE_READ)))
- {
return -EINVAL;
- }
state = card->states[1];
- if(state)
- {
- if ( (state->open_mode & FMODE_WRITE) & (file->f_mode & FMODE_WRITE) )
- {
- CS_DBGOUT(CS_RELEASE, 2, printk("cs46xx: cs_release() FMODE_WRITE\n") );
+ if (state) {
+ if ((state->open_mode & FMODE_WRITE) & (file->f_mode & FMODE_WRITE)) {
+ CS_DBGOUT(CS_RELEASE, 2, printk("cs46xx: cs_release() FMODE_WRITE\n"));
dmabuf = &state->dmabuf;
cs_clear_tail(state);
drain_dac(state, file->f_flags & O_NONBLOCK);
@@ -3375,8 +3209,7 @@ static int cs_release(struct inode *inode, struct file *file)
state->card->states[state->virt] = NULL;
state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
- if( (tmp = cs461x_powerdown(card, CS_POWER_DAC, CS_FALSE )) )
- {
+ if ((tmp = cs461x_powerdown(card, CS_POWER_DAC, CS_FALSE))) {
CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
"cs46xx: cs_release_mixdev() powerdown DAC failure (0x%x)\n",tmp) );
}
@@ -3384,17 +3217,14 @@ static int cs_release(struct inode *inode, struct file *file)
/* Now turn off external AMP if needed */
state->card->amplifier_ctrl(state->card, -1);
state->card->active_ctrl(state->card, -1);
-
kfree(state);
}
}
state = card->states[0];
- if(state)
- {
- if ( (state->open_mode & FMODE_READ) & (file->f_mode & FMODE_READ) )
- {
- CS_DBGOUT(CS_RELEASE, 2, printk("cs46xx: cs_release() FMODE_READ\n") );
+ if (state) {
+ if ((state->open_mode & FMODE_READ) & (file->f_mode & FMODE_READ)) {
+ CS_DBGOUT(CS_RELEASE, 2, printk("cs46xx: cs_release() FMODE_READ\n"));
dmabuf = &state->dmabuf;
mutex_lock(&state->open_mutex);
stop_adc(state);
@@ -3407,8 +3237,7 @@ static int cs_release(struct inode *inode, struct file *file)
state->card->states[state->virt] = NULL;
state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
- if( (tmp = cs461x_powerdown(card, CS_POWER_ADC, CS_FALSE )) )
- {
+ if ((tmp = cs461x_powerdown(card, CS_POWER_ADC, CS_FALSE))) {
CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
"cs46xx: cs_release_mixdev() powerdown ADC failure (0x%x)\n",tmp) );
}
@@ -3416,12 +3245,11 @@ static int cs_release(struct inode *inode, struct file *file)
/* Now turn off external AMP if needed */
state->card->amplifier_ctrl(state->card, -1);
state->card->active_ctrl(state->card, -1);
-
kfree(state);
}
}
- CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 2, printk("cs46xx: cs_release()- 0\n") );
+ CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 2, printk("cs46xx: cs_release()- 0\n"));
return 0;
}
@@ -3474,21 +3302,18 @@ static void cs46xx_ac97_suspend(struct cs_card *card)
CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_suspend()+\n"));
- if(card->states[1])
- {
+ if (card->states[1]) {
stop_dac(card->states[1]);
resync_dma_ptrs(card->states[1]);
}
- if(card->states[0])
- {
+ if (card->states[0]) {
stop_adc(card->states[0]);
resync_dma_ptrs(card->states[0]);
}
- for(Count = 0x2, i=0; (Count <= CS46XX_AC97_HIGHESTREGTORESTORE)
- && (i < CS46XX_AC97_NUMBER_RESTORE_REGS);
- Count += 2, i++)
- {
+ for (Count = 0x2, i = 0; (Count <= CS46XX_AC97_HIGHESTREGTORESTORE)
+ && (i < CS46XX_AC97_NUMBER_RESTORE_REGS);
+ Count += 2, i++) {
card->pm.ac97[i] = cs_ac97_get(dev, BA0_AC97_RESET + Count);
}
/*
@@ -3522,11 +3347,10 @@ static void cs46xx_ac97_suspend(struct cs_card *card)
* well, for now, only power down the DAC/ADC and MIXER VREFON components.
* trouble with removing VREF.
*/
- if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
- CS_POWER_MIXVON, CS_TRUE )) )
- {
+ if ((tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
+ CS_POWER_MIXVON, CS_TRUE))) {
CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
- "cs46xx: cs46xx_ac97_suspend() failure (0x%x)\n",tmp) );
+ "cs46xx: cs46xx_ac97_suspend() failure (0x%x)\n",tmp));
}
CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_suspend()-\n"));
@@ -3566,16 +3390,13 @@ static void cs46xx_ac97_resume(struct cs_card *card)
* Restore just the first set of registers, from register number
* 0x02 to the register number that ulHighestRegToRestore specifies.
*/
- for( Count = 0x2, i=0;
- (Count <= CS46XX_AC97_HIGHESTREGTORESTORE)
- && (i < CS46XX_AC97_NUMBER_RESTORE_REGS);
- Count += 2, i++)
- {
+ for (Count = 0x2, i=0; (Count <= CS46XX_AC97_HIGHESTREGTORESTORE) &&
+ (i < CS46XX_AC97_NUMBER_RESTORE_REGS); Count += 2, i++) {
cs_ac97_set(dev, (u8)(BA0_AC97_RESET + Count), (u16)card->pm.ac97[i]);
}
/* Check if we have to init the amplifier */
- if(card->amp_init)
+ if (card->amp_init)
card->amp_init(card);
CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_resume()-\n"));
@@ -3585,30 +3406,27 @@ static void cs46xx_ac97_resume(struct cs_card *card)
static int cs46xx_restart_part(struct cs_card *card)
{
struct dmabuf *dmabuf;
+
CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
printk( "cs46xx: cs46xx_restart_part()+\n"));
- if(card->states[1])
- {
+ if (card->states[1]) {
dmabuf = &card->states[1]->dmabuf;
dmabuf->ready = 0;
resync_dma_ptrs(card->states[1]);
cs_set_divisor(dmabuf);
- if(__prog_dmabuf(card->states[1]))
- {
+ if (__prog_dmabuf(card->states[1])) {
CS_DBGOUT(CS_PM | CS_ERROR, 1,
printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() dac error\n"));
return -1;
}
cs_set_dac_rate(card->states[1], dmabuf->rate);
}
- if(card->states[0])
- {
+ if (card->states[0]) {
dmabuf = &card->states[0]->dmabuf;
dmabuf->ready = 0;
resync_dma_ptrs(card->states[0]);
cs_set_divisor(dmabuf);
- if(__prog_dmabuf(card->states[0]))
- {
+ if (__prog_dmabuf(card->states[0])) {
CS_DBGOUT(CS_PM | CS_ERROR, 1,
printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() adc error\n"));
return -1;
@@ -3616,17 +3434,17 @@ static int cs46xx_restart_part(struct cs_card *card)
cs_set_adc_rate(card->states[0], dmabuf->rate);
}
card->pm.flags |= CS46XX_PM_RESUMED;
- if(card->states[0])
+ if (card->states[0])
start_adc(card->states[0]);
- if(card->states[1])
+ if (card->states[1])
start_dac(card->states[1]);
card->pm.flags |= CS46XX_PM_IDLE;
card->pm.flags &= ~(CS46XX_PM_SUSPENDING | CS46XX_PM_SUSPENDED
| CS46XX_PM_RESUMING | CS46XX_PM_RESUMED);
- if(card->states[0])
+ if (card->states[0])
wake_up(&card->states[0]->dmabuf.wait);
- if(card->states[1])
+ if (card->states[1])
wake_up(&card->states[1]->dmabuf.wait);
CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
@@ -3634,20 +3452,19 @@ static int cs46xx_restart_part(struct cs_card *card)
return 0;
}
-
static void cs461x_reset(struct cs_card *card);
static void cs461x_proc_stop(struct cs_card *card);
static int cs46xx_suspend(struct cs_card *card, pm_message_t state)
{
unsigned int tmp;
+
CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
printk("cs46xx: cs46xx_suspend()+ flags=0x%x s=%p\n",
(unsigned)card->pm.flags,card));
/*
* check the current state, only suspend if IDLE
*/
- if(!(card->pm.flags & CS46XX_PM_IDLE))
- {
+ if (!(card->pm.flags & CS46XX_PM_IDLE)) {
CS_DBGOUT(CS_PM | CS_ERROR, 2,
printk("cs46xx: cs46xx_suspend() unable to suspend, not IDLE\n"));
return 1;
@@ -3679,13 +3496,11 @@ static int cs46xx_suspend(struct cs_card *card, pm_message_t state)
tmp = cs461x_peek(card, BA1_CCTL);
cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000);
- if(card->states[1])
- {
+ if (card->states[1]) {
card->pm.dmabuf_swptr_play = card->states[1]->dmabuf.swptr;
card->pm.dmabuf_count_play = card->states[1]->dmabuf.count;
}
- if(card->states[0])
- {
+ if (card->states[0]) {
card->pm.dmabuf_swptr_capture = card->states[0]->dmabuf.swptr;
card->pm.dmabuf_count_capture = card->states[0]->dmabuf.count;
}
@@ -3736,8 +3551,7 @@ static int cs46xx_resume(struct cs_card *card)
CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
printk( "cs46xx: cs46xx_resume()+ flags=0x%x\n",
(unsigned)card->pm.flags));
- if(!(card->pm.flags & CS46XX_PM_SUSPENDED))
- {
+ if (!(card->pm.flags & CS46XX_PM_SUSPENDED)) {
CS_DBGOUT(CS_PM | CS_ERROR, 2,
printk("cs46xx: cs46xx_resume() unable to resume, not SUSPENDED\n"));
return 1;
@@ -3747,10 +3561,8 @@ static int cs46xx_resume(struct cs_card *card)
printpm(card);
card->active_ctrl(card, 1);
- for(i=0;i<5;i++)
- {
- if (cs_hardware_init(card) != 0)
- {
+ for (i = 0; i < 5; i++) {
+ if (cs_hardware_init(card) != 0) {
CS_DBGOUT(CS_PM | CS_ERROR, 4, printk(
"cs46xx: cs46xx_resume()- ERROR in cs_hardware_init()\n"));
mdelay(10 * cs_laptop_wait);
@@ -3759,15 +3571,13 @@ static int cs46xx_resume(struct cs_card *card)
}
break;
}
- if(i>=4)
- {
+ if (i >= 4) {
CS_DBGOUT(CS_PM | CS_ERROR, 1, printk(
"cs46xx: cs46xx_resume()- cs_hardware_init() failed, retried %d times.\n",i));
return 0;
}
- if(cs46xx_restart_part(card))
- {
+ if (cs46xx_restart_part(card)) {
CS_DBGOUT(CS_PM | CS_ERROR, 4, printk(
"cs46xx: cs46xx_resume(): cs46xx_restart_part() returned error\n"));
}
@@ -3835,7 +3645,7 @@ static u16 _cs_ac97_get(struct ac97_codec *dev, u8 reg)
/*
* Wait for the read to occur.
*/
- if(!(card->pm.flags & CS46XX_PM_IDLE))
+ if (!(card->pm.flags & CS46XX_PM_IDLE))
loopcnt = 2000;
else
loopcnt = 500 * cs_laptop_wait;
@@ -3866,7 +3676,7 @@ static u16 _cs_ac97_get(struct ac97_codec *dev, u8 reg)
* Wait for the valid status bit to go active.
*/
- if(!(card->pm.flags & CS46XX_PM_IDLE))
+ if (!(card->pm.flags & CS46XX_PM_IDLE))
loopcnt = 2000;
else
loopcnt = 1000;
@@ -3885,7 +3695,7 @@ static u16 _cs_ac97_get(struct ac97_codec *dev, u8 reg)
/*
* Make sure we got valid status.
*/
- if (!( (tmp=cs461x_peekBA0(card, BA0_ACSTS)) & ACSTS_VSTS)) {
+ if (!((tmp = cs461x_peekBA0(card, BA0_ACSTS)) & ACSTS_VSTS)) {
CS_DBGOUT(CS_ERROR, 2, printk(KERN_WARNING
"cs46xx: AC'97 read problem (ACSTS_VSTS), reg = 0x%x val=0x%x 0xffff \n",
reg, tmp));
@@ -3923,12 +3733,9 @@ static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 val)
spin_lock(&card->ac97_lock);
- if(reg == AC97_CD_VOL)
- {
+ if (reg == AC97_CD_VOL)
val2 = _cs_ac97_get(dev, AC97_CD_VOL);
- }
-
-
+
/*
* 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
* 2. Write ACCDA = Command Data Register = 470h for data to write to AC97
@@ -3970,8 +3777,7 @@ static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 val)
/*
* Make sure the write completed.
*/
- if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV)
- {
+ if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV) {
CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
"cs46xx: AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val));
}
@@ -3998,25 +3804,23 @@ static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 val)
/* CD mute change ? */
- if(reg==AC97_CD_VOL)
- {
+ if (reg == AC97_CD_VOL) {
/* Mute bit change ? */
- if((val2^val)&0x8000 || ((val2 == 0x1f1f || val == 0x1f1f) && val2 != val))
- {
+ if ((val2^val) & 0x8000 ||
+ ((val2 == 0x1f1f || val == 0x1f1f) && val2 != val)) {
/* This is a hack but its cleaner than the alternatives.
Right now card->ac97_codec[0] might be NULL as we are
still doing codec setup. This does an early assignment
to avoid the problem if it occurs */
- if(card->ac97_codec[0]==NULL)
- card->ac97_codec[0]=dev;
+ if (card->ac97_codec[0] == NULL)
+ card->ac97_codec[0] = dev;
/* Mute on */
- if(val&0x8000 || val == 0x1f1f)
+ if (val & 0x8000 || val == 0x1f1f)
card->amplifier_ctrl(card, -1);
- else /* Mute off power on */
- {
- if(card->amp_init)
+ else { /* Mute off power on */
+ if (card->amp_init)
card->amp_init(card);
card->amplifier_ctrl(card, 1);
}
@@ -4024,46 +3828,41 @@ static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 val)
}
}
-
/* OSS /dev/mixer file operation methods */
static int cs_open_mixdev(struct inode *inode, struct file *file)
{
- int i=0;
+ int i = 0;
unsigned int minor = iminor(inode);
- struct cs_card *card=NULL;
+ struct cs_card *card = NULL;
struct list_head *entry;
unsigned int tmp;
CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
printk(KERN_INFO "cs46xx: cs_open_mixdev()+\n"));
- list_for_each(entry, &cs46xx_devs)
- {
+ list_for_each(entry, &cs46xx_devs) {
card = list_entry(entry, struct cs_card, list);
for (i = 0; i < NR_AC97; i++)
if (card->ac97_codec[i] != NULL &&
card->ac97_codec[i]->dev_mixer == minor)
goto match;
}
- if (!card)
- {
+ if (!card) {
CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
printk(KERN_INFO "cs46xx: cs46xx_open_mixdev()- -ENODEV\n"));
return -ENODEV;
}
match:
- if(!card->ac97_codec[i])
+ if (!card->ac97_codec[i])
return -ENODEV;
file->private_data = card->ac97_codec[i];
card->active_ctrl(card,1);
- if(!CS_IN_USE(&card->mixer_use_cnt))
- {
- if( (tmp = cs46xx_powerup(card, CS_POWER_MIXVON )) )
- {
+ if (!CS_IN_USE(&card->mixer_use_cnt)) {
+ if ((tmp = cs46xx_powerup(card, CS_POWER_MIXVON))) {
CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
- "cs46xx: cs_open_mixdev() powerup failure (0x%x)\n",tmp) );
+ "cs46xx: cs_open_mixdev() powerup failure (0x%x)\n", tmp));
return -EIO;
}
}
@@ -4077,7 +3876,7 @@ static int cs_open_mixdev(struct inode *inode, struct file *file)
static int cs_release_mixdev(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
- struct cs_card *card=NULL;
+ struct cs_card *card = NULL;
struct list_head *entry;
int i;
unsigned int tmp;
@@ -4092,15 +3891,13 @@ static int cs_release_mixdev(struct inode *inode, struct file *file)
card->ac97_codec[i]->dev_mixer == minor)
goto match;
}
- if (!card)
- {
+ if (!card) {
CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
printk(KERN_INFO "cs46xx: cs46xx_open_mixdev()- -ENODEV\n"));
return -ENODEV;
}
match:
- if(!CS_DEC_AND_TEST(&card->mixer_use_cnt))
- {
+ if (!CS_DEC_AND_TEST(&card->mixer_use_cnt)) {
CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
printk(KERN_INFO "cs46xx: cs_release_mixdev()- no powerdown, usecnt>0\n"));
card->active_ctrl(card, -1);
@@ -4110,10 +3907,9 @@ match:
/*
* ok, no outstanding mixer opens, so powerdown.
*/
- if( (tmp = cs461x_powerdown(card, CS_POWER_MIXVON, CS_FALSE )) )
- {
+ if ((tmp = cs461x_powerdown(card, CS_POWER_MIXVON, CS_FALSE))) {
CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
- "cs46xx: cs_release_mixdev() powerdown MIXVON failure (0x%x)\n",tmp) );
+ "cs46xx: cs_release_mixdev() powerdown MIXVON failure (0x%x)\n", tmp));
card->active_ctrl(card, -1);
card->amplifier_ctrl(card, -1);
return -EIO;
@@ -4126,76 +3922,60 @@ match:
}
static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
+ unsigned long arg)
{
- struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
- struct cs_card *card=NULL;
+ struct ac97_codec *codec = file->private_data;
+ struct cs_card *card = NULL;
struct list_head *entry;
unsigned long __user *p = (long __user *)arg;
-
#if CSDEBUG_INTERFACE
int val;
- if( (cmd == SOUND_MIXER_CS_GETDBGMASK) ||
+ if ( (cmd == SOUND_MIXER_CS_GETDBGMASK) ||
(cmd == SOUND_MIXER_CS_SETDBGMASK) ||
(cmd == SOUND_MIXER_CS_GETDBGLEVEL) ||
(cmd == SOUND_MIXER_CS_SETDBGLEVEL) ||
- (cmd == SOUND_MIXER_CS_APM))
- {
- switch(cmd)
- {
-
+ (cmd == SOUND_MIXER_CS_APM)) {
+ switch (cmd) {
case SOUND_MIXER_CS_GETDBGMASK:
return put_user(cs_debugmask, p);
-
case SOUND_MIXER_CS_GETDBGLEVEL:
return put_user(cs_debuglevel, p);
-
case SOUND_MIXER_CS_SETDBGMASK:
if (get_user(val, p))
return -EFAULT;
cs_debugmask = val;
return 0;
-
case SOUND_MIXER_CS_SETDBGLEVEL:
if (get_user(val, p))
return -EFAULT;
cs_debuglevel = val;
return 0;
-
case SOUND_MIXER_CS_APM:
if (get_user(val, p))
return -EFAULT;
- if(val == CS_IOCTL_CMD_SUSPEND)
- {
- list_for_each(entry, &cs46xx_devs)
- {
+ if (val == CS_IOCTL_CMD_SUSPEND) {
+ list_for_each(entry, &cs46xx_devs) {
card = list_entry(entry, struct cs_card, list);
cs46xx_suspend(card, PMSG_ON);
}
- }
- else if(val == CS_IOCTL_CMD_RESUME)
- {
- list_for_each(entry, &cs46xx_devs)
- {
+ } else if (val == CS_IOCTL_CMD_RESUME) {
+ list_for_each(entry, &cs46xx_devs) {
card = list_entry(entry, struct cs_card, list);
cs46xx_resume(card);
}
- }
- else
- {
+ } else {
CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
"cs46xx: mixer_ioctl(): invalid APM cmd (%d)\n",
val));
}
return 0;
-
default:
CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
- "cs46xx: mixer_ioctl(): ERROR unknown debug cmd\n") );
+ "cs46xx: mixer_ioctl(): ERROR unknown debug cmd\n"));
return 0;
- }
+ }
}
#endif
return codec->mixer_ioctl(codec, cmd, arg);
@@ -4232,8 +4012,7 @@ static int __init cs_ac97_init(struct cs_card *card)
codec->codec_read = cs_ac97_get;
codec->codec_write = cs_ac97_set;
- if (ac97_probe_codec(codec) == 0)
- {
+ if (ac97_probe_codec(codec) == 0) {
CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
"cs46xx: cs_ac97_init()- codec number %d not found\n",
num_ac97) );
@@ -4241,12 +4020,11 @@ static int __init cs_ac97_init(struct cs_card *card)
break;
}
CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
- "cs46xx: cs_ac97_init() found codec %d\n",num_ac97) );
+ "cs46xx: cs_ac97_init() found codec %d\n",num_ac97));
eid = cs_ac97_get(codec, AC97_EXTENDED_ID);
- if(eid==0xFFFF)
- {
+ if (eid == 0xFFFF) {
printk(KERN_WARNING "cs46xx: codec %d not present\n",num_ac97);
ac97_release_codec(codec);
break;
@@ -4285,27 +4063,23 @@ static void cs461x_download_image(struct cs_card *card)
{
unsigned i, j, temp1, temp2, offset, count;
unsigned char __iomem *pBA1 = ioremap(card->ba1_addr, 0x40000);
- for( i=0; i < CLEAR__COUNT; i++)
- {
+ for (i = 0; i < CLEAR__COUNT; i++) {
offset = ClrStat[i].BA1__DestByteOffset;
count = ClrStat[i].BA1__SourceSize;
- for( temp1 = offset; temp1<(offset+count); temp1+=4 )
+ for (temp1 = offset; temp1 < (offset + count); temp1 += 4)
writel(0, pBA1+temp1);
}
- for(i=0; i<FILL__COUNT; i++)
- {
+ for (i = 0; i < FILL__COUNT; i++) {
temp2 = FillStat[i].Offset;
- for(j=0; j<(FillStat[i].Size)/4; j++)
- {
+ for (j = 0; j < (FillStat[i].Size) / 4; j++) {
temp1 = (FillStat[i]).pFill[j];
- writel(temp1, pBA1+temp2+j*4);
+ writel(temp1, pBA1+temp2 + j * 4);
}
}
iounmap(pBA1);
}
-
/*
* Chip reset
*/
@@ -4365,15 +4139,13 @@ static void cs461x_clear_serial_FIFOs(struct cs_card *card, int type)
* playing or capturing then we don't want to put in 128 bytes of
* "noise".
*/
- if(type & CS_TYPE_DAC)
- {
+ if (type & CS_TYPE_DAC) {
startfifo = 128;
endfifo = 256;
}
- if(type & CS_TYPE_ADC)
- {
+ if (type & CS_TYPE_ADC) {
startfifo = 0;
- if(!endfifo)
+ if (!endfifo)
endfifo = 128;
}
/*
@@ -4417,8 +4189,7 @@ static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspend
CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
"cs46xx: cs461x_powerdown()+ type=0x%x\n",type));
- if(!cs_powerdown && !suspendflag)
- {
+ if (!cs_powerdown && !suspendflag) {
CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO
"cs46xx: cs461x_powerdown() DISABLED exiting\n"));
return 0;
@@ -4432,12 +4203,11 @@ static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspend
* currently powered down. If powering down DAC and ADC, then
* it is possible to power down the VREF (ON).
*/
- if ( ((type & CS_POWER_MIXVON) &&
- (!(type & CS_POWER_ADC) || (!(type & CS_POWER_DAC))) )
+ if (((type & CS_POWER_MIXVON) &&
+ (!(type & CS_POWER_ADC) || (!(type & CS_POWER_DAC))))
&&
((tmp & CS_AC97_POWER_CONTROL_ADC_ON) ||
- (tmp & CS_AC97_POWER_CONTROL_DAC_ON) ) )
- {
+ (tmp & CS_AC97_POWER_CONTROL_DAC_ON))) {
CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO
"cs46xx: cs461x_powerdown()- 0 unable to powerdown. tmp=0x%x\n",tmp));
return 0;
@@ -4452,8 +4222,7 @@ static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspend
/*
* Power down indicated areas.
*/
- if(type & CS_POWER_MIXVOFF)
- {
+ if (type & CS_POWER_MIXVOFF) {
CS_DBGOUT(CS_FUNCTION, 4,
printk(KERN_INFO "cs46xx: cs461x_powerdown()+ MIXVOFF\n"));
@@ -4461,12 +4230,10 @@ static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspend
* Power down the MIXER (VREF ON) on the AC97 card.
*/
tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- if (tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON)
- {
- if(!muted)
- {
+ if (tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON) {
+ if (!muted) {
cs_mute(card, CS_TRUE);
- muted=1;
+ muted = 1;
}
tmp |= CS_AC97_POWER_CONTROL_MIXVOFF;
cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
@@ -4492,16 +4259,14 @@ static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspend
* Check the status..
*/
if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_MIXVOFF_ON)
- {
+ CS_AC97_POWER_CONTROL_MIXVOFF_ON) {
CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
"cs46xx: powerdown MIXVOFF failed\n"));
return 1;
}
}
}
- if(type & CS_POWER_MIXVON)
- {
+ if (type & CS_POWER_MIXVON) {
CS_DBGOUT(CS_FUNCTION, 4,
printk(KERN_INFO "cs46xx: cs461x_powerdown()+ MIXVON\n"));
@@ -4509,15 +4274,13 @@ static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspend
* Power down the MIXER (VREF ON) on the AC97 card.
*/
tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- if (tmp & CS_AC97_POWER_CONTROL_MIXVON_ON)
- {
- if(!muted)
- {
+ if (tmp & CS_AC97_POWER_CONTROL_MIXVON_ON) {
+ if (!muted) {
cs_mute(card, CS_TRUE);
- muted=1;
+ muted = 1;
}
tmp |= CS_AC97_POWER_CONTROL_MIXVON;
- cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
+ cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp);
/*
* Now, we wait until we sample a ready state.
*/
@@ -4540,30 +4303,26 @@ static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspend
* Check the status..
*/
if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_MIXVON_ON)
- {
+ CS_AC97_POWER_CONTROL_MIXVON_ON) {
CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
"cs46xx: powerdown MIXVON failed\n"));
return 1;
}
}
}
- if(type & CS_POWER_ADC)
- {
+ if (type & CS_POWER_ADC) {
/*
* Power down the ADC on the AC97 card.
*/
CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO "cs46xx: cs461x_powerdown()+ ADC\n"));
tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- if (tmp & CS_AC97_POWER_CONTROL_ADC_ON)
- {
- if(!muted)
- {
+ if (tmp & CS_AC97_POWER_CONTROL_ADC_ON) {
+ if (!muted) {
cs_mute(card, CS_TRUE);
- muted=1;
+ muted = 1;
}
tmp |= CS_AC97_POWER_CONTROL_ADC;
- cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
+ cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp);
/*
* Now, we wait until we sample a ready state.
@@ -4587,16 +4346,14 @@ static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspend
* Check the status..
*/
if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_ADC_ON)
- {
+ CS_AC97_POWER_CONTROL_ADC_ON) {
CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
"cs46xx: powerdown ADC failed\n"));
return 1;
}
}
}
- if(type & CS_POWER_DAC)
- {
+ if (type & CS_POWER_DAC) {
/*
* Power down the DAC on the AC97 card.
*/
@@ -4604,15 +4361,13 @@ static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspend
CS_DBGOUT(CS_FUNCTION, 4,
printk(KERN_INFO "cs46xx: cs461x_powerdown()+ DAC\n"));
tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- if (tmp & CS_AC97_POWER_CONTROL_DAC_ON)
- {
- if(!muted)
- {
+ if (tmp & CS_AC97_POWER_CONTROL_DAC_ON) {
+ if (!muted) {
cs_mute(card, CS_TRUE);
- muted=1;
+ muted = 1;
}
tmp |= CS_AC97_POWER_CONTROL_DAC;
- cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
+ cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp);
/*
* Now, we wait until we sample a ready state.
*/
@@ -4635,8 +4390,7 @@ static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspend
* Check the status..
*/
if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_DAC_ON)
- {
+ CS_AC97_POWER_CONTROL_DAC_ON) {
CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
"cs46xx: powerdown DAC failed\n"));
return 1;
@@ -4644,7 +4398,7 @@ static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspend
}
}
tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- if(muted)
+ if (muted)
cs_mute(card, CS_FALSE);
CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
"cs46xx: cs461x_powerdown()- 0 tmp=0x%x\n",tmp));
@@ -4654,23 +4408,22 @@ static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspend
static int cs46xx_powerup(struct cs_card *card, unsigned int type)
{
int count;
- unsigned int tmp=0,muted=0;
+ unsigned int tmp = 0, muted = 0;
CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO
"cs46xx: cs46xx_powerup()+ type=0x%x\n",type));
/*
* check for VREF and powerup if need to.
*/
- if(type & CS_POWER_MIXVON)
+ if (type & CS_POWER_MIXVON)
type |= CS_POWER_MIXVOFF;
- if(type & (CS_POWER_DAC | CS_POWER_ADC))
+ if (type & (CS_POWER_DAC | CS_POWER_ADC))
type |= CS_POWER_MIXVON | CS_POWER_MIXVOFF;
/*
* Power up indicated areas.
*/
- if(type & CS_POWER_MIXVOFF)
- {
+ if (type & CS_POWER_MIXVOFF) {
CS_DBGOUT(CS_FUNCTION, 4,
printk(KERN_INFO "cs46xx: cs46xx_powerup()+ MIXVOFF\n"));
@@ -4678,12 +4431,10 @@ static int cs46xx_powerup(struct cs_card *card, unsigned int type)
* Power up the MIXER (VREF ON) on the AC97 card.
*/
tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- if (!(tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON))
- {
- if(!muted)
- {
+ if (!(tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON)) {
+ if (!muted) {
cs_mute(card, CS_TRUE);
- muted=1;
+ muted = 1;
}
tmp &= ~CS_AC97_POWER_CONTROL_MIXVOFF;
cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
@@ -4709,16 +4460,14 @@ static int cs46xx_powerup(struct cs_card *card, unsigned int type)
* Check the status..
*/
if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_MIXVOFF_ON))
- {
+ CS_AC97_POWER_CONTROL_MIXVOFF_ON)) {
CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
"cs46xx: powerup MIXVOFF failed\n"));
return 1;
}
}
}
- if(type & CS_POWER_MIXVON)
- {
+ if(type & CS_POWER_MIXVON) {
CS_DBGOUT(CS_FUNCTION, 4,
printk(KERN_INFO "cs46xx: cs46xx_powerup()+ MIXVON\n"));
@@ -4726,12 +4475,10 @@ static int cs46xx_powerup(struct cs_card *card, unsigned int type)
* Power up the MIXER (VREF ON) on the AC97 card.
*/
tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- if (!(tmp & CS_AC97_POWER_CONTROL_MIXVON_ON))
- {
- if(!muted)
- {
+ if (!(tmp & CS_AC97_POWER_CONTROL_MIXVON_ON)) {
+ if (!muted) {
cs_mute(card, CS_TRUE);
- muted=1;
+ muted = 1;
}
tmp &= ~CS_AC97_POWER_CONTROL_MIXVON;
cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
@@ -4757,27 +4504,23 @@ static int cs46xx_powerup(struct cs_card *card, unsigned int type)
* Check the status..
*/
if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_MIXVON_ON))
- {
+ CS_AC97_POWER_CONTROL_MIXVON_ON)) {
CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
"cs46xx: powerup MIXVON failed\n"));
return 1;
}
}
}
- if(type & CS_POWER_ADC)
- {
+ if (type & CS_POWER_ADC) {
/*
* Power up the ADC on the AC97 card.
*/
CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO "cs46xx: cs46xx_powerup()+ ADC\n"));
tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- if (!(tmp & CS_AC97_POWER_CONTROL_ADC_ON))
- {
- if(!muted)
- {
+ if (!(tmp & CS_AC97_POWER_CONTROL_ADC_ON)) {
+ if (!muted) {
cs_mute(card, CS_TRUE);
- muted=1;
+ muted = 1;
}
tmp &= ~CS_AC97_POWER_CONTROL_ADC;
cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
@@ -4804,16 +4547,14 @@ static int cs46xx_powerup(struct cs_card *card, unsigned int type)
* Check the status..
*/
if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_ADC_ON))
- {
+ CS_AC97_POWER_CONTROL_ADC_ON)) {
CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
"cs46xx: powerup ADC failed\n"));
return 1;
}
}
}
- if(type & CS_POWER_DAC)
- {
+ if (type & CS_POWER_DAC) {
/*
* Power up the DAC on the AC97 card.
*/
@@ -4821,12 +4562,10 @@ static int cs46xx_powerup(struct cs_card *card, unsigned int type)
CS_DBGOUT(CS_FUNCTION, 4,
printk(KERN_INFO "cs46xx: cs46xx_powerup()+ DAC\n"));
tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- if (!(tmp & CS_AC97_POWER_CONTROL_DAC_ON))
- {
- if(!muted)
- {
+ if (!(tmp & CS_AC97_POWER_CONTROL_DAC_ON)) {
+ if (!muted) {
cs_mute(card, CS_TRUE);
- muted=1;
+ muted = 1;
}
tmp &= ~CS_AC97_POWER_CONTROL_DAC;
cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
@@ -4852,8 +4591,7 @@ static int cs46xx_powerup(struct cs_card *card, unsigned int type)
* Check the status..
*/
if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_DAC_ON))
- {
+ CS_AC97_POWER_CONTROL_DAC_ON)) {
CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
"cs46xx: powerup DAC failed\n"));
return 1;
@@ -4861,14 +4599,13 @@ static int cs46xx_powerup(struct cs_card *card, unsigned int type)
}
}
tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- if(muted)
+ if (muted)
cs_mute(card, CS_FALSE);
CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
"cs46xx: cs46xx_powerup()- 0 tmp=0x%x\n",tmp));
return 0;
}
-
static void cs461x_proc_start(struct cs_card *card)
{
int cnt;
@@ -4965,7 +4702,7 @@ static int cs_hardware_init(struct cs_card *card)
* is not enough for some platforms! tested on an IBM Thinkpads and
* reference cards.
*/
- if(!(card->pm.flags & CS46XX_PM_IDLE))
+ if (!(card->pm.flags & CS46XX_PM_IDLE))
mdelay(initdelay);
/*
* Write the selected clock control setup to the hardware. Do not turn on
@@ -5017,8 +4754,7 @@ static int cs_hardware_init(struct cs_card *card)
* If we are resuming under 2.2.x then we can not schedule a timeout.
* so, just spin the CPU.
*/
- if(card->pm.flags & CS46XX_PM_IDLE)
- {
+ if (card->pm.flags & CS46XX_PM_IDLE) {
/*
* Wait for the card ready signal from the AC97 card.
*/
@@ -5033,9 +4769,7 @@ static int cs_hardware_init(struct cs_card *card)
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout(1);
} while (time_before(jiffies, end_time));
- }
- else
- {
+ } else {
for (count = 0; count < 100; count++) {
// First, we want to wait for a short time.
udelay(25 * cs_laptop_wait);
@@ -5064,8 +4798,7 @@ static int cs_hardware_init(struct cs_card *card)
*/
cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
- if(card->pm.flags & CS46XX_PM_IDLE)
- {
+ if (card->pm.flags & CS46XX_PM_IDLE) {
/*
* Wait until we've sampled input slots 3 and 4 as valid, meaning that
* the card is pumping ADC data across the AC-link.
@@ -5081,9 +4814,7 @@ static int cs_hardware_init(struct cs_card *card)
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout(1);
} while (time_before(jiffies, end_time));
- }
- else
- {
+ } else {
for (count = 0; count < 100; count++) {
// First, we want to wait for a short time.
udelay(25 * cs_laptop_wait);
@@ -5140,17 +4871,13 @@ static int cs_hardware_init(struct cs_card *card)
cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000);
/* initialize AC97 codec and register /dev/mixer */
- if(card->pm.flags & CS46XX_PM_IDLE)
- {
- if (cs_ac97_init(card) <= 0)
- {
+ if (card->pm.flags & CS46XX_PM_IDLE) {
+ if (cs_ac97_init(card) <= 0) {
CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
- "cs46xx: cs_ac97_init() failure\n") );
+ "cs46xx: cs_ac97_init() failure\n"));
return -EIO;
}
- }
- else
- {
+ } else {
cs46xx_ac97_resume(card);
}
@@ -5174,23 +4901,17 @@ static int cs_hardware_init(struct cs_card *card)
* If IDLE then Power down the part. We will power components up
* when we need them.
*/
- if(card->pm.flags & CS46XX_PM_IDLE)
- {
- if(!cs_powerdown)
- {
- if( (tmp = cs46xx_powerup(card, CS_POWER_DAC | CS_POWER_ADC |
- CS_POWER_MIXVON )) )
- {
+ if (card->pm.flags & CS46XX_PM_IDLE) {
+ if (!cs_powerdown) {
+ if ((tmp = cs46xx_powerup(card, CS_POWER_DAC | CS_POWER_ADC |
+ CS_POWER_MIXVON))) {
CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
"cs46xx: cs461x_powerup() failure (0x%x)\n",tmp) );
return -EIO;
}
- }
- else
- {
- if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
- CS_POWER_MIXVON, CS_FALSE )) )
- {
+ } else {
+ if ((tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
+ CS_POWER_MIXVON, CS_FALSE))) {
CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
"cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) );
return -EIO;
@@ -5310,14 +5031,13 @@ MODULE_AUTHOR("Alan Cox <alan@redhat.com>, Jaroslav Kysela, <pcaudio@crystal.cir
MODULE_DESCRIPTION("Crystal SoundFusion Audio Support");
MODULE_LICENSE("GPL");
-
static const char cs46xx_banner[] = KERN_INFO "Crystal 4280/46xx + AC97 Audio, version " CS46XX_MAJOR_VERSION "." CS46XX_MINOR_VERSION "." CS46XX_ARCH ", " __TIME__ " " __DATE__ "\n";
static const char fndmsg[] = KERN_INFO "cs46xx: Found %d audio device(s).\n";
static int __devinit cs46xx_probe(struct pci_dev *pci_dev,
const struct pci_device_id *pciid)
{
- int i,j;
+ int i, j;
u16 ss_card, ss_vendor;
struct cs_card *card;
dma_addr_t dma_mask;
@@ -5378,42 +5098,35 @@ static int __devinit cs46xx_probe(struct pci_dev *pci_dev,
while (cp->name)
{
- if(cp->vendor == ss_vendor && cp->id == ss_card)
- {
+ if (cp->vendor == ss_vendor && cp->id == ss_card) {
card->amplifier_ctrl = cp->amp;
- if(cp->active)
+ if (cp->active)
card->active_ctrl = cp->active;
- if(cp->amp_init)
+ if (cp->amp_init)
card->amp_init = cp->amp_init;
break;
}
cp++;
}
- if (cp->name==NULL)
- {
+ if (cp->name == NULL) {
printk(KERN_INFO "cs46xx: Unknown card (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n",
ss_vendor, ss_card, card->ba0_addr, card->ba1_addr, card->irq);
- }
- else
- {
+ } else {
printk(KERN_INFO "cs46xx: %s (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n",
cp->name, ss_vendor, ss_card, card->ba0_addr, card->ba1_addr, card->irq);
}
- if (card->amplifier_ctrl==NULL)
- {
+ if (card->amplifier_ctrl == NULL) {
card->amplifier_ctrl = amp_none;
card->active_ctrl = clkrun_hack;
}
- if (external_amp == 1)
- {
+ if (external_amp == 1) {
printk(KERN_INFO "cs46xx: Crystal EAPD support forced on.\n");
card->amplifier_ctrl = amp_voyetra;
}
- if (thinkpad == 1)
- {
+ if (thinkpad == 1) {
printk(KERN_INFO "cs46xx: Activating CLKRUN hack for Thinkpad.\n");
card->active_ctrl = clkrun_hack;
}
@@ -5425,13 +5138,11 @@ static int __devinit cs46xx_probe(struct pci_dev *pci_dev,
* and mdelay kernel code is replaced by a pm timer, or the delays
* work well for battery and/or AC power both.
*/
- if(card->active_ctrl == clkrun_hack)
- {
+ if (card->active_ctrl == clkrun_hack) {
initdelay = 2100;
cs_laptop_wait = 5;
}
- if((card->active_ctrl == clkrun_hack) && !(powerdown == 1))
- {
+ if ((card->active_ctrl == clkrun_hack) && !(powerdown == 1)) {
/*
* for some currently unknown reason, powering down the DAC and ADC component
* blocks on thinkpads causes some funky behavior... distoorrrtion and ac97
@@ -5440,7 +5151,7 @@ static int __devinit cs46xx_probe(struct pci_dev *pci_dev,
*/
cs_powerdown = 0;
}
- if(powerdown == 0)
+ if (powerdown == 0)
cs_powerdown = 0;
card->active_ctrl(card, 1);
@@ -5461,7 +5172,7 @@ static int __devinit cs46xx_probe(struct pci_dev *pci_dev,
card->ba1.name.pmem,
card->ba1.name.reg) );
- if(card->ba0 == 0 || card->ba1.name.data0 == 0 ||
+ if (card->ba0 == 0 || card->ba1.name.data0 == 0 ||
card->ba1.name.data1 == 0 || card->ba1.name.pmem == 0 ||
card->ba1.name.reg == 0)
goto fail2;
@@ -5477,14 +5188,12 @@ static int __devinit cs46xx_probe(struct pci_dev *pci_dev,
}
/* register /dev/midi */
- if((card->dev_midi = register_sound_midi(&cs_midi_fops, -1)) < 0)
+ if ((card->dev_midi = register_sound_midi(&cs_midi_fops, -1)) < 0)
printk(KERN_ERR "cs46xx: unable to register midi\n");
card->pm.flags |= CS46XX_PM_IDLE;
- for(i=0;i<5;i++)
- {
- if (cs_hardware_init(card) != 0)
- {
+ for (i = 0; i < 5; i++) {
+ if (cs_hardware_init(card) != 0) {
CS_DBGOUT(CS_ERROR, 4, printk(
"cs46xx: ERROR in cs_hardware_init()... retrying\n"));
for (j = 0; j < NR_AC97; j++)
@@ -5497,12 +5206,11 @@ static int __devinit cs46xx_probe(struct pci_dev *pci_dev,
}
break;
}
- if(i>=4)
- {
+ if(i >= 4) {
CS_DBGOUT(CS_PM | CS_ERROR, 1, printk(
"cs46xx: cs46xx_probe()- cs_hardware_init() failed, retried %d times.\n",i));
unregister_sound_dsp(card->dev_audio);
- if(card->dev_midi)
+ if (card->dev_midi)
unregister_sound_midi(card->dev_midi);
goto fail;
}
@@ -5518,7 +5226,7 @@ static int __devinit cs46xx_probe(struct pci_dev *pci_dev,
* Check if we have to init the amplifier, but probably already done
* since the CD logic in the ac97 init code will turn on the ext amp.
*/
- if(cp->amp_init)
+ if (cp->amp_init)
cp->amp_init(card);
card->active_ctrl(card, -1);
@@ -5536,15 +5244,15 @@ static int __devinit cs46xx_probe(struct pci_dev *pci_dev,
fail:
free_irq(card->irq, card);
fail2:
- if(card->ba0)
+ if (card->ba0)
iounmap(card->ba0);
- if(card->ba1.name.data0)
+ if (card->ba1.name.data0)
iounmap(card->ba1.name.data0);
- if(card->ba1.name.data1)
+ if (card->ba1.name.data1)
iounmap(card->ba1.name.data1);
- if(card->ba1.name.pmem)
+ if (card->ba1.name.pmem)
iounmap(card->ba1.name.pmem);
- if(card->ba1.name.reg)
+ if (card->ba1.name.reg)
iounmap(card->ba1.name.reg);
kfree(card);
CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO
@@ -5598,9 +5306,8 @@ static void __devexit cs46xx_remove(struct pci_dev *pci_dev)
* Power down the DAC and ADC. We will power them up (if) when we need
* them.
*/
- if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
- CS_POWER_MIXVON, CS_TRUE )) )
- {
+ if ((tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
+ CS_POWER_MIXVON, CS_TRUE))) {
CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
"cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) );
}
@@ -5634,7 +5341,7 @@ static void __devexit cs46xx_remove(struct pci_dev *pci_dev)
ac97_release_codec(card->ac97_codec[i]);
}
unregister_sound_dsp(card->dev_audio);
- if(card->dev_midi)
+ if (card->dev_midi)
unregister_sound_midi(card->dev_midi);
list_del(&card->list);
kfree(card);
@@ -5693,8 +5400,7 @@ static int __init cs46xx_init_module(void)
"cs46xx: cs46xx_init_module()+ \n"));
rtn = pci_register_driver(&cs46xx_pci_driver);
- if(rtn == -ENODEV)
- {
+ if (rtn == -ENODEV) {
CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(
"cs46xx: Unable to detect valid cs46xx device\n"));
}
diff --git a/sound/oss/emu10k1/midi.c b/sound/oss/emu10k1/midi.c
index 25ae8e4..8ac77df 100644
--- a/sound/oss/emu10k1/midi.c
+++ b/sound/oss/emu10k1/midi.c
@@ -45,7 +45,7 @@
#include "../sound_config.h"
#endif
-static DEFINE_SPINLOCK(midi_spinlock __attribute((unused)));
+static DEFINE_SPINLOCK(midi_spinlock);
static void init_midi_hdr(struct midi_hdr *midihdr)
{
diff --git a/sound/oss/msnd.c b/sound/oss/msnd.c
index 5dbfc0f..ba38d62 100644
--- a/sound/oss/msnd.c
+++ b/sound/oss/msnd.c
@@ -47,7 +47,7 @@
static multisound_dev_t *devs[MSND_MAX_DEVS];
static int num_devs;
-int __init msnd_register(multisound_dev_t *dev)
+int msnd_register(multisound_dev_t *dev)
{
int i;
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index a208180..d37346b 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -216,14 +216,19 @@ config SND_CS46XX_NEW_DSP
This works better than the old code, so say Y.
config SND_CS5535AUDIO
- tristate "CS5535 Audio"
+ tristate "CS5535/CS5536 Audio"
depends on SND && X86 && !X86_64
select SND_PCM
select SND_AC97_CODEC
help
Say Y here to include support for audio on CS5535 chips. It is
referred to as NS CS5535 IO or AMD CS5535 IO companion in
- various literature.
+ various literature. This driver also supports the CS5536 audio
+ device. However, for both chips, on certain boards, you may
+ need to use ac97_quirk=hp_only if your board has physically
+ mapped headphone out to master output. If that works for you,
+ send lspci -vvv output to the mailing list so that your board
+ can be identified in the quirks list.
To compile this driver as a module, choose M here: the module
will be called snd-cs5535audio.
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index d052007..0abf280 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -253,6 +253,8 @@ void snd_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short va
ac97->bus->ops->write(ac97, reg, value);
}
+EXPORT_SYMBOL(snd_ac97_write);
+
/**
* snd_ac97_read - read a value from the given register
*
@@ -281,6 +283,8 @@ static inline unsigned short snd_ac97_read_cache(struct snd_ac97 *ac97, unsigned
return ac97->regs[reg];
}
+EXPORT_SYMBOL(snd_ac97_read);
+
/**
* snd_ac97_write_cache - write a value on the given register and update the cache
* @ac97: the ac97 instance
@@ -302,6 +306,8 @@ void snd_ac97_write_cache(struct snd_ac97 *ac97, unsigned short reg, unsigned sh
mutex_unlock(&ac97->reg_mutex);
}
+EXPORT_SYMBOL(snd_ac97_write_cache);
+
/**
* snd_ac97_update - update the value on the given register
* @ac97: the ac97 instance
@@ -331,6 +337,8 @@ int snd_ac97_update(struct snd_ac97 *ac97, unsigned short reg, unsigned short va
return change;
}
+EXPORT_SYMBOL(snd_ac97_update);
+
/**
* snd_ac97_update_bits - update the bits on the given register
* @ac97: the ac97 instance
@@ -356,6 +364,8 @@ int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned sho
return change;
}
+EXPORT_SYMBOL(snd_ac97_update_bits);
+
/* no lock version - see snd_ac97_updat_bits() */
int snd_ac97_update_bits_nolock(struct snd_ac97 *ac97, unsigned short reg,
unsigned short mask, unsigned short value)
@@ -563,7 +573,7 @@ AC97_SINGLE("PC Speaker Playback Volume", AC97_PC_BEEP, 1, 15, 1)
};
static const struct snd_kcontrol_new snd_ac97_controls_mic_boost =
- AC97_SINGLE("Mic Boost (+20dB)", AC97_MIC, 6, 1, 0);
+ AC97_SINGLE("Mic Boost (+20dB) Switch", AC97_MIC, 6, 1, 0);
static const char* std_rec_sel[] = {"Mic", "CD", "Video", "Aux", "Line", "Mix", "Mix Mono", "Phone"};
@@ -605,7 +615,7 @@ AC97_SINGLE("Simulated Stereo Enhancement", AC97_GENERAL_PURPOSE, 14, 1, 0),
AC97_SINGLE("3D Control - Switch", AC97_GENERAL_PURPOSE, 13, 1, 0),
AC97_SINGLE("Loudness (bass boost)", AC97_GENERAL_PURPOSE, 12, 1, 0),
AC97_ENUM("Mono Output Select", std_enum[2]),
-AC97_ENUM("Mic Select", std_enum[3]),
+AC97_ENUM("Mic Select Capture Switch", std_enum[3]),
AC97_SINGLE("ADC/DAC Loopback", AC97_GENERAL_PURPOSE, 7, 1, 0)
};
@@ -1226,7 +1236,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
ac97->regs[AC97_CENTER_LFE_MASTER] = 0x8080;
/* build center controls */
- if (snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER)) {
+ if ((snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER))
+ && !(ac97->flags & AC97_AD_MULTI)) {
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_center[0], ac97))) < 0)
return err;
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_center[1], ac97))) < 0)
@@ -1238,7 +1249,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
}
/* build LFE controls */
- if (snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER+1)) {
+ if ((snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER+1))
+ && !(ac97->flags & AC97_AD_MULTI)) {
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_lfe[0], ac97))) < 0)
return err;
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_lfe[1], ac97))) < 0)
@@ -1250,7 +1262,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
}
/* build surround controls */
- if (snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER)) {
+ if ((snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER))
+ && !(ac97->flags & AC97_AD_MULTI)) {
/* Surround Master (0x38) is with stereo mutes */
if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback", AC97_SURROUND_MASTER, 1, ac97)) < 0)
return err;
@@ -1335,9 +1348,11 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
}
/* build Aux controls */
- if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) {
- if ((err = snd_ac97_cmix_new(card, "Aux Playback", AC97_AUX, ac97)) < 0)
- return err;
+ if (!(ac97->flags & AC97_HAS_NO_AUX)) {
+ if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) {
+ if ((err = snd_ac97_cmix_new(card, "Aux Playback", AC97_AUX, ac97)) < 0)
+ return err;
+ }
}
/* build PCM controls */
@@ -1682,6 +1697,7 @@ const char *snd_ac97_get_short_name(struct snd_ac97 *ac97)
return "unknown codec";
}
+EXPORT_SYMBOL(snd_ac97_get_short_name);
/* wait for a while until registers are accessible after RESET
* return 0 if ok, negative not ready
@@ -1774,6 +1790,8 @@ int snd_ac97_bus(struct snd_card *card, int num, struct snd_ac97_bus_ops *ops,
return 0;
}
+EXPORT_SYMBOL(snd_ac97_bus);
+
/* stop no dev release warning */
static void ac97_device_release(struct device * dev)
{
@@ -2117,6 +2135,7 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
return 0;
}
+EXPORT_SYMBOL(snd_ac97_mixer);
/*
* Power down the chip.
@@ -2166,6 +2185,8 @@ void snd_ac97_suspend(struct snd_ac97 *ac97)
snd_ac97_powerdown(ac97);
}
+EXPORT_SYMBOL(snd_ac97_suspend);
+
/*
* restore ac97 status
*/
@@ -2267,6 +2288,8 @@ __reset_ready:
snd_ac97_restore_iec958(ac97);
}
}
+
+EXPORT_SYMBOL(snd_ac97_resume);
#endif
@@ -2590,29 +2613,7 @@ int snd_ac97_tune_hardware(struct snd_ac97 *ac97, struct ac97_quirk *quirk, cons
return 0;
}
-
-/*
- * Exported symbols
- */
-
-EXPORT_SYMBOL(snd_ac97_write);
-EXPORT_SYMBOL(snd_ac97_read);
-EXPORT_SYMBOL(snd_ac97_write_cache);
-EXPORT_SYMBOL(snd_ac97_update);
-EXPORT_SYMBOL(snd_ac97_update_bits);
-EXPORT_SYMBOL(snd_ac97_get_short_name);
-EXPORT_SYMBOL(snd_ac97_bus);
-EXPORT_SYMBOL(snd_ac97_mixer);
-EXPORT_SYMBOL(snd_ac97_pcm_assign);
-EXPORT_SYMBOL(snd_ac97_pcm_open);
-EXPORT_SYMBOL(snd_ac97_pcm_close);
-EXPORT_SYMBOL(snd_ac97_pcm_double_rate_rules);
EXPORT_SYMBOL(snd_ac97_tune_hardware);
-EXPORT_SYMBOL(snd_ac97_set_rate);
-#ifdef CONFIG_PM
-EXPORT_SYMBOL(snd_ac97_resume);
-EXPORT_SYMBOL(snd_ac97_suspend);
-#endif
/*
* INIT part
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index 4d9cf37..7f197c7 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -464,6 +464,10 @@ int patch_wolfson05(struct snd_ac97 * ac97)
{
/* WM9705, WM9710 */
ac97->build_ops = &patch_wolfson_wm9705_ops;
+#ifdef CONFIG_TOUCHSCREEN_WM9705
+ /* WM9705 touchscreen uses AUX and VIDEO for touch */
+ ac97->flags |=3D AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX;
+#endif
return 0;
}
@@ -1367,6 +1371,13 @@ static void ad18xx_resume(struct snd_ac97 *ac97)
snd_ac97_restore_iec958(ac97);
}
+
+static void ad1888_resume(struct snd_ac97 *ac97)
+{
+ ad18xx_resume(ac97);
+ snd_ac97_write_cache(ac97, AC97_CODEC_CLASS_REV, 0x8080);
+}
+
#endif
int patch_ad1819(struct snd_ac97 * ac97)
@@ -1627,6 +1638,7 @@ static const struct snd_kcontrol_new snd_ac97_ad1981x_jack_sense[] = {
* (SS vendor << 16 | device)
*/
static unsigned int ad1981_jacks_blacklist[] = {
+ 0x10140537, /* Thinkpad T41p */
0x10140554, /* Thinkpad T42p/R50p */
0 /* end */
};
@@ -1839,7 +1851,7 @@ static struct snd_ac97_build_ops patch_ad1888_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1888_specific,
#ifdef CONFIG_PM
- .resume = ad18xx_resume,
+ .resume = ad1888_resume,
#endif
.update_jacks = ad1888_update_jacks,
};
@@ -2048,7 +2060,10 @@ int patch_alc650(struct snd_ac97 * ac97)
/* Enable SPDIF-IN only on Rev.E and above */
val = snd_ac97_read(ac97, AC97_ALC650_CLOCK);
/* SPDIF IN with pin 47 */
- if (ac97->spec.dev_flags)
+ if (ac97->spec.dev_flags &&
+ /* ASUS A6KM requires EAPD */
+ ! (ac97->subsystem_vendor == 0x1043 &&
+ ac97->subsystem_device == 0x1103))
val |= 0x03; /* enable */
else
val &= ~0x03; /* disable */
diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c
index 512a358..f684aa2 100644
--- a/sound/pci/ac97/ac97_pcm.c
+++ b/sound/pci/ac97/ac97_pcm.c
@@ -317,6 +317,8 @@ int snd_ac97_set_rate(struct snd_ac97 *ac97, int reg, unsigned int rate)
return 0;
}
+EXPORT_SYMBOL(snd_ac97_set_rate);
+
static unsigned short get_pslots(struct snd_ac97 *ac97, unsigned char *rate_table, unsigned short *spdif_slots)
{
if (!ac97_is_audio(ac97))
@@ -550,6 +552,8 @@ int snd_ac97_pcm_assign(struct snd_ac97_bus *bus,
return 0;
}
+EXPORT_SYMBOL(snd_ac97_pcm_assign);
+
/**
* snd_ac97_pcm_open - opens the given AC97 pcm
* @pcm: the ac97 pcm instance
@@ -633,6 +637,8 @@ int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate,
return err;
}
+EXPORT_SYMBOL(snd_ac97_pcm_open);
+
/**
* snd_ac97_pcm_close - closes the given AC97 pcm
* @pcm: the ac97 pcm instance
@@ -658,6 +664,8 @@ int snd_ac97_pcm_close(struct ac97_pcm *pcm)
return 0;
}
+EXPORT_SYMBOL(snd_ac97_pcm_close);
+
static int double_rate_hw_constraint_rate(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
@@ -709,3 +717,5 @@ int snd_ac97_pcm_double_rate_rules(struct snd_pcm_runtime *runtime)
SNDRV_PCM_HW_PARAM_RATE, -1);
return err;
}
+
+EXPORT_SYMBOL(snd_ac97_pcm_double_rate_rules);
diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c
index 4d523df..2118df5 100644
--- a/sound/pci/ac97/ac97_proc.c
+++ b/sound/pci/ac97/ac97_proc.c
@@ -433,7 +433,7 @@ void snd_ac97_proc_init(struct snd_ac97 * ac97)
prefix = ac97_is_audio(ac97) ? "ac97" : "mc97";
sprintf(name, "%s#%d-%d", prefix, ac97->addr, ac97->num);
if ((entry = snd_info_create_card_entry(ac97->bus->card, name, ac97->bus->proc)) != NULL) {
- snd_info_set_text_ops(entry, ac97, 1024, snd_ac97_proc_read);
+ snd_info_set_text_ops(entry, ac97, snd_ac97_proc_read);
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
entry = NULL;
@@ -442,10 +442,9 @@ void snd_ac97_proc_init(struct snd_ac97 * ac97)
ac97->proc = entry;
sprintf(name, "%s#%d-%d+regs", prefix, ac97->addr, ac97->num);
if ((entry = snd_info_create_card_entry(ac97->bus->card, name, ac97->bus->proc)) != NULL) {
- snd_info_set_text_ops(entry, ac97, 1024, snd_ac97_proc_regs_read);
+ snd_info_set_text_ops(entry, ac97, snd_ac97_proc_regs_read);
#ifdef CONFIG_SND_DEBUG
entry->mode |= S_IWUSR;
- entry->c.text.write_size = 1024;
entry->c.text.write = snd_ac97_proc_regs_write;
#endif
if (snd_info_register(entry) < 0) {
diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c
index 0fb7b34..94c26ec 100644
--- a/sound/pci/ac97/ak4531_codec.c
+++ b/sound/pci/ac97/ak4531_codec.c
@@ -453,7 +453,7 @@ static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak453
struct snd_info_entry *entry;
if (! snd_card_proc_new(card, "ak4531", &entry))
- snd_info_set_text_ops(entry, ak4531, 1024, snd_ak4531_proc_read);
+ snd_info_set_text_ops(entry, ak4531, snd_ak4531_proc_read);
}
#endif
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index eece1c7..d42bf45 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -753,7 +753,7 @@ snd_ad1889_proc_init(struct snd_ad1889 *chip)
struct snd_info_entry *entry;
if (!snd_card_proc_new(chip->card, chip->card->driver, &entry))
- snd_info_set_text_ops(entry, chip, 1024, snd_ad1889_proc_read);
+ snd_info_set_text_ops(entry, chip, snd_ad1889_proc_read);
}
static struct ac97_quirk ac97_quirks[] = {
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index e2dbc21..5dfdbf6 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -49,7 +49,7 @@ MODULE_SUPPORTED_DEVICE("{{ALI,M5451,pci},{ALI,M5451}}");
static int index = SNDRV_DEFAULT_IDX1; /* Index */
static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */
static int pcm_channels = 32;
-static int spdif = 0;
+static int spdif;
module_param(index, int, 0444);
MODULE_PARM_DESC(index, "Index value for ALI M5451 PCI Audio.");
@@ -2173,7 +2173,7 @@ static void __devinit snd_ali_proc_init(struct snd_ali *codec)
{
struct snd_info_entry *entry;
if(!snd_card_proc_new(codec->card, "ali5451", &entry))
- snd_info_set_text_ops(entry, codec, 1024, snd_ali_proc_read);
+ snd_info_set_text_ops(entry, codec, snd_ali_proc_read);
}
static int __devinit snd_ali_resources(struct snd_ali *codec)
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index 60423b1..a9f0806 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -746,8 +746,8 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci,
card->shortname, chip->alt_port, chip->irq);
if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_ALS4000,
- gcr+0x30, 1, pci->irq, 0,
- &chip->rmidi)) < 0) {
+ gcr+0x30, MPU401_INFO_INTEGRATED,
+ pci->irq, 0, &chip->rmidi)) < 0) {
printk(KERN_ERR "als4000: no MPU-401 device at 0x%lx?\n", gcr+0x30);
goto out_err;
}
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index d0f759d..f18a8c0 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -1504,7 +1504,7 @@ static void __devinit snd_atiixp_proc_init(struct atiixp *chip)
struct snd_info_entry *entry;
if (! snd_card_proc_new(chip->card, "atiixp", &entry))
- snd_info_set_text_ops(entry, chip, 1024, snd_atiixp_proc_read);
+ snd_info_set_text_ops(entry, chip, snd_atiixp_proc_read);
}
#else /* !CONFIG_PROC_FS */
#define snd_atiixp_proc_init(chip)
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index 12a34c3..4073905 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -1177,7 +1177,7 @@ static void __devinit snd_atiixp_proc_init(struct atiixp_modem *chip)
struct snd_info_entry *entry;
if (! snd_card_proc_new(chip->card, "atiixp-modem", &entry))
- snd_info_set_text_ops(entry, chip, 1024, snd_atiixp_proc_read);
+ snd_info_set_text_ops(entry, chip, snd_atiixp_proc_read);
}
#else
#define snd_atiixp_proc_init(chip)
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
index 126870e..8a3b118 100644
--- a/sound/pci/au88x0/au88x0.c
+++ b/sound/pci/au88x0/au88x0.c
@@ -261,6 +261,13 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
return err;
}
snd_vortex_workaround(pci, pcifix[dev]);
+
+ // Card details needed in snd_vortex_midi
+ strcpy(card->driver, CARD_NAME_SHORT);
+ sprintf(card->shortname, "Aureal Vortex %s", CARD_NAME_SHORT);
+ sprintf(card->longname, "%s at 0x%lx irq %i",
+ card->shortname, chip->io, chip->irq);
+
// (4) Alloc components.
// ADB pcm.
if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_ADB, NR_ADB)) < 0) {
@@ -323,11 +330,6 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
#endif
// (5)
- strcpy(card->driver, CARD_NAME_SHORT);
- strcpy(card->shortname, CARD_NAME_SHORT);
- sprintf(card->longname, "%s at 0x%lx irq %i",
- card->shortname, chip->io, chip->irq);
-
if ((err = pci_read_config_word(pci, PCI_DEVICE_ID,
&(chip->device))) < 0) {
snd_card_free(card);
diff --git a/sound/pci/au88x0/au88x0_mpu401.c b/sound/pci/au88x0/au88x0_mpu401.c
index 873f486..c75d368 100644
--- a/sound/pci/au88x0/au88x0_mpu401.c
+++ b/sound/pci/au88x0/au88x0_mpu401.c
@@ -47,7 +47,7 @@ static int __devinit snd_vortex_midi(vortex_t * vortex)
struct snd_rawmidi *rmidi;
int temp, mode;
struct snd_mpu401 *mpu;
- int port;
+ unsigned long port;
#ifdef VORTEX_MPU401_LEGACY
/* EnableHardCodedMPU401Port() */
@@ -70,9 +70,6 @@ static int __devinit snd_vortex_midi(vortex_t * vortex)
temp |= (MIDI_CLOCK_DIV << 8) | ((mode >> 24) & 0xff) << 4;
hwwrite(vortex->mmio, VORTEX_CTRL2, temp);
hwwrite(vortex->mmio, VORTEX_MIDI_CMD, MPU401_RESET);
- /* Set some kind of mode */
- if (mode)
- hwwrite(vortex->mmio, VORTEX_MIDI_CMD, MPU401_ENTER_UART);
/* Check if anything is OK. */
temp = hwread(vortex->mmio, VORTEX_MIDI_DATA);
@@ -98,7 +95,8 @@ static int __devinit snd_vortex_midi(vortex_t * vortex)
port = (unsigned long)(vortex->mmio + VORTEX_MIDI_DATA);
if ((temp =
snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_AUREAL, port,
- 1, 0, 0, &rmidi)) != 0) {
+ MPU401_INFO_INTEGRATED | MPU401_INFO_MMIO,
+ 0, 0, &rmidi)) != 0) {
hwwrite(vortex->mmio, VORTEX_CTRL,
(hwread(vortex->mmio, VORTEX_CTRL) &
~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN);
@@ -107,6 +105,9 @@ static int __devinit snd_vortex_midi(vortex_t * vortex)
mpu = rmidi->private_data;
mpu->cport = (unsigned long)(vortex->mmio + VORTEX_MIDI_CMD);
#endif
+ /* Overwrite MIDI name */
+ snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI %d", CARD_NAME_SHORT , vortex->card->number);
+
vortex->rmidi = rmidi;
return 0;
}
diff --git a/sound/pci/au88x0/au88x0_xtalk.c b/sound/pci/au88x0/au88x0_xtalk.c
index 4534e18..b4151e2 100644
--- a/sound/pci/au88x0/au88x0_xtalk.c
+++ b/sound/pci/au88x0/au88x0_xtalk.c
@@ -66,31 +66,20 @@ static xtalk_gains_t const asXtalkGainsAllChan = {
0
//0x7FFF,0x7FFF,0x7FFF,0x7FFF,0x7fff,0x7FFF,0x7FFF,0x7FFF,0x7FFF,0x7fff
};
-static xtalk_gains_t const asXtalkGainsZeros = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
+static xtalk_gains_t const asXtalkGainsZeros;
-static xtalk_dline_t const alXtalkDlineZeros = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0
-};
+static xtalk_dline_t const alXtalkDlineZeros;
static xtalk_dline_t const alXtalkDlineTest = {
0xFC18, 0x03E8FFFF, 0x186A0, 0x7960FFFE, 1, 0xFFFFFFFF,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0
};
-static xtalk_instate_t const asXtalkInStateZeros = { 0, 0, 0, 0 };
+static xtalk_instate_t const asXtalkInStateZeros;
static xtalk_instate_t const asXtalkInStateTest =
{ 0xFF80, 0x0080, 0xFFFF, 0x0001 };
-static xtalk_state_t const asXtalkOutStateZeros = {
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0}
-};
+static xtalk_state_t const asXtalkOutStateZeros;
+
static short const sDiamondKLeftEq = 0x401d;
static short const sDiamondKRightEq = 0x401d;
static short const sDiamondKLeftXt = 0xF90E;
@@ -162,13 +151,7 @@ static xtalk_coefs_t const asXtalkNarrowCoefsRightXt = {
{0, 0, 0, 0, 0}
};
-static xtalk_coefs_t const asXtalkCoefsZeros = {
- {0, 0, 0, 0, 0},
- {0, 0, 0, 0, 0},
- {0, 0, 0, 0, 0},
- {0, 0, 0, 0, 0},
- {0, 0, 0, 0, 0}
-};
+static xtalk_coefs_t const asXtalkCoefsZeros;
static xtalk_coefs_t const asXtalkCoefsPipe = {
{0, 0, 0x0FA0, 0, 0},
{0, 0, 0x0FA0, 0, 0},
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 52a3645..6e62daf 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -33,14 +33,21 @@
* in the first place >:-P}),
* I was forced to base this driver on reverse engineering
* (3 weeks' worth of evenings filled with driver work).
- * (and no, I did NOT go the easy way: to pick up a PCI128 for 9 Euros)
+ * (and no, I did NOT go the easy way: to pick up a SB PCI128 for 9 Euros)
*
* The AZF3328 chip (note: AZF3328, *not* AZT3328, that's just the driver name
* for compatibility reasons) has the following features:
*
* - builtin AC97 conformant codec (SNR over 80dB)
- * (really AC97 compliant?? I really doubt it when looking
- * at the mixer register layout)
+ * Note that "conformant" != "compliant"!! this chip's mixer register layout
+ * *differs* from the standard AC97 layout:
+ * they chose to not implement the headphone register (which is not a
+ * problem since it's merely optional), yet when doing this, they committed
+ * the grave sin of letting other registers follow immediately instead of
+ * keeping a headphone dummy register, thereby shifting the mixer register
+ * addresses illegally. So far unfortunately it looks like the very flexible
+ * ALSA AC97 support is still not enough to easily compensate for such a
+ * grave layout violation despite all tweaks and quirks mechanisms it offers.
* - builtin genuine OPL3
* - full duplex 16bit playback/record at independent sampling rate
* - MPU401 (+ legacy address support) FIXME: how to enable legacy addr??
@@ -90,10 +97,15 @@
*
* TODO
* - test MPU401 MIDI playback etc.
- * - power management. See e.g. intel8x0 or cs4281.
- * This would be nice since the chip runs a bit hot, and it's *required*
- * anyway for proper ACPI power management.
+ * - add some power micro-management (disable various units of the card
+ * as long as they're unused). However this requires I/O ports which I
+ * haven't figured out yet and which thus might not even exist...
+ * The standard suspend/resume functionality could probably make use of
+ * some improvement, too...
* - figure out what all unknown port bits are responsible for
+ * - figure out some cleverly evil scheme to possibly make ALSA AC97 code
+ * fully accept our quite incompatible ""AC97"" mixer and thus save some
+ * code (but I'm not too optimistic that doing this is possible at all)
*/
#include <sound/driver.h>
@@ -214,6 +226,16 @@ struct snd_azf3328 {
struct pci_dev *pci;
int irq;
+
+#ifdef CONFIG_PM
+ /* register value containers for power management
+ * Note: not always full I/O range preserved (just like Win driver!) */
+ u16 saved_regs_codec [AZF_IO_SIZE_CODEC_PM / 2];
+ u16 saved_regs_io2 [AZF_IO_SIZE_IO2_PM / 2];
+ u16 saved_regs_mpu [AZF_IO_SIZE_MPU_PM / 2];
+ u16 saved_regs_synth[AZF_IO_SIZE_SYNTH_PM / 2];
+ u16 saved_regs_mixer[AZF_IO_SIZE_MIXER_PM / 2];
+#endif
};
static const struct pci_device_id snd_azf3328_ids[] __devinitdata = {
@@ -317,10 +339,8 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, int reg
else
dst_vol_left &= ~0x80;
- do
- {
- if (!left_done)
- {
+ do {
+ if (!left_done) {
if (curr_vol_left > dst_vol_left)
curr_vol_left--;
else
@@ -330,8 +350,7 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, int reg
left_done = 1;
outb(curr_vol_left, portbase + 1);
}
- if (!right_done)
- {
+ if (!right_done) {
if (curr_vol_right > dst_vol_right)
curr_vol_right--;
else
@@ -346,8 +365,7 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, int reg
}
if (delay)
mdelay(delay);
- }
- while ((!left_done) || (!right_done));
+ } while ((!left_done) || (!right_done));
snd_azf3328_dbgcallleave();
}
@@ -514,15 +532,18 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
static const char * const texts1[] = {
- "ModemOut1", "ModemOut2"
+ "Mic1", "Mic2"
};
static const char * const texts2[] = {
- "MonoSelectSource1", "MonoSelectSource2"
+ "Mix", "Mic"
};
static const char * const texts3[] = {
"Mic", "CD", "Video", "Aux",
"Line", "Mix", "Mix Mono", "Phone"
};
+ static const char * const texts4[] = {
+ "pre 3D", "post 3D"
+ };
struct azf3328_mixer_reg reg;
snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);
@@ -531,14 +552,19 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol,
uinfo->value.enumerated.items = reg.enum_c;
if (uinfo->value.enumerated.item > reg.enum_c - 1U)
uinfo->value.enumerated.item = reg.enum_c - 1U;
- if (reg.reg == IDX_MIXER_ADVCTL2)
- {
- if (reg.lchan_shift == 8) /* modem out sel */
+ if (reg.reg == IDX_MIXER_ADVCTL2) {
+ switch(reg.lchan_shift) {
+ case 8: /* modem out sel */
strcpy(uinfo->value.enumerated.name, texts1[uinfo->value.enumerated.item]);
- else /* mono sel source */
+ break;
+ case 9: /* mono sel source */
strcpy(uinfo->value.enumerated.name, texts2[uinfo->value.enumerated.item]);
- }
- else
+ break;
+ case 15: /* PCM Out Path */
+ strcpy(uinfo->value.enumerated.name, texts4[uinfo->value.enumerated.item]);
+ break;
+ }
+ } else
strcpy(uinfo->value.enumerated.name, texts3[uinfo->value.enumerated.item]
);
return 0;
@@ -554,12 +580,10 @@ snd_azf3328_get_mixer_enum(struct snd_kcontrol *kcontrol,
snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);
val = snd_azf3328_mixer_inw(chip, reg.reg);
- if (reg.reg == IDX_MIXER_REC_SELECT)
- {
+ if (reg.reg == IDX_MIXER_REC_SELECT) {
ucontrol->value.enumerated.item[0] = (val >> 8) & (reg.enum_c - 1);
ucontrol->value.enumerated.item[1] = (val >> 0) & (reg.enum_c - 1);
- }
- else
+ } else
ucontrol->value.enumerated.item[0] = (val >> reg.lchan_shift) & (reg.enum_c - 1);
snd_azf3328_dbgmixer("get_enum: %02x is %04x -> %d|%d (shift %02d, enum_c %d)\n",
@@ -579,16 +603,13 @@ snd_azf3328_put_mixer_enum(struct snd_kcontrol *kcontrol,
snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);
oreg = snd_azf3328_mixer_inw(chip, reg.reg);
val = oreg;
- if (reg.reg == IDX_MIXER_REC_SELECT)
- {
+ if (reg.reg == IDX_MIXER_REC_SELECT) {
if (ucontrol->value.enumerated.item[0] > reg.enum_c - 1U ||
ucontrol->value.enumerated.item[1] > reg.enum_c - 1U)
return -EINVAL;
val = (ucontrol->value.enumerated.item[0] << 8) |
(ucontrol->value.enumerated.item[1] << 0);
- }
- else
- {
+ } else {
if (ucontrol->value.enumerated.item[0] > reg.enum_c - 1U)
return -EINVAL;
val &= ~((reg.enum_c - 1) << reg.lchan_shift);
@@ -629,13 +650,14 @@ static const struct snd_kcontrol_new snd_azf3328_mixer_controls[] __devinitdata
AZF3328_MIXER_VOL_MONO("Modem Playback Volume", IDX_MIXER_MODEMOUT, 0x1f, 1),
AZF3328_MIXER_SWITCH("Modem Capture Switch", IDX_MIXER_MODEMIN, 15, 1),
AZF3328_MIXER_VOL_MONO("Modem Capture Volume", IDX_MIXER_MODEMIN, 0x1f, 1),
- AZF3328_MIXER_ENUM("Modem Out Select", IDX_MIXER_ADVCTL2, 2, 8),
- AZF3328_MIXER_ENUM("Mono Select Source", IDX_MIXER_ADVCTL2, 2, 9),
+ AZF3328_MIXER_ENUM("Mic Select", IDX_MIXER_ADVCTL2, 2, 8),
+ AZF3328_MIXER_ENUM("Mono Output Select", IDX_MIXER_ADVCTL2, 2, 9),
+ AZF3328_MIXER_ENUM("PCM", IDX_MIXER_ADVCTL2, 2, 15), /* PCM Out Path, place in front since it controls *both* 3D and Bass/Treble! */
AZF3328_MIXER_VOL_SPECIAL("Tone Control - Treble", IDX_MIXER_BASSTREBLE, 0x07, 1, 0),
AZF3328_MIXER_VOL_SPECIAL("Tone Control - Bass", IDX_MIXER_BASSTREBLE, 0x07, 9, 0),
AZF3328_MIXER_SWITCH("3D Control - Switch", IDX_MIXER_ADVCTL2, 13, 0),
- AZF3328_MIXER_VOL_SPECIAL("3D Control - Wide", IDX_MIXER_ADVCTL1, 0x07, 1, 0), /* "3D Width" */
- AZF3328_MIXER_VOL_SPECIAL("3D Control - Space", IDX_MIXER_ADVCTL1, 0x03, 8, 0), /* "Hifi 3D" */
+ AZF3328_MIXER_VOL_SPECIAL("3D Control - Width", IDX_MIXER_ADVCTL1, 0x07, 1, 0), /* "3D Width" */
+ AZF3328_MIXER_VOL_SPECIAL("3D Control - Depth", IDX_MIXER_ADVCTL1, 0x03, 8, 0), /* "Hifi 3D" */
#if MIXER_TESTING
AZF3328_MIXER_SWITCH("0", IDX_MIXER_ADVCTL2, 0, 0),
AZF3328_MIXER_SWITCH("1", IDX_MIXER_ADVCTL2, 1, 0),
@@ -813,22 +835,18 @@ snd_azf3328_setdmaa(struct snd_azf3328 *chip,
unsigned int is_running;
snd_azf3328_dbgcallenter();
- if (do_recording)
- {
+ if (do_recording) {
/* access capture registers, i.e. skip playback reg section */
portbase = chip->codec_port + 0x20;
is_running = chip->is_recording;
- }
- else
- {
+ } else {
/* access the playback register section */
portbase = chip->codec_port + 0x00;
is_running = chip->is_playing;
}
/* AZF3328 uses a two buffer pointer DMA playback approach */
- if (!is_running)
- {
+ if (!is_running) {
unsigned long addr_area2;
unsigned long count_areas, count_tmp; /* width 32bit -- overflow!! */
count_areas = size/2;
@@ -961,6 +979,13 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd)
chip->is_playing = 1;
snd_azf3328_dbgplay("STARTED PLAYBACK\n");
break;
+ case SNDRV_PCM_TRIGGER_RESUME:
+ snd_azf3328_dbgplay("RESUME PLAYBACK\n");
+ /* resume playback if we were active */
+ if (chip->is_playing)
+ snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS,
+ snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | DMA_RESUME);
+ break;
case SNDRV_PCM_TRIGGER_STOP:
snd_azf3328_dbgplay("STOP PLAYBACK\n");
@@ -988,6 +1013,12 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd)
chip->is_playing = 0;
snd_azf3328_dbgplay("STOPPED PLAYBACK\n");
break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ snd_azf3328_dbgplay("SUSPEND PLAYBACK\n");
+ /* make sure playback is stopped */
+ snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS,
+ snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) & ~DMA_RESUME);
+ break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n");
break;
@@ -995,6 +1026,7 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd)
snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n");
break;
default:
+ printk(KERN_ERR "FIXME: unknown trigger mode!\n");
return -EINVAL;
}
@@ -1068,6 +1100,13 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd)
chip->is_recording = 1;
snd_azf3328_dbgplay("STARTED CAPTURE\n");
break;
+ case SNDRV_PCM_TRIGGER_RESUME:
+ snd_azf3328_dbgplay("RESUME CAPTURE\n");
+ /* resume recording if we were active */
+ if (chip->is_recording)
+ snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS,
+ snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) | DMA_RESUME);
+ break;
case SNDRV_PCM_TRIGGER_STOP:
snd_azf3328_dbgplay("STOP CAPTURE\n");
@@ -1088,6 +1127,12 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd)
chip->is_recording = 0;
snd_azf3328_dbgplay("STOPPED CAPTURE\n");
break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ snd_azf3328_dbgplay("SUSPEND CAPTURE\n");
+ /* make sure recording is stopped */
+ snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS,
+ snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) & ~DMA_RESUME);
+ break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n");
break;
@@ -1095,6 +1140,7 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd)
snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n");
break;
default:
+ printk(KERN_ERR "FIXME: unknown trigger mode!\n");
return -EINVAL;
}
@@ -1163,8 +1209,7 @@ snd_azf3328_interrupt(int irq, void *dev_id, struct pt_regs *regs)
snd_azf3328_codec_inw(chip, IDX_IO_PLAY_IRQTYPE),
status);
- if (status & IRQ_TIMER)
- {
+ if (status & IRQ_TIMER) {
/* snd_azf3328_dbgplay("timer %ld\n", inl(chip->codec_port+IDX_IO_TIMER_VALUE) & TIMER_VALUE_MASK); */
if (chip->timer)
snd_timer_interrupt(chip->timer, chip->timer->sticks);
@@ -1174,50 +1219,43 @@ snd_azf3328_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_unlock(&chip->reg_lock);
snd_azf3328_dbgplay("azt3328: timer IRQ\n");
}
- if (status & IRQ_PLAYBACK)
- {
+ if (status & IRQ_PLAYBACK) {
spin_lock(&chip->reg_lock);
which = snd_azf3328_codec_inb(chip, IDX_IO_PLAY_IRQTYPE);
/* ack all IRQ types immediately */
snd_azf3328_codec_outb(chip, IDX_IO_PLAY_IRQTYPE, which);
spin_unlock(&chip->reg_lock);
- if (chip->pcm && chip->playback_substream)
- {
+ if (chip->pcm && chip->playback_substream) {
snd_pcm_period_elapsed(chip->playback_substream);
snd_azf3328_dbgplay("PLAY period done (#%x), @ %x\n",
which,
inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS));
- }
- else
+ } else
snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n");
if (which & IRQ_PLAY_SOMETHING)
snd_azf3328_dbgplay("azt3328: unknown play IRQ type occurred, please report!\n");
}
- if (status & IRQ_RECORDING)
- {
+ if (status & IRQ_RECORDING) {
spin_lock(&chip->reg_lock);
which = snd_azf3328_codec_inb(chip, IDX_IO_REC_IRQTYPE);
/* ack all IRQ types immediately */
snd_azf3328_codec_outb(chip, IDX_IO_REC_IRQTYPE, which);
spin_unlock(&chip->reg_lock);
- if (chip->pcm && chip->capture_substream)
- {
+ if (chip->pcm && chip->capture_substream) {
snd_pcm_period_elapsed(chip->capture_substream);
snd_azf3328_dbgplay("REC period done (#%x), @ %x\n",
which,
inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS));
- }
- else
+ } else
snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n");
if (which & IRQ_REC_SOMETHING)
snd_azf3328_dbgplay("azt3328: unknown rec IRQ type occurred, please report!\n");
}
/* MPU401 has less critical IRQ requirements
* than timer and playback/recording, right? */
- if (status & IRQ_MPU401)
- {
+ if (status & IRQ_MPU401) {
snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
/* hmm, do we have to ack the IRQ here somehow?
@@ -1511,8 +1549,7 @@ snd_azf3328_timer_start(struct snd_timer *timer)
snd_azf3328_dbgcallenter();
chip = snd_timer_chip(timer);
delay = ((timer->sticks * seqtimer_scaling) - 1) & TIMER_VALUE_MASK;
- if (delay < 49)
- {
+ if (delay < 49) {
/* uhoh, that's not good, since user-space won't know about
* this timing tweak
* (we need to do it to avoid a lockup, though) */
@@ -1766,9 +1803,11 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
goto out_err;
}
+ card->private_data = chip;
+
if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_MPU401,
- chip->mpu_port, 1, pci->irq, 0,
- &chip->rmidi)) < 0) {
+ chip->mpu_port, MPU401_INFO_INTEGRATED,
+ pci->irq, 0, &chip->rmidi)) < 0) {
snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n", chip->mpu_port);
goto out_err;
}
@@ -1791,6 +1830,8 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
}
}
+ opl3->private_data = chip;
+
sprintf(card->longname, "%s at 0x%lx, irq %i",
card->shortname, chip->codec_port, chip->irq);
@@ -1834,11 +1875,80 @@ snd_azf3328_remove(struct pci_dev *pci)
snd_azf3328_dbgcallleave();
}
+#ifdef CONFIG_PM
+static int
+snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state)
+{
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct snd_azf3328 *chip = card->private_data;
+ int reg;
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+
+ snd_pcm_suspend_all(chip->pcm);
+
+ for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++)
+ chip->saved_regs_mixer[reg] = inw(chip->mixer_port + reg * 2);
+
+ /* make sure to disable master volume etc. to prevent looping sound */
+ snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1);
+ snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1);
+
+ for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++)
+ chip->saved_regs_codec[reg] = inw(chip->codec_port + reg * 2);
+ for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++)
+ chip->saved_regs_io2[reg] = inw(chip->io2_port + reg * 2);
+ for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++)
+ chip->saved_regs_mpu[reg] = inw(chip->mpu_port + reg * 2);
+ for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++)
+ chip->saved_regs_synth[reg] = inw(chip->synth_port + reg * 2);
+
+ pci_set_power_state(pci, PCI_D3hot);
+ pci_disable_device(pci);
+ pci_save_state(pci);
+ return 0;
+}
+
+static int
+snd_azf3328_resume(struct pci_dev *pci)
+{
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct snd_azf3328 *chip = card->private_data;
+ int reg;
+
+ pci_restore_state(pci);
+ pci_enable_device(pci);
+ pci_set_power_state(pci, PCI_D0);
+ pci_set_master(pci);
+
+ for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++)
+ outw(chip->saved_regs_io2[reg], chip->io2_port + reg * 2);
+ for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++)
+ outw(chip->saved_regs_mpu[reg], chip->mpu_port + reg * 2);
+ for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++)
+ outw(chip->saved_regs_synth[reg], chip->synth_port + reg * 2);
+ for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++)
+ outw(chip->saved_regs_mixer[reg], chip->mixer_port + reg * 2);
+ for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++)
+ outw(chip->saved_regs_codec[reg], chip->codec_port + reg * 2);
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+ return 0;
+}
+#endif
+
+
+
+
static struct pci_driver driver = {
.name = "AZF3328",
.id_table = snd_azf3328_ids,
.probe = snd_azf3328_probe,
.remove = __devexit_p(snd_azf3328_remove),
+#ifdef CONFIG_PM
+ .suspend = snd_azf3328_suspend,
+ .resume = snd_azf3328_resume,
+#endif
};
static int __init
diff --git a/sound/pci/azt3328.h b/sound/pci/azt3328.h
index f489bda..b4f3e3c 100644
--- a/sound/pci/azt3328.h
+++ b/sound/pci/azt3328.h
@@ -5,6 +5,9 @@
/*** main I/O area port indices ***/
/* (only 0x70 of 0x80 bytes saved/restored by Windows driver) */
+#define AZF_IO_SIZE_CODEC 0x80
+#define AZF_IO_SIZE_CODEC_PM 0x70
+
/* the driver initialisation suggests a layout of 4 main areas:
* from 0x00 (playback), from 0x20 (recording) and from 0x40 (maybe MPU401??).
* And another area from 0x60 to 0x6f (DirectX timer, IRQ management,
@@ -87,7 +90,7 @@
#define IDX_IO_REC_DMA_CURROFS 0x34 /* PU:0x00000000 */
#define IDX_IO_REC_SOUNDFORMAT 0x36 /* PU:0x0000 */
-/** hmm, what is this I/O area for? MPU401?? (after playback, recording, ???, timer) **/
+/** hmm, what is this I/O area for? MPU401?? or external DAC via I2S?? (after playback, recording, ???, timer) **/
#define IDX_IO_SOMETHING_FLAGS 0x40 /* gets set to 0x34 just like port 0x0 and 0x20 on card init, PU:0x0000 */
/* general */
#define IDX_IO_42H 0x42 /* PU:0x0001 */
@@ -107,7 +110,8 @@
#define IRQ_UNKNOWN2 0x0080 /* probably unused */
#define IDX_IO_66H 0x66 /* writing 0xffff returns 0x0000 */
#define IDX_IO_SOME_VALUE 0x68 /* this is set to e.g. 0x3ff or 0x300, and writable; maybe some buffer limit, but I couldn't find out more, PU:0x00ff */
-#define IDX_IO_6AH 0x6A /* this WORD can be set to have bits 0x0028 activated; actually inhibits PCM playback!!! maybe power management?? */
+#define IDX_IO_6AH 0x6A /* this WORD can be set to have bits 0x0028 activated (FIXME: correct??); actually inhibits PCM playback!!! maybe power management?? */
+ #define IO_6A_PAUSE_PLAYBACK 0x0200 /* bit 9; sure, this pauses playback, but what the heck is this really about?? */
#define IDX_IO_6CH 0x6C
#define IDX_IO_6EH 0x6E /* writing 0xffff returns 0x83fe */
/* further I/O indices not saved/restored, so probably not used */
@@ -115,15 +119,25 @@
/*** I/O 2 area port indices ***/
/* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */
+#define AZF_IO_SIZE_IO2 0x08
+#define AZF_IO_SIZE_IO2_PM 0x06
+
#define IDX_IO2_LEGACY_ADDR 0x04
#define LEGACY_SOMETHING 0x01 /* OPL3?? */
#define LEGACY_JOY 0x08
+#define AZF_IO_SIZE_MPU 0x04
+#define AZF_IO_SIZE_MPU_PM 0x04
+
+#define AZF_IO_SIZE_SYNTH 0x08
+#define AZF_IO_SIZE_SYNTH_PM 0x06
/*** mixer I/O area port indices ***/
/* (only 0x22 of 0x40 bytes saved/restored by Windows driver)
- * generally spoken: AC97 register index = AZF3328 mixer reg index + 2
- * (in other words: AZF3328 NOT fully AC97 compliant) */
+ * UNFORTUNATELY azf3328 is NOT truly AC97 compliant: see main file intro */
+#define AZF_IO_SIZE_MIXER 0x40
+#define AZF_IO_SIZE_MIXER_PM 0x22
+
#define MIXER_VOLUME_RIGHT_MASK 0x001f
#define MIXER_VOLUME_LEFT_MASK 0x1f00
#define MIXER_MUTE_MASK 0x8000
@@ -156,14 +170,14 @@
#define IDX_MIXER_ADVCTL1 0x1e
/* unlisted bits are unmodifiable */
#define MIXER_ADVCTL1_3DWIDTH_MASK 0x000e
- #define MIXER_ADVCTL1_HIFI3D_MASK 0x0300
-#define IDX_MIXER_ADVCTL2 0x20 /* resembles AC97_GENERAL_PURPOSE reg! */
+ #define MIXER_ADVCTL1_HIFI3D_MASK 0x0300 /* yup, this is missing the high bit that official AC97 contains, plus it doesn't have linear bit value range behaviour but instead acts weirdly (possibly we're dealing with two *different* 3D settings here??) */
+#define IDX_MIXER_ADVCTL2 0x20 /* subset of AC97_GENERAL_PURPOSE reg! */
/* unlisted bits are unmodifiable */
- #define MIXER_ADVCTL2_BIT7 0x0080 /* WaveOut 3D Bypass? mutes WaveOut at LineOut */
- #define MIXER_ADVCTL2_BIT8 0x0100 /* is this Modem Out Select? */
- #define MIXER_ADVCTL2_BIT9 0x0200 /* Mono Select Source? */
- #define MIXER_ADVCTL2_BIT13 0x2000 /* 3D enable? */
- #define MIXER_ADVCTL2_BIT15 0x8000 /* unknown */
+ #define MIXER_ADVCTL2_LPBK 0x0080 /* Loopback mode -- Win driver: "WaveOut3DBypass"? mutes WaveOut at LineOut */
+ #define MIXER_ADVCTL2_MS 0x0100 /* Mic Select 0=Mic1, 1=Mic2 -- Win driver: "ModemOutSelect"?? */
+ #define MIXER_ADVCTL2_MIX 0x0200 /* Mono output select 0=Mix, 1=Mic; Win driver: "MonoSelectSource"?? */
+ #define MIXER_ADVCTL2_3D 0x2000 /* 3D Enhancement 1=on */
+ #define MIXER_ADVCTL2_POP 0x8000 /* Pcm Out Path, 0=pre 3D, 1=post 3D */
#define IDX_MIXER_SOMETHING30H 0x30 /* used, but unknown??? */
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index 9ee07d4..c33642d 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -44,7 +44,7 @@ MODULE_SUPPORTED_DEVICE("{{Brooktree,Bt878},"
static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* Exclude the first card */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
-static int digital_rate[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 }; /* digital input rate */
+static int digital_rate[SNDRV_CARDS]; /* digital input rate */
static int load_all; /* allow to load the non-whitelisted cards */
module_param_array(index, int, NULL, 0444);
@@ -781,10 +781,12 @@ static struct pci_device_id snd_bt87x_ids[] __devinitdata = {
BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, 0x0070, 0x13eb, 32000),
/* Viewcast Osprey 200 */
BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff01, 44100),
- /* AVerMedia Studio No. 103, 203, ...? */
- BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, 48000),
/* Leadtek Winfast tv 2000xp delux */
BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, 32000),
+ /* Voodoo TV 200 */
+ BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x121a, 0x3000, 32000),
+ /* AVerMedia Studio No. 103, 203, ...? */
+ BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, 48000),
{ }
};
MODULE_DEVICE_TABLE(pci, snd_bt87x_ids);
diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h
index c8131ea..9cb66c5 100644
--- a/sound/pci/ca0106/ca0106.h
+++ b/sound/pci/ca0106/ca0106.h
@@ -537,9 +537,9 @@
#endif
#define ADC_MUX_MASK 0x0000000f //Mask for ADC Mux
+#define ADC_MUX_PHONE 0x00000001 //Value to select TAD at ADC Mux (Not used)
#define ADC_MUX_MIC 0x00000002 //Value to select Mic at ADC Mux
#define ADC_MUX_LINEIN 0x00000004 //Value to select LineIn at ADC Mux
-#define ADC_MUX_PHONE 0x00000001 //Value to select TAD at ADC Mux (Not used)
#define ADC_MUX_AUX 0x00000008 //Value to select Aux at ADC Mux
#define SET_CHANNEL 0 /* Testing channel outputs 0=Front, 1=Center/LFE, 2=Unknown, 3=Rear */
@@ -604,6 +604,8 @@ struct snd_ca0106 {
u32 spdif_bits[4]; /* s/pdif out setup */
int spdif_enable;
int capture_source;
+ int i2c_capture_source;
+ u8 i2c_capture_volume[4][2];
int capture_mic_line_in;
struct snd_dma_buffer buffer;
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index fd8bfeb..59bf9bd 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -186,8 +186,8 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
/* New Audigy SE. Has a different DAC. */
/* SB0570:
* CTRL:CA0106-DAT
- * ADC: WM8768GEDS
- * DAC: WM8775EDS
+ * ADC: WM8775EDS
+ * DAC: WM8768GEDS
*/
{ .serial = 0x100a1102,
.name = "Audigy SE [SB0570]",
@@ -195,9 +195,14 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
.i2c_adc = 1,
.spi_dac = 1 } ,
/* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */
+ /* SB0438
+ * CTRL:CA0106-DAT
+ * ADC: WM8775SEDS
+ * DAC: CS4382-KQZ
+ */
{ .serial = 0x10091462,
.name = "MSI K8N Diamond MB [SB0438]",
- .gpio_type = 1,
+ .gpio_type = 2,
.i2c_adc = 1 } ,
/* Shuttle XPC SD31P which has an onboard Creative Labs
* Sound Blaster Live! 24-bit EAX
@@ -326,6 +331,7 @@ int snd_ca0106_spi_write(struct snd_ca0106 * emu,
return 0;
}
+/* The ADC does not support i2c read, so only write is implemented */
int snd_ca0106_i2c_write(struct snd_ca0106 *emu,
u32 reg,
u32 value)
@@ -340,6 +346,7 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu,
}
tmp = reg << 25 | value << 16;
+ // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value);
/* Not sure what this I2C channel controls. */
/* snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); */
@@ -348,8 +355,9 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu,
for (retry = 0; retry < 10; retry++) {
/* Send the data to i2c */
- tmp = snd_ca0106_ptr_read(emu, I2C_A, 0);
- tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);
+ //tmp = snd_ca0106_ptr_read(emu, I2C_A, 0);
+ //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);
+ tmp = 0;
tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
snd_ca0106_ptr_write(emu, I2C_A, 0, tmp);
@@ -1181,7 +1189,7 @@ static unsigned int spi_dac_init[] = {
0x02ff,
0x0400,
0x0520,
- 0x0600,
+ 0x0620, /* Set 24 bit. Was 0x0600 */
0x08ff,
0x0aff,
0x0cff,
@@ -1200,6 +1208,22 @@ static unsigned int spi_dac_init[] = {
0x1400,
};
+static unsigned int i2c_adc_init[][2] = {
+ { 0x17, 0x00 }, /* Reset */
+ { 0x07, 0x00 }, /* Timeout */
+ { 0x0b, 0x22 }, /* Interface control */
+ { 0x0c, 0x22 }, /* Master mode control */
+ { 0x0d, 0x08 }, /* Powerdown control */
+ { 0x0e, 0xcf }, /* Attenuation Left 0x01 = -103dB, 0xff = 24dB */
+ { 0x0f, 0xcf }, /* Attenuation Right 0.5dB steps */
+ { 0x10, 0x7b }, /* ALC Control 1 */
+ { 0x11, 0x00 }, /* ALC Control 2 */
+ { 0x12, 0x32 }, /* ALC Control 3 */
+ { 0x13, 0x00 }, /* Noise gate control */
+ { 0x14, 0xa6 }, /* Limiter control */
+ { 0x15, ADC_MUX_LINEIN }, /* ADC Mixer control */
+};
+
static int __devinit snd_ca0106_create(struct snd_card *card,
struct pci_dev *pci,
struct snd_ca0106 **rchip)
@@ -1361,7 +1385,12 @@ static int __devinit snd_ca0106_create(struct snd_card *card,
snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC, Line in, TAD in, AUX in */
chip->capture_source = 3; /* Set CAPTURE_SOURCE */
- if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */
+ if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */
+ /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */
+ outl(0x0, chip->port+GPIO);
+ //outl(0x00f0e000, chip->port+GPIO); /* Analog */
+ outl(0x005f5301, chip->port+GPIO); /* Analog */
+ } else if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */
/* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */
outl(0x0, chip->port+GPIO);
//outl(0x00f0e000, chip->port+GPIO); /* Analog */
@@ -1379,7 +1408,19 @@ static int __devinit snd_ca0106_create(struct snd_card *card,
outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */
if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */
- snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */
+ int size, n;
+
+ size = ARRAY_SIZE(i2c_adc_init);
+ //snd_printk("I2C:array size=0x%x\n", size);
+ for (n=0; n < size; n++) {
+ snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], i2c_adc_init[n][1]);
+ }
+ for (n=0; n < 4; n++) {
+ chip->i2c_capture_volume[n][0]= 0xcf;
+ chip->i2c_capture_volume[n][1]= 0xcf;
+ }
+ chip->i2c_capture_source=2; /* Line in */
+ //snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */
}
if (chip->details->spi_dac == 1) { /* The SB0570 use SPI to control DAC. */
int size, n;
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index 06fe055..146eed70d 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -171,6 +171,76 @@ static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol,
return change;
}
+static int snd_ca0106_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[6] = {
+ "Phone", "Mic", "Line in", "Aux"
+ };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 4;
+ if (uinfo->value.enumerated.item > 3)
+ uinfo->value.enumerated.item = 3;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_ca0106_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
+ return 0;
+}
+
+static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int source_id;
+ unsigned int ngain, ogain;
+ int change = 0;
+ u32 source;
+ /* If the capture source has changed,
+ * update the capture volume from the cached value
+ * for the particular source.
+ */
+ source_id = ucontrol->value.enumerated.item[0] ;
+ change = (emu->i2c_capture_source != source_id);
+ if (change) {
+ snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
+ ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
+ ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
+ if (ngain != ogain)
+ snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
+ ngain = emu->i2c_capture_volume[source_id][1]; /* Left */
+ ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Left */
+ if (ngain != ogain)
+ snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
+ source = 1 << source_id;
+ snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */
+ emu->i2c_capture_source = source_id;
+ }
+ return change;
+}
+
+static int snd_ca0106_capture_line_in_side_out_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[2] = { "Side out", "Line in" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item > 1)
+ uinfo->value.enumerated.item = 1;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
static int snd_ca0106_capture_mic_line_in_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -207,16 +277,16 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol,
if (change) {
emu->capture_mic_line_in = val;
if (val) {
- snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_PHONE); /* Mute input */
+ //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
tmp = inl(emu->port+GPIO) & ~0x400;
tmp = tmp | 0x400;
outl(tmp, emu->port+GPIO);
- snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC);
+ //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC);
} else {
- snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_PHONE); /* Mute input */
+ //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
tmp = inl(emu->port+GPIO) & ~0x400;
outl(tmp, emu->port+GPIO);
- snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN);
+ //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN);
}
}
return change;
@@ -225,12 +295,22 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol,
static struct snd_kcontrol_new snd_ca0106_capture_mic_line_in __devinitdata =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Mic/Line in Capture",
+ .name = "Shared Mic/Line in Capture Switch",
.info = snd_ca0106_capture_mic_line_in_info,
.get = snd_ca0106_capture_mic_line_in_get,
.put = snd_ca0106_capture_mic_line_in_put
};
+static struct snd_kcontrol_new snd_ca0106_capture_line_in_side_out __devinitdata =
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Shared Line in/Side out Capture Switch",
+ .info = snd_ca0106_capture_line_in_side_out_info,
+ .get = snd_ca0106_capture_mic_line_in_get,
+ .put = snd_ca0106_capture_mic_line_in_put
+};
+
+
static int snd_ca0106_spdif_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -329,15 +409,81 @@ static int snd_ca0106_volume_put(struct snd_kcontrol *kcontrol,
return 1;
}
+static int snd_ca0106_i2c_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 255;
+ return 0;
+}
+
+static int snd_ca0106_i2c_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
+ int source_id;
+
+ source_id = kcontrol->private_value;
+
+ ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
+ ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
+ return 0;
+}
+
+static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int ogain;
+ unsigned int ngain;
+ int source_id;
+ int change = 0;
+
+ source_id = kcontrol->private_value;
+ ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
+ ngain = ucontrol->value.integer.value[0];
+ if (ngain > 0xff)
+ return 0;
+ if (ogain != ngain) {
+ if (emu->i2c_capture_source == source_id)
+ snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) );
+ emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0];
+ change = 1;
+ }
+ ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
+ ngain = ucontrol->value.integer.value[1];
+ if (ngain > 0xff)
+ return 0;
+ if (ogain != ngain) {
+ if (emu->i2c_capture_source == source_id)
+ snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
+ emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1];
+ change = 1;
+ }
+
+ return change;
+}
+
#define CA_VOLUME(xname,chid,reg) \
{ \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = snd_ca0106_volume_info, \
- .get = snd_ca0106_volume_get, \
- .put = snd_ca0106_volume_put, \
+ .info = snd_ca0106_volume_info, \
+ .get = snd_ca0106_volume_get, \
+ .put = snd_ca0106_volume_put, \
.private_value = ((chid) << 8) | (reg) \
}
+#define I2C_VOLUME(xname,chid) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_ca0106_i2c_volume_info, \
+ .get = snd_ca0106_i2c_volume_get, \
+ .put = snd_ca0106_i2c_volume_put, \
+ .private_value = chid \
+}
+
static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
CA_VOLUME("Analog Front Playback Volume",
@@ -361,6 +507,11 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
CA_VOLUME("CAPTURE feedback Playback Volume",
1, CAPTURE_CONTROL),
+ I2C_VOLUME("Phone Capture Volume", 0),
+ I2C_VOLUME("Mic Capture Volume", 1),
+ I2C_VOLUME("Line in Capture Volume", 2),
+ I2C_VOLUME("Aux Capture Volume", 3),
+
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -378,12 +529,19 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Capture Source",
+ .name = "Digital Capture Source",
.info = snd_ca0106_capture_source_info,
.get = snd_ca0106_capture_source_get,
.put = snd_ca0106_capture_source_put
},
{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .info = snd_ca0106_i2c_capture_source_info,
+ .get = snd_ca0106_i2c_capture_source_get,
+ .put = snd_ca0106_i2c_capture_source_put
+ },
+ {
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
.count = 4,
@@ -477,7 +635,10 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
return err;
}
if (emu->details->i2c_adc == 1) {
- err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu));
+ if (emu->details->gpio_type == 1)
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu));
+ else /* gpio_type == 2 */
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_line_in_side_out, emu));
if (err < 0)
return err;
}
diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c
index 6375727..75ca421 100644
--- a/sound/pci/ca0106/ca0106_proc.c
+++ b/sound/pci/ca0106/ca0106_proc.c
@@ -431,33 +431,30 @@ int __devinit snd_ca0106_proc_init(struct snd_ca0106 * emu)
struct snd_info_entry *entry;
if(! snd_card_proc_new(emu->card, "iec958", &entry))
- snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_iec958);
+ snd_info_set_text_ops(entry, emu, snd_ca0106_proc_iec958);
if(! snd_card_proc_new(emu->card, "ca0106_reg32", &entry)) {
- snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read32);
- entry->c.text.write_size = 64;
+ snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read32);
entry->c.text.write = snd_ca0106_proc_reg_write32;
entry->mode |= S_IWUSR;
}
if(! snd_card_proc_new(emu->card, "ca0106_reg16", &entry))
- snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read16);
+ snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read16);
if(! snd_card_proc_new(emu->card, "ca0106_reg8", &entry))
- snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read8);
+ snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read8);
if(! snd_card_proc_new(emu->card, "ca0106_regs1", &entry)) {
- snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read1);
- entry->c.text.write_size = 64;
+ snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read1);
entry->c.text.write = snd_ca0106_proc_reg_write;
entry->mode |= S_IWUSR;
// entry->private_data = emu;
}
if(! snd_card_proc_new(emu->card, "ca0106_i2c", &entry)) {
- snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_i2c_write);
- entry->c.text.write_size = 64;
+ snd_info_set_text_ops(entry, emu, snd_ca0106_proc_i2c_write);
entry->c.text.write = snd_ca0106_proc_i2c_write;
entry->mode |= S_IWUSR;
// entry->private_data = emu;
}
if(! snd_card_proc_new(emu->card, "ca0106_regs2", &entry))
- snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read2);
+ snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read2);
return 0;
}
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index e5ce2da..0938c15 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -2121,7 +2121,7 @@ static struct snd_kcontrol_new snd_cmipci_mixers[] __devinitdata = {
CMIPCI_MIXER_VOL_MONO("Mic Capture Volume", CM_REG_MIXER2, CM_VADMIC_SHIFT, 7),
CMIPCI_SB_VOL_MONO("Phone Playback Volume", CM_REG_EXTENT_IND, 5, 7),
CMIPCI_DOUBLE("Phone Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 4, 4, 1, 0, 0),
- CMIPCI_DOUBLE("PC Speaker Playnack Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 3, 3, 1, 0, 0),
+ CMIPCI_DOUBLE("PC Speaker Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 3, 3, 1, 0, 0),
CMIPCI_DOUBLE("Mic Boost Capture Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 0, 0, 1, 0, 0),
};
@@ -2602,7 +2602,7 @@ static void __devinit snd_cmipci_proc_init(struct cmipci *cm)
struct snd_info_entry *entry;
if (! snd_card_proc_new(cm->card, "cmipci", &entry))
- snd_info_set_text_ops(entry, cm, 1024, snd_cmipci_proc_read);
+ snd_info_set_text_ops(entry, cm, snd_cmipci_proc_read);
}
#else /* !CONFIG_PROC_FS */
static inline void snd_cmipci_proc_init(struct cmipci *cm) {}
@@ -2932,7 +2932,7 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc
}
integrated_midi = snd_cmipci_read_b(cm, CM_REG_MPU_PCI) != 0xff;
- if (integrated_midi)
+ if (integrated_midi && mpu_port[dev] == 1)
iomidi = cm->iobase + CM_REG_MPU_PCI;
else {
iomidi = mpu_port[dev];
@@ -2981,7 +2981,9 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc
if (iomidi > 0) {
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI,
- iomidi, integrated_midi,
+ iomidi,
+ (integrated_midi ?
+ MPU401_INFO_INTEGRATED : 0),
cm->irq, 0, &cm->rmidi)) < 0) {
printk(KERN_ERR "cmipci: no UART401 device at 0x%lx\n", iomidi);
}
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index b3c94d8..e77a4ce3 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -1184,7 +1184,7 @@ static void __devinit snd_cs4281_proc_init(struct cs4281 * chip)
struct snd_info_entry *entry;
if (! snd_card_proc_new(chip->card, "cs4281", &entry))
- snd_info_set_text_ops(entry, chip, 1024, snd_cs4281_proc_read);
+ snd_info_set_text_ops(entry, chip, snd_cs4281_proc_read);
if (! snd_card_proc_new(chip->card, "cs4281_BA0", &entry)) {
entry->content = SNDRV_INFO_CONTENT_DATA;
entry->private_data = chip;
@@ -1379,6 +1379,13 @@ static int __devinit snd_cs4281_create(struct snd_card *card,
chip->ba0_addr = pci_resource_start(pci, 0);
chip->ba1_addr = pci_resource_start(pci, 1);
+ chip->ba0 = ioremap_nocache(chip->ba0_addr, pci_resource_len(pci, 0));
+ chip->ba1 = ioremap_nocache(chip->ba1_addr, pci_resource_len(pci, 1));
+ if (!chip->ba0 || !chip->ba1) {
+ snd_cs4281_free(chip);
+ return -ENOMEM;
+ }
+
if (request_irq(pci->irq, snd_cs4281_interrupt, SA_INTERRUPT|SA_SHIRQ,
"CS4281", chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
@@ -1387,13 +1394,6 @@ static int __devinit snd_cs4281_create(struct snd_card *card,
}
chip->irq = pci->irq;
- chip->ba0 = ioremap_nocache(chip->ba0_addr, pci_resource_len(pci, 0));
- chip->ba1 = ioremap_nocache(chip->ba1_addr, pci_resource_len(pci, 1));
- if (!chip->ba0 || !chip->ba1) {
- snd_cs4281_free(chip);
- return -ENOMEM;
- }
-
tmp = snd_cs4281_chip_init(chip);
if (tmp) {
snd_cs4281_free(chip);
diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c
index 848d772..772dc52 100644
--- a/sound/pci/cs46xx/cs46xx.c
+++ b/sound/pci/cs46xx/cs46xx.c
@@ -48,8 +48,8 @@ MODULE_SUPPORTED_DEVICE("{{Cirrus Logic,Sound Fusion (CS4280)},"
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
-static int external_amp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
-static int thinkpad[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int external_amp[SNDRV_CARDS];
+static int thinkpad[SNDRV_CARDS];
static int mmap_valid[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
module_param_array(index, int, NULL, 0444);
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index 69dbf54..5c21144 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -2877,14 +2877,15 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip)
if (chip->region.idx[0].resource)
snd_cs46xx_hw_stop(chip);
+ if (chip->irq >= 0)
+ free_irq(chip->irq, chip);
+
for (idx = 0; idx < 5; idx++) {
struct snd_cs46xx_region *region = &chip->region.idx[idx];
if (region->remap_addr)
iounmap(region->remap_addr);
release_and_free_resource(region->resource);
}
- if (chip->irq >= 0)
- free_irq(chip->irq, chip);
if (chip->active_ctrl)
chip->active_ctrl(chip, -chip->amplifier);
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c
index f407d2a..5c9711c 100644
--- a/sound/pci/cs46xx/dsp_spos.c
+++ b/sound/pci/cs46xx/dsp_spos.c
@@ -767,7 +767,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip)
if ((entry = snd_info_create_card_entry(card, "dsp", card->proc_root)) != NULL) {
entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
- entry->c.text.read_size = 512;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
@@ -784,7 +783,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip)
entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->private_data = chip;
entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
- entry->c.text.read_size = 512;
entry->c.text.read = cs46xx_dsp_proc_symbol_table_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
@@ -797,7 +795,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip)
entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->private_data = chip;
entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
- entry->c.text.read_size = 512;
entry->c.text.read = cs46xx_dsp_proc_modules_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
@@ -810,7 +807,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip)
entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->private_data = chip;
entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
- entry->c.text.read_size = 512;
entry->c.text.read = cs46xx_dsp_proc_parameter_dump_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
@@ -823,7 +819,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip)
entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->private_data = chip;
entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
- entry->c.text.read_size = 512;
entry->c.text.read = cs46xx_dsp_proc_sample_dump_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
@@ -836,7 +831,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip)
entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->private_data = chip;
entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
- entry->c.text.read_size = 512;
entry->c.text.read = cs46xx_dsp_proc_task_tree_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
@@ -849,7 +843,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip)
entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->private_data = chip;
entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
- entry->c.text.read_size = 1024;
entry->c.text.read = cs46xx_dsp_proc_scb_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c
index 2c4ee45..3844d18 100644
--- a/sound/pci/cs46xx/dsp_spos_scb_lib.c
+++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c
@@ -267,7 +267,6 @@ void cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip,
entry->private_data = scb_info;
entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
- entry->c.text.read_size = 512;
entry->c.text.read = cs46xx_dsp_proc_scb_info_read;
if (snd_info_register(entry) < 0) {
diff --git a/sound/pci/cs5535audio/Makefile b/sound/pci/cs5535audio/Makefile
index 08d8ee6..2911a8a 100644
--- a/sound/pci/cs5535audio/Makefile
+++ b/sound/pci/cs5535audio/Makefile
@@ -4,5 +4,9 @@
snd-cs5535audio-objs := cs5535audio.o cs5535audio_pcm.o
+ifdef CONFIG_PM
+snd-cs5535audio-objs += cs5535audio_pm.o
+endif
+
# Toplevel Module Dependency
obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c
index 2c1213a..91c18a1 100644
--- a/sound/pci/cs5535audio/cs5535audio.c
+++ b/sound/pci/cs5535audio/cs5535audio.c
@@ -1,5 +1,5 @@
/*
- * Driver for audio on multifunction CS5535 companion device
+ * Driver for audio on multifunction CS5535/6 companion device
* Copyright (C) Jaya Kumar
*
* Based on Jaroslav Kysela and Takashi Iwai's examples.
@@ -40,16 +40,36 @@
#define DRIVER_NAME "cs5535audio"
+static char *ac97_quirk;
+module_param(ac97_quirk, charp, 0444);
+MODULE_PARM_DESC(ac97_quirk, "AC'97 board specific workarounds.");
+
+static struct ac97_quirk ac97_quirks[] __devinitdata = {
+#if 0 /* Not yet confirmed if all 5536 boards are HP only */
+ {
+ .subvendor = PCI_VENDOR_ID_AMD,
+ .subdevice = PCI_DEVICE_ID_AMD_CS5536_AUDIO,
+ .name = "AMD RDK",
+ .type = AC97_TUNE_HP_ONLY
+ },
+#endif
+ {}
+};
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for " DRIVER_NAME);
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for " DRIVER_NAME);
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable " DRIVER_NAME);
+
static struct pci_device_id snd_cs5535audio_ids[] __devinitdata = {
- { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_AUDIO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_AUDIO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_AUDIO) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_AUDIO) },
{}
};
@@ -90,7 +110,8 @@ static unsigned short snd_cs5535audio_codec_read(struct cs5535audio *cs5535au,
udelay(1);
} while (--timeout);
if (!timeout)
- snd_printk(KERN_ERR "Failure reading cs5535 codec\n");
+ snd_printk(KERN_ERR "Failure reading codec reg 0x%x,"
+ "Last value=0x%x\n", reg, val);
return (unsigned short) val;
}
@@ -148,6 +169,8 @@ static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
return err;
}
+ snd_ac97_tune_hardware(cs5535au->ac97, ac97_quirks, ac97_quirk);
+
return 0;
}
@@ -347,6 +370,8 @@ static int __devinit snd_cs5535audio_probe(struct pci_dev *pci,
if ((err = snd_cs5535audio_create(card, pci, &cs5535au)) < 0)
goto probefail_out;
+ card->private_data = cs5535au;
+
if ((err = snd_cs5535audio_mixer(cs5535au)) < 0)
goto probefail_out;
@@ -383,6 +408,10 @@ static struct pci_driver driver = {
.id_table = snd_cs5535audio_ids,
.probe = snd_cs5535audio_probe,
.remove = __devexit_p(snd_cs5535audio_remove),
+#ifdef CONFIG_PM
+ .suspend = snd_cs5535audio_suspend,
+ .resume = snd_cs5535audio_resume,
+#endif
};
static int __init alsa_card_cs5535audio_init(void)
diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h
index 5e55a1a..4fd1f31 100644
--- a/sound/pci/cs5535audio/cs5535audio.h
+++ b/sound/pci/cs5535audio/cs5535audio.h
@@ -74,6 +74,8 @@
#define PRM_RDY_STS 0x00800000
#define ACC_CODEC_CNTL_WR_CMD (~0x80000000)
#define ACC_CODEC_CNTL_RD_CMD 0x80000000
+#define ACC_CODEC_CNTL_LNK_SHUTDOWN 0x00040000
+#define ACC_CODEC_CNTL_LNK_WRM_RST 0x00020000
#define PRD_JMP 0x2000
#define PRD_EOP 0x4000
#define PRD_EOT 0x8000
@@ -88,6 +90,7 @@ struct cs5535audio_dma_ops {
void (*disable_dma)(struct cs5535audio *cs5535au);
void (*pause_dma)(struct cs5535audio *cs5535au);
void (*setup_prd)(struct cs5535audio *cs5535au, u32 prd_addr);
+ u32 (*read_prd)(struct cs5535audio *cs5535au);
u32 (*read_dma_pntr)(struct cs5535audio *cs5535au);
};
@@ -103,11 +106,14 @@ struct cs5535audio_dma {
struct snd_pcm_substream *substream;
unsigned int buf_addr, buf_bytes;
unsigned int period_bytes, periods;
+ int suspended;
+ u32 saved_prd;
};
struct cs5535audio {
struct snd_card *card;
struct snd_ac97 *ac97;
+ struct snd_pcm *pcm;
int irq;
struct pci_dev *pci;
unsigned long port;
@@ -117,6 +123,8 @@ struct cs5535audio {
struct cs5535audio_dma dmas[NUM_CS5535AUDIO_DMAS];
};
+int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state);
+int snd_cs5535audio_resume(struct pci_dev *pci);
int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio);
#endif /* __SOUND_CS5535AUDIO_H */
diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c
index 60bb82b..f0a4869 100644
--- a/sound/pci/cs5535audio/cs5535audio_pcm.c
+++ b/sound/pci/cs5535audio/cs5535audio_pcm.c
@@ -43,7 +43,8 @@ static struct snd_pcm_hardware snd_cs5535audio_playback =
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_SYNC_START
+ SNDRV_PCM_INFO_SYNC_START |
+ SNDRV_PCM_INFO_RESUME
),
.formats = (
SNDRV_PCM_FMTBIT_S16_LE
@@ -193,6 +194,11 @@ static void cs5535audio_playback_setup_prd(struct cs5535audio *cs5535au,
cs_writel(cs5535au, ACC_BM0_PRD, prd_addr);
}
+static u32 cs5535audio_playback_read_prd(struct cs5535audio *cs5535au)
+{
+ return cs_readl(cs5535au, ACC_BM0_PRD);
+}
+
static u32 cs5535audio_playback_read_dma_pntr(struct cs5535audio *cs5535au)
{
return cs_readl(cs5535au, ACC_BM0_PNTR);
@@ -219,6 +225,11 @@ static void cs5535audio_capture_setup_prd(struct cs5535audio *cs5535au,
cs_writel(cs5535au, ACC_BM1_PRD, prd_addr);
}
+static u32 cs5535audio_capture_read_prd(struct cs5535audio *cs5535au)
+{
+ return cs_readl(cs5535au, ACC_BM1_PRD);
+}
+
static u32 cs5535audio_capture_read_dma_pntr(struct cs5535audio *cs5535au)
{
return cs_readl(cs5535au, ACC_BM1_PNTR);
@@ -285,9 +296,17 @@ static int snd_cs5535audio_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_START:
dma->ops->enable_dma(cs5535au);
break;
+ case SNDRV_PCM_TRIGGER_RESUME:
+ dma->ops->enable_dma(cs5535au);
+ dma->suspended = 0;
+ break;
case SNDRV_PCM_TRIGGER_STOP:
dma->ops->disable_dma(cs5535au);
break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ dma->ops->disable_dma(cs5535au);
+ dma->suspended = 1;
+ break;
default:
snd_printk(KERN_ERR "unhandled trigger\n");
err = -EINVAL;
@@ -375,6 +394,7 @@ static struct cs5535audio_dma_ops snd_cs5535audio_playback_dma_ops = {
.enable_dma = cs5535audio_playback_enable_dma,
.disable_dma = cs5535audio_playback_disable_dma,
.setup_prd = cs5535audio_playback_setup_prd,
+ .read_prd = cs5535audio_playback_read_prd,
.pause_dma = cs5535audio_playback_pause_dma,
.read_dma_pntr = cs5535audio_playback_read_dma_pntr,
};
@@ -384,6 +404,7 @@ static struct cs5535audio_dma_ops snd_cs5535audio_capture_dma_ops = {
.enable_dma = cs5535audio_capture_enable_dma,
.disable_dma = cs5535audio_capture_disable_dma,
.setup_prd = cs5535audio_capture_setup_prd,
+ .read_prd = cs5535audio_capture_read_prd,
.pause_dma = cs5535audio_capture_pause_dma,
.read_dma_pntr = cs5535audio_capture_read_dma_pntr,
};
@@ -413,6 +434,7 @@ int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535au)
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(cs5535au->pci),
64*1024, 128*1024);
+ cs5535au->pcm = pcm;
return 0;
}
diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c
new file mode 100644
index 0000000..aad0e69
--- /dev/null
+++ b/sound/pci/cs5535audio/cs5535audio_pm.c
@@ -0,0 +1,123 @@
+/*
+ * Power management for audio on multifunction CS5535 companion device
+ * Copyright (C) Jaya Kumar
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+#include <sound/asoundef.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include "cs5535audio.h"
+
+static void snd_cs5535audio_stop_hardware(struct cs5535audio *cs5535au)
+{
+ /*
+ we depend on snd_ac97_suspend to tell the
+ AC97 codec to shutdown. the amd spec suggests
+ that the LNK_SHUTDOWN be done at the same time
+ that the codec power-down is issued. instead,
+ we do it just after rather than at the same
+ time. excluding codec specific build_ops->suspend
+ ac97 powerdown hits:
+ 0x8000 EAPD
+ 0x4000 Headphone amplifier
+ 0x0300 ADC & DAC
+ 0x0400 Analog Mixer powerdown (Vref on)
+ I am not sure if this is the best that we can do.
+ The remainder to be investigated are:
+ - analog mixer (vref off) 0x0800
+ - AC-link powerdown 0x1000
+ - codec internal clock 0x2000
+ */
+
+ /* set LNK_SHUTDOWN to shutdown AC link */
+ cs_writel(cs5535au, ACC_CODEC_CNTL, ACC_CODEC_CNTL_LNK_SHUTDOWN);
+
+}
+
+int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state)
+{
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct cs5535audio *cs5535au = card->private_data;
+ int i;
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+ for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) {
+ struct cs5535audio_dma *dma = &cs5535au->dmas[i];
+ if (dma && dma->substream && !dma->suspended)
+ dma->saved_prd = dma->ops->read_prd(cs5535au);
+ }
+ snd_pcm_suspend_all(cs5535au->pcm);
+ snd_ac97_suspend(cs5535au->ac97);
+ /* save important regs, then disable aclink in hw */
+ snd_cs5535audio_stop_hardware(cs5535au);
+ pci_disable_device(pci);
+ pci_save_state(pci);
+
+ return 0;
+}
+
+int snd_cs5535audio_resume(struct pci_dev *pci)
+{
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct cs5535audio *cs5535au = card->private_data;
+ u32 tmp;
+ int timeout;
+ int i;
+
+ pci_restore_state(pci);
+ pci_enable_device(pci);
+ pci_set_master(pci);
+
+ /* set LNK_WRM_RST to reset AC link */
+ cs_writel(cs5535au, ACC_CODEC_CNTL, ACC_CODEC_CNTL_LNK_WRM_RST);
+
+ timeout = 50;
+ do {
+ tmp = cs_readl(cs5535au, ACC_CODEC_STATUS);
+ if (tmp & PRM_RDY_STS)
+ break;
+ udelay(1);
+ } while (--timeout);
+
+ if (!timeout)
+ snd_printk(KERN_ERR "Failure getting AC Link ready\n");
+
+ /* we depend on ac97 to perform the codec power up */
+ snd_ac97_resume(cs5535au->ac97);
+ /* set up rate regs, dma. actual initiation is done in trig */
+ for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) {
+ struct cs5535audio_dma *dma = &cs5535au->dmas[i];
+ if (dma && dma->substream && dma->suspended) {
+ dma->substream->ops->prepare(dma->substream);
+ dma->ops->setup_prd(cs5535au, dma->saved_prd);
+ }
+ }
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+
+ return 0;
+}
+
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
index 42b11ba..549673e 100644
--- a/sound/pci/emu10k1/emu10k1.c
+++ b/sound/pci/emu10k1/emu10k1.c
@@ -46,13 +46,13 @@ MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB Live!/PCI512/E-mu APS},"
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
-static int extin[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
-static int extout[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int extin[SNDRV_CARDS];
+static int extout[SNDRV_CARDS];
static int seq_ports[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4};
static int max_synth_voices[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 64};
static int max_buffer_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 128};
-static int enable_ir[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
-static uint subsystem[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; /* Force card subsystem model */
+static int enable_ir[SNDRV_CARDS];
+static uint subsystem[SNDRV_CARDS]; /* Force card subsystem model */
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for the EMU10K1 soundcard.");
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 6bfa084..42a358f 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -777,14 +777,6 @@ static int snd_emu10k1_dev_free(struct snd_device *device)
static struct snd_emu_chip_details emu_chip_details[] = {
/* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/
- /* Audigy4 SB0400 */
- {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10211102,
- .driver = "Audigy2", .name = "Audigy 4 [SB0400]",
- .id = "Audigy2",
- .emu10k2_chip = 1,
- .ca0108_chip = 1,
- .spk71 = 1,
- .ac97_chip = 1} ,
/* Tested by James@superbug.co.uk 3rd July 2005 */
/* DSP: CA0108-IAT
* DAC: CS4382-KQ
@@ -799,13 +791,59 @@ static struct snd_emu_chip_details emu_chip_details[] = {
.ca0108_chip = 1,
.spk71 = 1,
.ac97_chip = 1} ,
+ /* Audigy4 (Not PRO) SB0610 */
+ /* Tested by James@superbug.co.uk 4th April 2006 */
+ /* A_IOCFG bits
+ * Output
+ * 0: ?
+ * 1: ?
+ * 2: ?
+ * 3: 0 - Digital Out, 1 - Line in
+ * 4: ?
+ * 5: ?
+ * 6: ?
+ * 7: ?
+ * Input
+ * 8: ?
+ * 9: ?
+ * A: Green jack sense (Front)
+ * B: ?
+ * C: Black jack sense (Rear/Side Right)
+ * D: Yellow jack sense (Center/LFE/Side Left)
+ * E: ?
+ * F: ?
+ *
+ * Digital Out/Line in switch using A_IOCFG bit 3 (0x08)
+ * 0 - Digital Out
+ * 1 - Line in
+ */
+ /* Mic input not tested.
+ * Analog CD input not tested
+ * Digital Out not tested.
+ * Line in working.
+ * Audio output 5.1 working. Side outputs not working.
+ */
+ /* DSP: CA10300-IAT LF
+ * DAC: Cirrus Logic CS4382-KQZ
+ * ADC: Philips 1361T
+ * AC97: Sigmatel STAC9750
+ * CA0151: None
+ */
+ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10211102,
+ .driver = "Audigy2", .name = "Audigy 4 [SB0610]",
+ .id = "Audigy2",
+ .emu10k2_chip = 1,
+ .ca0108_chip = 1,
+ .spk71 = 1,
+ .adc_1361t = 1, /* 24 bit capture instead of 16bit */
+ .ac97_chip = 1} ,
/* Audigy 2 ZS Notebook Cardbus card.*/
/* Tested by James@superbug.co.uk 22th December 2005 */
/* Audio output 7.1/Headphones working.
* Digital output working. (AC3 not checked, only PCM)
* Audio inputs not tested.
*/
- /* DSP: Tiny2
+ /* DSP: Tina2
* DAC: Wolfson WM8768/WM8568
* ADC: Wolfson WM8775
* AC97: None
@@ -1421,16 +1459,3 @@ void snd_emu10k1_resume_regs(struct snd_emu10k1 *emu)
}
}
#endif
-
-/* memory.c */
-EXPORT_SYMBOL(snd_emu10k1_synth_alloc);
-EXPORT_SYMBOL(snd_emu10k1_synth_free);
-EXPORT_SYMBOL(snd_emu10k1_synth_bzero);
-EXPORT_SYMBOL(snd_emu10k1_synth_copy_from_user);
-EXPORT_SYMBOL(snd_emu10k1_memblk_map);
-/* voice.c */
-EXPORT_SYMBOL(snd_emu10k1_voice_alloc);
-EXPORT_SYMBOL(snd_emu10k1_voice_free);
-/* io.c */
-EXPORT_SYMBOL(snd_emu10k1_ptr_read);
-EXPORT_SYMBOL(snd_emu10k1_ptr_write);
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index d51290c..0fb27e4 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -1055,8 +1055,7 @@ static int __devinit snd_emu10k1x_proc_init(struct emu10k1x * emu)
struct snd_info_entry *entry;
if(! snd_card_proc_new(emu->card, "emu10k1x_regs", &entry)) {
- snd_info_set_text_ops(entry, emu, 1024, snd_emu10k1x_proc_reg_read);
- entry->c.text.write_size = 64;
+ snd_info_set_text_ops(entry, emu, snd_emu10k1x_proc_reg_read);
entry->c.text.write = snd_emu10k1x_proc_reg_write;
entry->mode |= S_IWUSR;
entry->private_data = emu;
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
index 2a9d12d..c31f3d0 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -777,6 +777,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
};
static char *audigy_remove_ctls[] = {
/* Master/PCM controls on ac97 of Audigy has no effect */
+ /* On the Audigy2 the AC97 playback is piped into
+ * the Philips ADC for 24bit capture */
"PCM Playback Switch",
"PCM Playback Volume",
"Master Mono Playback Switch",
@@ -804,6 +806,47 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
"AMic Playback Volume", "Mic Playback Volume",
NULL
};
+ static char *audigy_remove_ctls_1361t_adc[] = {
+ /* On the Audigy2 the AC97 playback is piped into
+ * the Philips ADC for 24bit capture */
+ "PCM Playback Switch",
+ "PCM Playback Volume",
+ "Master Mono Playback Switch",
+ "Master Mono Playback Volume",
+ "Capture Source",
+ "Capture Switch",
+ "Capture Volume",
+ "Mic Capture Volume",
+ "Headphone Playback Switch",
+ "Headphone Playback Volume",
+ "3D Control - Center",
+ "3D Control - Depth",
+ "3D Control - Switch",
+ "Line2 Playback Volume",
+ "Line2 Capture Volume",
+ NULL
+ };
+ static char *audigy_rename_ctls_1361t_adc[] = {
+ "Master Playback Switch", "Master Capture Switch",
+ "Master Playback Volume", "Master Capture Volume",
+ "Wave Master Playback Volume", "Master Playback Volume",
+ "PC Speaker Playback Switch", "PC Speaker Capture Switch",
+ "PC Speaker Playback Volume", "PC Speaker Capture Volume",
+ "Phone Playback Switch", "Phone Capture Switch",
+ "Phone Playback Volume", "Phone Capture Volume",
+ "Mic Playback Switch", "Mic Capture Switch",
+ "Mic Playback Volume", "Mic Capture Volume",
+ "Line Playback Switch", "Line Capture Switch",
+ "Line Playback Volume", "Line Capture Volume",
+ "CD Playback Switch", "CD Capture Switch",
+ "CD Playback Volume", "CD Capture Volume",
+ "Aux Playback Switch", "Aux Capture Switch",
+ "Aux Playback Volume", "Aux Capture Volume",
+ "Video Playback Switch", "Video Capture Switch",
+ "Video Playback Volume", "Video Capture Volume",
+
+ NULL
+ };
if (emu->card_capabilities->ac97_chip) {
struct snd_ac97_bus *pbus;
@@ -834,7 +877,10 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
/* set capture source to mic */
snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
- c = audigy_remove_ctls;
+ if (emu->card_capabilities->adc_1361t)
+ c = audigy_remove_ctls_1361t_adc;
+ else
+ c = audigy_remove_ctls;
} else {
/*
* Credits for cards based on STAC9758:
@@ -863,11 +909,15 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
}
if (emu->audigy)
- c = audigy_rename_ctls;
+ if (emu->card_capabilities->adc_1361t)
+ c = audigy_rename_ctls_1361t_adc;
+ else
+ c = audigy_rename_ctls;
else
c = emu10k1_rename_ctls;
for (; *c; c += 2)
rename_ctl(card, c[0], c[1]);
+
if (emu->card_capabilities->subsystem == 0x20071102) { /* Audigy 4 Pro */
rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c
index 90f1c52..b939e03 100644
--- a/sound/pci/emu10k1/emuproc.c
+++ b/sound/pci/emu10k1/emuproc.c
@@ -532,57 +532,51 @@ int __devinit snd_emu10k1_proc_init(struct snd_emu10k1 * emu)
struct snd_info_entry *entry;
#ifdef CONFIG_SND_DEBUG
if (! snd_card_proc_new(emu->card, "io_regs", &entry)) {
- snd_info_set_text_ops(entry, emu, 1024, snd_emu_proc_io_reg_read);
- entry->c.text.write_size = 64;
+ snd_info_set_text_ops(entry, emu, snd_emu_proc_io_reg_read);
entry->c.text.write = snd_emu_proc_io_reg_write;
entry->mode |= S_IWUSR;
}
if (! snd_card_proc_new(emu->card, "ptr_regs00a", &entry)) {
- snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00a);
- entry->c.text.write_size = 64;
+ snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read00a);
entry->c.text.write = snd_emu_proc_ptr_reg_write00;
entry->mode |= S_IWUSR;
}
if (! snd_card_proc_new(emu->card, "ptr_regs00b", &entry)) {
- snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00b);
- entry->c.text.write_size = 64;
+ snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read00b);
entry->c.text.write = snd_emu_proc_ptr_reg_write00;
entry->mode |= S_IWUSR;
}
if (! snd_card_proc_new(emu->card, "ptr_regs20a", &entry)) {
- snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20a);
- entry->c.text.write_size = 64;
+ snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read20a);
entry->c.text.write = snd_emu_proc_ptr_reg_write20;
entry->mode |= S_IWUSR;
}
if (! snd_card_proc_new(emu->card, "ptr_regs20b", &entry)) {
- snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20b);
- entry->c.text.write_size = 64;
+ snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read20b);
entry->c.text.write = snd_emu_proc_ptr_reg_write20;
entry->mode |= S_IWUSR;
}
if (! snd_card_proc_new(emu->card, "ptr_regs20c", &entry)) {
- snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20c);
- entry->c.text.write_size = 64;
+ snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read20c);
entry->c.text.write = snd_emu_proc_ptr_reg_write20;
entry->mode |= S_IWUSR;
}
#endif
if (! snd_card_proc_new(emu->card, "emu10k1", &entry))
- snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_read);
+ snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_read);
if (emu->card_capabilities->emu10k2_chip) {
if (! snd_card_proc_new(emu->card, "spdif-in", &entry))
- snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_spdif_read);
+ snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_spdif_read);
}
if (emu->card_capabilities->ca0151_chip) {
if (! snd_card_proc_new(emu->card, "capture-rates", &entry))
- snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_rates_read);
+ snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_rates_read);
}
if (! snd_card_proc_new(emu->card, "voices", &entry))
- snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_voices_read);
+ snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_voices_read);
if (! snd_card_proc_new(emu->card, "fx8010_gpr", &entry)) {
entry->content = SNDRV_INFO_CONTENT_DATA;
@@ -616,7 +610,6 @@ int __devinit snd_emu10k1_proc_init(struct snd_emu10k1 * emu)
entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->private_data = emu;
entry->mode = S_IFREG | S_IRUGO /*| S_IWUSR*/;
- entry->c.text.read_size = 128*1024;
entry->c.text.read = snd_emu10k1_proc_acode_read;
}
return 0;
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c
index ef5304d..029e785 100644
--- a/sound/pci/emu10k1/io.c
+++ b/sound/pci/emu10k1/io.c
@@ -62,6 +62,8 @@ unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, un
}
}
+EXPORT_SYMBOL(snd_emu10k1_ptr_read);
+
void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data)
{
unsigned int regptr;
@@ -92,6 +94,8 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i
}
}
+EXPORT_SYMBOL(snd_emu10k1_ptr_write);
+
unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu,
unsigned int reg,
unsigned int chn)
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c
index e7ec986..4fcaefe 100644
--- a/sound/pci/emu10k1/memory.c
+++ b/sound/pci/emu10k1/memory.c
@@ -287,6 +287,8 @@ int snd_emu10k1_memblk_map(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *b
return err;
}
+EXPORT_SYMBOL(snd_emu10k1_memblk_map);
+
/*
* page allocation for DMA
*/
@@ -387,6 +389,7 @@ snd_emu10k1_synth_alloc(struct snd_emu10k1 *hw, unsigned int size)
return (struct snd_util_memblk *)blk;
}
+EXPORT_SYMBOL(snd_emu10k1_synth_alloc);
/*
* free a synth sample area
@@ -409,6 +412,7 @@ snd_emu10k1_synth_free(struct snd_emu10k1 *emu, struct snd_util_memblk *memblk)
return 0;
}
+EXPORT_SYMBOL(snd_emu10k1_synth_free);
/* check new allocation range */
static void get_single_page_range(struct snd_util_memhdr *hdr,
@@ -540,6 +544,8 @@ int snd_emu10k1_synth_bzero(struct snd_emu10k1 *emu, struct snd_util_memblk *blk
return 0;
}
+EXPORT_SYMBOL(snd_emu10k1_synth_bzero);
+
/*
* copy_from_user(blk + offset, data, size)
*/
@@ -568,3 +574,5 @@ int snd_emu10k1_synth_copy_from_user(struct snd_emu10k1 *emu, struct snd_util_me
} while (offset < end_offset);
return 0;
}
+
+EXPORT_SYMBOL(snd_emu10k1_synth_copy_from_user);
diff --git a/sound/pci/emu10k1/p17v.h b/sound/pci/emu10k1/p17v.h
new file mode 100644
index 0000000..7ddb5be
--- /dev/null
+++ b/sound/pci/emu10k1/p17v.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk>
+ * Driver p17v chips
+ * Version: 0.01
+ *
+ * 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
+ *
+ */
+
+/******************************************************************************/
+/* Audigy2Value Tina (P17V) pointer-offset register set,
+ * accessed through the PTR20 and DATA24 registers */
+/******************************************************************************/
+
+/* 00 - 07: Not used */
+#define P17V_PLAYBACK_FIFO_PTR 0x08 /* Current playback fifo pointer
+ * and number of sound samples in cache.
+ */
+/* 09 - 12: Not used */
+#define P17V_CAPTURE_FIFO_PTR 0x13 /* Current capture fifo pointer
+ * and number of sound samples in cache.
+ */
+/* 14 - 17: Not used */
+#define P17V_PB_CHN_SEL 0x18 /* P17v playback channel select */
+#define P17V_SE_SLOT_SEL_L 0x19 /* Sound Engine slot select low */
+#define P17V_SE_SLOT_SEL_H 0x1a /* Sound Engine slot select high */
+/* 1b - 1f: Not used */
+/* 20 - 2f: Not used */
+/* 30 - 3b: Not used */
+#define P17V_SPI 0x3c /* SPI interface register */
+#define P17V_I2C_ADDR 0x3d /* I2C Address */
+#define P17V_I2C_0 0x3e /* I2C Data */
+#define P17V_I2C_1 0x3f /* I2C Data */
+
+#define P17V_START_AUDIO 0x40 /* Start Audio bit */
+/* 41 - 47: Reserved */
+#define P17V_START_CAPTURE 0x48 /* Start Capture bit */
+#define P17V_CAPTURE_FIFO_BASE 0x49 /* Record FIFO base address */
+#define P17V_CAPTURE_FIFO_SIZE 0x4a /* Record FIFO buffer size */
+#define P17V_CAPTURE_FIFO_INDEX 0x4b /* Record FIFO capture index */
+#define P17V_CAPTURE_VOL_H 0x4c /* P17v capture volume control */
+#define P17V_CAPTURE_VOL_L 0x4d /* P17v capture volume control */
+/* 4e - 4f: Not used */
+/* 50 - 5f: Not used */
+#define P17V_SRCSel 0x60 /* SRC48 and SRCMulti sample rate select
+ * and output select
+ */
+#define P17V_MIXER_AC97_10K1_VOL_L 0x61 /* 10K to Mixer_AC97 input volume control */
+#define P17V_MIXER_AC97_10K1_VOL_H 0x62 /* 10K to Mixer_AC97 input volume control */
+#define P17V_MIXER_AC97_P17V_VOL_L 0x63 /* P17V to Mixer_AC97 input volume control */
+#define P17V_MIXER_AC97_P17V_VOL_H 0x64 /* P17V to Mixer_AC97 input volume control */
+#define P17V_MIXER_AC97_SRP_REC_VOL_L 0x65 /* SRP Record to Mixer_AC97 input volume control */
+#define P17V_MIXER_AC97_SRP_REC_VOL_H 0x66 /* SRP Record to Mixer_AC97 input volume control */
+/* 67 - 68: Reserved */
+#define P17V_MIXER_Spdif_10K1_VOL_L 0x69 /* 10K to Mixer_Spdif input volume control */
+#define P17V_MIXER_Spdif_10K1_VOL_H 0x6A /* 10K to Mixer_Spdif input volume control */
+#define P17V_MIXER_Spdif_P17V_VOL_L 0x6B /* P17V to Mixer_Spdif input volume control */
+#define P17V_MIXER_Spdif_P17V_VOL_H 0x6C /* P17V to Mixer_Spdif input volume control */
+#define P17V_MIXER_Spdif_SRP_REC_VOL_L 0x6D /* SRP Record to Mixer_Spdif input volume control */
+#define P17V_MIXER_Spdif_SRP_REC_VOL_H 0x6E /* SRP Record to Mixer_Spdif input volume control */
+/* 6f - 70: Reserved */
+#define P17V_MIXER_I2S_10K1_VOL_L 0x71 /* 10K to Mixer_I2S input volume control */
+#define P17V_MIXER_I2S_10K1_VOL_H 0x72 /* 10K to Mixer_I2S input volume control */
+#define P17V_MIXER_I2S_P17V_VOL_L 0x73 /* P17V to Mixer_I2S input volume control */
+#define P17V_MIXER_I2S_P17V_VOL_H 0x74 /* P17V to Mixer_I2S input volume control */
+#define P17V_MIXER_I2S_SRP_REC_VOL_L 0x75 /* SRP Record to Mixer_I2S input volume control */
+#define P17V_MIXER_I2S_SRP_REC_VOL_H 0x76 /* SRP Record to Mixer_I2S input volume control */
+/* 77 - 78: Reserved */
+#define P17V_MIXER_AC97_ENABLE 0x79 /* Mixer AC97 input audio enable */
+#define P17V_MIXER_SPDIF_ENABLE 0x7A /* Mixer SPDIF input audio enable */
+#define P17V_MIXER_I2S_ENABLE 0x7B /* Mixer I2S input audio enable */
+#define P17V_AUDIO_OUT_ENABLE 0x7C /* Audio out enable */
+#define P17V_MIXER_ATT 0x7D /* SRP Mixer Attenuation Select */
+#define P17V_SRP_RECORD_SRR 0x7E /* SRP Record channel source Select */
+#define P17V_SOFT_RESET_SRP_MIXER 0x7F /* SRP and mixer soft reset */
+
+#define P17V_AC97_OUT_MASTER_VOL_L 0x80 /* AC97 Output master volume control */
+#define P17V_AC97_OUT_MASTER_VOL_H 0x81 /* AC97 Output master volume control */
+#define P17V_SPDIF_OUT_MASTER_VOL_L 0x82 /* SPDIF Output master volume control */
+#define P17V_SPDIF_OUT_MASTER_VOL_H 0x83 /* SPDIF Output master volume control */
+#define P17V_I2S_OUT_MASTER_VOL_L 0x84 /* I2S Output master volume control */
+#define P17V_I2S_OUT_MASTER_VOL_H 0x85 /* I2S Output master volume control */
+/* 86 - 87: Not used */
+#define P17V_I2S_CHANNEL_SWAP_PHASE_INVERSE 0x88 /* I2S out mono channel swap
+ * and phase inverse */
+#define P17V_SPDIF_CHANNEL_SWAP_PHASE_INVERSE 0x89 /* SPDIF out mono channel swap
+ * and phase inverse */
+/* 8A: Not used */
+#define P17V_SRP_P17V_ESR 0x8B /* SRP_P17V estimated sample rate and rate lock */
+#define P17V_SRP_REC_ESR 0x8C /* SRP_REC estimated sample rate and rate lock */
+#define P17V_SRP_BYPASS 0x8D /* srps channel bypass and srps bypass */
+/* 8E - 92: Not used */
+#define P17V_I2S_SRC_SEL 0x93 /* I2SIN mode sel */
+
+
+
+
+
+
diff --git a/sound/pci/emu10k1/tina2.h b/sound/pci/emu10k1/tina2.h
index 5c43abf..f2d8eb6 100644
--- a/sound/pci/emu10k1/tina2.h
+++ b/sound/pci/emu10k1/tina2.h
@@ -1,11 +1,7 @@
/*
* Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk>
- * Driver p16v chips
- * Version: 0.21
- *
- *
- * This code was initally based on code from ALSA's emu10k1x.c which is:
- * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
+ * Driver tina2 chips
+ * Version: 0.1
*
* 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
diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c
index 56ffb7d..94eca82 100644
--- a/sound/pci/emu10k1/voice.c
+++ b/sound/pci/emu10k1/voice.c
@@ -139,6 +139,8 @@ int snd_emu10k1_voice_alloc(struct snd_emu10k1 *emu, int type, int number,
return result;
}
+EXPORT_SYMBOL(snd_emu10k1_voice_alloc);
+
int snd_emu10k1_voice_free(struct snd_emu10k1 *emu,
struct snd_emu10k1_voice *pvoice)
{
@@ -153,3 +155,5 @@ int snd_emu10k1_voice_free(struct snd_emu10k1 *emu,
spin_unlock_irqrestore(&emu->voice_lock, flags);
return 0;
}
+
+EXPORT_SYMBOL(snd_emu10k1_voice_free);
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index ca9e34e..9d46bbe 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -1915,7 +1915,7 @@ static void __devinit snd_ensoniq_proc_init(struct ensoniq * ensoniq)
struct snd_info_entry *entry;
if (! snd_card_proc_new(ensoniq->card, "audiopci", &entry))
- snd_info_set_text_ops(entry, ensoniq, 1024, snd_ensoniq_proc_read);
+ snd_info_set_text_ops(entry, ensoniq, snd_ensoniq_proc_read);
}
/*
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 6f9094c..ca6603f 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -1756,7 +1756,8 @@ static int __devinit snd_es1938_probe(struct pci_dev *pci,
}
}
if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
- chip->mpu_port, 1, chip->irq, 0, &chip->rmidi) < 0) {
+ chip->mpu_port, MPU401_INFO_INTEGRATED,
+ chip->irq, 0, &chip->rmidi) < 0) {
printk(KERN_ERR "es1938: unable to initialize MPU-401\n");
} else {
// this line is vital for MIDI interrupt handling on ess-solo1
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index 5ff4175..bfa0876 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -132,7 +132,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card *
static int total_bufsize[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1024 };
static int pcm_substreams_p[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4 };
static int pcm_substreams_c[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1 };
-static int clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int clock[SNDRV_CARDS];
static int use_pm[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
static int enable_mpu[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
#ifdef SUPPORT_JOYSTICK
@@ -2727,7 +2727,8 @@ static int __devinit snd_es1968_probe(struct pci_dev *pci,
}
if (enable_mpu[dev]) {
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
- chip->io_port + ESM_MPU401_PORT, 1,
+ chip->io_port + ESM_MPU401_PORT,
+ MPU401_INFO_INTEGRATED,
chip->irq, 0, &chip->rmidi)) < 0) {
printk(KERN_WARNING "es1968: skipping MPU-401 MIDI support..\n");
}
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index d72fc28..0afa573 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -56,7 +56,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card *
* 3 = MediaForte 64-PCR
* High 16-bits are video (radio) device number + 1
*/
-static int tea575x_tuner[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 };
+static int tea575x_tuner[SNDRV_CARDS];
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for the FM801 soundcard.");
@@ -1448,7 +1448,8 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci,
return err;
}
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_FM801,
- FM801_REG(chip, MPU401_DATA), 1,
+ FM801_REG(chip, MPU401_DATA),
+ MPU401_INFO_INTEGRATED,
chip->irq, 0, &chip->rmidi)) < 0) {
snd_card_free(card);
return err;
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index ddfb5ff..dbacba6 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -1,5 +1,5 @@
snd-hda-intel-objs := hda_intel.o
-snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o patch_si3054.o
+snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o patch_si3054.o patch_atihdmi.o
ifdef CONFIG_PROC_FS
snd-hda-codec-objs += hda_proc.o
endif
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 5bee3b5..8c2a817 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -86,6 +86,8 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int dire
return res;
}
+EXPORT_SYMBOL(snd_hda_codec_read);
+
/**
* snd_hda_codec_write - send a single command without waiting for response
* @codec: the HDA codec
@@ -108,6 +110,8 @@ int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct,
return err;
}
+EXPORT_SYMBOL(snd_hda_codec_write);
+
/**
* snd_hda_sequence_write - sequence writes
* @codec: the HDA codec
@@ -122,6 +126,8 @@ void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq)
snd_hda_codec_write(codec, seq->nid, 0, seq->verb, seq->param);
}
+EXPORT_SYMBOL(snd_hda_sequence_write);
+
/**
* snd_hda_get_sub_nodes - get the range of sub nodes
* @codec: the HDA codec
@@ -140,6 +146,8 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *sta
return (int)(parm & 0x7fff);
}
+EXPORT_SYMBOL(snd_hda_get_sub_nodes);
+
/**
* snd_hda_get_connections - get connection list
* @codec: the HDA codec
@@ -256,6 +264,8 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
return 0;
}
+EXPORT_SYMBOL(snd_hda_queue_unsol_event);
+
/*
* process queueud unsolicited events
*/
@@ -384,6 +394,7 @@ int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp,
return 0;
}
+EXPORT_SYMBOL(snd_hda_bus_new);
/*
* find a matching codec preset
@@ -587,6 +598,8 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
return 0;
}
+EXPORT_SYMBOL(snd_hda_codec_new);
+
/**
* snd_hda_codec_setup_stream - set up the codec for streaming
* @codec: the CODEC to set up
@@ -609,6 +622,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stre
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, format);
}
+EXPORT_SYMBOL(snd_hda_codec_setup_stream);
/*
* amp access functions
@@ -1294,6 +1308,7 @@ int snd_hda_build_controls(struct hda_bus *bus)
return 0;
}
+EXPORT_SYMBOL(snd_hda_build_controls);
/*
* stream formats
@@ -1382,6 +1397,8 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
return val;
}
+EXPORT_SYMBOL(snd_hda_calc_stream_format);
+
/**
* snd_hda_query_supported_pcm - query the supported PCM rates and formats
* @codec: the HDA codec
@@ -1663,6 +1680,7 @@ int snd_hda_build_pcms(struct hda_bus *bus)
return 0;
}
+EXPORT_SYMBOL(snd_hda_build_pcms);
/**
* snd_hda_check_board_config - compare the current codec with the config table
@@ -2165,6 +2183,8 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state)
return 0;
}
+EXPORT_SYMBOL(snd_hda_suspend);
+
/**
* snd_hda_resume - resume the codecs
* @bus: the HDA bus
@@ -2187,6 +2207,8 @@ int snd_hda_resume(struct hda_bus *bus)
return 0;
}
+EXPORT_SYMBOL(snd_hda_resume);
+
/**
* snd_hda_resume_ctls - resume controls in the new control list
* @codec: the HDA codec
@@ -2247,25 +2269,6 @@ int snd_hda_resume_spdif_in(struct hda_codec *codec)
#endif
/*
- * symbols exported for controller modules
- */
-EXPORT_SYMBOL(snd_hda_codec_read);
-EXPORT_SYMBOL(snd_hda_codec_write);
-EXPORT_SYMBOL(snd_hda_sequence_write);
-EXPORT_SYMBOL(snd_hda_get_sub_nodes);
-EXPORT_SYMBOL(snd_hda_queue_unsol_event);
-EXPORT_SYMBOL(snd_hda_bus_new);
-EXPORT_SYMBOL(snd_hda_codec_new);
-EXPORT_SYMBOL(snd_hda_codec_setup_stream);
-EXPORT_SYMBOL(snd_hda_calc_stream_format);
-EXPORT_SYMBOL(snd_hda_build_pcms);
-EXPORT_SYMBOL(snd_hda_build_controls);
-#ifdef CONFIG_PM
-EXPORT_SYMBOL(snd_hda_suspend);
-EXPORT_SYMBOL(snd_hda_resume);
-#endif
-
-/*
* INIT part
*/
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index e821d65..4070b5c 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -82,6 +82,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
"{Intel, ICH8},"
"{ATI, SB450},"
"{ATI, SB600},"
+ "{ATI, RS600},"
"{VIA, VT8251},"
"{VIA, VT8237A},"
"{SiS, SIS966},"
@@ -167,6 +168,12 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define ULI_PLAYBACK_INDEX 5
#define ULI_NUM_PLAYBACK 6
+/* ATI HDMI has 1 playback and 0 capture */
+#define ATIHDMI_CAPTURE_INDEX 0
+#define ATIHDMI_NUM_CAPTURE 0
+#define ATIHDMI_PLAYBACK_INDEX 0
+#define ATIHDMI_NUM_PLAYBACK 1
+
/* this number is statically defined for simplicity */
#define MAX_AZX_DEV 16
@@ -331,6 +338,7 @@ struct azx {
enum {
AZX_DRIVER_ICH,
AZX_DRIVER_ATI,
+ AZX_DRIVER_ATIHDMI,
AZX_DRIVER_VIA,
AZX_DRIVER_SIS,
AZX_DRIVER_ULI,
@@ -340,6 +348,7 @@ enum {
static char *driver_short_names[] __devinitdata = {
[AZX_DRIVER_ICH] = "HDA Intel",
[AZX_DRIVER_ATI] = "HDA ATI SB",
+ [AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI",
[AZX_DRIVER_VIA] = "HDA VIA VT82xx",
[AZX_DRIVER_SIS] = "HDA SIS966",
[AZX_DRIVER_ULI] = "HDA ULI M5461",
@@ -1393,10 +1402,10 @@ static int azx_free(struct azx *chip)
msleep(1);
}
- if (chip->remap_addr)
- iounmap(chip->remap_addr);
if (chip->irq >= 0)
free_irq(chip->irq, (void*)chip);
+ if (chip->remap_addr)
+ iounmap(chip->remap_addr);
if (chip->bdl.area)
snd_dma_free_pages(&chip->bdl);
@@ -1495,6 +1504,12 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
chip->playback_index_offset = ULI_PLAYBACK_INDEX;
chip->capture_index_offset = ULI_CAPTURE_INDEX;
break;
+ case AZX_DRIVER_ATIHDMI:
+ chip->playback_streams = ATIHDMI_NUM_PLAYBACK;
+ chip->capture_streams = ATIHDMI_NUM_CAPTURE;
+ chip->playback_index_offset = ATIHDMI_PLAYBACK_INDEX;
+ chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX;
+ break;
default:
chip->playback_streams = ICH6_NUM_PLAYBACK;
chip->capture_streams = ICH6_NUM_CAPTURE;
@@ -1621,6 +1636,7 @@ static struct pci_device_id azx_ids[] __devinitdata = {
{ 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */
{ 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */
{ 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */
+ { 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */
{ 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */
{ 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */
{ 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */
diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h
index acaef3c8..0b66879 100644
--- a/sound/pci/hda/hda_patch.h
+++ b/sound/pci/hda/hda_patch.h
@@ -12,6 +12,8 @@ extern struct hda_codec_preset snd_hda_preset_analog[];
extern struct hda_codec_preset snd_hda_preset_sigmatel[];
/* SiLabs 3054/3055 modem codecs */
extern struct hda_codec_preset snd_hda_preset_si3054[];
+/* ATI HDMI codecs */
+extern struct hda_codec_preset snd_hda_preset_atihdmi[];
static const struct hda_codec_preset *hda_preset_tables[] = {
snd_hda_preset_realtek,
@@ -19,5 +21,6 @@ static const struct hda_codec_preset *hda_preset_tables[] = {
snd_hda_preset_analog,
snd_hda_preset_sigmatel,
snd_hda_preset_si3054,
+ snd_hda_preset_atihdmi,
NULL
};
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index ca514a6..c2f0fe8 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -182,6 +182,10 @@ static void print_pin_caps(struct snd_info_buffer *buffer,
snd_iprintf(buffer, " OUT");
if (caps & AC_PINCAP_HP_DRV)
snd_iprintf(buffer, " HP");
+ if (caps & AC_PINCAP_EAPD)
+ snd_iprintf(buffer, " EAPD");
+ if (caps & AC_PINCAP_PRES_DETECT)
+ snd_iprintf(buffer, " Detect");
snd_iprintf(buffer, "\n");
caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps,
@@ -318,7 +322,7 @@ int snd_hda_codec_proc_new(struct hda_codec *codec)
if (err < 0)
return err;
- snd_info_set_text_ops(entry, codec, 32 * 1024, print_codec_info);
+ snd_info_set_text_ops(entry, codec, print_codec_info);
return 0;
}
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 40f000b..dd4e00a 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -789,6 +789,8 @@ static struct hda_board_config ad1986a_cfg_tbl[] = {
{ .modelname = "3stack", .config = AD1986A_3STACK },
{ .pci_subvendor = 0x10de, .pci_subdevice = 0xcb84,
.config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b3,
+ .config = AD1986A_3STACK }, /* ASUS P5RD2-VM / P5GPL-X SE */
{ .modelname = "laptop", .config = AD1986A_LAPTOP },
{ .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e,
.config = AD1986A_LAPTOP }, /* FSC V2060 */
@@ -809,6 +811,8 @@ static struct hda_board_config ad1986a_cfg_tbl[] = {
.config = AD1986A_LAPTOP_EAPD }, /* ASUS Z62F */
{ .pci_subvendor = 0x103c, .pci_subdevice = 0x30af,
.config = AD1986A_LAPTOP_EAPD }, /* HP Compaq Presario B2800 */
+ { .pci_subvendor = 0x17aa, .pci_subdevice = 0x2066,
+ .config = AD1986A_LAPTOP_EAPD }, /* Lenovo 3000 N100-07684JU */
{}
};
@@ -963,7 +967,7 @@ static struct snd_kcontrol_new ad1983_mixers[] = {
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
+ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
.info = ad1983_spdif_route_info,
.get = ad1983_spdif_route_get,
.put = ad1983_spdif_route_put,
@@ -1103,7 +1107,7 @@ static struct snd_kcontrol_new ad1981_mixers[] = {
/* identical with AD1983 */
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
+ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
.info = ad1983_spdif_route_info,
.get = ad1983_spdif_route_get,
.put = ad1983_spdif_route_put,
@@ -1329,13 +1333,60 @@ static int ad1981_hp_init(struct hda_codec *codec)
return 0;
}
+/* configuration for Lenovo Thinkpad T60 */
+static struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
+ HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .info = ad198x_mux_enum_info,
+ .get = ad198x_mux_enum_get,
+ .put = ad198x_mux_enum_put,
+ },
+ /* identical with AD1983 */
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
+ .info = ad1983_spdif_route_info,
+ .get = ad1983_spdif_route_get,
+ .put = ad1983_spdif_route_put,
+ },
+ { } /* end */
+};
+
+static struct hda_input_mux ad1981_thinkpad_capture_source = {
+ .num_items = 3,
+ .items = {
+ { "Mic", 0x0 },
+ { "Mix", 0x2 },
+ { "CD", 0x4 },
+ },
+};
+
/* models */
-enum { AD1981_BASIC, AD1981_HP };
+enum { AD1981_BASIC, AD1981_HP, AD1981_THINKPAD };
static struct hda_board_config ad1981_cfg_tbl[] = {
{ .modelname = "hp", .config = AD1981_HP },
/* All HP models */
{ .pci_subvendor = 0x103c, .config = AD1981_HP },
+ { .pci_subvendor = 0x30b0, .pci_subdevice = 0x103c,
+ .config = AD1981_HP }, /* HP nx6320 (reversed SSID, H/W bug) */
+ { .modelname = "thinkpad", .config = AD1981_THINKPAD },
+ /* Lenovo Thinkpad T60/X60/Z6xx */
+ { .pci_subvendor = 0x17aa, .config = AD1981_THINKPAD },
+ { .pci_subvendor = 0x1014, .pci_subdevice = 0x0597,
+ .config = AD1981_THINKPAD }, /* Z60m/t */
{ .modelname = "basic", .config = AD1981_BASIC },
{}
};
@@ -1381,6 +1432,10 @@ static int patch_ad1981(struct hda_codec *codec)
codec->patch_ops.init = ad1981_hp_init;
codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
break;
+ case AD1981_THINKPAD:
+ spec->mixers[0] = ad1981_thinkpad_mixers;
+ spec->input_mux = &ad1981_thinkpad_capture_source;
+ break;
}
return 0;
diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c
new file mode 100644
index 0000000..a27440f
--- /dev/null
+++ b/sound/pci/hda/patch_atihdmi.c
@@ -0,0 +1,165 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for ATI HDMI codecs
+ *
+ * Copyright (c) 2006 ATI Technologies Inc.
+ *
+ *
+ * This driver 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 driver 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 <sound/driver.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+struct atihdmi_spec {
+ struct hda_multi_out multiout;
+
+ struct hda_pcm pcm_rec;
+};
+
+static struct hda_verb atihdmi_basic_init[] = {
+ /* enable digital output on pin widget */
+ { 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ {} /* terminator */
+};
+
+/*
+ * Controls
+ */
+static int atihdmi_build_controls(struct hda_codec *codec)
+{
+ struct atihdmi_spec *spec = codec->spec;
+ int err;
+
+ err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int atihdmi_init(struct hda_codec *codec)
+{
+ snd_hda_sequence_write(codec, atihdmi_basic_init);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ * resume
+ */
+static int atihdmi_resume(struct hda_codec *codec)
+{
+ atihdmi_init(codec);
+ snd_hda_resume_spdif_out(codec);
+
+ return 0;
+}
+#endif
+
+/*
+ * Digital out
+ */
+static int atihdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct atihdmi_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int atihdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct atihdmi_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0x2, /* NID to query formats and rates and setup streams */
+ .ops = {
+ .open = atihdmi_dig_playback_pcm_open,
+ .close = atihdmi_dig_playback_pcm_close
+ },
+};
+
+static int atihdmi_build_pcms(struct hda_codec *codec)
+{
+ struct atihdmi_spec *spec = codec->spec;
+ struct hda_pcm *info = &spec->pcm_rec;
+
+ codec->num_pcms = 1;
+ codec->pcm_info = info;
+
+ info->name = "ATI HDMI";
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback;
+
+ return 0;
+}
+
+static void atihdmi_free(struct hda_codec *codec)
+{
+ kfree(codec->spec);
+}
+
+static struct hda_codec_ops atihdmi_patch_ops = {
+ .build_controls = atihdmi_build_controls,
+ .build_pcms = atihdmi_build_pcms,
+ .init = atihdmi_init,
+ .free = atihdmi_free,
+#ifdef CONFIG_PM
+ .resume = atihdmi_resume,
+#endif
+};
+
+static int patch_atihdmi(struct hda_codec *codec)
+{
+ struct atihdmi_spec *spec;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+
+ spec->multiout.num_dacs = 0; /* no analog */
+ spec->multiout.max_channels = 2;
+ spec->multiout.dig_out_nid = 0x2; /* NID for copying analog to digital,
+ * seems to be unused in pure-digital
+ * case. */
+
+ codec->patch_ops = atihdmi_patch_ops;
+
+ return 0;
+}
+
+/*
+ * patch entries
+ */
+struct hda_codec_preset snd_hda_preset_atihdmi[] = {
+ { .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
+ {} /* terminator */
+};
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index f0e9a9c..98b9f16 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -2174,6 +2174,7 @@ static struct hda_board_config alc880_cfg_tbl[] = {
{ .modelname = "lg", .config = ALC880_LG },
{ .pci_subvendor = 0x1854, .pci_subdevice = 0x003b, .config = ALC880_LG },
+ { .pci_subvendor = 0x1854, .pci_subdevice = 0x0068, .config = ALC880_LG },
{ .modelname = "lg-lw", .config = ALC880_LG_LW },
{ .pci_subvendor = 0x1854, .pci_subdevice = 0x0018, .config = ALC880_LG_LW },
@@ -3105,6 +3106,7 @@ static struct hda_verb alc260_init_verbs[] = {
{ }
};
+#if 0 /* should be identical with alc260_init_verbs? */
static struct hda_verb alc260_hp_init_verbs[] = {
/* Headphone and output */
{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
@@ -3151,6 +3153,7 @@ static struct hda_verb alc260_hp_init_verbs[] = {
{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
{ }
};
+#endif
static struct hda_verb alc260_hp_3013_init_verbs[] = {
/* Line out and output */
@@ -3822,12 +3825,16 @@ static struct hda_board_config alc260_cfg_tbl[] = {
{ .modelname = "basic", .config = ALC260_BASIC },
{ .pci_subvendor = 0x104d, .pci_subdevice = 0x81bb,
.config = ALC260_BASIC }, /* Sony VAIO */
+ { .pci_subvendor = 0x104d, .pci_subdevice = 0x81cc,
+ .config = ALC260_BASIC }, /* Sony VAIO VGN-S3HP */
+ { .pci_subvendor = 0x104d, .pci_subdevice = 0x81cd,
+ .config = ALC260_BASIC }, /* Sony VAIO */
{ .pci_subvendor = 0x152d, .pci_subdevice = 0x0729,
.config = ALC260_BASIC }, /* CTL Travel Master U553W */
{ .modelname = "hp", .config = ALC260_HP },
{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP },
{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP },
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP },
+ { .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP_3013 },
{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 },
{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, .config = ALC260_HP },
{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3015, .config = ALC260_HP },
@@ -3862,7 +3869,7 @@ static struct alc_config_preset alc260_presets[] = {
.mixers = { alc260_base_output_mixer,
alc260_input_mixer,
alc260_capture_alt_mixer },
- .init_verbs = { alc260_hp_init_verbs },
+ .init_verbs = { alc260_init_verbs },
.num_dacs = ARRAY_SIZE(alc260_dac_nids),
.dac_nids = alc260_dac_nids,
.num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
@@ -4094,21 +4101,6 @@ static struct snd_kcontrol_new alc882_base_mixer[] = {
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 3,
- .info = alc882_mux_enum_info,
- .get = alc882_mux_enum_get,
- .put = alc882_mux_enum_put,
- },
{ } /* end */
};
@@ -4342,8 +4334,6 @@ static struct alc_config_preset alc882_presets[] = {
.num_dacs = ARRAY_SIZE(alc882_dac_nids),
.dac_nids = alc882_dac_nids,
.dig_out_nid = ALC882_DIGOUT_NID,
- .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
- .adc_nids = alc882_adc_nids,
.dig_in_nid = ALC882_DIGIN_NID,
.num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
.channel_mode = alc882_ch_modes,
@@ -4355,8 +4345,6 @@ static struct alc_config_preset alc882_presets[] = {
.num_dacs = ARRAY_SIZE(alc882_dac_nids),
.dac_nids = alc882_dac_nids,
.dig_out_nid = ALC882_DIGOUT_NID,
- .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
- .adc_nids = alc882_adc_nids,
.dig_in_nid = ALC882_DIGIN_NID,
.num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
.channel_mode = alc882_sixstack_modes,
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 8c440fb..36f1994 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -41,6 +41,7 @@
#define STAC_REF 0
#define STAC_D945GTP3 1
#define STAC_D945GTP5 2
+#define STAC_MACMINI 3
struct sigmatel_spec {
struct snd_kcontrol_new *mixers[4];
@@ -52,6 +53,7 @@ struct sigmatel_spec {
unsigned int mic_switch: 1;
unsigned int alt_switch: 1;
unsigned int hp_detect: 1;
+ unsigned int gpio_mute: 1;
/* playback */
struct hda_multi_out multiout;
@@ -293,6 +295,7 @@ static unsigned int *stac922x_brd_tbl[] = {
ref922x_pin_configs,
d945gtp3_pin_configs,
d945gtp5_pin_configs,
+ NULL, /* STAC_MACMINI */
};
static struct hda_board_config stac922x_cfg_tbl[] = {
@@ -324,6 +327,9 @@ static struct hda_board_config stac922x_cfg_tbl[] = {
{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
.pci_subdevice = 0x0417,
.config = STAC_D945GTP5 }, /* Intel D975XBK - 5 Stack */
+ { .pci_subvendor = 0x8384,
+ .pci_subdevice = 0x7680,
+ .config = STAC_MACMINI }, /* Apple Mac Mini (early 2006) */
{} /* terminator */
};
@@ -841,6 +847,19 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const
}
}
+ if (imux->num_items == 1) {
+ /*
+ * Set the current input for the muxes.
+ * The STAC9221 has two input muxes with identical source
+ * NID lists. Hopefully this won't get confused.
+ */
+ for (i = 0; i < spec->num_muxes; i++) {
+ snd_hda_codec_write(codec, spec->mux_nids[i], 0,
+ AC_VERB_SET_CONNECT_SEL,
+ imux->items[0].index);
+ }
+ }
+
return 0;
}
@@ -946,6 +965,45 @@ static int stac9200_parse_auto_config(struct hda_codec *codec)
return 1;
}
+/*
+ * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
+ * funky external mute control using GPIO pins.
+ */
+
+static void stac922x_gpio_mute(struct hda_codec *codec, int pin, int muted)
+{
+ unsigned int gpiostate, gpiomask, gpiodir;
+
+ gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
+ AC_VERB_GET_GPIO_DATA, 0);
+
+ if (!muted)
+ gpiostate |= (1 << pin);
+ else
+ gpiostate &= ~(1 << pin);
+
+ gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
+ AC_VERB_GET_GPIO_MASK, 0);
+ gpiomask |= (1 << pin);
+
+ gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
+ AC_VERB_GET_GPIO_DIRECTION, 0);
+ gpiodir |= (1 << pin);
+
+ /* AppleHDA seems to do this -- WTF is this verb?? */
+ snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
+
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_MASK, gpiomask);
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_DIRECTION, gpiodir);
+
+ msleep(1);
+
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_DATA, gpiostate);
+}
+
static int stac92xx_init(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
@@ -982,6 +1040,11 @@ static int stac92xx_init(struct hda_codec *codec)
stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
AC_PINCTL_IN_EN);
+ if (spec->gpio_mute) {
+ stac922x_gpio_mute(codec, 0, 0);
+ stac922x_gpio_mute(codec, 1, 0);
+ }
+
return 0;
}
@@ -1132,7 +1195,7 @@ static int patch_stac922x(struct hda_codec *codec)
spec->board_config = snd_hda_check_board_config(codec, stac922x_cfg_tbl);
if (spec->board_config < 0)
snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, using BIOS defaults\n");
- else {
+ else if (stac922x_brd_tbl[spec->board_config] != NULL) {
spec->num_pins = 10;
spec->pin_nids = stac922x_pin_nids;
spec->pin_configs = stac922x_brd_tbl[spec->board_config];
@@ -1154,6 +1217,9 @@ static int patch_stac922x(struct hda_codec *codec)
return err;
}
+ if (spec->board_config == STAC_MACMINI)
+ spec->gpio_mute = 1;
+
codec->patch_ops = stac92xx_patch_ops;
return 0;
@@ -1262,13 +1328,13 @@ static int vaio_master_sw_put(struct snd_kcontrol *kcontrol,
int change;
change = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0,
- 0x80, valp[0] & 0x80);
+ 0x80, (valp[0] ? 0 : 0x80));
change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0,
- 0x80, valp[1] & 0x80);
+ 0x80, (valp[1] ? 0 : 0x80));
snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0,
- 0x80, valp[0] & 0x80);
+ 0x80, (valp[0] ? 0 : 0x80));
snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0,
- 0x80, valp[1] & 0x80);
+ 0x80, (valp[1] ? 0 : 0x80));
return change;
}
@@ -1370,6 +1436,12 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = {
{ .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
{ .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
{ .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
+ { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac922x },
+ { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac922x },
+ { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac922x },
+ { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac922x },
+ { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac922x },
+ { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac922x },
{ .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
{ .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
{ .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c
index 336dc48..ca74f5b 100644
--- a/sound/pci/ice1712/aureon.c
+++ b/sound/pci/ice1712/aureon.c
@@ -1281,9 +1281,15 @@ static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable)
tmp2 = tmp = snd_ice1712_gpio_read(ice);
if (enable)
- tmp |= AUREON_HP_SEL;
+ if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT)
+ tmp |= AUREON_HP_SEL;
+ else
+ tmp |= PRODIGY_HP_SEL;
else
- tmp &= ~ AUREON_HP_SEL;
+ if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT)
+ tmp &= ~ AUREON_HP_SEL;
+ else
+ tmp &= ~ PRODIGY_HP_SEL;
if (tmp != tmp2) {
snd_ice1712_gpio_write(ice, tmp);
return 1;
@@ -2079,16 +2085,16 @@ static unsigned char prodigy71_eeprom[] __devinitdata = {
};
static unsigned char prodigy71lt_eeprom[] __devinitdata = {
- 0x0b, /* SYSCINF: clock 512, spdif-in/ADC, 4DACs */
+ 0x4b, /* SYSCINF: clock 512, spdif-in/ADC, 4DACs */
0x80, /* ACLINK: I2S */
0xfc, /* I2S: vol, 96k, 24bit, 192k */
- 0xc3, /* SPDUF: out-en, out-int */
- 0x00, /* GPIO_DIR */
- 0x07, /* GPIO_DIR1 */
- 0x00, /* GPIO_DIR2 */
- 0xff, /* GPIO_MASK */
- 0xf8, /* GPIO_MASK1 */
- 0xff, /* GPIO_MASK2 */
+ 0xc3, /* SPDIF: out-en, out-int, spdif-in */
+ 0xff, /* GPIO_DIR */
+ 0xff, /* GPIO_DIR1 */
+ 0x5f, /* GPIO_DIR2 */
+ 0x00, /* GPIO_MASK */
+ 0x00, /* GPIO_MASK1 */
+ 0x00, /* GPIO_MASK2 */
0x00, /* GPIO_STATE */
0x00, /* GPIO_STATE1 */
0x00, /* GPIO_STATE2 */
diff --git a/sound/pci/ice1712/aureon.h b/sound/pci/ice1712/aureon.h
index 98a6752..3b7bea6 100644
--- a/sound/pci/ice1712/aureon.h
+++ b/sound/pci/ice1712/aureon.h
@@ -58,5 +58,6 @@ extern struct snd_ice1712_card_info snd_vt1724_aureon_cards[];
#define PRODIGY_WM_CS (1 << 8)
#define PRODIGY_SPI_MOSI (1 << 10)
#define PRODIGY_SPI_CLK (1 << 9)
+#define PRODIGY_HP_SEL (1 << 5)
#endif /* __SOUND_AUREON_H */
diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c
index 2c529e7..b135389 100644
--- a/sound/pci/ice1712/ews.c
+++ b/sound/pci/ice1712/ews.c
@@ -1031,6 +1031,9 @@ struct snd_ice1712_card_info snd_ice1712_ews_cards[] __devinitdata = {
.model = "dmx6fire",
.chip_init = snd_ice1712_ews_init,
.build_controls = snd_ice1712_ews_add_controls,
+ .mpu401_1_name = "MIDI-Front DMX6fire",
+ .mpu401_2_name = "Wavetable DMX6fire",
+ .mpu401_2_info_flags = MPU401_INFO_OUTPUT,
},
{ } /* terminator */
};
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index c56793b..8459071 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -61,7 +61,6 @@
#include <sound/core.h>
#include <sound/cs8427.h>
#include <sound/info.h>
-#include <sound/mpu401.h>
#include <sound/initval.h>
#include <sound/asoundef.h>
@@ -1596,7 +1595,7 @@ static void __devinit snd_ice1712_proc_init(struct snd_ice1712 * ice)
struct snd_info_entry *entry;
if (! snd_card_proc_new(ice->card, "ice1712", &entry))
- snd_info_set_text_ops(entry, ice, 1024, snd_ice1712_proc_read);
+ snd_info_set_text_ops(entry, ice, snd_ice1712_proc_read);
}
/*
@@ -2398,13 +2397,14 @@ static int __devinit snd_ice1712_chip_init(struct snd_ice1712 *ice)
udelay(200);
outb(ICE1712_NATIVE, ICEREG(ice, CONTROL));
udelay(200);
- if (ice->eeprom.subvendor == ICE1712_SUBDEVICE_DMX6FIRE && !ice->dxr_enable) {
- /* Limit active ADCs and DACs to 6; */
- /* Note: DXR extension not supported */
- pci_write_config_byte(ice->pci, 0x60, 0x2a);
- } else {
- pci_write_config_byte(ice->pci, 0x60, ice->eeprom.data[ICE_EEP1_CODEC]);
- }
+ if (ice->eeprom.subvendor == ICE1712_SUBDEVICE_DMX6FIRE &&
+ !ice->dxr_enable)
+ /* Set eeprom value to limit active ADCs and DACs to 6;
+ * Also disable AC97 as no hardware in standard 6fire card/box
+ * Note: DXR extensions are not currently supported
+ */
+ ice->eeprom.data[ICE_EEP1_CODEC] = 0x3a;
+ pci_write_config_byte(ice->pci, 0x60, ice->eeprom.data[ICE_EEP1_CODEC]);
pci_write_config_byte(ice->pci, 0x61, ice->eeprom.data[ICE_EEP1_ACLINK]);
pci_write_config_byte(ice->pci, 0x62, ice->eeprom.data[ICE_EEP1_I2SID]);
pci_write_config_byte(ice->pci, 0x63, ice->eeprom.data[ICE_EEP1_SPDIF]);
@@ -2737,21 +2737,38 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci,
if (! c->no_mpu401) {
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712,
- ICEREG(ice, MPU1_CTRL), 1,
+ ICEREG(ice, MPU1_CTRL),
+ (c->mpu401_1_info_flags |
+ MPU401_INFO_INTEGRATED),
ice->irq, 0,
&ice->rmidi[0])) < 0) {
snd_card_free(card);
return err;
}
-
- if (ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_2xMPU401)
+ if (c->mpu401_1_name)
+ /* Prefered name available in card_info */
+ snprintf(ice->rmidi[0]->name,
+ sizeof(ice->rmidi[0]->name),
+ "%s %d", c->mpu401_1_name, card->number);
+
+ if (ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_2xMPU401) {
+ /* 2nd port used */
if ((err = snd_mpu401_uart_new(card, 1, MPU401_HW_ICE1712,
- ICEREG(ice, MPU2_CTRL), 1,
+ ICEREG(ice, MPU2_CTRL),
+ (c->mpu401_2_info_flags |
+ MPU401_INFO_INTEGRATED),
ice->irq, 0,
&ice->rmidi[1])) < 0) {
snd_card_free(card);
return err;
}
+ if (c->mpu401_2_name)
+ /* Prefered name available in card_info */
+ snprintf(ice->rmidi[1]->name,
+ sizeof(ice->rmidi[1]->name),
+ "%s %d", c->mpu401_2_name,
+ card->number);
+ }
}
snd_ice1712_set_input_clock_source(ice, 0);
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
index 053f8e5..ce27eac 100644
--- a/sound/pci/ice1712/ice1712.h
+++ b/sound/pci/ice1712/ice1712.h
@@ -29,6 +29,7 @@
#include <sound/ak4xxx-adda.h>
#include <sound/ak4114.h>
#include <sound/pcm.h>
+#include <sound/mpu401.h>
/*
@@ -495,6 +496,10 @@ struct snd_ice1712_card_info {
int (*chip_init)(struct snd_ice1712 *);
int (*build_controls)(struct snd_ice1712 *);
unsigned int no_mpu401: 1;
+ unsigned int mpu401_1_info_flags;
+ unsigned int mpu401_2_info_flags;
+ const char *mpu401_1_name;
+ const char *mpu401_2_name;
unsigned int eeprom_size;
unsigned char *eeprom_data;
};
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index b1c007e..34a58c62 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -1293,7 +1293,7 @@ static void __devinit snd_vt1724_proc_init(struct snd_ice1712 * ice)
struct snd_info_entry *entry;
if (! snd_card_proc_new(ice->card, "ice1724", &entry))
- snd_info_set_text_ops(entry, ice, 1024, snd_vt1724_proc_read);
+ snd_info_set_text_ops(entry, ice, snd_vt1724_proc_read);
}
/*
@@ -2388,7 +2388,8 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci,
if (! c->no_mpu401) {
if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) {
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712,
- ICEREG1724(ice, MPU_CTRL), 1,
+ ICEREG1724(ice, MPU_CTRL),
+ MPU401_INFO_INTEGRATED,
ice->irq, 0,
&ice->rmidi[0])) < 0) {
snd_card_free(card);
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c
index d23fb3f..0efcad9 100644
--- a/sound/pci/ice1712/pontis.c
+++ b/sound/pci/ice1712/pontis.c
@@ -680,9 +680,8 @@ static void wm_proc_init(struct snd_ice1712 *ice)
{
struct snd_info_entry *entry;
if (! snd_card_proc_new(ice->card, "wm_codec", &entry)) {
- snd_info_set_text_ops(entry, ice, 1024, wm_proc_regs_read);
+ snd_info_set_text_ops(entry, ice, wm_proc_regs_read);
entry->mode |= S_IWUSR;
- entry->c.text.write_size = 1024;
entry->c.text.write = wm_proc_regs_write;
}
}
@@ -705,9 +704,8 @@ static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buff
static void cs_proc_init(struct snd_ice1712 *ice)
{
struct snd_info_entry *entry;
- if (! snd_card_proc_new(ice->card, "cs_codec", &entry)) {
- snd_info_set_text_ops(entry, ice, 1024, cs_proc_regs_read);
- }
+ if (! snd_card_proc_new(ice->card, "cs_codec", &entry))
+ snd_info_set_text_ops(entry, ice, cs_proc_regs_read);
}
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index 0df7602..edc1447 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -66,7 +66,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel,82801AA-ICH},"
static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */
-static int ac97_clock = 0;
+static int ac97_clock;
static char *ac97_quirk;
static int buggy_semaphore;
static int buggy_irq = -1; /* auto-check */
@@ -1807,6 +1807,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
},
{
.subvendor = 0x1028,
+ .subdevice = 0x014e,
+ .name = "Dell D800", /* STAC9750/51 */
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .subvendor = 0x1028,
.subdevice = 0x0163,
.name = "Dell Unknown", /* STAC9750/51 */
.type = AC97_TUNE_HP_ONLY
@@ -2645,7 +2651,7 @@ static void __devinit snd_intel8x0_proc_init(struct intel8x0 * chip)
struct snd_info_entry *entry;
if (! snd_card_proc_new(chip->card, "intel8x0", &entry))
- snd_info_set_text_ops(entry, chip, 1024, snd_intel8x0_proc_read);
+ snd_info_set_text_ops(entry, chip, snd_intel8x0_proc_read);
}
#else
#define snd_intel8x0_proc_init(x)
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index 720635f..24703d7 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -59,7 +59,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel,82801AA-ICH},"
static int index = -2; /* Exclude the first card */
static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */
-static int ac97_clock = 0;
+static int ac97_clock;
module_param(index, int, 0444);
MODULE_PARM_DESC(index, "Index value for Intel i8x0 modemcard.");
@@ -1092,7 +1092,7 @@ static void __devinit snd_intel8x0m_proc_init(struct intel8x0m * chip)
struct snd_info_entry *entry;
if (! snd_card_proc_new(chip->card, "intel8x0m", &entry))
- snd_info_set_text_ops(entry, chip, 1024, snd_intel8x0m_proc_read);
+ snd_info_set_text_ops(entry, chip, snd_intel8x0m_proc_read);
}
#else /* !CONFIG_PROC_FS */
#define snd_intel8x0m_proc_init(chip)
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index e39fad1..6e97932 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -2085,7 +2085,7 @@ static void __devinit snd_korg1212_proc_init(struct snd_korg1212 *korg1212)
struct snd_info_entry *entry;
if (! snd_card_proc_new(korg1212->card, "korg1212", &entry))
- snd_info_set_text_ops(entry, korg1212, 1024, snd_korg1212_proc_read);
+ snd_info_set_text_ops(entry, korg1212, snd_korg1212_proc_read);
}
static int
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 1928e06..1c344fb 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -2861,7 +2861,8 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
#if 0 /* TODO: not supported yet */
/* TODO enable MIDI IRQ and I/O */
err = snd_mpu401_uart_new(chip->card, 0, MPU401_HW_MPU401,
- chip->iobase + MPU401_DATA_PORT, 1,
+ chip->iobase + MPU401_DATA_PORT,
+ MPU401_INFO_INTEGRATED,
chip->irq, 0, &chip->rmidi);
if (err < 0)
printk(KERN_WARNING "maestro3: no MIDI support.\n");
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index 09cc078..366c4a7 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -1244,7 +1244,6 @@ static void __devinit snd_mixart_proc_init(struct snd_mixart *chip)
/* text interface to read perf and temp meters */
if (! snd_card_proc_new(chip->card, "board_info", &entry)) {
entry->private_data = chip;
- entry->c.text.read_size = 1024;
entry->c.text.read = snd_mixart_proc_read;
}
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index dafa223..8198884 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -1150,9 +1150,9 @@ static void __devinit pcxhr_proc_init(struct snd_pcxhr *chip)
struct snd_info_entry *entry;
if (! snd_card_proc_new(chip->card, "info", &entry))
- snd_info_set_text_ops(entry, chip, 1024, pcxhr_proc_info);
+ snd_info_set_text_ops(entry, chip, pcxhr_proc_info);
if (! snd_card_proc_new(chip->card, "sync", &entry))
- snd_info_set_text_ops(entry, chip, 1024, pcxhr_proc_sync);
+ snd_info_set_text_ops(entry, chip, pcxhr_proc_sync);
}
/* end of proc interface */
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index d8cc985..5618ec9 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -1836,11 +1836,11 @@ static int snd_riptide_free(struct snd_riptide *chip)
UNSET_GRESET(cif->hwport);
kfree(chip->cif);
}
+ if (chip->irq >= 0)
+ free_irq(chip->irq, chip);
if (chip->fw_entry)
release_firmware(chip->fw_entry);
release_and_free_resource(chip->res_port);
- if (chip->irq >= 0)
- free_irq(chip->irq, chip);
kfree(chip);
return 0;
}
@@ -1992,7 +1992,7 @@ static void __devinit snd_riptide_proc_init(struct snd_riptide *chip)
struct snd_info_entry *entry;
if (!snd_card_proc_new(chip->card, "riptide", &entry))
- snd_info_set_text_ops(entry, chip, 4096, snd_riptide_proc_read);
+ snd_info_set_text_ops(entry, chip, snd_riptide_proc_read);
}
static int __devinit snd_riptide_mixer(struct snd_riptide *chip)
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
index 55b1d48..2cb9fe9 100644
--- a/sound/pci/rme32.c
+++ b/sound/pci/rme32.c
@@ -1368,18 +1368,18 @@ static int __devinit snd_rme32_create(struct rme32 * rme32)
return err;
rme32->port = pci_resource_start(rme32->pci, 0);
- if (request_irq(pci->irq, snd_rme32_interrupt, SA_INTERRUPT | SA_SHIRQ, "RME32", (void *) rme32)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
- return -EBUSY;
- }
- rme32->irq = pci->irq;
-
if ((rme32->iobase = ioremap_nocache(rme32->port, RME32_IO_SIZE)) == 0) {
snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n",
rme32->port, rme32->port + RME32_IO_SIZE - 1);
return -ENOMEM;
}
+ if (request_irq(pci->irq, snd_rme32_interrupt, SA_INTERRUPT | SA_SHIRQ, "RME32", (void *) rme32)) {
+ snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ return -EBUSY;
+ }
+ rme32->irq = pci->irq;
+
/* read the card's revision number */
pci_read_config_byte(pci, 8, &rme32->rev);
@@ -1578,7 +1578,7 @@ static void __devinit snd_rme32_proc_init(struct rme32 * rme32)
struct snd_info_entry *entry;
if (! snd_card_proc_new(rme32->card, "rme32", &entry))
- snd_info_set_text_ops(entry, rme32, 1024, snd_rme32_proc_read);
+ snd_info_set_text_ops(entry, rme32, snd_rme32_proc_read);
}
/*
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index 3c1bc53..991cb18 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -1151,6 +1151,25 @@ static struct snd_pcm_hw_constraint_list hw_constraints_period_bytes = {
.mask = 0
};
+static void
+rme96_set_buffer_size_constraint(struct rme96 *rme96,
+ struct snd_pcm_runtime *runtime)
+{
+ unsigned int size;
+
+ snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ RME96_BUFFER_SIZE, RME96_BUFFER_SIZE);
+ if ((size = rme96->playback_periodsize) != 0 ||
+ (size = rme96->capture_periodsize) != 0)
+ snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+ size, size);
+ else
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+ &hw_constraints_period_bytes);
+}
+
static int
snd_rme96_playback_spdif_open(struct snd_pcm_substream *substream)
{
@@ -1180,8 +1199,7 @@ snd_rme96_playback_spdif_open(struct snd_pcm_substream *substream)
runtime->hw.rate_min = rate;
runtime->hw.rate_max = rate;
}
- snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE);
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes);
+ rme96_set_buffer_size_constraint(rme96, runtime);
rme96->wcreg_spdif_stream = rme96->wcreg_spdif;
rme96->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
@@ -1219,9 +1237,7 @@ snd_rme96_capture_spdif_open(struct snd_pcm_substream *substream)
rme96->capture_substream = substream;
spin_unlock_irq(&rme96->lock);
- snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE);
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes);
-
+ rme96_set_buffer_size_constraint(rme96, runtime);
return 0;
}
@@ -1254,8 +1270,7 @@ snd_rme96_playback_adat_open(struct snd_pcm_substream *substream)
runtime->hw.rate_min = rate;
runtime->hw.rate_max = rate;
}
- snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE);
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes);
+ rme96_set_buffer_size_constraint(rme96, runtime);
return 0;
}
@@ -1291,8 +1306,7 @@ snd_rme96_capture_adat_open(struct snd_pcm_substream *substream)
rme96->capture_substream = substream;
spin_unlock_irq(&rme96->lock);
- snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE);
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes);
+ rme96_set_buffer_size_constraint(rme96, runtime);
return 0;
}
@@ -1569,17 +1583,17 @@ snd_rme96_create(struct rme96 *rme96)
return err;
rme96->port = pci_resource_start(rme96->pci, 0);
+ if ((rme96->iobase = ioremap_nocache(rme96->port, RME96_IO_SIZE)) == 0) {
+ snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n", rme96->port, rme96->port + RME96_IO_SIZE - 1);
+ return -ENOMEM;
+ }
+
if (request_irq(pci->irq, snd_rme96_interrupt, SA_INTERRUPT|SA_SHIRQ, "RME96", (void *)rme96)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
return -EBUSY;
}
rme96->irq = pci->irq;
- if ((rme96->iobase = ioremap_nocache(rme96->port, RME96_IO_SIZE)) == 0) {
- snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n", rme96->port, rme96->port + RME96_IO_SIZE - 1);
- return -ENOMEM;
- }
-
/* read the card's revision number */
pci_read_config_byte(pci, 8, &rme96->rev);
@@ -1805,7 +1819,7 @@ snd_rme96_proc_init(struct rme96 *rme96)
struct snd_info_entry *entry;
if (! snd_card_proc_new(rme96->card, "rme96", &entry))
- snd_info_set_text_ops(entry, rme96, 1024, snd_rme96_proc_read);
+ snd_info_set_text_ops(entry, rme96, snd_rme96_proc_read);
}
/*
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 61f82f0..eaf3c22 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -389,7 +389,7 @@ MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP},"
/* use hotplug firmeare loader? */
#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
-#ifndef HDSP_USE_HWDEP_LOADER
+#if !defined(HDSP_USE_HWDEP_LOADER) && !defined(CONFIG_SND_HDSP)
#define HDSP_FW_LOADER
#endif
#endif
@@ -3169,9 +3169,10 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
char *clock_source;
int x;
- if (hdsp_check_for_iobox (hdsp))
+ if (hdsp_check_for_iobox (hdsp)) {
snd_iprintf(buffer, "No I/O box connected.\nPlease connect one and upload firmware.\n");
return;
+ }
if (hdsp_check_for_firmware(hdsp, 0)) {
if (hdsp->state & HDSP_FirmwareCached) {
@@ -3470,7 +3471,7 @@ static void __devinit snd_hdsp_proc_init(struct hdsp *hdsp)
struct snd_info_entry *entry;
if (! snd_card_proc_new(hdsp->card, "hdsp", &entry))
- snd_info_set_text_ops(entry, hdsp, 1024, snd_hdsp_proc_read);
+ snd_info_set_text_ops(entry, hdsp, snd_hdsp_proc_read);
}
static void snd_hdsp_free_buffers(struct hdsp *hdsp)
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 722b9e6..bba1615 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -2489,7 +2489,7 @@ static void __devinit snd_hdspm_proc_init(struct hdspm * hdspm)
struct snd_info_entry *entry;
if (!snd_card_proc_new(hdspm->card, "hdspm", &entry))
- snd_info_set_text_ops(entry, hdspm, 1024,
+ snd_info_set_text_ops(entry, hdspm,
snd_hdspm_proc_read);
}
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index 75d6406..3b945e8 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -41,7 +41,7 @@
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
-static int precise_ptr[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 }; /* Enable precise pointer */
+static int precise_ptr[SNDRV_CARDS]; /* Enable precise pointer */
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for RME Digi9652 (Hammerfall) soundcard.");
@@ -1787,7 +1787,7 @@ static void __devinit snd_rme9652_proc_init(struct snd_rme9652 *rme9652)
struct snd_info_entry *entry;
if (! snd_card_proc_new(rme9652->card, "rme9652", &entry))
- snd_info_set_text_ops(entry, rme9652, 1024, snd_rme9652_proc_read);
+ snd_info_set_text_ops(entry, rme9652, snd_rme9652_proc_read);
}
static void snd_rme9652_free_buffers(struct snd_rme9652 *rme9652)
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index 91f8bf3..dcf4029 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -54,8 +54,8 @@ MODULE_SUPPORTED_DEVICE("{{S3,SonicVibes PCI}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
-static int reverb[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
-static int mge[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int reverb[SNDRV_CARDS];
+static int mge[SNDRV_CARDS];
static unsigned int dmaio = 0x7a00; /* DDMA i/o address */
module_param_array(index, int, NULL, 0444);
@@ -1144,7 +1144,7 @@ static void __devinit snd_sonicvibes_proc_init(struct sonicvibes * sonic)
struct snd_info_entry *entry;
if (! snd_card_proc_new(sonic->card, "sonicvibes", &entry))
- snd_info_set_text_ops(entry, sonic, 1024, snd_sonicvibes_proc_read);
+ snd_info_set_text_ops(entry, sonic, snd_sonicvibes_proc_read);
}
/*
@@ -1456,7 +1456,7 @@ static int __devinit snd_sonic_probe(struct pci_dev *pci,
return err;
}
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SONICVIBES,
- sonic->midi_port, 1,
+ sonic->midi_port, MPU401_INFO_INTEGRATED,
sonic->irq, 0,
&midi_uart)) < 0) {
snd_card_free(card);
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c
index 9624a5f..5629b7e 100644
--- a/sound/pci/trident/trident.c
+++ b/sound/pci/trident/trident.c
@@ -148,7 +148,8 @@ static int __devinit snd_trident_probe(struct pci_dev *pci,
}
if (trident->device != TRIDENT_DEVICE_ID_SI7018 &&
(err = snd_mpu401_uart_new(card, 0, MPU401_HW_TRID4DWAVE,
- trident->midi_port, 1,
+ trident->midi_port,
+ MPU401_INFO_INTEGRATED,
trident->irq, 0, &trident->rmidi)) < 0) {
snd_card_free(card);
return err;
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index 52178b8..d99ed72 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -306,6 +306,8 @@ void snd_trident_start_voice(struct snd_trident * trident, unsigned int voice)
outl(mask, TRID_REG(trident, reg));
}
+EXPORT_SYMBOL(snd_trident_start_voice);
+
/*---------------------------------------------------------------------------
void snd_trident_stop_voice(struct snd_trident * trident, unsigned int voice)
@@ -328,6 +330,8 @@ void snd_trident_stop_voice(struct snd_trident * trident, unsigned int voice)
outl(mask, TRID_REG(trident, reg));
}
+EXPORT_SYMBOL(snd_trident_stop_voice);
+
/*---------------------------------------------------------------------------
int snd_trident_allocate_pcm_channel(struct snd_trident *trident)
@@ -502,6 +506,8 @@ void snd_trident_write_voice_regs(struct snd_trident * trident,
#endif
}
+EXPORT_SYMBOL(snd_trident_write_voice_regs);
+
/*---------------------------------------------------------------------------
snd_trident_write_cso_reg
@@ -3332,7 +3338,7 @@ static void __devinit snd_trident_proc_init(struct snd_trident * trident)
if (trident->device == TRIDENT_DEVICE_ID_SI7018)
s = "sis7018";
if (! snd_card_proc_new(trident->card, s, &entry))
- snd_info_set_text_ops(entry, trident, 1024, snd_trident_proc_read);
+ snd_info_set_text_ops(entry, trident, snd_trident_proc_read);
}
static int snd_trident_dev_free(struct snd_device *device)
@@ -3884,6 +3890,8 @@ struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident,
return NULL;
}
+EXPORT_SYMBOL(snd_trident_alloc_voice);
+
void snd_trident_free_voice(struct snd_trident * trident, struct snd_trident_voice *voice)
{
unsigned long flags;
@@ -3912,6 +3920,8 @@ void snd_trident_free_voice(struct snd_trident * trident, struct snd_trident_voi
private_free(voice);
}
+EXPORT_SYMBOL(snd_trident_free_voice);
+
static void snd_trident_clear_voices(struct snd_trident * trident, unsigned short v_min, unsigned short v_max)
{
unsigned int i, val, mask[2] = { 0, 0 };
@@ -3993,13 +4003,3 @@ int snd_trident_resume(struct pci_dev *pci)
return 0;
}
#endif /* CONFIG_PM */
-
-EXPORT_SYMBOL(snd_trident_alloc_voice);
-EXPORT_SYMBOL(snd_trident_free_voice);
-EXPORT_SYMBOL(snd_trident_start_voice);
-EXPORT_SYMBOL(snd_trident_stop_voice);
-EXPORT_SYMBOL(snd_trident_write_voice_regs);
-/* trident_memory.c symbols */
-EXPORT_SYMBOL(snd_trident_synth_alloc);
-EXPORT_SYMBOL(snd_trident_synth_free);
-EXPORT_SYMBOL(snd_trident_synth_copy_from_user);
diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c
index 46c6982..aff3f87 100644
--- a/sound/pci/trident/trident_memory.c
+++ b/sound/pci/trident/trident_memory.c
@@ -349,6 +349,7 @@ snd_trident_synth_alloc(struct snd_trident *hw, unsigned int size)
return blk;
}
+EXPORT_SYMBOL(snd_trident_synth_alloc);
/*
* free a synth sample area
@@ -365,6 +366,7 @@ snd_trident_synth_free(struct snd_trident *hw, struct snd_util_memblk *blk)
return 0;
}
+EXPORT_SYMBOL(snd_trident_synth_free);
/*
* reset TLB entry and free kernel page
@@ -486,3 +488,4 @@ int snd_trident_synth_copy_from_user(struct snd_trident *trident,
return 0;
}
+EXPORT_SYMBOL(snd_trident_synth_copy_from_user);
diff --git a/sound/pci/trident/trident_synth.c b/sound/pci/trident/trident_synth.c
index cc7af8b..9b7dee8 100644
--- a/sound/pci/trident/trident_synth.c
+++ b/sound/pci/trident/trident_synth.c
@@ -914,7 +914,9 @@ static int snd_trident_synth_create_port(struct snd_trident * trident, int idx)
&callbacks,
SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE |
- SNDRV_SEQ_PORT_TYPE_SYNTH,
+ SNDRV_SEQ_PORT_TYPE_SYNTH |
+ SNDRV_SEQ_PORT_TYPE_HARDWARE |
+ SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
16, 0,
name);
if (p->chset->port < 0) {
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 39daf62..2527bbd 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -1775,6 +1775,12 @@ static struct ac97_quirk ac97_quirks[] = {
.name = "Targa Traveller 811",
.type = AC97_TUNE_HP_ONLY,
},
+ {
+ .subvendor = 0x161f,
+ .subdevice = 0x2032,
+ .name = "m680x",
+ .type = AC97_TUNE_HP_ONLY, /* http://launchpad.net/bugs/38546 */
+ },
{ } /* terminator */
};
@@ -1973,7 +1979,7 @@ static int __devinit snd_via686_init_misc(struct via82xx *chip)
pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, legacy_cfg);
if (chip->mpu_res) {
if (snd_mpu401_uart_new(chip->card, 0, MPU401_HW_VIA686A,
- mpu_port, 1,
+ mpu_port, MPU401_INFO_INTEGRATED,
chip->irq, 0, &chip->rmidi) < 0) {
printk(KERN_WARNING "unable to initialize MPU-401"
" at 0x%lx, skipping\n", mpu_port);
@@ -2015,7 +2021,7 @@ static void __devinit snd_via82xx_proc_init(struct via82xx *chip)
struct snd_info_entry *entry;
if (! snd_card_proc_new(chip->card, "via82xx", &entry))
- snd_info_set_text_ops(entry, chip, 1024, snd_via82xx_proc_read);
+ snd_info_set_text_ops(entry, chip, snd_via82xx_proc_read);
}
/*
@@ -2365,7 +2371,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci, int revision)
{ .subvendor = 0x1462, .subdevice = 0x0470, .action = VIA_DXS_SRC }, /* MSI KT880 Delta-FSR */
{ .subvendor = 0x1462, .subdevice = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */
{ .subvendor = 0x1462, .subdevice = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */
- { .subvendor = 0x1462, .subdevice = 0x7023, .action = VIA_DXS_NO_VRA }, /* MSI K8T Neo2-FI */
+ { .subvendor = 0x1462, .subdevice = 0x7023, .action = VIA_DXS_SRC }, /* MSI K8T Neo2-FI */
{ .subvendor = 0x1462, .subdevice = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */
{ .subvendor = 0x1462, .subdevice = 0x7142, .action = VIA_DXS_ENABLE }, /* MSI K8MM-V */
{ .subvendor = 0x1462, .subdevice = 0xb012, .action = VIA_DXS_SRC }, /* P4M800/VIA8237R */
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index ef97e50..577a2b0 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -929,7 +929,7 @@ static void __devinit snd_via82xx_proc_init(struct via82xx_modem *chip)
struct snd_info_entry *entry;
if (! snd_card_proc_new(chip->card, "via82xx", &entry))
- snd_info_set_text_ops(entry, chip, 1024, snd_via82xx_proc_read);
+ snd_info_set_text_ops(entry, chip, snd_via82xx_proc_read);
}
/*
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c
index 65ebf5f..26aa775 100644
--- a/sound/pci/ymfpci/ymfpci.c
+++ b/sound/pci/ymfpci/ymfpci.c
@@ -308,7 +308,8 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci,
}
if (chip->mpu_res) {
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_YMFPCI,
- mpu_port[dev], 1,
+ mpu_port[dev],
+ MPU401_INFO_INTEGRATED,
pci->irq, 0, &chip->rawmidi)) < 0) {
printk(KERN_WARNING "ymfpci: cannot initialize MPU401 at 0x%lx, skipping...\n", mpu_port[dev]);
legacy_ctrl &= ~YMFPCI_LEGACY_MIEN; /* disable MPU401 irq */
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index 8ac5ab5..f894752 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -1919,7 +1919,7 @@ static int __devinit snd_ymfpci_proc_init(struct snd_card *card, struct snd_ymfp
struct snd_info_entry *entry;
if (! snd_card_proc_new(card, "ymfpci", &entry))
- snd_info_set_text_ops(entry, chip, 1024, snd_ymfpci_proc_read);
+ snd_info_set_text_ops(entry, chip, snd_ymfpci_proc_read);
return 0;
}
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
index bd0d70f..1dfe29b 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
@@ -144,7 +144,7 @@ static void pdacf_proc_init(struct snd_pdacf *chip)
struct snd_info_entry *entry;
if (! snd_card_proc_new(chip->card, "pdaudiocf", &entry))
- snd_info_set_text_ops(entry, chip, 1024, pdacf_proc_read);
+ snd_info_set_text_ops(entry, chip, pdacf_proc_read);
}
struct snd_pdacf *snd_pdacf_create(struct snd_card *card)
diff --git a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c
index 7f82f61..1ee0918 100644
--- a/sound/pcmcia/vx/vxp_ops.c
+++ b/sound/pcmcia/vx/vxp_ops.c
@@ -202,7 +202,7 @@ static int vxp_load_xilinx_binary(struct vx_core *_chip, const struct firmware *
c |= (int)vx_inb(chip, RXM) << 8;
c |= vx_inb(chip, RXL);
- snd_printdd(KERN_DEBUG "xilinx: dsp size received 0x%x, orig 0x%x\n", c, fw->size);
+ snd_printdd(KERN_DEBUG "xilinx: dsp size received 0x%x, orig 0x%Zx\n", c, fw->size);
vx_outb(chip, ICR, ICR_HF0);
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c
index 7e0cda2..cafe664 100644
--- a/sound/pcmcia/vx/vxpocket.c
+++ b/sound/pcmcia/vx/vxpocket.c
@@ -261,7 +261,7 @@ static int vxpocket_config(struct pcmcia_device *link)
link->dev_node = &vxp->node;
kfree(parse);
- return 9;
+ return 0;
cs_failed:
cs_error(link, last_fn, last_ret);
diff --git a/sound/ppc/Makefile b/sound/ppc/Makefile
index d6ba995..4d95c65 100644
--- a/sound/ppc/Makefile
+++ b/sound/ppc/Makefile
@@ -3,7 +3,7 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
#
-snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o toonie.o keywest.o beep.o
+snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o beep.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_POWERMAC) += snd-powermac.o
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index f0794ef..b678814 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -867,8 +867,6 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
unsigned int *prop, l;
struct macio_chip* macio;
- u32 layout_id = 0;
-
if (!machine_is(powermac))
return -ENODEV;
@@ -929,8 +927,14 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
if (prop && *prop < 16)
chip->subframe = *prop;
prop = (unsigned int *) get_property(sound, "layout-id", NULL);
- if (prop)
- layout_id = *prop;
+ if (prop) {
+ /* partly deprecate snd-powermac, for those machines
+ * that have a layout-id property for now */
+ printk(KERN_INFO "snd-powermac no longer handles any "
+ "machines with a layout-id property "
+ "in the device-tree, use snd-aoa.\n");
+ return -ENODEV;
+ }
/* This should be verified on older screamers */
if (device_is_compatible(sound, "screamer")) {
chip->model = PMAC_SCREAMER;
@@ -963,38 +967,6 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
chip->freq_table = tumbler_freqs;
chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
}
- if (device_is_compatible(sound, "AOAKeylargo") ||
- device_is_compatible(sound, "AOAbase") ||
- device_is_compatible(sound, "AOAK2")) {
- /* For now, only support very basic TAS3004 based machines with
- * single frequency until proper i2s control is implemented
- */
- switch(layout_id) {
- case 0x24:
- case 0x29:
- case 0x33:
- case 0x46:
- case 0x48:
- case 0x50:
- case 0x5c:
- chip->num_freqs = ARRAY_SIZE(tumbler_freqs);
- chip->model = PMAC_SNAPPER;
- chip->can_byte_swap = 0; /* FIXME: check this */
- chip->control_mask = MASK_IEPC | 0x11;/* disable IEE */
- break;
- case 0x3a:
- chip->num_freqs = ARRAY_SIZE(tumbler_freqs);
- chip->model = PMAC_TOONIE;
- chip->can_byte_swap = 0; /* FIXME: check this */
- chip->control_mask = MASK_IEPC | 0x11;/* disable IEE */
- break;
- default:
- printk(KERN_ERR "snd: Unknown layout ID 0x%x\n",
- layout_id);
- return -ENODEV;
-
- }
- }
prop = (unsigned int *)get_property(sound, "device-id", NULL);
if (prop)
chip->device_id = *prop;
diff --git a/sound/ppc/pmac.h b/sound/ppc/pmac.h
index 3a9bd4d..8394e66 100644
--- a/sound/ppc/pmac.h
+++ b/sound/ppc/pmac.h
@@ -85,7 +85,7 @@ struct pmac_stream {
enum snd_pmac_model {
PMAC_AWACS, PMAC_SCREAMER, PMAC_BURGUNDY, PMAC_DACA, PMAC_TUMBLER,
- PMAC_SNAPPER, PMAC_TOONIE
+ PMAC_SNAPPER
};
struct snd_pmac {
@@ -188,7 +188,6 @@ int snd_pmac_burgundy_init(struct snd_pmac *chip);
int snd_pmac_daca_init(struct snd_pmac *chip);
int snd_pmac_tumbler_init(struct snd_pmac *chip);
int snd_pmac_tumbler_post_init(void);
-int snd_pmac_toonie_init(struct snd_pmac *chip);
/* i2c functions */
struct pmac_keywest {
diff --git a/sound/ppc/powermac.c b/sound/ppc/powermac.c
index f4902a2..fa9a44a 100644
--- a/sound/ppc/powermac.c
+++ b/sound/ppc/powermac.c
@@ -94,13 +94,6 @@ static int __init snd_pmac_probe(struct platform_device *devptr)
if ( snd_pmac_tumbler_init(chip) < 0 || snd_pmac_tumbler_post_init() < 0)
goto __error;
break;
- case PMAC_TOONIE:
- strcpy(card->driver, "PMac Toonie");
- strcpy(card->shortname, "PowerMac Toonie");
- strcpy(card->longname, card->shortname);
- if ((err = snd_pmac_toonie_init(chip)) < 0)
- goto __error;
- break;
case PMAC_AWACS:
case PMAC_SCREAMER:
name_ext = chip->model == PMAC_SCREAMER ? "Screamer" : "AWACS";
@@ -188,11 +181,15 @@ static int __init alsa_card_pmac_init(void)
if ((err = platform_driver_register(&snd_pmac_driver)) < 0)
return err;
device = platform_device_register_simple(SND_PMAC_DRIVER, -1, NULL, 0);
- if (IS_ERR(device)) {
- platform_driver_unregister(&snd_pmac_driver);
- return PTR_ERR(device);
- }
- return 0;
+ if (!IS_ERR(device)) {
+ if (platform_get_drvdata(device))
+ return 0;
+ platform_device_unregister(device);
+ err = -ENODEV;
+ } else
+ err = PTR_ERR(device);
+ platform_driver_unregister(&snd_pmac_driver);
+ return err;
}
diff --git a/sound/ppc/toonie.c b/sound/ppc/toonie.c
index 1ac7c85..e69de29 100644
--- a/sound/ppc/toonie.c
+++ b/sound/ppc/toonie.c
@@ -1,378 +0,0 @@
-/*
- * Mac Mini "toonie" mixer control
- *
- * Copyright (c) 2005 by Benjamin Herrenschmidt <benh@kernel.crashing.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, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <sound/driver.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/kmod.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <sound/core.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include "pmac.h"
-
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(fmt...) printk(fmt)
-#else
-#define DBG(fmt...)
-#endif
-
-struct pmac_gpio {
- unsigned int addr;
- u8 active_val;
- u8 inactive_val;
- u8 active_state;
-};
-
-struct pmac_toonie
-{
- struct pmac_gpio hp_detect_gpio;
- struct pmac_gpio hp_mute_gpio;
- struct pmac_gpio amp_mute_gpio;
- int hp_detect_irq;
- int auto_mute_notify;
- struct work_struct detect_work;
-};
-
-
-/*
- * gpio access
- */
-#define do_gpio_write(gp, val) \
- pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, (gp)->addr, val)
-#define do_gpio_read(gp) \
- pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, (gp)->addr, 0)
-#define tumbler_gpio_free(gp) /* NOP */
-
-static void write_audio_gpio(struct pmac_gpio *gp, int active)
-{
- if (! gp->addr)
- return;
- active = active ? gp->active_val : gp->inactive_val;
- do_gpio_write(gp, active);
- DBG("(I) gpio %x write %d\n", gp->addr, active);
-}
-
-static int check_audio_gpio(struct pmac_gpio *gp)
-{
- int ret;
-
- if (! gp->addr)
- return 0;
-
- ret = do_gpio_read(gp);
-
- return (ret & 0xd) == (gp->active_val & 0xd);
-}
-
-static int read_audio_gpio(struct pmac_gpio *gp)
-{
- int ret;
- if (! gp->addr)
- return 0;
- ret = ((do_gpio_read(gp) & 0x02) !=0);
- return ret == gp->active_state;
-}
-
-
-enum { TOONIE_MUTE_HP, TOONIE_MUTE_AMP };
-
-static int toonie_get_mute_switch(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
- struct pmac_toonie *mix = chip->mixer_data;
- struct pmac_gpio *gp;
-
- if (mix == NULL)
- return -ENODEV;
- switch(kcontrol->private_value) {
- case TOONIE_MUTE_HP:
- gp = &mix->hp_mute_gpio;
- break;
- case TOONIE_MUTE_AMP:
- gp = &mix->amp_mute_gpio;
- break;
- default:
- return -EINVAL;
- }
- ucontrol->value.integer.value[0] = !check_audio_gpio(gp);
- return 0;
-}
-
-static int toonie_put_mute_switch(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
- struct pmac_toonie *mix = chip->mixer_data;
- struct pmac_gpio *gp;
- int val;
-
- if (chip->update_automute && chip->auto_mute)
- return 0; /* don't touch in the auto-mute mode */
-
- if (mix == NULL)
- return -ENODEV;
-
- switch(kcontrol->private_value) {
- case TOONIE_MUTE_HP:
- gp = &mix->hp_mute_gpio;
- break;
- case TOONIE_MUTE_AMP:
- gp = &mix->amp_mute_gpio;
- break;
- default:
- return -EINVAL;
- }
- val = ! check_audio_gpio(gp);
- if (val != ucontrol->value.integer.value[0]) {
- write_audio_gpio(gp, ! ucontrol->value.integer.value[0]);
- return 1;
- }
- return 0;
-}
-
-static struct snd_kcontrol_new toonie_hp_sw __initdata = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Headphone Playback Switch",
- .info = snd_pmac_boolean_mono_info,
- .get = toonie_get_mute_switch,
- .put = toonie_put_mute_switch,
- .private_value = TOONIE_MUTE_HP,
-};
-static struct snd_kcontrol_new toonie_speaker_sw __initdata = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "PC Speaker Playback Switch",
- .info = snd_pmac_boolean_mono_info,
- .get = toonie_get_mute_switch,
- .put = toonie_put_mute_switch,
- .private_value = TOONIE_MUTE_AMP,
-};
-
-/*
- * auto-mute stuffs
- */
-static int toonie_detect_headphone(struct snd_pmac *chip)
-{
- struct pmac_toonie *mix = chip->mixer_data;
- int detect = 0;
-
- if (mix->hp_detect_gpio.addr)
- detect |= read_audio_gpio(&mix->hp_detect_gpio);
- return detect;
-}
-
-static void toonie_check_mute(struct snd_pmac *chip, struct pmac_gpio *gp, int val,
- int do_notify, struct snd_kcontrol *sw)
-{
- if (check_audio_gpio(gp) != val) {
- write_audio_gpio(gp, val);
- if (do_notify)
- snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
- &sw->id);
- }
-}
-
-static void toonie_detect_handler(void *self)
-{
- struct snd_pmac *chip = (struct snd_pmac *) self;
- struct pmac_toonie *mix;
- int headphone;
-
- if (!chip)
- return;
-
- mix = chip->mixer_data;
- snd_assert(mix, return);
-
- headphone = toonie_detect_headphone(chip);
-
- DBG("headphone: %d, lineout: %d\n", headphone, lineout);
-
- if (headphone) {
- /* unmute headphone/lineout & mute speaker */
- toonie_check_mute(chip, &mix->hp_mute_gpio, 0,
- mix->auto_mute_notify, chip->master_sw_ctl);
- toonie_check_mute(chip, &mix->amp_mute_gpio, 1,
- mix->auto_mute_notify, chip->speaker_sw_ctl);
- } else {
- /* unmute speaker, mute others */
- toonie_check_mute(chip, &mix->amp_mute_gpio, 0,
- mix->auto_mute_notify, chip->speaker_sw_ctl);
- toonie_check_mute(chip, &mix->hp_mute_gpio, 1,
- mix->auto_mute_notify, chip->master_sw_ctl);
- }
- if (mix->auto_mute_notify) {
- snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
- &chip->hp_detect_ctl->id);
- }
-}
-
-static void toonie_update_automute(struct snd_pmac *chip, int do_notify)
-{
- if (chip->auto_mute) {
- struct pmac_toonie *mix;
- mix = chip->mixer_data;
- snd_assert(mix, return);
- mix->auto_mute_notify = do_notify;
- schedule_work(&mix->detect_work);
- }
-}
-
-/* interrupt - headphone plug changed */
-static irqreturn_t toonie_hp_intr(int irq, void *devid, struct pt_regs *regs)
-{
- struct snd_pmac *chip = devid;
-
- if (chip->update_automute && chip->initialized) {
- chip->update_automute(chip, 1);
- return IRQ_HANDLED;
- }
- return IRQ_NONE;
-}
-
-/* look for audio gpio device */
-static int find_audio_gpio(const char *name, const char *platform,
- struct pmac_gpio *gp)
-{
- struct device_node *np;
- u32 *base, addr;
-
- if (! (np = find_devices("gpio")))
- return -ENODEV;
-
- for (np = np->child; np; np = np->sibling) {
- char *property = get_property(np, "audio-gpio", NULL);
- if (property && strcmp(property, name) == 0)
- break;
- if (device_is_compatible(np, name))
- break;
- }
- if (np == NULL)
- return -ENODEV;
-
- base = (u32 *)get_property(np, "AAPL,address", NULL);
- if (! base) {
- base = (u32 *)get_property(np, "reg", NULL);
- if (!base) {
- DBG("(E) cannot find address for device %s !\n", name);
- return -ENODEV;
- }
- addr = *base;
- if (addr < 0x50)
- addr += 0x50;
- } else
- addr = *base;
-
- gp->addr = addr & 0x0000ffff;
-
- /* Try to find the active state, default to 0 ! */
- base = (u32 *)get_property(np, "audio-gpio-active-state", NULL);
- if (base) {
- gp->active_state = *base;
- gp->active_val = (*base) ? 0x5 : 0x4;
- gp->inactive_val = (*base) ? 0x4 : 0x5;
- } else {
- u32 *prop = NULL;
- gp->active_state = 0;
- gp->active_val = 0x4;
- gp->inactive_val = 0x5;
- /* Here are some crude hacks to extract the GPIO polarity and
- * open collector informations out of the do-platform script
- * as we don't yet have an interpreter for these things
- */
- if (platform)
- prop = (u32 *)get_property(np, platform, NULL);
- if (prop) {
- if (prop[3] == 0x9 && prop[4] == 0x9) {
- gp->active_val = 0xd;
- gp->inactive_val = 0xc;
- }
- if (prop[3] == 0x1 && prop[4] == 0x1) {
- gp->active_val = 0x5;
- gp->inactive_val = 0x4;
- }
- }
- }
-
- DBG("(I) GPIO device %s found, offset: %x, active state: %d !\n",
- name, gp->addr, gp->active_state);
-
- return (np->n_intrs > 0) ? np->intrs[0].line : 0;
-}
-
-static void toonie_cleanup(struct snd_pmac *chip)
-{
- struct pmac_toonie *mix = chip->mixer_data;
- if (! mix)
- return;
- if (mix->hp_detect_irq >= 0)
- free_irq(mix->hp_detect_irq, chip);
- kfree(mix);
- chip->mixer_data = NULL;
-}
-
-int __init snd_pmac_toonie_init(struct snd_pmac *chip)
-{
- struct pmac_toonie *mix;
-
- mix = kmalloc(sizeof(*mix), GFP_KERNEL);
- if (! mix)
- return -ENOMEM;
-
- chip->mixer_data = mix;
- chip->mixer_free = toonie_cleanup;
-
- find_audio_gpio("headphone-mute", NULL, &mix->hp_mute_gpio);
- find_audio_gpio("amp-mute", NULL, &mix->amp_mute_gpio);
- mix->hp_detect_irq = find_audio_gpio("headphone-detect",
- NULL, &mix->hp_detect_gpio);
-
- strcpy(chip->card->mixername, "PowerMac Toonie");
-
- chip->master_sw_ctl = snd_ctl_new1(&toonie_hp_sw, chip);
- snd_ctl_add(chip->card, chip->master_sw_ctl);
-
- chip->speaker_sw_ctl = snd_ctl_new1(&toonie_speaker_sw, chip);
- snd_ctl_add(chip->card, chip->speaker_sw_ctl);
-
- INIT_WORK(&mix->detect_work, toonie_detect_handler, (void *)chip);
-
- if (mix->hp_detect_irq >= 0) {
- snd_pmac_add_automute(chip);
-
- chip->detect_headphone = toonie_detect_headphone;
- chip->update_automute = toonie_update_automute;
- toonie_update_automute(chip, 0);
-
- if (request_irq(mix->hp_detect_irq, toonie_hp_intr, 0,
- "Sound Headphone Detection", chip) < 0)
- mix->hp_detect_irq = -1;
- }
-
- return 0;
-}
-
diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c
index dfe9bac..ba1b2a3 100644
--- a/sound/sparc/amd7930.c
+++ b/sound/sparc/amd7930.c
@@ -46,6 +46,7 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/sbus.h>
+#include <asm/prom.h>
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
@@ -335,7 +336,6 @@ struct snd_amd7930 {
int pgain;
int mgain;
- struct sbus_dev *sdev;
unsigned int irq;
unsigned int regs_size;
struct snd_amd7930 *next;
@@ -946,11 +946,9 @@ static struct snd_device_ops snd_amd7930_dev_ops = {
};
static int __init snd_amd7930_create(struct snd_card *card,
- struct sbus_dev *sdev,
struct resource *rp,
unsigned int reg_size,
- struct linux_prom_irqs *irq_prop,
- int dev,
+ int irq, int dev,
struct snd_amd7930 **ramd)
{
unsigned long flags;
@@ -964,7 +962,6 @@ static int __init snd_amd7930_create(struct snd_card *card,
spin_lock_init(&amd->lock);
amd->card = card;
- amd->sdev = sdev;
amd->regs_size = reg_size;
amd->regs = sbus_ioremap(rp, 0, amd->regs_size, "amd7930");
@@ -975,15 +972,14 @@ static int __init snd_amd7930_create(struct snd_card *card,
amd7930_idle(amd);
- if (request_irq(irq_prop->pri, snd_amd7930_interrupt,
+ if (request_irq(irq, snd_amd7930_interrupt,
SA_INTERRUPT | SA_SHIRQ, "amd7930", amd)) {
snd_printk("amd7930-%d: Unable to grab IRQ %d\n",
- dev,
- irq_prop->pri);
+ dev, irq);
snd_amd7930_free(amd);
return -EBUSY;
}
- amd->irq = irq_prop->pri;
+ amd->irq = irq;
amd7930_enable_ints(amd);
@@ -1017,47 +1013,21 @@ static int __init snd_amd7930_create(struct snd_card *card,
return 0;
}
-static int __init amd7930_attach(int prom_node, struct sbus_dev *sdev)
+static int __init amd7930_attach_common(struct resource *rp, int irq)
{
- static int dev;
- struct linux_prom_registers reg_prop;
- struct linux_prom_irqs irq_prop;
- struct resource res, *rp;
+ static int dev_num;
struct snd_card *card;
struct snd_amd7930 *amd;
int err;
- if (dev >= SNDRV_CARDS)
+ if (dev_num >= SNDRV_CARDS)
return -ENODEV;
- if (!enable[dev]) {
- dev++;
+ if (!enable[dev_num]) {
+ dev_num++;
return -ENOENT;
}
- err = prom_getproperty(prom_node, "intr",
- (char *) &irq_prop, sizeof(irq_prop));
- if (err < 0) {
- snd_printk("amd7930-%d: Firmware node lacks IRQ property.\n", dev);
- return -ENODEV;
- }
-
- err = prom_getproperty(prom_node, "reg",
- (char *) &reg_prop, sizeof(reg_prop));
- if (err < 0) {
- snd_printk("amd7930-%d: Firmware node lacks register property.\n", dev);
- return -ENODEV;
- }
-
- if (sdev) {
- rp = &sdev->resource[0];
- } else {
- rp = &res;
- rp->start = reg_prop.phys_addr;
- rp->end = rp->start + reg_prop.reg_size - 1;
- rp->flags = IORESOURCE_IO | (reg_prop.which_io & 0xff);
- }
-
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+ card = snd_card_new(index[dev_num], id[dev_num], THIS_MODULE, 0);
if (card == NULL)
return -ENOMEM;
@@ -1067,10 +1037,11 @@ static int __init amd7930_attach(int prom_node, struct sbus_dev *sdev)
card->shortname,
rp->flags & 0xffL,
rp->start,
- irq_prop.pri);
+ irq);
- if ((err = snd_amd7930_create(card, sdev, rp, reg_prop.reg_size,
- &irq_prop, dev, &amd)) < 0)
+ if ((err = snd_amd7930_create(card, rp,
+ (rp->end - rp->start) + 1,
+ irq, dev_num, &amd)) < 0)
goto out_err;
if ((err = snd_amd7930_pcm(amd)) < 0)
@@ -1085,7 +1056,8 @@ static int __init amd7930_attach(int prom_node, struct sbus_dev *sdev)
amd->next = amd7930_list;
amd7930_list = amd;
- dev++;
+ dev_num++;
+
return 0;
out_err:
@@ -1093,29 +1065,71 @@ out_err:
return err;
}
-static int __init amd7930_init(void)
+static int __init amd7930_obio_attach(struct device_node *dp)
+{
+ struct linux_prom_registers *regs;
+ struct linux_prom_irqs *irqp;
+ struct resource res, *rp;
+ int len;
+
+ irqp = of_get_property(dp, "intr", &len);
+ if (!irqp) {
+ snd_printk("%s: Firmware node lacks IRQ property.\n",
+ dp->full_name);
+ return -ENODEV;
+ }
+
+ regs = of_get_property(dp, "reg", &len);
+ if (!regs) {
+ snd_printk("%s: Firmware node lacks register property.\n",
+ dp->full_name);
+ return -ENODEV;
+ }
+
+ rp = &res;
+ rp->start = regs->phys_addr;
+ rp->end = rp->start + regs->reg_size - 1;
+ rp->flags = IORESOURCE_IO | (regs->which_io & 0xff);
+
+ return amd7930_attach_common(rp, irqp->pri);
+}
+
+static int __devinit amd7930_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev;
- int node, found;
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
- found = 0;
+ return amd7930_attach_common(&sdev->resource[0], sdev->irqs[0]);
+}
+
+static struct of_device_id amd7930_match[] = {
+ {
+ .name = "audio",
+ },
+ {},
+};
+
+static struct of_platform_driver amd7930_sbus_driver = {
+ .name = "audio",
+ .match_table = amd7930_match,
+ .probe = amd7930_sbus_probe,
+};
+
+static int __init amd7930_init(void)
+{
+ struct device_node *dp;
/* Try to find the sun4c "audio" node first. */
- node = prom_getchild(prom_root_node);
- node = prom_searchsiblings(node, "audio");
- if (node && amd7930_attach(node, NULL) == 0)
- found++;
+ dp = of_find_node_by_path("/");
+ dp = dp->child;
+ while (dp) {
+ if (!strcmp(dp->name, "audio"))
+ amd7930_obio_attach(dp);
- /* Probe each SBUS for amd7930 chips. */
- for_all_sbusdev(sdev, sbus) {
- if (!strcmp(sdev->prom_name, "audio")) {
- if (amd7930_attach(sdev->prom_node, sdev) == 0)
- found++;
- }
+ dp = dp->sibling;
}
- return (found > 0) ? 0 : -EIO;
+ /* Probe each SBUS for amd7930 chips. */
+ return of_register_driver(&amd7930_sbus_driver, &sbus_bus_type);
}
static void __exit amd7930_exit(void)
@@ -1131,6 +1145,8 @@ static void __exit amd7930_exit(void)
}
amd7930_list = NULL;
+
+ of_unregister_driver(&amd7930_sbus_driver);
}
module_init(amd7930_init);
diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c
index b3efc9a..da54d04 100644
--- a/sound/sparc/cs4231.c
+++ b/sound/sparc/cs4231.c
@@ -2284,15 +2284,14 @@ static int __init cs4231_init(void)
for_each_ebusdev(edev, ebus) {
int match = 0;
- if (!strcmp(edev->prom_name, "SUNW,CS4231")) {
+ if (!strcmp(edev->prom_node->name, "SUNW,CS4231")) {
match = 1;
- } else if (!strcmp(edev->prom_name, "audio")) {
- char compat[16];
+ } else if (!strcmp(edev->prom_node->name, "audio")) {
+ char *compat;
- prom_getstring(edev->prom_node, "compatible",
- compat, sizeof(compat));
- compat[15] = '\0';
- if (!strcmp(compat, "SUNW,CS4231"))
+ compat = of_get_property(edev->prom_node,
+ "compatible", NULL);
+ if (compat && !strcmp(compat, "SUNW,CS4231"))
match = 1;
}
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c
index e622d08..5eecdd0 100644
--- a/sound/sparc/dbri.c
+++ b/sound/sparc/dbri.c
@@ -92,7 +92,7 @@ MODULE_PARM_DESC(enable, "Enable Sun DBRI soundcard.");
#define D_USR (1<<4)
#define D_DESC (1<<5)
-static int dbri_debug = 0;
+static int dbri_debug;
module_param(dbri_debug, int, 0644);
MODULE_PARM_DESC(dbri_debug, "Debug value for Sun DBRI soundcard.");
@@ -593,7 +593,7 @@ struct snd_dbri {
/* Return a pointer to dbri_streaminfo */
#define DBRI_STREAM(dbri, substream) &dbri->stream_info[DBRI_STREAMNO(substream)]
-static struct snd_dbri *dbri_list = NULL; /* All DBRI devices */
+static struct snd_dbri *dbri_list; /* All DBRI devices */
/*
* Short data pipes transmit LSB first. The CS4215 receives MSB first. Grrr.
@@ -2521,11 +2521,11 @@ void snd_dbri_proc(struct snd_dbri * dbri)
struct snd_info_entry *entry;
if (! snd_card_proc_new(dbri->card, "regs", &entry))
- snd_info_set_text_ops(entry, dbri, 1024, dbri_regs_read);
+ snd_info_set_text_ops(entry, dbri, dbri_regs_read);
#ifdef DBRI_DEBUG
if (! snd_card_proc_new(dbri->card, "debug", &entry)) {
- snd_info_set_text_ops(entry, dbri, 4096, dbri_debug_read);
+ snd_info_set_text_ops(entry, dbri, dbri_debug_read);
entry->mode = S_IFREG | S_IRUGO; /* Readable only. */
}
#endif
diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c
index fc733bb..573e370 100644
--- a/sound/synth/emux/emux.c
+++ b/sound/synth/emux/emux.c
@@ -63,6 +63,7 @@ int snd_emux_new(struct snd_emux **remu)
return 0;
}
+EXPORT_SYMBOL(snd_emux_new);
/*
*/
@@ -136,6 +137,7 @@ int snd_emux_register(struct snd_emux *emu, struct snd_card *card, int index, ch
return 0;
}
+EXPORT_SYMBOL(snd_emux_register);
/*
*/
@@ -171,18 +173,8 @@ int snd_emux_free(struct snd_emux *emu)
return 0;
}
-
-EXPORT_SYMBOL(snd_emux_new);
-EXPORT_SYMBOL(snd_emux_register);
EXPORT_SYMBOL(snd_emux_free);
-EXPORT_SYMBOL(snd_emux_terminate_all);
-EXPORT_SYMBOL(snd_emux_lock_voice);
-EXPORT_SYMBOL(snd_emux_unlock_voice);
-
-/* soundfont.c */
-EXPORT_SYMBOL(snd_sf_linear_to_log);
-
/*
* INIT part
diff --git a/sound/synth/emux/emux_proc.c b/sound/synth/emux/emux_proc.c
index 1ba68ce..58b9601 100644
--- a/sound/synth/emux/emux_proc.c
+++ b/sound/synth/emux/emux_proc.c
@@ -119,7 +119,6 @@ void snd_emux_proc_init(struct snd_emux *emu, struct snd_card *card, int device)
entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->private_data = emu;
- entry->c.text.read_size = 1024;
entry->c.text.read = snd_emux_proc_info_read;
if (snd_info_register(entry) < 0)
snd_info_free_entry(entry);
diff --git a/sound/synth/emux/emux_seq.c b/sound/synth/emux/emux_seq.c
index 8f00f07..d176cc0 100644
--- a/sound/synth/emux/emux_seq.c
+++ b/sound/synth/emux/emux_seq.c
@@ -55,7 +55,8 @@ static struct snd_midi_op emux_ops = {
SNDRV_SEQ_PORT_TYPE_MIDI_GM |\
SNDRV_SEQ_PORT_TYPE_MIDI_GS |\
SNDRV_SEQ_PORT_TYPE_MIDI_XG |\
- SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE)
+ SNDRV_SEQ_PORT_TYPE_HARDWARE |\
+ SNDRV_SEQ_PORT_TYPE_SYNTHESIZER)
/*
* Initialise the EMUX Synth by creating a client and registering
diff --git a/sound/synth/emux/emux_synth.c b/sound/synth/emux/emux_synth.c
index 24705d1..3733118 100644
--- a/sound/synth/emux/emux_synth.c
+++ b/sound/synth/emux/emux_synth.c
@@ -434,6 +434,7 @@ snd_emux_terminate_all(struct snd_emux *emu)
spin_unlock_irqrestore(&emu->voice_lock, flags);
}
+EXPORT_SYMBOL(snd_emux_terminate_all);
/*
* Terminate all voices associated with the given port
@@ -951,6 +952,8 @@ void snd_emux_lock_voice(struct snd_emux *emu, int voice)
spin_unlock_irqrestore(&emu->voice_lock, flags);
}
+EXPORT_SYMBOL(snd_emux_lock_voice);
+
/*
*/
void snd_emux_unlock_voice(struct snd_emux *emu, int voice)
@@ -965,3 +968,5 @@ void snd_emux_unlock_voice(struct snd_emux *emu, int voice)
voice, emu->voices[voice].state);
spin_unlock_irqrestore(&emu->voice_lock, flags);
}
+
+EXPORT_SYMBOL(snd_emux_unlock_voice);
diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c
index 32c2716..455e535 100644
--- a/sound/synth/emux/soundfont.c
+++ b/sound/synth/emux/soundfont.c
@@ -195,7 +195,7 @@ snd_soundfont_load(struct snd_sf_list *sflist, const void __user *data,
break;
case SNDRV_SFNT_REMOVE_INFO:
/* patch must be opened */
- if (sflist->currsf) {
+ if (!sflist->currsf) {
snd_printk("soundfont: remove_info: patch not opened\n");
rc = -EINVAL;
} else {
@@ -810,6 +810,9 @@ snd_sf_linear_to_log(unsigned int amount, int offset, int ratio)
return v;
}
+EXPORT_SYMBOL(snd_sf_linear_to_log);
+
+
#define OFFSET_MSEC 653117 /* base = 1000 */
#define OFFSET_ABSCENT 851781 /* base = 8176 */
#define OFFSET_SAMPLERATE 1011119 /* base = 44100 */
@@ -1485,4 +1488,3 @@ snd_soundfont_remove_unlocked(struct snd_sf_list *sflist)
unlock_preset(sflist);
return 0;
}
-
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index 4e614ac..627de95 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -2138,7 +2138,7 @@ static void proc_pcm_format_add(struct snd_usb_stream *stream)
sprintf(name, "stream%d", stream->pcm_index);
if (! snd_card_proc_new(card, name, &entry))
- snd_info_set_text_ops(entry, stream, 1024, proc_pcm_format_read);
+ snd_info_set_text_ops(entry, stream, proc_pcm_format_read);
}
#else
@@ -2627,9 +2627,10 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
if (!csep && altsd->bNumEndpoints >= 2)
csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT);
if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) {
- snd_printk(KERN_ERR "%d:%u:%d : no or invalid class specific endpoint descriptor\n",
+ snd_printk(KERN_WARNING "%d:%u:%d : no or invalid"
+ " class specific endpoint descriptor\n",
dev->devnum, iface_no, altno);
- continue;
+ csep = NULL;
}
fp = kmalloc(sizeof(*fp), GFP_KERNEL);
@@ -2648,7 +2649,7 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
if (snd_usb_get_speed(dev) == USB_SPEED_HIGH)
fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
* (fp->maxpacksize & 0x7ff);
- fp->attributes = csep[3];
+ fp->attributes = csep ? csep[3] : 0;
/* some quirks for attributes here */
@@ -2980,7 +2981,7 @@ static int create_ua1000_quirk(struct snd_usb_audio *chip,
return -ENXIO;
alts = &iface->altsetting[1];
altsd = get_iface_desc(alts);
- if (alts->extralen != 11 || alts->extra[1] != CS_AUDIO_INTERFACE ||
+ if (alts->extralen != 11 || alts->extra[1] != USB_DT_CS_INTERFACE ||
altsd->bNumEndpoints != 1)
return -ENXIO;
@@ -3197,9 +3198,9 @@ static void snd_usb_audio_create_proc(struct snd_usb_audio *chip)
{
struct snd_info_entry *entry;
if (! snd_card_proc_new(chip->card, "usbbus", &entry))
- snd_info_set_text_ops(entry, chip, 1024, proc_audio_usbbus_read);
+ snd_info_set_text_ops(entry, chip, proc_audio_usbbus_read);
if (! snd_card_proc_new(chip->card, "usbid", &entry))
- snd_info_set_text_ops(entry, chip, 1024, proc_audio_usbid_read);
+ snd_info_set_text_ops(entry, chip, proc_audio_usbid_read);
}
/*
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 8873352..0f4b2b8 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -30,13 +30,6 @@
#define USB_SUBCLASS_MIDI_STREAMING 0x03
#define USB_SUBCLASS_VENDOR_SPEC 0xff
-#define CS_AUDIO_UNDEFINED 0x20
-#define CS_AUDIO_DEVICE 0x21
-#define CS_AUDIO_CONFIGURATION 0x22
-#define CS_AUDIO_STRING 0x23
-#define CS_AUDIO_INTERFACE 0x24
-#define CS_AUDIO_ENDPOINT 0x25
-
#define HEADER 0x01
#define INPUT_TERMINAL 0x02
#define OUTPUT_TERMINAL 0x03
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
index 2b9d940..5105b6b 100644
--- a/sound/usb/usbmidi.c
+++ b/sound/usb/usbmidi.c
@@ -48,6 +48,7 @@
#include <linux/usb.h>
#include <sound/core.h>
#include <sound/rawmidi.h>
+#include <sound/asequencer.h>
#include "usbaudio.h"
@@ -1010,97 +1011,157 @@ static struct snd_rawmidi_substream *snd_usbmidi_find_substream(struct snd_usb_m
* "(product) MIDI (n)" schema because they aren't external MIDI ports,
* such as internal control or synthesizer ports.
*/
-static struct {
+static struct port_info {
u32 id;
- int port;
- const char *name_format;
-} snd_usbmidi_port_names[] = {
+ short int port;
+ short int voices;
+ const char *name;
+ unsigned int seq_flags;
+} snd_usbmidi_port_info[] = {
+#define PORT_INFO(vendor, product, num, name_, voices_, flags) \
+ { .id = USB_ID(vendor, product), \
+ .port = num, .voices = voices_, \
+ .name = name_, .seq_flags = flags }
+#define EXTERNAL_PORT(vendor, product, num, name) \
+ PORT_INFO(vendor, product, num, name, 0, \
+ SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \
+ SNDRV_SEQ_PORT_TYPE_HARDWARE | \
+ SNDRV_SEQ_PORT_TYPE_PORT)
+#define CONTROL_PORT(vendor, product, num, name) \
+ PORT_INFO(vendor, product, num, name, 0, \
+ SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \
+ SNDRV_SEQ_PORT_TYPE_HARDWARE)
+#define ROLAND_SYNTH_PORT(vendor, product, num, name, voices) \
+ PORT_INFO(vendor, product, num, name, voices, \
+ SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \
+ SNDRV_SEQ_PORT_TYPE_MIDI_GM | \
+ SNDRV_SEQ_PORT_TYPE_MIDI_GM2 | \
+ SNDRV_SEQ_PORT_TYPE_MIDI_GS | \
+ SNDRV_SEQ_PORT_TYPE_MIDI_XG | \
+ SNDRV_SEQ_PORT_TYPE_HARDWARE | \
+ SNDRV_SEQ_PORT_TYPE_SYNTHESIZER)
+#define SOUNDCANVAS_PORT(vendor, product, num, name, voices) \
+ PORT_INFO(vendor, product, num, name, voices, \
+ SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \
+ SNDRV_SEQ_PORT_TYPE_MIDI_GM | \
+ SNDRV_SEQ_PORT_TYPE_MIDI_GM2 | \
+ SNDRV_SEQ_PORT_TYPE_MIDI_GS | \
+ SNDRV_SEQ_PORT_TYPE_MIDI_XG | \
+ SNDRV_SEQ_PORT_TYPE_MIDI_MT32 | \
+ SNDRV_SEQ_PORT_TYPE_HARDWARE | \
+ SNDRV_SEQ_PORT_TYPE_SYNTHESIZER)
/* Roland UA-100 */
- { USB_ID(0x0582, 0x0000), 2, "%s Control" },
+ CONTROL_PORT(0x0582, 0x0000, 2, "%s Control"),
/* Roland SC-8850 */
- { USB_ID(0x0582, 0x0003), 0, "%s Part A" },
- { USB_ID(0x0582, 0x0003), 1, "%s Part B" },
- { USB_ID(0x0582, 0x0003), 2, "%s Part C" },
- { USB_ID(0x0582, 0x0003), 3, "%s Part D" },
- { USB_ID(0x0582, 0x0003), 4, "%s MIDI 1" },
- { USB_ID(0x0582, 0x0003), 5, "%s MIDI 2" },
+ SOUNDCANVAS_PORT(0x0582, 0x0003, 0, "%s Part A", 128),
+ SOUNDCANVAS_PORT(0x0582, 0x0003, 1, "%s Part B", 128),
+ SOUNDCANVAS_PORT(0x0582, 0x0003, 2, "%s Part C", 128),
+ SOUNDCANVAS_PORT(0x0582, 0x0003, 3, "%s Part D", 128),
+ EXTERNAL_PORT(0x0582, 0x0003, 4, "%s MIDI 1"),
+ EXTERNAL_PORT(0x0582, 0x0003, 5, "%s MIDI 2"),
/* Roland U-8 */
- { USB_ID(0x0582, 0x0004), 0, "%s MIDI" },
- { USB_ID(0x0582, 0x0004), 1, "%s Control" },
+ EXTERNAL_PORT(0x0582, 0x0004, 0, "%s MIDI"),
+ CONTROL_PORT(0x0582, 0x0004, 1, "%s Control"),
/* Roland SC-8820 */
- { USB_ID(0x0582, 0x0007), 0, "%s Part A" },
- { USB_ID(0x0582, 0x0007), 1, "%s Part B" },
- { USB_ID(0x0582, 0x0007), 2, "%s MIDI" },
+ SOUNDCANVAS_PORT(0x0582, 0x0007, 0, "%s Part A", 64),
+ SOUNDCANVAS_PORT(0x0582, 0x0007, 1, "%s Part B", 64),
+ EXTERNAL_PORT(0x0582, 0x0007, 2, "%s MIDI"),
/* Roland SK-500 */
- { USB_ID(0x0582, 0x000b), 0, "%s Part A" },
- { USB_ID(0x0582, 0x000b), 1, "%s Part B" },
- { USB_ID(0x0582, 0x000b), 2, "%s MIDI" },
+ SOUNDCANVAS_PORT(0x0582, 0x000b, 0, "%s Part A", 64),
+ SOUNDCANVAS_PORT(0x0582, 0x000b, 1, "%s Part B", 64),
+ EXTERNAL_PORT(0x0582, 0x000b, 2, "%s MIDI"),
/* Roland SC-D70 */
- { USB_ID(0x0582, 0x000c), 0, "%s Part A" },
- { USB_ID(0x0582, 0x000c), 1, "%s Part B" },
- { USB_ID(0x0582, 0x000c), 2, "%s MIDI" },
+ SOUNDCANVAS_PORT(0x0582, 0x000c, 0, "%s Part A", 64),
+ SOUNDCANVAS_PORT(0x0582, 0x000c, 1, "%s Part B", 64),
+ EXTERNAL_PORT(0x0582, 0x000c, 2, "%s MIDI"),
/* Edirol UM-880 */
- { USB_ID(0x0582, 0x0014), 8, "%s Control" },
+ CONTROL_PORT(0x0582, 0x0014, 8, "%s Control"),
/* Edirol SD-90 */
- { USB_ID(0x0582, 0x0016), 0, "%s Part A" },
- { USB_ID(0x0582, 0x0016), 1, "%s Part B" },
- { USB_ID(0x0582, 0x0016), 2, "%s MIDI 1" },
- { USB_ID(0x0582, 0x0016), 3, "%s MIDI 2" },
+ ROLAND_SYNTH_PORT(0x0582, 0x0016, 0, "%s Part A", 128),
+ ROLAND_SYNTH_PORT(0x0582, 0x0016, 1, "%s Part B", 128),
+ EXTERNAL_PORT(0x0582, 0x0016, 2, "%s MIDI 1"),
+ EXTERNAL_PORT(0x0582, 0x0016, 3, "%s MIDI 2"),
/* Edirol UM-550 */
- { USB_ID(0x0582, 0x0023), 5, "%s Control" },
+ CONTROL_PORT(0x0582, 0x0023, 5, "%s Control"),
/* Edirol SD-20 */
- { USB_ID(0x0582, 0x0027), 0, "%s Part A" },
- { USB_ID(0x0582, 0x0027), 1, "%s Part B" },
- { USB_ID(0x0582, 0x0027), 2, "%s MIDI" },
+ ROLAND_SYNTH_PORT(0x0582, 0x0027, 0, "%s Part A", 64),
+ ROLAND_SYNTH_PORT(0x0582, 0x0027, 1, "%s Part B", 64),
+ EXTERNAL_PORT(0x0582, 0x0027, 2, "%s MIDI"),
/* Edirol SD-80 */
- { USB_ID(0x0582, 0x0029), 0, "%s Part A" },
- { USB_ID(0x0582, 0x0029), 1, "%s Part B" },
- { USB_ID(0x0582, 0x0029), 2, "%s MIDI 1" },
- { USB_ID(0x0582, 0x0029), 3, "%s MIDI 2" },
+ ROLAND_SYNTH_PORT(0x0582, 0x0029, 0, "%s Part A", 128),
+ ROLAND_SYNTH_PORT(0x0582, 0x0029, 1, "%s Part B", 128),
+ EXTERNAL_PORT(0x0582, 0x0029, 2, "%s MIDI 1"),
+ EXTERNAL_PORT(0x0582, 0x0029, 3, "%s MIDI 2"),
/* Edirol UA-700 */
- { USB_ID(0x0582, 0x002b), 0, "%s MIDI" },
- { USB_ID(0x0582, 0x002b), 1, "%s Control" },
+ EXTERNAL_PORT(0x0582, 0x002b, 0, "%s MIDI"),
+ CONTROL_PORT(0x0582, 0x002b, 1, "%s Control"),
/* Roland VariOS */
- { USB_ID(0x0582, 0x002f), 0, "%s MIDI" },
- { USB_ID(0x0582, 0x002f), 1, "%s External MIDI" },
- { USB_ID(0x0582, 0x002f), 2, "%s Sync" },
+ EXTERNAL_PORT(0x0582, 0x002f, 0, "%s MIDI"),
+ EXTERNAL_PORT(0x0582, 0x002f, 1, "%s External MIDI"),
+ EXTERNAL_PORT(0x0582, 0x002f, 2, "%s Sync"),
/* Edirol PCR */
- { USB_ID(0x0582, 0x0033), 0, "%s MIDI" },
- { USB_ID(0x0582, 0x0033), 1, "%s 1" },
- { USB_ID(0x0582, 0x0033), 2, "%s 2" },
+ EXTERNAL_PORT(0x0582, 0x0033, 0, "%s MIDI"),
+ EXTERNAL_PORT(0x0582, 0x0033, 1, "%s 1"),
+ EXTERNAL_PORT(0x0582, 0x0033, 2, "%s 2"),
/* BOSS GS-10 */
- { USB_ID(0x0582, 0x003b), 0, "%s MIDI" },
- { USB_ID(0x0582, 0x003b), 1, "%s Control" },
+ EXTERNAL_PORT(0x0582, 0x003b, 0, "%s MIDI"),
+ CONTROL_PORT(0x0582, 0x003b, 1, "%s Control"),
/* Edirol UA-1000 */
- { USB_ID(0x0582, 0x0044), 0, "%s MIDI" },
- { USB_ID(0x0582, 0x0044), 1, "%s Control" },
+ EXTERNAL_PORT(0x0582, 0x0044, 0, "%s MIDI"),
+ CONTROL_PORT(0x0582, 0x0044, 1, "%s Control"),
/* Edirol UR-80 */
- { USB_ID(0x0582, 0x0048), 0, "%s MIDI" },
- { USB_ID(0x0582, 0x0048), 1, "%s 1" },
- { USB_ID(0x0582, 0x0048), 2, "%s 2" },
+ EXTERNAL_PORT(0x0582, 0x0048, 0, "%s MIDI"),
+ EXTERNAL_PORT(0x0582, 0x0048, 1, "%s 1"),
+ EXTERNAL_PORT(0x0582, 0x0048, 2, "%s 2"),
/* Edirol PCR-A */
- { USB_ID(0x0582, 0x004d), 0, "%s MIDI" },
- { USB_ID(0x0582, 0x004d), 1, "%s 1" },
- { USB_ID(0x0582, 0x004d), 2, "%s 2" },
+ EXTERNAL_PORT(0x0582, 0x004d, 0, "%s MIDI"),
+ EXTERNAL_PORT(0x0582, 0x004d, 1, "%s 1"),
+ EXTERNAL_PORT(0x0582, 0x004d, 2, "%s 2"),
/* Edirol UM-3EX */
- { USB_ID(0x0582, 0x009a), 3, "%s Control" },
+ CONTROL_PORT(0x0582, 0x009a, 3, "%s Control"),
/* M-Audio MidiSport 8x8 */
- { USB_ID(0x0763, 0x1031), 8, "%s Control" },
- { USB_ID(0x0763, 0x1033), 8, "%s Control" },
+ CONTROL_PORT(0x0763, 0x1031, 8, "%s Control"),
+ CONTROL_PORT(0x0763, 0x1033, 8, "%s Control"),
/* MOTU Fastlane */
- { USB_ID(0x07fd, 0x0001), 0, "%s MIDI A" },
- { USB_ID(0x07fd, 0x0001), 1, "%s MIDI B" },
+ EXTERNAL_PORT(0x07fd, 0x0001, 0, "%s MIDI A"),
+ EXTERNAL_PORT(0x07fd, 0x0001, 1, "%s MIDI B"),
/* Emagic Unitor8/AMT8/MT4 */
- { USB_ID(0x086a, 0x0001), 8, "%s Broadcast" },
- { USB_ID(0x086a, 0x0002), 8, "%s Broadcast" },
- { USB_ID(0x086a, 0x0003), 4, "%s Broadcast" },
+ EXTERNAL_PORT(0x086a, 0x0001, 8, "%s Broadcast"),
+ EXTERNAL_PORT(0x086a, 0x0002, 8, "%s Broadcast"),
+ EXTERNAL_PORT(0x086a, 0x0003, 4, "%s Broadcast"),
};
+static struct port_info *find_port_info(struct snd_usb_midi* umidi, int number)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_info); ++i) {
+ if (snd_usbmidi_port_info[i].id == umidi->chip->usb_id &&
+ snd_usbmidi_port_info[i].port == number)
+ return &snd_usbmidi_port_info[i];
+ }
+ return NULL;
+}
+
+static void snd_usbmidi_get_port_info(struct snd_rawmidi *rmidi, int number,
+ struct snd_seq_port_info *seq_port_info)
+{
+ struct snd_usb_midi *umidi = rmidi->private_data;
+ struct port_info *port_info;
+
+ /* TODO: read port flags from descriptors */
+ port_info = find_port_info(umidi, number);
+ if (port_info) {
+ seq_port_info->type = port_info->seq_flags;
+ seq_port_info->midi_voices = port_info->voices;
+ }
+}
+
static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi,
int stream, int number,
struct snd_rawmidi_substream ** rsubstream)
{
- int i;
+ struct port_info *port_info;
const char *name_format;
struct snd_rawmidi_substream *substream = snd_usbmidi_find_substream(umidi, stream, number);
@@ -1110,14 +1171,8 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi,
}
/* TODO: read port name from jack descriptor */
- name_format = "%s MIDI %d";
- for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_names); ++i) {
- if (snd_usbmidi_port_names[i].id == umidi->chip->usb_id &&
- snd_usbmidi_port_names[i].port == number) {
- name_format = snd_usbmidi_port_names[i].name_format;
- break;
- }
- }
+ port_info = find_port_info(umidi, number);
+ name_format = port_info ? port_info->name : "%s MIDI %d";
snprintf(substream->name, sizeof(substream->name),
name_format, umidi->chip->card->shortname, number + 1);
@@ -1358,7 +1413,7 @@ static int snd_usbmidi_detect_yamaha(struct snd_usb_midi* umidi,
for (cs_desc = hostif->extra;
cs_desc < hostif->extra + hostif->extralen && cs_desc[0] >= 2;
cs_desc += cs_desc[0]) {
- if (cs_desc[1] == CS_AUDIO_INTERFACE) {
+ if (cs_desc[1] == USB_DT_CS_INTERFACE) {
if (cs_desc[2] == MIDI_IN_JACK)
endpoint->in_cables = (endpoint->in_cables << 1) | 1;
else if (cs_desc[2] == MIDI_OUT_JACK)
@@ -1457,6 +1512,10 @@ static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi* umidi,
return 0;
}
+static struct snd_rawmidi_global_ops snd_usbmidi_ops = {
+ .get_port_info = snd_usbmidi_get_port_info,
+};
+
static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi,
int out_ports, int in_ports)
{
@@ -1472,6 +1531,7 @@ static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi,
rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
SNDRV_RAWMIDI_INFO_INPUT |
SNDRV_RAWMIDI_INFO_DUPLEX;
+ rmidi->ops = &snd_usbmidi_ops;
rmidi->private_data = umidi;
rmidi->private_free = snd_usbmidi_rawmidi_free;
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_usbmidi_output_ops);
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
index ce86283..491e975 100644
--- a/sound/usb/usbmixer.c
+++ b/sound/usb/usbmixer.c
@@ -46,6 +46,27 @@
/* ignore error from controls - for debugging */
/* #define IGNORE_CTL_ERROR */
+/*
+ * Sound Blaster remote control configuration
+ *
+ * format of remote control data:
+ * Extigy: xx 00
+ * Audigy 2 NX: 06 80 xx 00 00 00
+ * Live! 24-bit: 06 80 xx yy 22 83
+ */
+static const struct rc_config {
+ u32 usb_id;
+ u8 offset;
+ u8 length;
+ u8 packet_length;
+ u8 mute_mixer_id;
+ u32 mute_code;
+} rc_configs[] = {
+ { USB_ID(0x041e, 0x3000), 0, 1, 2, 18, 0x0013 }, /* Extigy */
+ { USB_ID(0x041e, 0x3020), 2, 1, 6, 18, 0x0013 }, /* Audigy 2 NX */
+ { USB_ID(0x041e, 0x3040), 2, 2, 6, 2, 0x6e91 }, /* Live! 24-bit */
+};
+
struct usb_mixer_interface {
struct snd_usb_audio *chip;
unsigned int ctrlif;
@@ -55,11 +76,7 @@ struct usb_mixer_interface {
struct usb_mixer_elem_info **id_elems; /* array[256], indexed by unit id */
/* Sound Blaster remote control stuff */
- enum {
- RC_NONE,
- RC_EXTIGY,
- RC_AUDIGY2NX,
- } rc_type;
+ const struct rc_config *rc_cfg;
unsigned long rc_hwdep_open;
u32 rc_code;
wait_queue_head_t rc_waitq;
@@ -1647,7 +1664,7 @@ static void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer,
static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer,
int unitid)
{
- if (mixer->rc_type == RC_NONE)
+ if (!mixer->rc_cfg)
return;
/* unit ids specific to Extigy/Audigy 2 NX: */
switch (unitid) {
@@ -1732,20 +1749,19 @@ static void snd_usb_soundblaster_remote_complete(struct urb *urb,
struct pt_regs *regs)
{
struct usb_mixer_interface *mixer = urb->context;
- /*
- * format of remote control data:
- * Extigy: xx 00
- * Audigy 2 NX: 06 80 xx 00 00 00
- */
- int offset = mixer->rc_type == RC_EXTIGY ? 0 : 2;
+ const struct rc_config *rc = mixer->rc_cfg;
u32 code;
- if (urb->status < 0 || urb->actual_length <= offset)
+ if (urb->status < 0 || urb->actual_length < rc->packet_length)
return;
- code = mixer->rc_buffer[offset];
+
+ code = mixer->rc_buffer[rc->offset];
+ if (rc->length == 2)
+ code |= mixer->rc_buffer[rc->offset + 1] << 8;
+
/* the Mute button actually changes the mixer control */
- if (code == 13)
- snd_usb_mixer_notify_id(mixer, 18);
+ if (code == rc->mute_code)
+ snd_usb_mixer_notify_id(mixer, rc->mute_mixer_id);
mixer->rc_code = code;
wmb();
wake_up(&mixer->rc_waitq);
@@ -1801,21 +1817,17 @@ static unsigned int snd_usb_sbrc_hwdep_poll(struct snd_hwdep *hw, struct file *f
static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer)
{
struct snd_hwdep *hwdep;
- int err, len;
+ int err, len, i;
- switch (mixer->chip->usb_id) {
- case USB_ID(0x041e, 0x3000):
- mixer->rc_type = RC_EXTIGY;
- len = 2;
- break;
- case USB_ID(0x041e, 0x3020):
- mixer->rc_type = RC_AUDIGY2NX;
- len = 6;
- break;
- default:
+ for (i = 0; i < ARRAY_SIZE(rc_configs); ++i)
+ if (rc_configs[i].usb_id == mixer->chip->usb_id)
+ break;
+ if (i >= ARRAY_SIZE(rc_configs))
return 0;
- }
+ mixer->rc_cfg = &rc_configs[i];
+ len = mixer->rc_cfg->packet_length;
+
init_waitqueue_head(&mixer->rc_waitq);
err = snd_hwdep_new(mixer->chip->card, "SB remote control", 0, &hwdep);
if (err < 0)
@@ -1998,7 +2010,7 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif)
if ((err = snd_audigy2nx_controls_create(mixer)) < 0)
goto _error;
if (!snd_card_proc_new(chip->card, "audigy2nx", &entry))
- snd_info_set_text_ops(entry, mixer, 1024,
+ snd_info_set_text_ops(entry, mixer,
snd_audigy2nx_proc_read);
}
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c
index fe67a92..88b72b5 100644
--- a/sound/usb/usx2y/usx2yhwdeppcm.c
+++ b/sound/usb/usx2y/usx2yhwdeppcm.c
@@ -632,7 +632,7 @@ static int usX2Y_pcms_lock_check(struct snd_card *card)
for (s = 0; s < 2; ++s) {
struct snd_pcm_substream *substream;
substream = pcm->streams[s].substream;
- if (substream && substream->ffile != NULL)
+ if (SUBSTREAM_BUSY(substream))
err = -EBUSY;
}
}
OpenPOWER on IntegriCloud